Skip to content

Commit 0dd9d8d

Browse files
authored
feat: add java-to-typescript skill
feat: add java-to-typescript skill
2 parents 6b15454 + 0041a1f commit 0dd9d8d

105 files changed

Lines changed: 12262 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/eval.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: eval
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'skills/java-to-typescript/**'
7+
- '.github/workflows/eval.yml'
8+
workflow_dispatch:
9+
10+
jobs:
11+
unit-and-e1:
12+
runs-on: ubuntu-latest
13+
defaults:
14+
run:
15+
working-directory: skills/java-to-typescript
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Setup Node 20
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: '20'
23+
cache: 'npm'
24+
cache-dependency-path: skills/java-to-typescript/package-lock.json
25+
26+
- name: Install dev deps
27+
run: npm ci
28+
29+
- name: Typecheck
30+
run: npm run typecheck
31+
32+
- name: Unit tests (scripts/lib + scripts)
33+
run: npx vitest run scripts/
34+
35+
- name: E1 (analyze accuracy) eval
36+
run: npx vitest run evals/__tests__/runner.test.ts

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ target/
33
.idea/
44
*.iml
55
.vscode/
6+
.project
7+
.settings/
8+
.classpath
69
.DS_Store
710
*.log
811
/tmp/
@@ -11,3 +14,9 @@ target/
1114

1215
# skill-creator iteration artifacts (sibling to each skill, named <skill>-workspace/)
1316
*-workspace/
17+
18+
# java-to-typescript skill: TS scripts / evals build artifacts
19+
skills/java-to-typescript/node_modules/
20+
skills/java-to-typescript/dist/
21+
skills/java-to-typescript/.vitest-cache/
22+
skills/java-to-typescript/coverage/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ A monorepo of [Claude Code](https://docs.claude.com/claude-code) / Agent SDK ski
77
| Skill | Maven coordinates | What it does |
88
|---|---|---|
99
| [`gitlab-helper`](skills/gitlab-helper) | `io.github.randomcodespace.ai:gitlab-helper` | GitLab CI/CD, pipelines, runners, and API automation. Version-aware doc grounding + `glab`/`python-gitlab` automation. |
10+
| [`java-to-typescript`](skills/java-to-typescript) | `io.github.randomcodespace.ai:java-to-typescript` | Migrate a Java service (Spring Boot, Quarkus, Micronaut, Spring MVC) to TypeScript with four-phase orchestration, deterministic plumbing scripts, and contract-parity verification. Air-gap-friendly. |
1011

1112
## Using a skill
1213

assembly/skill-bundle.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
</includes>
2121
<excludes>
2222
<exclude>pom.xml</exclude>
23-
<exclude>target/**</exclude>
23+
<exclude>**/target/**</exclude>
24+
<exclude>**/__tests__/**</exclude>
25+
<exclude>**/*.test.ts</exclude>
26+
<exclude>**/node_modules/**</exclude>
27+
<exclude>**/.vitest-cache/**</exclude>
28+
<exclude>**/coverage/**</exclude>
29+
<exclude>**/dist/**</exclude>
2430
</excludes>
2531
</fileSet>
2632
</fileSets>

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
<modules>
2323
<module>skills/gitlab-helper</module>
24+
<module>skills/java-to-typescript</module>
2425
</modules>
2526

2627
<properties>

skills/java-to-typescript/SKILL.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
---
2+
name: java-to-typescript
3+
description: Use when migrating a Java service (Spring Boot, Quarkus, Micronaut, Spring MVC) to TypeScript. Supports full rewrite, strangler-fig, and module-by-module modes; targets Node (default), Bun, or Deno on Express, Koa, Hono, or Restify, with contract-parity verification against the original Java service.
4+
---
5+
6+
# java-to-typescript
7+
8+
Migrate a Java HTTP service to TypeScript across four phases with explicit user gates. The LLM owns every translation decision; the bundled scripts only do deterministic plumbing (XML parsing, workspace scaffolding, HTTP capture, JSON diff). No runtime internet access is required.
9+
10+
## When to use
11+
12+
Invoke when the user asks to port, migrate, or rewrite a Java service in TypeScript. Detect Spring Boot / Quarkus / Micronaut / Spring MVC by scanning `pom.xml` or `build.gradle[.kts]` for the canonical dependency coords.
13+
14+
Do not use for: GraphQL Java migrations, Akka/Pekko, Android, JNI, Java agents, or pure-library JARs without an HTTP surface.
15+
16+
## Hard constraints
17+
18+
1. The LLM does every translation. Scripts never translate, never decide a library choice, never write source code. They produce JSON, JSONL, or templated config files only.
19+
2. No runtime internet. The registry at `references/library-map.yaml` is the only source of library-mapping truth. Unmapped libraries escalate to the user via `AskUserQuestion` — never silently auto-fill, never call `context7` at runtime.
20+
3. Never skip a phase. Phase 2 is a hard user gate; Phase 4 is the acceptance gate.
21+
22+
## The four phases
23+
24+
### Phase 1 — Analyze (read-only)
25+
26+
Run:
27+
28+
```
29+
tsx scripts/pom-to-workspace.ts analyze --repo <java-repo>
30+
```
31+
32+
This writes `<java-repo>/migration/analysis.json` with detected build system, modules, framework per module, dependency inventory, and any `unmappedDependencies`. Cross-reference dependencies against `references/library-map.yaml`.
33+
34+
Consult: `references/library-map.yaml`, `references/frameworks/*.md`.
35+
36+
### Phase 2 — Plan (hard user gate, diff preview)
37+
38+
Ask the user (via your platform's interactive-prompt mechanism — `AskUserQuestion` in Claude Code; see `references/platform-adaptation.md` for Copilot CLI / Codex equivalents) for:
39+
40+
- Migration mode (`full-rewrite | strangler-fig | module-by-module`) — consult `references/migration-modes.md`.
41+
- Target TS framework per Java module (Express default; Koa, Hono, Restify selectable) — consult `references/targets/*.md`.
42+
- Runtime (Node default; Bun, Deno opt-in) — consult `references/runtimes/*.md`.
43+
- Package manager (npm default; pnpm, yarn, bun opt-in).
44+
- DI library (tsyringe default).
45+
- Validation library (zod default).
46+
47+
For each entry in `analysis.json.unmappedDependencies`, ask the user (interactive prompt) for a target. Do not auto-resolve. Do not call `context7`.
48+
49+
Write `<java-repo>/migration/plan.md` containing per-module decisions, dependency order, and a one-shot diff preview (per module: what gets created, what the projected `package.json` looks like, which Java files map to which TS files).
50+
51+
**Gate:** wait for explicit user approval of `plan.md` before Phase 3.
52+
53+
Consult: `references/migration-modes.md`, `references/targets/*.md`, `references/runtimes/*.md`, `references/build-layout.md`, `references/type-fidelity.md`.
54+
55+
### Phase 3 — Port
56+
57+
Order:
58+
59+
1. Write `<java-repo>/migration/scaffold.json` (derived from `plan.md`). Run `tsx scripts/pom-to-workspace.ts scaffold --plan <java-repo>/migration/scaffold.json --out <ts-repo>`. This emits root `package.json`, per-module `package.json`, `tsconfig.json`, `vitest.config.ts`, and `.gitignore`. No source code.
60+
61+
2. Port deterministic surfaces first, per module: config (zod-validated env), DTOs (zod schemas), entities (Drizzle schema), validation rules. Consult `references/categories/{config,validation,persistence}.md` and `references/type-fidelity.md`.
62+
63+
3. Port handlers one at a time, smallest module first. For each handler: read Java source → consult `references/frameworks/<source>.md` + `references/targets/<target>.md` → emit TS → run `tsc --noEmit` on the touched module → append a one-line entry to `<java-repo>/migration/port-log.md` recording any non-trivial decision.
64+
65+
4. Port tests alongside each handler. Map JUnit→Vitest, Mockito→`vi.mock`, AssertJ→`expect`, Testcontainers→testcontainers-node. Consult `references/categories/testing.md`.
66+
67+
5. Apply type-fidelity policy per `references/type-fidelity.md`. Deviations require a one-line `port-log.md` entry.
68+
69+
6. **Parallelize independent modules** when the dependency graph permits — use whatever subagent/worker dispatch your platform offers. Modules with no cross-edges to in-flight work can be ported concurrently; modules that depend on an unfinished sibling MUST wait. The skill itself does not bundle a subagent runner; orchestration is the platform's job. (See `references/platform-adaptation.md` for the per-platform mechanism: Claude Code subagents, Copilot CLI workers, Codex CLI parallel tasks. If your platform has no parallel-dispatch primitive, port sequentially — correctness is unaffected.)
70+
71+
**Non-negotiable patterns** (from `references/type-fidelity.md` §7.3):
72+
- One handler per file.
73+
- DTO ≡ zod schema. No interfaces on HTTP boundaries without a schema.
74+
- Repository ≡ Drizzle query module. No faked JPA repository interfaces.
75+
- Config ≡ single zod-parsed env object per module. No scattered `process.env.FOO`.
76+
- Logger ≡ module-scoped pino child. No `console.log`.
77+
- Errors ≡ subclasses of a per-module base class, mapped to HTTP status via single middleware.
78+
79+
### Phase 4 — Verify (acceptance gate)
80+
81+
The user starts both the Java service (`localhost:<javaPort>`) and the TS service (`localhost:<tsPort>`). The skill prints the expected commands and waits — it never boots services itself.
82+
83+
1. Generate `<java-repo>/migration/corpus.jsonl` from Java controller signatures + sample DB state. Ask the user to review or extend before recording.
84+
85+
2. Run:
86+
87+
```
88+
tsx scripts/record-fixtures.ts --java-base http://localhost:<javaPort> --corpus migration/corpus.jsonl --out migration/fixtures.jsonl
89+
```
90+
91+
3. Write `<java-repo>/migration/allowlist.json` declaring paths expected to differ (timestamps, generated IDs, trace headers). Schema:
92+
93+
```json
94+
{ "headers": ["x-request-id", "date", "traceparent"],
95+
"bodyPaths": ["$.createdAt", "$.updatedAt"],
96+
"arrayKeys": { "$.items": "id" } }
97+
```
98+
99+
4. Run:
100+
101+
```
102+
tsx scripts/replay-fixtures.ts --ts-base http://localhost:<tsPort> --fixtures migration/fixtures.jsonl --allowlist migration/allowlist.json --report migration/verify-report.md
103+
```
104+
105+
5. Run the ported Vitest suite from the TS workspace root.
106+
107+
**Acceptance gate (both required):** zero unexpected diffs in `verify-report.md` AND all ported Vitest suites green.
108+
109+
Consult: `references/categories/testing.md`.
110+
111+
## Migration artifact location
112+
113+
All artifacts (`analysis.json`, `plan.md`, `scaffold.json`, `corpus.jsonl`, `fixtures.jsonl`, `allowlist.json`, `port-log.md`, `verify-report.md`, `verify-report.json`) live in `<java-repo>/migration/`. On first run, the skill adds `migration/` to the target repo's `.gitignore`.
114+
115+
## When stuck
116+
117+
- Library not in registry: ask the user via `AskUserQuestion`. Do not invent a mapping.
118+
- Build-system parse warnings (Gradle Kotlin DSL with dynamic deps): show the warning verbatim to the user; ask them to confirm the dependency list.
119+
- Phase 4 unexpected diffs: report each diff with the Java side and TS side excerpted; return to Phase 3 for the responsible handler.
120+
- Tests fail after porting: do not weaken assertions to make them pass. Diagnose root cause; if the Java behavior cannot be replicated, escalate.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Evals
2+
3+
How to run the eval suite for the `java-to-typescript` skill.
4+
5+
## Eval types
6+
7+
| ID | What it measures | Determinism | When it runs |
8+
|---|---|---|---|
9+
| E1 | Analyze accuracy (Phase 1) | deterministic | every PR |
10+
| E2 | Plan reasonability (Phase 2) | LLM-judged | tag releases / on demand |
11+
| E3 | Port quality (Phase 3) | hybrid (hard `tsc`+tests; idioms LLM-judged) | tag releases / on demand |
12+
| E4 | Contract parity (Phase 4) | deterministic | manual smoke; CI optional |
13+
14+
## Quick start
15+
16+
```bash
17+
# All evals against the default fixture (spring-boot-users)
18+
npx tsx evals/runner.ts --eval all
19+
20+
# Specific eval
21+
npx tsx evals/runner.ts --eval E1
22+
npx tsx evals/runner.ts --eval E2 --runs 5
23+
npx tsx evals/runner.ts --eval E3 --runs 5
24+
25+
# Specific fixture
26+
npx tsx evals/runner.ts --fixture spring-boot-users --eval E1
27+
28+
# Override the plan/port being judged (defaults to sample/plan.md and sample/ts-port/api)
29+
npx tsx evals/runner.ts --eval E2 --plan /tmp/my-plan.md
30+
npx tsx evals/runner.ts --eval E3 --ts-repo /tmp/my-ts-port
31+
```
32+
33+
Vitest also exercises the deterministic + mock-mode paths:
34+
35+
```bash
36+
npx vitest run evals/__tests__/runner.test.ts
37+
npx vitest run evals/__tests__/judge.test.ts
38+
```
39+
40+
## Flags
41+
42+
| Flag | Default | Notes |
43+
|---|---|---|
44+
| `--fixture <name>` | `spring-boot-users` | Picks fixture under `evals/fixtures/<name>/` |
45+
| `--eval <id>` | `all` | `E1`, `E2`, `E3`, or `all` (E4 is invoked separately via `replay-fixtures.ts`) |
46+
| `--runs <n>` | `1` for deterministic evals, `5` for LLM-judged | N runs aggregated into `mean ± stddev` |
47+
| `--plan <path>` | `<fixture>/sample/plan.md` | Plan content for E2 to judge |
48+
| `--ts-repo <path>` | `<fixture>/sample/ts-port/api` | TS workspace for E3 to gate + judge |
49+
50+
## Judge modes (E2 + E3)
51+
52+
The judge in `evals/judge.ts` runs in two modes:
53+
54+
| Mode | Trigger | Behavior |
55+
|---|---|---|
56+
| **Mock** (default) | Either `MOCK_JUDGE` is unset/non-`0` OR `ANTHROPIC_API_KEY` is absent | Returns a deterministic score in 7-9 derived from `sha256(content + rubric)`. Free, fast, CI-safe, no network. |
57+
| **Real** | `MOCK_JUDGE=0` AND `ANTHROPIC_API_KEY=sk-...` both set | Calls `claude-haiku-4-5-20251001` with the rubric + content + judge instructions, parses a `{score, rationale}` JSON response. |
58+
59+
```bash
60+
# Run E2 + E3 with the real Anthropic judge
61+
MOCK_JUDGE=0 ANTHROPIC_API_KEY=sk-ant-... \
62+
npx tsx evals/runner.ts --eval all --runs 5
63+
```
64+
65+
The real-mode test in `evals/__tests__/judge.test.ts` is auto-skipped when the env vars aren't set, so CI never accidentally hits the API.
66+
67+
## Variance handling
68+
69+
LLM-judged evals (`E2`, `E3` idiom dimension) run N times (default 5). Output is `mean ± stddev`. Sample-stddev with `n-1` denominator. The rule for accepting a skill change as an improvement: **mean delta must exceed 1 stddev** of the prior baseline.
70+
71+
Mock mode produces `stddev=0` because the hash is deterministic — useful for verifying the harness wiring, not for measuring real model judgment.
72+
73+
## Sample inputs (reference shapes E2/E3 judge against)
74+
75+
Per fixture, `sample/` holds reference inputs:
76+
77+
- `sample/plan.md` — example of what a passing Phase 2 plan looks like
78+
- `sample/ts-port/<module>/` — minimal but tsc-clean + vitest-green reference TS workspace
79+
80+
These are *examples* for E2/E3 in mock mode. In real mode against a real migration, you'd pass `--plan /path/to/your/migration/plan.md` and `--ts-repo /path/to/the/produced/ts-workspace`.
81+
82+
## Adding a new fixture
83+
84+
1. `mkdir -p evals/fixtures/<name>/{java,expected,sample}`.
85+
2. Populate `java/` with a minimal runnable Spring Boot / Quarkus / Micronaut / Spring MVC project.
86+
3. Run analyze: `npx tsx scripts/pom-to-workspace.ts analyze --repo evals/fixtures/<name>/java`.
87+
4. Copy `evals/fixtures/<name>/java/migration/analysis.json` to `evals/fixtures/<name>/expected/analysis.json`.
88+
5. Write `expected/corpus.jsonl`, `expected/allowlist.json`, `expected/ts-shape.md`, `expected/plan-rubric.md`.
89+
6. Hand-author `sample/plan.md` (covering every rubric item) + `sample/ts-port/<module>/` (a minimal TS port that compiles + has at least one passing test).
90+
7. Re-run `evals/__tests__/runner.test.ts` to verify E1 + E2 + E3 against the new fixture.
91+
92+
## CI integration
93+
94+
`.github/workflows/eval.yml` runs typecheck + unit tests + E1 on every PR touching `skills/java-to-typescript/**`. E2/E3 in mock mode are exercised by the unit test suite (`runner.test.ts` + `judge.test.ts`). Real-mode E2/E3 against actual Claude API is opt-in only — run manually on tag releases with the env vars set, or wire a separate workflow keyed to `ANTHROPIC_API_KEY` secret if you want it on every release.
95+
96+
## Air-gap note
97+
98+
Evals never hit the public internet in mock mode. In real mode, only the Anthropic API is contacted (egress to `api.anthropic.com` over HTTPS). Java fixtures must compile against locally vendored Maven repositories (Artifactory / Nexus / proxied central). The eval runner itself only parses XML and connects to `localhost` for E4.

0 commit comments

Comments
 (0)