@llm4ts/shell 2.45.0 → 2.46.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 (64) hide show
  1. package/dist/Cli.d.ts +3 -7
  2. package/dist/Cli.d.ts.map +1 -1
  3. package/dist/Cli.js +20 -4
  4. package/dist/Cli.js.map +1 -1
  5. package/dist/FlowLaunch.d.ts +2 -16
  6. package/dist/FlowLaunch.d.ts.map +1 -1
  7. package/dist/FlowLaunch.js +20 -66
  8. package/dist/FlowLaunch.js.map +1 -1
  9. package/dist/FlowProcess.d.ts +67 -0
  10. package/dist/FlowProcess.d.ts.map +1 -0
  11. package/dist/FlowProcess.js +175 -0
  12. package/dist/FlowProcess.js.map +1 -0
  13. package/dist/Menu.d.ts +1 -1
  14. package/dist/Menu.d.ts.map +1 -1
  15. package/dist/OperatorActTools.d.ts +170 -0
  16. package/dist/OperatorActTools.d.ts.map +1 -0
  17. package/dist/OperatorActTools.js +332 -0
  18. package/dist/OperatorActTools.js.map +1 -0
  19. package/dist/OperatorConfig.d.ts +44 -0
  20. package/dist/OperatorConfig.d.ts.map +1 -0
  21. package/dist/OperatorConfig.js +88 -0
  22. package/dist/OperatorConfig.js.map +1 -0
  23. package/dist/OperatorNode.d.ts +45 -0
  24. package/dist/OperatorNode.d.ts.map +1 -0
  25. package/dist/OperatorNode.js +103 -0
  26. package/dist/OperatorNode.js.map +1 -0
  27. package/dist/OperatorRuns.d.ts +76 -0
  28. package/dist/OperatorRuns.d.ts.map +1 -0
  29. package/dist/OperatorRuns.js +146 -0
  30. package/dist/OperatorRuns.js.map +1 -0
  31. package/dist/OperatorServer.d.ts +160 -0
  32. package/dist/OperatorServer.d.ts.map +1 -0
  33. package/dist/OperatorServer.js +123 -0
  34. package/dist/OperatorServer.js.map +1 -0
  35. package/dist/OperatorTools.d.ts +558 -0
  36. package/dist/OperatorTools.d.ts.map +1 -0
  37. package/dist/OperatorTools.js +398 -0
  38. package/dist/OperatorTools.js.map +1 -0
  39. package/dist/Refine.d.ts +2 -2
  40. package/dist/Refine.d.ts.map +1 -1
  41. package/dist/Refine.js +3 -5
  42. package/dist/Refine.js.map +1 -1
  43. package/dist/RunSupervisor.d.ts +51 -0
  44. package/dist/RunSupervisor.d.ts.map +1 -0
  45. package/dist/RunSupervisor.js +282 -0
  46. package/dist/RunSupervisor.js.map +1 -0
  47. package/dist/ShellErrors.d.ts +9 -0
  48. package/dist/ShellErrors.d.ts.map +1 -0
  49. package/dist/ShellErrors.js +7 -0
  50. package/dist/ShellErrors.js.map +1 -0
  51. package/flows/port-guide.js +4 -1
  52. package/package.json +13 -4
  53. package/src/Cli.ts +64 -3
  54. package/src/FlowLaunch.ts +20 -66
  55. package/src/FlowProcess.ts +239 -0
  56. package/src/OperatorActTools.ts +407 -0
  57. package/src/OperatorConfig.ts +148 -0
  58. package/src/OperatorNode.ts +147 -0
  59. package/src/OperatorRuns.ts +270 -0
  60. package/src/OperatorServer.ts +192 -0
  61. package/src/OperatorTools.ts +610 -0
  62. package/src/Refine.ts +4 -7
  63. package/src/RunSupervisor.ts +403 -0
  64. package/src/ShellErrors.ts +6 -0
@@ -0,0 +1,282 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ import * as Clock from "effect/Clock";
4
+ import * as Deferred from "effect/Deferred";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Exit from "effect/Exit";
7
+ import * as Ref from "effect/Ref";
8
+ import * as Scope from "effect/Scope";
9
+ import * as Semaphore from "effect/Semaphore";
10
+ import { encodeOperatorRunLine, latestRuns, OperatorRun, RunInProgress, UnknownRun } from "@llm4ts/flow/OperatorSchemas";
11
+ /**
12
+ * Where the operator keeps one repository's registry and run logs:
13
+ * `${XDG_STATE_HOME:-~/.local/state}/llm4ts/mcp/<repoId>`. An empty
14
+ * `XDG_STATE_HOME` counts as unset; never under `<repo>/.llm4ts/`.
15
+ */
16
+ export const operatorStateDir = (environment, repoId) => {
17
+ const home = environment.HOME !== undefined && environment.HOME.length > 0 ? environment.HOME : homedir();
18
+ const stateHome = environment.XDG_STATE_HOME !== undefined && environment.XDG_STATE_HOME.length > 0
19
+ ? environment.XDG_STATE_HOME
20
+ : join(home, ".local", "state");
21
+ return join(stateHome, "llm4ts", "mcp", repoId);
22
+ };
23
+ /** Knobs that become the flow's argv, in a fixed order; `flags` come last. */
24
+ export const knobsToArgs = (_flow, knobs) => [
25
+ ...(knobs.task === undefined ? [] : [knobs.task]),
26
+ ...(knobs.epic === undefined ? [] : ["--epic", knobs.epic]),
27
+ ...(knobs.land === undefined ? [] : [`--land=${knobs.land}`]),
28
+ ...(knobs.judgeRounds === undefined ? [] : ["--judge-rounds", String(knobs.judgeRounds)]),
29
+ ...(knobs.mergeRevisions === undefined
30
+ ? []
31
+ : ["--merge-revisions", String(knobs.mergeRevisions)]),
32
+ ...(knobs.flags ?? [])
33
+ ];
34
+ /** The only knobs that reach the flow's environment. */
35
+ export const knobsToEnvironment = (knobs) => ({
36
+ ...(knobs.executors === undefined ? {} : { LLM4TS_EXECUTORS: knobs.executors.join(",") }),
37
+ ...(knobs.pack === undefined ? {} : { LLM4TS_PACK: knobs.pack }),
38
+ ...(knobs.coder === undefined ? {} : { LLM4TS_CODER: knobs.coder })
39
+ });
40
+ const randomHex = () => Math.floor(Math.random() * 0x10000)
41
+ .toString(16)
42
+ .padStart(4, "0");
43
+ const isActive = (run) => run.state === "starting" || run.state === "running";
44
+ /** The server's own bearer token never reaches a child flow. */
45
+ const childEnvironment = (base) => Object.fromEntries(Object.entries(base).filter(([name]) => name !== "LLM4TS_MCP_TOKEN"));
46
+ export const makeRunSupervisor = (options) => Effect.gen(function* () {
47
+ const graceMs = options.graceMs ?? 30_000;
48
+ const readOnlyFlows = options.readOnlyFlows ?? new Set(["epic-retro"]);
49
+ const random = options.random ?? randomHex;
50
+ const stateDir = (repoId) => operatorStateDir(options.environment, repoId);
51
+ const registryPath = (repoId) => join(stateDir(repoId), "runs.jsonl");
52
+ const readRepo = (repoId) => options.files
53
+ .read(registryPath(repoId))
54
+ .pipe(Effect.map((contents) => latestRuns((contents ?? "").split("\n"))));
55
+ const record = (run) => options.files.append(registryPath(run.repo), `${encodeOperatorRunLine(run)}\n`);
56
+ const withState = (run, fields) => new OperatorRun({ ...run, ...fields });
57
+ // Runs whose child died while no supervisor watched them.
58
+ for (const repo of options.repos) {
59
+ for (const run of yield* readRepo(repo.id)) {
60
+ if (isActive(run) && (run.pid === undefined || !options.process.isAlive(run.pid))) {
61
+ const endedAt = yield* Clock.currentTimeMillis;
62
+ yield* record(withState(run, { state: "lost", endedAt }));
63
+ }
64
+ }
65
+ }
66
+ const live = new Map();
67
+ // Runs between their `starting` record and their `live` entry.
68
+ const launching = new Set();
69
+ // Orphan runs (alive, left by an earlier server) a `stop` already
70
+ // signalled, with the outcome of their escalation.
71
+ const orphansStopping = new Map();
72
+ const lock = yield* Semaphore.make(1);
73
+ const watchers = yield* Scope.make();
74
+ const isOrphan = (run) => isActive(run) && !live.has(run.runId) && !launching.has(run.runId);
75
+ // An active record nobody here watches: a run from an earlier server.
76
+ // Its child is re-checked lazily; once gone the record becomes `lost`.
77
+ const reconcile = (run) => Effect.gen(function* () {
78
+ if (!isOrphan(run) || (run.pid !== undefined && options.process.isAlive(run.pid))) {
79
+ return run;
80
+ }
81
+ const endedAt = yield* Clock.currentTimeMillis;
82
+ const lost = withState(run, { state: "lost", endedAt });
83
+ yield* record(lost);
84
+ return lost;
85
+ });
86
+ const readRepoLive = (repoId) => readRepo(repoId).pipe(Effect.flatMap((runs) => Effect.forEach(runs, reconcile)));
87
+ const allRuns = (repoId) => Effect.forEach(options.repos.filter((repo) => repoId === undefined || repo.id === repoId), (repo) => readRepoLive(repo.id)).pipe(Effect.map((perRepo) => perRepo.flat().sort((a, b) => b.startedAt - a.startedAt)), Effect.orDie);
88
+ const get = (runId) => allRuns().pipe(Effect.map((runs) => runs.find((run) => run.runId === runId)));
89
+ const watch = (running, entry) => Effect.gen(function* () {
90
+ const exit = yield* entry.handle.exited;
91
+ const stopped = yield* Ref.get(entry.stopping);
92
+ const endedAt = yield* Clock.currentTimeMillis;
93
+ const final = withState(running, {
94
+ state: stopped ? "interrupted" : "exited",
95
+ endedAt,
96
+ ...(exit.code === undefined ? {} : { exitCode: exit.code }),
97
+ ...(exit.signal === undefined ? {} : { signal: exit.signal })
98
+ });
99
+ // A failed append leaves the record active; with the child gone, the
100
+ // next read reconciles it to `lost`. `stop` must not wait on it.
101
+ yield* record(final).pipe(Effect.ignore, Effect.ensuring(Effect.suspend(() => {
102
+ live.delete(running.runId);
103
+ return Deferred.succeed(entry.final, final);
104
+ })));
105
+ });
106
+ const start = (request) => lock.withPermits(1)(Effect.gen(function* () {
107
+ const existing = yield* readRepoLive(request.repo.id);
108
+ const requestId = request.knobs.requestId;
109
+ if (requestId !== undefined) {
110
+ const repeated = existing.find((run) => run.requestId === requestId);
111
+ if (repeated !== undefined)
112
+ return repeated;
113
+ }
114
+ if (!readOnlyFlows.has(request.flow.name)) {
115
+ const busy = existing.filter((run) => isActive(run) && !readOnlyFlows.has(run.flow));
116
+ const [newest] = busy;
117
+ if (newest !== undefined && busy.length >= options.parallelRuns) {
118
+ return yield* new RunInProgress({
119
+ message: `${request.repo.id} already runs ${newest.flow} (${newest.runId})`,
120
+ runId: newest.runId
121
+ });
122
+ }
123
+ }
124
+ const startedAt = yield* Clock.currentTimeMillis;
125
+ const taken = (id) => live.has(id) || existing.some((run) => run.runId === id);
126
+ let runId = `op-${startedAt}-${random()}`;
127
+ for (let attempt = 0; attempt < 16 && taken(runId); attempt++) {
128
+ runId = `op-${startedAt}-${random()}`;
129
+ }
130
+ const tracePath = join(request.repo.path, ".llm4ts", `trace-${startedAt}.jsonl`);
131
+ const logDir = join(stateDir(request.repo.id), "runs", runId);
132
+ const args = knobsToArgs(request.flow.name, request.knobs);
133
+ const starting = new OperatorRun({
134
+ runId,
135
+ repo: request.repo.id,
136
+ flow: request.flow.name,
137
+ args,
138
+ knobs: request.knobs,
139
+ startedAt,
140
+ tracePath,
141
+ logDir,
142
+ state: "starting",
143
+ ...(requestId === undefined ? {} : { requestId })
144
+ });
145
+ launching.add(runId);
146
+ return yield* Effect.gen(function* () {
147
+ yield* record(starting);
148
+ const handle = yield* options.process
149
+ .start({
150
+ flowPath: request.flow.path,
151
+ args,
152
+ environment: {
153
+ ...childEnvironment(request.baseEnvironment),
154
+ ...knobsToEnvironment(request.knobs),
155
+ LLM4TS_RUN_ID: runId,
156
+ LLM4TS_TRACE_PATH: tracePath,
157
+ LLM4TS_FLOW: request.flow.name
158
+ },
159
+ cwd: request.repo.path,
160
+ stdio: { stdout: join(logDir, "stdout.log"), stderr: join(logDir, "stderr.log") },
161
+ detached: true
162
+ })
163
+ .pipe(Effect.tapError(() => Effect.gen(function* () {
164
+ const endedAt = yield* Clock.currentTimeMillis;
165
+ yield* record(withState(starting, { state: "exited", endedAt }));
166
+ })));
167
+ const running = withState(starting, { state: "running", pid: handle.pid });
168
+ yield* record(running);
169
+ const entry = {
170
+ handle,
171
+ stopping: yield* Ref.make(false),
172
+ final: yield* Deferred.make()
173
+ };
174
+ live.set(runId, entry);
175
+ yield* Effect.forkIn(watch(running, entry), watchers);
176
+ return running;
177
+ }).pipe(Effect.ensuring(Effect.sync(() => launching.delete(runId))));
178
+ }));
179
+ // Polls until the pid is gone or `ms` elapses; true when it is gone.
180
+ const awaitGone = (pid, ms) => Effect.gen(function* () {
181
+ const step = Math.max(1, Math.min(250, ms));
182
+ for (let waited = 0; waited < ms; waited += step) {
183
+ if (!options.process.isAlive(pid))
184
+ return true;
185
+ yield* Effect.sleep(step);
186
+ }
187
+ return !options.process.isAlive(pid);
188
+ });
189
+ // A live run's signal-and-escalate sequence. It runs in `watchers`, not
190
+ // in the caller's fiber, so a cancelled `stop` still sends SIGTERM.
191
+ const escalate = (entry) => Effect.gen(function* () {
192
+ if (yield* Deferred.isDone(entry.final))
193
+ return;
194
+ yield* entry.handle.signal("SIGINT");
195
+ const graceful = yield* Deferred.await(entry.final).pipe(Effect.timeoutOption(graceMs));
196
+ if (graceful._tag === "None")
197
+ yield* entry.handle.signal("SIGTERM");
198
+ });
199
+ // The same for an orphan, by pid. It records `interrupted` once the pid
200
+ // is gone and always completes `outcome`, even when interrupted.
201
+ const escalateOrphan = (run, pid, outcome) => Effect.gen(function* () {
202
+ yield* options.process.signal(pid, "SIGINT");
203
+ let gone = yield* awaitGone(pid, graceMs);
204
+ if (!gone) {
205
+ yield* options.process.signal(pid, "SIGTERM");
206
+ gone = yield* awaitGone(pid, graceMs);
207
+ }
208
+ if (!gone)
209
+ return;
210
+ const endedAt = yield* Clock.currentTimeMillis;
211
+ const interrupted = withState(run, { state: "interrupted", endedAt });
212
+ yield* record(interrupted).pipe(Effect.ignore);
213
+ yield* Deferred.succeed(outcome, interrupted);
214
+ }).pipe(Effect.ensuring(Deferred.succeed(outcome, run)));
215
+ const stopOrphan = (run, pid) => Effect.gen(function* () {
216
+ const candidate = yield* Deferred.make();
217
+ // Check-and-set and fork with no interruption point between them:
218
+ // only the first stop signals, and its escalation always starts.
219
+ const outcome = yield* Effect.uninterruptible(Effect.gen(function* () {
220
+ const existing = orphansStopping.get(run.runId);
221
+ if (existing !== undefined)
222
+ return existing;
223
+ orphansStopping.set(run.runId, candidate);
224
+ yield* Effect.forkIn(escalateOrphan(run, pid, candidate), watchers);
225
+ return candidate;
226
+ }));
227
+ const result = yield* Deferred.await(outcome);
228
+ if (!isActive(result))
229
+ return result;
230
+ // The child ignored SIGTERM too: report where the registry stands.
231
+ return (yield* get(run.runId)) ?? result;
232
+ });
233
+ const stop = (runId) => Effect.gen(function* () {
234
+ const entry = live.get(runId);
235
+ if (entry === undefined) {
236
+ const known = yield* get(runId);
237
+ if (known === undefined) {
238
+ return yield* new UnknownRun({ message: `no run ${runId}` });
239
+ }
240
+ if (isOrphan(known) && known.pid !== undefined) {
241
+ return yield* stopOrphan(known, known.pid);
242
+ }
243
+ return known;
244
+ }
245
+ // Only the first stop signals: a second SIGINT kills a flow at once.
246
+ // The winner forks the escalation into `watchers`; every caller,
247
+ // the winner included, only awaits the outcome.
248
+ yield* Effect.uninterruptible(Effect.gen(function* () {
249
+ const already = yield* Ref.getAndSet(entry.stopping, true);
250
+ if (!already)
251
+ yield* Effect.forkIn(escalate(entry), watchers);
252
+ }));
253
+ const graceful = yield* Deferred.await(entry.final).pipe(Effect.timeoutOption(graceMs));
254
+ if (graceful._tag === "Some")
255
+ return graceful.value;
256
+ const forced = yield* Deferred.await(entry.final).pipe(Effect.timeoutOption(graceMs));
257
+ if (forced._tag === "Some")
258
+ return forced.value;
259
+ // The child ignored SIGTERM too: report where the registry stands.
260
+ const latest = yield* get(runId);
261
+ return latest ?? (yield* new UnknownRun({ message: `no run ${runId}` }));
262
+ });
263
+ // Live runs are stopped (their escalations finish within the stop's
264
+ // wait) and pending orphan escalations awaited before `watchers` closes.
265
+ yield* Effect.addFinalizer(() => Effect.all([
266
+ Effect.forEach([...live.keys()], (runId) => Effect.ignore(stop(runId)), {
267
+ concurrency: "unbounded",
268
+ discard: true
269
+ }),
270
+ Effect.forEach([...orphansStopping.values()], Deferred.await, {
271
+ concurrency: "unbounded",
272
+ discard: true
273
+ })
274
+ ], { concurrency: "unbounded", discard: true }).pipe(Effect.andThen(Scope.close(watchers, Exit.void))));
275
+ return {
276
+ start,
277
+ stop,
278
+ get,
279
+ list: allRuns
280
+ };
281
+ });
282
+ //# sourceMappingURL=RunSupervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RunSupervisor.js","sourceRoot":"","sources":["../src/RunSupervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAA;AACjC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,aAAa,EACb,UAAU,EACX,MAAM,8BAA8B,CAAA;AAKrC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,WAAyD,EACzD,MAAc,EACN,EAAE;IACV,MAAM,IAAI,GACR,WAAW,CAAC,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAA;IAC9F,MAAM,SAAS,GACb,WAAW,CAAC,cAAc,KAAK,SAAS,IAAI,WAAW,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;QAC/E,CAAC,CAAC,WAAW,CAAC,cAAc;QAC5B,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IACnC,OAAO,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AACjD,CAAC,CAAA;AAqCD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,KAAoB,EAAyB,EAAE,CAAC;IACzF,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjD,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3D,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7D,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IACzF,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS;QACpC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,CAAC,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IACxD,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;CACvB,CAAA;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAoB,EAA0B,EAAE,CAAC,CAAC;IACnF,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACzF,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAChE,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;CACpE,CAAC,CAAA;AAEF,MAAM,SAAS,GAAG,GAAW,EAAE,CAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC;KAChC,QAAQ,CAAC,EAAE,CAAC;KACZ,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AAQrB,MAAM,QAAQ,GAAG,CAAC,GAAgB,EAAW,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,CAAA;AAEnG,gEAAgE;AAChE,MAAM,gBAAgB,GAAG,CACvB,IAAkD,EACd,EAAE,CACtC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAA;AAE1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,OAA0B,EACwC,EAAE,CACpE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAAA;IACzC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;IACtE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAA;IAC1C,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IAClF,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAA;IAE7E,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE,CAClC,OAAO,CAAC,KAAK;SACV,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;SAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7E,MAAM,MAAM,GAAG,CAAC,GAAgB,EAAE,EAAE,CAClC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACjF,MAAM,SAAS,GAAG,CAAC,GAAgB,EAAE,MAA4B,EAAe,EAAE,CAChF,IAAI,WAAW,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;IAExC,0DAA0D;IAC1D,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAClF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;gBAC9C,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAA;IACvC,+DAA+D;IAC/D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IACnC,kEAAkE;IAClE,mDAAmD;IACnD,MAAM,eAAe,GAAG,IAAI,GAAG,EAA0C,CAAA;IACzE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IAEpC,MAAM,QAAQ,GAAG,CAAC,GAAgB,EAAW,EAAE,CAC7C,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAEpE,sEAAsE;IACtE,uEAAuE;IACvE,MAAM,SAAS,GAAG,CAAC,GAAgB,EAAgD,EAAE,CACnF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAClF,OAAO,GAAG,CAAA;QACZ,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;QACvD,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC,CAAC,CAAA;IAEJ,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,EAAE,CACtC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IAElF,MAAM,OAAO,GAAG,CAAC,MAAe,EAAE,EAAE,CAClC,MAAM,CAAC,OAAO,CACZ,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,EAC1E,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAChC,CAAC,IAAI,CACJ,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EACjF,MAAM,CAAC,KAAK,CACb,CAAA;IAEH,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE,CAC5B,OAAO,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CAAA;IAE/E,MAAM,KAAK,GAAG,CAAC,OAAoB,EAAE,KAAc,EAAE,EAAE,CACrD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAA;QACvC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE;YAC/B,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ;YACzC,OAAO;YACP,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3D,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;SAC9D,CAAC,CAAA;QACF,qEAAqE;QACrE,iEAAiE;QACjE,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CACvB,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,QAAQ,CACb,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YAClB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YAC1B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC7C,CAAC,CAAC,CACH,CACF,CAAA;IACH,CAAC,CAAC,CAAA;IAEJ,MAAM,KAAK,GAAG,CAAC,OAAiB,EAAE,EAAE,CAClC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CACjB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAA;QACzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAA;YACpE,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;QAC7C,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YACpF,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;YACrB,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBAChE,OAAO,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC;oBAC9B,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,iBAAiB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,GAAG;oBAC3E,KAAK,EAAE,MAAM,CAAC,KAAK;iBACpB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAChD,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAA;QACtF,IAAI,KAAK,GAAG,MAAM,SAAS,IAAI,MAAM,EAAE,EAAE,CAAA;QACzC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YAC9D,KAAK,GAAG,MAAM,SAAS,IAAI,MAAM,EAAE,EAAE,CAAA;QACvC,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,SAAS,QAAQ,CAAC,CAAA;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;QAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;QAC1D,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC;YAC/B,KAAK;YACL,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;YACrB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;YACvB,IAAI;YACJ,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS;YACT,SAAS;YACT,MAAM;YACN,KAAK,EAAE,UAAU;YACjB,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;SAClD,CAAC,CAAA;QACF,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAChC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YACvB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO;iBAClC,KAAK,CAAC;gBACL,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;gBAC3B,IAAI;gBACJ,WAAW,EAAE;oBACX,GAAG,gBAAgB,CAAC,OAAO,CAAC,eAAe,CAAC;oBAC5C,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC;oBACpC,aAAa,EAAE,KAAK;oBACpB,iBAAiB,EAAE,SAAS;oBAC5B,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;iBAC/B;gBACD,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;gBACtB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE;gBACjF,QAAQ,EAAE,IAAI;aACf,CAAC;iBACD,IAAI,CACH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CACnB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;gBAC9C,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;YAClE,CAAC,CAAC,CACH,CACF,CAAA;YACH,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAA;YAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACtB,MAAM,KAAK,GAAY;gBACrB,MAAM;gBACN,QAAQ,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;gBAChC,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAe;aAC3C,CAAA;YACD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YACtB,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAA;YACrD,OAAO,OAAO,CAAA;QAChB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IACtE,CAAC,CAAC,CACH,CAAA;IAEH,qEAAqE;IACrE,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,EAAU,EAA0B,EAAE,CACpE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;QAC3C,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAA;YAC9C,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEJ,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAuB,EAAE,CACvD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,OAAM;QAC/C,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAA;QACvF,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM;YAAE,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;IAEJ,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,cAAc,GAAG,CACrB,GAAgB,EAChB,GAAW,EACX,OAAuC,EAClB,EAAE,CACvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QAC5C,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;YAC7C,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACvC,CAAC;QACD,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAA;QAC9C,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAA;QACrE,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC9C,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IAE1D,MAAM,UAAU,GAAG,CAAC,GAAgB,EAAE,GAAW,EAA8B,EAAE,CAC/E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAe,CAAA;QACrD,kEAAkE;QAClE,iEAAiE;QACjE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,eAAe,CAC3C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/C,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YAC3C,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;YACzC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAA;YACnE,OAAO,SAAS,CAAA;QAClB,CAAC,CAAC,CACH,CAAA;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAA;QACpC,mEAAmE;QACnE,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEJ,MAAM,IAAI,GAAG,CAAC,KAAa,EAA0C,EAAE,CACrE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAA;YAC9D,CAAC;YACD,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;gBAC/C,OAAO,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;YAC5C,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,qEAAqE;QACrE,iEAAiE;QACjE,gDAAgD;QAChD,KAAK,CAAC,CAAC,MAAM,CAAC,eAAe,CAC3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;YAC1D,IAAI,CAAC,OAAO;gBAAE,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAA;QAC/D,CAAC,CAAC,CACH,CAAA;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAA;QACvF,IAAI,QAAQ,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,QAAQ,CAAC,KAAK,CAAA;QACnD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAA;QACrF,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC,KAAK,CAAA;QAC/C,mEAAmE;QACnE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAChC,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEJ,oEAAoE;IACpE,yEAAyE;IACzE,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAC9B,MAAM,CAAC,GAAG,CACR;QACE,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;YACtE,WAAW,EAAE,WAAW;YACxB,OAAO,EAAE,IAAI;SACd,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE;YAC5D,WAAW,EAAE,WAAW;YACxB,OAAO,EAAE,IAAI;SACd,CAAC;KACH,EACD,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAC5C,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACzD,CAAA;IAED,OAAO;QACL,KAAK;QACL,IAAI;QACJ,GAAG;QACH,IAAI,EAAE,OAAO;KACe,CAAA;AAChC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,9 @@
1
+ import * as Schema from "effect/Schema";
2
+ declare const ShellUsageError_base: Schema.Class<ShellUsageError, Schema.TaggedStruct<"ShellUsage", {
3
+ readonly message: Schema.String;
4
+ }>, import("effect/Cause").YieldableError>;
5
+ /** Shared so modules that `Cli.ts` imports can fail with it without an import cycle. */
6
+ export declare class ShellUsageError extends ShellUsageError_base {
7
+ }
8
+ export {};
9
+ //# sourceMappingURL=ShellErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShellErrors.d.ts","sourceRoot":"","sources":["../src/ShellErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;;;;AAEvC,wFAAwF;AACxF,qBAAa,eAAgB,SAAQ,oBAEnC;CAAG"}
@@ -0,0 +1,7 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** Shared so modules that `Cli.ts` imports can fail with it without an import cycle. */
3
+ export class ShellUsageError extends Schema.TaggedError()("ShellUsage", {
4
+ message: Schema.String
5
+ }) {
6
+ }
7
+ //# sourceMappingURL=ShellErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShellErrors.js","sourceRoot":"","sources":["../src/ShellErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,wFAAwF;AACxF,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,YAAY,EAAE;IACvF,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CAAC;CAAG"}
@@ -85,7 +85,10 @@ const program = Effect.gen(function* () {
85
85
  coder,
86
86
  reasoning: asReadOnly(coder),
87
87
  reviewers: [asReadOnly(coder)],
88
- environment: process.env
88
+ environment: process.env,
89
+ // The trial ports are written under `.llm4ts/port/trial/` by the
90
+ // coder itself, so this run lifts the default deny of the run state.
91
+ deniedPaths: []
89
92
  }, (context) => Effect.gen(function* () {
90
93
  const events = context.events;
91
94
  const repo = yield* makeNodeWorkspace(input.workDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llm4ts/shell",
3
- "version": "2.45.0",
3
+ "version": "2.46.0",
4
4
  "description": "Interactive shell and CLI for llm4ts: flow discovery, run-a-flow, and view",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,9 +22,18 @@
22
22
  "./CoderChoice": "./dist/CoderChoice.js",
23
23
  "./FlowCatalog": "./dist/FlowCatalog.js",
24
24
  "./FlowLaunch": "./dist/FlowLaunch.js",
25
+ "./FlowProcess": "./dist/FlowProcess.js",
25
26
  "./Menu": "./dist/Menu.js",
27
+ "./OperatorActTools": "./dist/OperatorActTools.js",
28
+ "./OperatorConfig": "./dist/OperatorConfig.js",
29
+ "./OperatorNode": "./dist/OperatorNode.js",
30
+ "./OperatorRuns": "./dist/OperatorRuns.js",
31
+ "./OperatorServer": "./dist/OperatorServer.js",
32
+ "./OperatorTools": "./dist/OperatorTools.js",
26
33
  "./Refine": "./dist/Refine.js",
34
+ "./RunSupervisor": "./dist/RunSupervisor.js",
27
35
  "./Package": "./dist/Package.js",
36
+ "./ShellErrors": "./dist/ShellErrors.js",
28
37
  "./package.json": "./package.json"
29
38
  },
30
39
  "publishConfig": {
@@ -52,9 +61,9 @@
52
61
  "dependencies": {
53
62
  "@effect/platform-node": "4.0.0",
54
63
  "@effect/platform-node-shared": "4.0.0",
55
- "@llm4ts/flow": "2.45.0",
56
- "@llm4ts/core": "2.45.0",
57
- "@llm4ts/runner": "2.45.0"
64
+ "@llm4ts/core": "2.46.0",
65
+ "@llm4ts/runner": "2.46.0",
66
+ "@llm4ts/flow": "2.46.0"
58
67
  },
59
68
  "peerDependencies": {
60
69
  "effect": "4.0.0"
package/src/Cli.ts CHANGED
@@ -50,13 +50,14 @@ import {
50
50
  type FlowTierPaths
51
51
  } from "./FlowCatalog.ts"
52
52
  import { launchFlow } from "./FlowLaunch.ts"
53
+ import { mcpOptionsFrom } from "./OperatorConfig.ts"
54
+ import { nodeOperatorRuntime, nodeRead, runMcp } from "./OperatorNode.ts"
53
55
  import { mainMenu } from "./Menu.ts"
54
56
  import { ModDir, refineSession } from "./Refine.ts"
55
57
  import { packageVersion } from "./Package.ts"
58
+ import { ShellUsageError } from "./ShellErrors.ts"
56
59
 
57
- export class ShellUsageError extends Schema.TaggedError<ShellUsageError>()("ShellUsage", {
58
- message: Schema.String
59
- }) {}
60
+ export { ShellUsageError }
60
61
 
61
62
  export class ShellActionError extends Schema.TaggedError<ShellActionError>()("ShellAction", {
62
63
  message: Schema.String
@@ -981,6 +982,65 @@ const geminiBridgeCommand = Command.make(
981
982
  )
982
983
  )
983
984
 
985
+ const mcpCommand = Command.make(
986
+ "mcp",
987
+ {
988
+ stdio: Flag.Boolean("stdio").pipe(
989
+ Flag.withDefault(false),
990
+ Flag.withDescription("Speak MCP on stdin/stdout (the default transport)")
991
+ ),
992
+ http: Flag.Boolean("http").pipe(
993
+ Flag.withDefault(false),
994
+ Flag.withDescription(
995
+ "Serve MCP over HTTP at /mcp; needs a bearer token from LLM4TS_MCP_TOKEN or --token-file"
996
+ )
997
+ ),
998
+ host: Flag.String("host").pipe(
999
+ Flag.optional,
1000
+ Flag.withDescription("HTTP host to bind (default 127.0.0.1)")
1001
+ ),
1002
+ port: Flag.Int("port").pipe(Flag.optional, Flag.withDescription("HTTP port (default 4321)")),
1003
+ tokenFile: Flag.String("token-file").pipe(
1004
+ Flag.optional,
1005
+ Flag.withDescription("File holding the HTTP bearer token (when LLM4TS_MCP_TOKEN is unset)")
1006
+ ),
1007
+ repo: Flag.String("repo").pipe(
1008
+ Flag.atLeast(0),
1009
+ Flag.withDescription(
1010
+ "Repository to serve, repeatable (default: the repos in ~/.config/llm4ts/mcp.json)"
1011
+ )
1012
+ ),
1013
+ allowRun: Flag.Boolean("allow-run").pipe(
1014
+ Flag.withDefault(false),
1015
+ Flag.withDescription("Offer the tools that start, stop and resume flows")
1016
+ ),
1017
+ allowApprove: Flag.Boolean("allow-approve").pipe(
1018
+ Flag.withDefault(false),
1019
+ Flag.withDescription("Offer the approve tool, which ticks a retro report's approval marker")
1020
+ ),
1021
+ parallelRuns: Flag.Int("parallel-runs").pipe(
1022
+ Flag.optional,
1023
+ Flag.withDescription(
1024
+ "Flows that write a checkout and may run at once per repository (default 1)"
1025
+ )
1026
+ )
1027
+ },
1028
+ (flags) =>
1029
+ Effect.gen(function* () {
1030
+ const config = yield* mcpOptionsFrom(flags, process.env, process.cwd(), nodeRead)
1031
+ // SIGINT/SIGTERM interrupt the server; runMcp then stops the flows it started.
1032
+ yield* runMcp(
1033
+ config,
1034
+ nodeOperatorRuntime(config, (cwd) => shellTierPaths({ cwd })),
1035
+ process
1036
+ )
1037
+ })
1038
+ ).pipe(
1039
+ Command.withDescription(
1040
+ "Serve llm4ts to an MCP client (Grok Bot, Claude Code, Cursor): status, diagnosis and, when allowed, runs (ADR 0041)"
1041
+ )
1042
+ )
1043
+
984
1044
  const doctorCommand = Command.make("doctor", {}, () =>
985
1045
  Effect.gen(function* () {
986
1046
  const report = yield* makeDoctorProgram()
@@ -1014,6 +1074,7 @@ export const shellCommand = Command.make("llm4ts", {}, () =>
1014
1074
  graphCommand,
1015
1075
  rosterCommand,
1016
1076
  geminiBridgeCommand,
1077
+ mcpCommand,
1017
1078
  doctorCommand
1018
1079
  ])
1019
1080
  )
package/src/FlowLaunch.ts CHANGED
@@ -1,46 +1,9 @@
1
- import { spawn, spawnSync } from "node:child_process"
2
- import { existsSync } from "node:fs"
1
+ import { spawnSync } from "node:child_process"
3
2
  import { constants } from "node:os"
4
- import { dirname, join, resolve } from "node:path"
5
- import { fileURLToPath } from "node:url"
6
3
  import * as Effect from "effect/Effect"
7
- import * as Schema from "effect/Schema"
4
+ import { FlowLaunchError, needsResolveFallback, nodeFlowProcess } from "./FlowProcess.ts"
8
5
 
9
- export class FlowLaunchError extends Schema.TaggedError<FlowLaunchError>()("FlowLaunch", {
10
- message: Schema.String
11
- }) {}
12
-
13
- /**
14
- * True when the flow script cannot resolve `@llm4ts/runner` from its own
15
- * location — a global flow, a built-in copy, or a bare repository. Project
16
- * flows inside a repository that installs `@llm4ts/*` resolve their own pin
17
- * and need no help (the project-wins policy of ADR 0006). Implemented as the
18
- * same `node_modules` directory walk ESM resolution performs, so the check
19
- * stays honest under test runners that patch the module system.
20
- */
21
- export const needsResolveFallback = (flowPath: string): boolean => {
22
- let directory = dirname(resolve(flowPath))
23
- while (true) {
24
- if (existsSync(join(directory, "node_modules", "@llm4ts", "runner", "package.json"))) {
25
- return false
26
- }
27
- const parent = dirname(directory)
28
- if (parent === directory) {
29
- return true
30
- }
31
- directory = parent
32
- }
33
- }
34
-
35
- // In the published package the hook is the compiled sibling; when running
36
- // from src (tests), it is the TypeScript source, which the child can load
37
- // because it always runs with type stripping enabled.
38
- const resolveFallbackUrl = (() => {
39
- const compiled = new URL("./ResolveFallback.js", import.meta.url)
40
- return existsSync(fileURLToPath(compiled))
41
- ? compiled.href
42
- : new URL("./ResolveFallback.ts", import.meta.url).href
43
- })()
6
+ export { FlowLaunchError, needsResolveFallback }
44
7
 
45
8
  export interface LaunchFlowOptions {
46
9
  readonly flowPath: string
@@ -76,40 +39,31 @@ const restoreTerminal = (stdio: "inherit" | "ignore"): void => {
76
39
  * the child's exit code (`128 + signal` when terminated by a signal).
77
40
  */
78
41
  export const launchFlow = (options: LaunchFlowOptions): Effect.Effect<number, FlowLaunchError> =>
79
- Effect.callback<number, FlowLaunchError>((resume) => {
42
+ Effect.gen(function* () {
80
43
  const environment = { ...(options.environment ?? process.env) }
81
44
  if (options.coder !== undefined) {
82
45
  environment.LLM4TS_CODER = options.coder
83
46
  }
84
- const nodeArgs = ["--experimental-strip-types"]
85
- if (needsResolveFallback(options.flowPath)) {
86
- nodeArgs.push("--import", resolveFallbackUrl)
87
- }
88
- const child = spawn(process.execPath, [...nodeArgs, options.flowPath, ...options.taskArgs], {
89
- stdio: options.stdio ?? "inherit",
90
- env: environment,
91
- ...(options.cwd === undefined ? {} : { cwd: options.cwd })
92
- })
47
+ const stdio = options.stdio ?? "inherit"
93
48
  const ignoreSigint = (): void => {}
94
49
  process.on("SIGINT", ignoreSigint)
95
50
  const restoreSigint = (): void => {
96
51
  process.removeListener("SIGINT", ignoreSigint)
97
52
  }
98
- child.on("error", (error) => {
99
- restoreSigint()
100
- resume(Effect.fail(new FlowLaunchError({ message: error.message })))
101
- })
102
- child.on("exit", (code, signal) => {
103
- restoreSigint()
104
- restoreTerminal(options.stdio ?? "inherit")
105
- if (signal !== null) {
106
- resume(Effect.succeed(128 + (constants.signals[signal] ?? 15)))
107
- } else {
108
- resume(Effect.succeed(code ?? 1))
53
+ return yield* Effect.gen(function* () {
54
+ const handle = yield* nodeFlowProcess.start({
55
+ flowPath: options.flowPath,
56
+ args: options.taskArgs,
57
+ environment,
58
+ stdio,
59
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd })
60
+ })
61
+ const exit = yield* handle.exited.pipe(Effect.onInterrupt(() => handle.signal("SIGINT")))
62
+ restoreTerminal(stdio)
63
+ if (exit.signal !== undefined) {
64
+ const number = Object.entries(constants.signals).find(([name]) => name === exit.signal)
65
+ return 128 + (number?.[1] ?? 15)
109
66
  }
110
- })
111
- return Effect.sync(() => {
112
- restoreSigint()
113
- child.kill("SIGINT")
114
- })
67
+ return exit.code ?? 1
68
+ }).pipe(Effect.ensuring(Effect.sync(restoreSigint)))
115
69
  })