@vendoai/apps 0.4.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 (203) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +8 -0
  3. package/dist/adapter-conformance.d.ts +48 -0
  4. package/dist/adapter-conformance.d.ts.map +1 -0
  5. package/dist/adapter-conformance.js +196 -0
  6. package/dist/adapter-conformance.js.map +1 -0
  7. package/dist/agent-tools.d.ts +10 -0
  8. package/dist/agent-tools.d.ts.map +1 -0
  9. package/dist/agent-tools.js +252 -0
  10. package/dist/agent-tools.js.map +1 -0
  11. package/dist/app-data.d.ts +23 -0
  12. package/dist/app-data.d.ts.map +1 -0
  13. package/dist/app-data.js +129 -0
  14. package/dist/app-data.js.map +1 -0
  15. package/dist/app-token.d.ts +24 -0
  16. package/dist/app-token.d.ts.map +1 -0
  17. package/dist/app-token.js +61 -0
  18. package/dist/app-token.js.map +1 -0
  19. package/dist/audit.d.ts +11 -0
  20. package/dist/audit.d.ts.map +1 -0
  21. package/dist/audit.js +19 -0
  22. package/dist/audit.js.map +1 -0
  23. package/dist/automation-plan.d.ts +43 -0
  24. package/dist/automation-plan.d.ts.map +1 -0
  25. package/dist/automation-plan.js +212 -0
  26. package/dist/automation-plan.js.map +1 -0
  27. package/dist/bench/client.d.ts +43 -0
  28. package/dist/bench/client.d.ts.map +1 -0
  29. package/dist/bench/client.js +129 -0
  30. package/dist/bench/client.js.map +1 -0
  31. package/dist/bench/fixtures.d.ts +42 -0
  32. package/dist/bench/fixtures.d.ts.map +1 -0
  33. package/dist/bench/fixtures.js +146 -0
  34. package/dist/bench/fixtures.js.map +1 -0
  35. package/dist/bench/judge.d.ts +9 -0
  36. package/dist/bench/judge.d.ts.map +1 -0
  37. package/dist/bench/judge.js +71 -0
  38. package/dist/bench/judge.js.map +1 -0
  39. package/dist/bench/metrics.d.ts +32 -0
  40. package/dist/bench/metrics.d.ts.map +1 -0
  41. package/dist/bench/metrics.js +172 -0
  42. package/dist/bench/metrics.js.map +1 -0
  43. package/dist/bench/prompts.d.ts +17 -0
  44. package/dist/bench/prompts.d.ts.map +1 -0
  45. package/dist/bench/prompts.js +100 -0
  46. package/dist/bench/prompts.js.map +1 -0
  47. package/dist/bench/report.d.ts +43 -0
  48. package/dist/bench/report.d.ts.map +1 -0
  49. package/dist/bench/report.js +74 -0
  50. package/dist/bench/report.js.map +1 -0
  51. package/dist/bench/runner.d.ts +15 -0
  52. package/dist/bench/runner.d.ts.map +1 -0
  53. package/dist/bench/runner.js +26 -0
  54. package/dist/bench/runner.js.map +1 -0
  55. package/dist/bench/toolfork.d.ts +18 -0
  56. package/dist/bench/toolfork.d.ts.map +1 -0
  57. package/dist/bench/toolfork.js +125 -0
  58. package/dist/bench/toolfork.js.map +1 -0
  59. package/dist/box-agent.d.ts +78 -0
  60. package/dist/box-agent.d.ts.map +1 -0
  61. package/dist/box-agent.js +137 -0
  62. package/dist/box-agent.js.map +1 -0
  63. package/dist/box-env.d.ts +26 -0
  64. package/dist/box-env.d.ts.map +1 -0
  65. package/dist/box-env.js +52 -0
  66. package/dist/box-env.js.map +1 -0
  67. package/dist/call.d.ts +23 -0
  68. package/dist/call.d.ts.map +1 -0
  69. package/dist/call.js +45 -0
  70. package/dist/call.js.map +1 -0
  71. package/dist/cloud.d.ts +4917 -0
  72. package/dist/cloud.d.ts.map +1 -0
  73. package/dist/cloud.js +16 -0
  74. package/dist/cloud.js.map +1 -0
  75. package/dist/e2b/index.d.ts +30 -0
  76. package/dist/e2b/index.d.ts.map +1 -0
  77. package/dist/e2b/index.js +273 -0
  78. package/dist/e2b/index.js.map +1 -0
  79. package/dist/egress-approval.d.ts +73 -0
  80. package/dist/egress-approval.d.ts.map +1 -0
  81. package/dist/egress-approval.js +74 -0
  82. package/dist/egress-approval.js.map +1 -0
  83. package/dist/engine.d.ts +188 -0
  84. package/dist/engine.d.ts.map +1 -0
  85. package/dist/engine.js +1507 -0
  86. package/dist/engine.js.map +1 -0
  87. package/dist/fn.d.ts +22 -0
  88. package/dist/fn.d.ts.map +1 -0
  89. package/dist/fn.js +108 -0
  90. package/dist/fn.js.map +1 -0
  91. package/dist/history.d.ts +21 -0
  92. package/dist/history.d.ts.map +1 -0
  93. package/dist/history.js +158 -0
  94. package/dist/history.js.map +1 -0
  95. package/dist/inclient.d.ts +48 -0
  96. package/dist/inclient.d.ts.map +1 -0
  97. package/dist/inclient.js +68 -0
  98. package/dist/inclient.js.map +1 -0
  99. package/dist/index.d.ts +24 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +25 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/interchange.d.ts +17 -0
  104. package/dist/interchange.d.ts.map +1 -0
  105. package/dist/interchange.js +133 -0
  106. package/dist/interchange.js.map +1 -0
  107. package/dist/machine-lifecycle.d.ts +102 -0
  108. package/dist/machine-lifecycle.d.ts.map +1 -0
  109. package/dist/machine-lifecycle.js +360 -0
  110. package/dist/machine-lifecycle.js.map +1 -0
  111. package/dist/manifest.d.ts +42 -0
  112. package/dist/manifest.d.ts.map +1 -0
  113. package/dist/manifest.js +53 -0
  114. package/dist/manifest.js.map +1 -0
  115. package/dist/open.d.ts +45 -0
  116. package/dist/open.d.ts.map +1 -0
  117. package/dist/open.js +245 -0
  118. package/dist/open.js.map +1 -0
  119. package/dist/parked-action.d.ts +51 -0
  120. package/dist/parked-action.d.ts.map +1 -0
  121. package/dist/parked-action.js +29 -0
  122. package/dist/parked-action.js.map +1 -0
  123. package/dist/persistence.d.ts +41 -0
  124. package/dist/persistence.d.ts.map +1 -0
  125. package/dist/persistence.js +86 -0
  126. package/dist/persistence.js.map +1 -0
  127. package/dist/pins.d.ts +231 -0
  128. package/dist/pins.d.ts.map +1 -0
  129. package/dist/pins.js +213 -0
  130. package/dist/pins.js.map +1 -0
  131. package/dist/pipeline.d.ts +142 -0
  132. package/dist/pipeline.d.ts.map +1 -0
  133. package/dist/pipeline.js +1014 -0
  134. package/dist/pipeline.js.map +1 -0
  135. package/dist/prewired-schema.d.ts +16 -0
  136. package/dist/prewired-schema.d.ts.map +1 -0
  137. package/dist/prewired-schema.js +48 -0
  138. package/dist/prewired-schema.js.map +1 -0
  139. package/dist/redaction.d.ts +13 -0
  140. package/dist/redaction.d.ts.map +1 -0
  141. package/dist/redaction.js +67 -0
  142. package/dist/redaction.js.map +1 -0
  143. package/dist/runtime.d.ts +463 -0
  144. package/dist/runtime.d.ts.map +1 -0
  145. package/dist/runtime.js +1715 -0
  146. package/dist/runtime.js.map +1 -0
  147. package/dist/sandbox.d.ts +90 -0
  148. package/dist/sandbox.d.ts.map +1 -0
  149. package/dist/sandbox.js +2 -0
  150. package/dist/sandbox.js.map +1 -0
  151. package/dist/schedules.d.ts +89 -0
  152. package/dist/schedules.d.ts.map +1 -0
  153. package/dist/schedules.js +334 -0
  154. package/dist/schedules.js.map +1 -0
  155. package/dist/secret-exposure.d.ts +55 -0
  156. package/dist/secret-exposure.d.ts.map +1 -0
  157. package/dist/secret-exposure.js +53 -0
  158. package/dist/secret-exposure.js.map +1 -0
  159. package/dist/ship-diff.d.ts +47 -0
  160. package/dist/ship-diff.d.ts.map +1 -0
  161. package/dist/ship-diff.js +39 -0
  162. package/dist/ship-diff.js.map +1 -0
  163. package/dist/testing/fake-box.d.ts +67 -0
  164. package/dist/testing/fake-box.d.ts.map +1 -0
  165. package/dist/testing/fake-box.js +166 -0
  166. package/dist/testing/fake-box.js.map +1 -0
  167. package/dist/testing/fake-sandbox-v2.d.ts +59 -0
  168. package/dist/testing/fake-sandbox-v2.d.ts.map +1 -0
  169. package/dist/testing/fake-sandbox-v2.js +121 -0
  170. package/dist/testing/fake-sandbox-v2.js.map +1 -0
  171. package/dist/testing/fake-sandbox.d.ts +94 -0
  172. package/dist/testing/fake-sandbox.d.ts.map +1 -0
  173. package/dist/testing/fake-sandbox.js +239 -0
  174. package/dist/testing/fake-sandbox.js.map +1 -0
  175. package/dist/testing/guard-fixture.d.ts +19 -0
  176. package/dist/testing/guard-fixture.d.ts.map +1 -0
  177. package/dist/testing/guard-fixture.js +134 -0
  178. package/dist/testing/guard-fixture.js.map +1 -0
  179. package/dist/testing/index.d.ts +8 -0
  180. package/dist/testing/index.d.ts.map +1 -0
  181. package/dist/testing/index.js +8 -0
  182. package/dist/testing/index.js.map +1 -0
  183. package/dist/testing/memory-store.d.ts +5 -0
  184. package/dist/testing/memory-store.d.ts.map +1 -0
  185. package/dist/testing/memory-store.js +4 -0
  186. package/dist/testing/memory-store.js.map +1 -0
  187. package/dist/testing/scripted-model.d.ts +32 -0
  188. package/dist/testing/scripted-model.d.ts.map +1 -0
  189. package/dist/testing/scripted-model.js +112 -0
  190. package/dist/testing/scripted-model.js.map +1 -0
  191. package/dist/testing/seed-app-row.d.ts +4 -0
  192. package/dist/testing/seed-app-row.d.ts.map +1 -0
  193. package/dist/testing/seed-app-row.js +7 -0
  194. package/dist/testing/seed-app-row.js.map +1 -0
  195. package/dist/unified-diff.d.ts +13 -0
  196. package/dist/unified-diff.d.ts.map +1 -0
  197. package/dist/unified-diff.js +127 -0
  198. package/dist/unified-diff.js.map +1 -0
  199. package/dist/version-hash.d.ts +9 -0
  200. package/dist/version-hash.d.ts.map +1 -0
  201. package/dist/version-hash.js +12 -0
  202. package/dist/version-hash.js.map +1 -0
  203. package/package.json +84 -0
@@ -0,0 +1,334 @@
1
+ import { VendoError, } from "@vendoai/core";
2
+ import { Cron } from "croner";
3
+ import { z } from "zod";
4
+ import { requestAppWithBootRetry } from "./box-agent.js";
5
+ import { parseVendoManifest } from "./manifest.js";
6
+ import { appLifecycleEvent } from "./audit.js";
7
+ import { rowFromRecord } from "./persistence.js";
8
+ /**
9
+ * execution-v2 Wave 2 Lane D — BYO schedule execution. Any external cron
10
+ * (Vercel cron, GitHub Actions, crontab — or later the Cloud broker calling
11
+ * the same surface) hits the host's authenticated tick; this engine reads each
12
+ * machine-bearing app's `vendo.json` schedule declarations (Lane C's parser)
13
+ * over the box door, computes due-ness against store-cached last-fired state,
14
+ * wakes ONLY due machines, POSTs their declared `/fn/<name>` targets as the
15
+ * app owner's away execution, and lets the normal idle policy put the box back
16
+ * to sleep.
17
+ *
18
+ * The store cache is what keeps sleeping machines asleep: due-ness never
19
+ * requires a wake. The accepted consequence is that a manifest edited while
20
+ * the machine sleeps is not seen until the machine is next awake — the engine
21
+ * re-reads `vendo.json` whenever the machine is awake at tick time (and on the
22
+ * first tick after graduation, which wakes once to learn the schedules), and
23
+ * {@link ScheduleEngine.syncManifest} is the explicit hook the Wave-3 in-box
24
+ * agent calls at edit-complete.
25
+ */
26
+ export const SCHEDULE_STATE_COLLECTION = "vendo_app_schedules";
27
+ /** Bounded CAS retries before an app's state write reports a conflict. */
28
+ const CLAIM_ATTEMPTS = 3;
29
+ const decoder = new TextDecoder();
30
+ const scheduleStateSchema = z.object({
31
+ syncedAt: z.string(),
32
+ schedules: z.array(z.object({
33
+ cron: z.string(),
34
+ fn: z.string(),
35
+ since: z.string(),
36
+ lastFiredAt: z.string().optional(),
37
+ lastStatus: z.enum(["ok", "error"]).optional(),
38
+ })),
39
+ });
40
+ /**
41
+ * The latest occurrence of `cron` after `baseline` and at or before `at`, or
42
+ * undefined when none is due. Exact for ANY downtime length: a binary search
43
+ * over the window (each probe one croner `nextRun`), never a bounded forward
44
+ * scan — so a host offline for months still collapses to ONE fire at the
45
+ * latest occurrence, with no truncated catch-up batches (AI-review triage,
46
+ * PR #406). Occurrences of a five-field cron are ≥60s apart, so once the
47
+ * window shrinks under a second, `lo` (always a known occurrence ≤ at) is it.
48
+ */
49
+ const latestDueOccurrence = (cron, baseline, at) => {
50
+ const job = new Cron(cron, { timezone: "UTC", paused: true });
51
+ const first = job.nextRun(new Date(baseline));
52
+ if (first === null || first.getTime() > at.getTime())
53
+ return undefined;
54
+ let lo = first.getTime();
55
+ let hi = at.getTime();
56
+ while (hi - lo > 1000) {
57
+ const mid = lo + Math.floor((hi - lo) / 2);
58
+ const next = job.nextRun(new Date(mid));
59
+ if (next !== null && next.getTime() <= at.getTime())
60
+ lo = next.getTime();
61
+ else
62
+ hi = mid;
63
+ }
64
+ return new Date(lo).toISOString();
65
+ };
66
+ /** Croner is the cron arbiter: a declaration the manifest's field-shape regex
67
+ * admits but no calendar time satisfies (e.g. "99 99 * * *") must fail LOUDLY
68
+ * at the read boundary, not on a later tick's due computation. */
69
+ const assertCronValid = (cron, appId) => {
70
+ try {
71
+ // paused: constructed for validation only, never scheduled.
72
+ new Cron(cron, { timezone: "UTC", paused: true });
73
+ }
74
+ catch (error) {
75
+ throw new VendoError("validation", `invalid vendo.json: schedule cron "${cron}" is not a valid cron expression: ${error instanceof Error ? error.message : "invalid"}`, { appId });
76
+ }
77
+ };
78
+ export const createScheduleEngine = (config) => {
79
+ const states = config.store.records(SCHEDULE_STATE_COLLECTION);
80
+ const apps = config.store.records("vendo_apps");
81
+ let running;
82
+ const machineRows = async () => {
83
+ const machineBearing = [];
84
+ let cursor;
85
+ do {
86
+ const page = await apps.list(cursor === undefined ? {} : { cursor });
87
+ for (const record of page.records) {
88
+ let row;
89
+ try {
90
+ row = rowFromRecord(record);
91
+ }
92
+ catch {
93
+ continue; // Corrupt rows cannot schedule, and must not break the tick.
94
+ }
95
+ if (row.doc.machine === undefined)
96
+ continue;
97
+ machineBearing.push({ id: record.id, subject: row.subject, doc: row.doc });
98
+ }
99
+ cursor = page.cursor;
100
+ } while (cursor !== undefined);
101
+ return machineBearing;
102
+ };
103
+ /** State rows whose app lost its machine (or is gone) are ghost schedules —
104
+ * swept by listing the (small) state collection, never by probing every
105
+ * layer-1 app row. */
106
+ const sweepStaleStates = async (machineBearing) => {
107
+ let cursor;
108
+ const stale = [];
109
+ do {
110
+ const page = await states.list(cursor === undefined ? {} : { cursor });
111
+ for (const record of page.records) {
112
+ if (!machineBearing.has(record.id))
113
+ stale.push(record.id);
114
+ }
115
+ cursor = page.cursor;
116
+ } while (cursor !== undefined);
117
+ for (const appId of stale)
118
+ await states.delete(appId).catch(() => undefined);
119
+ };
120
+ const readState = async (appId) => {
121
+ const record = await states.get(appId);
122
+ if (record === null)
123
+ return null;
124
+ const parsed = scheduleStateSchema.safeParse(record.data);
125
+ // Corrupt state re-syncs from the box rather than wedging the tick.
126
+ return parsed.success ? parsed.data : null;
127
+ };
128
+ /**
129
+ * Read-mutate-CAS on one app's schedule state (the lifecycle's document
130
+ * pattern): EVERY state write is revision-checked where the store supports
131
+ * it, so a concurrent claim's `lastFiredAt` can never be rolled back by a
132
+ * racing manifest sync or outcome note (AI-review triage, PR #406). The
133
+ * mutate callback sees the freshest state on every attempt.
134
+ */
135
+ const updateState = async (appId, mutate) => {
136
+ for (let attempt = 0; attempt < CLAIM_ATTEMPTS; attempt += 1) {
137
+ const record = await states.get(appId);
138
+ const parsed = record === null ? null : scheduleStateSchema.safeParse(record.data);
139
+ const previous = parsed !== null && parsed.success ? parsed.data : null;
140
+ const next = mutate(previous);
141
+ const input = { id: appId, data: next };
142
+ if (record === null || states.atomic === undefined || record.revision === undefined) {
143
+ await states.put(input);
144
+ return next;
145
+ }
146
+ const swapped = await states.atomic.compareAndSwap(input, record.revision);
147
+ if (swapped !== null)
148
+ return next;
149
+ }
150
+ throw new VendoError("conflict", `schedule state for ${appId} was concurrently modified`, { appId });
151
+ };
152
+ const syncManifest = async (app, at = new Date()) => {
153
+ const machine = await config.lifecycle.wake(app);
154
+ // A wake may resume a snapshot whose app is still booting; retry the
155
+ // manifest read past the provider's transient "port not open".
156
+ const answer = await requestAppWithBootRetry(machine, { method: "GET", path: "/vendo.json" }, config.bootRetry ?? {});
157
+ let declared;
158
+ if (answer.status === 404) {
159
+ // No manifest is a valid box: it just declares no schedules.
160
+ declared = [];
161
+ }
162
+ else if (answer.status >= 200 && answer.status < 300) {
163
+ declared = parseVendoManifest(decoder.decode(answer.body)).schedules ?? [];
164
+ }
165
+ else {
166
+ throw new VendoError("validation", `vendo.json read failed (${answer.status})`, { appId: app.id });
167
+ }
168
+ for (const { cron } of declared)
169
+ assertCronValid(cron, app.id);
170
+ return updateState(app.id, (previous) => {
171
+ const carried = new Map((previous?.schedules ?? []).map((schedule) => [`${schedule.cron}\n${schedule.fn}`, schedule]));
172
+ return {
173
+ syncedAt: at.toISOString(),
174
+ schedules: declared.map(({ cron, fn }) => {
175
+ const kept = carried.get(`${cron}\n${fn}`);
176
+ return kept === undefined ? { cron, fn, since: at.toISOString() } : { ...kept };
177
+ }),
178
+ };
179
+ });
180
+ };
181
+ /** Claim the due occurrences in the store BEFORE firing (at-most-once): a
182
+ * racer re-reads and finds nothing due. CAS when the store supports it;
183
+ * read-then-put otherwise (the lifecycle's own degradation posture). */
184
+ const claimDue = async (appId, at) => {
185
+ for (let attempt = 0; attempt < CLAIM_ATTEMPTS; attempt += 1) {
186
+ const record = await states.get(appId);
187
+ if (record === null)
188
+ return null;
189
+ const parsed = scheduleStateSchema.safeParse(record.data);
190
+ if (!parsed.success)
191
+ return null;
192
+ const state = parsed.data;
193
+ const due = [];
194
+ const next = {
195
+ ...state,
196
+ schedules: state.schedules.map((schedule) => {
197
+ // A legacy-cached cron croner rejects is contained per schedule
198
+ // (sync validates new declarations; this guards old cache rows).
199
+ let scheduledFor;
200
+ try {
201
+ scheduledFor = latestDueOccurrence(schedule.cron, schedule.lastFiredAt ?? schedule.since, at);
202
+ }
203
+ catch {
204
+ scheduledFor = undefined;
205
+ }
206
+ if (scheduledFor === undefined)
207
+ return schedule;
208
+ due.push({ cron: schedule.cron, fn: schedule.fn, scheduledFor });
209
+ return { ...schedule, lastFiredAt: scheduledFor };
210
+ }),
211
+ };
212
+ if (due.length === 0)
213
+ return { state, due };
214
+ const input = { id: appId, data: next };
215
+ if (states.atomic === undefined || record.revision === undefined) {
216
+ await states.put(input);
217
+ return { state: next, due };
218
+ }
219
+ const swapped = await states.atomic.compareAndSwap(input, record.revision);
220
+ if (swapped !== null)
221
+ return { state: next, due };
222
+ }
223
+ return { conflict: true };
224
+ };
225
+ const recordOutcome = async (appId, fn, cron, status) => {
226
+ // Best-effort doctor detail; the claim already made the fire durable.
227
+ await updateState(appId, (previous) => ({
228
+ syncedAt: previous?.syncedAt ?? new Date().toISOString(),
229
+ schedules: (previous?.schedules ?? []).map((schedule) => schedule.cron === cron && schedule.fn === fn ? { ...schedule, lastStatus: status } : schedule),
230
+ })).catch(() => undefined);
231
+ };
232
+ const fireApp = async (row, at, report) => {
233
+ let state = await readState(row.id);
234
+ if (state === null) {
235
+ // First tick after graduation: wake once to learn the schedules. Nothing
236
+ // can be due yet — declarations only fire forward from their sync.
237
+ state = await syncManifest(row.doc, at);
238
+ return;
239
+ }
240
+ if (config.lifecycle.peek(row.id) !== undefined) {
241
+ // The box is awake anyway — re-read vendo.json so schedule edits made
242
+ // inside the box (agent sessions, layer-3 apps) are picked up. A failed
243
+ // refresh FAILS CLOSED for this tick: the cached declarations were just
244
+ // proven stale-or-unreadable, so firing them would honor a manifest the
245
+ // box may no longer declare. Loud error now, retry next tick.
246
+ try {
247
+ state = await syncManifest(row.doc, at);
248
+ }
249
+ catch (error) {
250
+ report.errors.push({ appId: row.id, message: error instanceof Error ? error.message : "manifest refresh failed" });
251
+ return;
252
+ }
253
+ }
254
+ const claimed = await claimDue(row.id, at);
255
+ if (claimed === null)
256
+ return;
257
+ if ("conflict" in claimed) {
258
+ report.errors.push({ appId: row.id, message: "schedule state was concurrently modified" });
259
+ return;
260
+ }
261
+ for (const { cron, fn, scheduledFor } of claimed.due) {
262
+ // The app's owner, away, in the app venue — the same authority a tree
263
+ // action carries when the owner isn't looking; box callbacks during the
264
+ // run ride the app token through the existing guard seams.
265
+ const ctx = {
266
+ principal: { kind: "user", subject: row.subject },
267
+ venue: "app",
268
+ presence: "away",
269
+ sessionId: `schedule_${row.id}`,
270
+ appId: row.id,
271
+ };
272
+ const outcome = await config.callFn(row.doc, fn, {}, ctx);
273
+ const status = outcome.status === "ok" ? "ok" : "error";
274
+ report.fired.push({
275
+ appId: row.id,
276
+ fn,
277
+ cron,
278
+ scheduledFor,
279
+ status,
280
+ ...(outcome.status === "error" ? { message: outcome.error.message } : {}),
281
+ });
282
+ await recordOutcome(row.id, fn, cron, status);
283
+ await config.audit?.(appLifecycleEvent({ kind: "user", subject: row.subject }, { venue: "app", presence: "away" }, row.id, { operation: "schedule-fire", fn, cron, scheduledFor }, outcome.status));
284
+ }
285
+ };
286
+ const runTick = async (at) => {
287
+ const report = { checked: 0, fired: [], errors: [] };
288
+ const machineBearing = await machineRows();
289
+ await sweepStaleStates(new Set(machineBearing.map((row) => row.id)));
290
+ for (const row of machineBearing) {
291
+ report.checked += 1;
292
+ try {
293
+ await fireApp(row, at, report);
294
+ }
295
+ catch (error) {
296
+ report.errors.push({ appId: row.id, message: error instanceof Error ? error.message : "schedule tick failed" });
297
+ }
298
+ }
299
+ return report;
300
+ };
301
+ return {
302
+ tick(at = new Date()) {
303
+ const inflight = running;
304
+ if (inflight !== undefined)
305
+ return inflight;
306
+ const run = runTick(at).finally(() => {
307
+ running = undefined;
308
+ });
309
+ running = run;
310
+ return run;
311
+ },
312
+ syncManifest,
313
+ async clearForApp(appId) {
314
+ await states.delete(appId).catch(() => undefined);
315
+ },
316
+ async report() {
317
+ const machineBearing = await machineRows();
318
+ const statuses = [];
319
+ for (const row of machineBearing) {
320
+ const state = await readState(row.id);
321
+ statuses.push({
322
+ appId: row.id,
323
+ name: row.doc.name,
324
+ provisionedAt: row.doc.machine?.provisionedAt ?? "",
325
+ awake: config.lifecycle.peek(row.id) !== undefined,
326
+ ...(state === null ? {} : { syncedAt: state.syncedAt }),
327
+ schedules: state?.schedules ?? [],
328
+ });
329
+ }
330
+ return statuses;
331
+ },
332
+ };
333
+ };
334
+ //# sourceMappingURL=schedules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.js","sourceRoot":"","sources":["../src/schedules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { type AppId, type ApprovalId, type IsoDateTime, type StoreAdapter } from "@vendoai/core";
2
+ /**
3
+ * ENG-345 — the guarded per-secret in-sandbox exposure grant (secrets
4
+ * fast-follow to the Option B gateway pick).
5
+ *
6
+ * Option B stays the DEFAULT: a declared secret enters the sandbox as an opaque
7
+ * handle and is substituted only at the egress proxy (06-apps §4.3). This grant
8
+ * is the EXCEPTION path — an explicit, per-secret × per-app, owner-only opt-in
9
+ * that places the REAL value into the sandbox env instead of a handle. It is:
10
+ * - off by default (no record → handle),
11
+ * - owner-only (only the principal who owns the app copy can set it),
12
+ * - gated by the guard's existing high-risk approval flow (written `active`
13
+ * only after the parked critical approval is decided approved),
14
+ * - audited per run (machine.ts emits one exposed-run event per run), and
15
+ * - NEVER carried by shares/remixes.
16
+ *
17
+ * The last invariant is enforced structurally, not by stripping: these grants
18
+ * live in their OWN store collection keyed by the app's id, and are never part
19
+ * of the app document that exportApp/share/publish/fork/importApp copy. A copy
20
+ * always gets a fresh AppId (06-apps §7), which by construction has no grants —
21
+ * so a copied app can never inherit an exposure grant.
22
+ */
23
+ export interface SecretExposureGrant {
24
+ appId: AppId;
25
+ secretName: string;
26
+ /** The app owner's principal subject — the only principal who may set this. */
27
+ owner: string;
28
+ /** `pending` = parked on a high-risk approval; `active` = approved and live. */
29
+ status: "pending" | "active";
30
+ /** The guard approval that gates turning this on (06-apps §9 approval model). */
31
+ approvalId: ApprovalId;
32
+ requestedAt: IsoDateTime;
33
+ grantedAt?: IsoDateTime;
34
+ }
35
+ /** ENG-345 — persistence for per-secret × per-app in-sandbox exposure grants. */
36
+ export interface SecretExposure {
37
+ /** Active grants for one app (owner-scoped by construction). */
38
+ active(appId: AppId): Promise<SecretExposureGrant[]>;
39
+ /** Names of secrets currently exposed in-sandbox for one app. */
40
+ activeNames(appId: AppId): Promise<Set<string>>;
41
+ /** Every grant (pending + active) for one app. */
42
+ list(appId: AppId): Promise<SecretExposureGrant[]>;
43
+ /** Park a grant on a high-risk approval (status `pending`). */
44
+ putPending(grant: Omit<SecretExposureGrant, "status">): Promise<void>;
45
+ /** Flip a parked grant to `active` once its approval is approved. Returns the grant, or null if none pending. */
46
+ activate(appId: AppId, secretName: string): Promise<SecretExposureGrant | null>;
47
+ /** Turn a secret off — reverts to the Option B handle default. */
48
+ revoke(appId: AppId, secretName: string): Promise<void>;
49
+ /** Grants (pending/active) parked on a specific approval id. */
50
+ byApproval(approvalId: ApprovalId): Promise<SecretExposureGrant[]>;
51
+ /** Delete every grant for one app (app deletion cleanup). */
52
+ clearForApp(appId: AppId): Promise<void>;
53
+ }
54
+ export declare const createSecretExposure: (store: StoreAdapter) => SecretExposure;
55
+ //# sourceMappingURL=secret-exposure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-exposure.d.ts","sourceRoot":"","sources":["../src/secret-exposure.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EAElB,MAAM,eAAe,CAAC;AAGvB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,iFAAiF;IACjF,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAYD,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACrD,iEAAiE;IACjE,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,kDAAkD;IAClD,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACnD,+DAA+D;IAC/D,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,iHAAiH;IACjH,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAChF,kEAAkE;IAClE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,gEAAgE;IAChE,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACnE,6DAA6D;IAC7D,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,oBAAoB,GAAI,OAAO,YAAY,KAAG,cA+C1D,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { listAllRecords } from "./persistence.js";
2
+ /** Deterministic id so re-requesting the same (app, secret) overwrites, never duplicates. */
3
+ const recordId = (appId, secretName) => `xpo_${appId}__${secretName}`;
4
+ const COLLECTION = "vendo_secret_exposure";
5
+ const grantData = (record) => record.data;
6
+ const listAll = (store, refs) => listAllRecords(store.records(COLLECTION), { refs });
7
+ export const createSecretExposure = (store) => {
8
+ const collection = store.records(COLLECTION);
9
+ const refsFor = (grant) => ({
10
+ subject: grant.owner,
11
+ app_id: grant.appId,
12
+ secret: grant.secretName,
13
+ status: grant.status,
14
+ approval: grant.approvalId,
15
+ });
16
+ const list = async (appId) => (await listAll(store, { app_id: appId })).map(grantData);
17
+ return {
18
+ list,
19
+ async active(appId) {
20
+ return (await list(appId)).filter((grant) => grant.status === "active");
21
+ },
22
+ async activeNames(appId) {
23
+ return new Set((await list(appId)).filter((grant) => grant.status === "active").map((grant) => grant.secretName));
24
+ },
25
+ async putPending(grant) {
26
+ const full = { ...grant, status: "pending" };
27
+ await collection.put({ id: recordId(grant.appId, grant.secretName), data: full, refs: refsFor(full) });
28
+ },
29
+ async activate(appId, secretName) {
30
+ const record = await collection.get(recordId(appId, secretName));
31
+ if (record === null)
32
+ return null;
33
+ const grant = grantData(record);
34
+ if (grant.status === "active")
35
+ return grant;
36
+ const activated = { ...grant, status: "active", grantedAt: new Date().toISOString() };
37
+ await collection.put({ id: record.id, data: activated, refs: refsFor(activated) });
38
+ return activated;
39
+ },
40
+ async revoke(appId, secretName) {
41
+ await collection.delete(recordId(appId, secretName));
42
+ },
43
+ async byApproval(approvalId) {
44
+ return (await listAll(store, { approval: approvalId })).map(grantData);
45
+ },
46
+ async clearForApp(appId) {
47
+ for (const record of await listAll(store, { app_id: appId })) {
48
+ await collection.delete(record.id);
49
+ }
50
+ },
51
+ };
52
+ };
53
+ //# sourceMappingURL=secret-exposure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-exposure.js","sourceRoot":"","sources":["../src/secret-exposure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { AppDocument, AppId } from "@vendoai/core";
2
+ import { type PinBaseline } from "./pins.js";
3
+ /**
4
+ * 06-apps §8–§9 — the reviewable ship-diff for one app version: everything the
5
+ * app would ship into the host page relative to the captured host baselines.
6
+ * This is the artifact a human approver reads before minting an
7
+ * `InClientApproval` (OSS computes and verifies; Cloud's review console
8
+ * displays it and mints). Additive runtime surface — not part of the frozen
9
+ * 06 §1 method table.
10
+ */
11
+ export interface ShipDiff {
12
+ appId: AppId;
13
+ /** `appVersionHash` of the reviewed version — the hash an approval pins. */
14
+ versionHash: string;
15
+ /** Pinned host slots: the net diff of the fork against the captured baseline. */
16
+ pins: ShipDiffPin[];
17
+ /** Generated components with no host baseline: reviewed as pure additions. */
18
+ generated: ShipDiffGenerated[];
19
+ }
20
+ export interface ShipDiffPin {
21
+ slot: string;
22
+ /** The generated-component name the fork ships under (`pinComponentName`). */
23
+ component: string;
24
+ /** The baseline hash the pin was forked from (`Pin.base`). */
25
+ baseHash: string;
26
+ /** The hash of the currently captured host baseline, when one exists. */
27
+ baselineHash?: string;
28
+ /**
29
+ * True when the host component changed under the pin (baseline hash no
30
+ * longer matches `baseHash`) or the baseline is missing entirely — the
31
+ * approver is not looking at the source the fork was made from.
32
+ */
33
+ drifted: boolean;
34
+ /** Unified diff from the captured host source to the shipped fork source. */
35
+ diff: string;
36
+ }
37
+ export interface ShipDiffGenerated {
38
+ component: string;
39
+ /** Unified diff from nothing — the entire shipped source, as additions. */
40
+ diff: string;
41
+ }
42
+ /**
43
+ * Compute the ship-diff of an app version against the captured host baselines.
44
+ * Pure over its inputs so Cloud's console and tests can reuse it verbatim.
45
+ */
46
+ export declare const computeShipDiff: (doc: AppDocument, baselines: readonly PinBaseline[]) => ShipDiff;
47
+ //# sourceMappingURL=ship-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-diff.d.ts","sourceRoot":"","sources":["../src/ship-diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAmC,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG9E;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,8EAA8E;IAC9E,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK,WAAW,EAChB,WAAW,SAAS,WAAW,EAAE,KAChC,QA8BF,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { appVersionHash } from "./version-hash.js";
2
+ import { pinComponentName, pinForkSource } from "./pins.js";
3
+ import { unifiedDiff } from "./unified-diff.js";
4
+ /**
5
+ * Compute the ship-diff of an app version against the captured host baselines.
6
+ * Pure over its inputs so Cloud's console and tests can reuse it verbatim.
7
+ */
8
+ export const computeShipDiff = (doc, baselines) => {
9
+ const pins = (doc.pins ?? []).map((pin) => {
10
+ const component = pinComponentName(pin.slot);
11
+ const baseline = baselines.find((candidate) => candidate.slot === pin.slot);
12
+ const shipped = doc.components?.[component] ?? "";
13
+ return {
14
+ slot: pin.slot,
15
+ component,
16
+ baseHash: pin.base,
17
+ ...(baseline === undefined ? {} : { baselineHash: baseline.hash }),
18
+ drifted: baseline?.hash !== pin.base,
19
+ // Diff from the source the fork actually started as (`pinForkSource`):
20
+ // the synthesized default-export alias on a named-export capture is fork
21
+ // plumbing, not a host edit, so an unedited fork reads as an empty diff.
22
+ diff: unifiedDiff(`${pin.slot}/${component}.tsx`, baseline === undefined ? "" : pinForkSource(baseline.source), shipped),
23
+ };
24
+ });
25
+ const pinnedComponents = new Set(pins.map((pin) => pin.component));
26
+ const generated = Object.entries(doc.components ?? {})
27
+ .filter(([name]) => !pinnedComponents.has(name))
28
+ .map(([name, source]) => ({
29
+ component: name,
30
+ diff: unifiedDiff(`generated/${name}.tsx`, "", source),
31
+ }));
32
+ return {
33
+ appId: doc.id,
34
+ versionHash: appVersionHash(doc),
35
+ pins,
36
+ generated,
37
+ };
38
+ };
39
+ //# sourceMappingURL=ship-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-diff.js","sourceRoot":"","sources":["../src/ship-diff.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAoB,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA4ChD;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAgB,EAChB,SAAiC,EACvB,EAAE;IACZ,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAe,EAAE;QACrD,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAClD,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS;YACT,QAAQ,EAAE,GAAG,CAAC,IAAI;YAClB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;YAClE,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK,GAAG,CAAC,IAAI;YACpC,uEAAuE;YACvE,yEAAyE;YACzE,yEAAyE;YACzE,IAAI,EAAE,WAAW,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;SACzH,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;SACnD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;SAC/C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAqB,EAAE,CAAC,CAAC;QAC3C,SAAS,EAAE,IAAI;QACf,IAAI,EAAE,WAAW,CAAC,aAAa,IAAI,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC;KACvD,CAAC,CAAC,CAAC;IACN,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,EAAE;QACb,WAAW,EAAE,cAAc,CAAC,GAAG,CAAC;QAChC,IAAI;QACJ,SAAS;KACV,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ import type { SandboxAdapter, SandboxMachine } from "../sandbox.js";
2
+ import type { BoxEditResult } from "../box-agent.js";
3
+ /** The mutable inside-the-box state an in-box agent edits. */
4
+ export interface FakeBoxState {
5
+ env: Record<string, string>;
6
+ /** The vendo.json the box serves (schedules + egress declarations). */
7
+ manifest: {
8
+ schedules?: Array<{
9
+ cron: string;
10
+ fn: string;
11
+ }>;
12
+ egress?: string[];
13
+ };
14
+ /** POST /fn/<name> handlers the agent installed. */
15
+ fns: Map<string, (args: unknown, env: Record<string, string>) => unknown>;
16
+ /**
17
+ * Wave 4 (layer 3) — served pages the agent installed on non-/fn GET paths
18
+ * (path → HTML body). When present, the box "serves a real web app".
19
+ */
20
+ pages: Map<string, string>;
21
+ }
22
+ /** The injectable in-box coding agent: mutates box state, returns a result. */
23
+ export type FakeBoxAgent = (task: {
24
+ prompt: string;
25
+ context?: string;
26
+ env: Record<string, string>;
27
+ box: FakeBoxState;
28
+ }) => BoxEditResult | Promise<BoxEditResult>;
29
+ interface FakeBoxOptions {
30
+ agent?: FakeBoxAgent;
31
+ }
32
+ export interface FakeBoxAdapter extends SandboxAdapter {
33
+ /** Every machine this adapter created (for assertions on live/torn-down state). */
34
+ readonly machines: FakeBoxMachine[];
35
+ }
36
+ declare class FakeBoxMachine implements SandboxMachine {
37
+ readonly state: FakeBoxState;
38
+ readonly allowedDomains: readonly string[] | undefined;
39
+ private readonly agent;
40
+ readonly id: string;
41
+ destroyed: boolean;
42
+ stopped: boolean;
43
+ /** Task results by id (control-port task store). */
44
+ private readonly tasks;
45
+ constructor(state: FakeBoxState, allowedDomains: readonly string[] | undefined, agent: FakeBoxAgent);
46
+ private appPort;
47
+ request(req: {
48
+ method: string;
49
+ path: string;
50
+ port?: number;
51
+ headers?: Record<string, string>;
52
+ body?: Uint8Array | string;
53
+ }): Promise<{
54
+ status: number;
55
+ headers: Record<string, string>;
56
+ body: Uint8Array;
57
+ }>;
58
+ private control;
59
+ private app;
60
+ url(port?: number): Promise<string>;
61
+ snapshot(): Promise<string>;
62
+ stop(): Promise<void>;
63
+ destroy(): Promise<void>;
64
+ }
65
+ export declare const fakeBoxSandbox: (options?: FakeBoxOptions) => FakeBoxAdapter;
66
+ export {};
67
+ //# sourceMappingURL=fake-box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-box.d.ts","sourceRoot":"","sources":["../../src/testing/fake-box.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAgBrD,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjF,oDAAoD;IACpD,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,CAAC;IAC1E;;;OAGG;IACH,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,YAAY,CAAC;CACnB,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAU7C,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAMD,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;CACrC;AAED,cAAM,cAAe,YAAW,cAAc;IAQ1C,QAAQ,CAAC,KAAK,EAAE,YAAY;IAC5B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS;IACtD,OAAO,CAAC,QAAQ,CAAC,KAAK;IATxB,QAAQ,CAAC,EAAE,SAAqB;IAChC,SAAS,UAAS;IAClB,OAAO,UAAS;IAChB,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6E;gBAGxF,KAAK,EAAE,YAAY,EACnB,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACrC,KAAK,EAAE,YAAY;IAGtC,OAAO,CAAC,OAAO;IAKT,OAAO,CAAC,GAAG,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;YAcpE,OAAO;IAiCrB,OAAO,CAAC,GAAG;IAqCL,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAa3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAC/B;AAED,eAAO,MAAM,cAAc,GAAI,UAAS,cAAmB,KAAG,cAgC7D,CAAC"}