@llm4ts/runner 0.17.0 → 0.18.1
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/Kits.d.ts +67 -0
- package/dist/Kits.d.ts.map +1 -0
- package/dist/Kits.js +143 -0
- package/dist/Kits.js.map +1 -0
- package/dist/Packs.d.ts +42 -17
- package/dist/Packs.d.ts.map +1 -1
- package/dist/Packs.js +75 -35
- package/dist/Packs.js.map +1 -1
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/package.json +5 -3
- package/src/Kits.ts +198 -0
- package/src/Packs.ts +106 -45
- package/src/index.ts +46 -0
package/dist/Kits.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A kit is a directory bundling everything stack-specific the engine flows
|
|
3
|
+
* consume: `packs/<name>/pack.md` manifests, the `scaffolds/` they point at,
|
|
4
|
+
* a `patterns/` deck of translation cards, optional `flows/` of its own, and
|
|
5
|
+
* a `README.md` whose first paragraph is the kit's description (ADR 0014).
|
|
6
|
+
* Kits are discovered in the same three tiers as flows — the project's
|
|
7
|
+
* `.llm4ts/kits/`, the global `~/.config/llm4ts/kits/`, and the built-in
|
|
8
|
+
* kits shipped beside the engine flows — with project > global > builtin
|
|
9
|
+
* precedence by kit name.
|
|
10
|
+
*/
|
|
11
|
+
export type KitTier = "project" | "global" | "builtin";
|
|
12
|
+
export interface KitTierPaths {
|
|
13
|
+
readonly project?: string;
|
|
14
|
+
readonly global?: string;
|
|
15
|
+
readonly builtin?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DiscoveredKit {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
/** Absolute kit directory. */
|
|
20
|
+
readonly root: string;
|
|
21
|
+
readonly tier: KitTier;
|
|
22
|
+
readonly description?: string;
|
|
23
|
+
/** Pack names: every `packs/<name>/pack.md`. */
|
|
24
|
+
readonly packs: ReadonlyArray<string>;
|
|
25
|
+
/** Flow names: every `flows/<name>.ts|js` (not `lib/` or `test/`). */
|
|
26
|
+
readonly flows: ReadonlyArray<string>;
|
|
27
|
+
readonly shadows: ReadonlyArray<KitTier>;
|
|
28
|
+
}
|
|
29
|
+
export declare const kitTierPaths: (options: {
|
|
30
|
+
readonly cwd: string;
|
|
31
|
+
readonly homeDir: string;
|
|
32
|
+
readonly environment?: Readonly<Record<string, string | undefined>>;
|
|
33
|
+
readonly builtinDir?: string;
|
|
34
|
+
}) => KitTierPaths;
|
|
35
|
+
/**
|
|
36
|
+
* The built-in kits directory for a flow script: the `kits/` directory that
|
|
37
|
+
* sits beside the engine `flows/` — in a checkout `<repo>/kits`, in the
|
|
38
|
+
* published shell `<shell>/kits` — found by walking up from the flow's own
|
|
39
|
+
* directory. A kit's own flows live two levels deeper and resolve the same
|
|
40
|
+
* way. `undefined` when no `kits/` directory is within reach.
|
|
41
|
+
*/
|
|
42
|
+
export declare const builtinKitsDir: (flowDir: string) => string | undefined;
|
|
43
|
+
/** The first non-empty line after the README's `# ` title, without markup. */
|
|
44
|
+
export declare const parseKitDescription: (readme: string) => string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Discovers kits across the tiers. A directory is a kit when it holds at
|
|
47
|
+
* least one pack or one flow; missing tier directories contribute nothing.
|
|
48
|
+
*/
|
|
49
|
+
export declare const discoverKits: (paths: KitTierPaths) => ReadonlyArray<DiscoveredKit>;
|
|
50
|
+
export type PackLookup = {
|
|
51
|
+
readonly _tag: "Found";
|
|
52
|
+
readonly kit: DiscoveredKit;
|
|
53
|
+
readonly pack: string;
|
|
54
|
+
} | {
|
|
55
|
+
readonly _tag: "Ambiguous";
|
|
56
|
+
readonly candidates: ReadonlyArray<string>;
|
|
57
|
+
} | {
|
|
58
|
+
readonly _tag: "Absent";
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Resolves a pack name across discovered kits. `kit/pack` names one kit;
|
|
62
|
+
* a bare name is searched tier by tier (project, then global, then builtin)
|
|
63
|
+
* and is ambiguous only when two kits of the SAME tier both ship it — a
|
|
64
|
+
* project kit shadows a built-in one, exactly as flows do.
|
|
65
|
+
*/
|
|
66
|
+
export declare const findPack: (reference: string, kits: ReadonlyArray<DiscoveredKit>) => PackLookup;
|
|
67
|
+
//# sourceMappingURL=Kits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kits.d.ts","sourceRoot":"","sources":["../src/Kits.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CACzC;AAID,eAAO,MAAM,YAAY,GAAI,SAAS;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IACnE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B,KAAG,YAWH,CAAA;AAUD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SAczD,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,SAU7D,CAAA;AAyCD;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,YAAY,KAAG,aAAa,CAAC,aAAa,CAuB7E,CAAA;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE/B;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,MAAM,EAAE,MAAM,aAAa,CAAC,aAAa,CAAC,KAAG,UAoBhF,CAAA"}
|
package/dist/Kits.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
const tierOrder = ["project", "global", "builtin"];
|
|
4
|
+
export const kitTierPaths = (options) => {
|
|
5
|
+
const environment = options.environment ?? process.env;
|
|
6
|
+
const configHome = environment.XDG_CONFIG_HOME !== undefined && environment.XDG_CONFIG_HOME.length > 0
|
|
7
|
+
? environment.XDG_CONFIG_HOME
|
|
8
|
+
: join(options.homeDir, ".config");
|
|
9
|
+
return {
|
|
10
|
+
project: join(options.cwd, ".llm4ts", "kits"),
|
|
11
|
+
global: join(configHome, "llm4ts", "kits"),
|
|
12
|
+
...(options.builtinDir === undefined ? {} : { builtin: options.builtinDir })
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
const isDirectory = (path) => {
|
|
16
|
+
try {
|
|
17
|
+
return statSync(path).isDirectory();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The built-in kits directory for a flow script: the `kits/` directory that
|
|
25
|
+
* sits beside the engine `flows/` — in a checkout `<repo>/kits`, in the
|
|
26
|
+
* published shell `<shell>/kits` — found by walking up from the flow's own
|
|
27
|
+
* directory. A kit's own flows live two levels deeper and resolve the same
|
|
28
|
+
* way. `undefined` when no `kits/` directory is within reach.
|
|
29
|
+
*/
|
|
30
|
+
export const builtinKitsDir = (flowDir) => {
|
|
31
|
+
let directory = resolve(flowDir);
|
|
32
|
+
for (let depth = 0; depth < 4; depth += 1) {
|
|
33
|
+
const candidate = join(directory, "kits");
|
|
34
|
+
if (isDirectory(candidate)) {
|
|
35
|
+
return candidate;
|
|
36
|
+
}
|
|
37
|
+
const parent = dirname(directory);
|
|
38
|
+
if (parent === directory) {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
directory = parent;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
};
|
|
45
|
+
/** The first non-empty line after the README's `# ` title, without markup. */
|
|
46
|
+
export const parseKitDescription = (readme) => {
|
|
47
|
+
const lines = readme.split(/\r?\n/);
|
|
48
|
+
const start = lines.findIndex((line) => line.startsWith("# "));
|
|
49
|
+
for (const line of lines.slice(start + 1)) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (trimmed.length > 0 && !trimmed.startsWith("#")) {
|
|
52
|
+
return trimmed;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
};
|
|
57
|
+
const listDirectories = (path) => isDirectory(path)
|
|
58
|
+
? readdirSync(path)
|
|
59
|
+
.filter((entry) => isDirectory(join(path, entry)))
|
|
60
|
+
.sort()
|
|
61
|
+
: [];
|
|
62
|
+
const readKit = (name, root, tier) => {
|
|
63
|
+
const packs = listDirectories(join(root, "packs")).filter((pack) => existsSync(join(root, "packs", pack, "pack.md")));
|
|
64
|
+
const flowsDir = join(root, "flows");
|
|
65
|
+
const flows = isDirectory(flowsDir)
|
|
66
|
+
? readdirSync(flowsDir)
|
|
67
|
+
.filter((entry) => entry.endsWith(".ts") || entry.endsWith(".js"))
|
|
68
|
+
.map((entry) => entry.replace(/\.(ts|js)$/, ""))
|
|
69
|
+
.sort()
|
|
70
|
+
: [];
|
|
71
|
+
if (packs.length === 0 && flows.length === 0) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const readme = join(root, "README.md");
|
|
75
|
+
const description = existsSync(readme)
|
|
76
|
+
? parseKitDescription(readFileSync(readme, "utf8"))
|
|
77
|
+
: undefined;
|
|
78
|
+
return {
|
|
79
|
+
name,
|
|
80
|
+
root,
|
|
81
|
+
tier,
|
|
82
|
+
...(description === undefined ? {} : { description }),
|
|
83
|
+
packs,
|
|
84
|
+
flows
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Discovers kits across the tiers. A directory is a kit when it holds at
|
|
89
|
+
* least one pack or one flow; missing tier directories contribute nothing.
|
|
90
|
+
*/
|
|
91
|
+
export const discoverKits = (paths) => {
|
|
92
|
+
const byName = new Map();
|
|
93
|
+
for (const tier of tierOrder) {
|
|
94
|
+
const directory = paths[tier];
|
|
95
|
+
if (directory === undefined) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
for (const name of listDirectories(directory)) {
|
|
99
|
+
const kit = readKit(name, join(resolve(directory), name), tier);
|
|
100
|
+
if (kit === undefined) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const existing = byName.get(name);
|
|
104
|
+
if (existing === undefined) {
|
|
105
|
+
byName.set(name, { kit, shadows: [] });
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
existing.shadows.push(tier);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return [...byName.values()]
|
|
113
|
+
.map(({ kit, shadows }) => ({ ...kit, shadows }))
|
|
114
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Resolves a pack name across discovered kits. `kit/pack` names one kit;
|
|
118
|
+
* a bare name is searched tier by tier (project, then global, then builtin)
|
|
119
|
+
* and is ambiguous only when two kits of the SAME tier both ship it — a
|
|
120
|
+
* project kit shadows a built-in one, exactly as flows do.
|
|
121
|
+
*/
|
|
122
|
+
export const findPack = (reference, kits) => {
|
|
123
|
+
const slash = reference.indexOf("/");
|
|
124
|
+
if (slash > 0 && reference.indexOf("/", slash + 1) < 0) {
|
|
125
|
+
const kitName = reference.slice(0, slash);
|
|
126
|
+
const pack = reference.slice(slash + 1);
|
|
127
|
+
const kit = kits.find((candidate) => candidate.name === kitName);
|
|
128
|
+
return kit !== undefined && kit.packs.includes(pack)
|
|
129
|
+
? { _tag: "Found", kit, pack }
|
|
130
|
+
: { _tag: "Absent" };
|
|
131
|
+
}
|
|
132
|
+
for (const tier of tierOrder) {
|
|
133
|
+
const holders = kits.filter((kit) => kit.tier === tier && kit.packs.includes(reference));
|
|
134
|
+
if (holders.length === 1) {
|
|
135
|
+
return { _tag: "Found", kit: holders[0], pack: reference };
|
|
136
|
+
}
|
|
137
|
+
if (holders.length > 1) {
|
|
138
|
+
return { _tag: "Ambiguous", candidates: holders.map((kit) => `${kit.name}/${reference}`) };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { _tag: "Absent" };
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=Kits.js.map
|
package/dist/Kits.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kits.js","sourceRoot":"","sources":["../src/Kits.ts"],"names":[],"mappings":"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"}
|
package/dist/Packs.d.ts
CHANGED
|
@@ -4,51 +4,76 @@ import type { PlanParseError } from "@llm4ts/flow/FlowError";
|
|
|
4
4
|
import { type Pack } from "@llm4ts/flow/Pack";
|
|
5
5
|
import { type PatternCard } from "@llm4ts/flow/Patterns";
|
|
6
6
|
import type { WorkspaceError, WorkspaceShape } from "@llm4ts/flow/Workspace";
|
|
7
|
+
import { type DiscoveredKit, type KitTierPaths } from "./Kits.ts";
|
|
7
8
|
declare const PackNotFound_base: Schema.Class<PackNotFound, Schema.TaggedStruct<"PackNotFound", {
|
|
8
9
|
readonly message: Schema.String;
|
|
9
10
|
}>, import("effect/Cause").YieldableError>;
|
|
10
11
|
/**
|
|
11
12
|
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
12
|
-
* (default `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* the
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* (default `cobol-springboot`) in one of three forms:
|
|
14
|
+
*
|
|
15
|
+
* - a bare name (`cobol-springboot`) or `kit/pack` (`mainframe-java/cobol-springboot`),
|
|
16
|
+
* resolved across the kits discovered in the project, global, and built-in
|
|
17
|
+
* tiers (ADR 0014);
|
|
18
|
+
* - a path relative to the launch directory whose directory holds `pack.md`
|
|
19
|
+
* (`packs/my-pack`) — a pack still being written, not yet in a kit;
|
|
20
|
+
* - an absolute path to such a directory.
|
|
21
|
+
*
|
|
22
|
+
* The built-in tier is what lets `llm4ts run modernize-survey --repo <estate>`
|
|
23
|
+
* work from any directory instead of only from a checkout.
|
|
18
24
|
*/
|
|
19
25
|
export declare class PackNotFound extends PackNotFound_base {
|
|
20
26
|
}
|
|
21
27
|
export interface LocatedPack {
|
|
22
|
-
/** Directory the pack workspace is rooted at. */
|
|
28
|
+
/** Directory the pack workspace is rooted at: the kit, or the pack itself. */
|
|
23
29
|
readonly root: string;
|
|
24
|
-
/** Pack directory relative to `root` (`"."`
|
|
30
|
+
/** Pack directory relative to `root` (`"."` for a path-form pack). */
|
|
25
31
|
readonly dir: string;
|
|
32
|
+
/** The kit the pack came from; absent for a path-form pack. */
|
|
33
|
+
readonly kit?: DiscoveredKit;
|
|
26
34
|
}
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
export type PackLocation = ({
|
|
36
|
+
readonly _tag: "Located";
|
|
37
|
+
} & LocatedPack) | {
|
|
38
|
+
readonly _tag: "Ambiguous";
|
|
39
|
+
readonly candidates: ReadonlyArray<string>;
|
|
40
|
+
} | {
|
|
41
|
+
readonly _tag: "Absent";
|
|
42
|
+
};
|
|
43
|
+
/** Resolves a pack reference: absolute path, launch-relative path, then kits. */
|
|
44
|
+
export declare const locatePack: (reference: string, options: {
|
|
45
|
+
readonly launchDir: string;
|
|
46
|
+
readonly kits: ReadonlyArray<DiscoveredKit>;
|
|
47
|
+
}) => PackLocation;
|
|
29
48
|
export interface OpenedPack {
|
|
30
49
|
readonly pack: Pack;
|
|
31
50
|
/**
|
|
32
|
-
* Workspace rooted where the pack was found
|
|
33
|
-
*
|
|
34
|
-
*
|
|
51
|
+
* Workspace rooted where the pack was found — the kit for a kit pack, the
|
|
52
|
+
* pack directory itself otherwise. Pack-relative paths — prompts,
|
|
53
|
+
* `<pack>/patterns`, `lessons.md`, the scaffold — must resolve through
|
|
54
|
+
* this workspace, not the launch directory's.
|
|
35
55
|
*/
|
|
36
56
|
readonly workspace: WorkspaceShape;
|
|
37
57
|
/** Pack directory within `workspace`. */
|
|
38
58
|
readonly dir: string;
|
|
59
|
+
/** The kit the pack belongs to, when it came from one. */
|
|
60
|
+
readonly kit?: DiscoveredKit;
|
|
39
61
|
}
|
|
62
|
+
export declare const defaultPackName = "cobol-springboot";
|
|
40
63
|
export declare const openPack: (options: {
|
|
41
64
|
readonly environment: Readonly<Record<string, string | undefined>>;
|
|
42
65
|
/** The directory the flow was launched from (`resolveFlowInput().workspace`). */
|
|
43
66
|
readonly launchDir: string;
|
|
44
67
|
/** The directory holding the flow script (`import.meta.dirname`). */
|
|
45
68
|
readonly flowDir: string;
|
|
69
|
+
/** Kit tiers to search; defaults to the standard tiers around `launchDir` and `flowDir`. */
|
|
70
|
+
readonly kits?: KitTierPaths;
|
|
46
71
|
}) => Effect.Effect<OpenedPack, PlanParseError | WorkspaceError | PackNotFound, never>;
|
|
47
72
|
/**
|
|
48
|
-
* The
|
|
49
|
-
*
|
|
50
|
-
* patterns are
|
|
73
|
+
* The pattern cards of the kit the opened pack belongs to (`<kit>/patterns`);
|
|
74
|
+
* a path-form pack, or a kit without a deck, contributes none. Pack-local
|
|
75
|
+
* cards (`<pack>/patterns`) are loaded separately by the flows.
|
|
51
76
|
*/
|
|
52
|
-
export declare const
|
|
77
|
+
export declare const loadKitPatternCards: (opened: OpenedPack) => Effect.Effect<readonly PatternCard[], WorkspaceError, never>;
|
|
53
78
|
export {};
|
|
54
79
|
//# sourceMappingURL=Packs.d.ts.map
|
package/dist/Packs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Packs.d.ts","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Packs.d.ts","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAY,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5E,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,WAAW,CAAA;;;;AAGlB;;;;;;;;;;;;;GAaG;AAEH,qBAAa,YAAa,SAAQ,iBAEhC;CAAG;AAEL,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAA;CAC7B;AAED,MAAM,MAAM,YAAY,GACpB,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,WAAW,CAAC,GAC5C;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAI/B,iFAAiF;AACjF,eAAO,MAAM,UAAU,GACrB,WAAW,MAAM,EACjB,SAAS;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;CAAE,KACnF,YAwBF,CAAA;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;IAClC,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAA;CAC7B;AAED,eAAO,MAAM,eAAe,qBAAqB,CAAA;AAEjD,eAAO,MAAM,QAAQ;0BACG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,iFAAiF;wBAC7D,MAAM;IAC1B,qEAAqE;sBACnD,MAAM;IACxB,4FAA4F;oBAC5E,YAAY;sFAuC5B,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,sFAO9B,CAAA"}
|
package/dist/Packs.js
CHANGED
|
@@ -1,63 +1,103 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import { isAbsolute, join, resolve } from "node:path";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Schema from "effect/Schema";
|
|
5
6
|
import { loadPack } from "@llm4ts/flow/Pack";
|
|
6
7
|
import { loadPatternCards } from "@llm4ts/flow/Patterns";
|
|
8
|
+
import { builtinKitsDir, discoverKits, findPack, kitTierPaths } from "./Kits.js";
|
|
7
9
|
import { makeNodeWorkspace } from "./NodeWorkspace.js";
|
|
8
10
|
/**
|
|
9
11
|
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
10
|
-
* (default `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* (default `cobol-springboot`) in one of three forms:
|
|
13
|
+
*
|
|
14
|
+
* - a bare name (`cobol-springboot`) or `kit/pack` (`mainframe-java/cobol-springboot`),
|
|
15
|
+
* resolved across the kits discovered in the project, global, and built-in
|
|
16
|
+
* tiers (ADR 0014);
|
|
17
|
+
* - a path relative to the launch directory whose directory holds `pack.md`
|
|
18
|
+
* (`packs/my-pack`) — a pack still being written, not yet in a kit;
|
|
19
|
+
* - an absolute path to such a directory.
|
|
20
|
+
*
|
|
21
|
+
* The built-in tier is what lets `llm4ts run modernize-survey --repo <estate>`
|
|
22
|
+
* work from any directory instead of only from a checkout.
|
|
16
23
|
*/
|
|
17
24
|
export class PackNotFound extends Schema.TaggedErrorClass()("PackNotFound", {
|
|
18
25
|
message: Schema.String
|
|
19
26
|
}) {
|
|
20
27
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
const hasManifest = (directory) => existsSync(join(directory, "pack.md"));
|
|
29
|
+
/** Resolves a pack reference: absolute path, launch-relative path, then kits. */
|
|
30
|
+
export const locatePack = (reference, options) => {
|
|
31
|
+
if (isAbsolute(reference)) {
|
|
32
|
+
return hasManifest(reference)
|
|
33
|
+
? { _tag: "Located", root: reference, dir: "." }
|
|
34
|
+
: { _tag: "Absent" };
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
const launchDir = resolve(options.launchDir);
|
|
37
|
+
if (reference.includes("/") && hasManifest(join(launchDir, reference))) {
|
|
38
|
+
return { _tag: "Located", root: launchDir, dir: reference };
|
|
39
|
+
}
|
|
40
|
+
const lookup = findPack(reference, options.kits);
|
|
41
|
+
switch (lookup._tag) {
|
|
42
|
+
case "Found":
|
|
43
|
+
return {
|
|
44
|
+
_tag: "Located",
|
|
45
|
+
root: lookup.kit.root,
|
|
46
|
+
dir: join("packs", lookup.pack),
|
|
47
|
+
kit: lookup.kit
|
|
48
|
+
};
|
|
49
|
+
case "Ambiguous":
|
|
50
|
+
return lookup;
|
|
51
|
+
case "Absent":
|
|
52
|
+
return lookup;
|
|
31
53
|
}
|
|
32
|
-
return undefined;
|
|
33
54
|
};
|
|
55
|
+
export const defaultPackName = "cobol-springboot";
|
|
34
56
|
export const openPack = Effect.fn("@llm4ts/runner/Packs.openPack")(function* (options) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
57
|
+
const reference = options.environment.LLM4TS_PACK?.trim() || defaultPackName;
|
|
58
|
+
const builtinDir = builtinKitsDir(options.flowDir);
|
|
59
|
+
const tiers = options.kits ??
|
|
60
|
+
kitTierPaths({
|
|
61
|
+
cwd: options.launchDir,
|
|
62
|
+
homeDir: homedir(),
|
|
63
|
+
environment: options.environment,
|
|
64
|
+
...(builtinDir === undefined ? {} : { builtinDir })
|
|
65
|
+
});
|
|
66
|
+
const kits = discoverKits(tiers);
|
|
67
|
+
const location = locatePack(reference, { launchDir: options.launchDir, kits });
|
|
68
|
+
if (location._tag === "Ambiguous") {
|
|
69
|
+
return yield* PackNotFound.make({
|
|
70
|
+
message: `pack '${reference}' is shipped by more than one kit — ` +
|
|
71
|
+
`name one of: ${location.candidates.join(", ")}`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (location._tag === "Absent") {
|
|
75
|
+
const known = kits.flatMap((kit) => kit.packs.map((pack) => `${kit.name}/${pack}`));
|
|
38
76
|
return yield* PackNotFound.make({
|
|
39
|
-
message: `pack '${
|
|
40
|
-
|
|
41
|
-
|
|
77
|
+
message: `pack '${reference}' not found: no kit ships it` +
|
|
78
|
+
(known.length === 0 ? "" : ` (known packs: ${known.join(", ")})`) +
|
|
79
|
+
` and no ${join(reference, "pack.md")} exists under ${resolve(options.launchDir)} — ` +
|
|
80
|
+
"set LLM4TS_PACK to a kit pack name, a kit/pack name, or a directory holding pack.md"
|
|
42
81
|
});
|
|
43
82
|
}
|
|
44
|
-
const workspace = yield* makeNodeWorkspace(
|
|
45
|
-
const pack = yield* loadPack(workspace,
|
|
46
|
-
return {
|
|
83
|
+
const workspace = yield* makeNodeWorkspace(location.root);
|
|
84
|
+
const pack = yield* loadPack(workspace, location.dir);
|
|
85
|
+
return {
|
|
86
|
+
pack,
|
|
87
|
+
workspace,
|
|
88
|
+
dir: location.dir,
|
|
89
|
+
...(location.kit === undefined ? {} : { kit: location.kit })
|
|
90
|
+
};
|
|
47
91
|
});
|
|
48
92
|
/**
|
|
49
|
-
* The
|
|
50
|
-
*
|
|
51
|
-
* patterns are
|
|
93
|
+
* The pattern cards of the kit the opened pack belongs to (`<kit>/patterns`);
|
|
94
|
+
* a path-form pack, or a kit without a deck, contributes none. Pack-local
|
|
95
|
+
* cards (`<pack>/patterns`) are loaded separately by the flows.
|
|
52
96
|
*/
|
|
53
|
-
export const
|
|
54
|
-
|
|
55
|
-
.map((candidate) => resolve(candidate))
|
|
56
|
-
.find((candidate) => existsSync(join(candidate, "patterns")));
|
|
57
|
-
if (root === undefined) {
|
|
97
|
+
export const loadKitPatternCards = Effect.fn("@llm4ts/runner/Packs.loadKitPatternCards")(function* (opened) {
|
|
98
|
+
if (opened.kit === undefined || !existsSync(join(opened.kit.root, "patterns"))) {
|
|
58
99
|
return [];
|
|
59
100
|
}
|
|
60
|
-
|
|
61
|
-
return yield* loadPatternCards(workspace, "patterns");
|
|
101
|
+
return yield* loadPatternCards(opened.workspace, "patterns");
|
|
62
102
|
});
|
|
63
103
|
//# sourceMappingURL=Packs.js.map
|
package/dist/Packs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Packs.js","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAa,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAA;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAEtD
|
|
1
|
+
{"version":3,"file":"Packs.js","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow author's entry point: everything a flow script under
|
|
3
|
+
* `.llm4ts/flows/` reaches for, re-exported from the runner and flow
|
|
4
|
+
* subpaths so a script needs one import line. Nothing here is new API — the
|
|
5
|
+
* subpath exports stay the contract for everything else, and the list is
|
|
6
|
+
* exactly what the shipped flows use.
|
|
7
|
+
*/
|
|
8
|
+
export { runEmbedded, runFlowMain, runNode } from "./FlowRunner.ts";
|
|
9
|
+
export type { FlowRunnerOptions } from "./FlowRunner.ts";
|
|
10
|
+
export { resolveFlowInput, ScriptUsage } from "./FlowArgs.ts";
|
|
11
|
+
export type { FlowInput } from "./FlowArgs.ts";
|
|
12
|
+
export { apiConnectorFromEnvironment, asReadOnly, coderFor, coderFromEnv, mock, withModel, withTurnLimit } from "./Connectors.ts";
|
|
13
|
+
export { loadKitPatternCards, openPack, PackNotFound } from "./Packs.ts";
|
|
14
|
+
export type { OpenedPack } from "./Packs.ts";
|
|
15
|
+
export { nodePlainFileStore } from "./NodePlainFileStore.ts";
|
|
16
|
+
export { makeNodeWorkspace } from "./NodeWorkspace.ts";
|
|
17
|
+
export { nodeProcessExecutor } from "./NodeProcessExecutor.ts";
|
|
18
|
+
export { reviewFingerprint } from "./ReviewFingerprint.ts";
|
|
19
|
+
export { completeAndPublish, implementPlanFlow } from "@llm4ts/flow/Flow";
|
|
20
|
+
export type { ImplementPlanOptions } from "@llm4ts/flow/Flow";
|
|
21
|
+
export type { FlowContextShape } from "@llm4ts/flow/FlowContext";
|
|
22
|
+
export { implementTaskLoop, stage } from "@llm4ts/flow/PlanExecution";
|
|
23
|
+
export { lintCommand, mergeReviewResults, minimalReviewers, reviewAndFixLoop, ReviewResult } from "@llm4ts/flow/Review";
|
|
24
|
+
export { Reviewer } from "@llm4ts/flow/Reviewer";
|
|
25
|
+
export { makeChat } from "@llm4ts/flow/Chat";
|
|
26
|
+
export { makePlanStore } from "@llm4ts/flow/Persistence";
|
|
27
|
+
export { defaultPlanInstructions, planFrom, writeBrief } from "@llm4ts/flow/Planner";
|
|
28
|
+
export { defaultPlanPath, parsePlan, Plan } from "@llm4ts/flow/Plan";
|
|
29
|
+
export { AssistantMessage, Info } from "@llm4ts/flow/FlowEvents";
|
|
30
|
+
export { FlowAborted, FlowLlmError } from "@llm4ts/flow/FlowError";
|
|
31
|
+
export { loadPack } from "@llm4ts/flow/Pack";
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACnE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC7D,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EACL,2BAA2B,EAC3B,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,aAAa,EACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACzE,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACpF,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow author's entry point: everything a flow script under
|
|
3
|
+
* `.llm4ts/flows/` reaches for, re-exported from the runner and flow
|
|
4
|
+
* subpaths so a script needs one import line. Nothing here is new API — the
|
|
5
|
+
* subpath exports stay the contract for everything else, and the list is
|
|
6
|
+
* exactly what the shipped flows use.
|
|
7
|
+
*/
|
|
8
|
+
export { runEmbedded, runFlowMain, runNode } from "./FlowRunner.js";
|
|
9
|
+
export { resolveFlowInput, ScriptUsage } from "./FlowArgs.js";
|
|
10
|
+
export { apiConnectorFromEnvironment, asReadOnly, coderFor, coderFromEnv, mock, withModel, withTurnLimit } from "./Connectors.js";
|
|
11
|
+
export { loadKitPatternCards, openPack, PackNotFound } from "./Packs.js";
|
|
12
|
+
export { nodePlainFileStore } from "./NodePlainFileStore.js";
|
|
13
|
+
export { makeNodeWorkspace } from "./NodeWorkspace.js";
|
|
14
|
+
export { nodeProcessExecutor } from "./NodeProcessExecutor.js";
|
|
15
|
+
export { reviewFingerprint } from "./ReviewFingerprint.js";
|
|
16
|
+
export { completeAndPublish, implementPlanFlow } from "@llm4ts/flow/Flow";
|
|
17
|
+
export { implementTaskLoop, stage } from "@llm4ts/flow/PlanExecution";
|
|
18
|
+
export { lintCommand, mergeReviewResults, minimalReviewers, reviewAndFixLoop, ReviewResult } from "@llm4ts/flow/Review";
|
|
19
|
+
export { Reviewer } from "@llm4ts/flow/Reviewer";
|
|
20
|
+
export { makeChat } from "@llm4ts/flow/Chat";
|
|
21
|
+
export { makePlanStore } from "@llm4ts/flow/Persistence";
|
|
22
|
+
export { defaultPlanInstructions, planFrom, writeBrief } from "@llm4ts/flow/Planner";
|
|
23
|
+
export { defaultPlanPath, parsePlan, Plan } from "@llm4ts/flow/Plan";
|
|
24
|
+
export { AssistantMessage, Info } from "@llm4ts/flow/FlowEvents";
|
|
25
|
+
export { FlowAborted, FlowLlmError } from "@llm4ts/flow/FlowError";
|
|
26
|
+
export { loadPack } from "@llm4ts/flow/Pack";
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEnE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE7D,OAAO,EACL,2BAA2B,EAC3B,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,IAAI,EACJ,SAAS,EACT,aAAa,EACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAExE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAGzE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACpF,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llm4ts/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "Node runner, CLI, terminal, and MCP composition for llm4ts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"exports": {
|
|
16
|
+
".": "./dist/index.js",
|
|
16
17
|
"./Cli": "./dist/Cli.js",
|
|
17
18
|
"./CoderPolicy": "./dist/CoderPolicy.js",
|
|
18
19
|
"./Connectors": "./dist/Connectors.js",
|
|
19
20
|
"./Doctor": "./dist/Doctor.js",
|
|
20
21
|
"./FlowArgs": "./dist/FlowArgs.js",
|
|
21
22
|
"./FlowRunner": "./dist/FlowRunner.js",
|
|
23
|
+
"./Kits": "./dist/Kits.js",
|
|
22
24
|
"./McpStdio": "./dist/McpStdio.js",
|
|
23
25
|
"./NodeHttpClient": "./dist/NodeHttpClient.js",
|
|
24
26
|
"./NodeGeminiCliExecutor": "./dist/NodeGeminiCliExecutor.js",
|
|
@@ -57,8 +59,8 @@
|
|
|
57
59
|
"typescript"
|
|
58
60
|
],
|
|
59
61
|
"dependencies": {
|
|
60
|
-
"@llm4ts/
|
|
61
|
-
"@llm4ts/
|
|
62
|
+
"@llm4ts/core": "0.18.1",
|
|
63
|
+
"@llm4ts/flow": "0.18.1"
|
|
62
64
|
},
|
|
63
65
|
"peerDependencies": {
|
|
64
66
|
"effect": "4.0.0-beta.102"
|
package/src/Kits.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"
|
|
2
|
+
import { dirname, join, resolve } from "node:path"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A kit is a directory bundling everything stack-specific the engine flows
|
|
6
|
+
* consume: `packs/<name>/pack.md` manifests, the `scaffolds/` they point at,
|
|
7
|
+
* a `patterns/` deck of translation cards, optional `flows/` of its own, and
|
|
8
|
+
* a `README.md` whose first paragraph is the kit's description (ADR 0014).
|
|
9
|
+
* Kits are discovered in the same three tiers as flows — the project's
|
|
10
|
+
* `.llm4ts/kits/`, the global `~/.config/llm4ts/kits/`, and the built-in
|
|
11
|
+
* kits shipped beside the engine flows — with project > global > builtin
|
|
12
|
+
* precedence by kit name.
|
|
13
|
+
*/
|
|
14
|
+
export type KitTier = "project" | "global" | "builtin"
|
|
15
|
+
|
|
16
|
+
export interface KitTierPaths {
|
|
17
|
+
readonly project?: string
|
|
18
|
+
readonly global?: string
|
|
19
|
+
readonly builtin?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface DiscoveredKit {
|
|
23
|
+
readonly name: string
|
|
24
|
+
/** Absolute kit directory. */
|
|
25
|
+
readonly root: string
|
|
26
|
+
readonly tier: KitTier
|
|
27
|
+
readonly description?: string
|
|
28
|
+
/** Pack names: every `packs/<name>/pack.md`. */
|
|
29
|
+
readonly packs: ReadonlyArray<string>
|
|
30
|
+
/** Flow names: every `flows/<name>.ts|js` (not `lib/` or `test/`). */
|
|
31
|
+
readonly flows: ReadonlyArray<string>
|
|
32
|
+
readonly shadows: ReadonlyArray<KitTier>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const tierOrder: ReadonlyArray<KitTier> = ["project", "global", "builtin"]
|
|
36
|
+
|
|
37
|
+
export const kitTierPaths = (options: {
|
|
38
|
+
readonly cwd: string
|
|
39
|
+
readonly homeDir: string
|
|
40
|
+
readonly environment?: Readonly<Record<string, string | undefined>>
|
|
41
|
+
readonly builtinDir?: string
|
|
42
|
+
}): KitTierPaths => {
|
|
43
|
+
const environment = options.environment ?? process.env
|
|
44
|
+
const configHome =
|
|
45
|
+
environment.XDG_CONFIG_HOME !== undefined && environment.XDG_CONFIG_HOME.length > 0
|
|
46
|
+
? environment.XDG_CONFIG_HOME
|
|
47
|
+
: join(options.homeDir, ".config")
|
|
48
|
+
return {
|
|
49
|
+
project: join(options.cwd, ".llm4ts", "kits"),
|
|
50
|
+
global: join(configHome, "llm4ts", "kits"),
|
|
51
|
+
...(options.builtinDir === undefined ? {} : { builtin: options.builtinDir })
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isDirectory = (path: string): boolean => {
|
|
56
|
+
try {
|
|
57
|
+
return statSync(path).isDirectory()
|
|
58
|
+
} catch {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The built-in kits directory for a flow script: the `kits/` directory that
|
|
65
|
+
* sits beside the engine `flows/` — in a checkout `<repo>/kits`, in the
|
|
66
|
+
* published shell `<shell>/kits` — found by walking up from the flow's own
|
|
67
|
+
* directory. A kit's own flows live two levels deeper and resolve the same
|
|
68
|
+
* way. `undefined` when no `kits/` directory is within reach.
|
|
69
|
+
*/
|
|
70
|
+
export const builtinKitsDir = (flowDir: string): string | undefined => {
|
|
71
|
+
let directory = resolve(flowDir)
|
|
72
|
+
for (let depth = 0; depth < 4; depth += 1) {
|
|
73
|
+
const candidate = join(directory, "kits")
|
|
74
|
+
if (isDirectory(candidate)) {
|
|
75
|
+
return candidate
|
|
76
|
+
}
|
|
77
|
+
const parent = dirname(directory)
|
|
78
|
+
if (parent === directory) {
|
|
79
|
+
break
|
|
80
|
+
}
|
|
81
|
+
directory = parent
|
|
82
|
+
}
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The first non-empty line after the README's `# ` title, without markup. */
|
|
87
|
+
export const parseKitDescription = (readme: string): string | undefined => {
|
|
88
|
+
const lines = readme.split(/\r?\n/)
|
|
89
|
+
const start = lines.findIndex((line) => line.startsWith("# "))
|
|
90
|
+
for (const line of lines.slice(start + 1)) {
|
|
91
|
+
const trimmed = line.trim()
|
|
92
|
+
if (trimmed.length > 0 && !trimmed.startsWith("#")) {
|
|
93
|
+
return trimmed
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return undefined
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const listDirectories = (path: string): ReadonlyArray<string> =>
|
|
100
|
+
isDirectory(path)
|
|
101
|
+
? readdirSync(path)
|
|
102
|
+
.filter((entry) => isDirectory(join(path, entry)))
|
|
103
|
+
.sort()
|
|
104
|
+
: []
|
|
105
|
+
|
|
106
|
+
const readKit = (
|
|
107
|
+
name: string,
|
|
108
|
+
root: string,
|
|
109
|
+
tier: KitTier
|
|
110
|
+
): Omit<DiscoveredKit, "shadows"> | undefined => {
|
|
111
|
+
const packs = listDirectories(join(root, "packs")).filter((pack) =>
|
|
112
|
+
existsSync(join(root, "packs", pack, "pack.md"))
|
|
113
|
+
)
|
|
114
|
+
const flowsDir = join(root, "flows")
|
|
115
|
+
const flows = isDirectory(flowsDir)
|
|
116
|
+
? readdirSync(flowsDir)
|
|
117
|
+
.filter((entry) => entry.endsWith(".ts") || entry.endsWith(".js"))
|
|
118
|
+
.map((entry) => entry.replace(/\.(ts|js)$/, ""))
|
|
119
|
+
.sort()
|
|
120
|
+
: []
|
|
121
|
+
if (packs.length === 0 && flows.length === 0) {
|
|
122
|
+
return undefined
|
|
123
|
+
}
|
|
124
|
+
const readme = join(root, "README.md")
|
|
125
|
+
const description = existsSync(readme)
|
|
126
|
+
? parseKitDescription(readFileSync(readme, "utf8"))
|
|
127
|
+
: undefined
|
|
128
|
+
return {
|
|
129
|
+
name,
|
|
130
|
+
root,
|
|
131
|
+
tier,
|
|
132
|
+
...(description === undefined ? {} : { description }),
|
|
133
|
+
packs,
|
|
134
|
+
flows
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Discovers kits across the tiers. A directory is a kit when it holds at
|
|
140
|
+
* least one pack or one flow; missing tier directories contribute nothing.
|
|
141
|
+
*/
|
|
142
|
+
export const discoverKits = (paths: KitTierPaths): ReadonlyArray<DiscoveredKit> => {
|
|
143
|
+
const byName = new Map<string, { kit: Omit<DiscoveredKit, "shadows">; shadows: Array<KitTier> }>()
|
|
144
|
+
for (const tier of tierOrder) {
|
|
145
|
+
const directory = paths[tier]
|
|
146
|
+
if (directory === undefined) {
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
for (const name of listDirectories(directory)) {
|
|
150
|
+
const kit = readKit(name, join(resolve(directory), name), tier)
|
|
151
|
+
if (kit === undefined) {
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
const existing = byName.get(name)
|
|
155
|
+
if (existing === undefined) {
|
|
156
|
+
byName.set(name, { kit, shadows: [] })
|
|
157
|
+
} else {
|
|
158
|
+
existing.shadows.push(tier)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return [...byName.values()]
|
|
163
|
+
.map(({ kit, shadows }): DiscoveredKit => ({ ...kit, shadows }))
|
|
164
|
+
.sort((left, right) => left.name.localeCompare(right.name))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export type PackLookup =
|
|
168
|
+
| { readonly _tag: "Found"; readonly kit: DiscoveredKit; readonly pack: string }
|
|
169
|
+
| { readonly _tag: "Ambiguous"; readonly candidates: ReadonlyArray<string> }
|
|
170
|
+
| { readonly _tag: "Absent" }
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Resolves a pack name across discovered kits. `kit/pack` names one kit;
|
|
174
|
+
* a bare name is searched tier by tier (project, then global, then builtin)
|
|
175
|
+
* and is ambiguous only when two kits of the SAME tier both ship it — a
|
|
176
|
+
* project kit shadows a built-in one, exactly as flows do.
|
|
177
|
+
*/
|
|
178
|
+
export const findPack = (reference: string, kits: ReadonlyArray<DiscoveredKit>): PackLookup => {
|
|
179
|
+
const slash = reference.indexOf("/")
|
|
180
|
+
if (slash > 0 && reference.indexOf("/", slash + 1) < 0) {
|
|
181
|
+
const kitName = reference.slice(0, slash)
|
|
182
|
+
const pack = reference.slice(slash + 1)
|
|
183
|
+
const kit = kits.find((candidate) => candidate.name === kitName)
|
|
184
|
+
return kit !== undefined && kit.packs.includes(pack)
|
|
185
|
+
? { _tag: "Found", kit, pack }
|
|
186
|
+
: { _tag: "Absent" }
|
|
187
|
+
}
|
|
188
|
+
for (const tier of tierOrder) {
|
|
189
|
+
const holders = kits.filter((kit) => kit.tier === tier && kit.packs.includes(reference))
|
|
190
|
+
if (holders.length === 1) {
|
|
191
|
+
return { _tag: "Found", kit: holders[0]!, pack: reference }
|
|
192
|
+
}
|
|
193
|
+
if (holders.length > 1) {
|
|
194
|
+
return { _tag: "Ambiguous", candidates: holders.map((kit) => `${kit.name}/${reference}`) }
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { _tag: "Absent" }
|
|
198
|
+
}
|
package/src/Packs.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
|
+
import { homedir } from "node:os"
|
|
2
3
|
import { isAbsolute, join, resolve } from "node:path"
|
|
3
4
|
import * as Effect from "effect/Effect"
|
|
4
5
|
import * as Schema from "effect/Schema"
|
|
@@ -6,16 +7,29 @@ import type { PlanParseError } from "@llm4ts/flow/FlowError"
|
|
|
6
7
|
import { loadPack, type Pack } from "@llm4ts/flow/Pack"
|
|
7
8
|
import { loadPatternCards, type PatternCard } from "@llm4ts/flow/Patterns"
|
|
8
9
|
import type { WorkspaceError, WorkspaceShape } from "@llm4ts/flow/Workspace"
|
|
10
|
+
import {
|
|
11
|
+
builtinKitsDir,
|
|
12
|
+
discoverKits,
|
|
13
|
+
findPack,
|
|
14
|
+
kitTierPaths,
|
|
15
|
+
type DiscoveredKit,
|
|
16
|
+
type KitTierPaths
|
|
17
|
+
} from "./Kits.ts"
|
|
9
18
|
import { makeNodeWorkspace } from "./NodeWorkspace.ts"
|
|
10
19
|
|
|
11
20
|
/**
|
|
12
21
|
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
13
|
-
* (default `
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
22
|
+
* (default `cobol-springboot`) in one of three forms:
|
|
23
|
+
*
|
|
24
|
+
* - a bare name (`cobol-springboot`) or `kit/pack` (`mainframe-java/cobol-springboot`),
|
|
25
|
+
* resolved across the kits discovered in the project, global, and built-in
|
|
26
|
+
* tiers (ADR 0014);
|
|
27
|
+
* - a path relative to the launch directory whose directory holds `pack.md`
|
|
28
|
+
* (`packs/my-pack`) — a pack still being written, not yet in a kit;
|
|
29
|
+
* - an absolute path to such a directory.
|
|
30
|
+
*
|
|
31
|
+
* The built-in tier is what lets `llm4ts run modernize-survey --repo <estate>`
|
|
32
|
+
* work from any directory instead of only from a checkout.
|
|
19
33
|
*/
|
|
20
34
|
|
|
21
35
|
export class PackNotFound extends Schema.TaggedErrorClass<PackNotFound>()("PackNotFound", {
|
|
@@ -23,79 +37,126 @@ export class PackNotFound extends Schema.TaggedErrorClass<PackNotFound>()("PackN
|
|
|
23
37
|
}) {}
|
|
24
38
|
|
|
25
39
|
export interface LocatedPack {
|
|
26
|
-
/** Directory the pack workspace is rooted at. */
|
|
40
|
+
/** Directory the pack workspace is rooted at: the kit, or the pack itself. */
|
|
27
41
|
readonly root: string
|
|
28
|
-
/** Pack directory relative to `root` (`"."`
|
|
42
|
+
/** Pack directory relative to `root` (`"."` for a path-form pack). */
|
|
29
43
|
readonly dir: string
|
|
44
|
+
/** The kit the pack came from; absent for a path-form pack. */
|
|
45
|
+
readonly kit?: DiscoveredKit
|
|
30
46
|
}
|
|
31
47
|
|
|
32
|
-
|
|
48
|
+
export type PackLocation =
|
|
49
|
+
| ({ readonly _tag: "Located" } & LocatedPack)
|
|
50
|
+
| { readonly _tag: "Ambiguous"; readonly candidates: ReadonlyArray<string> }
|
|
51
|
+
| { readonly _tag: "Absent" }
|
|
52
|
+
|
|
53
|
+
const hasManifest = (directory: string): boolean => existsSync(join(directory, "pack.md"))
|
|
54
|
+
|
|
55
|
+
/** Resolves a pack reference: absolute path, launch-relative path, then kits. */
|
|
33
56
|
export const locatePack = (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
):
|
|
37
|
-
if (isAbsolute(
|
|
38
|
-
return
|
|
57
|
+
reference: string,
|
|
58
|
+
options: { readonly launchDir: string; readonly kits: ReadonlyArray<DiscoveredKit> }
|
|
59
|
+
): PackLocation => {
|
|
60
|
+
if (isAbsolute(reference)) {
|
|
61
|
+
return hasManifest(reference)
|
|
62
|
+
? { _tag: "Located", root: reference, dir: "." }
|
|
63
|
+
: { _tag: "Absent" }
|
|
64
|
+
}
|
|
65
|
+
const launchDir = resolve(options.launchDir)
|
|
66
|
+
if (reference.includes("/") && hasManifest(join(launchDir, reference))) {
|
|
67
|
+
return { _tag: "Located", root: launchDir, dir: reference }
|
|
39
68
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
|
|
69
|
+
const lookup = findPack(reference, options.kits)
|
|
70
|
+
switch (lookup._tag) {
|
|
71
|
+
case "Found":
|
|
72
|
+
return {
|
|
73
|
+
_tag: "Located",
|
|
74
|
+
root: lookup.kit.root,
|
|
75
|
+
dir: join("packs", lookup.pack),
|
|
76
|
+
kit: lookup.kit
|
|
77
|
+
}
|
|
78
|
+
case "Ambiguous":
|
|
79
|
+
return lookup
|
|
80
|
+
case "Absent":
|
|
81
|
+
return lookup
|
|
45
82
|
}
|
|
46
|
-
return undefined
|
|
47
83
|
}
|
|
48
84
|
|
|
49
85
|
export interface OpenedPack {
|
|
50
86
|
readonly pack: Pack
|
|
51
87
|
/**
|
|
52
|
-
* Workspace rooted where the pack was found
|
|
53
|
-
*
|
|
54
|
-
*
|
|
88
|
+
* Workspace rooted where the pack was found — the kit for a kit pack, the
|
|
89
|
+
* pack directory itself otherwise. Pack-relative paths — prompts,
|
|
90
|
+
* `<pack>/patterns`, `lessons.md`, the scaffold — must resolve through
|
|
91
|
+
* this workspace, not the launch directory's.
|
|
55
92
|
*/
|
|
56
93
|
readonly workspace: WorkspaceShape
|
|
57
94
|
/** Pack directory within `workspace`. */
|
|
58
95
|
readonly dir: string
|
|
96
|
+
/** The kit the pack belongs to, when it came from one. */
|
|
97
|
+
readonly kit?: DiscoveredKit
|
|
59
98
|
}
|
|
60
99
|
|
|
100
|
+
export const defaultPackName = "cobol-springboot"
|
|
101
|
+
|
|
61
102
|
export const openPack = Effect.fn("@llm4ts/runner/Packs.openPack")(function* (options: {
|
|
62
103
|
readonly environment: Readonly<Record<string, string | undefined>>
|
|
63
104
|
/** The directory the flow was launched from (`resolveFlowInput().workspace`). */
|
|
64
105
|
readonly launchDir: string
|
|
65
106
|
/** The directory holding the flow script (`import.meta.dirname`). */
|
|
66
107
|
readonly flowDir: string
|
|
108
|
+
/** Kit tiers to search; defaults to the standard tiers around `launchDir` and `flowDir`. */
|
|
109
|
+
readonly kits?: KitTierPaths
|
|
67
110
|
}): Effect.fn.Return<OpenedPack, PackNotFound | WorkspaceError | PlanParseError> {
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
111
|
+
const reference = options.environment.LLM4TS_PACK?.trim() || defaultPackName
|
|
112
|
+
const builtinDir = builtinKitsDir(options.flowDir)
|
|
113
|
+
const tiers =
|
|
114
|
+
options.kits ??
|
|
115
|
+
kitTierPaths({
|
|
116
|
+
cwd: options.launchDir,
|
|
117
|
+
homeDir: homedir(),
|
|
118
|
+
environment: options.environment,
|
|
119
|
+
...(builtinDir === undefined ? {} : { builtinDir })
|
|
120
|
+
})
|
|
121
|
+
const kits = discoverKits(tiers)
|
|
122
|
+
const location = locatePack(reference, { launchDir: options.launchDir, kits })
|
|
123
|
+
if (location._tag === "Ambiguous") {
|
|
71
124
|
return yield* PackNotFound.make({
|
|
72
125
|
message:
|
|
73
|
-
`pack '${
|
|
74
|
-
|
|
75
|
-
"set LLM4TS_PACK or launch from a directory containing the pack"
|
|
126
|
+
`pack '${reference}' is shipped by more than one kit — ` +
|
|
127
|
+
`name one of: ${location.candidates.join(", ")}`
|
|
76
128
|
})
|
|
77
129
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
130
|
+
if (location._tag === "Absent") {
|
|
131
|
+
const known = kits.flatMap((kit) => kit.packs.map((pack) => `${kit.name}/${pack}`))
|
|
132
|
+
return yield* PackNotFound.make({
|
|
133
|
+
message:
|
|
134
|
+
`pack '${reference}' not found: no kit ships it` +
|
|
135
|
+
(known.length === 0 ? "" : ` (known packs: ${known.join(", ")})`) +
|
|
136
|
+
` and no ${join(reference, "pack.md")} exists under ${resolve(options.launchDir)} — ` +
|
|
137
|
+
"set LLM4TS_PACK to a kit pack name, a kit/pack name, or a directory holding pack.md"
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
const workspace = yield* makeNodeWorkspace(location.root)
|
|
141
|
+
const pack = yield* loadPack(workspace, location.dir)
|
|
142
|
+
return {
|
|
143
|
+
pack,
|
|
144
|
+
workspace,
|
|
145
|
+
dir: location.dir,
|
|
146
|
+
...(location.kit === undefined ? {} : { kit: location.kit })
|
|
147
|
+
}
|
|
81
148
|
})
|
|
82
149
|
|
|
83
150
|
/**
|
|
84
|
-
* The
|
|
85
|
-
*
|
|
86
|
-
* patterns are
|
|
151
|
+
* The pattern cards of the kit the opened pack belongs to (`<kit>/patterns`);
|
|
152
|
+
* a path-form pack, or a kit without a deck, contributes none. Pack-local
|
|
153
|
+
* cards (`<pack>/patterns`) are loaded separately by the flows.
|
|
87
154
|
*/
|
|
88
|
-
export const
|
|
89
|
-
|
|
90
|
-
)(function* (
|
|
91
|
-
roots: ReadonlyArray<string>
|
|
155
|
+
export const loadKitPatternCards = Effect.fn("@llm4ts/runner/Packs.loadKitPatternCards")(function* (
|
|
156
|
+
opened: OpenedPack
|
|
92
157
|
): Effect.fn.Return<ReadonlyArray<PatternCard>, WorkspaceError> {
|
|
93
|
-
|
|
94
|
-
.map((candidate) => resolve(candidate))
|
|
95
|
-
.find((candidate) => existsSync(join(candidate, "patterns")))
|
|
96
|
-
if (root === undefined) {
|
|
158
|
+
if (opened.kit === undefined || !existsSync(join(opened.kit.root, "patterns"))) {
|
|
97
159
|
return []
|
|
98
160
|
}
|
|
99
|
-
|
|
100
|
-
return yield* loadPatternCards(workspace, "patterns")
|
|
161
|
+
return yield* loadPatternCards(opened.workspace, "patterns")
|
|
101
162
|
})
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow author's entry point: everything a flow script under
|
|
3
|
+
* `.llm4ts/flows/` reaches for, re-exported from the runner and flow
|
|
4
|
+
* subpaths so a script needs one import line. Nothing here is new API — the
|
|
5
|
+
* subpath exports stay the contract for everything else, and the list is
|
|
6
|
+
* exactly what the shipped flows use.
|
|
7
|
+
*/
|
|
8
|
+
export { runEmbedded, runFlowMain, runNode } from "./FlowRunner.ts"
|
|
9
|
+
export type { FlowRunnerOptions } from "./FlowRunner.ts"
|
|
10
|
+
export { resolveFlowInput, ScriptUsage } from "./FlowArgs.ts"
|
|
11
|
+
export type { FlowInput } from "./FlowArgs.ts"
|
|
12
|
+
export {
|
|
13
|
+
apiConnectorFromEnvironment,
|
|
14
|
+
asReadOnly,
|
|
15
|
+
coderFor,
|
|
16
|
+
coderFromEnv,
|
|
17
|
+
mock,
|
|
18
|
+
withModel,
|
|
19
|
+
withTurnLimit
|
|
20
|
+
} from "./Connectors.ts"
|
|
21
|
+
export { loadKitPatternCards, openPack, PackNotFound } from "./Packs.ts"
|
|
22
|
+
export type { OpenedPack } from "./Packs.ts"
|
|
23
|
+
export { nodePlainFileStore } from "./NodePlainFileStore.ts"
|
|
24
|
+
export { makeNodeWorkspace } from "./NodeWorkspace.ts"
|
|
25
|
+
export { nodeProcessExecutor } from "./NodeProcessExecutor.ts"
|
|
26
|
+
export { reviewFingerprint } from "./ReviewFingerprint.ts"
|
|
27
|
+
|
|
28
|
+
export { completeAndPublish, implementPlanFlow } from "@llm4ts/flow/Flow"
|
|
29
|
+
export type { ImplementPlanOptions } from "@llm4ts/flow/Flow"
|
|
30
|
+
export type { FlowContextShape } from "@llm4ts/flow/FlowContext"
|
|
31
|
+
export { implementTaskLoop, stage } from "@llm4ts/flow/PlanExecution"
|
|
32
|
+
export {
|
|
33
|
+
lintCommand,
|
|
34
|
+
mergeReviewResults,
|
|
35
|
+
minimalReviewers,
|
|
36
|
+
reviewAndFixLoop,
|
|
37
|
+
ReviewResult
|
|
38
|
+
} from "@llm4ts/flow/Review"
|
|
39
|
+
export { Reviewer } from "@llm4ts/flow/Reviewer"
|
|
40
|
+
export { makeChat } from "@llm4ts/flow/Chat"
|
|
41
|
+
export { makePlanStore } from "@llm4ts/flow/Persistence"
|
|
42
|
+
export { defaultPlanInstructions, planFrom, writeBrief } from "@llm4ts/flow/Planner"
|
|
43
|
+
export { defaultPlanPath, parsePlan, Plan } from "@llm4ts/flow/Plan"
|
|
44
|
+
export { AssistantMessage, Info } from "@llm4ts/flow/FlowEvents"
|
|
45
|
+
export { FlowAborted, FlowLlmError } from "@llm4ts/flow/FlowError"
|
|
46
|
+
export { loadPack } from "@llm4ts/flow/Pack"
|