@xenosystem/agent-interface-client 0.1.0 → 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 CHANGED
@@ -1,67 +1,67 @@
1
- XENO Agent — Proprietary Software License
2
- Copyright © 2026 XENO Corporation. All rights reserved.
3
-
4
- This software, including its source code, compiled binaries, published packages,
5
- assets, and accompanying documentation (collectively, the "Software"), is the
6
- proprietary and confidential property of XENO Corporation ("XENO"). The Software
7
- is licensed for use, not sold, and no title to or ownership of the Software is
8
- transferred to any user.
9
-
10
- 1. GRANT OF USE
11
- Subject to a separate written agreement and/or the terms of service published
12
- at https://xenostudio.ai, XENO grants the end user a limited, non-exclusive,
13
- non-transferable, revocable license to install and use the Software for its
14
- intended purpose. The standalone desktop application ("the Agent") may be used
15
- locally at no charge; connected platform features — hosted agent runs, model
16
- inference, credits, and account services — are governed by the applicable
17
- subscription and the XENO terms of service.
18
-
19
- 2. PACKAGE DISTRIBUTION
20
- The `@xeno-corporation/xeno-agent-interface-*` and
21
- `@xeno-corporation/xeno-agents-client` packages are published to a PRIVATE
22
- registry and are licensed for use solely by XENO products and by parties
23
- holding a separate written agreement with XENO. Access credentials to that
24
- registry do not grant redistribution rights. Publication of any package in
25
- this repository to a public registry is prohibited without written
26
- authorization from XENO.
27
-
28
- 3. RESTRICTIONS
29
- Except to the extent expressly permitted by applicable law or by a separate
30
- written agreement with XENO, you may NOT: (a) copy, redistribute, sell, rent,
31
- lease, sublicense, or otherwise transfer the Software; (b) modify, adapt,
32
- translate, or create derivative works of the Software; (c) reverse-engineer,
33
- decompile, or disassemble the Software, or attempt to derive its source code;
34
- (d) remove, obscure, or alter any proprietary notices; or (e) use the Software
35
- to build a competing product.
36
-
37
- 4. RESERVATION OF RIGHTS
38
- All rights not expressly granted are reserved by XENO Corporation. The Software
39
- is protected by copyright and other intellectual-property laws and treaties.
40
-
41
- 5. DISCLAIMER OF WARRANTY
42
- THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTY OF ANY
43
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THE
45
- SOFTWARE EXECUTES AGENT-DIRECTED OPERATIONS AGAINST A USER-SELECTED WORKSPACE,
46
- INCLUDING FILE AND PROCESS ACTIONS; THE USER IS RESPONSIBLE FOR THE WORKSPACES
47
- AND PERMISSIONS THEY GRANT IT.
48
-
49
- 6. LIMITATION OF LIABILITY
50
- TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL XENO CORPORATION BE
51
- LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE
52
- DAMAGES, OR ANY LOSS OF PROFITS OR DATA, ARISING FROM OR RELATED TO THE USE OF
53
- OR INABILITY TO USE THE SOFTWARE.
54
-
55
- 7. THIRD-PARTY COMPONENTS
56
- The Software includes third-party open-source components, each licensed under
57
- its own terms; those terms govern those components and are not superseded by
58
- this license. It also composes third-party agent providers over the Agent
59
- Client Protocol and hosted APIs; use of those providers is governed by their
60
- own terms.
61
-
62
- For licensing inquiries, contact: legal@xenostudio.ai
63
-
64
- NOTE TO OPERATOR: confirm the exact legal entity name and notice/contact details
65
- with counsel before public distribution and code-signing (the code-signing
66
- publisher name must match the registered entity). No public distribution of this
67
- product is authorized by this file — see docs/PRODUCT_STATUS.md.
1
+ XENO Agent — Proprietary Software License
2
+ Copyright © 2026 XENO Corporation. All rights reserved.
3
+
4
+ This software, including its source code, compiled binaries, published packages,
5
+ assets, and accompanying documentation (collectively, the "Software"), is the
6
+ proprietary and confidential property of XENO Corporation ("XENO"). The Software
7
+ is licensed for use, not sold, and no title to or ownership of the Software is
8
+ transferred to any user.
9
+
10
+ 1. GRANT OF USE
11
+ Subject to a separate written agreement and/or the terms of service published
12
+ at https://xenostudio.ai, XENO grants the end user a limited, non-exclusive,
13
+ non-transferable, revocable license to install and use the Software for its
14
+ intended purpose. The standalone desktop application ("the Agent") may be used
15
+ locally at no charge; connected platform features — hosted agent runs, model
16
+ inference, credits, and account services — are governed by the applicable
17
+ subscription and the XENO terms of service.
18
+
19
+ 2. PACKAGE DISTRIBUTION
20
+ The `@xeno-corporation/xeno-agent-interface-*` and
21
+ `@xeno-corporation/xeno-agents-client` packages are published to a PRIVATE
22
+ registry and are licensed for use solely by XENO products and by parties
23
+ holding a separate written agreement with XENO. Access credentials to that
24
+ registry do not grant redistribution rights. Publication of any package in
25
+ this repository to a public registry is prohibited without written
26
+ authorization from XENO.
27
+
28
+ 3. RESTRICTIONS
29
+ Except to the extent expressly permitted by applicable law or by a separate
30
+ written agreement with XENO, you may NOT: (a) copy, redistribute, sell, rent,
31
+ lease, sublicense, or otherwise transfer the Software; (b) modify, adapt,
32
+ translate, or create derivative works of the Software; (c) reverse-engineer,
33
+ decompile, or disassemble the Software, or attempt to derive its source code;
34
+ (d) remove, obscure, or alter any proprietary notices; or (e) use the Software
35
+ to build a competing product.
36
+
37
+ 4. RESERVATION OF RIGHTS
38
+ All rights not expressly granted are reserved by XENO Corporation. The Software
39
+ is protected by copyright and other intellectual-property laws and treaties.
40
+
41
+ 5. DISCLAIMER OF WARRANTY
42
+ THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTY OF ANY
43
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THE
45
+ SOFTWARE EXECUTES AGENT-DIRECTED OPERATIONS AGAINST A USER-SELECTED WORKSPACE,
46
+ INCLUDING FILE AND PROCESS ACTIONS; THE USER IS RESPONSIBLE FOR THE WORKSPACES
47
+ AND PERMISSIONS THEY GRANT IT.
48
+
49
+ 6. LIMITATION OF LIABILITY
50
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL XENO CORPORATION BE
51
+ LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE
52
+ DAMAGES, OR ANY LOSS OF PROFITS OR DATA, ARISING FROM OR RELATED TO THE USE OF
53
+ OR INABILITY TO USE THE SOFTWARE.
54
+
55
+ 7. THIRD-PARTY COMPONENTS
56
+ The Software includes third-party open-source components, each licensed under
57
+ its own terms; those terms govern those components and are not superseded by
58
+ this license. It also composes third-party agent providers over the Agent
59
+ Client Protocol and hosted APIs; use of those providers is governed by their
60
+ own terms.
61
+
62
+ For licensing inquiries, contact: legal@xenostudio.ai
63
+
64
+ NOTE TO OPERATOR: confirm the exact legal entity name and notice/contact details
65
+ with counsel before public distribution and code-signing (the code-signing
66
+ publisher name must match the registered entity). No public distribution of this
67
+ product is authorized by this file — see docs/PRODUCT_STATUS.md.
@@ -1,4 +1,5 @@
1
1
  export * from './transport.js';
2
2
  export * from './lease.js';
3
3
  export * from './attach.js';
4
+ export * from './paths.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAiBA,cAAc,gBAAgB,CAAA;AAI9B,cAAc,YAAY,CAAA;AAG1B,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAiBA,cAAc,gBAAgB,CAAA;AAI9B,cAAc,YAAY,CAAA;AAG1B,cAAc,aAAa,CAAA;AAI3B,cAAc,YAAY,CAAA"}
@@ -20,4 +20,7 @@ export * from './transport.js';
20
20
  export * from './lease.js';
21
21
  // Attaching to a per-user host. Attaches or refuses; never becomes the host.
22
22
  export * from './attach.js';
23
+ // Where the host's lease lives. The ONE path a surface needs to find a running host —
24
+ // `packages/host` DERIVES its own root from this, so the two cannot drift.
25
+ export * from './paths.js';
23
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yFAAyF;AACzF,2FAA2F;AAC3F,6FAA6F;AAC7F,0FAA0F;AAC1F,gDAAgD;AAChD,EAAE;AACF,6FAA6F;AAC7F,uFAAuF;AACvF,wCAAwC;AACxC,EAAE;AACF,qFAAqF;AAErF,yFAAyF;AACzF,0FAA0F;AAC1F,sBAAsB;AACtB,cAAc,gBAAgB,CAAA;AAE9B,8FAA8F;AAC9F,mDAAmD;AACnD,cAAc,YAAY,CAAA;AAE1B,6EAA6E;AAC7E,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/local/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yFAAyF;AACzF,2FAA2F;AAC3F,6FAA6F;AAC7F,0FAA0F;AAC1F,gDAAgD;AAChD,EAAE;AACF,6FAA6F;AAC7F,uFAAuF;AACvF,wCAAwC;AACxC,EAAE;AACF,qFAAqF;AAErF,yFAAyF;AACzF,0FAA0F;AAC1F,sBAAsB;AACtB,cAAc,gBAAgB,CAAA;AAE9B,8FAA8F;AAC9F,mDAAmD;AACnD,cAAc,YAAY,CAAA;AAE1B,6EAA6E;AAC7E,cAAc,aAAa,CAAA;AAE3B,sFAAsF;AACtF,2EAA2E;AAC3E,cAAc,YAAY,CAAA"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Where the per-user Agent host's lease lives — the ONE path a surface needs in order to
3
+ * find a running host (ADE §2.7).
4
+ *
5
+ * 🔴 This is here, in the published client, on purpose.
6
+ *
7
+ * The full layout resolver (`resolveLocalAgentHostPaths`) lives in `packages/host`, which is
8
+ * PRIVATE. A surface that has to attach — `xeno-agent-cli` as a `headless-client`, and Spawn
9
+ * next — cannot import it, so without this it would hand-retype `join(home, '.xeno',
10
+ * 'agent-host-v1')`. That is the exact failure shape this ecosystem keeps paying for: a value
11
+ * that already exists as a constant, restated by hand somewhere a search will not look. The
12
+ * scope rename hid in six places that way.
13
+ *
14
+ * A retyped path fails SILENTLY and in the worst possible manner: attach returns `no-host`
15
+ * forever, which is indistinguishable from "the host is not running". Nothing errors; the
16
+ * feature simply never works.
17
+ *
18
+ * So `packages/host` DERIVES its `hostRootDirectory` from this function rather than computing
19
+ * its own. One definition, imported by both sides of the lease.
20
+ *
21
+ * The split follows the same rule as the rest of this subpath: a surface gets the client half
22
+ * (where to look) and never the server half (the state repository, conversations, workspace
23
+ * authority, ACP registry). Those are host-owned, and a surface must not know their paths, let
24
+ * alone open them.
25
+ */
26
+ /** The per-user XENO root under the home directory. */
27
+ export declare const USER_XENO_ROOT_SEGMENT = ".xeno";
28
+ /**
29
+ * The lease/RPC root segment, and it is VERSIONED deliberately.
30
+ *
31
+ * An older Hub and a newer standalone app must not elect competing owners of the same lease
32
+ * during a rollout. Bumping this segment is how two incompatible host generations are kept from
33
+ * seeing each other — so changing it is a protocol break, not a rename.
34
+ */
35
+ export declare const LOCAL_AGENT_HOST_ROOT_SEGMENT = "agent-host-v1";
36
+ export interface ResolveLocalAgentHostRootOptions {
37
+ /** The user's home directory. Required — never defaulted from the environment here. */
38
+ homeDirectory: string;
39
+ /**
40
+ * An explicit root. Supplying it produces a fully isolated host, which is how tests and
41
+ * development profiles avoid colliding with the real one.
42
+ */
43
+ hostRootDirectory?: string;
44
+ }
45
+ /**
46
+ * Resolve the directory containing `agent-host.lock`.
47
+ *
48
+ * Callers pass `homeDirectory` explicitly rather than having it read from the environment,
49
+ * because a path resolver that reads ambient state cannot be tested for the isolated case and
50
+ * silently differs between a packaged app and a CLI.
51
+ */
52
+ export declare function resolveLocalAgentHostRoot(options: ResolveLocalAgentHostRootOptions): string;
53
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/local/paths.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,uDAAuD;AACvD,eAAO,MAAM,sBAAsB,UAAU,CAAA;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,kBAAkB,CAAA;AAE5D,MAAM,WAAW,gCAAgC;IAC/C,uFAAuF;IACvF,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,GAAG,MAAM,CAM3F"}
@@ -0,0 +1,56 @@
1
+ import { join, resolve } from 'node:path';
2
+ /**
3
+ * Where the per-user Agent host's lease lives — the ONE path a surface needs in order to
4
+ * find a running host (ADE §2.7).
5
+ *
6
+ * 🔴 This is here, in the published client, on purpose.
7
+ *
8
+ * The full layout resolver (`resolveLocalAgentHostPaths`) lives in `packages/host`, which is
9
+ * PRIVATE. A surface that has to attach — `xeno-agent-cli` as a `headless-client`, and Spawn
10
+ * next — cannot import it, so without this it would hand-retype `join(home, '.xeno',
11
+ * 'agent-host-v1')`. That is the exact failure shape this ecosystem keeps paying for: a value
12
+ * that already exists as a constant, restated by hand somewhere a search will not look. The
13
+ * scope rename hid in six places that way.
14
+ *
15
+ * A retyped path fails SILENTLY and in the worst possible manner: attach returns `no-host`
16
+ * forever, which is indistinguishable from "the host is not running". Nothing errors; the
17
+ * feature simply never works.
18
+ *
19
+ * So `packages/host` DERIVES its `hostRootDirectory` from this function rather than computing
20
+ * its own. One definition, imported by both sides of the lease.
21
+ *
22
+ * The split follows the same rule as the rest of this subpath: a surface gets the client half
23
+ * (where to look) and never the server half (the state repository, conversations, workspace
24
+ * authority, ACP registry). Those are host-owned, and a surface must not know their paths, let
25
+ * alone open them.
26
+ */
27
+ /** The per-user XENO root under the home directory. */
28
+ export const USER_XENO_ROOT_SEGMENT = '.xeno';
29
+ /**
30
+ * The lease/RPC root segment, and it is VERSIONED deliberately.
31
+ *
32
+ * An older Hub and a newer standalone app must not elect competing owners of the same lease
33
+ * during a rollout. Bumping this segment is how two incompatible host generations are kept from
34
+ * seeing each other — so changing it is a protocol break, not a rename.
35
+ */
36
+ export const LOCAL_AGENT_HOST_ROOT_SEGMENT = 'agent-host-v1';
37
+ /**
38
+ * Resolve the directory containing `agent-host.lock`.
39
+ *
40
+ * Callers pass `homeDirectory` explicitly rather than having it read from the environment,
41
+ * because a path resolver that reads ambient state cannot be tested for the isolated case and
42
+ * silently differs between a packaged app and a CLI.
43
+ */
44
+ export function resolveLocalAgentHostRoot(options) {
45
+ const homeDirectory = normalizePath(options.homeDirectory);
46
+ if (!homeDirectory)
47
+ throw new Error('Agent host homeDirectory is required.');
48
+ const explicitHostRoot = normalizePath(options.hostRootDirectory);
49
+ if (explicitHostRoot)
50
+ return explicitHostRoot;
51
+ return join(resolve(homeDirectory, USER_XENO_ROOT_SEGMENT), LOCAL_AGENT_HOST_ROOT_SEGMENT);
52
+ }
53
+ function normalizePath(value) {
54
+ return typeof value === 'string' && value.trim() ? resolve(value.trim()) : undefined;
55
+ }
56
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/local/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,uDAAuD;AACvD,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,eAAe,CAAA;AAY5D;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAyC;IACjF,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;IAC1D,IAAI,CAAC,aAAa;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;IAC5E,MAAM,gBAAgB,GAAG,aAAa,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACjE,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAA;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,EAAE,6BAA6B,CAAC,CAAA;AAC5F,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACtF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/agent-interface-client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "directory": "packages/client"
29
29
  },
30
30
  "dependencies": {
31
- "@xenosystem/agent-interface-contract": "0.1.0"
31
+ "@xenosystem/agent-interface-contract": "0.1.1"
32
32
  },
33
33
  "scripts": {}
34
34
  }
@@ -1,116 +0,0 @@
1
- /**
2
- * Attaching to a per-user Agent host — the SURFACE side of ADE §2.7.
3
- *
4
- * 🔴 `attachToLocalAgentHost` attaches or refuses; it can never become the host. There is no
5
- * `createHostTransport` parameter, so there is nothing it could construct even if asked — the
6
- * dangerous shape (a CLI started while no app is running WINS the lease and is then expected to
7
- * *be* the host) is unrepresentable rather than merely forbidden.
8
- *
9
- * That property is why this file can live in a publishable package at all: everything here is
10
- * what a thin client legitimately needs, and nothing here can take ownership. Acquisition and the
11
- * host authority stay in the private `packages/host`.
12
- */
13
- import { type LocalAgentHostLeaseDescriptor } from './localLease.js';
14
- import { LocalAgentHostRpcClientTransport } from './localTransport.js';
15
- /**
16
- * 🔴 STRUCTURAL, not the concrete server/lease classes.
17
- *
18
- * The session only ever closes the server and releases or heartbeats the lease — three calls.
19
- * Typing those fields as the host's concrete `LocalAgentHostRpcServer` and `LocalAgentHostLease`
20
- * dragged the whole server implementation into this file, which is what kept the session
21
- * unpublishable. Naming the three calls it actually makes decouples it, and the host's real
22
- * classes satisfy these by shape with no adapter.
23
- */
24
- export interface ClosableAuthorityServer {
25
- close(): Promise<void>;
26
- }
27
- export interface RenewableAuthorityLease {
28
- release(): Promise<unknown>;
29
- heartbeat(): Promise<unknown>;
30
- }
31
- export type LocalAgentHostAuthorityRole = 'owner' | 'attached-client';
32
- export declare class LocalAgentHostAuthoritySession {
33
- readonly role: LocalAgentHostAuthorityRole;
34
- readonly descriptor: LocalAgentHostLeaseDescriptor;
35
- readonly transport: LocalAgentHostRpcClientTransport;
36
- private readonly server;
37
- private readonly lease;
38
- private readonly onAuthorityLost;
39
- private heartbeatTimer;
40
- private heartbeatPending;
41
- private closed;
42
- constructor(options: {
43
- role: LocalAgentHostAuthorityRole;
44
- descriptor: LocalAgentHostLeaseDescriptor;
45
- transport: LocalAgentHostRpcClientTransport;
46
- server?: ClosableAuthorityServer;
47
- lease?: RenewableAuthorityLease;
48
- heartbeatIntervalMs?: number;
49
- onAuthorityLost?: (error: Error) => void;
50
- });
51
- close(): Promise<void>;
52
- private heartbeat;
53
- }
54
- /**
55
- * Elects the one local authority. Only the elected owner invokes
56
- * createHostTransport; every other process attaches to its authenticated RPC
57
- * endpoint, which prevents duplicate provider processes and split-brain state.
58
- */
59
- /**
60
- * Why a surface could not attach. The REASON, not a boolean.
61
- *
62
- * 🔴 A CLI needs to tell its user what to do next, and "could not connect"
63
- * does not. "No host is running" means start the app; "protocol mismatch" means
64
- * the two builds disagree and one needs updating; "unreachable" means a host
65
- * claims to be there and is not answering, which is a different problem again.
66
- * Collapsing them sends a person to fix the wrong thing.
67
- */
68
- export type AttachLocalAgentHostRefusal = {
69
- reason: 'no-host';
70
- detail: string;
71
- } | {
72
- reason: 'host-gone';
73
- detail: string;
74
- } | {
75
- reason: 'protocol-mismatch';
76
- detail: string;
77
- hostProtocol: number;
78
- clientProtocol: number;
79
- } | {
80
- reason: 'unreachable';
81
- detail: string;
82
- };
83
- export type AttachLocalAgentHostResult = {
84
- attached: true;
85
- session: LocalAgentHostAuthoritySession;
86
- } | ({
87
- attached: false;
88
- } & AttachLocalAgentHostRefusal);
89
- export interface AttachToLocalAgentHostOptions {
90
- rootDirectory: string;
91
- protocolVersion?: number;
92
- connectTimeoutMs?: number;
93
- requestTimeoutMs?: number;
94
- /** Injected for tests; production reads the real clock and process table. */
95
- now?: () => number;
96
- staleAfterMs?: number;
97
- isProcessAlive?: (pid: number) => boolean;
98
- }
99
- /**
100
- * Attach to a host someone else owns — and NEVER become one.
101
- *
102
- * 🔴 This exists because `startLocalAgentHostAuthority` is acquire-or-attach,
103
- * and for a surface that is the wrong shape in the most dangerous way: a CLI
104
- * started while no app is running would WIN the lease and then be asked to
105
- * build a host, which a thin client has no business owning. ADE §2.7 is
106
- * explicit that `xeno-agent-cli` "becomes a client of the same per-user host";
107
- * a client that can silently become the server is not that.
108
- *
109
- * 🔴 The defect is made UNREPRESENTABLE rather than documented: there is no
110
- * `createHostTransport` parameter here, so there is nothing this function could
111
- * construct even if it wanted to. It inspects, it connects, or it refuses with
112
- * a reason.
113
- */
114
- export declare function attachToLocalAgentHost(options: AttachToLocalAgentHostOptions): Promise<AttachLocalAgentHostResult>;
115
- export declare function connectBeforeDeadline(transport: LocalAgentHostRpcClientTransport, timeoutMs: number): Promise<void>;
116
- //# sourceMappingURL=localAttach.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localAttach.d.ts","sourceRoot":"","sources":["../src/localAttach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAIL,KAAK,6BAA6B,EACnC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,gCAAgC,EAGjC,MAAM,qBAAqB,CAAA;AAE5B;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,uBAAuB;IAItC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3B,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAC9B;AAGD,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,iBAAiB,CAAA;AAErE,qBAAa,8BAA8B;IACzC,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAA;IAC1C,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAA;IAClD,QAAQ,CAAC,SAAS,EAAE,gCAAgC,CAAA;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsC;IACtE,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,MAAM,CAAQ;gBAEV,OAAO,EAAE;QACnB,IAAI,EAAE,2BAA2B,CAAA;QACjC,UAAU,EAAE,6BAA6B,CAAA;QACzC,SAAS,EAAE,gCAAgC,CAAA;QAC3C,MAAM,CAAC,EAAE,uBAAuB,CAAA;QAChC,KAAK,CAAC,EAAE,uBAAuB,CAAA;QAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KACzC;IAaK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAYd,SAAS;CAaxB;AAED;;;;GAIG;AACH;;;;;;;;GAQG;AACH,MAAM,MAAM,2BAA2B,GACnC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC7F;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7C,MAAM,MAAM,0BAA0B,GAClC;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,8BAA8B,CAAA;CAAE,GAC3D,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAA;CAAE,GAAG,2BAA2B,CAAC,CAAA;AAEvD,MAAM,WAAW,6BAA6B;IAC5C,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAC1C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,0BAA0B,CAAC,CAgFrC;AAGD,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,gCAAgC,EAC3C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -1,187 +0,0 @@
1
- /**
2
- * Attaching to a per-user Agent host — the SURFACE side of ADE §2.7.
3
- *
4
- * 🔴 `attachToLocalAgentHost` attaches or refuses; it can never become the host. There is no
5
- * `createHostTransport` parameter, so there is nothing it could construct even if asked — the
6
- * dangerous shape (a CLI started while no app is running WINS the lease and is then expected to
7
- * *be* the host) is unrepresentable rather than merely forbidden.
8
- *
9
- * That property is why this file can live in a publishable package at all: everything here is
10
- * what a thin client legitimately needs, and nothing here can take ownership. Acquisition and the
11
- * host authority stay in the private `packages/host`.
12
- */
13
- import { XENO_AGENT_HOST_PROTOCOL_VERSION, } from '@xenosystem/agent-interface-contract';
14
- import { inspectLocalAgentHostLease, isLeaseOwnerGone, readLocalAgentHostLeaseConnection, } from './localLease.js';
15
- import { LocalAgentHostRpcClientTransport, positiveInteger, resolveLocalAgentHostEndpoint, } from './localTransport.js';
16
- export class LocalAgentHostAuthoritySession {
17
- role;
18
- descriptor;
19
- transport;
20
- server;
21
- lease;
22
- onAuthorityLost;
23
- heartbeatTimer;
24
- heartbeatPending = false;
25
- closed = false;
26
- constructor(options) {
27
- this.role = options.role;
28
- this.descriptor = { ...options.descriptor };
29
- this.transport = options.transport;
30
- this.server = options.server;
31
- this.lease = options.lease;
32
- this.onAuthorityLost = options.onAuthorityLost;
33
- if (this.lease && options.heartbeatIntervalMs) {
34
- this.heartbeatTimer = setInterval(() => { void this.heartbeat(); }, options.heartbeatIntervalMs);
35
- this.heartbeatTimer.unref?.();
36
- }
37
- }
38
- async close() {
39
- if (this.closed)
40
- return;
41
- this.closed = true;
42
- if (this.heartbeatTimer) {
43
- clearInterval(this.heartbeatTimer);
44
- this.heartbeatTimer = undefined;
45
- }
46
- this.transport.close();
47
- await this.server?.close();
48
- await this.lease?.release();
49
- }
50
- async heartbeat() {
51
- if (this.closed || this.heartbeatPending || !this.lease)
52
- return;
53
- this.heartbeatPending = true;
54
- try {
55
- await this.lease.heartbeat();
56
- }
57
- catch (error) {
58
- const failure = asError(error);
59
- await this.close().catch(() => undefined);
60
- this.onAuthorityLost?.(failure);
61
- }
62
- finally {
63
- this.heartbeatPending = false;
64
- }
65
- }
66
- }
67
- /**
68
- * Attach to a host someone else owns — and NEVER become one.
69
- *
70
- * 🔴 This exists because `startLocalAgentHostAuthority` is acquire-or-attach,
71
- * and for a surface that is the wrong shape in the most dangerous way: a CLI
72
- * started while no app is running would WIN the lease and then be asked to
73
- * build a host, which a thin client has no business owning. ADE §2.7 is
74
- * explicit that `xeno-agent-cli` "becomes a client of the same per-user host";
75
- * a client that can silently become the server is not that.
76
- *
77
- * 🔴 The defect is made UNREPRESENTABLE rather than documented: there is no
78
- * `createHostTransport` parameter here, so there is nothing this function could
79
- * construct even if it wanted to. It inspects, it connects, or it refuses with
80
- * a reason.
81
- */
82
- export async function attachToLocalAgentHost(options) {
83
- const protocolVersion = positiveInteger(options.protocolVersion) || XENO_AGENT_HOST_PROTOCOL_VERSION;
84
- const connectTimeoutMs = positiveInteger(options.connectTimeoutMs) || 5_000;
85
- const requestTimeoutMs = positiveInteger(options.requestTimeoutMs) || 30_000;
86
- const descriptor = await inspectLocalAgentHostLease(options.rootDirectory);
87
- if (!descriptor) {
88
- return {
89
- attached: false,
90
- reason: 'no-host',
91
- detail: 'No XENO Agent host is running for this user. Start the Agent app, or run the host detached.',
92
- };
93
- }
94
- // 🔴 The SAME staleness rule the acquire path uses — imported, not restated.
95
- // A crashed owner leaves its lock file behind, and connecting to it would
96
- // hang until the transport timed out with "unreachable", which reads as a
97
- // network fault rather than a host that is simply gone.
98
- if (isLeaseOwnerGone({
99
- heartbeatAt: descriptor.heartbeatAt,
100
- pid: descriptor.pid,
101
- at: (options.now || Date.now)(),
102
- ...(options.staleAfterMs === undefined ? {} : { staleAfterMs: options.staleAfterMs }),
103
- ...(options.isProcessAlive ? { isProcessAlive: options.isProcessAlive } : {}),
104
- })) {
105
- return {
106
- attached: false,
107
- reason: 'host-gone',
108
- detail: `The recorded Agent host (pid ${descriptor.pid}) is no longer running. Start the Agent app again.`,
109
- };
110
- }
111
- if (descriptor.protocolVersion !== protocolVersion) {
112
- return {
113
- attached: false,
114
- reason: 'protocol-mismatch',
115
- hostProtocol: descriptor.protocolVersion,
116
- clientProtocol: protocolVersion,
117
- detail: `The running Agent host speaks protocol ${descriptor.protocolVersion} and this client speaks ${protocolVersion}. Update whichever is older.`,
118
- };
119
- }
120
- const connection = await readLocalAgentHostLeaseConnection(options.rootDirectory);
121
- if (!connection || connection.descriptor.instanceId !== descriptor.instanceId) {
122
- // The host restarted between the inspection and the read. Refusing beats
123
- // connecting to a different instance than the one just vetted.
124
- return {
125
- attached: false,
126
- reason: 'unreachable',
127
- detail: 'The Agent host changed while connecting. Retry.',
128
- };
129
- }
130
- const transport = new LocalAgentHostRpcClientTransport({
131
- endpoint: connection.descriptor.endpoint,
132
- transportToken: connection.transportToken,
133
- protocolVersion,
134
- requestTimeoutMs,
135
- });
136
- try {
137
- await connectBeforeDeadline(transport, connectTimeoutMs);
138
- }
139
- catch (error) {
140
- transport.close();
141
- return {
142
- attached: false,
143
- reason: 'unreachable',
144
- detail: error instanceof Error ? error.message : String(error),
145
- };
146
- }
147
- return {
148
- attached: true,
149
- session: new LocalAgentHostAuthoritySession({
150
- // Always a client. There is no branch here that produces an owner, which
151
- // is the property this function exists to guarantee.
152
- role: 'attached-client',
153
- descriptor: connection.descriptor,
154
- transport,
155
- }),
156
- };
157
- }
158
- export async function connectBeforeDeadline(transport, timeoutMs) {
159
- const deadline = Date.now() + timeoutMs;
160
- let lastError;
161
- do {
162
- try {
163
- await transport.connect();
164
- return;
165
- }
166
- catch (error) {
167
- lastError = asError(error);
168
- if (!isRetryableConnectionError(lastError) || Date.now() >= deadline)
169
- break;
170
- await delay(Math.min(50, Math.max(1, deadline - Date.now())));
171
- }
172
- } while (Date.now() < deadline);
173
- throw lastError || new Error('Unable to connect to the local Agent host authority.');
174
- }
175
- function isRetryableConnectionError(error) {
176
- if (!('code' in error))
177
- return false;
178
- const code = error.code;
179
- return code === 'ENOENT' || code === 'ECONNREFUSED' || code === 'EPIPE';
180
- }
181
- function delay(milliseconds) {
182
- return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
183
- }
184
- function asError(error) {
185
- return error instanceof Error ? error : new Error(String(error));
186
- }
187
- //# sourceMappingURL=localAttach.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localAttach.js","sourceRoot":"","sources":["../src/localAttach.ts"],"names":[],"mappings":"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"}
@@ -1,50 +0,0 @@
1
- export interface LocalAgentHostLeaseDescriptor {
2
- schemaVersion: 1;
3
- instanceId: string;
4
- pid: number;
5
- endpoint: string;
6
- protocolVersion: number;
7
- acquiredAt: number;
8
- heartbeatAt: number;
9
- }
10
- export interface LocalAgentHostLeaseConnectionInfo {
11
- descriptor: LocalAgentHostLeaseDescriptor;
12
- /** Sensitive same-user bearer credential. Never expose this to a renderer or diagnostic export. */
13
- transportToken: string;
14
- }
15
- export interface LocalAgentHostLeaseRecord extends LocalAgentHostLeaseDescriptor {
16
- transportToken: string;
17
- }
18
- export declare const DEFAULT_LEASE_STALE_AFTER_MS = 15000;
19
- /**
20
- * Is the recorded owner gone?
21
- *
22
- * 🔴 TWO conditions, and the second is the one that matters. A missed
23
- * heartbeat alone does not mean a dead host — a process paused by a debugger,
24
- * a laptop resumed from sleep, or a machine under load all produce one. Taking
25
- * the lease from a LIVE owner is the split-brain the lease exists to prevent,
26
- * so the pid must also be gone.
27
- *
28
- * Exported and shared because a second caller now needs the same question
29
- * answered without acquiring anything: a surface deciding whether a host is
30
- * actually there. Two spellings of "is the owner dead" would eventually
31
- * disagree, and the two answers are "take over" and "connect".
32
- */
33
- export declare function isLeaseOwnerGone(input: {
34
- heartbeatAt: number;
35
- pid: number;
36
- at: number;
37
- staleAfterMs?: number;
38
- isProcessAlive?: (pid: number) => boolean;
39
- }): boolean;
40
- export declare function inspectLocalAgentHostLease(rootDirectory: string): Promise<LocalAgentHostLeaseDescriptor | null>;
41
- /**
42
- * Reads connection material for another trusted main/host process owned by the
43
- * same OS user. Callers must keep the token outside renderers, logs, and IPC.
44
- */
45
- export declare function readLocalAgentHostLeaseConnection(rootDirectory: string): Promise<LocalAgentHostLeaseConnectionInfo | null>;
46
- export declare function readLeaseRecord(path: string): Promise<LocalAgentHostLeaseRecord>;
47
- export declare function parseLeaseRecord(value: string): LocalAgentHostLeaseRecord;
48
- export declare function publicDescriptor(record: LocalAgentHostLeaseRecord): LocalAgentHostLeaseDescriptor;
49
- export declare function defaultProcessAlive(pid: number): boolean;
50
- //# sourceMappingURL=localLease.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localLease.d.ts","sourceRoot":"","sources":["../src/localLease.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,6BAA6B;IAC5C,aAAa,EAAE,CAAC,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,6BAA6B,CAAA;IACzC,mGAAmG;IACnG,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,yBAA0B,SAAQ,6BAA6B;IAC9E,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAElD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAC1C,GAAG,OAAO,CAIV;AAID,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAQ/C;AAED;;;GAGG;AACH,wBAAsB,iCAAiC,CACrD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,iCAAiC,GAAG,IAAI,CAAC,CAYnD;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEtF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB,CAqBzE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,yBAAyB,GAAG,6BAA6B,CAUjG;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQxD"}
@@ -1,120 +0,0 @@
1
- import { isNodeError } from './localTransport.js';
2
- /**
3
- * Local Agent host lease — the READ half.
4
- *
5
- * A surface needs to find and validate a running host: read the lease, decide whether its owner
6
- * is gone, and pull the connection info. It must never be able to ACQUIRE one — a thin client
7
- * that can win the lease would then be asked to *be* the host, which ADE §2.7 explicitly rules
8
- * out. Acquisition stays in `packages/host`, so the client cannot take ownership because the code
9
- * to do it is not here.
10
- *
11
- * `isNodeError` and the parse/record helpers are exported for the host's acquire half; they are
12
- * internal to the lease protocol and not part of the supported surface.
13
- */
14
- import { randomBytes } from 'node:crypto';
15
- import { mkdir, open, readFile, unlink } from 'node:fs/promises';
16
- import { join } from 'node:path';
17
- export const DEFAULT_LEASE_STALE_AFTER_MS = 15_000;
18
- /**
19
- * Is the recorded owner gone?
20
- *
21
- * 🔴 TWO conditions, and the second is the one that matters. A missed
22
- * heartbeat alone does not mean a dead host — a process paused by a debugger,
23
- * a laptop resumed from sleep, or a machine under load all produce one. Taking
24
- * the lease from a LIVE owner is the split-brain the lease exists to prevent,
25
- * so the pid must also be gone.
26
- *
27
- * Exported and shared because a second caller now needs the same question
28
- * answered without acquiring anything: a surface deciding whether a host is
29
- * actually there. Two spellings of "is the owner dead" would eventually
30
- * disagree, and the two answers are "take over" and "connect".
31
- */
32
- export function isLeaseOwnerGone(input) {
33
- const staleAfterMs = positiveInteger(input.staleAfterMs) || DEFAULT_LEASE_STALE_AFTER_MS;
34
- const alive = input.isProcessAlive || defaultProcessAlive;
35
- return input.at - input.heartbeatAt > staleAfterMs && !alive(input.pid);
36
- }
37
- export async function inspectLocalAgentHostLease(rootDirectory) {
38
- const path = join(rootDirectory, 'agent-host.lock');
39
- try {
40
- return publicDescriptor(await readLeaseRecord(path));
41
- }
42
- catch (error) {
43
- if (isNodeError(error, 'ENOENT'))
44
- return null;
45
- throw error;
46
- }
47
- }
48
- /**
49
- * Reads connection material for another trusted main/host process owned by the
50
- * same OS user. Callers must keep the token outside renderers, logs, and IPC.
51
- */
52
- export async function readLocalAgentHostLeaseConnection(rootDirectory) {
53
- const path = join(rootDirectory, 'agent-host.lock');
54
- try {
55
- const record = await readLeaseRecord(path);
56
- return {
57
- descriptor: publicDescriptor(record),
58
- transportToken: record.transportToken,
59
- };
60
- }
61
- catch (error) {
62
- if (isNodeError(error, 'ENOENT'))
63
- return null;
64
- throw error;
65
- }
66
- }
67
- export async function readLeaseRecord(path) {
68
- return parseLeaseRecord(await readFile(path, 'utf8'));
69
- }
70
- export function parseLeaseRecord(value) {
71
- let parsed;
72
- try {
73
- parsed = JSON.parse(value);
74
- }
75
- catch {
76
- throw new Error('Agent host authority lease is malformed.');
77
- }
78
- if (!isRecord(parsed)
79
- || parsed.schemaVersion !== 1
80
- || typeof parsed.instanceId !== 'string'
81
- || typeof parsed.pid !== 'number'
82
- || typeof parsed.endpoint !== 'string'
83
- || typeof parsed.protocolVersion !== 'number'
84
- || typeof parsed.acquiredAt !== 'number'
85
- || typeof parsed.heartbeatAt !== 'number'
86
- || typeof parsed.transportToken !== 'string'
87
- || parsed.transportToken.length < 32) {
88
- throw new Error('Agent host authority lease is invalid.');
89
- }
90
- return parsed;
91
- }
92
- export function publicDescriptor(record) {
93
- return {
94
- schemaVersion: 1,
95
- instanceId: record.instanceId,
96
- pid: record.pid,
97
- endpoint: record.endpoint,
98
- protocolVersion: record.protocolVersion,
99
- acquiredAt: record.acquiredAt,
100
- heartbeatAt: record.heartbeatAt,
101
- };
102
- }
103
- export function defaultProcessAlive(pid) {
104
- if (!Number.isInteger(pid) || pid <= 0)
105
- return false;
106
- try {
107
- process.kill(pid, 0);
108
- return true;
109
- }
110
- catch (error) {
111
- return isNodeError(error, 'EPERM');
112
- }
113
- }
114
- function positiveInteger(value) {
115
- return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
116
- }
117
- function isRecord(value) {
118
- return typeof value === 'object' && value !== null && !Array.isArray(value);
119
- }
120
- //# sourceMappingURL=localLease.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localLease.js","sourceRoot":"","sources":["../src/localLease.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEjD;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAwBhC,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAA;AAElD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAMhC;IACC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,4BAA4B,CAAA;IACxF,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,IAAI,mBAAmB,CAAA;IACzD,OAAO,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,WAAW,GAAG,YAAY,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACzE,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,aAAqB;IAErB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAA;IACnD,IAAI,CAAC;QACH,OAAO,gBAAgB,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAA;QAC7C,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,aAAqB;IAErB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAA;IACnD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAA;QAC1C,OAAO;YACL,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC;YACpC,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAA;QAC7C,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,OAAO,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;IAC7D,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;WAChB,MAAM,CAAC,aAAa,KAAK,CAAC;WAC1B,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;WACrC,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;WAC9B,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;WACnC,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ;WAC1C,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;WACrC,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ;WACtC,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ;WACzC,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,EAAE,EACpC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,MAA8C,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiC;IAChE,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACpC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAyB;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9F,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC"}
@@ -1,100 +0,0 @@
1
- /**
2
- * Local Agent host wire protocol — framing plus the CLIENT transport.
3
- *
4
- * 🔴 This lives in the CLIENT package, not in `contract`, and the reason is load-bearing:
5
- * `contract` is Node-free and must stay that way. A renderer reaches `contract/index.js`, and
6
- * Vite fails a browser build on any `node:` builtin ("stat" is not exported by
7
- * "__vite-browser-external") — `browserBarrelPurity.test.ts` pins that. This module needs
8
- * `node:net`, `node:crypto` and `node:fs/promises`, so it cannot go there.
9
- *
10
- * It is also why the split is client-package-and-below rather than contract-and-below: a surface
11
- * that wants to ATTACH to a local host needs Node anyway.
12
- *
13
- * @packageDocumentation
14
- */
15
- import { type Socket } from 'node:net';
16
- import { type AgentHostEvent, type AgentHostEventListener, type AgentHostInput, type AgentHostMethod, type AgentHostOutput, type AgentHostProtocolErrorCode, type AgentHostTransport, type AgentHostUnsubscribe } from '@xenosystem/agent-interface-contract';
17
- export declare const LOCAL_AGENT_HOST_DEFAULT_MAX_FRAME_BYTES: number;
18
- export declare const LOCAL_AGENT_HOST_ABSOLUTE_MAX_FRAME_BYTES: number;
19
- export interface LocalRpcRequest {
20
- kind: 'request';
21
- id: string;
22
- protocolVersion: number;
23
- token: string;
24
- method: AgentHostMethod;
25
- input: unknown;
26
- }
27
- export type LocalRpcResponse = {
28
- kind: 'response';
29
- id: string;
30
- ok: true;
31
- output: unknown;
32
- } | {
33
- kind: 'response';
34
- id: string;
35
- ok: false;
36
- error: {
37
- code: AgentHostProtocolErrorCode;
38
- message: string;
39
- };
40
- };
41
- interface LocalRpcEvent {
42
- kind: 'event';
43
- event: AgentHostEvent;
44
- }
45
- export type LocalRpcServerMessage = LocalRpcResponse | LocalRpcEvent;
46
- export interface LocalAgentHostRpcServerOptions {
47
- transport: AgentHostTransport;
48
- endpoint: string;
49
- transportToken: string;
50
- protocolVersion?: number;
51
- maxFrameBytes?: number;
52
- removeStaleEndpoint?: boolean;
53
- }
54
- export interface LocalAgentHostRpcClientOptions {
55
- endpoint: string;
56
- transportToken: string;
57
- protocolVersion?: number;
58
- maxFrameBytes?: number;
59
- requestTimeoutMs?: number;
60
- }
61
- /** Node-side AgentHostTransport implementation for a local host authority. */
62
- export declare class LocalAgentHostRpcClientTransport implements AgentHostTransport {
63
- private readonly endpoint;
64
- private readonly transportToken;
65
- private readonly protocolVersion;
66
- private readonly maxFrameBytes;
67
- private readonly requestTimeoutMs;
68
- private readonly listeners;
69
- private readonly pending;
70
- private readonly requestPrefix;
71
- private requestSequence;
72
- private socket;
73
- private connectPromise;
74
- constructor(options: LocalAgentHostRpcClientOptions);
75
- get connected(): boolean;
76
- connect(): Promise<void>;
77
- request<M extends AgentHostMethod>(method: M, input: AgentHostInput<M>): Promise<AgentHostOutput<M>>;
78
- subscribe(listener: AgentHostEventListener): AgentHostUnsubscribe;
79
- close(): void;
80
- private receive;
81
- private disconnect;
82
- }
83
- export declare function resolveLocalAgentHostEndpoint(rootDirectory: string, scope?: string): string;
84
- export declare class JsonLineDecoder {
85
- private readonly maxFrameBytes;
86
- private readonly onFrame;
87
- private buffer;
88
- constructor(maxFrameBytes: number, onFrame: (frame: string) => void);
89
- push(chunk: Buffer): void;
90
- }
91
- export declare function writeFrame(socket: Socket, value: unknown, maxFrameBytes: number): void;
92
- export declare function safeTokenEquals(left: string, right: string): boolean;
93
- export declare function assertLocalRpcOptions(endpoint: string, transportToken: string): void;
94
- export declare function positiveInteger(value: number | undefined): number | undefined;
95
- export declare function resolveMaxFrameBytes(value: number | undefined): number;
96
- export declare function asError(error: unknown): Error;
97
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
98
- export declare function isNodeError(error: unknown, code: string): error is NodeJS.ErrnoException;
99
- export {};
100
- //# sourceMappingURL=localTransport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localTransport.d.ts","sourceRoot":"","sources":["../src/localTransport.ts"],"names":[],"mappings":"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"}
@@ -1,276 +0,0 @@
1
- /**
2
- * Local Agent host wire protocol — framing plus the CLIENT transport.
3
- *
4
- * 🔴 This lives in the CLIENT package, not in `contract`, and the reason is load-bearing:
5
- * `contract` is Node-free and must stay that way. A renderer reaches `contract/index.js`, and
6
- * Vite fails a browser build on any `node:` builtin ("stat" is not exported by
7
- * "__vite-browser-external") — `browserBarrelPurity.test.ts` pins that. This module needs
8
- * `node:net`, `node:crypto` and `node:fs/promises`, so it cannot go there.
9
- *
10
- * It is also why the split is client-package-and-below rather than contract-and-below: a surface
11
- * that wants to ATTACH to a local host needs Node anyway.
12
- *
13
- * @packageDocumentation
14
- */
15
- import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
16
- import { chmod, mkdir, unlink } from 'node:fs/promises';
17
- import { dirname, join, resolve } from 'node:path';
18
- import { createConnection, createServer, } from 'node:net';
19
- import { AgentHostProtocolError, XENO_AGENT_HOST_PROTOCOL_VERSION, isAgentHostMethod, isAgentHostEvent, } from '@xenosystem/agent-interface-contract';
20
- export const LOCAL_AGENT_HOST_DEFAULT_MAX_FRAME_BYTES = 32 * 1024 * 1024;
21
- export const LOCAL_AGENT_HOST_ABSOLUTE_MAX_FRAME_BYTES = 64 * 1024 * 1024;
22
- const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
23
- /** Node-side AgentHostTransport implementation for a local host authority. */
24
- export class LocalAgentHostRpcClientTransport {
25
- endpoint;
26
- transportToken;
27
- protocolVersion;
28
- maxFrameBytes;
29
- requestTimeoutMs;
30
- listeners = new Set();
31
- pending = new Map();
32
- requestPrefix = randomBytes(12).toString('hex');
33
- requestSequence = 0;
34
- socket = null;
35
- connectPromise = null;
36
- constructor(options) {
37
- assertLocalRpcOptions(options.endpoint, options.transportToken);
38
- this.endpoint = options.endpoint;
39
- this.transportToken = options.transportToken;
40
- this.protocolVersion = positiveInteger(options.protocolVersion) || XENO_AGENT_HOST_PROTOCOL_VERSION;
41
- this.maxFrameBytes = resolveMaxFrameBytes(options.maxFrameBytes);
42
- this.requestTimeoutMs = positiveInteger(options.requestTimeoutMs) || DEFAULT_REQUEST_TIMEOUT_MS;
43
- }
44
- get connected() {
45
- return this.socket !== null && !this.socket.destroyed;
46
- }
47
- async connect() {
48
- if (this.connected)
49
- return;
50
- if (this.connectPromise)
51
- return this.connectPromise;
52
- this.connectPromise = new Promise((resolveConnect, rejectConnect) => {
53
- const socket = createConnection(this.endpoint);
54
- const decoder = new JsonLineDecoder(this.maxFrameBytes, (frame) => this.receive(frame));
55
- const failConnect = (error) => {
56
- socket.off('connect', connected);
57
- this.socket = null;
58
- rejectConnect(error);
59
- };
60
- const connected = () => {
61
- socket.off('error', failConnect);
62
- socket.setNoDelay(true);
63
- this.socket = socket;
64
- resolveConnect();
65
- };
66
- socket.once('error', failConnect);
67
- socket.once('connect', connected);
68
- socket.on('data', (chunk) => {
69
- try {
70
- decoder.push(chunk);
71
- }
72
- catch (error) {
73
- this.disconnect(asError(error));
74
- }
75
- });
76
- socket.on('error', (error) => this.disconnect(error));
77
- socket.on('close', () => this.disconnect(new Error('Local Agent host connection closed.')));
78
- }).finally(() => {
79
- this.connectPromise = null;
80
- });
81
- return this.connectPromise;
82
- }
83
- async request(method, input) {
84
- await this.connect();
85
- const socket = this.socket;
86
- if (!socket || socket.destroyed) {
87
- throw new AgentHostProtocolError('not_connected', 'Local Agent host is not connected.');
88
- }
89
- const id = `${this.requestPrefix}:${++this.requestSequence}`;
90
- const request = {
91
- kind: 'request',
92
- id,
93
- protocolVersion: this.protocolVersion,
94
- token: this.transportToken,
95
- method,
96
- input: structuredClone(input),
97
- };
98
- return new Promise((resolveRequest, rejectRequest) => {
99
- const requestTimeoutMs = resolveRequestTimeout(method, input, this.requestTimeoutMs);
100
- const timeout = setTimeout(() => {
101
- this.pending.delete(id);
102
- rejectRequest(new AgentHostProtocolError('not_connected', `Local Agent host request timed out: ${method}.`));
103
- }, requestTimeoutMs);
104
- this.pending.set(id, {
105
- resolve: (output) => resolveRequest(output),
106
- reject: rejectRequest,
107
- timeout,
108
- });
109
- try {
110
- writeClientFrame(socket, request, this.maxFrameBytes);
111
- }
112
- catch (error) {
113
- clearTimeout(timeout);
114
- this.pending.delete(id);
115
- rejectRequest(asError(error));
116
- }
117
- });
118
- }
119
- subscribe(listener) {
120
- this.listeners.add(listener);
121
- return () => {
122
- this.listeners.delete(listener);
123
- };
124
- }
125
- close() {
126
- this.disconnect(new Error('Local Agent host client closed.'));
127
- }
128
- receive(frame) {
129
- let value;
130
- try {
131
- value = JSON.parse(frame);
132
- }
133
- catch {
134
- this.disconnect(new AgentHostProtocolError('invalid_response', 'Local Agent host returned malformed JSON.'));
135
- return;
136
- }
137
- if (isLocalRpcEvent(value)) {
138
- for (const listener of [...this.listeners])
139
- listener(structuredClone(value.event));
140
- return;
141
- }
142
- if (!isLocalRpcResponse(value)) {
143
- this.disconnect(new AgentHostProtocolError('invalid_response', 'Local Agent host returned an invalid RPC frame.'));
144
- return;
145
- }
146
- const pending = this.pending.get(value.id);
147
- if (!pending)
148
- return;
149
- clearTimeout(pending.timeout);
150
- this.pending.delete(value.id);
151
- if (value.ok)
152
- pending.resolve(structuredClone(value.output));
153
- else
154
- pending.reject(new AgentHostProtocolError(value.error.code, value.error.message));
155
- }
156
- disconnect(error) {
157
- const socket = this.socket;
158
- this.socket = null;
159
- if (socket && !socket.destroyed)
160
- socket.destroy();
161
- for (const pending of this.pending.values()) {
162
- clearTimeout(pending.timeout);
163
- pending.reject(error);
164
- }
165
- this.pending.clear();
166
- }
167
- }
168
- function resolveRequestTimeout(method, input, fallback) {
169
- if (method !== 'workspace.command.run')
170
- return fallback;
171
- const requested = isRecord(input) && typeof input.timeoutMs === 'number' && Number.isFinite(input.timeoutMs)
172
- ? Math.max(1_000, Math.min(120_000, Math.floor(input.timeoutMs)))
173
- : 20_000;
174
- return Math.max(fallback, requested + 5_000);
175
- }
176
- export function resolveLocalAgentHostEndpoint(rootDirectory, scope = 'default') {
177
- if (!rootDirectory.trim())
178
- throw new Error('Local Agent host rootDirectory is required.');
179
- if (!scope.trim())
180
- throw new Error('Local Agent host endpoint scope is required.');
181
- const digest = createHash('sha256')
182
- .update(`${resolve(rootDirectory)}\0${scope}`, 'utf8')
183
- .digest('hex')
184
- .slice(0, 24);
185
- return process.platform === 'win32'
186
- ? `\\\\.\\pipe\\xeno-agent-host-${digest}`
187
- : join(rootDirectory, `agent-host-${digest}.sock`);
188
- }
189
- export class JsonLineDecoder {
190
- maxFrameBytes;
191
- onFrame;
192
- buffer = Buffer.alloc(0);
193
- constructor(maxFrameBytes, onFrame) {
194
- this.maxFrameBytes = maxFrameBytes;
195
- this.onFrame = onFrame;
196
- }
197
- push(chunk) {
198
- this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
199
- if (this.buffer.length > this.maxFrameBytes && this.buffer.indexOf(0x0a) < 0) {
200
- throw new AgentHostProtocolError('invalid_response', 'Local Agent host RPC frame exceeds the size limit.');
201
- }
202
- let newline = this.buffer.indexOf(0x0a);
203
- while (newline >= 0) {
204
- if (newline > this.maxFrameBytes) {
205
- throw new AgentHostProtocolError('invalid_response', 'Local Agent host RPC frame exceeds the size limit.');
206
- }
207
- const frameBuffer = this.buffer.subarray(0, newline);
208
- this.buffer = this.buffer.subarray(newline + 1);
209
- const frame = frameBuffer.toString('utf8').replace(/\r$/, '');
210
- if (frame)
211
- this.onFrame(frame);
212
- newline = this.buffer.indexOf(0x0a);
213
- }
214
- }
215
- }
216
- function isLocalRpcResponse(value) {
217
- if (!isRecord(value) || value.kind !== 'response' || typeof value.id !== 'string' || typeof value.ok !== 'boolean') {
218
- return false;
219
- }
220
- if (value.ok)
221
- return 'output' in value;
222
- return isRecord(value.error)
223
- && isProtocolErrorCode(value.error.code)
224
- && typeof value.error.message === 'string';
225
- }
226
- function isLocalRpcEvent(value) {
227
- return isRecord(value) && value.kind === 'event' && isAgentHostEvent(value.event);
228
- }
229
- function writeClientFrame(socket, value, maxFrameBytes) {
230
- writeFrame(socket, value, maxFrameBytes);
231
- }
232
- export function writeFrame(socket, value, maxFrameBytes) {
233
- const encoded = `${JSON.stringify(value)}\n`;
234
- if (Buffer.byteLength(encoded, 'utf8') > maxFrameBytes) {
235
- throw new AgentHostProtocolError('invalid_response', 'Local Agent host RPC frame exceeds the size limit.');
236
- }
237
- socket.write(encoded, 'utf8');
238
- }
239
- export function safeTokenEquals(left, right) {
240
- const leftBytes = Buffer.from(left, 'utf8');
241
- const rightBytes = Buffer.from(right, 'utf8');
242
- return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);
243
- }
244
- export function assertLocalRpcOptions(endpoint, transportToken) {
245
- if (!endpoint.trim())
246
- throw new Error('Local Agent host endpoint is required.');
247
- if (transportToken.length < 32)
248
- throw new Error('Local Agent host transportToken must contain at least 32 characters.');
249
- }
250
- export function positiveInteger(value) {
251
- return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
252
- }
253
- export function resolveMaxFrameBytes(value) {
254
- const requested = positiveInteger(value) || LOCAL_AGENT_HOST_DEFAULT_MAX_FRAME_BYTES;
255
- if (requested > LOCAL_AGENT_HOST_ABSOLUTE_MAX_FRAME_BYTES) {
256
- throw new Error(`Local Agent host RPC frame limit cannot exceed ${LOCAL_AGENT_HOST_ABSOLUTE_MAX_FRAME_BYTES} bytes.`);
257
- }
258
- return requested;
259
- }
260
- function isProtocolErrorCode(value) {
261
- return value === 'invalid_handshake'
262
- || value === 'protocol_mismatch'
263
- || value === 'surface_mismatch'
264
- || value === 'not_connected'
265
- || value === 'invalid_response';
266
- }
267
- export function asError(error) {
268
- return error instanceof Error ? error : new Error(String(error));
269
- }
270
- export function isRecord(value) {
271
- return typeof value === 'object' && value !== null && !Array.isArray(value);
272
- }
273
- export function isNodeError(error, code) {
274
- return error instanceof Error && 'code' in error && error.code === code;
275
- }
276
- //# sourceMappingURL=localTransport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"localTransport.js","sourceRoot":"","sources":["../src/localTransport.ts"],"names":[],"mappings":"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"}