@revisium/orchestrator 0.0.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 (176) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -0
  3. package/bin/revo.js +2 -0
  4. package/control-plane/bootstrap.config.json +931 -0
  5. package/dist/app.module.js +28 -0
  6. package/dist/app.module.js.map +1 -0
  7. package/dist/cli/commands/bootstrap.js +39 -0
  8. package/dist/cli/commands/bootstrap.js.map +1 -0
  9. package/dist/cli/commands/dev.js +143 -0
  10. package/dist/cli/commands/dev.js.map +1 -0
  11. package/dist/cli/commands/inbox.js +288 -0
  12. package/dist/cli/commands/inbox.js.map +1 -0
  13. package/dist/cli/commands/mcp.js +16 -0
  14. package/dist/cli/commands/mcp.js.map +1 -0
  15. package/dist/cli/commands/playbook.js +74 -0
  16. package/dist/cli/commands/playbook.js.map +1 -0
  17. package/dist/cli/commands/poll-workflow-state.js +144 -0
  18. package/dist/cli/commands/poll-workflow-state.js.map +1 -0
  19. package/dist/cli/commands/revisium-context.js +23 -0
  20. package/dist/cli/commands/revisium-context.js.map +1 -0
  21. package/dist/cli/commands/revisium-helpers.js +61 -0
  22. package/dist/cli/commands/revisium-helpers.js.map +1 -0
  23. package/dist/cli/commands/revisium.js +89 -0
  24. package/dist/cli/commands/revisium.js.map +1 -0
  25. package/dist/cli/commands/run.js +426 -0
  26. package/dist/cli/commands/run.js.map +1 -0
  27. package/dist/cli/commands/work.js +149 -0
  28. package/dist/cli/commands/work.js.map +1 -0
  29. package/dist/cli/config.js +2 -0
  30. package/dist/cli/config.js.map +1 -0
  31. package/dist/cli/index.js +32 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/cli/live-guard.js +49 -0
  34. package/dist/cli/live-guard.js.map +1 -0
  35. package/dist/cli/needs-host.js +78 -0
  36. package/dist/cli/needs-host.js.map +1 -0
  37. package/dist/cli/program.js +37 -0
  38. package/dist/cli/program.js.map +1 -0
  39. package/dist/config.js +102 -0
  40. package/dist/config.js.map +1 -0
  41. package/dist/control-plane/client-transport.js +146 -0
  42. package/dist/control-plane/client-transport.js.map +1 -0
  43. package/dist/control-plane/data-access.js +99 -0
  44. package/dist/control-plane/data-access.js.map +1 -0
  45. package/dist/control-plane/definitions.js +120 -0
  46. package/dist/control-plane/definitions.js.map +1 -0
  47. package/dist/control-plane/errors.js +13 -0
  48. package/dist/control-plane/errors.js.map +1 -0
  49. package/dist/control-plane/inbox.js +261 -0
  50. package/dist/control-plane/inbox.js.map +1 -0
  51. package/dist/control-plane/index.js +6 -0
  52. package/dist/control-plane/index.js.map +1 -0
  53. package/dist/control-plane/json-fields.js +68 -0
  54. package/dist/control-plane/json-fields.js.map +1 -0
  55. package/dist/control-plane/resolve-cwd.js +75 -0
  56. package/dist/control-plane/resolve-cwd.js.map +1 -0
  57. package/dist/control-plane/steps.js +381 -0
  58. package/dist/control-plane/steps.js.map +1 -0
  59. package/dist/control-plane/tables.js +13 -0
  60. package/dist/control-plane/tables.js.map +1 -0
  61. package/dist/control-plane/versioned-meaning.js +53 -0
  62. package/dist/control-plane/versioned-meaning.js.map +1 -0
  63. package/dist/engine/dbos.module.js +18 -0
  64. package/dist/engine/dbos.module.js.map +1 -0
  65. package/dist/engine/dbos.service.js +296 -0
  66. package/dist/engine/dbos.service.js.map +1 -0
  67. package/dist/engine/ensure-postgres.js +80 -0
  68. package/dist/engine/ensure-postgres.js.map +1 -0
  69. package/dist/engine/types.js +2 -0
  70. package/dist/engine/types.js.map +1 -0
  71. package/dist/host/ensure-revisium.js +269 -0
  72. package/dist/host/ensure-revisium.js.map +1 -0
  73. package/dist/host/host.lifecycle.js +75 -0
  74. package/dist/host/host.lifecycle.js.map +1 -0
  75. package/dist/mcp/mcp-capabilities.js +47 -0
  76. package/dist/mcp/mcp-capabilities.js.map +1 -0
  77. package/dist/mcp/mcp-facade.service.js +130 -0
  78. package/dist/mcp/mcp-facade.service.js.map +1 -0
  79. package/dist/mcp/mcp-stdio.service.js +48 -0
  80. package/dist/mcp/mcp-stdio.service.js.map +1 -0
  81. package/dist/mcp/mcp-tools.js +264 -0
  82. package/dist/mcp/mcp-tools.js.map +1 -0
  83. package/dist/mcp/mcp.module.js +21 -0
  84. package/dist/mcp/mcp.module.js.map +1 -0
  85. package/dist/package-info.js +10 -0
  86. package/dist/package-info.js.map +1 -0
  87. package/dist/pipeline/await-human.js +62 -0
  88. package/dist/pipeline/await-human.js.map +1 -0
  89. package/dist/pipeline/develop-task.workflow.js +497 -0
  90. package/dist/pipeline/develop-task.workflow.js.map +1 -0
  91. package/dist/pipeline/pipeline.module.js +34 -0
  92. package/dist/pipeline/pipeline.module.js.map +1 -0
  93. package/dist/playbook/catalog-loader.js +145 -0
  94. package/dist/playbook/catalog-loader.js.map +1 -0
  95. package/dist/playbook/errors.js +14 -0
  96. package/dist/playbook/errors.js.map +1 -0
  97. package/dist/playbook/import-mapper.js +186 -0
  98. package/dist/playbook/import-mapper.js.map +1 -0
  99. package/dist/playbook/manifest.js +60 -0
  100. package/dist/playbook/manifest.js.map +1 -0
  101. package/dist/playbook/playbook-installer.js +51 -0
  102. package/dist/playbook/playbook-installer.js.map +1 -0
  103. package/dist/playbook/prompt-composer.js +34 -0
  104. package/dist/playbook/prompt-composer.js.map +1 -0
  105. package/dist/playbook/source-resolver.js +105 -0
  106. package/dist/playbook/source-resolver.js.map +1 -0
  107. package/dist/poller/pr-readiness-core.js +656 -0
  108. package/dist/poller/pr-readiness-core.js.map +1 -0
  109. package/dist/poller/pr-readiness.js +91 -0
  110. package/dist/poller/pr-readiness.js.map +1 -0
  111. package/dist/revisium/inbox.service.js +67 -0
  112. package/dist/revisium/inbox.service.js.map +1 -0
  113. package/dist/revisium/playbooks.service.js +99 -0
  114. package/dist/revisium/playbooks.service.js.map +1 -0
  115. package/dist/revisium/revisium.module.js +55 -0
  116. package/dist/revisium/revisium.module.js.map +1 -0
  117. package/dist/revisium/roles.service.js +79 -0
  118. package/dist/revisium/roles.service.js.map +1 -0
  119. package/dist/revisium/run.service.js +182 -0
  120. package/dist/revisium/run.service.js.map +1 -0
  121. package/dist/revisium/tokens.js +7 -0
  122. package/dist/revisium/tokens.js.map +1 -0
  123. package/dist/run/append-event.js +112 -0
  124. package/dist/run/append-event.js.map +1 -0
  125. package/dist/run/cancel-run.js +47 -0
  126. package/dist/run/cancel-run.js.map +1 -0
  127. package/dist/run/create-run.js +208 -0
  128. package/dist/run/create-run.js.map +1 -0
  129. package/dist/run/fail-run.js +20 -0
  130. package/dist/run/fail-run.js.map +1 -0
  131. package/dist/run/inspect-run.js +287 -0
  132. package/dist/run/inspect-run.js.map +1 -0
  133. package/dist/run/terminal-run-status.js +45 -0
  134. package/dist/run/terminal-run-status.js.map +1 -0
  135. package/dist/runners/claude-code.service.js +48 -0
  136. package/dist/runners/claude-code.service.js.map +1 -0
  137. package/dist/runners/gh-identity.js +108 -0
  138. package/dist/runners/gh-identity.js.map +1 -0
  139. package/dist/runners/integrator.js +417 -0
  140. package/dist/runners/integrator.js.map +1 -0
  141. package/dist/runners/runner.module.js +40 -0
  142. package/dist/runners/runner.module.js.map +1 -0
  143. package/dist/runners/tokens.js +7 -0
  144. package/dist/runners/tokens.js.map +1 -0
  145. package/dist/task-control-plane/pr-readiness.service.js +33 -0
  146. package/dist/task-control-plane/pr-readiness.service.js.map +1 -0
  147. package/dist/task-control-plane/task-control-plane-api.service.js +440 -0
  148. package/dist/task-control-plane/task-control-plane-api.service.js.map +1 -0
  149. package/dist/task-control-plane/task-control-plane.module.js +23 -0
  150. package/dist/task-control-plane/task-control-plane.module.js.map +1 -0
  151. package/dist/worker/build-context.js +39 -0
  152. package/dist/worker/build-context.js.map +1 -0
  153. package/dist/worker/claude-code-runner.js +135 -0
  154. package/dist/worker/claude-code-runner.js.map +1 -0
  155. package/dist/worker/git-worktree-manager.js +84 -0
  156. package/dist/worker/git-worktree-manager.js.map +1 -0
  157. package/dist/worker/loop.js +122 -0
  158. package/dist/worker/loop.js.map +1 -0
  159. package/dist/worker/process-executor.js +62 -0
  160. package/dist/worker/process-executor.js.map +1 -0
  161. package/dist/worker/result-envelope.js +134 -0
  162. package/dist/worker/result-envelope.js.map +1 -0
  163. package/dist/worker/runner-dispatch.js +20 -0
  164. package/dist/worker/runner-dispatch.js.map +1 -0
  165. package/dist/worker/runner.js +2 -0
  166. package/dist/worker/runner.js.map +1 -0
  167. package/dist/worker/script-runner.js +28 -0
  168. package/dist/worker/script-runner.js.map +1 -0
  169. package/dist/worker/stub-runner.js +59 -0
  170. package/dist/worker/stub-runner.js.map +1 -0
  171. package/dist/worker/worker-id.js +18 -0
  172. package/dist/worker/worker-id.js.map +1 -0
  173. package/dist/worker/worktree-manager.js +7 -0
  174. package/dist/worker/worktree-manager.js.map +1 -0
  175. package/package.json +66 -0
  176. package/revisium.config.json +10 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * ensureRevisium() — shared auto-start helper (Round 3).
3
+ *
4
+ * Models three distinct states (F7):
5
+ * 1. HEALTHY → no-op, return proven runtime.
6
+ * 2. NO LIVE DAEMON (null runtime or dead pid) → fresh detached spawn + wait.
7
+ * 3. ALIVE BUT UNHEALTHY → bounded re-poll, then throw (never orphan a live process).
8
+ *
9
+ * Called by BOTH `revisium start` command and host bootstrap (DRY extraction, F9).
10
+ *
11
+ * TOCTOU / compare-and-delete (F16, F19, F21):
12
+ * In state 2 we re-classify IMMEDIATELY before any removal. decideRuntimeAction()
13
+ * returns a RuntimeDecision that encodes BOTH the action AND shouldRemove — so the
14
+ * identity rule (only remove when the recheck still matches the stale snapshot by pid
15
+ * AND startedAt) lives in one tested place and the caller cannot drift from it (F21).
16
+ *
17
+ * The same removeRuntimeIfMatches() helper is shared by the state-2 pre-spawn cleanup
18
+ * AND the spawn-timeout cleanup (F19), so neither path can accidentally delete a runtime
19
+ * that belongs to a concurrently-started daemon.
20
+ *
21
+ * Known limitation — concurrent cold-start (deferred per ТЗ §3.3.5, slice 0001):
22
+ * Two host processes starting with no live daemon in the same narrow window can still
23
+ * race to spawn — the compare-and-delete re-check narrows the orphan window but does
24
+ * NOT serialize spawns. Full cross-process file-locking is intentionally deferred to a
25
+ * future slice. The practical guard is the re-check plus the fact that the host path
26
+ * only runs for explicit dev:* invocations.
27
+ */
28
+ import { spawn } from 'node:child_process';
29
+ import { closeSync, existsSync, openSync, readFileSync, writeFileSync } from 'node:fs';
30
+ import { createRequire } from 'node:module';
31
+ import { baseUrl, findFreePort, getConfig, healthUrl, isAlive, isHealthy, readRuntime, removeRuntime, } from '../cli/config.js';
32
+ import { killTree, parsePort, tailLines, waitForExit, waitHealthy, } from '../cli/commands/revisium-helpers.js';
33
+ const require = createRequire(import.meta.url);
34
+ /** Default cold-start timeout in ms (120 s — matches the existing waitHealthy default). */
35
+ const DEFAULT_TIMEOUT_MS = 120_000;
36
+ /** Default re-poll budget for the alive-but-unhealthy case (consensus MINOR, round 4). */
37
+ const DEFAULT_RECHECK_MS = 20_000;
38
+ /**
39
+ * Remove runtime.json ONLY if the current file on disk still matches the given snapshot
40
+ * (same pid AND startedAt). Shared by the state-2 pre-spawn path and the spawn-timeout
41
+ * cleanup path (F19 / F21 DRY) so neither can accidentally delete a runtime that belongs
42
+ * to a concurrently-started daemon.
43
+ *
44
+ * If the file has been replaced (different identity) or already removed (null), this is a
45
+ * safe no-op — the file either belongs to another process or was already cleaned up.
46
+ *
47
+ * Exported (@internal) for unit testing; production callers should use only the internal
48
+ * call sites (state-2 pre-spawn cleanup and spawn-timeout cleanup).
49
+ */
50
+ export function removeRuntimeIfMatches(snapshot) {
51
+ const current = readRuntime();
52
+ if (current?.pid === snapshot.pid && current?.startedAt === snapshot.startedAt) {
53
+ removeRuntime();
54
+ }
55
+ }
56
+ /**
57
+ * Decide what action to take in state 2 ("no live daemon" from initial classification)
58
+ * given the stale snapshot and an immediate re-read immediately before any removal.
59
+ *
60
+ * Pure function (no side effects, no I/O) — unit-testable in isolation (F18 / F16 / F21).
61
+ *
62
+ * Compare-and-delete contract (F16, F21):
63
+ * - shouldRemove is true ONLY when the re-read runtime STILL matches the stale snapshot
64
+ * (same pid AND startedAt). This prevents deleting a live runtime written concurrently
65
+ * BETWEEN our initial dead-pid read and this re-check.
66
+ * - If the re-check shows a DIFFERENT (or new) live pid, the action routes into alive
67
+ * paths ('return-running' or 'repoll') and shouldRemove is always false.
68
+ *
69
+ * @param stalePidSnapshot - The RuntimeState we observed initially (dead pid), or null.
70
+ * @param recheck - The result of readRuntime() immediately before removal.
71
+ * @param recheckAlive - Whether recheck.pid is alive (ignored when recheck is null).
72
+ * @param recheckHealthy - Whether recheck daemon is healthy (ignored when recheck is null).
73
+ */
74
+ export function decideRuntimeAction(stalePidSnapshot, recheck, recheckAlive, recheckHealthy) {
75
+ if (recheck && recheckAlive) {
76
+ // A concurrent process wrote a live runtime — do NOT delete or spawn over it.
77
+ if (recheckHealthy)
78
+ return { action: 'return-running', shouldRemove: false };
79
+ return { action: 'repoll', shouldRemove: false };
80
+ }
81
+ // No live runtime after re-read. Determine whether we may remove the stale file.
82
+ if (stalePidSnapshot !== null) {
83
+ // Compare-and-delete identity check (F21): only set shouldRemove=true when the
84
+ // recheck runtime STILL matches the stale snapshot (same pid AND startedAt).
85
+ // - recheck null → file already cleaned up by another process; skip remove but proceed.
86
+ // - recheck present but different identity → new stale entry from a different past run;
87
+ // our snapshot doesn't own it — leave it for its owner.
88
+ const matchesSnapshot = recheck !== null &&
89
+ recheck.pid === stalePidSnapshot.pid &&
90
+ recheck.startedAt === stalePidSnapshot.startedAt;
91
+ return { action: 'remove-and-spawn', shouldRemove: matchesSnapshot };
92
+ }
93
+ return { action: 'spawn', shouldRemove: false };
94
+ }
95
+ /**
96
+ * Classify the daemon state given a snapshot of: the runtime file, whether the
97
+ * recorded pid is alive, and whether the daemon responds to health checks.
98
+ *
99
+ * Pure function (no side effects, no I/O) — unit-testable in isolation (F15).
100
+ *
101
+ * - 'healthy' → pid alive AND health check passed.
102
+ * - 'alive-unhealthy' → pid alive BUT health check failed (never spawn a second daemon).
103
+ * - 'no-live-daemon' → no runtime.json OR recorded pid is dead (safe to spawn fresh).
104
+ *
105
+ * Note: the alive-unhealthy case intentionally includes a concurrent-start scenario
106
+ * where the runtime was written but the daemon is mid-startup (F11): returning
107
+ * 'alive-unhealthy' rather than 'no-live-daemon' routes callers into the bounded
108
+ * re-poll path instead of unconditionally spawning a second daemon.
109
+ */
110
+ export function classifyRuntimeState(rt, alive, healthy) {
111
+ if (!rt || !alive)
112
+ return 'no-live-daemon';
113
+ if (healthy)
114
+ return 'healthy';
115
+ return 'alive-unhealthy';
116
+ }
117
+ /**
118
+ * Handle state 3: alive-but-unhealthy daemon.
119
+ *
120
+ * Performs a bounded re-poll. Returns `{alreadyRunning:true}` if the daemon becomes
121
+ * healthy within `recheckMs`. Throws with an actionable message otherwise — never
122
+ * removes runtime.json, never spawns (would orphan a live process).
123
+ */
124
+ async function handleAliveUnhealthy(rt, recheckMs) {
125
+ const becameHealthy = await waitHealthy(healthUrl(rt.httpPort), recheckMs);
126
+ if (becameHealthy) {
127
+ const freshRt = readRuntime();
128
+ if (!freshRt)
129
+ throw new Error('runtime.json disappeared during re-poll');
130
+ return { runtime: freshRt, alreadyRunning: true };
131
+ }
132
+ throw new Error(`Revisium (pid ${rt.pid}) is running but unhealthy — run \`revo revisium stop\` and retry`);
133
+ }
134
+ /**
135
+ * Perform the "re-poll" branch of state 2: a concurrent start wrote a live-but-unhealthy
136
+ * runtime — poll for late-up rather than spawning a second daemon.
137
+ */
138
+ async function recheckRepoll(rtRecheck, recheckMs) {
139
+ const becameHealthy = await waitHealthy(healthUrl(rtRecheck.httpPort), recheckMs);
140
+ if (becameHealthy) {
141
+ const freshRt = readRuntime();
142
+ if (!freshRt)
143
+ throw new Error('runtime.json disappeared during recheck re-poll');
144
+ return { runtime: freshRt, alreadyRunning: true };
145
+ }
146
+ throw new Error(`Revisium (pid ${rtRecheck.pid}) is running but unhealthy — run \`revo revisium stop\` and retry`);
147
+ }
148
+ /**
149
+ * Spawn the standalone daemon (detached + unref'd) and wait for health.
150
+ *
151
+ * Writes extended runtime.json (F8: includes dataDir). On health timeout, kills the
152
+ * spawned child, removes its runtime.json (compare-and-delete — F19), and throws.
153
+ *
154
+ * @returns EnsureResult from the freshly-written runtime.json (F3: pid-proven ports).
155
+ */
156
+ async function startAndWaitForHealth(cfg, timeoutMs) {
157
+ const { httpPort, pgPort, dataDir, logFile, runtimeFile } = cfg;
158
+ const entry = require.resolve('@revisium/standalone/bin/revisium-standalone.js');
159
+ const out = openSync(logFile, 'a');
160
+ const child = spawn(process.execPath, [entry, '--port', String(httpPort), '--pg-port', String(pgPort), '--data', dataDir], { detached: true, stdio: ['ignore', out, out] });
161
+ closeSync(out);
162
+ if (!child.pid) {
163
+ throw new Error('Failed to start standalone Revisium: spawn returned no pid');
164
+ }
165
+ child.unref(); // detached — daemon outlives this process
166
+ // Capture the exact identity of the runtime WE just wrote (F19).
167
+ const spawnStartedAt = new Date().toISOString();
168
+ writeFileSync(runtimeFile, JSON.stringify({ httpPort, pgPort, pid: child.pid, startedAt: spawnStartedAt, dataDir }, null, 2));
169
+ const spawnSnapshot = { pid: child.pid, startedAt: spawnStartedAt };
170
+ const spawnHealthy = await waitHealthy(healthUrl(httpPort), timeoutMs);
171
+ if (!spawnHealthy) {
172
+ // F19: Only removeRuntime() when the file still identifies OUR child (compare-and-delete).
173
+ const logTail = tailLines(logFile, 20);
174
+ killTree(child.pid, 'SIGTERM');
175
+ await waitForExit(child.pid, 20_000);
176
+ if (isAlive(child.pid))
177
+ killTree(child.pid, 'SIGKILL');
178
+ removeRuntimeIfMatches(spawnSnapshot);
179
+ throw new Error(`Revisium did not become healthy on ${baseUrl(httpPort)} within ${timeoutMs / 1000}s` +
180
+ ` — see \`revo revisium logs\`\n${logTail}`);
181
+ }
182
+ // Re-read the freshly-written runtime.json (F3: pid-proven ports).
183
+ const written = readRuntime();
184
+ if (!written)
185
+ throw new Error('runtime.json disappeared after successful start');
186
+ return { runtime: written, alreadyRunning: false };
187
+ }
188
+ /**
189
+ * Ensure the Revisium standalone daemon is running and healthy.
190
+ *
191
+ * Three-state logic (F7):
192
+ * - State 1: recorded pid alive + healthy → return immediately (alreadyRunning = true).
193
+ * - State 2: no runtime.json OR recorded pid is dead → removeRuntime if stale, spawn fresh.
194
+ * - State 3: recorded pid alive but unhealthy → bounded re-poll (recheckMs), then THROW
195
+ * (never removeRuntime, never spawn — leaves the live process for `revo revisium stop`).
196
+ *
197
+ * @returns EnsureResult with the pid-proven runtime (fresh or existing).
198
+ * @throws if the daemon is alive-but-unhealthy after re-poll, or if spawn times out.
199
+ */
200
+ export async function ensureRevisium(options = {}) {
201
+ const { timeoutMs = DEFAULT_TIMEOUT_MS, recheckMs = DEFAULT_RECHECK_MS } = options;
202
+ const config = getConfig();
203
+ const rt = readRuntime();
204
+ const alive = rt ? isAlive(rt.pid) : false;
205
+ const healthy = rt && alive ? await isHealthy(rt.httpPort) : false;
206
+ const stateClass = classifyRuntimeState(rt, alive, healthy);
207
+ // ── State 1: healthy ──────────────────────────────────────────────────────
208
+ if (stateClass === 'healthy') {
209
+ return { runtime: rt, alreadyRunning: true };
210
+ }
211
+ // ── State 3: alive but unhealthy ─────────────────────────────────────────
212
+ if (stateClass === 'alive-unhealthy') {
213
+ return handleAliveUnhealthy(rt, recheckMs);
214
+ }
215
+ // ── State 2: no live daemon ───────────────────────────────────────────────
216
+ //
217
+ // F16 / F21 compare-and-delete: re-classify IMMEDIATELY before any removal.
218
+ // decideRuntimeAction() encodes both the action AND shouldRemove so the identity
219
+ // check lives in one tested pure function (F21).
220
+ const rtRecheck = readRuntime();
221
+ const recheckAlive = rtRecheck ? isAlive(rtRecheck.pid) : false;
222
+ const recheckHealthy = rtRecheck && recheckAlive ? await isHealthy(rtRecheck.httpPort) : false;
223
+ const decision = decideRuntimeAction(rt, rtRecheck, recheckAlive, recheckHealthy);
224
+ if (decision.action === 'return-running') {
225
+ return { runtime: rtRecheck, alreadyRunning: true };
226
+ }
227
+ if (decision.action === 'repoll') {
228
+ return recheckRepoll(rtRecheck, recheckMs);
229
+ }
230
+ // action === 'remove-and-spawn' or 'spawn'
231
+ // F22: removeRuntimeIfMatches re-reads and checks identity AT DELETE TIME.
232
+ if (decision.shouldRemove)
233
+ removeRuntimeIfMatches(rtRecheck);
234
+ const httpPort = await findFreePort(parsePort(options.port, config.preferredPort));
235
+ // CR5: Two independent findFreePort calls can return the same port when their search
236
+ // bases overlap. If they collide, re-pick pgPort from httpPort+1 to guarantee distinct ports.
237
+ let pgPort = await findFreePort(parsePort(options.pgPort, config.preferredPgPort));
238
+ if (pgPort === httpPort) {
239
+ pgPort = await findFreePort(httpPort + 1);
240
+ }
241
+ const dataDir = options.data ?? config.dataDir;
242
+ return startAndWaitForHealth({ httpPort, pgPort, dataDir, logFile: config.logFile, runtimeFile: config.runtimeFile }, timeoutMs);
243
+ }
244
+ /** Maximum valid TCP port number (inclusive). */
245
+ const MAX_TCP_PORT = 65535;
246
+ /**
247
+ * Read the postmaster.pid file to cross-check the pg port from runtime.json (F3).
248
+ * Returns the pg port if found, or null if the file is absent (older standalone layout).
249
+ *
250
+ * CR6: Valid port range is 1–65535 (inclusive). Out-of-range values (e.g. 70000) return null.
251
+ */
252
+ export function readPostmasterPgPort(dataDir) {
253
+ const postmasterPid = `${dataDir}/pgdata/postmaster.pid`;
254
+ if (!existsSync(postmasterPid))
255
+ return null;
256
+ try {
257
+ const lines = readFileSync(postmasterPid, 'utf8').split(/\r?\n/);
258
+ // Line 4 (index 3) is the pg port according to the PostgreSQL postmaster.pid format.
259
+ const portStr = lines[3]?.trim();
260
+ if (!portStr)
261
+ return null;
262
+ const port = Number(portStr);
263
+ return Number.isInteger(port) && port > 0 && port <= MAX_TCP_PORT ? port : null;
264
+ }
265
+ catch {
266
+ return null;
267
+ }
268
+ }
269
+ //# sourceMappingURL=ensure-revisium.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-revisium.js","sourceRoot":"","sources":["../../src/host/ensure-revisium.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ /**
11
+ * HostLifecycle — OnApplicationBootstrap / OnApplicationShutdown.
12
+ *
13
+ * Boot order (§2 of the ТЗ):
14
+ * 1. ensureRevisium() — auto-start if no live daemon; three-state (F7).
15
+ * 2. Pid-proven pg port from the returned runtime (never resolvePorts() — F3).
16
+ * 3. Optional postmaster.pid cross-check (F8).
17
+ * 4. ensurePostgres(provenPgPort) — CREATE DATABASE dbos if absent.
18
+ * 5. dbosService.setConfig(url) + dbosService.launch().
19
+ *
20
+ * Shutdown:
21
+ * - DBOS.shutdown() only.
22
+ * - INTENTIONALLY does NOT stop the Revisium daemon (Round 3, human decision):
23
+ * the daemon is detached+unref'd and is a shared, long-lived process; subsequent
24
+ * `revo dev:status <id>` invocations must find the same daemon + embedded Postgres.
25
+ */
26
+ import { Injectable } from '@nestjs/common';
27
+ import { DbosService } from '../engine/dbos.service.js';
28
+ import { ensureRevisium, readPostmasterPgPort } from './ensure-revisium.js';
29
+ import { dbosSystemDatabaseUrl, ensurePostgres } from '../engine/ensure-postgres.js';
30
+ function isMcpStdioHost() {
31
+ return process.env.REVO_MCP_STDIO === '1';
32
+ }
33
+ let HostLifecycle = class HostLifecycle {
34
+ dbosService;
35
+ constructor(dbosService) {
36
+ this.dbosService = dbosService;
37
+ }
38
+ async onApplicationBootstrap() {
39
+ // Step 1: Ensure Revisium daemon is running (auto-start if absent).
40
+ const { runtime } = await ensureRevisium();
41
+ // Step 2: Pid-proven pg port (F3 — never resolvePorts()).
42
+ let provenPgPort = runtime.pgPort;
43
+ // Optional cross-check against postmaster.pid (F8).
44
+ if (runtime.dataDir) {
45
+ const pmPort = readPostmasterPgPort(runtime.dataDir);
46
+ if (pmPort !== null && pmPort !== runtime.pgPort) {
47
+ throw new Error(`Stale runtime.json: runtime.pgPort=${runtime.pgPort} but postmaster.pid reports port=${pmPort}. ` +
48
+ 'Restart Revisium: revo revisium stop && revo revisium start');
49
+ }
50
+ if (pmPort !== null) {
51
+ provenPgPort = pmPort;
52
+ }
53
+ }
54
+ // If runtime.dataDir is absent (older standalone), skip cross-check and rely on rt.pgPort.
55
+ // Step 3: Ensure the `dbos` database exists.
56
+ await ensurePostgres(provenPgPort);
57
+ // Step 4+5: Configure + launch DBOS.
58
+ this.dbosService.setConfig(dbosSystemDatabaseUrl(provenPgPort), {
59
+ logLevel: isMcpStdioHost() ? 'warn' : undefined,
60
+ });
61
+ await this.dbosService.launch();
62
+ }
63
+ async onApplicationShutdown() {
64
+ // Intentional: host does not own the Revisium daemon lifecycle.
65
+ // Only DBOS.shutdown() runs on exit.
66
+ // The daemon was spawned detached+unref'd and must outlive the host process.
67
+ await this.dbosService.shutdown();
68
+ }
69
+ };
70
+ HostLifecycle = __decorate([
71
+ Injectable(),
72
+ __metadata("design:paramtypes", [DbosService])
73
+ ], HostLifecycle);
74
+ export { HostLifecycle };
75
+ //# sourceMappingURL=host.lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.lifecycle.js","sourceRoot":"","sources":["../../src/host/host.lifecycle.ts"],"names":[],"mappings":";;;;;;;;;AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAiD,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAErF,SAAS,cAAc;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,GAAG,CAAC;AAC5C,CAAC;AAGM,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,WAAwB;QAAxB,gBAAW,GAAX,WAAW,CAAa;IAAG,CAAC;IAEzD,KAAK,CAAC,sBAAsB;QAC1B,oEAAoE;QACpE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;QAE3C,0DAA0D;QAC1D,IAAI,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;QAElC,oDAAoD;QACpD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACrD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CACb,sCAAsC,OAAO,CAAC,MAAM,oCAAoC,MAAM,IAAI;oBAChG,6DAA6D,CAChE,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;QACH,CAAC;QACD,2FAA2F;QAE3F,6CAA6C;QAC7C,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;QAEnC,qCAAqC;QACrC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,CAAC,EAAE;YAC9D,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SAChD,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,qBAAqB;QACzB,gEAAgE;QAChE,qCAAqC;QACrC,6EAA6E;QAC7E,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAzCY,aAAa;IADzB,UAAU,EAAE;qCAE+B,WAAW;GAD1C,aAAa,CAyCzB"}
@@ -0,0 +1,47 @@
1
+ export const MCP_TOOL_NAMES = [
2
+ 'get_status',
3
+ 'doctor',
4
+ 'get_capabilities',
5
+ 'validate_repository',
6
+ 'get_repository_context',
7
+ 'get_project',
8
+ 'create_run',
9
+ 'start_run',
10
+ 'resume_run',
11
+ 'cancel_run',
12
+ 'list_runs',
13
+ 'get_run',
14
+ 'get_run_events',
15
+ 'get_run_log',
16
+ 'get_run_digest',
17
+ 'list_inbox',
18
+ 'get_inbox_item',
19
+ 'get_pending_decisions',
20
+ 'approve_gate',
21
+ 'reject_gate',
22
+ 'answer_question',
23
+ 'resolve_inbox_item',
24
+ 'summarize_gate_risk',
25
+ 'install_playbook',
26
+ 'list_playbooks',
27
+ 'list_roles',
28
+ 'get_role',
29
+ 'list_pipelines',
30
+ 'get_pipeline',
31
+ 'simulate_route',
32
+ 'get_pr_readiness',
33
+ 'list_pr_feedback',
34
+ ];
35
+ export const MCP_INSTRUCTIONS = `Revo is a local-first software-development task orchestrator.
36
+
37
+ Use these tools to manage tasks end-to-end from your coding agent:
38
+ - create and start runs;
39
+ - inspect run status, events, attempts, and digests;
40
+ - resolve human inbox gates and questions;
41
+ - inspect installed playbooks, roles, and pipelines;
42
+ - inspect PR readiness and actionable review feedback before resuming work;
43
+ - validate repository context before starting live work.
44
+
45
+ This MCP server is local stdio only and does not expose generic Revisium table CRUD.
46
+ Use product-level tools instead of writing raw rows.`;
47
+ //# sourceMappingURL=mcp-capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-capabilities.js","sourceRoot":"","sources":["../../src/mcp/mcp-capabilities.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY;IACZ,QAAQ;IACR,kBAAkB;IAClB,qBAAqB;IACrB,wBAAwB;IACxB,aAAa;IACb,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,SAAS;IACT,gBAAgB;IAChB,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,gBAAgB;IAChB,uBAAuB;IACvB,cAAc;IACd,aAAa;IACb,iBAAiB;IACjB,oBAAoB;IACpB,qBAAqB;IACrB,kBAAkB;IAClB,gBAAgB;IAChB,YAAY;IACZ,UAAU;IACV,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;CACV,CAAC;AAIX,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;qDAWqB,CAAC"}
@@ -0,0 +1,130 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { TaskControlPlaneApiService, } from '../task-control-plane/task-control-plane-api.service.js';
12
+ import { MCP_TOOL_NAMES } from './mcp-capabilities.js';
13
+ let McpFacadeService = class McpFacadeService {
14
+ api;
15
+ constructor(api) {
16
+ this.api = api;
17
+ }
18
+ getCapabilities() {
19
+ return {
20
+ transport: 'stdio',
21
+ auth: 'none',
22
+ tools: [...MCP_TOOL_NAMES],
23
+ runnerModes: ['script', 'live'],
24
+ notes: [
25
+ 'Local stdio MCP server; no remote HTTP listener.',
26
+ 'Tools expose product operations, not generic Revisium row CRUD.',
27
+ 'Live runs use the real Claude runner and git/GitHub integrator.',
28
+ ],
29
+ };
30
+ }
31
+ getStatus() {
32
+ return this.api.getStatus();
33
+ }
34
+ doctor() {
35
+ return this.api.doctor();
36
+ }
37
+ getProject() {
38
+ return this.api.getProject();
39
+ }
40
+ validateRepository(input) {
41
+ return this.api.validateRepository(input);
42
+ }
43
+ getRepositoryContext(input) {
44
+ return this.api.getRepositoryContext(input);
45
+ }
46
+ createRun(input) {
47
+ return this.api.createRun(input);
48
+ }
49
+ startRun(input) {
50
+ return this.api.startRun(input);
51
+ }
52
+ resumeRun(input) {
53
+ return this.api.resumeRun(input);
54
+ }
55
+ cancelRun(runId) {
56
+ return this.api.cancelRun(runId);
57
+ }
58
+ listRuns(filter) {
59
+ return this.api.listRuns(filter);
60
+ }
61
+ getRun(input) {
62
+ return this.api.getRun(input);
63
+ }
64
+ getRunEvents(input) {
65
+ return this.api.getRunEvents(input);
66
+ }
67
+ getRunLog(input) {
68
+ return this.api.getRunLog(input);
69
+ }
70
+ getRunDigest(runId) {
71
+ return this.api.getRunDigest(runId);
72
+ }
73
+ listInbox(filter) {
74
+ return this.api.listInbox(filter);
75
+ }
76
+ getInboxItem(inboxId) {
77
+ return this.api.getInboxItem(inboxId);
78
+ }
79
+ getPendingDecisions(runId) {
80
+ return this.api.getPendingDecisions(runId);
81
+ }
82
+ approveGate(input) {
83
+ return this.api.approveGate(input);
84
+ }
85
+ rejectGate(input) {
86
+ return this.api.rejectGate(input);
87
+ }
88
+ answerQuestion(input) {
89
+ return this.api.answerQuestion(input);
90
+ }
91
+ resolveInboxItem(input) {
92
+ return this.api.resolveInboxItem(input);
93
+ }
94
+ summarizeGateRisk(inboxId) {
95
+ return this.api.summarizeGateRisk(inboxId);
96
+ }
97
+ installPlaybook(input) {
98
+ return this.api.installPlaybook(input);
99
+ }
100
+ listPlaybooks() {
101
+ return this.api.listPlaybooks();
102
+ }
103
+ listRoles() {
104
+ return this.api.listRoles();
105
+ }
106
+ getRole(roleId) {
107
+ return this.api.getRole(roleId);
108
+ }
109
+ listPipelines() {
110
+ return this.api.listPipelines();
111
+ }
112
+ getPipeline(pipelineId) {
113
+ return this.api.getPipeline(pipelineId);
114
+ }
115
+ simulateRoute(input) {
116
+ return this.api.simulateRoute(input);
117
+ }
118
+ getPrReadiness(input) {
119
+ return this.api.getPrReadiness(input);
120
+ }
121
+ listPrFeedback(input) {
122
+ return this.api.listPrFeedback(input);
123
+ }
124
+ };
125
+ McpFacadeService = __decorate([
126
+ Injectable(),
127
+ __metadata("design:paramtypes", [TaskControlPlaneApiService])
128
+ ], McpFacadeService);
129
+ export { McpFacadeService };
130
+ //# sourceMappingURL=mcp-facade.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-facade.service.js","sourceRoot":"","sources":["../../src/mcp/mcp-facade.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
+ import { readPackageVersion } from '../package-info.js';
14
+ import { MCP_INSTRUCTIONS } from './mcp-capabilities.js';
15
+ import { McpFacadeService } from './mcp-facade.service.js';
16
+ import { registerRevoMcpTools } from './mcp-tools.js';
17
+ let McpStdioService = class McpStdioService {
18
+ facade;
19
+ constructor(facade) {
20
+ this.facade = facade;
21
+ }
22
+ async start() {
23
+ const server = new McpServer({ name: 'revo', version: readPackageVersion() }, { instructions: MCP_INSTRUCTIONS });
24
+ registerRevoMcpTools(server, this.facade);
25
+ const transport = new StdioServerTransport();
26
+ const closed = new Promise((resolve, reject) => {
27
+ transport.onclose = () => resolve();
28
+ transport.onerror = (error) => reject(error);
29
+ process.stdin.once('end', resolve);
30
+ process.stdin.once('close', resolve);
31
+ process.once('SIGINT', resolve);
32
+ process.once('SIGTERM', resolve);
33
+ });
34
+ try {
35
+ await server.connect(transport);
36
+ await closed;
37
+ }
38
+ finally {
39
+ await server.close().catch(() => undefined);
40
+ }
41
+ }
42
+ };
43
+ McpStdioService = __decorate([
44
+ Injectable(),
45
+ __metadata("design:paramtypes", [McpFacadeService])
46
+ ], McpStdioService);
47
+ export { McpStdioService };
48
+ //# sourceMappingURL=mcp-stdio.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-stdio.service.js","sourceRoot":"","sources":["../../src/mcp/mcp-stdio.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG/C,IAAM,eAAe,GAArB,MAAM,eAAe;IACG;IAA7B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEzD,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAC/C,EAAE,YAAY,EAAE,gBAAgB,EAAE,CACnC,CAAC;QACF,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;YACpC,SAAS,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,MAAM,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;CACF,CAAA;AA3BY,eAAe;IAD3B,UAAU,EAAE;qCAE0B,gBAAgB;GAD1C,eAAe,CA2B3B"}