@llm4ts/runner 0.1.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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/Cli.d.ts +5 -0
  4. package/dist/Cli.d.ts.map +1 -0
  5. package/dist/Cli.js +36 -0
  6. package/dist/Cli.js.map +1 -0
  7. package/dist/CoderPolicy.d.ts +12 -0
  8. package/dist/CoderPolicy.d.ts.map +1 -0
  9. package/dist/CoderPolicy.js +59 -0
  10. package/dist/CoderPolicy.js.map +1 -0
  11. package/dist/Connectors.d.ts +28 -0
  12. package/dist/Connectors.d.ts.map +1 -0
  13. package/dist/Connectors.js +165 -0
  14. package/dist/Connectors.js.map +1 -0
  15. package/dist/Doctor.d.ts +4 -0
  16. package/dist/Doctor.d.ts.map +1 -0
  17. package/dist/Doctor.js +33 -0
  18. package/dist/Doctor.js.map +1 -0
  19. package/dist/FlowArgs.d.ts +34 -0
  20. package/dist/FlowArgs.d.ts.map +1 -0
  21. package/dist/FlowArgs.js +136 -0
  22. package/dist/FlowArgs.js.map +1 -0
  23. package/dist/FlowRunner.d.ts +48 -0
  24. package/dist/FlowRunner.d.ts.map +1 -0
  25. package/dist/FlowRunner.js +97 -0
  26. package/dist/FlowRunner.js.map +1 -0
  27. package/dist/McpStdio.d.ts +7 -0
  28. package/dist/McpStdio.d.ts.map +1 -0
  29. package/dist/McpStdio.js +19 -0
  30. package/dist/McpStdio.js.map +1 -0
  31. package/dist/NodeGeminiCliExecutor.d.ts +7 -0
  32. package/dist/NodeGeminiCliExecutor.d.ts.map +1 -0
  33. package/dist/NodeGeminiCliExecutor.js +26 -0
  34. package/dist/NodeGeminiCliExecutor.js.map +1 -0
  35. package/dist/NodeHttpClient.d.ts +5 -0
  36. package/dist/NodeHttpClient.d.ts.map +1 -0
  37. package/dist/NodeHttpClient.js +109 -0
  38. package/dist/NodeHttpClient.js.map +1 -0
  39. package/dist/NodePlainFileStore.d.ts +5 -0
  40. package/dist/NodePlainFileStore.d.ts.map +1 -0
  41. package/dist/NodePlainFileStore.js +64 -0
  42. package/dist/NodePlainFileStore.js.map +1 -0
  43. package/dist/NodeProcessExecutor.d.ts +5 -0
  44. package/dist/NodeProcessExecutor.d.ts.map +1 -0
  45. package/dist/NodeProcessExecutor.js +212 -0
  46. package/dist/NodeProcessExecutor.js.map +1 -0
  47. package/dist/NodeRuntime.d.ts +4 -0
  48. package/dist/NodeRuntime.d.ts.map +1 -0
  49. package/dist/NodeRuntime.js +11 -0
  50. package/dist/NodeRuntime.js.map +1 -0
  51. package/dist/NodeTemporaryFiles.d.ts +5 -0
  52. package/dist/NodeTemporaryFiles.d.ts.map +1 -0
  53. package/dist/NodeTemporaryFiles.js +30 -0
  54. package/dist/NodeTemporaryFiles.js.map +1 -0
  55. package/dist/NodeWorkspace.d.ts +6 -0
  56. package/dist/NodeWorkspace.d.ts.map +1 -0
  57. package/dist/NodeWorkspace.js +231 -0
  58. package/dist/NodeWorkspace.js.map +1 -0
  59. package/dist/Package.d.ts +2 -0
  60. package/dist/Package.d.ts.map +1 -0
  61. package/dist/Package.js +2 -0
  62. package/dist/Package.js.map +1 -0
  63. package/dist/ReviewFingerprint.d.ts +2 -0
  64. package/dist/ReviewFingerprint.d.ts.map +1 -0
  65. package/dist/ReviewFingerprint.js +13 -0
  66. package/dist/ReviewFingerprint.js.map +1 -0
  67. package/dist/Terminal.d.ts +46 -0
  68. package/dist/Terminal.d.ts.map +1 -0
  69. package/dist/Terminal.js +226 -0
  70. package/dist/Terminal.js.map +1 -0
  71. package/dist/TerminalInteraction.d.ts +4 -0
  72. package/dist/TerminalInteraction.d.ts.map +1 -0
  73. package/dist/TerminalInteraction.js +25 -0
  74. package/dist/TerminalInteraction.js.map +1 -0
  75. package/dist/cli-main.d.ts +3 -0
  76. package/dist/cli-main.d.ts.map +1 -0
  77. package/dist/cli-main.js +39 -0
  78. package/dist/cli-main.js.map +1 -0
  79. package/package.json +74 -0
  80. package/src/Cli.ts +51 -0
  81. package/src/CoderPolicy.ts +82 -0
  82. package/src/Connectors.ts +225 -0
  83. package/src/Doctor.ts +44 -0
  84. package/src/FlowArgs.ts +167 -0
  85. package/src/FlowRunner.ts +220 -0
  86. package/src/McpStdio.ts +41 -0
  87. package/src/NodeGeminiCliExecutor.ts +56 -0
  88. package/src/NodeHttpClient.ts +224 -0
  89. package/src/NodePlainFileStore.ts +75 -0
  90. package/src/NodeProcessExecutor.ts +331 -0
  91. package/src/NodeRuntime.ts +19 -0
  92. package/src/NodeTemporaryFiles.ts +46 -0
  93. package/src/NodeWorkspace.ts +282 -0
  94. package/src/Package.ts +1 -0
  95. package/src/ReviewFingerprint.ts +13 -0
  96. package/src/Terminal.ts +329 -0
  97. package/src/TerminalInteraction.ts +43 -0
  98. package/src/cli-main.ts +53 -0
@@ -0,0 +1,46 @@
1
+ import type * as Duration from "effect/Duration";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Ref from "effect/Ref";
4
+ import type * as Scope from "effect/Scope";
5
+ import * as Schema from "effect/Schema";
6
+ import type { FlowEvent, FlowEventHub } from "@llm4ts/flow/FlowEvents";
7
+ export declare const Verbosity: Schema.Literals<readonly ["Quiet", "Normal", "Verbose", "Debug"]>;
8
+ export type Verbosity = typeof Verbosity.Type;
9
+ export declare const parseVerbosity: (value: string | undefined) => Verbosity;
10
+ export declare const rendersEvent: (verbosity: Verbosity, event: FlowEvent) => boolean;
11
+ export declare const terminalSafe: (value: string) => string;
12
+ export interface TerminalPalette {
13
+ readonly enabled: boolean;
14
+ readonly stageStart: (label: string) => string;
15
+ readonly stageDone: (label: string) => string;
16
+ readonly fail: (label: string) => string;
17
+ readonly info: (label: string) => string;
18
+ readonly assistant: (text: string) => string;
19
+ readonly toolCall: (tool: string, args: string) => string;
20
+ readonly status: (frame: string, label: string) => string;
21
+ }
22
+ export declare const makeTerminalPalette: (enabled: boolean) => TerminalPalette;
23
+ export declare const plainTerminalPalette: TerminalPalette;
24
+ export declare const terminalLine: (event: FlowEvent, palette?: TerminalPalette) => string;
25
+ export declare const indentBlock: (depth: number, rendered: string) => string;
26
+ export declare const indentDepths: (events: ReadonlyArray<FlowEvent>) => ReadonlyArray<number>;
27
+ export interface TerminalSurface {
28
+ readonly palette: TerminalPalette;
29
+ readonly log: (line: string) => Effect.Effect<void>;
30
+ readonly setStatus: (label: string | undefined) => Effect.Effect<void>;
31
+ readonly suspend: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
32
+ }
33
+ export declare const makePlainTerminalSurface: (write?: (line: string) => void) => TerminalSurface;
34
+ export interface TerminalOutput {
35
+ readonly isTTY?: boolean;
36
+ readonly write: (text: string) => unknown;
37
+ }
38
+ export declare const terminalSupportsColor: (output: TerminalOutput, environment: Readonly<Record<string, string | undefined>>) => boolean;
39
+ export declare const makeLiveTerminalSurface: (write?: ((text: string) => void) | undefined, palette?: TerminalPalette | undefined, tick?: Duration.Input | undefined) => Effect.Effect<TerminalSurface, never, Scope.Scope>;
40
+ export declare const makeTerminalSurface: (environment?: Readonly<Record<string, string | undefined>>, output?: TerminalOutput) => Effect.Effect<TerminalSurface, never, Scope.Scope>;
41
+ export interface TerminalConsumer {
42
+ readonly consumed: Ref.Ref<number>;
43
+ readonly awaitDrained: (timeout?: Duration.Input) => Effect.Effect<void>;
44
+ }
45
+ export declare const consumeTerminalEvents: (events: FlowEventHub, surface: TerminalSurface, verbosity?: "Debug" | "Quiet" | "Normal" | "Verbose" | undefined) => Effect.Effect<TerminalConsumer, never, Scope.Scope>;
46
+ //# sourceMappingURL=Terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Terminal.d.ts","sourceRoot":"","sources":["../src/Terminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Ref from "effect/Ref";
3
+ import * as Semaphore from "effect/Semaphore";
4
+ import * as Schema from "effect/Schema";
5
+ import * as Stream from "effect/Stream";
6
+ export const Verbosity = Schema.Literals(["Quiet", "Normal", "Verbose", "Debug"]);
7
+ export const parseVerbosity = (value) => {
8
+ switch (value?.trim().toLowerCase()) {
9
+ case "quiet":
10
+ return "Quiet";
11
+ case "verbose":
12
+ return "Verbose";
13
+ case "debug":
14
+ return "Debug";
15
+ default:
16
+ return "Normal";
17
+ }
18
+ };
19
+ export const rendersEvent = (verbosity, event) => {
20
+ switch (event._tag) {
21
+ case "StageStarted":
22
+ case "StageCompleted":
23
+ case "StageFailed":
24
+ case "Aborted":
25
+ case "CapabilityDenied":
26
+ case "CapabilityUnenforceable":
27
+ return true;
28
+ case "TokensUsed":
29
+ return verbosity === "Verbose" || verbosity === "Debug";
30
+ default:
31
+ return verbosity !== "Quiet";
32
+ }
33
+ };
34
+ export const terminalSafe = (value) => {
35
+ let safe = "";
36
+ for (let index = 0; index < value.length; index += 1) {
37
+ const code = value.charCodeAt(index);
38
+ const escapedCsi = code === 27 && value.charAt(index + 1) === "[";
39
+ if (escapedCsi || code === 155) {
40
+ index += escapedCsi ? 2 : 1;
41
+ while (index < value.length) {
42
+ const terminator = value.charCodeAt(index);
43
+ if (terminator >= 64 && terminator <= 126) {
44
+ break;
45
+ }
46
+ index += 1;
47
+ }
48
+ continue;
49
+ }
50
+ const escapedOsc = code === 27 && value.charAt(index + 1) === "]";
51
+ if (escapedOsc || code === 157) {
52
+ index += escapedOsc ? 2 : 1;
53
+ while (index < value.length) {
54
+ const current = value.charCodeAt(index);
55
+ if (current === 7) {
56
+ break;
57
+ }
58
+ if (current === 27 && value.charAt(index + 1) === "\\") {
59
+ index += 1;
60
+ break;
61
+ }
62
+ index += 1;
63
+ }
64
+ continue;
65
+ }
66
+ const allowedWhitespace = code === 9 || code === 10 || code === 13;
67
+ if (allowedWhitespace || (code >= 32 && !(code >= 127 && code <= 159))) {
68
+ safe += value.charAt(index);
69
+ }
70
+ }
71
+ return safe;
72
+ };
73
+ const Ansi = Object.freeze({
74
+ reset: "\u001b[0m",
75
+ boldMagenta: "\u001b[1;35m",
76
+ green: "\u001b[32m",
77
+ red: "\u001b[31m",
78
+ yellowBold: "\u001b[1;33m",
79
+ darkGray: "\u001b[90m"
80
+ });
81
+ export const makeTerminalPalette = (enabled) => {
82
+ const paint = (code, text) => enabled ? `${code}${text}${Ansi.reset}` : text;
83
+ return {
84
+ enabled,
85
+ stageStart: (label) => `${paint(Ansi.boldMagenta, "▶ ")}${label}`,
86
+ stageDone: (label) => `${paint(Ansi.green, "✔ ")}${label}`,
87
+ fail: (label) => `${paint(Ansi.red, "✖ ")}${label}`,
88
+ info: (label) => paint(Ansi.darkGray, `· ${label}`),
89
+ assistant: (text) => `${paint(Ansi.boldMagenta, "● ")}${text}`,
90
+ toolCall: (tool, args) => {
91
+ const head = paint(Ansi.yellowBold, `● ${tool}`);
92
+ return args.length === 0 ? head : `${head} ${paint(Ansi.darkGray, args)}`;
93
+ },
94
+ status: (frame, label) => `${paint(Ansi.boldMagenta, frame)} ${label}`
95
+ };
96
+ };
97
+ export const plainTerminalPalette = makeTerminalPalette(false);
98
+ export const terminalLine = (event, palette = plainTerminalPalette) => {
99
+ const safe = terminalSafe;
100
+ switch (event._tag) {
101
+ case "StageStarted":
102
+ return palette.stageStart(safe(event.stage));
103
+ case "StageCompleted":
104
+ return palette.stageDone(safe(event.stage));
105
+ case "StageFailed":
106
+ return palette.fail(`${safe(event.stage)} — ${safe(event.message)}`);
107
+ case "Aborted":
108
+ return palette.fail(`aborted: ${safe(event.message)}`);
109
+ case "Info":
110
+ return palette.info(safe(event.message));
111
+ case "ToolUse":
112
+ return palette.toolCall(safe(event.tool), safe(event.args));
113
+ case "AssistantMessage":
114
+ return palette.assistant(safe(event.text).trim());
115
+ case "TokensUsed":
116
+ return palette.info(`tokens: ${safe(event.agent)} ${event.usage.prompt} in / ${event.usage.completion} out`);
117
+ case "CapabilityUsed":
118
+ return palette.info(`capability ${safe(event.capability)}: ${safe(event.operation)}`);
119
+ case "CapabilityDenied":
120
+ return palette.fail(`capability denied: ${safe(event.capability)} for ${safe(event.operation)}`);
121
+ case "CapabilityUnenforceable":
122
+ return palette.fail(`capability unenforceable: ${safe(event.detail)}`);
123
+ case "Declassified":
124
+ return palette.info(`declassified: ${safe(event.label)}`);
125
+ }
126
+ };
127
+ export const indentBlock = (depth, rendered) => {
128
+ const padding = " ".repeat(Math.max(0, depth));
129
+ const lines = rendered.split("\n");
130
+ return lines.map((line, index) => `${padding}${index === 0 ? "" : " "}${line}`).join("\n");
131
+ };
132
+ const closesChild = (event) => event._tag === "StageCompleted" || event._tag === "StageFailed" || event._tag === "Aborted";
133
+ export const indentDepths = (events) => {
134
+ let depth = 0;
135
+ return events.map((event) => {
136
+ if (closesChild(event)) {
137
+ depth = Math.max(0, depth - 1);
138
+ return depth;
139
+ }
140
+ const current = depth;
141
+ if (event._tag === "StageStarted") {
142
+ depth += 1;
143
+ }
144
+ return current;
145
+ });
146
+ };
147
+ export const makePlainTerminalSurface = (write = (line) => process.stdout.write(`${line}\n`)) => ({
148
+ palette: plainTerminalPalette,
149
+ log: (line) => Effect.sync(() => write(line)),
150
+ setStatus: (_label) => Effect.void,
151
+ suspend: (effect) => effect
152
+ });
153
+ const spinnerFrames = Object.freeze(["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]);
154
+ const clearLine = "\r\u001b[2K";
155
+ export const terminalSupportsColor = (output, environment) => output.isTTY === true && environment.NO_COLOR === undefined;
156
+ export const makeLiveTerminalSurface = Effect.fn("@llm4ts/runner/Terminal.makeLive")(function* (write = (text) => {
157
+ process.stdout.write(text);
158
+ }, palette = makeTerminalPalette(true), tick = "100 millis") {
159
+ const lock = yield* Semaphore.make(1);
160
+ const status = yield* Ref.make(undefined);
161
+ const frame = yield* Ref.make(0);
162
+ const suspended = yield* Ref.make(false);
163
+ const emit = (text) => Effect.sync(() => write(text));
164
+ const drawStatus = Effect.gen(function* () {
165
+ if (yield* Ref.get(suspended)) {
166
+ return;
167
+ }
168
+ const label = yield* Ref.get(status);
169
+ if (label !== undefined) {
170
+ const currentFrame = yield* Ref.get(frame);
171
+ yield* emit(`${clearLine}${palette.status(spinnerFrames[currentFrame % spinnerFrames.length], label)}`);
172
+ }
173
+ });
174
+ const surface = {
175
+ palette,
176
+ log: (line) => lock.withPermit(emit(clearLine).pipe(Effect.andThen(emit(`${line}\n`)), Effect.andThen(drawStatus))),
177
+ setStatus: (label) => lock.withPermit(Ref.set(status, label).pipe(Effect.andThen(emit(clearLine)), Effect.andThen(drawStatus))),
178
+ suspend: (effect) => lock
179
+ .withPermit(Ref.set(suspended, true).pipe(Effect.andThen(emit(clearLine))))
180
+ .pipe(Effect.andThen(effect), Effect.ensuring(lock.withPermit(Ref.set(suspended, false).pipe(Effect.andThen(drawStatus)))))
181
+ };
182
+ yield* Effect.sleep(tick).pipe(Effect.andThen(Ref.update(frame, (current) => current + 1)), Effect.andThen(lock.withPermit(drawStatus)), Effect.forever, Effect.forkScoped);
183
+ yield* Effect.addFinalizer(() => lock.withPermit(emit(clearLine)));
184
+ return surface;
185
+ });
186
+ export const makeTerminalSurface = (environment = process.env, output = process.stdout) => {
187
+ const write = (text) => {
188
+ output.write(text);
189
+ };
190
+ return terminalSupportsColor(output, environment)
191
+ ? makeLiveTerminalSurface(write)
192
+ : Effect.succeed(makePlainTerminalSurface((line) => write(`${line}\n`)));
193
+ };
194
+ export const consumeTerminalEvents = Effect.fn("@llm4ts/runner/Terminal.consume")(function* (events, surface, verbosity = "Normal") {
195
+ const depth = yield* Ref.make(0);
196
+ const stages = yield* Ref.make([]);
197
+ const consumed = yield* Ref.make(0);
198
+ const subscription = yield* events.subscribe;
199
+ const palette = surface.palette;
200
+ yield* Stream.fromSubscription(subscription).pipe(Stream.runForEach((event) => Effect.gen(function* () {
201
+ const currentDepth = closesChild(event)
202
+ ? yield* Ref.updateAndGet(depth, (value) => Math.max(0, value - 1))
203
+ : yield* Ref.get(depth);
204
+ if (event._tag === "StageStarted") {
205
+ yield* Ref.update(depth, (value) => value + 1);
206
+ const active = terminalSafe(event.stage);
207
+ yield* Ref.update(stages, (current) => [...current, active]);
208
+ yield* surface.setStatus(active);
209
+ }
210
+ else if (closesChild(event)) {
211
+ const remaining = yield* Ref.updateAndGet(stages, (current) => current.slice(0, -1));
212
+ yield* surface.setStatus(remaining.at(-1));
213
+ }
214
+ if (rendersEvent(verbosity, event)) {
215
+ yield* surface.log(indentBlock(currentDepth, terminalLine(event, palette)));
216
+ }
217
+ yield* Ref.update(consumed, (count) => count + 1);
218
+ })), Effect.forkScoped);
219
+ const awaitDrained = (timeout = "3 seconds") => Effect.gen(function* () {
220
+ const target = yield* events.publishedCount;
221
+ const drain = Effect.suspend(() => Ref.get(consumed).pipe(Effect.flatMap((count) => count >= target ? Effect.void : Effect.yieldNow.pipe(Effect.andThen(drain)))));
222
+ yield* Effect.timeoutOption(drain, timeout);
223
+ });
224
+ return { consumed, awaitDrained };
225
+ });
226
+ //# sourceMappingURL=Terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Terminal.js","sourceRoot":"","sources":["../src/Terminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ApprovalPolicy, InteractionShape } from "@llm4ts/flow/Interaction";
2
+ export declare const terminalInteraction: InteractionShape;
3
+ export declare const terminalApprovalPolicy: (interaction?: InteractionShape) => ApprovalPolicy;
4
+ //# sourceMappingURL=TerminalInteraction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TerminalInteraction.d.ts","sourceRoot":"","sources":["../src/TerminalInteraction.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAGhF,eAAO,MAAM,mBAAmB,EAAE,gBAoBjC,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,cAAa,gBAAsC,KAClD,cAWD,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { stdin, stderr } from "node:process";
3
+ import * as Effect from "effect/Effect";
4
+ import { ProcessError } from "@llm4ts/flow/FlowError";
5
+ import { ApprovalAllowed, ApprovalDenied } from "@llm4ts/flow/Interaction";
6
+ export const terminalInteraction = {
7
+ ask: (question) => Effect.acquireUseRelease(Effect.sync(() => createInterface({
8
+ input: stdin,
9
+ output: stderr
10
+ })), (terminal) => Effect.tryPromise({
11
+ try: () => terminal.question(`❓ ${question}\n> `),
12
+ catch: (error) => ProcessError.make({
13
+ message: "terminal input",
14
+ detail: error instanceof Error ? error.message : String(error)
15
+ })
16
+ }), (terminal) => Effect.sync(() => terminal.close()))
17
+ };
18
+ export const terminalApprovalPolicy = (interaction = terminalInteraction) => ({
19
+ decide: (toolName, input) => interaction
20
+ .ask(`Allow tool '${toolName}' with input ${JSON.stringify(input)}? [y/N]`)
21
+ .pipe(Effect.map((answer) => /^(y|yes)$/iu.test(answer.trim())
22
+ ? new ApprovalAllowed()
23
+ : ApprovalDenied.make({ reason: "operator denied" })))
24
+ });
25
+ //# sourceMappingURL=TerminalInteraction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TerminalInteraction.js","sourceRoot":"","sources":["../src/TerminalInteraction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE1E,MAAM,CAAC,MAAM,mBAAmB,GAAqB;IACnD,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,CAChB,MAAM,CAAC,iBAAiB,CACtB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CACf,eAAe,CAAC;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,MAAM;KACf,CAAC,CACH,EACD,CAAC,QAAQ,EAAE,EAAE,CACX,MAAM,CAAC,UAAU,CAAC;QAChB,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,QAAQ,MAAM,CAAC;QACjD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,YAAY,CAAC,IAAI,CAAC;YAChB,OAAO,EAAE,gBAAgB;YACzB,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC/D,CAAC;KACL,CAAC,EACJ,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAClD;CACJ,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,cAAgC,mBAAmB,EACnC,EAAE,CAAC,CAAC;IACpB,MAAM,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAC1B,WAAW;SACR,GAAG,CAAC,eAAe,QAAQ,gBAAgB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC;SAC1E,IAAI,CACH,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACpB,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC,CAAC,IAAI,eAAe,EAAE;QACvB,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CACvD,CACF;CACN,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-main.d.ts","sourceRoot":"","sources":["../src/cli-main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import * as Effect from "effect/Effect";
4
+ import { makeCliProgram } from "./Cli.js";
5
+ import { makeDoctorProgram } from "./Doctor.js";
6
+ import { FlowHelp, parseFlowArgs } from "./FlowArgs.js";
7
+ const argv = process.argv.slice(2);
8
+ const packageVersion = () => {
9
+ const manifest = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
10
+ return typeof manifest === "object" &&
11
+ manifest !== null &&
12
+ "version" in manifest &&
13
+ typeof manifest.version === "string"
14
+ ? manifest.version
15
+ : "unknown";
16
+ };
17
+ const flowProgram = () => {
18
+ const parsed = parseFlowArgs(argv);
19
+ if (parsed.ok && parsed.value.help === true) {
20
+ return Effect.sync(() => process.stdout.write(FlowHelp));
21
+ }
22
+ if (parsed.ok && parsed.value.version === true) {
23
+ return Effect.sync(() => process.stdout.write(`${packageVersion()}\n`));
24
+ }
25
+ return makeCliProgram(argv).pipe(Effect.match({
26
+ onFailure: (error) => {
27
+ process.stderr.write(`${error.message}\n`);
28
+ return error._tag === "ScriptUsage" ? 2 : 1;
29
+ },
30
+ onSuccess: () => 0
31
+ }), Effect.flatMap((exitCode) => Effect.sync(() => {
32
+ process.exitCode = exitCode;
33
+ })));
34
+ };
35
+ const main = argv[0] === "doctor"
36
+ ? makeDoctorProgram().pipe(Effect.flatMap((report) => Effect.sync(() => process.stdout.write(report))))
37
+ : flowProgram();
38
+ Effect.runFork(main);
39
+ //# sourceMappingURL=cli-main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-main.js","sourceRoot":"","sources":["../src/cli-main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAElC,MAAM,cAAc,GAAG,GAAW,EAAE;IAClC,MAAM,QAAQ,GAAY,IAAI,CAAC,KAAK,CAClC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAClE,CAAA;IACD,OAAO,OAAO,QAAQ,KAAK,QAAQ;QACjC,QAAQ,KAAK,IAAI;QACjB,SAAS,IAAI,QAAQ;QACrB,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ;QACpC,CAAC,CAAC,QAAQ,CAAC,OAAO;QAClB,CAAC,CAAC,SAAS,CAAA;AACf,CAAC,CAAA;AAED,MAAM,WAAW,GAAG,GAAwB,EAAE;IAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;IAClC,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC1D,CAAC;IACD,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,cAAc,EAAE,IAAI,CAAC,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,CAC9B,MAAM,CAAC,KAAK,CAAC;QACX,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAA;YAC1C,OAAO,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC7C,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;KACnB,CAAC,EACF,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACf,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC7B,CAAC,CAAC,CACH,CACF,CAAA;AACH,CAAC,CAAA;AAED,MAAM,IAAI,GACR,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;IAClB,CAAC,CAAC,iBAAiB,EAAE,CAAC,IAAI,CACtB,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAC5E;IACH,CAAC,CAAC,WAAW,EAAE,CAAA;AAEnB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@llm4ts/runner",
3
+ "version": "0.1.0",
4
+ "description": "Node runner, CLI, terminal, and MCP composition for llm4ts",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "bin": {
16
+ "llm4ts": "./dist/cli-main.js"
17
+ },
18
+ "exports": {
19
+ "./Cli": "./dist/Cli.js",
20
+ "./CoderPolicy": "./dist/CoderPolicy.js",
21
+ "./Connectors": "./dist/Connectors.js",
22
+ "./Doctor": "./dist/Doctor.js",
23
+ "./FlowArgs": "./dist/FlowArgs.js",
24
+ "./FlowRunner": "./dist/FlowRunner.js",
25
+ "./McpStdio": "./dist/McpStdio.js",
26
+ "./NodeHttpClient": "./dist/NodeHttpClient.js",
27
+ "./NodeGeminiCliExecutor": "./dist/NodeGeminiCliExecutor.js",
28
+ "./NodePlainFileStore": "./dist/NodePlainFileStore.js",
29
+ "./NodeProcessExecutor": "./dist/NodeProcessExecutor.js",
30
+ "./NodeTemporaryFiles": "./dist/NodeTemporaryFiles.js",
31
+ "./NodeWorkspace": "./dist/NodeWorkspace.js",
32
+ "./NodeRuntime": "./dist/NodeRuntime.js",
33
+ "./ReviewFingerprint": "./dist/ReviewFingerprint.js",
34
+ "./Terminal": "./dist/Terminal.js",
35
+ "./TerminalInteraction": "./dist/TerminalInteraction.js",
36
+ "./Package": "./dist/Package.js",
37
+ "./package.json": "./package.json"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "provenance": true
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/riccardomerolla/llm4ts.git",
46
+ "directory": "packages/runner"
47
+ },
48
+ "homepage": "https://github.com/riccardomerolla/llm4ts#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/riccardomerolla/llm4ts/issues"
51
+ },
52
+ "keywords": [
53
+ "llm",
54
+ "effect",
55
+ "ai",
56
+ "agents",
57
+ "workflow",
58
+ "typescript"
59
+ ],
60
+ "dependencies": {
61
+ "@llm4ts/core": "0.1.0",
62
+ "@llm4ts/flow": "0.1.0"
63
+ },
64
+ "peerDependencies": {
65
+ "effect": "^4.0.0-beta.102"
66
+ },
67
+ "devDependencies": {
68
+ "effect": "^4.0.0-beta.102"
69
+ },
70
+ "scripts": {
71
+ "clean": "tsc -b tsconfig.json --clean",
72
+ "test": "vitest run test"
73
+ }
74
+ }
package/src/Cli.ts ADDED
@@ -0,0 +1,51 @@
1
+ import { join } from "node:path"
2
+ import * as Effect from "effect/Effect"
3
+ import { FlowLlmError, type FlowError } from "@llm4ts/flow/FlowError"
4
+ import { AssistantMessage } from "@llm4ts/flow/FlowEvents"
5
+ import { collect } from "@llm4ts/core/Streaming"
6
+ import { CliConnectorConfig } from "@llm4ts/core/ConnectorConfig"
7
+ import { coderFromEnv } from "./Connectors.ts"
8
+ import { parseFlowArgs, readFlowPrompt, resolveFlowRepo, type ScriptUsage } from "./FlowArgs.ts"
9
+ import { runNode } from "./FlowRunner.ts"
10
+ import { parseVerbosity } from "./Terminal.ts"
11
+
12
+ export const makeCliProgram = (
13
+ argv: ReadonlyArray<string>,
14
+ environment: Readonly<Record<string, string | undefined>> = process.env,
15
+ workspace = process.cwd(),
16
+ defaultPrompt?: string
17
+ ): Effect.Effect<void, ScriptUsage | FlowError> => {
18
+ const parsed = parseFlowArgs(argv)
19
+ if (!parsed.ok) {
20
+ return Effect.fail(parsed.error)
21
+ }
22
+ return Effect.gen(function* () {
23
+ const prompt = yield* readFlowPrompt(parsed.value, defaultPrompt)
24
+ const workDir = yield* resolveFlowRepo(parsed.value, workspace)
25
+ const selected = coderFromEnv(environment)
26
+ const coder = CliConnectorConfig.make({
27
+ ...selected,
28
+ workingDir: workDir
29
+ })
30
+ const timestamp = Date.now()
31
+ yield* runNode(
32
+ {
33
+ workDir,
34
+ workspace,
35
+ userPrompt: prompt,
36
+ coder,
37
+ verbosity: parseVerbosity(environment.LLM4TS_VERBOSITY),
38
+ tracePath: join(workDir, ".llm4ts", `trace-${timestamp}.jsonl`),
39
+ runId: timestamp.toString()
40
+ },
41
+ (context) =>
42
+ collect(context.coder.executeStream(prompt)).pipe(
43
+ Effect.mapError(FlowLlmError.from),
44
+ Effect.tap((response) =>
45
+ context.events.publish(AssistantMessage.make({ text: response.content }))
46
+ ),
47
+ Effect.asVoid
48
+ )
49
+ )
50
+ })
51
+ }
@@ -0,0 +1,82 @@
1
+ import * as Schema from "effect/Schema"
2
+ import { Capabilities, type Capability, allows } from "@llm4ts/core/Capability"
3
+ import type { Grants } from "@llm4ts/core/Capability"
4
+ import { CliConnectorConfig } from "@llm4ts/core/ConnectorConfig"
5
+ import { ConnectorIds } from "@llm4ts/core/Models"
6
+
7
+ export class AppliedCoderPolicy extends Schema.Class<AppliedCoderPolicy>("AppliedCoderPolicy")({
8
+ config: CliConnectorConfig,
9
+ unenforceable: Schema.Array(Schema.String)
10
+ }) {}
11
+
12
+ interface DeniedPattern {
13
+ readonly capability: Capability
14
+ readonly pattern: string
15
+ }
16
+
17
+ const patterns: ReadonlyArray<DeniedPattern> = [
18
+ {
19
+ capability: Capabilities.GitPush,
20
+ pattern: "Bash(git push:*)"
21
+ },
22
+ {
23
+ capability: Capabilities.GitWrite,
24
+ pattern: "Bash(git commit:*),Bash(git add:*),Bash(git checkout:*)"
25
+ },
26
+ {
27
+ capability: Capabilities.GhWrite,
28
+ pattern: "Bash(gh pr:*),Bash(gh issue:*),Bash(gh api:*)"
29
+ },
30
+ {
31
+ capability: Capabilities.AdoWrite,
32
+ pattern: "Bash(az repos:*),Bash(az boards:*)"
33
+ }
34
+ ]
35
+
36
+ const capabilityName = (capability: Capability): string =>
37
+ capability._tag === "Exec" ? `Exec(${capability.command})` : capability._tag
38
+
39
+ const withDisallowed = (
40
+ config: CliConnectorConfig,
41
+ denied: ReadonlyArray<DeniedPattern>
42
+ ): CliConnectorConfig => {
43
+ const existing = config.flags["disallowed-tools"]
44
+ const values = [
45
+ ...(existing === undefined || existing.length === 0 ? [] : [existing]),
46
+ ...denied.map(({ pattern }) => pattern)
47
+ ]
48
+
49
+ return new CliConnectorConfig({
50
+ ...config,
51
+ flags: {
52
+ ...config.flags,
53
+ "disallowed-tools": values.join(",")
54
+ }
55
+ })
56
+ }
57
+
58
+ export const applyCoderPolicy = (
59
+ config: CliConnectorConfig,
60
+ grants: Grants
61
+ ): AppliedCoderPolicy => {
62
+ const denied = patterns.filter(({ capability }) => !allows(grants, capability))
63
+
64
+ if (denied.length === 0) {
65
+ return new AppliedCoderPolicy({ config, unenforceable: [] })
66
+ }
67
+
68
+ if (config.connectorId.value === ConnectorIds.ClaudeCli.value) {
69
+ return new AppliedCoderPolicy({
70
+ config: withDisallowed(config, denied),
71
+ unenforceable: []
72
+ })
73
+ }
74
+
75
+ return new AppliedCoderPolicy({
76
+ config,
77
+ unenforceable: denied.map(
78
+ ({ capability }) =>
79
+ `${config.connectorId.value} cannot enforce the missing ${capabilityName(capability)} restriction on the coder`
80
+ )
81
+ })
82
+ }