@jini-ai/daemon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/agent-executor.d.ts +458 -0
- package/dist/agent-executor.d.ts.map +1 -0
- package/dist/agent-executor.js +1277 -0
- package/dist/agent-executor.js.map +1 -0
- package/dist/artifacts/index.d.ts +14 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +14 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/manifest.d.ts +90 -0
- package/dist/artifacts/manifest.d.ts.map +1 -0
- package/dist/artifacts/manifest.js +229 -0
- package/dist/artifacts/manifest.js.map +1 -0
- package/dist/artifacts/publication-guard.d.ts +28 -0
- package/dist/artifacts/publication-guard.d.ts.map +1 -0
- package/dist/artifacts/publication-guard.js +77 -0
- package/dist/artifacts/publication-guard.js.map +1 -0
- package/dist/artifacts/runtime-compat.d.ts +37 -0
- package/dist/artifacts/runtime-compat.d.ts.map +1 -0
- package/dist/artifacts/runtime-compat.js +33 -0
- package/dist/artifacts/runtime-compat.js.map +1 -0
- package/dist/artifacts/store.d.ts +85 -0
- package/dist/artifacts/store.d.ts.map +1 -0
- package/dist/artifacts/store.js +92 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/artifacts/stub-guard.d.ts +73 -0
- package/dist/artifacts/stub-guard.d.ts.map +1 -0
- package/dist/artifacts/stub-guard.js +198 -0
- package/dist/artifacts/stub-guard.js.map +1 -0
- package/dist/artifacts/text-suppression.d.ts +68 -0
- package/dist/artifacts/text-suppression.d.ts.map +1 -0
- package/dist/artifacts/text-suppression.js +184 -0
- package/dist/artifacts/text-suppression.js.map +1 -0
- package/dist/close-status.d.ts +86 -0
- package/dist/close-status.d.ts.map +1 -0
- package/dist/close-status.js +91 -0
- package/dist/close-status.js.map +1 -0
- package/dist/continuation/continuation-transport.d.ts +41 -0
- package/dist/continuation/continuation-transport.d.ts.map +1 -0
- package/dist/continuation/continuation-transport.js +18 -0
- package/dist/continuation/continuation-transport.js.map +1 -0
- package/dist/continuation/index.d.ts +4 -0
- package/dist/continuation/index.d.ts.map +1 -0
- package/dist/continuation/index.js +4 -0
- package/dist/continuation/index.js.map +1 -0
- package/dist/continuation/journal.d.ts +37 -0
- package/dist/continuation/journal.d.ts.map +1 -0
- package/dist/continuation/journal.js +23 -0
- package/dist/continuation/journal.js.map +1 -0
- package/dist/continuation/run-start-handler.d.ts +75 -0
- package/dist/continuation/run-start-handler.d.ts.map +1 -0
- package/dist/continuation/run-start-handler.js +32 -0
- package/dist/continuation/run-start-handler.js.map +1 -0
- package/dist/delegated-tool-bridge.d.ts +53 -0
- package/dist/delegated-tool-bridge.d.ts.map +1 -0
- package/dist/delegated-tool-bridge.js +92 -0
- package/dist/delegated-tool-bridge.js.map +1 -0
- package/dist/event-log.d.ts +134 -0
- package/dist/event-log.d.ts.map +1 -0
- package/dist/event-log.js +108 -0
- package/dist/event-log.js.map +1 -0
- package/dist/frontend-capability-tools.d.ts +102 -0
- package/dist/frontend-capability-tools.d.ts.map +1 -0
- package/dist/frontend-capability-tools.js +68 -0
- package/dist/frontend-capability-tools.js.map +1 -0
- package/dist/frontend-session-registry.d.ts +127 -0
- package/dist/frontend-session-registry.d.ts.map +1 -0
- package/dist/frontend-session-registry.js +180 -0
- package/dist/frontend-session-registry.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy-data-migration.d.ts +104 -0
- package/dist/legacy-data-migration.d.ts.map +1 -0
- package/dist/legacy-data-migration.js +239 -0
- package/dist/legacy-data-migration.js.map +1 -0
- package/dist/routines/index.d.ts +12 -0
- package/dist/routines/index.d.ts.map +1 -0
- package/dist/routines/index.js +12 -0
- package/dist/routines/index.js.map +1 -0
- package/dist/routines/routine-store.d.ts +77 -0
- package/dist/routines/routine-store.d.ts.map +1 -0
- package/dist/routines/routine-store.js +162 -0
- package/dist/routines/routine-store.js.map +1 -0
- package/dist/routines/schedule.d.ts +72 -0
- package/dist/routines/schedule.d.ts.map +1 -0
- package/dist/routines/schedule.js +263 -0
- package/dist/routines/schedule.js.map +1 -0
- package/dist/routines/scheduler.d.ts +34 -0
- package/dist/routines/scheduler.d.ts.map +1 -0
- package/dist/routines/scheduler.js +330 -0
- package/dist/routines/scheduler.js.map +1 -0
- package/dist/routines/types.d.ts +131 -0
- package/dist/routines/types.d.ts.map +1 -0
- package/dist/routines/types.js +9 -0
- package/dist/routines/types.js.map +1 -0
- package/dist/run/core/failure-taxonomy.d.ts +27 -0
- package/dist/run/core/failure-taxonomy.d.ts.map +1 -0
- package/dist/run/core/failure-taxonomy.js +16 -0
- package/dist/run/core/failure-taxonomy.js.map +1 -0
- package/dist/run/core/index.d.ts +5 -0
- package/dist/run/core/index.d.ts.map +1 -0
- package/dist/run/core/index.js +5 -0
- package/dist/run/core/index.js.map +1 -0
- package/dist/run/core/result.d.ts +25 -0
- package/dist/run/core/result.d.ts.map +1 -0
- package/dist/run/core/result.js +52 -0
- package/dist/run/core/result.js.map +1 -0
- package/dist/run/core/retry.d.ts +106 -0
- package/dist/run/core/retry.d.ts.map +1 -0
- package/dist/run/core/retry.js +210 -0
- package/dist/run/core/retry.js.map +1 -0
- package/dist/run/diagnostics/diagnostics.d.ts +86 -0
- package/dist/run/diagnostics/diagnostics.d.ts.map +1 -0
- package/dist/run/diagnostics/diagnostics.js +211 -0
- package/dist/run/diagnostics/diagnostics.js.map +1 -0
- package/dist/run/diagnostics/index.d.ts +3 -0
- package/dist/run/diagnostics/index.d.ts.map +1 -0
- package/dist/run/diagnostics/index.js +3 -0
- package/dist/run/diagnostics/index.js.map +1 -0
- package/dist/run/index.d.ts +16 -0
- package/dist/run/index.d.ts.map +1 -0
- package/dist/run/index.js +16 -0
- package/dist/run/index.js.map +1 -0
- package/dist/run-lifecycle.d.ts +118 -0
- package/dist/run-lifecycle.d.ts.map +1 -0
- package/dist/run-lifecycle.js +451 -0
- package/dist/run-lifecycle.js.map +1 -0
- package/dist/terminal-session.d.ts +139 -0
- package/dist/terminal-session.d.ts.map +1 -0
- package/dist/terminal-session.js +316 -0
- package/dist/terminal-session.js.map +1 -0
- package/dist/tokens.d.ts +9 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +19 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tool-executor.d.ts +97 -0
- package/dist/tool-executor.d.ts.map +1 -0
- package/dist/tool-executor.js +198 -0
- package/dist/tool-executor.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/** A surface that has attached itself and can execute capabilities on a bound run's behalf. */
|
|
2
|
+
export interface FrontendSessionDescriptor {
|
|
3
|
+
/** Identifies this surface. Minted by the host at attach time; opaque here. */
|
|
4
|
+
readonly sessionId: string;
|
|
5
|
+
/**
|
|
6
|
+
* Capability ids this surface claims it can execute. A call for anything this surface does not
|
|
7
|
+
* claim fails closed rather than hanging.
|
|
8
|
+
*/
|
|
9
|
+
readonly capabilities: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
/** One capability call pushed to a surface, awaiting exactly one answer. */
|
|
12
|
+
export interface FrontendInvocation {
|
|
13
|
+
/** Correlates the answer with this call. Minted here, never supplied by the surface. */
|
|
14
|
+
readonly invocationId: string;
|
|
15
|
+
readonly capabilityId: string;
|
|
16
|
+
readonly input: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/** A surface's answer. A refusal is an outcome, not a transport failure. */
|
|
19
|
+
export type FrontendOutcome = {
|
|
20
|
+
readonly ok: true;
|
|
21
|
+
readonly output: unknown;
|
|
22
|
+
} | {
|
|
23
|
+
readonly ok: false;
|
|
24
|
+
readonly message: string;
|
|
25
|
+
};
|
|
26
|
+
export interface FrontendSessionHandle {
|
|
27
|
+
readonly sessionId: string;
|
|
28
|
+
/**
|
|
29
|
+
* Secret that proves a caller is the surface this handle belongs to, and the only thing that
|
|
30
|
+
* may cross a wire to bind a run (see {@link FrontendSessionRegistry.bindRunByToken}).
|
|
31
|
+
*
|
|
32
|
+
* Separate from `sessionId` on purpose. The session id is *addressing*, not authority: it
|
|
33
|
+
* appears in a URL path (`/api/frontend-sessions/:sessionId/responses`), and URLs leak by
|
|
34
|
+
* default — into access logs, proxies, browser history, `Referer` headers, and crash reports.
|
|
35
|
+
* Binding a run is the act that hands an agent control of a real user's screen, so it must not
|
|
36
|
+
* be authorized by a value the system is already scattering across places designed to be read.
|
|
37
|
+
*/
|
|
38
|
+
readonly bindToken: string;
|
|
39
|
+
/**
|
|
40
|
+
* Detaches the surface. Every invocation still awaiting it is rejected rather than left pending,
|
|
41
|
+
* so a closed tab surfaces as a failed tool call instead of a run that never finishes.
|
|
42
|
+
*/
|
|
43
|
+
detach(): void;
|
|
44
|
+
}
|
|
45
|
+
export interface FrontendSessionRegistry {
|
|
46
|
+
/**
|
|
47
|
+
* Registers a surface and the function that pushes invocations to it (an SSE write, a WebSocket
|
|
48
|
+
* send, an in-process call for a browser-resident caller that needs no relay at all).
|
|
49
|
+
*
|
|
50
|
+
* @throws If `sessionId` is already attached.
|
|
51
|
+
*/
|
|
52
|
+
attach(descriptor: FrontendSessionDescriptor, deliver: (invocation: FrontendInvocation) => void): FrontendSessionHandle;
|
|
53
|
+
/**
|
|
54
|
+
* Associates a started run with the surface that originated it, so capability calls made by that
|
|
55
|
+
* run's agent reach that surface. Re-binding the same run to the same session is a no-op; binding
|
|
56
|
+
* it to a different one replaces the association, which is what a host should do when a run is
|
|
57
|
+
* genuinely taken over.
|
|
58
|
+
*
|
|
59
|
+
* @returns A function that removes this association — call it when the run reaches a terminal
|
|
60
|
+
* state so a long-lived surface does not accumulate bindings for runs that ended.
|
|
61
|
+
* @throws If `sessionId` is not attached. Binding a run to a surface that is already gone would
|
|
62
|
+
* produce calls that hang until their tool timeout instead of failing immediately.
|
|
63
|
+
*/
|
|
64
|
+
bindRun(runId: string, sessionId: string): () => void;
|
|
65
|
+
/**
|
|
66
|
+
* Binds a run to whichever surface holds `bindToken` — the wire-safe form of {@link bindRun}.
|
|
67
|
+
*
|
|
68
|
+
* **Use this for anything a caller supplied.** `bindRun` trusts its `sessionId` argument
|
|
69
|
+
* completely, which is correct for a composition root choosing among surfaces it already knows
|
|
70
|
+
* about, and unsafe the moment the id came from outside: session ids travel in URLs, so a caller
|
|
71
|
+
* that observed one in a log could bind *its* run to *someone else's* tab and drive that screen.
|
|
72
|
+
* A bind token is minted per surface, delivered once over that surface's own stream, and never
|
|
73
|
+
* appears in a URL.
|
|
74
|
+
*
|
|
75
|
+
* @returns The same unbind function `bindRun` returns.
|
|
76
|
+
* @throws If no attached surface holds this token. The message deliberately does not
|
|
77
|
+
* distinguish "never existed" from "detached" — telling a caller which one it guessed is how a
|
|
78
|
+
* probe learns whether a token is worth retrying.
|
|
79
|
+
*/
|
|
80
|
+
bindRunByToken(runId: string, bindToken: string): () => void;
|
|
81
|
+
/**
|
|
82
|
+
* Routes one capability call to the surface bound to `runId` and resolves with its output.
|
|
83
|
+
*
|
|
84
|
+
* @throws If no surface is bound to `runId`, if the bound surface does not claim `capabilityId`,
|
|
85
|
+
* if delivery fails, if the surface answers with a refusal, or if `signal` aborts first.
|
|
86
|
+
*/
|
|
87
|
+
invoke(runId: string, capabilityId: string, input: Record<string, unknown>, signal?: AbortSignal): Promise<unknown>;
|
|
88
|
+
/**
|
|
89
|
+
* Settles a pending invocation with the surface's answer.
|
|
90
|
+
*
|
|
91
|
+
* @returns `true` if this call settled it; `false` if it was already settled, unknown, or belongs
|
|
92
|
+
* to a different session — the duplicate-answer case, which is a no-op by design.
|
|
93
|
+
*/
|
|
94
|
+
settle(sessionId: string, invocationId: string, outcome: FrontendOutcome): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Capability ids reachable for `runId` right now — empty when nothing is bound. A caller uses
|
|
97
|
+
* this to advertise only what can actually be served, so an agent is never offered a capability
|
|
98
|
+
* that would fail the moment it tried.
|
|
99
|
+
*/
|
|
100
|
+
capabilitiesFor(runId: string): readonly string[];
|
|
101
|
+
/** The surface bound to `runId`, or `undefined` when there is none. */
|
|
102
|
+
sessionFor(runId: string): FrontendSessionDescriptor | undefined;
|
|
103
|
+
}
|
|
104
|
+
export interface CreateFrontendSessionRegistryOptions {
|
|
105
|
+
/** Injectable id source for invocation ids — defaults to `randomUUID`. Test-only hook. */
|
|
106
|
+
readonly newInvocationId?: () => string;
|
|
107
|
+
/**
|
|
108
|
+
* Injectable source for bind tokens — defaults to `randomUUID`. Test-only hook.
|
|
109
|
+
*
|
|
110
|
+
* A production override must be unguessable: this value is the sole authority for binding a run
|
|
111
|
+
* to a surface, so a predictable sequence would reintroduce exactly the hazard
|
|
112
|
+
* {@link FrontendSessionRegistry.bindRunByToken} exists to close.
|
|
113
|
+
*/
|
|
114
|
+
readonly newBindToken?: () => string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Creates an in-memory registry of attached surfaces.
|
|
118
|
+
*
|
|
119
|
+
* State is per-process and intentionally not persisted: an attached surface is a live connection,
|
|
120
|
+
* so it cannot outlive the process that holds it, and a restart correctly presents as "nothing
|
|
121
|
+
* attached" rather than as a stale route to a tab that is long gone.
|
|
122
|
+
*
|
|
123
|
+
* @complexity Every operation is O(1) except `detach`, which is O(p + b) in that surface\'s pending
|
|
124
|
+
* invocations and bound runs.
|
|
125
|
+
*/
|
|
126
|
+
export declare function createFrontendSessionRegistry(options?: CreateFrontendSessionRegistryOptions): FrontendSessionRegistry;
|
|
127
|
+
//# sourceMappingURL=frontend-session-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend-session-registry.d.ts","sourceRoot":"","sources":["../src/frontend-session-registry.ts"],"names":[],"mappings":"AAiDA,+FAA+F;AAC/F,MAAM,WAAW,yBAAyB;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,MAAM,CACJ,UAAU,EAAE,yBAAyB,EACrC,OAAO,EAAE,CAAC,UAAU,EAAE,kBAAkB,KAAK,IAAI,GAChD,qBAAqB,CAAC;IACzB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IACtD;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC7D;;;;;OAKG;IACH,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;IACnF;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAClD,uEAAuE;IACvE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS,CAAC;CAClE;AAED,MAAM,WAAW,oCAAoC;IACnD,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;CACtC;AAeD;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,oCAAyC,GACjD,uBAAuB,CA0IzB"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `FrontendSessionRegistry` — the addressing layer between a run and an attached surface.
|
|
3
|
+
*
|
|
4
|
+
* Everything else on the delegated-tool path already exists: a CLI agent calls the injected MCP
|
|
5
|
+
* server, which posts `{runId, toolUseId, toolId, input}` back over loopback, which reaches
|
|
6
|
+
* `DelegatedToolBridge` and then `ToolExecutor`. What was missing is one concept — **a run has an
|
|
7
|
+
* id, a browser tab has nothing**, so a tool call arrives with no addressee. This registry is that
|
|
8
|
+
* addressee: a surface attaches itself against a run, and a tool handler can then reach *that*
|
|
9
|
+
* surface, execute a capability there, and get an answer back.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately generic. This module knows nothing about `page.*`, the DOM, or chat — it routes an
|
|
12
|
+
* opaque `capabilityId` plus an opaque input to whichever surface claimed that capability. The
|
|
13
|
+
* vocabulary of what can be executed is the host's to define (see `@jini-ai/agentic`), which is what
|
|
14
|
+
* keeps a browser concept out of a server package.
|
|
15
|
+
*
|
|
16
|
+
* It also introduces **no second execution path**. The registry is only reachable from inside a
|
|
17
|
+
* `ToolHandler`, so every call through it has already passed `ToolExecutor`'s authorization,
|
|
18
|
+
* confirmation, timeout, cancellation, truncation, and audit trail. A route that called `invoke`
|
|
19
|
+
* directly would be strictly weaker, which is exactly the failure this design exists to avoid.
|
|
20
|
+
*
|
|
21
|
+
* That statement is about *this* path, and is worth stating precisely, because one ungated path
|
|
22
|
+
* does exist elsewhere: a frontend may register the same capabilities with the browser's in-page
|
|
23
|
+
* WebMCP surface, where a caller has no run and no principal and therefore never reaches
|
|
24
|
+
* `ToolExecutor` at all. Nothing in this package can gate that — it happens entirely in the page —
|
|
25
|
+
* so it is off unless a host opts in (`@jini-ai/chat-react`'s `agentControl.webmcp`). A reader who
|
|
26
|
+
* takes "no second execution path" as a whole-system guarantee would be wrong; it is a guarantee
|
|
27
|
+
* about everything that arrives here.
|
|
28
|
+
*
|
|
29
|
+
* **Attaching and binding are separate on purpose.** A surface attaches once, when it opens — a
|
|
30
|
+
* chat pane mounts long before the user sends anything, and runs are created per message, so a
|
|
31
|
+
* surface cannot know a run id at attach time. A run is *bound* to the surface that originated it
|
|
32
|
+
* when it starts. Beyond matching reality, this dissolves the worst routing hazard by construction:
|
|
33
|
+
* a run has exactly one originating surface, so a capability call can never be ambiguous between
|
|
34
|
+
* two open tabs, and no tie-break heuristic is needed that could act on a window nobody is
|
|
35
|
+
* watching.
|
|
36
|
+
*
|
|
37
|
+
* Three failure modes are handled explicitly rather than left to chance:
|
|
38
|
+
*
|
|
39
|
+
* 1. **A capability nothing can serve** — no surface bound to the run, or one that does not claim
|
|
40
|
+
* the capability. Both fail closed with a message naming what was missing, never hang.
|
|
41
|
+
* 2. **A duplicate answer** (stream reconnect, retried POST, a surface that answers twice).
|
|
42
|
+
* {@link FrontendSessionRegistry.settle} is idempotent and reports whether it was the one that
|
|
43
|
+
* settled the invocation; the pending map *is* the idempotency store.
|
|
44
|
+
* 3. **A surface that never answers** (backgrounded tab, closed laptop). `invoke` rejects on its
|
|
45
|
+
* caller's `AbortSignal`, which inside a handler is `ToolExecutor`'s own timeout/cancel signal —
|
|
46
|
+
* so the existing `timeoutMs` on a tool descriptor covers this for free.
|
|
47
|
+
*/
|
|
48
|
+
import { randomUUID } from 'node:crypto';
|
|
49
|
+
/**
|
|
50
|
+
* Creates an in-memory registry of attached surfaces.
|
|
51
|
+
*
|
|
52
|
+
* State is per-process and intentionally not persisted: an attached surface is a live connection,
|
|
53
|
+
* so it cannot outlive the process that holds it, and a restart correctly presents as "nothing
|
|
54
|
+
* attached" rather than as a stale route to a tab that is long gone.
|
|
55
|
+
*
|
|
56
|
+
* @complexity Every operation is O(1) except `detach`, which is O(p + b) in that surface\'s pending
|
|
57
|
+
* invocations and bound runs.
|
|
58
|
+
*/
|
|
59
|
+
export function createFrontendSessionRegistry(options = {}) {
|
|
60
|
+
const newInvocationId = options.newInvocationId ?? randomUUID;
|
|
61
|
+
const newBindToken = options.newBindToken ?? randomUUID;
|
|
62
|
+
const sessions = new Map();
|
|
63
|
+
const runBindings = new Map();
|
|
64
|
+
/** bind token → session id. Cleared on detach, so a token dies with the surface it proves. */
|
|
65
|
+
const bindTokens = new Map();
|
|
66
|
+
/** Resolves the surface that may serve this call, or explains precisely what is missing. */
|
|
67
|
+
function resolveTarget(runId, capabilityId) {
|
|
68
|
+
const sessionId = runBindings.get(runId);
|
|
69
|
+
const session = sessionId === undefined ? undefined : sessions.get(sessionId);
|
|
70
|
+
if (session === undefined) {
|
|
71
|
+
throw new Error(`no frontend is bound to run "${runId}", so "${capabilityId}" cannot be executed`);
|
|
72
|
+
}
|
|
73
|
+
if (!session.descriptor.capabilities.includes(capabilityId)) {
|
|
74
|
+
throw new Error(`the frontend bound to run "${runId}" does not offer "${capabilityId}" `
|
|
75
|
+
+ `(it offers: ${session.descriptor.capabilities.join(', ') || 'nothing'})`);
|
|
76
|
+
}
|
|
77
|
+
return session;
|
|
78
|
+
}
|
|
79
|
+
function attach(descriptor, deliver) {
|
|
80
|
+
if (sessions.has(descriptor.sessionId)) {
|
|
81
|
+
throw new Error(`FrontendSessionRegistry: session "${descriptor.sessionId}" is already attached`);
|
|
82
|
+
}
|
|
83
|
+
const session = { descriptor, deliver, pending: new Map() };
|
|
84
|
+
sessions.set(descriptor.sessionId, session);
|
|
85
|
+
const bindToken = newBindToken();
|
|
86
|
+
bindTokens.set(bindToken, descriptor.sessionId);
|
|
87
|
+
return {
|
|
88
|
+
sessionId: descriptor.sessionId,
|
|
89
|
+
bindToken,
|
|
90
|
+
detach() {
|
|
91
|
+
sessions.delete(descriptor.sessionId);
|
|
92
|
+
bindTokens.delete(bindToken);
|
|
93
|
+
for (const [runId, boundTo] of runBindings) {
|
|
94
|
+
if (boundTo === descriptor.sessionId)
|
|
95
|
+
runBindings.delete(runId);
|
|
96
|
+
}
|
|
97
|
+
for (const [, entry] of session.pending) {
|
|
98
|
+
entry.dispose();
|
|
99
|
+
entry.reject(new Error(`frontend session "${descriptor.sessionId}" detached before answering`));
|
|
100
|
+
}
|
|
101
|
+
session.pending.clear();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function bindRun(runId, sessionId) {
|
|
106
|
+
if (!sessions.has(sessionId)) {
|
|
107
|
+
throw new Error(`FrontendSessionRegistry: cannot bind run "${runId}" to unattached session "${sessionId}"`);
|
|
108
|
+
}
|
|
109
|
+
runBindings.set(runId, sessionId);
|
|
110
|
+
return () => {
|
|
111
|
+
// Only release a binding this call still owns: a run taken over by another surface must not
|
|
112
|
+
// have its newer binding torn down by the older one\'s cleanup.
|
|
113
|
+
if (runBindings.get(runId) === sessionId)
|
|
114
|
+
runBindings.delete(runId);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function bindRunByToken(runId, bindToken) {
|
|
118
|
+
const sessionId = bindTokens.get(bindToken);
|
|
119
|
+
// One message for both "no such token" and "the surface holding it detached". Distinguishing
|
|
120
|
+
// them tells a caller whether a guess was close, which is the feedback a probe needs and the
|
|
121
|
+
// only feedback it needs.
|
|
122
|
+
if (sessionId === undefined) {
|
|
123
|
+
throw new Error(`FrontendSessionRegistry: cannot bind run "${runId}" — unknown or expired bind token`);
|
|
124
|
+
}
|
|
125
|
+
return bindRun(runId, sessionId);
|
|
126
|
+
}
|
|
127
|
+
// `async` so that a routing refusal from `resolveTarget` surfaces as a rejected promise like
|
|
128
|
+
// every other failure here. Throwing synchronously out of a Promise-returning function would
|
|
129
|
+
// make `invoke(...).catch(...)` an uncaught exception for exactly the fail-closed cases this
|
|
130
|
+
// registry exists to report.
|
|
131
|
+
async function invoke(runId, capabilityId, input, signal) {
|
|
132
|
+
const target = resolveTarget(runId, capabilityId);
|
|
133
|
+
const invocationId = newInvocationId();
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const cancelled = () => new Error(`"${capabilityId}" was cancelled before the frontend answered`);
|
|
136
|
+
const onAbort = () => {
|
|
137
|
+
target.pending.delete(invocationId);
|
|
138
|
+
reject(cancelled());
|
|
139
|
+
};
|
|
140
|
+
const dispose = () => signal?.removeEventListener('abort', onAbort);
|
|
141
|
+
if (signal?.aborted) {
|
|
142
|
+
reject(cancelled());
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
146
|
+
target.pending.set(invocationId, { resolve, reject, dispose });
|
|
147
|
+
try {
|
|
148
|
+
target.deliver({ invocationId, capabilityId, input });
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// A dead channel must fail the call rather than leave it pending until the tool times out.
|
|
152
|
+
target.pending.delete(invocationId);
|
|
153
|
+
dispose();
|
|
154
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function settle(sessionId, invocationId, outcome) {
|
|
159
|
+
const session = sessions.get(sessionId);
|
|
160
|
+
const entry = session?.pending.get(invocationId);
|
|
161
|
+
if (session === undefined || entry === undefined)
|
|
162
|
+
return false;
|
|
163
|
+
session.pending.delete(invocationId);
|
|
164
|
+
entry.dispose();
|
|
165
|
+
if (outcome.ok)
|
|
166
|
+
entry.resolve(outcome.output);
|
|
167
|
+
else
|
|
168
|
+
entry.reject(new Error(outcome.message));
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
function sessionFor(runId) {
|
|
172
|
+
const sessionId = runBindings.get(runId);
|
|
173
|
+
return sessionId === undefined ? undefined : sessions.get(sessionId)?.descriptor;
|
|
174
|
+
}
|
|
175
|
+
function capabilitiesFor(runId) {
|
|
176
|
+
return sessionFor(runId)?.capabilities ?? [];
|
|
177
|
+
}
|
|
178
|
+
return { attach, bindRun, bindRunByToken, invoke, settle, capabilitiesFor, sessionFor };
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=frontend-session-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontend-session-registry.js","sourceRoot":"","sources":["../src/frontend-session-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @jini-ai/daemon
|
|
3
|
+
*
|
|
4
|
+
* `RunLifecycle` + the durable `EventLog` kernel port (extraction-plan §8
|
|
5
|
+
* task 5), plus the `ToolExecutor` tool-execution boundary (extraction-plan
|
|
6
|
+
* §2.5 / §8 task 6), and `AgentExecutor` — the driver that wires
|
|
7
|
+
* `@jini-ai/agent-runtime` into `RunLifecycle` (extraction-plan §2.1 / §3).
|
|
8
|
+
* See `source-map.md` for full provenance and scope-decision notes.
|
|
9
|
+
*
|
|
10
|
+
* The generic `ArtifactStore` kernel port used to live here too — moved to its own
|
|
11
|
+
* `@jini-ai/artifacts` package on 2026-07-19 (see `tokens.ts`'s doc comment).
|
|
12
|
+
*
|
|
13
|
+
* `routines/` (2026-07-21) adds the `RoutineService` scheduler (DST-safe wall-clock schedule
|
|
14
|
+
* math, race-safe scheduled-slot persistence) and the `RoutineStore` CRUD + run-history port,
|
|
15
|
+
* mirroring `EventLog`'s kernel-owned, storage-injected precedent. See its own module doc and
|
|
16
|
+
* `source-map.md`'s dated section for provenance.
|
|
17
|
+
*
|
|
18
|
+
* `terminal-session.ts` (2026-07-21) adds the interactive-terminal session manager: a
|
|
19
|
+
* `node-pty`-backed `PtySpawn` wired into `@jini-ai/platform`'s generic `TerminalService`, plus
|
|
20
|
+
* session-ownership gating and the kill/write/resize lock `@jini-ai/http`'s `terminals.ts` route
|
|
21
|
+
* pack calls into. This is this workspace's first native-compiled-addon dependency — see this
|
|
22
|
+
* package's `package.json` and `source-map.md`'s dated section.
|
|
23
|
+
*/
|
|
24
|
+
export * from './event-log.js';
|
|
25
|
+
export * from './close-status.js';
|
|
26
|
+
export * from './run-lifecycle.js';
|
|
27
|
+
export * from './tool-executor.js';
|
|
28
|
+
export * from './delegated-tool-bridge.js';
|
|
29
|
+
export * from './frontend-session-registry.js';
|
|
30
|
+
export * from './frontend-capability-tools.js';
|
|
31
|
+
export * from './agent-executor.js';
|
|
32
|
+
export * from './terminal-session.js';
|
|
33
|
+
export * from './tokens.js';
|
|
34
|
+
export * from './legacy-data-migration.js';
|
|
35
|
+
export * from './run/index.js';
|
|
36
|
+
export * from './continuation/index.js';
|
|
37
|
+
export * from './routines/index.js';
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @jini-ai/daemon
|
|
3
|
+
*
|
|
4
|
+
* `RunLifecycle` + the durable `EventLog` kernel port (extraction-plan §8
|
|
5
|
+
* task 5), plus the `ToolExecutor` tool-execution boundary (extraction-plan
|
|
6
|
+
* §2.5 / §8 task 6), and `AgentExecutor` — the driver that wires
|
|
7
|
+
* `@jini-ai/agent-runtime` into `RunLifecycle` (extraction-plan §2.1 / §3).
|
|
8
|
+
* See `source-map.md` for full provenance and scope-decision notes.
|
|
9
|
+
*
|
|
10
|
+
* The generic `ArtifactStore` kernel port used to live here too — moved to its own
|
|
11
|
+
* `@jini-ai/artifacts` package on 2026-07-19 (see `tokens.ts`'s doc comment).
|
|
12
|
+
*
|
|
13
|
+
* `routines/` (2026-07-21) adds the `RoutineService` scheduler (DST-safe wall-clock schedule
|
|
14
|
+
* math, race-safe scheduled-slot persistence) and the `RoutineStore` CRUD + run-history port,
|
|
15
|
+
* mirroring `EventLog`'s kernel-owned, storage-injected precedent. See its own module doc and
|
|
16
|
+
* `source-map.md`'s dated section for provenance.
|
|
17
|
+
*
|
|
18
|
+
* `terminal-session.ts` (2026-07-21) adds the interactive-terminal session manager: a
|
|
19
|
+
* `node-pty`-backed `PtySpawn` wired into `@jini-ai/platform`'s generic `TerminalService`, plus
|
|
20
|
+
* session-ownership gating and the kill/write/resize lock `@jini-ai/http`'s `terminals.ts` route
|
|
21
|
+
* pack calls into. This is this workspace's first native-compiled-addon dependency — see this
|
|
22
|
+
* package's `package.json` and `source-map.md`'s dated section.
|
|
23
|
+
*/
|
|
24
|
+
export * from './event-log.js';
|
|
25
|
+
export * from './close-status.js';
|
|
26
|
+
export * from './run-lifecycle.js';
|
|
27
|
+
export * from './tool-executor.js';
|
|
28
|
+
export * from './delegated-tool-bridge.js';
|
|
29
|
+
export * from './frontend-session-registry.js';
|
|
30
|
+
export * from './frontend-capability-tools.js';
|
|
31
|
+
export * from './agent-executor.js';
|
|
32
|
+
export * from './terminal-session.js';
|
|
33
|
+
export * from './tokens.js';
|
|
34
|
+
export * from './legacy-data-migration.js';
|
|
35
|
+
export * from './run/index.js';
|
|
36
|
+
export * from './continuation/index.js';
|
|
37
|
+
export * from './routines/index.js';
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/** Which files/dirs constitute a data root's migratable payload, host-supplied. */
|
|
2
|
+
export interface LegacyDataMigrationConfig {
|
|
3
|
+
/** Every file/dir under a data root that is part of the migratable payload. */
|
|
4
|
+
payloadEntries: readonly string[];
|
|
5
|
+
/**
|
|
6
|
+
* The one entry (must be a member of `payloadEntries`) whose presence as a
|
|
7
|
+
* *file* proves a directory holds real, populated data rather than an
|
|
8
|
+
* empty scaffold a packaged installer pre-creates. For a sqlite-backed
|
|
9
|
+
* daemon this is the database file.
|
|
10
|
+
*/
|
|
11
|
+
proofEntry: string;
|
|
12
|
+
/** Marker file name recording a completed migration. Defaults to `.migrated-from`. */
|
|
13
|
+
markerFile?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MigrateLegacyDataDirOptions extends LegacyDataMigrationConfig {
|
|
16
|
+
/** Path to the legacy data directory (typically from a host-defined env var). */
|
|
17
|
+
legacyDir: string | undefined;
|
|
18
|
+
/** Resolved current data root. */
|
|
19
|
+
dataDir: string;
|
|
20
|
+
/** Optional logger. Defaults to console.log. */
|
|
21
|
+
logger?: {
|
|
22
|
+
info(message: string): void;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Test seam. The default writes the JSON marker with fs.writeFileSync;
|
|
26
|
+
* tests inject a function that throws so the rollback path (which removes
|
|
27
|
+
* already-promoted payload entries) can be exercised without contriving
|
|
28
|
+
* real ENOSPC / read-only conditions. Production callers should never
|
|
29
|
+
* pass this.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
writeMarker?: (dataDir: string, legacyDir: string, markerFile: string) => void;
|
|
33
|
+
}
|
|
34
|
+
export type MigrateStatus = 'noop' | 'migrated' | 'skipped';
|
|
35
|
+
export interface MigrateLegacyDataDirResult {
|
|
36
|
+
status: MigrateStatus;
|
|
37
|
+
reason: string;
|
|
38
|
+
copied?: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Thrown when `legacyDir` is explicitly set but is not a usable legacy data
|
|
42
|
+
* dir, or the new `dataDir` is already populated and would be merged into.
|
|
43
|
+
* Failing loud here is the point: a silent skip trains an operator to
|
|
44
|
+
* assume a migration ran when it didn't.
|
|
45
|
+
*/
|
|
46
|
+
export declare class LegacyMigrationError extends Error {
|
|
47
|
+
readonly code: string;
|
|
48
|
+
constructor(code: string, message: string);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns true when `dataDir` looks like a fresh / never-used data root:
|
|
52
|
+
* either the directory does not exist, or it exists but does not contain
|
|
53
|
+
* the configured `proofEntry` as a file. Deliberately not just "the
|
|
54
|
+
* directory is empty" — a packaged install commonly pre-creates an empty
|
|
55
|
+
* `dataDir` before the daemon ever boots, so emptiness alone is not proof
|
|
56
|
+
* of "no prior data."
|
|
57
|
+
*
|
|
58
|
+
* @param dataDir - The data root to check.
|
|
59
|
+
* @param config - The host's payload/proof-entry configuration.
|
|
60
|
+
*/
|
|
61
|
+
export declare function dataDirIsEmptyOrFresh(dataDir: string, config: LegacyDataMigrationConfig): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Returns true when `legacyDir` contains a payload worth migrating: it
|
|
64
|
+
* exists and its configured `proofEntry` exists as a file.
|
|
65
|
+
*
|
|
66
|
+
* @param legacyDir - The candidate legacy data directory.
|
|
67
|
+
* @param config - The host's payload/proof-entry configuration.
|
|
68
|
+
*/
|
|
69
|
+
export declare function legacyDirHasPayload(legacyDir: string, config: LegacyDataMigrationConfig): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the list of configured payload entries that already exist under
|
|
72
|
+
* `dataDir`. Migration refuses to merge on top of any of them — a database
|
|
73
|
+
* file/WAL pair or a project tree cannot be safely interleaved with a
|
|
74
|
+
* foreign counterpart, and a partial overlay is worse than no migration.
|
|
75
|
+
*
|
|
76
|
+
* @param dataDir - The data root to check.
|
|
77
|
+
* @param config - The host's payload/proof-entry configuration.
|
|
78
|
+
*/
|
|
79
|
+
export declare function dataDirHasExistingPayload(dataDir: string, config: LegacyDataMigrationConfig): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Move staged payload entries into the final `dataDir`. Each entry is moved
|
|
82
|
+
* with `renameSync` (atomic on the same filesystem); a cross-device rename
|
|
83
|
+
* falls back to copy + remove. Rollback-safe in two layers: the copy
|
|
84
|
+
* fallback removes a partial destination on its own failure, and the outer
|
|
85
|
+
* loop removes every entry it already promoted before rethrowing.
|
|
86
|
+
*
|
|
87
|
+
* @param stagingDir - The sibling staging directory holding the copied payload.
|
|
88
|
+
* @param dataDir - The destination data root.
|
|
89
|
+
* @param entries - The payload entries to promote.
|
|
90
|
+
* @returns The entries that were placed into `dataDir` before any failure.
|
|
91
|
+
*/
|
|
92
|
+
export declare function promoteStaged(stagingDir: string, dataDir: string, entries: readonly string[]): readonly string[];
|
|
93
|
+
/**
|
|
94
|
+
* One-shot, idempotent legacy data migrator. Synchronous so it can run at
|
|
95
|
+
* module import time before a database connection opens. Throws
|
|
96
|
+
* {@link LegacyMigrationError} on operator-actionable failures (env set but
|
|
97
|
+
* path invalid; `dataDir` already populated; symlink in payload).
|
|
98
|
+
*
|
|
99
|
+
* @param options - Legacy/current dir paths plus the host's payload config.
|
|
100
|
+
* @returns The migration outcome (`noop` when unconfigured, `skipped` when
|
|
101
|
+
* already migrated, `migrated` with the copied entry list otherwise).
|
|
102
|
+
*/
|
|
103
|
+
export declare function migrateLegacyDataDirSync(options: MigrateLegacyDataDirOptions): MigrateLegacyDataDirResult;
|
|
104
|
+
//# sourceMappingURL=legacy-data-migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-data-migration.d.ts","sourceRoot":"","sources":["../src/legacy-data-migration.ts"],"names":[],"mappings":"AAoBA,mFAAmF;AACnF,MAAM,WAAW,yBAAyB;IACxC,+EAA+E;IAC/E,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,iFAAiF;IACjF,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;IACF;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAChF;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAID;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAGjG;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAGjG;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,yBAAyB,GAAG,MAAM,EAAE,CAGtG;AAiCD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAyBhH;AAqBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,2BAA2B,GAAG,0BAA0B,CA2DzG"}
|