@deepseekharness-mobile/companion 0.0.0-stage → 0.1.1
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 +21 -0
- package/README.md +79 -2
- package/cordis.patch.yml +20 -0
- package/dist/core/devices.d.ts +35 -0
- package/dist/core/devices.d.ts.map +1 -0
- package/dist/core/devices.js +90 -0
- package/dist/core/devices.js.map +1 -0
- package/dist/core/pairing.d.ts +21 -0
- package/dist/core/pairing.d.ts.map +1 -0
- package/dist/core/pairing.js +74 -0
- package/dist/core/pairing.js.map +1 -0
- package/dist/dsh/errors.d.ts +3 -0
- package/dist/dsh/errors.d.ts.map +1 -0
- package/dist/dsh/errors.js +15 -0
- package/dist/dsh/errors.js.map +1 -0
- package/dist/dsh/lifecycle.d.ts +37 -0
- package/dist/dsh/lifecycle.d.ts.map +1 -0
- package/dist/dsh/lifecycle.js +95 -0
- package/dist/dsh/lifecycle.js.map +1 -0
- package/dist/dsh/models.d.ts +39 -0
- package/dist/dsh/models.d.ts.map +1 -0
- package/dist/dsh/models.js +171 -0
- package/dist/dsh/models.js.map +1 -0
- package/dist/dsh/prompt.d.ts +8 -0
- package/dist/dsh/prompt.d.ts.map +1 -0
- package/dist/dsh/prompt.js +25 -0
- package/dist/dsh/prompt.js.map +1 -0
- package/dist/dsh/providers.d.ts +25 -0
- package/dist/dsh/providers.d.ts.map +1 -0
- package/dist/dsh/providers.js +315 -0
- package/dist/dsh/providers.js.map +1 -0
- package/dist/dsh/question-bridge.d.ts +25 -0
- package/dist/dsh/question-bridge.d.ts.map +1 -0
- package/dist/dsh/question-bridge.js +140 -0
- package/dist/dsh/question-bridge.js.map +1 -0
- package/dist/dsh/questions.d.ts +15 -0
- package/dist/dsh/questions.d.ts.map +1 -0
- package/dist/dsh/questions.js +126 -0
- package/dist/dsh/questions.js.map +1 -0
- package/dist/dsh/session-activity.d.ts +5 -0
- package/dist/dsh/session-activity.d.ts.map +1 -0
- package/dist/dsh/session-activity.js +100 -0
- package/dist/dsh/session-activity.js.map +1 -0
- package/dist/dsh/session-source.d.ts +19 -0
- package/dist/dsh/session-source.d.ts.map +1 -0
- package/dist/dsh/session-source.js +104 -0
- package/dist/dsh/session-source.js.map +1 -0
- package/dist/dsh/sessions.d.ts +10 -0
- package/dist/dsh/sessions.d.ts.map +1 -0
- package/dist/dsh/sessions.js +51 -0
- package/dist/dsh/sessions.js.map +1 -0
- package/dist/dsh/slash-commands.d.ts +15 -0
- package/dist/dsh/slash-commands.d.ts.map +1 -0
- package/dist/dsh/slash-commands.js +60 -0
- package/dist/dsh/slash-commands.js.map +1 -0
- package/dist/dsh/transcript.d.ts +28 -0
- package/dist/dsh/transcript.d.ts.map +1 -0
- package/dist/dsh/transcript.js +211 -0
- package/dist/dsh/transcript.js.map +1 -0
- package/dist/dsh/workspaces.d.ts +20 -0
- package/dist/dsh/workspaces.d.ts.map +1 -0
- package/dist/dsh/workspaces.js +123 -0
- package/dist/dsh/workspaces.js.map +1 -0
- package/dist/host-api.d.ts +148 -0
- package/dist/host-api.d.ts.map +1 -0
- package/dist/host-api.js +54 -0
- package/dist/host-api.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +268 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +5 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +40 -0
- package/dist/log.js.map +1 -0
- package/dist/open-browser.d.ts +3 -0
- package/dist/open-browser.d.ts.map +1 -0
- package/dist/open-browser.js +46 -0
- package/dist/open-browser.js.map +1 -0
- package/dist/pairing-message.d.ts +16 -0
- package/dist/pairing-message.d.ts.map +1 -0
- package/dist/pairing-message.js +38 -0
- package/dist/pairing-message.js.map +1 -0
- package/dist/persist/devices-file.d.ts +8 -0
- package/dist/persist/devices-file.d.ts.map +1 -0
- package/dist/persist/devices-file.js +47 -0
- package/dist/persist/devices-file.js.map +1 -0
- package/dist/probe.d.ts +25 -0
- package/dist/probe.d.ts.map +1 -0
- package/dist/probe.js +143 -0
- package/dist/probe.js.map +1 -0
- package/dist/public-origin.d.ts +11 -0
- package/dist/public-origin.d.ts.map +1 -0
- package/dist/public-origin.js +79 -0
- package/dist/public-origin.js.map +1 -0
- package/dist/qr-text.d.ts +2 -0
- package/dist/qr-text.d.ts.map +1 -0
- package/dist/qr-text.js +31 -0
- package/dist/qr-text.js.map +1 -0
- package/dist/routes/origin.d.ts +17 -0
- package/dist/routes/origin.d.ts.map +1 -0
- package/dist/routes/origin.js +85 -0
- package/dist/routes/origin.js.map +1 -0
- package/dist/routes/static.d.ts +9 -0
- package/dist/routes/static.d.ts.map +1 -0
- package/dist/routes/static.js +129 -0
- package/dist/routes/static.js.map +1 -0
- package/dist/routes/web-root.d.ts +2 -0
- package/dist/routes/web-root.d.ts.map +1 -0
- package/dist/routes/web-root.js +21 -0
- package/dist/routes/web-root.js.map +1 -0
- package/dist/server.d.ts +140 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +829 -0
- package/dist/server.js.map +1 -0
- package/dist/web/apple-touch-icon-precomposed.png +0 -0
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/assets/index-NOGXMIsS.js +65 -0
- package/dist/web/assets/index-NOGXMIsS.js.map +1 -0
- package/dist/web/assets/index-s7zoNGmx.css +1 -0
- package/dist/web/fonts/Montserrat-OFL.txt +93 -0
- package/dist/web/fonts/montserrat-medium.woff2 +0 -0
- package/dist/web/fonts/montserrat-regular.woff2 +0 -0
- package/dist/web/icon-192.png +0 -0
- package/dist/web/icon-512.png +0 -0
- package/dist/web/icon-maskable-512.png +0 -0
- package/dist/web/icon-maskable.svg +15 -0
- package/dist/web/icon.svg +6 -0
- package/dist/web/index.html +25 -0
- package/dist/web/manifest.webmanifest +37 -0
- package/package.json +60 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 joseph12n
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,80 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/joseph12n/dsh-mobile/main/docs/assets/logo.png" width="88" alt="DSH Mobile" />
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
<h1>@deepseekharness-mobile/companion</h1>
|
|
5
|
+
|
|
6
|
+
<p><strong>The host plugin for DSH Mobile.</strong><br />
|
|
7
|
+
Serves the PWA, pairs phones and bridges the <code>dsh-mobile/1</code> contract to DeepSeek
|
|
8
|
+
Harness — loopback-only, one token per device, no cloud in between.</p>
|
|
9
|
+
|
|
10
|
+
<p>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@deepseekharness-mobile/companion"><img src="https://img.shields.io/npm/v/@deepseekharness-mobile/companion?label=npm&color=4D6BFE" alt="npm" /></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@deepseekharness-mobile/companion"><img src="https://img.shields.io/npm/dm/@deepseekharness-mobile/companion?color=4D6BFE" alt="Downloads" /></a>
|
|
13
|
+
<a href="https://github.com/joseph12n/dsh-mobile/actions/workflows/ci.yml"><img src="https://github.com/joseph12n/dsh-mobile/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
14
|
+
<a href="https://sonarcloud.io/summary/new_code?id=joseph12n_dsh-mobile"><img src="https://sonarcloud.io/api/project_badges/measure?project=joseph12n_dsh-mobile&metric=alert_status" alt="Quality Gate" /></a>
|
|
15
|
+
<a href="https://github.com/joseph12n/dsh-mobile/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-4D6BFE.svg" alt="License" /></a>
|
|
16
|
+
<a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/DeepSeek%20Harness-companion-4D6BFE?logo=deepseek&logoColor=white" alt="DeepSeek Harness" /></a>
|
|
17
|
+
<a href="https://github.com/joseph12n/dsh-mobile/blob/main/docs/phone-setup.md"><img src="https://img.shields.io/badge/PWA-installable-5A0FC8?logo=googlechrome&logoColor=white" alt="PWA" /></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p>
|
|
21
|
+
<img src="https://raw.githubusercontent.com/joseph12n/dsh-mobile/main/docs/assets/session.png" width="215" alt="A live turn with the agent activity panel" />
|
|
22
|
+
<img src="https://raw.githubusercontent.com/joseph12n/dsh-mobile/main/docs/assets/settings.png" width="215" alt="Model providers and paired devices" />
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
dsh profile add @deepseekharness-mobile/companion
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The profile reads the bundle's `cordis.patch.yml`, mounts the plugin and serves the embedded
|
|
33
|
+
PWA on `127.0.0.1:6768`. Restart DSH afterwards, run `/mobile` in a session and open the link
|
|
34
|
+
on the phone; the PWA installs from the browser menu.
|
|
35
|
+
|
|
36
|
+
The listener is **loopback-only** by design: the phone reaches it through the tailnet name with
|
|
37
|
+
`tailscale serve`, which provides HTTPS and a secure context. The full path, with the usual
|
|
38
|
+
problems, is in
|
|
39
|
+
[`docs/phone-setup.md`](https://github.com/joseph12n/dsh-mobile/blob/main/docs/phone-setup.md).
|
|
40
|
+
|
|
41
|
+
## What the phone gets
|
|
42
|
+
|
|
43
|
+
- **Live transcript** with paged history, separated reasoning and streaming events.
|
|
44
|
+
- **Questions and approvals**, including the blocking `ask_user_question`, in an inline card.
|
|
45
|
+
- **Agent activity**: goal and round, running subagents and open tasks in a floating panel that
|
|
46
|
+
does not shrink the conversation.
|
|
47
|
+
- **Slash commands** from the composer, with the result outside the model transcript.
|
|
48
|
+
- **Model providers**: test a key and connect it; the key is stored on the host and never comes
|
|
49
|
+
back, and endpoints, headers, model overrides and OAuth stay on the desktop.
|
|
50
|
+
- **Paired devices**: last seen, revoke and forget, with the host revoking first.
|
|
51
|
+
- **Sessions, folders, model choice**, write and cancel, and an installable PWA with four
|
|
52
|
+
locales.
|
|
53
|
+
|
|
54
|
+
The full feature tour, the architecture and the security model live in the
|
|
55
|
+
[repository README](https://github.com/joseph12n/dsh-mobile#readme).
|
|
56
|
+
|
|
57
|
+
## Security
|
|
58
|
+
|
|
59
|
+
- **Loopback only.** The listen address is a constant, not an option; the tailnet name is the
|
|
60
|
+
only supported path and LAN access is not implemented.
|
|
61
|
+
- **Pair before anything.** The QR carries a single-use code in the URL fragment, valid for
|
|
62
|
+
10 minutes and never written to a log; redeeming it creates a device token stored as a hash.
|
|
63
|
+
- **One token per device.** Revoking one cuts its sockets and does not affect the others.
|
|
64
|
+
- **The host decides.** Capabilities are negotiated in `hello.ok`; the client cannot see or do
|
|
65
|
+
what the server does not send.
|
|
66
|
+
|
|
67
|
+
## Documentation
|
|
68
|
+
|
|
69
|
+
- [Repository](https://github.com/joseph12n/dsh-mobile) — the product, the features and the
|
|
70
|
+
screenshots.
|
|
71
|
+
- [Phone setup](https://github.com/joseph12n/dsh-mobile/blob/main/docs/phone-setup.md) —
|
|
72
|
+
Tailscale, pairing and the usual problems.
|
|
73
|
+
- [Architecture](https://github.com/joseph12n/dsh-mobile/blob/main/docs/architecture.md) — why
|
|
74
|
+
it is built this way.
|
|
75
|
+
- [`@deepseekharness-mobile/protocol`](https://www.npmjs.com/package/@deepseekharness-mobile/protocol)
|
|
76
|
+
— the wire contract, also on npm.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Capa de patch del plugin DSH Mobile.
|
|
2
|
+
#
|
|
3
|
+
# Se enlaza desde el perfil con `link:` en package.json y se activa añadiendo el
|
|
4
|
+
# bundle a `dsh.profile.bundles`, o bien insertando esta entrada en el
|
|
5
|
+
# `cordis.patch.yml` del perfil:
|
|
6
|
+
#
|
|
7
|
+
# - insert:
|
|
8
|
+
# - id: dsh-mobile-companion
|
|
9
|
+
# name: '@deepseekharness-mobile/companion'
|
|
10
|
+
# config: {}
|
|
11
|
+
#
|
|
12
|
+
# El plugin escucha en 127.0.0.1:6768 (loopback fijo: no hay modo de red). La
|
|
13
|
+
# autenticación por dispositivo ya existe; para llegar desde un teléfono se
|
|
14
|
+
# publica por el nombre del tailnet con `tailscale serve`, que sí alcanza el
|
|
15
|
+
# loopback y aporta HTTPS. La LAN directa no está soportada.
|
|
16
|
+
|
|
17
|
+
- insert:
|
|
18
|
+
- id: dsh-mobile-companion
|
|
19
|
+
name: './dist/index.js'
|
|
20
|
+
config: {}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface Device {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
platform: string;
|
|
5
|
+
createdAt: number;
|
|
6
|
+
lastSeenAt: number;
|
|
7
|
+
}
|
|
8
|
+
export interface StoredDevice extends Device {
|
|
9
|
+
tokenHash: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DevicePersistence {
|
|
12
|
+
load(): StoredDevice[];
|
|
13
|
+
save(devices: StoredDevice[]): void;
|
|
14
|
+
}
|
|
15
|
+
export interface DeviceRegistryOptions {
|
|
16
|
+
persistence: DevicePersistence;
|
|
17
|
+
now?: () => number;
|
|
18
|
+
generateToken?: () => string;
|
|
19
|
+
generateId?: () => string;
|
|
20
|
+
}
|
|
21
|
+
export interface Enrolled {
|
|
22
|
+
device: Device;
|
|
23
|
+
token: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function hashToken(token: string): string;
|
|
26
|
+
export declare class DeviceRegistry {
|
|
27
|
+
#private;
|
|
28
|
+
constructor(options: DeviceRegistryOptions);
|
|
29
|
+
enroll(name: string, platform: string): Enrolled;
|
|
30
|
+
authenticate(token: string): Device | undefined;
|
|
31
|
+
flush(): void;
|
|
32
|
+
list(): Device[];
|
|
33
|
+
revoke(id: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=devices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../src/core/devices.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,YAAY,EAAE,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,qBAAa,cAAc;;gBAQb,OAAO,EAAE,qBAAqB;IAgB1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAkBhD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAW/C,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,MAAM,EAAE;IAIhB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAc5B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
2
|
+
export function hashToken(token) {
|
|
3
|
+
return createHash('sha256').update(token, 'utf8').digest('hex');
|
|
4
|
+
}
|
|
5
|
+
export class DeviceRegistry {
|
|
6
|
+
#persistence;
|
|
7
|
+
#now;
|
|
8
|
+
#generateToken;
|
|
9
|
+
#generateId;
|
|
10
|
+
#devices;
|
|
11
|
+
#dirty = false;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.#persistence = options.persistence;
|
|
14
|
+
this.#now = options.now ?? (() => Date.now());
|
|
15
|
+
this.#generateToken = options.generateToken ?? (() => randomBytes(32).toString('base64url'));
|
|
16
|
+
this.#generateId = options.generateId ?? (() => randomUUID());
|
|
17
|
+
this.#devices = this.#loadSafely();
|
|
18
|
+
}
|
|
19
|
+
#loadSafely() {
|
|
20
|
+
try {
|
|
21
|
+
return this.#persistence.load();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
enroll(name, platform) {
|
|
28
|
+
const now = this.#now();
|
|
29
|
+
const token = this.#generateToken();
|
|
30
|
+
const stored = {
|
|
31
|
+
id: this.#generateId(),
|
|
32
|
+
name: name.trim().slice(0, 64) || 'Device',
|
|
33
|
+
platform: platform.slice(0, 64),
|
|
34
|
+
createdAt: now,
|
|
35
|
+
lastSeenAt: now,
|
|
36
|
+
tokenHash: hashToken(token),
|
|
37
|
+
};
|
|
38
|
+
this.#devices = [...this.#devices, stored];
|
|
39
|
+
this.#persist();
|
|
40
|
+
return { device: toPublic(stored), token };
|
|
41
|
+
}
|
|
42
|
+
authenticate(token) {
|
|
43
|
+
if (!token)
|
|
44
|
+
return undefined;
|
|
45
|
+
const hash = hashToken(token);
|
|
46
|
+
const found = this.#devices.find((device) => safeEqual(device.tokenHash, hash));
|
|
47
|
+
if (!found)
|
|
48
|
+
return undefined;
|
|
49
|
+
found.lastSeenAt = this.#now();
|
|
50
|
+
this.#dirty = true;
|
|
51
|
+
return toPublic(found);
|
|
52
|
+
}
|
|
53
|
+
flush() {
|
|
54
|
+
if (!this.#dirty)
|
|
55
|
+
return;
|
|
56
|
+
this.#persist();
|
|
57
|
+
}
|
|
58
|
+
list() {
|
|
59
|
+
return this.#devices.map(toPublic);
|
|
60
|
+
}
|
|
61
|
+
revoke(id) {
|
|
62
|
+
const before = this.#devices.length;
|
|
63
|
+
this.#devices = this.#devices.filter((device) => device.id !== id);
|
|
64
|
+
if (this.#devices.length === before)
|
|
65
|
+
return false;
|
|
66
|
+
this.#persist();
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
#persist() {
|
|
70
|
+
try {
|
|
71
|
+
this.#persistence.save(this.#devices);
|
|
72
|
+
this.#dirty = false;
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function toPublic(stored) {
|
|
78
|
+
const { tokenHash: _ignored, ...device } = stored;
|
|
79
|
+
return device;
|
|
80
|
+
}
|
|
81
|
+
function safeEqual(a, b) {
|
|
82
|
+
if (a.length !== b.length)
|
|
83
|
+
return false;
|
|
84
|
+
let diff = 0;
|
|
85
|
+
for (let index = 0; index < a.length; index += 1) {
|
|
86
|
+
diff |= a.charCodeAt(index) ^ b.charCodeAt(index);
|
|
87
|
+
}
|
|
88
|
+
return diff === 0;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=devices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../src/core/devices.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const CODE_BYTES = 16;
|
|
2
|
+
export declare const DEFAULT_TTL_MS: number;
|
|
3
|
+
export declare function normalizeCode(raw: string): string;
|
|
4
|
+
export interface IssuedCode {
|
|
5
|
+
code: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
}
|
|
8
|
+
export type RedeemResult = 'ok' | 'unknown' | 'expired' | 'consumed';
|
|
9
|
+
export interface PairingOptions {
|
|
10
|
+
ttlMs?: number;
|
|
11
|
+
now?: () => number;
|
|
12
|
+
generate?: () => string;
|
|
13
|
+
}
|
|
14
|
+
export declare class PairingService {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(options?: PairingOptions);
|
|
17
|
+
issue(): IssuedCode;
|
|
18
|
+
redeem(raw: string): RedeemResult;
|
|
19
|
+
pending(): IssuedCode[];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=pairing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../../src/core/pairing.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,KAAK,CAAC;AAE7B,eAAO,MAAM,cAAc,QAAiB,CAAC;AAmB7C,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;CACzB;AAOD,qBAAa,cAAc;;gBAMb,OAAO,GAAE,cAAmB;IAMxC,KAAK,IAAI,UAAU;IAQnB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY;IAejC,OAAO,IAAI,UAAU,EAAE;CAcxB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
3
|
+
export const CODE_BYTES = 16;
|
|
4
|
+
export const DEFAULT_TTL_MS = 10 * 60 * 1000;
|
|
5
|
+
function encodeBase32(bytes) {
|
|
6
|
+
let out = '';
|
|
7
|
+
let buffer = 0;
|
|
8
|
+
let bits = 0;
|
|
9
|
+
for (const byte of bytes) {
|
|
10
|
+
buffer = (buffer << 8) | byte;
|
|
11
|
+
bits += 8;
|
|
12
|
+
while (bits >= 5) {
|
|
13
|
+
bits -= 5;
|
|
14
|
+
out += ALPHABET[(buffer >>> bits) & 31];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (bits > 0)
|
|
18
|
+
out += ALPHABET[(buffer << (5 - bits)) & 31];
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
export function normalizeCode(raw) {
|
|
22
|
+
return raw
|
|
23
|
+
.toUpperCase()
|
|
24
|
+
.replace(/[^0-9A-Z]/g, '')
|
|
25
|
+
.replace(/[IL]/g, '1')
|
|
26
|
+
.replace(/O/g, '0');
|
|
27
|
+
}
|
|
28
|
+
export class PairingService {
|
|
29
|
+
#ttlMs;
|
|
30
|
+
#now;
|
|
31
|
+
#generate;
|
|
32
|
+
#codes = new Map();
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.#ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
35
|
+
this.#now = options.now ?? (() => Date.now());
|
|
36
|
+
this.#generate = options.generate ?? (() => encodeBase32(randomBytes(CODE_BYTES)));
|
|
37
|
+
}
|
|
38
|
+
issue() {
|
|
39
|
+
this.#prune();
|
|
40
|
+
const code = normalizeCode(this.#generate());
|
|
41
|
+
const expiresAt = this.#now() + this.#ttlMs;
|
|
42
|
+
this.#codes.set(code, { expiresAt, consumed: false });
|
|
43
|
+
return { code, expiresAt };
|
|
44
|
+
}
|
|
45
|
+
redeem(raw) {
|
|
46
|
+
const code = normalizeCode(raw);
|
|
47
|
+
const entry = this.#codes.get(code);
|
|
48
|
+
if (!entry)
|
|
49
|
+
return 'unknown';
|
|
50
|
+
if (entry.consumed)
|
|
51
|
+
return 'consumed';
|
|
52
|
+
if (entry.expiresAt <= this.#now()) {
|
|
53
|
+
this.#codes.delete(code);
|
|
54
|
+
return 'expired';
|
|
55
|
+
}
|
|
56
|
+
entry.consumed = true;
|
|
57
|
+
return 'ok';
|
|
58
|
+
}
|
|
59
|
+
pending() {
|
|
60
|
+
this.#prune();
|
|
61
|
+
const now = this.#now();
|
|
62
|
+
return [...this.#codes.entries()]
|
|
63
|
+
.filter(([, entry]) => !entry.consumed && entry.expiresAt > now)
|
|
64
|
+
.map(([code, entry]) => ({ code, expiresAt: entry.expiresAt }));
|
|
65
|
+
}
|
|
66
|
+
#prune() {
|
|
67
|
+
const horizon = this.#now() - 60 * 60 * 1000;
|
|
68
|
+
for (const [code, entry] of this.#codes) {
|
|
69
|
+
if (entry.expiresAt < horizon)
|
|
70
|
+
this.#codes.delete(code);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=pairing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../src/core/pairing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/dsh/errors.ts"],"names":[],"mappings":"AAKA,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIzD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMhD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function codeOf(error) {
|
|
2
|
+
if (typeof error !== 'object' || error === null)
|
|
3
|
+
return undefined;
|
|
4
|
+
const { code } = error;
|
|
5
|
+
return typeof code === 'string' ? code : undefined;
|
|
6
|
+
}
|
|
7
|
+
export function messageOf(error) {
|
|
8
|
+
if (typeof error === 'object' && error !== null) {
|
|
9
|
+
const { message } = error;
|
|
10
|
+
if (typeof message === 'string')
|
|
11
|
+
return message;
|
|
12
|
+
}
|
|
13
|
+
return String(error);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/dsh/errors.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAmB,CAAC;IACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,EAAE,OAAO,EAAE,GAAG,KAAmB,CAAC;QACxC,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type HostContext } from '../host-api.js';
|
|
2
|
+
export declare function canCreateSession(ctx: HostContext): boolean;
|
|
3
|
+
export declare function canArchiveSession(ctx: HostContext): boolean;
|
|
4
|
+
export declare function canUnarchiveSession(ctx: HostContext): boolean;
|
|
5
|
+
export type CreateResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
code: 'no-service' | 'no-folder' | 'failed';
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function createSession(ctx: HostContext, request: {
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
}): Promise<CreateResult>;
|
|
16
|
+
export type UnarchiveResult = {
|
|
17
|
+
ok: true;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
code: 'no-service' | 'not-found' | 'failed';
|
|
21
|
+
message: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function unarchiveSession(ctx: HostContext, request: {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
}): Promise<UnarchiveResult>;
|
|
26
|
+
export type ArchiveResult = {
|
|
27
|
+
ok: true;
|
|
28
|
+
} | {
|
|
29
|
+
ok: false;
|
|
30
|
+
code: 'no-service' | 'active' | 'not-found' | 'failed';
|
|
31
|
+
message: string;
|
|
32
|
+
};
|
|
33
|
+
export declare function archiveSession(ctx: HostContext, request: {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
stopActivity?: boolean;
|
|
36
|
+
}): Promise<ArchiveResult>;
|
|
37
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/dsh/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAa3D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAO1D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAO3D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAO7D;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,wBAAsB,aAAa,CACjC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAC/B,OAAO,CAAC,YAAY,CAAC,CAoBvB;AAED,MAAM,MAAM,eAAe,GACzB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7F,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,eAAe,CAAC,CAgB1B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,wBAAsB,cAAc,CAClC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,OAAO,CAAC,aAAa,CAAC,CA0BxB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { service } from '../host-api.js';
|
|
2
|
+
import { codeOf, messageOf } from './errors.js';
|
|
3
|
+
export function canCreateSession(ctx) {
|
|
4
|
+
try {
|
|
5
|
+
const controller = service(ctx, 'sessionController');
|
|
6
|
+
return typeof controller?.create === 'function';
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function canArchiveSession(ctx) {
|
|
13
|
+
try {
|
|
14
|
+
const controller = service(ctx, 'workspaceController');
|
|
15
|
+
return typeof controller?.archiveSession === 'function';
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function canUnarchiveSession(ctx) {
|
|
22
|
+
try {
|
|
23
|
+
const controller = service(ctx, 'workspaceController');
|
|
24
|
+
return typeof controller?.unarchiveSession === 'function';
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function createSession(ctx, request) {
|
|
31
|
+
const controller = service(ctx, 'sessionController');
|
|
32
|
+
if (!controller || typeof controller.create !== 'function') {
|
|
33
|
+
return { ok: false, code: 'no-service', message: 'This host cannot create sessions.' };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const created = await controller.create({ workspaceId: request.workspaceId });
|
|
37
|
+
const sessionId = created?.sessionId;
|
|
38
|
+
if (typeof sessionId !== 'string' || !sessionId) {
|
|
39
|
+
return { ok: false, code: 'failed', message: 'The host did not return a session.' };
|
|
40
|
+
}
|
|
41
|
+
return { ok: true, sessionId };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const code = codeOf(error);
|
|
45
|
+
if (code === 'workspace/not-found' || code === 'session/not-found') {
|
|
46
|
+
return { ok: false, code: 'no-folder', message: 'That folder no longer exists.' };
|
|
47
|
+
}
|
|
48
|
+
return { ok: false, code: 'failed', message: messageOf(error) };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function unarchiveSession(ctx, request) {
|
|
52
|
+
const controller = service(ctx, 'workspaceController');
|
|
53
|
+
if (!controller || typeof controller.unarchiveSession !== 'function') {
|
|
54
|
+
return { ok: false, code: 'no-service', message: 'This host cannot unarchive sessions.' };
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
await controller.unarchiveSession({ sessionId: request.sessionId });
|
|
58
|
+
return { ok: true };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const code = codeOf(error);
|
|
62
|
+
if (code === 'session/not-found' || code === 'workspace/not-found') {
|
|
63
|
+
return { ok: false, code: 'not-found', message: 'That session no longer exists.' };
|
|
64
|
+
}
|
|
65
|
+
return { ok: false, code: 'failed', message: messageOf(error) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function archiveSession(ctx, request) {
|
|
69
|
+
const controller = service(ctx, 'workspaceController');
|
|
70
|
+
if (!controller || typeof controller.archiveSession !== 'function') {
|
|
71
|
+
return { ok: false, code: 'no-service', message: 'This host cannot archive sessions.' };
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
await controller.archiveSession({
|
|
75
|
+
sessionId: request.sessionId,
|
|
76
|
+
...(request.stopActivity === true ? { stopActivity: true } : {}),
|
|
77
|
+
});
|
|
78
|
+
return { ok: true };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const code = codeOf(error);
|
|
82
|
+
if (code === 'workspace/session-active') {
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
code: 'active',
|
|
86
|
+
message: 'That session has work running. Stop it first.',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (code === 'session/not-found' || code === 'workspace/not-found') {
|
|
90
|
+
return { ok: false, code: 'not-found', message: 'That session no longer exists.' };
|
|
91
|
+
}
|
|
92
|
+
return { ok: false, code: 'failed', message: messageOf(error) };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/dsh/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type HostContext } from '../host-api.js';
|
|
2
|
+
import type { ModelCatalog, ModelSelection } from '@deepseekharness-mobile/protocol';
|
|
3
|
+
interface CatalogPayload {
|
|
4
|
+
default?: unknown;
|
|
5
|
+
groups?: unknown;
|
|
6
|
+
failures?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ModelController {
|
|
9
|
+
modelCatalog?: () => Promise<CatalogPayload>;
|
|
10
|
+
selectModel?: (request: {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
provider: string;
|
|
13
|
+
model: string;
|
|
14
|
+
reasoningEffort?: string;
|
|
15
|
+
}) => Promise<{
|
|
16
|
+
selected?: unknown;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function selectionOf(value: unknown): ModelSelection | undefined;
|
|
20
|
+
export declare function toCatalog(payload: unknown): ModelCatalog;
|
|
21
|
+
export declare function canListModels(ctx: HostContext): boolean;
|
|
22
|
+
export declare function canSelectModel(ctx: HostContext): boolean;
|
|
23
|
+
export declare function listModels(ctx: HostContext): Promise<ModelCatalog>;
|
|
24
|
+
export type SelectResult = {
|
|
25
|
+
ok: true;
|
|
26
|
+
selection: ModelSelection;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
code: 'no-service' | 'unavailable' | 'not-found' | 'failed';
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function selectModel(ctx: HostContext, request: {
|
|
33
|
+
sessionId: string;
|
|
34
|
+
provider: string;
|
|
35
|
+
model: string;
|
|
36
|
+
reasoningEffort?: string;
|
|
37
|
+
}): Promise<SelectResult>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=models.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/dsh/models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EACV,YAAY,EAIZ,cAAc,EACf,MAAM,kCAAkC,CAAC;AAgB1C,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7C,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,KAAK,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACvC;AAMD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CActE;AA6ED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,CAmBxD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAMvD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAMxD;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAcxE;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GACvC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,YAAY,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC5D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,wBAAsB,WAAW,CAC/B,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF,OAAO,CAAC,YAAY,CAAC,CA8BvB"}
|