@llm4ts/shell 2.36.0 → 2.38.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 +18 -1
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +89 -0
- package/dist/Cli.js.map +1 -1
- package/flows/lib/modernize-extract.js +9 -0
- package/flows/modernize-extract.js +17 -8
- package/flows/modernize-pack-check.js +65 -5
- package/flows/modernize-refine.js +4 -5
- package/flows/modernize-survey.js +80 -87
- package/kits/j2ee-nextjs/flows/lib/convert.js +4 -3
- package/kits/j2ee-nextjs/packs/j2ee-nextjs-spa/pack.md +38 -5
- package/kits/mainframe-java/packs/cobol-kafka/pack.md +24 -0
- package/kits/mainframe-java/packs/cobol-springboot/pack.md +24 -0
- package/kits/port/README.md +5 -4
- package/kits/port/packs/cobol-springboot-port/pack.md +48 -0
- package/kits/port/packs/cobol-springboot-port/patterns/pitfalls-cobol-springboot-port.md +36 -0
- package/kits/port/packs/cobol-springboot-port/prompts/porting.md +92 -0
- package/kits/port/packs/cobol-springboot-port/reviewers/spring-fidelity.md +15 -0
- package/package.json +4 -4
- package/src/Cli.ts +183 -0
package/src/Cli.ts
CHANGED
|
@@ -30,6 +30,12 @@ import {
|
|
|
30
30
|
type WatchOptions
|
|
31
31
|
} from "@llm4ts/runner/Watch"
|
|
32
32
|
import { makeProfileProgram, type ProfileOptions } from "@llm4ts/runner/Profile"
|
|
33
|
+
import {
|
|
34
|
+
makeGraphProgram,
|
|
35
|
+
nodeGraphDependencies,
|
|
36
|
+
type GraphCommand,
|
|
37
|
+
type GraphFormat
|
|
38
|
+
} from "@llm4ts/runner/Graph"
|
|
33
39
|
import { idleAfterFrom } from "@llm4ts/runner/AgentTree"
|
|
34
40
|
import { describeExclusion } from "@llm4ts/flow/Roster"
|
|
35
41
|
import { builtinKitsDir, discoverKits, kitTierPaths, type DiscoveredKit } from "@llm4ts/runner/Kits"
|
|
@@ -721,6 +727,182 @@ const rosterCommand = Command.make("roster", { repo: rosterRepo }, (config) =>
|
|
|
721
727
|
Command.withSubcommands([rosterPauseCommand, rosterResumeCommand])
|
|
722
728
|
)
|
|
723
729
|
|
|
730
|
+
// ---- graph (ADR 0030) -------------------------------------------------------
|
|
731
|
+
|
|
732
|
+
const graphFormats: ReadonlyArray<GraphFormat> = ["text", "json", "mermaid", "dot"]
|
|
733
|
+
|
|
734
|
+
type GraphSubcommand = "build" | "query" | "path" | "closure" | "stats" | "probe"
|
|
735
|
+
|
|
736
|
+
interface GraphFlags {
|
|
737
|
+
readonly repo: Option.Option<string>
|
|
738
|
+
readonly pack: Option.Option<string>
|
|
739
|
+
readonly format: string
|
|
740
|
+
readonly kind: Option.Option<string>
|
|
741
|
+
readonly hops: string
|
|
742
|
+
readonly max: string
|
|
743
|
+
readonly all: boolean
|
|
744
|
+
readonly force: boolean
|
|
745
|
+
readonly text?: string
|
|
746
|
+
readonly from?: string
|
|
747
|
+
readonly to?: string
|
|
748
|
+
readonly program?: string
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const positiveInt = (name: string, raw: string): Effect.Effect<number, ShellUsageError> => {
|
|
752
|
+
const value = Number.parseInt(raw, 10)
|
|
753
|
+
return Number.isInteger(value) && value > 0
|
|
754
|
+
? Effect.succeed(value)
|
|
755
|
+
: Effect.fail(
|
|
756
|
+
new ShellUsageError({ message: `${name} must be a positive integer, got '${raw}'` })
|
|
757
|
+
)
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export const graphCommandFrom = (
|
|
761
|
+
sub: GraphSubcommand,
|
|
762
|
+
flags: GraphFlags,
|
|
763
|
+
cwd: string = process.cwd()
|
|
764
|
+
): Effect.Effect<GraphCommand, ShellUsageError> =>
|
|
765
|
+
Effect.gen(function* () {
|
|
766
|
+
const repo = resolve(
|
|
767
|
+
cwd,
|
|
768
|
+
Option.getOrElse(flags.repo, () => ".")
|
|
769
|
+
)
|
|
770
|
+
const pack = Option.isSome(flags.pack) ? { pack: flags.pack.value } : {}
|
|
771
|
+
const format = graphFormats.find((candidate) => candidate === flags.format)
|
|
772
|
+
if (format === undefined) {
|
|
773
|
+
return yield* new ShellUsageError({
|
|
774
|
+
message: `format must be one of ${graphFormats.join(", ")}, got '${flags.format}'`
|
|
775
|
+
})
|
|
776
|
+
}
|
|
777
|
+
switch (sub) {
|
|
778
|
+
case "build":
|
|
779
|
+
return { _tag: "build", repo, ...pack }
|
|
780
|
+
case "stats":
|
|
781
|
+
return { _tag: "stats", repo, ...pack, format }
|
|
782
|
+
case "probe":
|
|
783
|
+
return { _tag: "probe", repo, ...pack, format }
|
|
784
|
+
case "query":
|
|
785
|
+
return {
|
|
786
|
+
_tag: "query",
|
|
787
|
+
repo,
|
|
788
|
+
...pack,
|
|
789
|
+
text: flags.text ?? "",
|
|
790
|
+
...(Option.isSome(flags.kind) ? { kind: flags.kind.value } : {}),
|
|
791
|
+
hops: yield* positiveInt("hops", flags.hops),
|
|
792
|
+
format,
|
|
793
|
+
all: flags.all,
|
|
794
|
+
force: flags.force
|
|
795
|
+
}
|
|
796
|
+
case "path":
|
|
797
|
+
return {
|
|
798
|
+
_tag: "path",
|
|
799
|
+
repo,
|
|
800
|
+
...pack,
|
|
801
|
+
from: flags.from ?? "",
|
|
802
|
+
to: flags.to ?? "",
|
|
803
|
+
max: yield* positiveInt("max", flags.max),
|
|
804
|
+
format,
|
|
805
|
+
force: flags.force
|
|
806
|
+
}
|
|
807
|
+
case "closure":
|
|
808
|
+
return {
|
|
809
|
+
_tag: "closure",
|
|
810
|
+
repo,
|
|
811
|
+
...pack,
|
|
812
|
+
program: flags.program ?? "",
|
|
813
|
+
max: yield* positiveInt("max", flags.max),
|
|
814
|
+
format,
|
|
815
|
+
force: flags.force
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
const graphFlags = {
|
|
821
|
+
repo: Flag.String("repo").pipe(
|
|
822
|
+
Flag.optional,
|
|
823
|
+
Flag.withDescription("The legacy repository (defaults to the current directory)")
|
|
824
|
+
),
|
|
825
|
+
pack: Flag.String("pack").pipe(
|
|
826
|
+
Flag.optional,
|
|
827
|
+
Flag.withDescription("Pack name or directory (defaults to LLM4TS_PACK, then cobol-springboot)")
|
|
828
|
+
),
|
|
829
|
+
format: Flag.String("format").pipe(
|
|
830
|
+
Flag.withDefault("text"),
|
|
831
|
+
Flag.withDescription("text | json | mermaid | dot")
|
|
832
|
+
),
|
|
833
|
+
kind: Flag.String("kind").pipe(
|
|
834
|
+
Flag.optional,
|
|
835
|
+
Flag.withDescription("Only nodes of this kind (query)")
|
|
836
|
+
),
|
|
837
|
+
hops: Flag.String("hops").pipe(
|
|
838
|
+
Flag.withDefault("1"),
|
|
839
|
+
Flag.withDescription("Neighbourhood radius (query)")
|
|
840
|
+
),
|
|
841
|
+
max: Flag.String("max").pipe(
|
|
842
|
+
Flag.withDefault("12"),
|
|
843
|
+
Flag.withDescription("Max hops (path) or files (closure)")
|
|
844
|
+
),
|
|
845
|
+
all: Flag.Boolean("all").pipe(
|
|
846
|
+
Flag.withDefault(false),
|
|
847
|
+
Flag.withDescription("Render the whole estate instead of the neighbourhood")
|
|
848
|
+
),
|
|
849
|
+
force: Flag.Boolean("force").pipe(
|
|
850
|
+
Flag.withDefault(false),
|
|
851
|
+
Flag.withDescription("Render mermaid above the 150-node cap")
|
|
852
|
+
)
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const runGraph = (sub: GraphSubcommand, flags: GraphFlags) =>
|
|
856
|
+
Effect.gen(function* () {
|
|
857
|
+
const command = yield* graphCommandFrom(sub, flags)
|
|
858
|
+
yield* Console.log(
|
|
859
|
+
yield* makeGraphProgram(command, nodeGraphDependencies(process.env, shellTierPaths()))
|
|
860
|
+
)
|
|
861
|
+
})
|
|
862
|
+
|
|
863
|
+
const graphBuildCommand = Command.make("build", graphFlags, (flags) =>
|
|
864
|
+
runGraph("build", flags)
|
|
865
|
+
).pipe(
|
|
866
|
+
Command.withDescription(
|
|
867
|
+
"Scan the estate with the pack's rules and write .llm4ts/graph/<pack>.json"
|
|
868
|
+
)
|
|
869
|
+
)
|
|
870
|
+
const graphQueryCommand = Command.make(
|
|
871
|
+
"query",
|
|
872
|
+
{ text: Argument.String("text"), ...graphFlags },
|
|
873
|
+
(flags) => runGraph("query", flags)
|
|
874
|
+
).pipe(Command.withDescription("Nodes matching a text and their neighbourhood"))
|
|
875
|
+
const graphPathCommand = Command.make(
|
|
876
|
+
"path",
|
|
877
|
+
{ from: Argument.String("from"), to: Argument.String("to"), ...graphFlags },
|
|
878
|
+
(flags) => runGraph("path", flags)
|
|
879
|
+
).pipe(Command.withDescription("Shortest path between two node references, either direction"))
|
|
880
|
+
const graphClosureCommand = Command.make(
|
|
881
|
+
"closure",
|
|
882
|
+
{ program: Argument.String("program"), ...graphFlags },
|
|
883
|
+
(flags) => runGraph("closure", flags)
|
|
884
|
+
).pipe(Command.withDescription("A program's dependency closure as the analyst sees it"))
|
|
885
|
+
const graphStatsCommand = Command.make("stats", graphFlags, (flags) =>
|
|
886
|
+
runGraph("stats", flags)
|
|
887
|
+
).pipe(Command.withDescription("Nodes, edges, mechanisms, origins and unresolved items by kind"))
|
|
888
|
+
const graphProbeCommand = Command.make("probe", graphFlags, (flags) =>
|
|
889
|
+
runGraph("probe", flags)
|
|
890
|
+
).pipe(Command.withDescription("Evaluate the pack's '## Probe:' flows"))
|
|
891
|
+
|
|
892
|
+
const graphCommand = Command.make("graph", {}, () =>
|
|
893
|
+
Console.log("llm4ts graph <build|query|path|closure|stats|probe> --repo <legacy> [--pack <name>]")
|
|
894
|
+
).pipe(
|
|
895
|
+
Command.withDescription("The legacy estate's code graph (ADR 0030): build it, query it, draw it"),
|
|
896
|
+
Command.withSubcommands([
|
|
897
|
+
graphBuildCommand,
|
|
898
|
+
graphQueryCommand,
|
|
899
|
+
graphPathCommand,
|
|
900
|
+
graphClosureCommand,
|
|
901
|
+
graphStatsCommand,
|
|
902
|
+
graphProbeCommand
|
|
903
|
+
])
|
|
904
|
+
)
|
|
905
|
+
|
|
724
906
|
const doctorCommand = Command.make("doctor", {}, () =>
|
|
725
907
|
Effect.gen(function* () {
|
|
726
908
|
const report = yield* makeDoctorProgram()
|
|
@@ -751,6 +933,7 @@ export const shellCommand = Command.make("llm4ts", {}, () =>
|
|
|
751
933
|
costsCommand,
|
|
752
934
|
watchCommand,
|
|
753
935
|
profileCommand,
|
|
936
|
+
graphCommand,
|
|
754
937
|
rosterCommand,
|
|
755
938
|
doctorCommand
|
|
756
939
|
])
|