@descryy/runtime-orchestrator 0.3.0 → 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 (46) hide show
  1. package/LICENSE +6 -0
  2. package/dist/attach-to-running-jvm-process.d.ts +45 -98
  3. package/dist/attach-to-running-jvm-process.d.ts.map +1 -1
  4. package/dist/attach-to-running-jvm-process.js +206 -136
  5. package/dist/attach-to-running-jvm-process.js.map +1 -1
  6. package/dist/attach-to-running-node-process.d.ts +45 -103
  7. package/dist/attach-to-running-node-process.d.ts.map +1 -1
  8. package/dist/attach-to-running-node-process.js +90 -115
  9. package/dist/attach-to-running-node-process.js.map +1 -1
  10. package/dist/attach-to-running-process.d.ts +32 -70
  11. package/dist/attach-to-running-process.d.ts.map +1 -1
  12. package/dist/attach-to-running-process.js +26 -54
  13. package/dist/attach-to-running-process.js.map +1 -1
  14. package/dist/cdp-client.d.ts +8 -18
  15. package/dist/cdp-client.d.ts.map +1 -1
  16. package/dist/cdp-client.js +9 -22
  17. package/dist/cdp-client.js.map +1 -1
  18. package/dist/cgroup-partial-restriction.d.ts +42 -89
  19. package/dist/cgroup-partial-restriction.d.ts.map +1 -1
  20. package/dist/cgroup-partial-restriction.js +44 -91
  21. package/dist/cgroup-partial-restriction.js.map +1 -1
  22. package/dist/collector-version.d.ts +3 -8
  23. package/dist/collector-version.d.ts.map +1 -1
  24. package/dist/collector-version.js +3 -8
  25. package/dist/collector-version.js.map +1 -1
  26. package/dist/instrumented-execution.d.ts +30 -73
  27. package/dist/instrumented-execution.d.ts.map +1 -1
  28. package/dist/instrumented-execution.js +103 -251
  29. package/dist/instrumented-execution.js.map +1 -1
  30. package/dist/jvm-agent/build.d.ts +29 -53
  31. package/dist/jvm-agent/build.d.ts.map +1 -1
  32. package/dist/jvm-agent/build.js +34 -61
  33. package/dist/jvm-agent/build.js.map +1 -1
  34. package/dist/polling-output-source.d.ts +8 -19
  35. package/dist/polling-output-source.d.ts.map +1 -1
  36. package/dist/polling-output-source.js +14 -31
  37. package/dist/polling-output-source.js.map +1 -1
  38. package/dist/profile-backend-observation.d.ts +26 -53
  39. package/dist/profile-backend-observation.d.ts.map +1 -1
  40. package/dist/profile-backend-observation.js +26 -55
  41. package/dist/profile-backend-observation.js.map +1 -1
  42. package/dist/respawn-and-supervise.d.ts +39 -72
  43. package/dist/respawn-and-supervise.d.ts.map +1 -1
  44. package/dist/respawn-and-supervise.js +43 -84
  45. package/dist/respawn-and-supervise.js.map +1 -1
  46. package/package.json +14 -9
@@ -1,42 +1,21 @@
1
1
  /**
2
- * Attach observation to a process Descry did not spawn (RUNTIME-CHECKLIST.md
3
- * §39 item 1's open half — "execute yes; attach: not implemented").
2
+ * Attach observation to a process Descry did not spawn.
4
3
  *
5
- * **What this honestly covers, and what it does not.** Every collector in
6
- * this repo reads a `ProcessOutputSource` (`process-output.ts`), and the
7
- * only live implementation (`createPollingProcessOutputSource`) is already
8
- * source-agnostic it needs a growing `readOutput(): string` and a boolean
9
- * `isFinished()`, nothing that presumes we spawned the process. `execute`
10
- * satisfies those from `ManagedProcess`'s in-memory pipe buffer
11
- * (`process-manager.ts`), which exists only because `child_process.spawn`
12
- * wired the pipes *at spawn time* — Node (and POSIX generally) gives no way
13
- * to retroactively attach to another process's stdout/stderr fds after the
14
- * fact. So true retroactive attach to an *arbitrary* already-running
15
- * process — one that logs to a TTY, or that never wrote its output
16
- * anywhere Descry can now reach — is not implemented here and is not a
17
- * bounded slice: it would need a per-language debugger/inspector protocol
18
- * (e.g. Node's own `SIGUSR1` inspector activation, JVM's Attach API, a
19
- * `/proc` ptrace shim on Linux only), each its own multi-week surface,
20
- * scoped in `documents/decisions-inbox/RT-attach-to-running-process-scope.md`.
4
+ * Node/POSIX give no way to retroactively attach to another process's
5
+ * stdout/stderr fds after the fact — pipes are only wired at spawn time. So true
6
+ * generic attach (a process that logs to a TTY, or never wrote output anywhere
7
+ * reachable) is not implemented; it would need a per-language debugger/inspector
8
+ * protocol, scoped separately in `documents/decisions-inbox/RT-attach-to-running-process-scope.md`.
21
9
  *
22
- * What IS real and implemented: attaching to a process that is already
23
- * running and was already directed to write its output to a file Descry
24
- * can read e.g. a dev server the user started with
25
- * `npm run dev > server.log 2>&1 &`, or any long-lived service whose
26
- * stdout/stderr is already redirected to disk. This is candidate (a), not
27
- * (b): narrower than generic attach, but a real, testable capability —
28
- * `attachToRunningProcess` verifies the target PID is alive, then reuses
29
- * the exact same live-tail machinery `execute` uses, catching up on
30
- * whatever the file already held *before* attach and then tailing new
31
- * writes exactly like a spawned process's buffer.
10
+ * What IS implemented: attaching to a process already directed to write output to
11
+ * a file Descry can read (e.g. `npm run dev > server.log 2>&1 &`).
12
+ * `attachToRunningProcess` verifies the target pid is alive, then reuses `execute`'s
13
+ * live-tail machinery, catching up on what the file already held and tailing new
14
+ * writes the same way.
32
15
  *
33
- * **Shares `execute`'s known identity gap (RT-024).** `isProcessAlive`
34
- * confirms *a* process with this pid exists, not that it is the one the
35
- * caller thinks it is pids are reused by the OS. `execute`'s own
36
- * readiness checks carry the identical caveat (see `readiness.ts`'s own
37
- * doc comment) and it is disclosed there rather than solved; the same is
38
- * true here, for the same reason: nothing in a bare pid or a bare file
39
- * path proves provenance.
16
+ * **Shares `execute`'s identity gap (RT-024).** `isProcessAlive` confirms a process
17
+ * with this pid exists, not that it's the one the caller thinks — pids are reused.
18
+ * Disclosed, not solved, same as `readiness.ts`.
40
19
  */
41
20
  import type { ProcessOutputSource } from "@descryy/runtime-backend-observation";
42
21
  export interface AttachToRunningProcessOptions {
@@ -46,31 +25,18 @@ export interface AttachToRunningProcessOptions {
46
25
  /** Path to a file the target process is already writing its stdout/stderr to. Read in full on every poll — same growing-buffer contract `ManagedProcess.readOutput()` has, not a delta. */
47
26
  readonly logFilePath: string;
48
27
  /**
49
- * The declared service this pid is, carried onto every `Evidence` a collector
50
- * built over this source emits. Optional here, unlike on the source itself,
51
- * because an attach to a bare pid genuinely may have no declared service
52
- * behind it — and omitting it resolves to `null`, which is a statement, not a
53
- * gap. Supply it whenever the caller *does* know: without it, correlation
54
- * cannot look a scope up for anything this source produces.
28
+ * The declared service this pid is. Optional because a bare-pid attach may
29
+ * genuinely have none declared omitting it resolves to `null`, a statement,
30
+ * not a gap. Without it, correlation can't look up a scope for this source.
55
31
  */
56
32
  readonly serviceName?: string | null;
57
33
  /**
58
- * True once the caller's observation window has closed. Required, and the
59
- * reason it is not optional is the bug it was added to fix.
60
- *
61
- * A source over an attached target has two independent reasons to end: the
62
- * target exited, or the caller stopped watching. The liveness check covers
63
- * only the first, and for a healthy attached service it is never true — so
64
- * with no second signal the source polls a live buffer forever. Two things
65
- * follow, and the second is the worse: the final line held in the splitter
66
- * for want of a newline is never flushed, and a consumer that stops
67
- * iterating never gets its generator back.
68
- *
69
- * The spawn path has always had this signal (`instrumented-execution.ts`
70
- * flips a `finished` flag immediately before `collector.stop()`, with an
71
- * ordering comment explaining that stop() would otherwise wait forever).
72
- * This is the same signal, and defaulting it to "never stops" would leave
73
- * both failures reachable by simply not passing it.
34
+ * True once the caller's observation window has closed. Required: a source has
35
+ * two independent end conditions (target exited, or caller stopped watching),
36
+ * and the liveness check alone never fires for a healthy target — without this,
37
+ * the source polls forever, the final unflushed line is lost, and a consumer
38
+ * that stops iterating never gets its generator back. Same signal
39
+ * `instrumented-execution.ts` uses before `collector.stop()`.
74
40
  */
75
41
  readonly stopObserving: () => boolean;
76
42
  readonly pollIntervalMs?: number;
@@ -83,21 +49,17 @@ export interface AttachToRunningProcessOptions {
83
49
  */
84
50
  export declare function isProcessAlive(pid: number): boolean;
85
51
  /**
86
- * Attach to an already-running process via a log file it is already
87
- * writing to. Throws immediately if the pid is not alive at call time
88
- * refusing rather than returning a source that would silently never emit
89
- * anything, the same "loud, not quiet" contract `ProcessCollector` uses for
90
- * its own ordering requirement.
52
+ * Attach to an already-running process via a log file it is already writing to.
53
+ * Throws immediately if the pid isn't alive refuses rather than returning a
54
+ * source that would silently never emit anything.
91
55
  *
92
- * Lines already in `logFilePath` at attach time are yielded first (the
93
- * "already running before we attached" evidence this is for), followed by
94
- * whatever the target writes afterward — indistinguishable, once attached,
95
- * from `execute`'s own live tail.
56
+ * Lines already in `logFilePath` at attach time are yielded first, followed by
57
+ * whatever the target writes afterward indistinguishable from `execute`'s live
58
+ * tail once attached.
96
59
  *
97
- * **Ending.** The source ends when the caller's window closes or the target
98
- * exits, whichever comes first see `stopObserving`. Both halves are needed:
99
- * the liveness check alone never fires for a healthy target, and the window
100
- * signal alone would poll a dead one until the caller noticed.
60
+ * Ends when the caller's window closes or the target exits, whichever comes
61
+ * first (see `stopObserving`) both are needed, or a healthy target polls
62
+ * forever, or a dead one polls until the caller notices.
101
63
  */
102
64
  export declare function attachToRunningProcess(options: AttachToRunningProcessOptions): ProcessOutputSource;
103
65
  //# sourceMappingURL=attach-to-running-process.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attach-to-running-process.d.ts","sourceRoot":"","sources":["../src/attach-to-running-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAIhF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2HAA2H;IAC3H,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,2LAA2L;IAC3L,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,mBAAmB,CA8BlG"}
1
+ {"version":3,"file":"attach-to-running-process.d.ts","sourceRoot":"","sources":["../src/attach-to-running-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAIhF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2HAA2H;IAC3H,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,2LAA2L;IAC3L,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,mBAAmB,CA2BlG"}
@@ -1,42 +1,21 @@
1
1
  /**
2
- * Attach observation to a process Descry did not spawn (RUNTIME-CHECKLIST.md
3
- * §39 item 1's open half — "execute yes; attach: not implemented").
2
+ * Attach observation to a process Descry did not spawn.
4
3
  *
5
- * **What this honestly covers, and what it does not.** Every collector in
6
- * this repo reads a `ProcessOutputSource` (`process-output.ts`), and the
7
- * only live implementation (`createPollingProcessOutputSource`) is already
8
- * source-agnostic it needs a growing `readOutput(): string` and a boolean
9
- * `isFinished()`, nothing that presumes we spawned the process. `execute`
10
- * satisfies those from `ManagedProcess`'s in-memory pipe buffer
11
- * (`process-manager.ts`), which exists only because `child_process.spawn`
12
- * wired the pipes *at spawn time* — Node (and POSIX generally) gives no way
13
- * to retroactively attach to another process's stdout/stderr fds after the
14
- * fact. So true retroactive attach to an *arbitrary* already-running
15
- * process — one that logs to a TTY, or that never wrote its output
16
- * anywhere Descry can now reach — is not implemented here and is not a
17
- * bounded slice: it would need a per-language debugger/inspector protocol
18
- * (e.g. Node's own `SIGUSR1` inspector activation, JVM's Attach API, a
19
- * `/proc` ptrace shim on Linux only), each its own multi-week surface,
20
- * scoped in `documents/decisions-inbox/RT-attach-to-running-process-scope.md`.
4
+ * Node/POSIX give no way to retroactively attach to another process's
5
+ * stdout/stderr fds after the fact — pipes are only wired at spawn time. So true
6
+ * generic attach (a process that logs to a TTY, or never wrote output anywhere
7
+ * reachable) is not implemented; it would need a per-language debugger/inspector
8
+ * protocol, scoped separately in `documents/decisions-inbox/RT-attach-to-running-process-scope.md`.
21
9
  *
22
- * What IS real and implemented: attaching to a process that is already
23
- * running and was already directed to write its output to a file Descry
24
- * can read e.g. a dev server the user started with
25
- * `npm run dev > server.log 2>&1 &`, or any long-lived service whose
26
- * stdout/stderr is already redirected to disk. This is candidate (a), not
27
- * (b): narrower than generic attach, but a real, testable capability —
28
- * `attachToRunningProcess` verifies the target PID is alive, then reuses
29
- * the exact same live-tail machinery `execute` uses, catching up on
30
- * whatever the file already held *before* attach and then tailing new
31
- * writes exactly like a spawned process's buffer.
10
+ * What IS implemented: attaching to a process already directed to write output to
11
+ * a file Descry can read (e.g. `npm run dev > server.log 2>&1 &`).
12
+ * `attachToRunningProcess` verifies the target pid is alive, then reuses `execute`'s
13
+ * live-tail machinery, catching up on what the file already held and tailing new
14
+ * writes the same way.
32
15
  *
33
- * **Shares `execute`'s known identity gap (RT-024).** `isProcessAlive`
34
- * confirms *a* process with this pid exists, not that it is the one the
35
- * caller thinks it is pids are reused by the OS. `execute`'s own
36
- * readiness checks carry the identical caveat (see `readiness.ts`'s own
37
- * doc comment) and it is disclosed there rather than solved; the same is
38
- * true here, for the same reason: nothing in a bare pid or a bare file
39
- * path proves provenance.
16
+ * **Shares `execute`'s identity gap (RT-024).** `isProcessAlive` confirms a process
17
+ * with this pid exists, not that it's the one the caller thinks — pids are reused.
18
+ * Disclosed, not solved, same as `readiness.ts`.
40
19
  */
41
20
  import { readFileSync } from "node:fs";
42
21
  import { createPollingProcessOutputSource } from "./polling-output-source.js";
@@ -56,21 +35,17 @@ export function isProcessAlive(pid) {
56
35
  }
57
36
  }
58
37
  /**
59
- * Attach to an already-running process via a log file it is already
60
- * writing to. Throws immediately if the pid is not alive at call time
61
- * refusing rather than returning a source that would silently never emit
62
- * anything, the same "loud, not quiet" contract `ProcessCollector` uses for
63
- * its own ordering requirement.
38
+ * Attach to an already-running process via a log file it is already writing to.
39
+ * Throws immediately if the pid isn't alive refuses rather than returning a
40
+ * source that would silently never emit anything.
64
41
  *
65
- * Lines already in `logFilePath` at attach time are yielded first (the
66
- * "already running before we attached" evidence this is for), followed by
67
- * whatever the target writes afterward — indistinguishable, once attached,
68
- * from `execute`'s own live tail.
42
+ * Lines already in `logFilePath` at attach time are yielded first, followed by
43
+ * whatever the target writes afterward indistinguishable from `execute`'s live
44
+ * tail once attached.
69
45
  *
70
- * **Ending.** The source ends when the caller's window closes or the target
71
- * exits, whichever comes first see `stopObserving`. Both halves are needed:
72
- * the liveness check alone never fires for a healthy target, and the window
73
- * signal alone would poll a dead one until the caller noticed.
46
+ * Ends when the caller's window closes or the target exits, whichever comes
47
+ * first (see `stopObserving`) both are needed, or a healthy target polls
48
+ * forever, or a dead one polls until the caller notices.
74
49
  */
75
50
  export function attachToRunningProcess(options) {
76
51
  if (!isProcessAlive(options.pid)) {
@@ -79,9 +54,7 @@ export function attachToRunningProcess(options) {
79
54
  }
80
55
  return createPollingProcessOutputSource({
81
56
  processId: options.processId,
82
- // An attach may or may not have a declared service behind it. `null` here
83
- // is the honest answer for an ad-hoc attach to a pid, and it is stated
84
- // rather than defaulted in the source itself.
57
+ // an ad-hoc attach may have no declared service; null is the honest answer
85
58
  serviceName: options.serviceName ?? null,
86
59
  readOutput: () => {
87
60
  try {
@@ -92,9 +65,8 @@ export function attachToRunningProcess(options) {
92
65
  throw new Error(`attachToRunningProcess: could not read log file "${options.logFilePath}" for pid ${options.pid}: ${detail}`);
93
66
  }
94
67
  },
95
- // A disjunction, not a replacement: either reason genuinely ends the
96
- // source, and dropping the liveness half would leave a target that dies
97
- // mid-window polled until the caller happened to notice.
68
+ // either reason ends the source; dropping the liveness half would leave a
69
+ // target that dies mid-window polled until the caller noticed
98
70
  isFinished: () => options.stopObserving() || !isProcessAlive(options.pid),
99
71
  ...(options.pollIntervalMs !== undefined ? { pollIntervalMs: options.pollIntervalMs } : {}),
100
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"attach-to-running-process.js","sourceRoot":"","sources":["../src/attach-to-running-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,OAAO,EAAE,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAuC9E;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAsC;IAC3E,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,+BAA+B,OAAO,CAAC,GAAG,SAAS,OAAO,CAAC,SAAS,qCAAqC;YACvG,6FAA6F,CAChG,CAAC;IACJ,CAAC;IAED,OAAO,gCAAgC,CAAC;QACtC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,0EAA0E;QAC1E,uEAAuE;QACvE,8CAA8C;QAC9C,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,UAAU,EAAE,GAAG,EAAE;YACf,IAAI,CAAC;gBACH,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACtE,MAAM,IAAI,KAAK,CACb,oDAAoD,OAAO,CAAC,WAAW,aAAa,OAAO,CAAC,GAAG,KAAK,MAAM,EAAE,CAC7G,CAAC;YACJ,CAAC;QACH,CAAC;QACD,qEAAqE;QACrE,wEAAwE;QACxE,yDAAyD;QACzD,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5F,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"attach-to-running-process.js","sourceRoot":"","sources":["../src/attach-to-running-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,OAAO,EAAE,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AA0B9E;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAsC;IAC3E,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,+BAA+B,OAAO,CAAC,GAAG,SAAS,OAAO,CAAC,SAAS,qCAAqC;YACvG,6FAA6F,CAChG,CAAC;IACJ,CAAC;IAED,OAAO,gCAAgC,CAAC;QACtC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,2EAA2E;QAC3E,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,UAAU,EAAE,GAAG,EAAE;YACf,IAAI,CAAC;gBACH,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACtE,MAAM,IAAI,KAAK,CACb,oDAAoD,OAAO,CAAC,WAAW,aAAa,OAAO,CAAC,GAAG,KAAK,MAAM,EAAE,CAC7G,CAAC;YACJ,CAAC;QACH,CAAC;QACD,0EAA0E;QAC1E,8DAA8D;QAC9D,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5F,CAAC,CAAC;AACL,CAAC"}
@@ -1,25 +1,15 @@
1
1
  /**
2
2
  * A minimal Chrome DevTools Protocol client over a raw `ws://` URL.
3
3
  *
4
- * **Why this exists rather than reusing something already in the repo.**
5
- * `packages/browser` speaks CDP too, but only through Playwright's own
6
- * `page.on("console"/"pageerror")` API (`browser-console-collector.ts`)
7
- * Playwright owns the actual WebSocket and the Target/Page domain framing
8
- * underneath it, and never exposes a bare "connect to an arbitrary `ws://`
9
- * endpoint and read raw CDP frames" surface. A Node inspector session has no
10
- * `Target`/`Page` domains at all — it is a single top-level session speaking
11
- * `Runtime`/`Debugger`/`Console` directly — so Playwright's browser
12
- * abstraction does not fit it even if pressed into service. Checked before
13
- * writing this: nothing else in the repo opens a WebSocket to a CDP
14
- * endpoint directly. This is that client, kept protocol-family-generic (it
15
- * knows nothing about "Node" or "browser") so a future CDP target of either
16
- * kind can reuse it instead of a third one being written.
4
+ * `packages/browser` speaks CDP only through Playwright's console API, which owns its
5
+ * own WebSocket and Target/Page framing and has no "connect to an arbitrary ws:// and
6
+ * read raw CDP frames" surface a Node inspector session has no Target/Page domains
7
+ * at all, so that abstraction doesn't fit. Kept protocol-family-generic (no "Node" or
8
+ * "browser" knowledge) so either kind of CDP target can reuse it.
17
9
  *
18
- * CDP-over-WebSocket is JSON-RPC-shaped: a sent message carries `id` and
19
- * gets exactly one `{id, result}` or `{id, error}` reply; an event has
20
- * `method`/`params` and no `id`. This client does nothing more than that
21
- * framing — domain-specific method names and event shapes belong to the
22
- * caller, not here.
10
+ * CDP-over-WebSocket is JSON-RPC-shaped: a sent message carries `id` and gets exactly
11
+ * one `{id, result}` or `{id, error}` reply; an event has `method`/`params`, no `id`.
12
+ * This client does only that framing method names and event shapes are the caller's.
23
13
  */
24
14
  export interface CdpSession {
25
15
  /** Sends a CDP command and resolves with its `result` once the matching `id` reply arrives. Rejects on a CDP-reported `error` or if the socket closes first. */
@@ -1 +1 @@
1
- {"version":3,"file":"cdp-client.d.ts","sourceRoot":"","sources":["../src/cdp-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,UAAU;IACzB,gKAAgK;IAChK,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAChF,qHAAqH;IACrH,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACnF,yFAAyF;IACzF,KAAK,IAAI,IAAI,CAAC;CACf;AAOD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmFpE"}
1
+ {"version":3,"file":"cdp-client.d.ts","sourceRoot":"","sources":["../src/cdp-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,UAAU;IACzB,gKAAgK;IAChK,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAChF,qHAAqH;IACrH,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACnF,yFAAyF;IACzF,KAAK,IAAI,IAAI,CAAC;CACf;AAOD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAgFpE"}
@@ -1,25 +1,15 @@
1
1
  /**
2
2
  * A minimal Chrome DevTools Protocol client over a raw `ws://` URL.
3
3
  *
4
- * **Why this exists rather than reusing something already in the repo.**
5
- * `packages/browser` speaks CDP too, but only through Playwright's own
6
- * `page.on("console"/"pageerror")` API (`browser-console-collector.ts`)
7
- * Playwright owns the actual WebSocket and the Target/Page domain framing
8
- * underneath it, and never exposes a bare "connect to an arbitrary `ws://`
9
- * endpoint and read raw CDP frames" surface. A Node inspector session has no
10
- * `Target`/`Page` domains at all — it is a single top-level session speaking
11
- * `Runtime`/`Debugger`/`Console` directly — so Playwright's browser
12
- * abstraction does not fit it even if pressed into service. Checked before
13
- * writing this: nothing else in the repo opens a WebSocket to a CDP
14
- * endpoint directly. This is that client, kept protocol-family-generic (it
15
- * knows nothing about "Node" or "browser") so a future CDP target of either
16
- * kind can reuse it instead of a third one being written.
4
+ * `packages/browser` speaks CDP only through Playwright's console API, which owns its
5
+ * own WebSocket and Target/Page framing and has no "connect to an arbitrary ws:// and
6
+ * read raw CDP frames" surface a Node inspector session has no Target/Page domains
7
+ * at all, so that abstraction doesn't fit. Kept protocol-family-generic (no "Node" or
8
+ * "browser" knowledge) so either kind of CDP target can reuse it.
17
9
  *
18
- * CDP-over-WebSocket is JSON-RPC-shaped: a sent message carries `id` and
19
- * gets exactly one `{id, result}` or `{id, error}` reply; an event has
20
- * `method`/`params` and no `id`. This client does nothing more than that
21
- * framing — domain-specific method names and event shapes belong to the
22
- * caller, not here.
10
+ * CDP-over-WebSocket is JSON-RPC-shaped: a sent message carries `id` and gets exactly
11
+ * one `{id, result}` or `{id, error}` reply; an event has `method`/`params`, no `id`.
12
+ * This client does only that framing method names and event shapes are the caller's.
23
13
  */
24
14
  /**
25
15
  * Resolves once the socket is open, or rejects if it errors/closes first —
@@ -68,10 +58,7 @@ export function connectCdp(webSocketUrl) {
68
58
  msg = JSON.parse(raw);
69
59
  }
70
60
  catch {
71
- // A frame that is not valid JSON is not a valid CDP message from
72
- // any target this protocol defines -- dropped rather than thrown,
73
- // the same "unparseable stdout is ignorable noise" rule
74
- // `test-runner`'s envelope gate applies to its own stream.
61
+ // non-JSON frame: not a valid CDP message, dropped rather than thrown
75
62
  return;
76
63
  }
77
64
  if (msg.id !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"cdp-client.js","sourceRoot":"","sources":["../src/cdp-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cdp-client.js","sourceRoot":"","sources":["../src/cdp-client.ts"],"names":[],"mappings":"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"}
@@ -1,123 +1,76 @@
1
1
  /**
2
- * Partial going-forward resource restriction for an already-running,
3
- * attached-to process, via cgroups v2 -- the second, narrower alternative
4
- * next to respawn-and-supervise (`respawn-and-supervise.ts`).
2
+ * Partial going-forward resource restriction for an already-running, attached-to
3
+ * process, via cgroups v2 narrower alternative to `respawn-and-supervise.ts`.
5
4
  *
6
- * **What this genuinely gets you, stated exactly, because the honest
7
- * boundary here is not the same shape as spawn-mode's.** Moving a live
8
- * pid's cgroup membership (writing it into a delegated cgroup's own
9
- * `cgroup.procs`, per the kernel's cgroups v2 unified hierarchy) applies
10
- * real, kernel-enforced resource limits -- `memory.max`, `cpu.max`,
11
- * `pids.max` -- to a process this runtime never spawned, without killing
12
- * or restarting it. That is real and this module proves it for real (see
13
- * the test suite). **It does NOT, and structurally cannot, give the moved
14
- * process any filesystem or network isolation.** Changing which mount or
15
- * network namespace an already-running process belongs to needs `setns()`
16
- * against a live pid -- a fundamentally different, far more invasive
17
- * operation than a cgroup move, not attempted here and out of scope for
18
- * this pass. Every value this module returns, and every place this
19
- * capability is described, says so: `CGROUP_PARTIAL_RESTRICTION_SCOPE`
20
- * below is the literal, load-bearing string every result carries, precisely
21
- * so nothing downstream can round it up to "sandboxed" or "isolated" --
22
- * words that would misrepresent this as equivalent to `sandbox.ts`'s real
23
- * spawn-time bwrap isolation.
5
+ * Moving a live pid into a delegated cgroup applies real kernel-enforced limits
6
+ * (`memory.max`, `cpu.max`, `pids.max`) without killing/restarting it. **It does
7
+ * NOT and cannot give filesystem or network isolation** that needs `setns()`
8
+ * against a live pid, out of scope here. `CGROUP_PARTIAL_RESTRICTION_SCOPE` is the
9
+ * literal string every result carries so nothing downstream rounds this up to
10
+ * "sandboxed"/"isolated" (which would misrepresent it as `sandbox.ts`'s real
11
+ * spawn-time bwrap isolation).
24
12
  *
25
- * **How the delegated cgroup is found -- measured on this host, not
26
- * assumed from cgroups v2 documentation.** A non-root user cannot write
27
- * anywhere under `/sys/fs/cgroup` by default; what makes any of this
28
- * possible at all is a systemd user session's own delegation
29
- * (`user@<uid>.service`, `Delegate=yes`), which typically extends through
30
- * `app.slice`/`session.slice`/`background.slice` beneath it. But
31
- * delegation is not uniform all the way down: cgroups v2's "no internal
32
- * processes" rule means a *leaf* cgroup that already directly holds a
33
- * process (a systemd `.scope`, including the very one this Node process
34
- * itself runs in) generally cannot have its `subtree_control` extended
35
- * further -- writing to it fails with `EBUSY`, measured directly against
36
- * this repo's own dev host while building this module. `findDelegatedCgroupAncestor`
37
- * therefore does not trust `cgroup.subtree_control` text or permission
38
- * bits alone; it walks up from this process's own `/proc/self/cgroup` path
39
- * and, at each ancestor, creates a real, temporary probe child directory
40
- * and checks whether the kernel actually gave it a `memory.max` file --
41
- * the only way to honestly know a given ancestor's delegation reaches that
42
- * far, empirically, the same "prove it against the real mechanism" standard
43
- * `sandbox.ts`'s own escape tests hold spawn-mode isolation to.
13
+ * Finding the delegated ancestor: a non-root user can only write under
14
+ * `/sys/fs/cgroup` where a systemd user session delegates it (`Delegate=yes`).
15
+ * Delegation isn't uniform all the way down a leaf cgroup already holding a
16
+ * process (e.g. this Node process's own scope) generally can't extend
17
+ * `subtree_control` further; writing fails `EBUSY` (measured on this repo's dev
18
+ * host). So `findDelegatedCgroupAncestor` doesn't trust subtree_control text or
19
+ * permission bits it walks up from `/proc/self/cgroup` and, at each ancestor,
20
+ * creates a real temporary probe child and checks whether the kernel actually gave
21
+ * it a `memory.max` file.
44
22
  */
45
23
  import type { CapabilityStatus } from "@descryy/runtime-contracts";
46
- /**
47
- * The literal, load-bearing scope string. Every `CgroupMoveResult` carries
48
- * this exact value under `scope` -- never restated by hand elsewhere, so a
49
- * caller (or a future capability-report string, or a decisions-inbox entry)
50
- * that quotes `.scope` can never accidentally drift from this wording.
51
- */
24
+ /** Literal scope string every `CgroupMoveResult` carries under `scope` — never restated by hand, so quotes of it can't drift. */
52
25
  export declare const CGROUP_PARTIAL_RESTRICTION_SCOPE: "partial -- resource limits only, no filesystem or network isolation";
53
26
  /**
54
- * Walks up from this process's own cgroup toward `/sys/fs/cgroup`, returning
55
- * the deepest (most specific) ancestor directory whose children genuinely
56
- * get a real `memory.max` -- i.e. the actual delegation boundary, not
57
- * merely a directory this uid happens to own. `null` when cgroups v2 is not
58
- * mounted, this process's own cgroup path cannot be determined, or no
59
- * ancestor all the way to the root passes the probe (no delegation at all).
27
+ * Walks up from this process's cgroup toward `/sys/fs/cgroup`, returning the
28
+ * deepest ancestor whose children genuinely get a real `memory.max` — the actual
29
+ * delegation boundary. `null` if cgroups v2 isn't mounted, own path can't be
30
+ * determined, or no ancestor passes the probe.
60
31
  */
61
32
  export declare function findDelegatedCgroupAncestor(): string | null;
62
33
  export declare function cgroupV2Capability(): CapabilityStatus;
63
34
  export interface CgroupResourceLimits {
64
35
  /**
65
- * Maps to cgroups v2 `memory.max`, in bytes. **Also writes `memory.swap.max=0`
66
- * for the same cgroup, deliberately, when this is set** -- measured directly
67
- * while building this module: with swap available on the host (the common
68
- * case), `memory.max` alone does not kill anything, it just makes the
69
- * kernel push the cgroup's pages to swap under pressure, so a caller
70
- * declaring a memory cap would silently get "slows down and swaps"
71
- * instead of the real, hard boundary the field name promises. Disabling
72
- * swap for the created cgroup is what makes `memory.max` an actual
73
- * enforced limit (the kernel's own cgroup-aware OOM killer terminates a
74
- * process here, SIGKILL, once reclaim genuinely cannot bring usage under
75
- * the cap) rather than a soft one. Not independently toggleable in this
76
- * pass -- if a future caller genuinely wants "cap it but let it swap,"
77
- * that is a real, separate field to add later, not silently assumed here.
36
+ * Maps to cgroups v2 `memory.max`, in bytes. Also writes `memory.swap.max=0` for
37
+ * the same cgroup measured: with swap available, `memory.max` alone doesn't
38
+ * kill anything, it just pushes pages to swap under pressure. Disabling swap is
39
+ * what makes it a hard, OOM-killer-enforced limit rather than a soft one. Not
40
+ * independently toggleable "cap it but let it swap" would be a separate field.
78
41
  */
79
42
  readonly memoryMaxBytes?: number;
80
- /** Maps to cgroups v2 `pids.max` -- caps the number of tasks (processes/threads) this cgroup may hold at once. */
43
+ /** Maps to cgroups v2 `pids.max` -- caps tasks (processes/threads) this cgroup may hold. */
81
44
  readonly maxProcesses?: number;
82
45
  /**
83
- * Raw cgroups v2 `cpu.max` value (`"$MAX $PERIOD"`, e.g. `"50000 100000"`
84
- * for 50% of one CPU). Declaring this when the delegated ancestor does
85
- * not actually expose a writable `cpu.max` to its children is a refusal
86
- * (throws), not a silently-dropped limit -- matching `applySandbox`'s own
87
- * "declared, refused rather than silently ignored if unenforceable"
88
- * precedent. Measured on this repo's own dev host: `cpu` was NOT
89
- * delegated at the same level `memory`/`pids` were, so this is a real,
90
- * not hypothetical, gap a caller can hit.
46
+ * Raw cgroups v2 `cpu.max` value (`"$MAX $PERIOD"`, e.g. `"50000 100000"` for
47
+ * 50% of one CPU). Throws rather than silently dropping if the delegated
48
+ * ancestor has no writable `cpu.max` measured on this repo's dev host: `cpu`
49
+ * was NOT delegated at the same level `memory`/`pids` were.
91
50
  */
92
51
  readonly cpuMax?: string;
93
52
  }
94
53
  export interface CgroupMoveResult {
95
54
  readonly applied: true;
96
55
  readonly cgroupPath: string;
97
- /** Always the literal `CGROUP_PARTIAL_RESTRICTION_SCOPE` string -- see its own doc for why this is never restated by hand. */
56
+ /** Always the literal `CGROUP_PARTIAL_RESTRICTION_SCOPE` string. */
98
57
  readonly scope: typeof CGROUP_PARTIAL_RESTRICTION_SCOPE;
99
58
  readonly appliedLimits: CgroupResourceLimits;
100
59
  /**
101
60
  * Best-effort removal of the cgroup this call created. Succeeds only once
102
- * `cgroup.procs` is empty -- the pid exited, or was itself moved
103
- * elsewhere -- because cgroups v2 refuses to remove a non-empty cgroup,
104
- * the same "no internal processes hiding a live one" rule
105
- * `findDelegatedCgroupAncestor`'s own probe relies on. Returns whether
106
- * removal actually happened; never throws.
61
+ * `cgroup.procs` is empty (pid exited or moved elsewhere) -- cgroups v2 refuses
62
+ * to remove a non-empty cgroup. Returns whether removal happened; never throws.
107
63
  */
108
64
  readonly release: () => boolean;
109
65
  }
110
66
  /**
111
- * Moves `options.pid` -- an already-running process this runtime did not
112
- * spawn -- into a newly created, resource-limited cgroup. Throws (does not
113
- * silently proceed) when the target is not alive, when `cgroupV2Capability()`
114
- * reports unavailable, or when a declared limit's controller file does not
115
- * actually exist under the delegated ancestor found for it.
67
+ * Moves `options.pid` (a process this runtime did not spawn) into a newly created,
68
+ * resource-limited cgroup. Throws if the target isn't alive, `cgroupV2Capability()`
69
+ * is unavailable, or a declared limit's controller file doesn't exist.
116
70
  *
117
- * Limits are written to the new cgroup BEFORE the pid is moved into it, so
118
- * a process is never observed inside a cgroup with a half-applied limit
119
- * set; if any write fails, the created (still-empty) cgroup is removed and
120
- * the error is rethrown rather than left as an orphaned, unlimited group.
71
+ * Limits are written before the pid is moved in, so a process is never observed
72
+ * with a half-applied limit set; on any write failure the still-empty cgroup is
73
+ * removed and the error rethrown, never left orphaned.
121
74
  */
122
75
  export declare function moveProcessIntoRestrictedCgroup(options: {
123
76
  readonly pid: number;
@@ -1 +1 @@
1
- {"version":3,"file":"cgroup-partial-restriction.d.ts","sourceRoot":"","sources":["../src/cgroup-partial-restriction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAKnE;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,EAAG,qEAA8E,CAAC;AAkD/H;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAiB3D;AAED,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkBrD;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,kHAAkH;IAClH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8HAA8H;IAC9H,QAAQ,CAAC,KAAK,EAAE,OAAO,gCAAgC,CAAC;IACxD,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,gBAAgB,CA2EnB"}
1
+ {"version":3,"file":"cgroup-partial-restriction.d.ts","sourceRoot":"","sources":["../src/cgroup-partial-restriction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAKnE,iIAAiI;AACjI,eAAO,MAAM,gCAAgC,EAAG,qEAA8E,CAAC;AA2C/H;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAc3D;AAED,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkBrD;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4FAA4F;IAC5F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,OAAO,gCAAgC,CAAC;IACxD,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,gBAAgB,CAsEnB"}