@llm4ts/shell 2.1.0 → 2.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/dist/Cli.d.ts +1 -1
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +32 -0
- package/dist/Cli.js.map +1 -1
- package/dist/Refine.d.ts +44 -0
- package/dist/Refine.d.ts.map +1 -0
- package/dist/Refine.js +362 -0
- package/dist/Refine.js.map +1 -0
- package/flows/lib/modernize-extract.js +217 -0
- package/flows/modernize-extract.js +13 -173
- package/flows/modernize-implement.js +28 -2
- package/flows/modernize-pack-check.js +7 -1
- package/flows/modernize-refine.js +389 -0
- package/flows/modernize-seed.js +50 -2
- package/flows/modernize-verify.js +12 -5
- package/kits/j2ee-nextjs/README.md +5 -4
- package/kits/j2ee-nextjs/fixtures/demo-bank/RUNBOOK.md +43 -0
- package/kits/j2ee-nextjs/fixtures/demo-bank/legacy-j2ee/PAGES.md +26 -0
- package/kits/j2ee-nextjs/flows/convert-all.js +56 -20
- package/kits/j2ee-nextjs/flows/convert-feature.js +48 -0
- package/kits/j2ee-nextjs/flows/lib/convert.js +292 -40
- package/kits/j2ee-nextjs/packs/j2ee-nextjs-spa/pack.md +16 -0
- package/kits/j2ee-nextjs/packs/j2ee-nextjs-spa/prompts/consolidate.md +10 -0
- package/kits/j2ee-nextjs/packs/j2ee-nextjs-spa/prompts/plan.md +24 -16
- package/kits/j2ee-nextjs/packs/j2ee-nextjs-spa/prompts/refine-propose.md +16 -0
- package/kits/mainframe-java/packs/cobol-springboot/pack.md +5 -0
- package/kits/mainframe-java/packs/cobol-springboot/prompts/consolidate.md +8 -0
- package/kits/mainframe-java/packs/cobol-springboot/prompts/refine-propose.md +10 -0
- package/package.json +5 -4
- package/src/Cli.ts +57 -0
- package/src/Refine.ts +504 -0
|
@@ -8,6 +8,7 @@ programs: .*\.jsp
|
|
|
8
8
|
specs-dir: docs/modernization/specs
|
|
9
9
|
features-dir: docs/modernization/features
|
|
10
10
|
program-files: (?:src/app/<NAME>(?:/.*)?|src/services/<NAME>(?:/.*)?|contracts/<NAME>\.openapi\.yaml|tests/<NAME>\..*)
|
|
11
|
+
feature-files: (?:src/services/<NAME>(?:/.*)?|contracts/<NAME>\.openapi\.yaml)
|
|
11
12
|
|
|
12
13
|
## Gates
|
|
13
14
|
|
|
@@ -47,3 +48,18 @@ unit: <jsp:include page="([^"]+)"
|
|
|
47
48
|
|
|
48
49
|
files: .*web\.xml
|
|
49
50
|
unit: <servlet-class>[a-z.]*\.([A-Za-z0-9]+)</servlet-class>
|
|
51
|
+
|
|
52
|
+
## Survey: jsp-form-action
|
|
53
|
+
|
|
54
|
+
files: .*\.jsp
|
|
55
|
+
unit: action="([^"]+)"
|
|
56
|
+
|
|
57
|
+
## Survey: jsp-ajax-target
|
|
58
|
+
|
|
59
|
+
files: .*\.jsp
|
|
60
|
+
unit: url:\s*['"]([^'"?]+)
|
|
61
|
+
|
|
62
|
+
## Consolidate
|
|
63
|
+
|
|
64
|
+
- cluster: jsp-form-action, jsp-ajax-target
|
|
65
|
+
- context: jsp-include
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
In a JSP portal a domain feature is the set of pages one servlet serves and
|
|
2
|
+
one ESB service pair backs: a list page with its detail or edit form, the
|
|
3
|
+
steps of one wizard (a session draft carried from step to step and a confirm
|
|
4
|
+
screen), a read-only screen with its ajax refresh. The shell — header, nav,
|
|
5
|
+
footer and any fragment every page includes — is one feature of its own,
|
|
6
|
+
planned first because every other feature renders inside it. Filler pages
|
|
7
|
+
with no form and no API call (help, profile, messages, settings) may be
|
|
8
|
+
folded into one "Portal shell and static pages" feature; say so in the
|
|
9
|
+
evidence. Never join two features that talk to different ESB services unless
|
|
10
|
+
one page posts to the other's servlet.
|
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
Derive the conversion task list for ONE
|
|
2
|
-
destination is an existing Next.js SPA with a design system,
|
|
3
|
-
and a port/adapter service convention — imitate it, never
|
|
1
|
+
Derive the conversion task list for ONE domain feature from the Page Specs of
|
|
2
|
+
its programs. The destination is an existing Next.js SPA with a design system,
|
|
3
|
+
an AuthProvider, and a port/adapter service convention — imitate it, never
|
|
4
|
+
fight it. The feature's included fragments (header, nav, footer) are context:
|
|
5
|
+
use their specs for layout and navigation, do not re-implement them here
|
|
6
|
+
unless this feature IS the shell.
|
|
4
7
|
|
|
5
|
-
- Task 1: the anti-corruption service layer — the typed port
|
|
6
|
-
src/services/<
|
|
7
|
-
contracts/<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
- Task 1: the feature's anti-corruption service layer — the typed port
|
|
9
|
+
interface under src/services/<feature>/port.ts matching the OpenAPI contract
|
|
10
|
+
at contracts/<feature>.openapi.yaml (domain names only, one operation per
|
|
11
|
+
API call across all the feature's pages), a mock adapter under
|
|
12
|
+
src/services/<feature>/mock.ts returning contract-shaped fixture data, and
|
|
13
|
+
the registry wiring. No page code yet.
|
|
14
|
+
- Then ONE task per page of the feature, in navigation order (the page with no
|
|
15
|
+
inbound link inside the feature first; list before edit; step 1 before
|
|
16
|
+
step 2 before confirm): the page component(s) under src/app/<page>/ using
|
|
17
|
+
ONLY the destination design-system components and the feature port —
|
|
18
|
+
forms, validation with VERBATIM messages, navigation, explicit state for
|
|
19
|
+
anything the legacy carried in the session or hidden fields — together with
|
|
20
|
+
its component tests under tests/<page>.page.test.tsx in the house test style:
|
|
21
|
+
spec'd fields render, spec'd validations fire with their exact messages, the
|
|
22
|
+
port is called with contract-shaped payloads. Nothing else.
|
|
23
|
+
- Each task names the programs, spec rules, and scenarios it covers. Scenarios
|
|
24
|
+
the decisions overlay marks drop, provided, or defer are out of scope: do
|
|
25
|
+
not plan them, and use the target capability a `provided` entry points at.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
The target is an existing Next.js SPA with a design system, an AuthProvider, a
|
|
2
|
+
router, and a port/adapter service convention. Things such a target usually
|
|
3
|
+
PROVIDES, so a legacy page or scenario about them is a `provided` candidate
|
|
4
|
+
once you have found the file that proves it:
|
|
5
|
+
|
|
6
|
+
- login, logout, session timeout, and "remember me" — the AuthProvider and its
|
|
7
|
+
login route own these; a legacy login JSP is provided, not converted;
|
|
8
|
+
- navigation shell, header, footer, and the nav link set — the app layout;
|
|
9
|
+
- "back" links, breadcrumbs, and page titles — the router and layout;
|
|
10
|
+
- session-carried drafts between wizard steps — client state, not a session;
|
|
11
|
+
- client-side validation libraries — the house Form validation map.
|
|
12
|
+
|
|
13
|
+
Things commonly DEPRECATED in a JSP estate, `drop` candidates when the spec
|
|
14
|
+
itself shows the evidence (dead route, expired campaign, developer harness,
|
|
15
|
+
print-only view, applet or Flash embed, frameset): name the evidence, never
|
|
16
|
+
guess from the page name alone. Never propose `defer`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
In a COBOL estate a domain feature is a job's worth of business behaviour: the
|
|
2
|
+
program a JCL step executes together with every program it CALLs and the
|
|
3
|
+
copybooks they share, or a set of programs that post to the same ledger
|
|
4
|
+
tables. Copybooks are context, never features of their own. Programs that
|
|
5
|
+
only compute (fee, interest, limit) and are CALLed from several jobs belong to
|
|
6
|
+
the feature that owns their business rule, not to every caller; say which in
|
|
7
|
+
the evidence. Never join two batch jobs that touch different ledgers unless
|
|
8
|
+
one executes the other.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
The target is a Spring Boot service with JPA entities, a validation chain, and
|
|
2
|
+
JUnit 5 acceptance tests over the seeded feature files. Things such a target
|
|
3
|
+
usually PROVIDES, so a legacy program or scenario about them is a `provided`
|
|
4
|
+
candidate once you have found the file that proves it: audit rows written by
|
|
5
|
+
an aspect or entity listener, request logging, the transaction boundary a
|
|
6
|
+
COBOL program opened and closed by hand, date and time stamping, and sequence
|
|
7
|
+
allocation. Things commonly DEPRECATED in a COBOL estate, `drop` candidates
|
|
8
|
+
when the source shows the evidence (a job step nothing schedules, a program no
|
|
9
|
+
JCL executes and nothing CALLs, a report format the business retired): name
|
|
10
|
+
the evidence, never guess from the program name alone. Never propose `defer`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llm4ts/shell",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Interactive shell and CLI for llm4ts: flow discovery, run-a-flow, and view",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"./FlowCatalog": "./dist/FlowCatalog.js",
|
|
24
24
|
"./FlowLaunch": "./dist/FlowLaunch.js",
|
|
25
25
|
"./Menu": "./dist/Menu.js",
|
|
26
|
+
"./Refine": "./dist/Refine.js",
|
|
26
27
|
"./Package": "./dist/Package.js",
|
|
27
28
|
"./package.json": "./package.json"
|
|
28
29
|
},
|
|
@@ -51,9 +52,9 @@
|
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@effect/platform-node": "4.0.0-rc.115",
|
|
53
54
|
"@effect/platform-node-shared": "4.0.0-rc.115",
|
|
54
|
-
"@llm4ts/
|
|
55
|
-
"@llm4ts/
|
|
56
|
-
"@llm4ts/
|
|
55
|
+
"@llm4ts/core": "2.2.0",
|
|
56
|
+
"@llm4ts/flow": "2.2.0",
|
|
57
|
+
"@llm4ts/runner": "2.2.0"
|
|
57
58
|
},
|
|
58
59
|
"peerDependencies": {
|
|
59
60
|
"effect": "4.0.0-rc.115"
|
package/src/Cli.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { homedir } from "node:os"
|
|
2
|
+
import { join, resolve } from "node:path"
|
|
2
3
|
import { fileURLToPath } from "node:url"
|
|
3
4
|
import * as Console from "effect/Console"
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
} from "./FlowCatalog.ts"
|
|
19
20
|
import { launchFlow } from "./FlowLaunch.ts"
|
|
20
21
|
import { mainMenu } from "./Menu.ts"
|
|
22
|
+
import { ModDir, refineSession } from "./Refine.ts"
|
|
21
23
|
import { packageVersion } from "./Package.ts"
|
|
22
24
|
|
|
23
25
|
export class ShellUsageError extends Schema.TaggedError<ShellUsageError>()("ShellUsage", {
|
|
@@ -295,6 +297,60 @@ const askCommand = Command.make(
|
|
|
295
297
|
})
|
|
296
298
|
).pipe(Command.withDescription("Stream a one-shot prompt to the selected coding agent"))
|
|
297
299
|
|
|
300
|
+
const refineCommand = Command.make(
|
|
301
|
+
"refine",
|
|
302
|
+
{
|
|
303
|
+
repo: Flag.String("repo").pipe(
|
|
304
|
+
Flag.optional,
|
|
305
|
+
Flag.withDescription(
|
|
306
|
+
"The LEGACY repository holding the extracted spec pack (defaults to the current directory)"
|
|
307
|
+
)
|
|
308
|
+
),
|
|
309
|
+
pack: Flag.String("pack").pipe(
|
|
310
|
+
Flag.optional,
|
|
311
|
+
Flag.withDescription("Pack forwarded as LLM4TS_PACK, as for `llm4ts run`")
|
|
312
|
+
),
|
|
313
|
+
target: Flag.String("target").pipe(
|
|
314
|
+
Flag.optional,
|
|
315
|
+
Flag.withDescription(
|
|
316
|
+
"The target repository, mounted read-only so the proposal can claim what it already provides (LLM4TS_TARGET_REPO)"
|
|
317
|
+
)
|
|
318
|
+
)
|
|
319
|
+
},
|
|
320
|
+
(config) =>
|
|
321
|
+
Effect.gen(function* () {
|
|
322
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
323
|
+
return yield* new ShellUsageError({
|
|
324
|
+
message:
|
|
325
|
+
"refine is interactive; off a terminal edit docs/modernization/decisions.md and run `llm4ts run modernize-refine`"
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
const repo = resolve(config.repo._tag === "Some" ? config.repo.value : process.cwd())
|
|
329
|
+
const flowPath = yield* resolveFlow("modernize-refine", shellTierPaths())
|
|
330
|
+
const environment: Record<string, string | undefined> = { ...process.env }
|
|
331
|
+
if (config.pack._tag === "Some") {
|
|
332
|
+
environment.LLM4TS_PACK = config.pack.value
|
|
333
|
+
}
|
|
334
|
+
if (config.target._tag === "Some") {
|
|
335
|
+
environment.LLM4TS_TARGET_REPO = resolve(config.target.value)
|
|
336
|
+
}
|
|
337
|
+
yield* refineSession({
|
|
338
|
+
modDir: join(repo, ModDir),
|
|
339
|
+
environment,
|
|
340
|
+
launch: (extra) =>
|
|
341
|
+
launchFlow({
|
|
342
|
+
flowPath,
|
|
343
|
+
taskArgs: ["--repo", repo],
|
|
344
|
+
environment: { ...environment, ...extra }
|
|
345
|
+
}).pipe(Effect.catch((error) => Console.error(error.message).pipe(Effect.as(1))))
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
).pipe(
|
|
349
|
+
Command.withDescription(
|
|
350
|
+
"Interactively mark, deepen, and consolidate an extracted spec pack, then run modernize-refine on it (ADR 0015)"
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
|
|
298
354
|
const doctorCommand = Command.make("doctor", {}, () =>
|
|
299
355
|
Effect.gen(function* () {
|
|
300
356
|
const report = yield* makeDoctorProgram()
|
|
@@ -321,6 +377,7 @@ export const shellCommand = Command.make("llm4ts", {}, () =>
|
|
|
321
377
|
kitsCommand,
|
|
322
378
|
viewCommand,
|
|
323
379
|
askCommand,
|
|
380
|
+
refineCommand,
|
|
324
381
|
doctorCommand
|
|
325
382
|
])
|
|
326
383
|
)
|