@llm4ts/runner 0.4.0 → 0.6.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/Packs.d.ts +54 -0
- package/dist/Packs.d.ts.map +1 -0
- package/dist/Packs.js +63 -0
- package/dist/Packs.js.map +1 -0
- package/package.json +4 -3
- package/src/Packs.ts +101 -0
package/dist/Packs.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import type { PlanParseError } from "@llm4ts/flow/FlowError";
|
|
4
|
+
import { type Pack } from "@llm4ts/flow/Pack";
|
|
5
|
+
import { type PatternCard } from "@llm4ts/flow/Patterns";
|
|
6
|
+
import type { WorkspaceError, WorkspaceShape } from "@llm4ts/flow/Workspace";
|
|
7
|
+
declare const PackNotFound_base: Schema.Class<PackNotFound, Schema.TaggedStruct<"PackNotFound", {
|
|
8
|
+
readonly message: Schema.String;
|
|
9
|
+
}>, import("effect/Cause").YieldableError>;
|
|
10
|
+
/**
|
|
11
|
+
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
12
|
+
* (default `packs/cobol-springboot`) and is resolved against the launch
|
|
13
|
+
* directory first — a pack the user keeps next to their work wins — then
|
|
14
|
+
* against the flow script's own directory, where the published shell ships
|
|
15
|
+
* the built-in packs. An absolute `LLM4TS_PACK` is used as-is. The fallback
|
|
16
|
+
* is what lets `llm4ts run modernize-survey --repo <estate>` work from any
|
|
17
|
+
* directory instead of only from a checkout with `packs/` at its cwd.
|
|
18
|
+
*/
|
|
19
|
+
export declare class PackNotFound extends PackNotFound_base {
|
|
20
|
+
}
|
|
21
|
+
export interface LocatedPack {
|
|
22
|
+
/** Directory the pack workspace is rooted at. */
|
|
23
|
+
readonly root: string;
|
|
24
|
+
/** Pack directory relative to `root` (`"."` when the pack path is absolute). */
|
|
25
|
+
readonly dir: string;
|
|
26
|
+
}
|
|
27
|
+
/** The first candidate root whose `packDir` holds a `pack.md` manifest. */
|
|
28
|
+
export declare const locatePack: (packDir: string, roots: ReadonlyArray<string>) => LocatedPack | undefined;
|
|
29
|
+
export interface OpenedPack {
|
|
30
|
+
readonly pack: Pack;
|
|
31
|
+
/**
|
|
32
|
+
* Workspace rooted where the pack was found. Pack-relative paths — prompts,
|
|
33
|
+
* `<pack>/patterns`, `lessons.md`, the scaffold — must resolve through this
|
|
34
|
+
* workspace, not the launch directory's.
|
|
35
|
+
*/
|
|
36
|
+
readonly workspace: WorkspaceShape;
|
|
37
|
+
/** Pack directory within `workspace`. */
|
|
38
|
+
readonly dir: string;
|
|
39
|
+
}
|
|
40
|
+
export declare const openPack: (options: {
|
|
41
|
+
readonly environment: Readonly<Record<string, string | undefined>>;
|
|
42
|
+
/** The directory the flow was launched from (`resolveFlowInput().workspace`). */
|
|
43
|
+
readonly launchDir: string;
|
|
44
|
+
/** The directory holding the flow script (`import.meta.dirname`). */
|
|
45
|
+
readonly flowDir: string;
|
|
46
|
+
}) => Effect.Effect<OpenedPack, PlanParseError | WorkspaceError | PackNotFound, never>;
|
|
47
|
+
/**
|
|
48
|
+
* The universal pattern cards: the first candidate root with a `patterns/`
|
|
49
|
+
* directory contributes them, and no root having one is an empty set —
|
|
50
|
+
* patterns are optional everywhere.
|
|
51
|
+
*/
|
|
52
|
+
export declare const loadUniversalPatternCards: (roots: readonly string[]) => Effect.Effect<readonly PatternCard[], WorkspaceError, never>;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=Packs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Packs.d.ts","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"AAEA,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;;;;AAG5E;;;;;;;;GAQG;AAEH,qBAAa,YAAa,SAAQ,iBAEhC;CAAG;AAEL,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,2EAA2E;AAC3E,eAAO,MAAM,UAAU,GACrB,SAAS,MAAM,EACf,OAAO,aAAa,CAAC,MAAM,CAAC,KAC3B,WAAW,GAAG,SAWhB,CAAA;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;IAClC,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,QAAQ;0BACG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,iFAAiF;wBAC7D,MAAM;IAC1B,qEAAqE;sBACnD,MAAM;sFAexB,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,4FAapC,CAAA"}
|
package/dist/Packs.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import { loadPack } from "@llm4ts/flow/Pack";
|
|
6
|
+
import { loadPatternCards } from "@llm4ts/flow/Patterns";
|
|
7
|
+
import { makeNodeWorkspace } from "./NodeWorkspace.js";
|
|
8
|
+
/**
|
|
9
|
+
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
10
|
+
* (default `packs/cobol-springboot`) and is resolved against the launch
|
|
11
|
+
* directory first — a pack the user keeps next to their work wins — then
|
|
12
|
+
* against the flow script's own directory, where the published shell ships
|
|
13
|
+
* the built-in packs. An absolute `LLM4TS_PACK` is used as-is. The fallback
|
|
14
|
+
* is what lets `llm4ts run modernize-survey --repo <estate>` work from any
|
|
15
|
+
* directory instead of only from a checkout with `packs/` at its cwd.
|
|
16
|
+
*/
|
|
17
|
+
export class PackNotFound extends Schema.TaggedErrorClass()("PackNotFound", {
|
|
18
|
+
message: Schema.String
|
|
19
|
+
}) {
|
|
20
|
+
}
|
|
21
|
+
/** The first candidate root whose `packDir` holds a `pack.md` manifest. */
|
|
22
|
+
export const locatePack = (packDir, roots) => {
|
|
23
|
+
if (isAbsolute(packDir)) {
|
|
24
|
+
return existsSync(join(packDir, "pack.md")) ? { root: packDir, dir: "." } : undefined;
|
|
25
|
+
}
|
|
26
|
+
for (const root of roots) {
|
|
27
|
+
const resolved = resolve(root);
|
|
28
|
+
if (existsSync(join(resolved, packDir, "pack.md"))) {
|
|
29
|
+
return { root: resolved, dir: packDir };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
};
|
|
34
|
+
export const openPack = Effect.fn("@llm4ts/runner/Packs.openPack")(function* (options) {
|
|
35
|
+
const packDir = options.environment.LLM4TS_PACK ?? "packs/cobol-springboot";
|
|
36
|
+
const located = locatePack(packDir, [options.launchDir, options.flowDir]);
|
|
37
|
+
if (located === undefined) {
|
|
38
|
+
return yield* PackNotFound.make({
|
|
39
|
+
message: `pack '${packDir}' not found: no ${join(packDir, "pack.md")} under ` +
|
|
40
|
+
`${resolve(options.launchDir)} or ${resolve(options.flowDir)} — ` +
|
|
41
|
+
"set LLM4TS_PACK or launch from a directory containing the pack"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const workspace = yield* makeNodeWorkspace(located.root);
|
|
45
|
+
const pack = yield* loadPack(workspace, located.dir);
|
|
46
|
+
return { pack, workspace, dir: located.dir };
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* The universal pattern cards: the first candidate root with a `patterns/`
|
|
50
|
+
* directory contributes them, and no root having one is an empty set —
|
|
51
|
+
* patterns are optional everywhere.
|
|
52
|
+
*/
|
|
53
|
+
export const loadUniversalPatternCards = Effect.fn("@llm4ts/runner/Packs.loadUniversalPatternCards")(function* (roots) {
|
|
54
|
+
const root = roots
|
|
55
|
+
.map((candidate) => resolve(candidate))
|
|
56
|
+
.find((candidate) => existsSync(join(candidate, "patterns")));
|
|
57
|
+
if (root === undefined) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const workspace = yield* makeNodeWorkspace(root);
|
|
61
|
+
return yield* loadPatternCards(workspace, "patterns");
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=Packs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Packs.js","sourceRoot":"","sources":["../src/Packs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llm4ts/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Node runner, CLI, terminal, and MCP composition for llm4ts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"./NodeTemporaryFiles": "./dist/NodeTemporaryFiles.js",
|
|
28
28
|
"./NodeWorkspace": "./dist/NodeWorkspace.js",
|
|
29
29
|
"./NodeRuntime": "./dist/NodeRuntime.js",
|
|
30
|
+
"./Packs": "./dist/Packs.js",
|
|
30
31
|
"./ReviewFingerprint": "./dist/ReviewFingerprint.js",
|
|
31
32
|
"./Terminal": "./dist/Terminal.js",
|
|
32
33
|
"./TerminalInteraction": "./dist/TerminalInteraction.js",
|
|
@@ -55,8 +56,8 @@
|
|
|
55
56
|
"typescript"
|
|
56
57
|
],
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@llm4ts/
|
|
59
|
-
"@llm4ts/
|
|
59
|
+
"@llm4ts/flow": "0.6.0",
|
|
60
|
+
"@llm4ts/core": "0.6.0"
|
|
60
61
|
},
|
|
61
62
|
"peerDependencies": {
|
|
62
63
|
"effect": "^4.0.0-beta.102"
|
package/src/Packs.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { isAbsolute, join, resolve } from "node:path"
|
|
3
|
+
import * as Effect from "effect/Effect"
|
|
4
|
+
import * as Schema from "effect/Schema"
|
|
5
|
+
import type { PlanParseError } from "@llm4ts/flow/FlowError"
|
|
6
|
+
import { loadPack, type Pack } from "@llm4ts/flow/Pack"
|
|
7
|
+
import { loadPatternCards, type PatternCard } from "@llm4ts/flow/Patterns"
|
|
8
|
+
import type { WorkspaceError, WorkspaceShape } from "@llm4ts/flow/Workspace"
|
|
9
|
+
import { makeNodeWorkspace } from "./NodeWorkspace.ts"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pack location for the modernization flows. `LLM4TS_PACK` names the pack
|
|
13
|
+
* (default `packs/cobol-springboot`) and is resolved against the launch
|
|
14
|
+
* directory first — a pack the user keeps next to their work wins — then
|
|
15
|
+
* against the flow script's own directory, where the published shell ships
|
|
16
|
+
* the built-in packs. An absolute `LLM4TS_PACK` is used as-is. The fallback
|
|
17
|
+
* is what lets `llm4ts run modernize-survey --repo <estate>` work from any
|
|
18
|
+
* directory instead of only from a checkout with `packs/` at its cwd.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export class PackNotFound extends Schema.TaggedErrorClass<PackNotFound>()("PackNotFound", {
|
|
22
|
+
message: Schema.String
|
|
23
|
+
}) {}
|
|
24
|
+
|
|
25
|
+
export interface LocatedPack {
|
|
26
|
+
/** Directory the pack workspace is rooted at. */
|
|
27
|
+
readonly root: string
|
|
28
|
+
/** Pack directory relative to `root` (`"."` when the pack path is absolute). */
|
|
29
|
+
readonly dir: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The first candidate root whose `packDir` holds a `pack.md` manifest. */
|
|
33
|
+
export const locatePack = (
|
|
34
|
+
packDir: string,
|
|
35
|
+
roots: ReadonlyArray<string>
|
|
36
|
+
): LocatedPack | undefined => {
|
|
37
|
+
if (isAbsolute(packDir)) {
|
|
38
|
+
return existsSync(join(packDir, "pack.md")) ? { root: packDir, dir: "." } : undefined
|
|
39
|
+
}
|
|
40
|
+
for (const root of roots) {
|
|
41
|
+
const resolved = resolve(root)
|
|
42
|
+
if (existsSync(join(resolved, packDir, "pack.md"))) {
|
|
43
|
+
return { root: resolved, dir: packDir }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface OpenedPack {
|
|
50
|
+
readonly pack: Pack
|
|
51
|
+
/**
|
|
52
|
+
* Workspace rooted where the pack was found. Pack-relative paths — prompts,
|
|
53
|
+
* `<pack>/patterns`, `lessons.md`, the scaffold — must resolve through this
|
|
54
|
+
* workspace, not the launch directory's.
|
|
55
|
+
*/
|
|
56
|
+
readonly workspace: WorkspaceShape
|
|
57
|
+
/** Pack directory within `workspace`. */
|
|
58
|
+
readonly dir: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const openPack = Effect.fn("@llm4ts/runner/Packs.openPack")(function* (options: {
|
|
62
|
+
readonly environment: Readonly<Record<string, string | undefined>>
|
|
63
|
+
/** The directory the flow was launched from (`resolveFlowInput().workspace`). */
|
|
64
|
+
readonly launchDir: string
|
|
65
|
+
/** The directory holding the flow script (`import.meta.dirname`). */
|
|
66
|
+
readonly flowDir: string
|
|
67
|
+
}): Effect.fn.Return<OpenedPack, PackNotFound | WorkspaceError | PlanParseError> {
|
|
68
|
+
const packDir = options.environment.LLM4TS_PACK ?? "packs/cobol-springboot"
|
|
69
|
+
const located = locatePack(packDir, [options.launchDir, options.flowDir])
|
|
70
|
+
if (located === undefined) {
|
|
71
|
+
return yield* PackNotFound.make({
|
|
72
|
+
message:
|
|
73
|
+
`pack '${packDir}' not found: no ${join(packDir, "pack.md")} under ` +
|
|
74
|
+
`${resolve(options.launchDir)} or ${resolve(options.flowDir)} — ` +
|
|
75
|
+
"set LLM4TS_PACK or launch from a directory containing the pack"
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
const workspace = yield* makeNodeWorkspace(located.root)
|
|
79
|
+
const pack = yield* loadPack(workspace, located.dir)
|
|
80
|
+
return { pack, workspace, dir: located.dir }
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The universal pattern cards: the first candidate root with a `patterns/`
|
|
85
|
+
* directory contributes them, and no root having one is an empty set —
|
|
86
|
+
* patterns are optional everywhere.
|
|
87
|
+
*/
|
|
88
|
+
export const loadUniversalPatternCards = Effect.fn(
|
|
89
|
+
"@llm4ts/runner/Packs.loadUniversalPatternCards"
|
|
90
|
+
)(function* (
|
|
91
|
+
roots: ReadonlyArray<string>
|
|
92
|
+
): Effect.fn.Return<ReadonlyArray<PatternCard>, WorkspaceError> {
|
|
93
|
+
const root = roots
|
|
94
|
+
.map((candidate) => resolve(candidate))
|
|
95
|
+
.find((candidate) => existsSync(join(candidate, "patterns")))
|
|
96
|
+
if (root === undefined) {
|
|
97
|
+
return []
|
|
98
|
+
}
|
|
99
|
+
const workspace = yield* makeNodeWorkspace(root)
|
|
100
|
+
return yield* loadPatternCards(workspace, "patterns")
|
|
101
|
+
})
|