kojee-mcp 0.5.3 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +112 -5
  2. package/dist/{chunk-YEC7IHIG.js → chunk-2BDAM3TH.js} +92 -523
  3. package/dist/chunk-2MIISF2W.js +35 -0
  4. package/dist/chunk-3XDJOHMZ.js +223 -0
  5. package/dist/{chunk-ZW4SW7LJ.js → chunk-64EOLZNI.js} +14 -5
  6. package/dist/chunk-6SK6ITFE.js +142 -0
  7. package/dist/chunk-GI2CKKBL.js +46 -0
  8. package/dist/chunk-HIZ4NDWN.js +141 -0
  9. package/dist/chunk-LDZXU3DW.js +170 -0
  10. package/dist/{resubscribe-SLZNA76S.js → chunk-OT2GILXC.js} +1 -0
  11. package/dist/{chunk-WBMX4CHB.js → chunk-UEGQGXPY.js} +57 -40
  12. package/dist/chunk-V5VZPYMZ.js +185 -0
  13. package/dist/{chunk-C6GZ2L2W.js → chunk-X672ZN7V.js} +5 -2
  14. package/dist/cli.js +47 -24
  15. package/dist/{codex-stop-hook-JOTBCS5K.js → codex-stop-hook-SWA53ECG.js} +1 -1
  16. package/dist/control-token-4BUCTYQB.js +13 -0
  17. package/dist/{doctor-TSHOMT5X.js → doctor-QCQDFLEH.js} +30 -17
  18. package/dist/{doctor-codex-BMI5JOO6.js → doctor-codex-NZ53ROQA.js} +12 -5
  19. package/dist/ensure-join-7AEDJMPE.js +96 -0
  20. package/dist/gateway-client-93P1E0CZ.d.ts +92 -0
  21. package/dist/{hook-server-QF5JVUHV.js → hook-server-37E2LUKJ.js} +91 -0
  22. package/dist/index.d.ts +18 -15
  23. package/dist/index.js +9 -3
  24. package/dist/lib.d.ts +427 -0
  25. package/dist/lib.js +44 -0
  26. package/dist/reconnect-scheduler-JSXCJKQP.js +26 -0
  27. package/dist/resubscribe-G5OGDZJD.js +6 -0
  28. package/dist/send-cli-C2F4WTBN.js +72 -0
  29. package/dist/{stop-hook-SEPWWETV.js → stop-hook-TRAMQYNE.js} +16 -8
  30. package/dist/{tail-stream-BYKO4DW6.js → tail-stream-VUZBYKXS.js} +4 -3
  31. package/dist/{user-prompt-submit-hook-ARPEO6FF.js → user-prompt-submit-hook-ZD2XKN7U.js} +7 -1
  32. package/dist/webhook-config-O4WMQ532.js +20 -0
  33. package/dist/{webhook-sink-7OYZBWXA.js → webhook-sink-NWGCUDGY.js} +28 -5
  34. package/dist/{wizard-7KHD5JT4.js → wizard-OSOAY4GO.js} +64 -27
  35. package/package.json +11 -2
  36. package/dist/chunk-F7L25L2J.js +0 -60
  37. package/dist/webhook-config-5TLLX7RA.js +0 -10
@@ -1,18 +1,21 @@
1
1
  import {
2
- loadPairedConfig
3
- } from "./chunk-YH27B6SW.js";
2
+ monitorHeartbeatPath,
3
+ statusLogPath
4
+ } from "./chunk-2TUAFAIW.js";
4
5
  import {
5
- deriveDiscoveryKey,
6
- findClaudeAncestorPid
7
- } from "./chunk-BJMASMKX.js";
6
+ loadControlToken
7
+ } from "./chunk-GI2CKKBL.js";
8
8
  import {
9
9
  buildMonitorSpawn,
10
10
  buildReplyRecipe
11
- } from "./chunk-C6GZ2L2W.js";
11
+ } from "./chunk-X672ZN7V.js";
12
12
  import {
13
- monitorHeartbeatPath,
14
- statusLogPath
15
- } from "./chunk-2TUAFAIW.js";
13
+ deriveDiscoveryKey,
14
+ findClaudeAncestorPid
15
+ } from "./chunk-BJMASMKX.js";
16
+ import {
17
+ loadPairedConfig
18
+ } from "./chunk-YH27B6SW.js";
16
19
  import {
17
20
  discoveryPathForKey,
18
21
  readSessionDiscoveryByKey
@@ -111,8 +114,17 @@ async function collectDoctorReport(deps = {}) {
111
114
  ok: health !== null,
112
115
  detail: health !== null ? "ok" : "unreachable"
113
116
  });
114
- const statusProbe = await probeJsonWithStatus(fetchFn, `${base}/status`);
115
- if (statusProbe.json === null && statusProbe.routeAbsent) {
117
+ const readControlToken = deps.readControlToken ?? loadControlToken;
118
+ const controlToken = readControlToken(discovery.controlTokenPath);
119
+ const statusHeaders = controlToken ? { Authorization: `Bearer ${controlToken}` } : {};
120
+ const statusProbe = await probeJsonWithStatus(fetchFn, `${base}/status`, statusHeaders);
121
+ if (statusProbe.json === null && statusProbe.unauthorized) {
122
+ checks.push({
123
+ name: "hook-server /status",
124
+ ok: "warn",
125
+ detail: `401 unauthorized \u2014 /status is gated by the control token (0.5.4); could not present a valid bearer from ${discovery.controlTokenPath ?? "~/.kojee/control-token"} (daemon restarted? re-run doctor; file unreadable? check perms)`
126
+ });
127
+ } else if (statusProbe.json === null && statusProbe.routeAbsent) {
116
128
  checks.push({
117
129
  name: "hook-server /status",
118
130
  ok: "unknown",
@@ -187,14 +199,15 @@ async function probeJson(fetchFn, url) {
187
199
  return null;
188
200
  }
189
201
  }
190
- async function probeJsonWithStatus(fetchFn, url) {
202
+ async function probeJsonWithStatus(fetchFn, url, headers = {}) {
191
203
  try {
192
- const res = await fetchFn(url);
193
- if (res.ok) return { json: await res.json(), routeAbsent: false };
204
+ const res = await fetchFn(url, { headers });
205
+ if (res.ok) return { json: await res.json(), routeAbsent: false, unauthorized: false };
194
206
  const routeAbsent = res.status === 404 || res.status === 405;
195
- return { json: null, routeAbsent };
207
+ const unauthorized = res.status === 401;
208
+ return { json: null, routeAbsent, unauthorized };
196
209
  } catch {
197
- return { json: null, routeAbsent: false };
210
+ return { json: null, routeAbsent: false, unauthorized: false };
198
211
  }
199
212
  }
200
213
  function formatDoctorReport(report) {
@@ -220,7 +233,7 @@ function formatDoctorReport(report) {
220
233
  async function runDoctor() {
221
234
  const { readRecordedRuntime } = await import("./runtime-record-WO4IECM6.js");
222
235
  if (readRecordedRuntime() === "codex") {
223
- const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-BMI5JOO6.js");
236
+ const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-NZ53ROQA.js");
224
237
  const report2 = collectCodexDoctorReport();
225
238
  console.error(formatCodexDoctorReport(report2));
226
239
  return report2.verdict === "broken" ? 1 : 0;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  defaultCodexConfigPath,
3
3
  defaultCodexHooksPath
4
- } from "./chunk-ZW4SW7LJ.js";
4
+ } from "./chunk-64EOLZNI.js";
5
5
  import "./chunk-SQL56SEB.js";
6
+ import {
7
+ resolveWebhookConfig
8
+ } from "./chunk-V5VZPYMZ.js";
6
9
  import {
7
10
  CODEX_LISTEN_CAP_MS
8
- } from "./chunk-C6GZ2L2W.js";
11
+ } from "./chunk-X672ZN7V.js";
9
12
  import "./chunk-BLEGIR35.js";
10
- import {
11
- resolveWebhookConfig
12
- } from "./chunk-F7L25L2J.js";
13
13
 
14
14
  // src/doctor-codex.ts
15
15
  import fs from "fs";
@@ -84,6 +84,13 @@ function collectCodexDoctorReport(deps = {}) {
84
84
  ok: true,
85
85
  detail: `enabled \u2014 ${resolution.config.redactedSummary}`
86
86
  });
87
+ if (resolution.warning) {
88
+ checks.push({
89
+ name: "webhook signature config",
90
+ ok: "warn",
91
+ detail: `${resolution.warning} \u2014 ${WIZARD_RERUN} with valid signature flags`
92
+ });
93
+ }
87
94
  } else if (resolution.error) {
88
95
  checks.push({
89
96
  name: "webhook sink",
@@ -0,0 +1,96 @@
1
+ // src/tandem/ensure-join.ts
2
+ var OBJECT_ID_RE = /^[0-9a-f]{24}$/i;
3
+ var DEFAULT_PER_CALL_TIMEOUT_MS = 1e4;
4
+ function parseTandemsConfig(raw) {
5
+ const trimmed = (raw ?? "").trim();
6
+ if (trimmed.length === 0) return { mode: "auto", ids: [], invalid: [] };
7
+ if (trimmed.toLowerCase() === "none") return { mode: "disabled", ids: [], invalid: [] };
8
+ const ids = [];
9
+ const invalid = [];
10
+ for (const entry of trimmed.split(/[\s,]+/)) {
11
+ if (entry.length === 0) continue;
12
+ (OBJECT_ID_RE.test(entry) ? ids : invalid).push(entry);
13
+ }
14
+ return { mode: "explicit", ids, invalid };
15
+ }
16
+ async function ensureJoinTandems(opts) {
17
+ const log = opts.log ?? ((line) => console.error(line));
18
+ const perCallTimeoutMs = opts.perCallTimeoutMs ?? DEFAULT_PER_CALL_TIMEOUT_MS;
19
+ const config = parseTandemsConfig(opts.env);
20
+ const result = { mode: config.mode, joined: [], already: [], failed: [] };
21
+ if (config.mode === "disabled") {
22
+ log("[ensure-join] disabled (KOJEE_TANDEMS=none)");
23
+ return result;
24
+ }
25
+ for (const bad of config.invalid) {
26
+ log(`[ensure-join] skipping invalid tandem id "${bad}" (not a 24-hex ObjectId)`);
27
+ }
28
+ let ids;
29
+ if (config.mode === "explicit") {
30
+ ids = config.ids;
31
+ log(`[ensure-join] mode=explicit n=${ids.length} (KOJEE_TANDEMS)`);
32
+ } else {
33
+ let listed = null;
34
+ try {
35
+ listed = opts.listTandems ? await opts.listTandems() : null;
36
+ } catch (err) {
37
+ log(`[ensure-join] tandem_list threw: ${err.message}`);
38
+ listed = null;
39
+ }
40
+ if (listed === null) {
41
+ log(
42
+ "[ensure-join] tandem_list failed \u2014 cannot auto re-seat this session (set KOJEE_TANDEMS=<ids> to pin, or KOJEE_TANDEMS=none to silence)"
43
+ );
44
+ return result;
45
+ }
46
+ ids = listed;
47
+ log(`[ensure-join] mode=auto n=${ids.length} (KOJEE_TANDEMS unset \u2014 re-seating where this agent already holds a seat)`);
48
+ }
49
+ for (const id of ids) {
50
+ const outcome = await joinOne(opts.gateway, id, perCallTimeoutMs);
51
+ if (outcome.kind === "failed") {
52
+ result.failed.push(id);
53
+ log(`[ensure-join] ${id}: FAILED \u2014 ${outcome.detail} (continuing)`);
54
+ continue;
55
+ }
56
+ if (outcome.kind === "already") {
57
+ result.already.push(id);
58
+ log(`[ensure-join] ${id}: already seated`);
59
+ } else {
60
+ result.joined.push(id);
61
+ log(`[ensure-join] ${id}: joined fresh`);
62
+ }
63
+ try {
64
+ opts.onJoined?.(id);
65
+ } catch {
66
+ }
67
+ }
68
+ return result;
69
+ }
70
+ async function joinOne(gateway, tandemId, perCallTimeoutMs) {
71
+ const ac = new AbortController();
72
+ const timer = setTimeout(() => ac.abort(), perCallTimeoutMs);
73
+ try {
74
+ const result = await gateway.sendRpc(
75
+ "tools/call",
76
+ { name: "tandem_join", arguments: { tandem_id: tandemId } },
77
+ ac.signal
78
+ );
79
+ const text = (result.content ?? []).map((c) => typeof c?.text === "string" ? c.text : "").filter(Boolean).join("\n");
80
+ if (result.isError) {
81
+ return { kind: "failed", detail: text || "tandem_join returned an error with no text" };
82
+ }
83
+ if (/already[\s_-]?(a[\s_-]?)?(member|seated|joined)/i.test(text)) {
84
+ return { kind: "already" };
85
+ }
86
+ return { kind: "joined" };
87
+ } catch (err) {
88
+ return { kind: "failed", detail: err?.message ?? String(err) };
89
+ } finally {
90
+ clearTimeout(timer);
91
+ }
92
+ }
93
+ export {
94
+ ensureJoinTandems,
95
+ parseTandemsConfig
96
+ };
@@ -0,0 +1,92 @@
1
+ import { KeyLike, JWK } from 'jose';
2
+
3
+ interface ProxyConfig {
4
+ token: string;
5
+ url: string;
6
+ keystorePath: string;
7
+ /**
8
+ * How credentials were resolved at launch: "token" when `--token` was passed
9
+ * on the CLI, "paired" when read from ~/.kojee/config.json. The proxy records
10
+ * this in its session-discovery file so `kojee-mcp doctor` can render the
11
+ * pairing check honestly on a token-mode box (no config.json by design).
12
+ * Defaults to "paired" when unset (back-compat with callers predating the
13
+ * field).
14
+ */
15
+ authMode?: "token" | "paired";
16
+ }
17
+ interface KeystoreData {
18
+ private_key_jwk: JWK;
19
+ kid: string;
20
+ broker_url: string;
21
+ public_jwk: JWK;
22
+ enrolled_at: string;
23
+ }
24
+ interface LoadedKeyPair {
25
+ privateKey: KeyLike;
26
+ publicJwk: JWK;
27
+ kid: string;
28
+ }
29
+ interface GovernanceMeta {
30
+ decision: "require_approval" | "deny" | "allow";
31
+ approval_id?: string;
32
+ expires_at?: string;
33
+ triggered_guardrails?: string[];
34
+ }
35
+ interface ToolCallContent {
36
+ type: string;
37
+ text: string;
38
+ }
39
+ interface ToolCallResult {
40
+ content: ToolCallContent[];
41
+ isError?: boolean;
42
+ _meta?: {
43
+ governance?: GovernanceMeta;
44
+ };
45
+ }
46
+
47
+ declare class GatewayClient {
48
+ private readonly brokerUrl;
49
+ private readonly token;
50
+ private readonly privateKey;
51
+ private readonly kid;
52
+ private currentNonce;
53
+ private requestCounter;
54
+ private readonly endpoint;
55
+ constructor(brokerUrl: string, token: string, privateKey: KeyLike, kid: string, sessionId: string);
56
+ /**
57
+ * Expose the DPoP signing key so peer modules sharing auth state
58
+ * (e.g. tandem/event-stream.ts) can sign their own requests.
59
+ */
60
+ getPrivateKey(): KeyLike;
61
+ /**
62
+ * Expose the bot_key_id (kid) for DPoP proof headers. Paired with
63
+ * getPrivateKey() so peer modules can construct proofs without
64
+ * threading the key material through their own constructors.
65
+ */
66
+ getKid(): string;
67
+ /**
68
+ * Derive a deterministic session ID from the gateway token.
69
+ * session_id = sha256(token + "proxy").slice(0, 16)
70
+ */
71
+ static deriveSessionId(token: string): string;
72
+ /**
73
+ * Send a JSON-RPC 2.0 request to the gateway, handling DPoP auth and
74
+ * nonce retry transparently. A 403 `step_up_required` (deprecated feature,
75
+ * owner ruling 2026-06-10) is no longer polled — it surfaces immediately as
76
+ * a structured tool error via translateHttpError.
77
+ *
78
+ * `signal` (ROUND-3 MAJOR A) is a REAL AbortSignal threaded into the
79
+ * underlying `fetch` option — NOT placed inside `params`/`arguments`. A
80
+ * caller with a per-call timeout budget (e.g. resubscribeMemberships) passes
81
+ * its controller's signal here so a hung backend aborts at the budget instead
82
+ * of hanging forever. Putting the signal in `arguments` (the round-2 bug) both
83
+ * left fetch un-aborted AND serialized a junk `{}` onto the wire body.
84
+ */
85
+ sendRpc(method: string, params?: Record<string, unknown>, signal?: AbortSignal): Promise<ToolCallResult>;
86
+ private executeWithRetries;
87
+ private sendHttpRequest;
88
+ private trackNonce;
89
+ private tryParseErrorBody;
90
+ }
91
+
92
+ export { GatewayClient as G, type KeystoreData as K, type LoadedKeyPair as L, type ProxyConfig as P, type ToolCallResult as T };
@@ -1,4 +1,13 @@
1
+ import {
2
+ executeSend,
3
+ httpStatusForEnvelope,
4
+ parseSendRequest,
5
+ sendFailure
6
+ } from "./chunk-HIZ4NDWN.js";
7
+ import "./chunk-LDZXU3DW.js";
8
+
1
9
  // src/tandem/hook-server.ts
10
+ import crypto from "crypto";
2
11
  import { createServer } from "http";
3
12
  async function startHookServer(opts) {
4
13
  const server = createServer((req, res) => {
@@ -24,6 +33,12 @@ async function handleRequest(req, res, opts) {
24
33
  if (req.method === "GET" && url.pathname === "/health") {
25
34
  return json(res, 200, { ok: true });
26
35
  }
36
+ if (req.method === "GET" && (url.pathname === "/status" || url.pathname === "/poll") && opts.controlToken !== void 0 && !bearerMatches(req.headers.authorization, opts.controlToken)) {
37
+ return json(res, 401, {
38
+ error: "unauthorized",
39
+ detail: "GET /poll and /status are gated by the control token (0.5.4) \u2014 read the file named by the discovery file's controlTokenPath and send it as `Authorization: Bearer <token>`"
40
+ });
41
+ }
27
42
  if (req.method === "GET" && url.pathname === "/status") {
28
43
  return respondWithStatus(res, opts);
29
44
  }
@@ -38,8 +53,84 @@ async function handleRequest(req, res, opts) {
38
53
  }
39
54
  return json(res, 400, { error: "unknown type", detail: "type must be 'stop' or 'user-prompt-submit'" });
40
55
  }
56
+ if (req.method === "POST" && url.pathname === "/send") {
57
+ return handleSend(req, res, opts);
58
+ }
41
59
  return json(res, 404, { error: "not_found", detail: `${req.method} ${url.pathname}` });
42
60
  }
61
+ var MAX_SEND_BODY_BYTES = 256 * 1024;
62
+ async function handleSend(req, res, opts) {
63
+ if (!opts.send) {
64
+ return respondEnvelope(
65
+ res,
66
+ sendFailure(
67
+ "send_unavailable",
68
+ "this daemon started without a send surface (no gateway/control token wired)"
69
+ )
70
+ );
71
+ }
72
+ if (!bearerMatches(req.headers.authorization, opts.send.authToken)) {
73
+ return respondEnvelope(
74
+ res,
75
+ sendFailure(
76
+ "unauthorized",
77
+ "missing or invalid bearer \u2014 read the control token from the file named by the discovery file's controlTokenPath and send it as `Authorization: Bearer <token>`"
78
+ )
79
+ );
80
+ }
81
+ let raw;
82
+ try {
83
+ raw = await readBody(req, MAX_SEND_BODY_BYTES);
84
+ } catch (err) {
85
+ return respondEnvelope(
86
+ res,
87
+ sendFailure("bad_request", err.message)
88
+ );
89
+ }
90
+ let input;
91
+ try {
92
+ input = JSON.parse(raw);
93
+ } catch {
94
+ return respondEnvelope(
95
+ res,
96
+ sendFailure("bad_request", "request body must be valid JSON")
97
+ );
98
+ }
99
+ const parsed = parseSendRequest(input);
100
+ if (!parsed.ok) {
101
+ return respondEnvelope(res, parsed);
102
+ }
103
+ const envelope = await executeSend(opts.send.gateway, parsed.request);
104
+ respondEnvelope(res, envelope);
105
+ }
106
+ function respondEnvelope(res, envelope) {
107
+ json(res, httpStatusForEnvelope(envelope), envelope);
108
+ }
109
+ function bearerMatches(header, expected) {
110
+ if (!header || !header.startsWith("Bearer ")) return false;
111
+ const presented = header.slice("Bearer ".length).trim();
112
+ if (presented.length === 0) return false;
113
+ const a = crypto.createHash("sha256").update(presented).digest();
114
+ const b = crypto.createHash("sha256").update(expected).digest();
115
+ return crypto.timingSafeEqual(a, b);
116
+ }
117
+ function readBody(req, maxBytes) {
118
+ return new Promise((resolve, reject) => {
119
+ const chunks = [];
120
+ let total = 0;
121
+ req.on("data", (chunk) => {
122
+ total += chunk.length;
123
+ if (total > maxBytes) {
124
+ reject(new Error(`request body exceeds ${maxBytes} bytes`));
125
+ req.destroy();
126
+ return;
127
+ }
128
+ chunks.push(chunk);
129
+ });
130
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
131
+ req.on("error", reject);
132
+ });
133
+ }
43
134
  function respondWithEvents(res, opts) {
44
135
  const entries = opts.queue.takeForHook();
45
136
  const events = entries.map((entry) => opts.adapter.formatTandemEvent(entry.event));
package/dist/index.d.ts CHANGED
@@ -1,18 +1,21 @@
1
- interface ProxyConfig {
2
- token: string;
3
- url: string;
4
- keystorePath: string;
5
- /**
6
- * How credentials were resolved at launch: "token" when `--token` was passed
7
- * on the CLI, "paired" when read from ~/.kojee/config.json. The proxy records
8
- * this in its session-discovery file so `kojee-mcp doctor` can render the
9
- * pairing check honestly on a token-mode box (no config.json by design).
10
- * Defaults to "paired" when unset (back-compat with callers predating the
11
- * field).
12
- */
13
- authMode?: "token" | "paired";
14
- }
1
+ import { G as GatewayClient, P as ProxyConfig } from './gateway-client-93P1E0CZ.js';
2
+ import 'jose';
15
3
 
4
+ /**
5
+ * List the tandem_ids where THIS AGENT holds an active seat, via a
6
+ * `tandem_list` tool call. The backend's tandem_list is PRINCIPAL-scoped:
7
+ * rows include rooms where only SIBLING agents of the principal sit
8
+ * (`my_membership: {is_member:false, principal_is_member:true}`). This is
9
+ * the auto ensure-join feed, so object rows are filtered to
10
+ * `my_membership.is_member === true` — FAIL CLOSED: a row missing the flag
11
+ * is excluded, because joining a room the agent was never in is the harm
12
+ * (live-reproduced 2026-06-10: 5 rows listed, only 2 agent seats).
13
+ * Returns the id array, or null when the list could not be determined (tool
14
+ * error or unparseable result) — null is the "unknown" signal callers map to a
15
+ * -1 membership count. MINOR 6: called fresh on every reconnect so the touch
16
+ * set tracks mid-session joins (not boot-frozen).
17
+ */
18
+ declare function listTandemIds(gateway: GatewayClient): Promise<string[] | null>;
16
19
  declare function startProxy(config: ProxyConfig): Promise<void>;
17
20
 
18
- export { type ProxyConfig, startProxy };
21
+ export { ProxyConfig, listTandemIds, startProxy };
package/dist/index.js CHANGED
@@ -1,10 +1,16 @@
1
1
  import {
2
+ listTandemIds,
2
3
  startProxy
3
- } from "./chunk-YEC7IHIG.js";
4
+ } from "./chunk-2BDAM3TH.js";
5
+ import "./chunk-X672ZN7V.js";
4
6
  import "./chunk-BJMASMKX.js";
5
- import "./chunk-C6GZ2L2W.js";
6
- import "./chunk-WBMX4CHB.js";
7
+ import "./chunk-6SK6ITFE.js";
8
+ import "./chunk-3XDJOHMZ.js";
9
+ import "./chunk-UEGQGXPY.js";
10
+ import "./chunk-2MIISF2W.js";
11
+ import "./chunk-LDZXU3DW.js";
7
12
  import "./chunk-BLEGIR35.js";
8
13
  export {
14
+ listTandemIds,
9
15
  startProxy
10
16
  };