@mahekara28/context-relay 0.0.0-stage → 0.3.0-beta.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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +128 -2
  3. package/README.python.md +246 -0
  4. package/dist/adapters/capture.d.ts +4 -0
  5. package/dist/adapters/capture.js +286 -0
  6. package/dist/adapters/capture.js.map +1 -0
  7. package/dist/adapters/config.d.ts +11 -0
  8. package/dist/adapters/config.js +139 -0
  9. package/dist/adapters/config.js.map +1 -0
  10. package/dist/adapters/manager.d.ts +57 -0
  11. package/dist/adapters/manager.js +220 -0
  12. package/dist/adapters/manager.js.map +1 -0
  13. package/dist/adapters/normalize.d.ts +9 -0
  14. package/dist/adapters/normalize.js +166 -0
  15. package/dist/adapters/normalize.js.map +1 -0
  16. package/dist/adapters/rpc.d.ts +12 -0
  17. package/dist/adapters/rpc.js +100 -0
  18. package/dist/adapters/rpc.js.map +1 -0
  19. package/dist/adapters/types.d.ts +59 -0
  20. package/dist/adapters/types.js +51 -0
  21. package/dist/adapters/types.js.map +1 -0
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.js +427 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/client.d.ts +11 -0
  26. package/dist/client.js +136 -0
  27. package/dist/client.js.map +1 -0
  28. package/dist/delivery.d.ts +9 -0
  29. package/dist/delivery.js +35 -0
  30. package/dist/delivery.js.map +1 -0
  31. package/dist/index.d.ts +5 -0
  32. package/dist/index.js +5 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/mcp.d.ts +3 -0
  35. package/dist/mcp.js +109 -0
  36. package/dist/mcp.js.map +1 -0
  37. package/dist/model.d.ts +169 -0
  38. package/dist/model.js +79 -0
  39. package/dist/model.js.map +1 -0
  40. package/dist/proposals.d.ts +65 -0
  41. package/dist/proposals.js +134 -0
  42. package/dist/proposals.js.map +1 -0
  43. package/dist/server.d.ts +21 -0
  44. package/dist/server.js +375 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/store.d.ts +33 -0
  47. package/dist/store.js +393 -0
  48. package/dist/store.js.map +1 -0
  49. package/dist/ui/app.js +845 -0
  50. package/dist/ui/assets/THIRD_PARTY_LICENSE.txt +25 -0
  51. package/dist/ui/assets/claude.svg +1 -0
  52. package/dist/ui/assets/codex.svg +1 -0
  53. package/dist/ui/assets/goose.svg +1 -0
  54. package/dist/ui/assets/opencode.svg +1 -0
  55. package/dist/ui/assets/relay.svg +1 -0
  56. package/dist/ui/index.html +23 -0
  57. package/dist/ui/style.css +989 -0
  58. package/dist/util.d.ts +16 -0
  59. package/dist/util.js +86 -0
  60. package/dist/util.js.map +1 -0
  61. package/docs/HARNESS_CONNECTIONS.md +53 -0
  62. package/docs/NPM_QUICKSTART.md +150 -0
  63. package/docs/WORKSPACE.md +61 -0
  64. package/docs/releases/NPM_PUBLISHING.md +60 -0
  65. package/package.json +78 -4
@@ -0,0 +1,286 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync, } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { basename, join, relative, resolve, sep } from "node:path";
6
+ import { RelayError } from "../model.js";
7
+ import { JsonLineRpc } from "./rpc.js";
8
+ import { array, object, string, claudeEvents, codexEvents, openCodeEvents, gooseEvents, } from "./normalize.js";
9
+ const execute = promisify(execFile);
10
+ function sameRoot(value, root) {
11
+ try {
12
+ return typeof value === "string" && realpathSync(value) === root;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ function lines(path) {
19
+ if (lstatSync(path).isSymbolicLink() ||
20
+ statSync(path).size > 16 * 1024 * 1024)
21
+ throw new RelayError("source_limit", "Transcript must be a regular file at most 16 MiB.");
22
+ const text = readFileSync(path, "utf8");
23
+ const chunks = text.split("\n");
24
+ // A writer may have left an incomplete final line; never import it early.
25
+ if (chunks.at(-1) !== "")
26
+ chunks.pop();
27
+ return chunks.filter(Boolean).map((line) => {
28
+ try {
29
+ return JSON.parse(line);
30
+ }
31
+ catch {
32
+ throw new RelayError("malformed_transcript", "Transcript contains an invalid complete JSONL record.");
33
+ }
34
+ });
35
+ }
36
+ function sourceFiles(directory) {
37
+ if (!existsSync(directory))
38
+ return [];
39
+ if (lstatSync(directory).isSymbolicLink())
40
+ throw new RelayError("unsafe_source", "Source root cannot be a symlink.");
41
+ const paths = [];
42
+ let visited = 0;
43
+ const walk = (path, depth) => {
44
+ if (depth > 2)
45
+ return;
46
+ for (const entry of readdirSync(path, { withFileTypes: true })) {
47
+ if (++visited > 10000)
48
+ throw new RelayError("source_limit", "Source directory is too large. Choose a narrower source root.");
49
+ const child = join(path, entry.name);
50
+ if (entry.isSymbolicLink())
51
+ continue;
52
+ if (entry.isDirectory())
53
+ walk(child, depth + 1);
54
+ else if (entry.isFile() && entry.name.endsWith(".jsonl"))
55
+ paths.push(child);
56
+ }
57
+ };
58
+ walk(directory, 0);
59
+ return paths;
60
+ }
61
+ async function codex(connection, project, operation) {
62
+ const rpc = new JsonLineRpc(connection.executable ?? "codex", ["app-server", "--listen", "stdio://"], project.root);
63
+ try {
64
+ await rpc.request("initialize", {
65
+ clientInfo: {
66
+ name: "context_relay",
67
+ title: "Context Relay capture",
68
+ version: "0.2.0-alpha.1",
69
+ },
70
+ capabilities: {},
71
+ });
72
+ rpc.notify("initialized");
73
+ return await operation(rpc);
74
+ }
75
+ finally {
76
+ rpc.close();
77
+ }
78
+ }
79
+ function localEndpoint(source) {
80
+ const url = new URL(source ?? "http://127.0.0.1:4096");
81
+ if (url.protocol !== "http:" ||
82
+ !["127.0.0.1", "[::1]", "localhost"].includes(url.hostname) ||
83
+ url.username ||
84
+ url.password ||
85
+ url.pathname !== "/" ||
86
+ url.search ||
87
+ url.hash)
88
+ throw new RelayError("invalid_endpoint", "OpenCode source must be a loopback HTTP origin without credentials.");
89
+ return url;
90
+ }
91
+ async function openCodeGet(connection, project, path) {
92
+ const base = localEndpoint(connection.source);
93
+ const url = new URL(path, base);
94
+ url.searchParams.set("directory", project.root);
95
+ const password = process.env.OPENCODE_SERVER_PASSWORD;
96
+ const username = process.env.OPENCODE_SERVER_USERNAME ?? "opencode";
97
+ const response = await fetch(url, {
98
+ headers: password
99
+ ? {
100
+ Authorization: "Basic " +
101
+ Buffer.from(`${username}:${password}`).toString("base64"),
102
+ }
103
+ : {},
104
+ signal: AbortSignal.timeout(10000),
105
+ redirect: "error",
106
+ });
107
+ if (!response.ok)
108
+ throw new RelayError("harness_http", `OpenCode returned HTTP ${response.status}. Check the endpoint and service credentials.`);
109
+ const reader = response.body?.getReader();
110
+ if (!reader)
111
+ throw new RelayError("harness_protocol", "OpenCode returned no response body.");
112
+ const chunks = [];
113
+ let bytes = 0;
114
+ while (true) {
115
+ const chunk = await reader.read();
116
+ if (chunk.done)
117
+ break;
118
+ bytes += chunk.value.byteLength;
119
+ if (bytes > 16 * 1024 * 1024) {
120
+ await reader.cancel();
121
+ throw new RelayError("harness_response_too_large", "OpenCode response exceeds 16 MiB.");
122
+ }
123
+ chunks.push(chunk.value);
124
+ }
125
+ try {
126
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
127
+ }
128
+ catch {
129
+ throw new RelayError("harness_protocol", "OpenCode returned invalid JSON.");
130
+ }
131
+ }
132
+ async function goose(connection, project, args) {
133
+ try {
134
+ const { stdout } = await execute(connection.executable ?? "goose", args, {
135
+ cwd: project.root,
136
+ timeout: 15000,
137
+ maxBuffer: 16 * 1024 * 1024,
138
+ windowsHide: true,
139
+ });
140
+ return JSON.parse(stdout);
141
+ }
142
+ catch {
143
+ throw new RelayError("harness_unavailable", "Goose capture failed. Check the executable path and JSON export support.");
144
+ }
145
+ }
146
+ export async function discover(connection, project) {
147
+ if (!connection.capture)
148
+ return [];
149
+ const make = (externalId, title, locator = externalId) => ({
150
+ externalId,
151
+ title: title.slice(0, 300) || "Untitled session",
152
+ locator,
153
+ harness: connection.harness,
154
+ projectId: project.id,
155
+ });
156
+ if (connection.harness === "claude") {
157
+ const directory = resolve(connection.source ?? join(homedir(), ".claude", "projects"));
158
+ const found = [];
159
+ for (const path of sourceFiles(directory)) {
160
+ const records = lines(path);
161
+ const metadata = records
162
+ .map(object)
163
+ .find((r) => sameRoot(r.cwd, project.root));
164
+ if (!metadata)
165
+ continue;
166
+ const nativeId = string(metadata.sessionId);
167
+ const sessionId = nativeId && basename(path) === nativeId + ".jsonl"
168
+ ? nativeId
169
+ : relative(directory, path).split(sep).join("/");
170
+ const firstUser = claudeEvents(records).find((event) => event.role === "user");
171
+ found.push(make(sessionId, firstUser?.text.slice(0, 120) ?? "Claude Code session", path));
172
+ }
173
+ return found;
174
+ }
175
+ if (connection.harness === "codex")
176
+ return codex(connection, project, async (rpc) => {
177
+ const found = [];
178
+ let cursor = null;
179
+ for (let page = 0; page < 20; page++) {
180
+ const result = await rpc.request("thread/list", {
181
+ cwd: project.root,
182
+ limit: 100,
183
+ cursor,
184
+ });
185
+ for (const raw of result.data) {
186
+ const thread = object(raw);
187
+ if (!sameRoot(thread.cwd, project.root))
188
+ continue;
189
+ if (string(thread.id))
190
+ found.push(make(string(thread.id), string(thread.name) || string(thread.preview)));
191
+ }
192
+ cursor = result.nextCursor ?? null;
193
+ if (!cursor)
194
+ return found;
195
+ }
196
+ throw new RelayError("source_limit", "More than 2,000 threads match. Narrow the source project.");
197
+ });
198
+ if (connection.harness === "opencode") {
199
+ const payload = await openCodeGet(connection, project, "/session");
200
+ if (!Array.isArray(payload))
201
+ throw new RelayError("unsupported_format", "OpenCode session API response changed.");
202
+ return payload
203
+ .map(object)
204
+ .filter((s) => sameRoot(s.directory, project.root) && string(s.id))
205
+ .map((s) => make(string(s.id), string(s.title)));
206
+ }
207
+ const payload = await goose(connection, project, [
208
+ "session",
209
+ "list",
210
+ "--format",
211
+ "json",
212
+ "--working_dir",
213
+ project.root,
214
+ "--limit",
215
+ "200",
216
+ ]);
217
+ const sessions = Array.isArray(payload)
218
+ ? payload
219
+ : array(object(payload).sessions);
220
+ return sessions
221
+ .map(object)
222
+ .filter((s) => sameRoot(s.working_dir ?? s.workingDir, project.root) && string(s.id))
223
+ .map((s) => make(string(s.id), string(s.name) || string(s.description)));
224
+ }
225
+ export async function capture(connection, project, session) {
226
+ let events;
227
+ if (connection.harness === "claude") {
228
+ const records = lines(session.locator);
229
+ if (!records.map(object).some((r) => sameRoot(r.cwd, project.root)))
230
+ throw new RelayError("project_mismatch", "Transcript no longer matches the selected project.");
231
+ events = claudeEvents(records);
232
+ }
233
+ else if (connection.harness === "codex")
234
+ events = await codex(connection, project, async (rpc) => {
235
+ const result = await rpc.request("thread/read", { threadId: session.externalId });
236
+ if (!sameRoot(result.thread.cwd, project.root))
237
+ throw new RelayError("project_mismatch", "Codex thread belongs to another project.");
238
+ const turns = [];
239
+ let cursor = null;
240
+ for (let page = 0; page < 100; page++) {
241
+ const part = await rpc.request("thread/turns/list", {
242
+ threadId: session.externalId,
243
+ limit: 100,
244
+ cursor,
245
+ sortDirection: "asc",
246
+ itemsView: "full",
247
+ });
248
+ turns.push(...part.data);
249
+ cursor = part.nextCursor ?? null;
250
+ if (!cursor)
251
+ return codexEvents(turns);
252
+ }
253
+ throw new RelayError("source_limit", "Thread exceeds 10,000 turns. Capture a smaller source export.");
254
+ });
255
+ else if (connection.harness === "opencode") {
256
+ const info = object(await openCodeGet(connection, project, "/session/" + encodeURIComponent(session.externalId)));
257
+ if (!sameRoot(info.directory, project.root))
258
+ throw new RelayError("project_mismatch", "OpenCode session belongs to another project.");
259
+ const messages = await openCodeGet(connection, project, "/session/" + encodeURIComponent(session.externalId) + "/message");
260
+ if (!Array.isArray(messages))
261
+ throw new RelayError("unsupported_format", "OpenCode messages API response changed.");
262
+ events = openCodeEvents(messages);
263
+ }
264
+ else {
265
+ const exported = await goose(connection, project, [
266
+ "session",
267
+ "export",
268
+ "--session-id",
269
+ session.externalId,
270
+ "--format",
271
+ "json",
272
+ ]);
273
+ const metadata = object(exported);
274
+ if (!sameRoot(metadata.working_dir ?? metadata.workingDir, project.root))
275
+ throw new RelayError("project_mismatch", "Goose export belongs to another project or has no working directory.");
276
+ events = gooseEvents(exported);
277
+ }
278
+ return {
279
+ projectId: project.id,
280
+ harness: connection.harness,
281
+ externalId: session.externalId,
282
+ title: session.title,
283
+ events,
284
+ };
285
+ }
286
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../packages/relay/src/adapters/capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type Project } from "../model.js";
2
+ import { type HarnessConnection } from "./types.js";
3
+ export interface ConfigReceipt {
4
+ path: string;
5
+ format: "json" | "toml";
6
+ section: string;
7
+ value: unknown;
8
+ }
9
+ export declare function mcpCommand(connection: HarnessConnection, directory: string): string[];
10
+ export declare function configureMcp(connection: HarnessConnection, project: Project, directory: string): ConfigReceipt | null;
11
+ export declare function removeMcp(receipt: ConfigReceipt): void;
@@ -0,0 +1,139 @@
1
+ import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { RelayError } from "../model.js";
5
+ import { canonical, digest, id } from "../util.js";
6
+ const begin = "# BEGIN context-relay npm";
7
+ const end = "# END context-relay npm";
8
+ function read(path) {
9
+ if (existsSync(dirname(path)) && lstatSync(dirname(path)).isSymbolicLink())
10
+ throw new RelayError("unsafe_config", "Configuration directory cannot be a symlink.");
11
+ if (!existsSync(path))
12
+ return null;
13
+ if (lstatSync(path).isSymbolicLink())
14
+ throw new RelayError("unsafe_config", "Configuration paths cannot be symlinks.");
15
+ return readFileSync(path, "utf8");
16
+ }
17
+ function replace(path, previous, next) {
18
+ mkdirSync(dirname(path), { recursive: true });
19
+ if (read(path) !== previous)
20
+ throw new RelayError("config_changed", "Harness configuration changed during review. Retry after inspection.", 409);
21
+ const temporary = path + ".relay-" + id();
22
+ try {
23
+ writeFileSync(temporary, next, { mode: 0o600, flag: "wx" });
24
+ if (read(path) !== previous)
25
+ throw new RelayError("config_changed", "Harness configuration changed during write.", 409);
26
+ renameSync(temporary, path);
27
+ }
28
+ finally {
29
+ if (existsSync(temporary))
30
+ unlinkSync(temporary);
31
+ }
32
+ }
33
+ export function mcpCommand(connection, directory) {
34
+ return [
35
+ process.execPath,
36
+ fileURLToPath(new URL("../cli.js", import.meta.url)),
37
+ "mcp",
38
+ "--data-dir",
39
+ directory,
40
+ "--project",
41
+ connection.projectId,
42
+ "--harness",
43
+ connection.harness,
44
+ ];
45
+ }
46
+ function jsonDocument(text) {
47
+ try {
48
+ const value = text === null ? {} : JSON.parse(text);
49
+ if (!value || typeof value !== "object" || Array.isArray(value))
50
+ throw new Error();
51
+ return value;
52
+ }
53
+ catch {
54
+ throw new RelayError("invalid_config", "Existing harness configuration must be a JSON object.");
55
+ }
56
+ }
57
+ export function configureMcp(connection, project, directory) {
58
+ if (!connection.configureMcp)
59
+ return null;
60
+ const command = mcpCommand(connection, directory);
61
+ if (connection.harness === "codex") {
62
+ const path = join(project.root, ".codex", "config.toml");
63
+ const previous = read(path);
64
+ const text = previous ?? "";
65
+ const block = `${begin}\n[mcp_servers.context_relay]\ncommand = ${JSON.stringify(command[0])}\nargs = ${JSON.stringify(command.slice(1))}\n${end}`;
66
+ const start = text.indexOf(begin);
67
+ const finish = text.indexOf(end);
68
+ if (start >= 0 || finish >= 0) {
69
+ if (start < 0 ||
70
+ finish < start ||
71
+ text.slice(start, finish + end.length) !== block)
72
+ throw new RelayError("config_conflict", "An existing Relay MCP block differs. Inspect it before reconnecting.", 409);
73
+ }
74
+ else {
75
+ if (/\[mcp_servers\.(?:context_relay|"context_relay"|'context_relay')\]/.test(text))
76
+ throw new RelayError("config_conflict", "A context_relay MCP entry already exists outside the managed block.", 409);
77
+ replace(path, previous, text + (text.endsWith("\n") || !text ? "" : "\n") + "\n" + block + "\n");
78
+ }
79
+ return { path, format: "toml", section: "context_relay", value: block };
80
+ }
81
+ if (connection.harness === "opencode" &&
82
+ existsSync(join(project.root, "opencode.jsonc")))
83
+ throw new RelayError("config_conflict", "This project uses opencode.jsonc. Use capture-only and add the MCP command manually to preserve its comments and settings.", 409);
84
+ const goose = connection.harness === "goose";
85
+ const path = join(project.root, goose
86
+ ? ".relay/goose-mcp.json"
87
+ : connection.harness === "claude"
88
+ ? ".mcp.json"
89
+ : "opencode.json");
90
+ const section = connection.harness === "opencode" ? "mcp" : "mcpServers";
91
+ const previous = read(path);
92
+ const document = jsonDocument(previous);
93
+ const entry = connection.harness === "opencode"
94
+ ? { type: "local", command, enabled: true }
95
+ : { type: "stdio", command: command[0], args: command.slice(1) };
96
+ const existing = document[section] ?? {};
97
+ if (!existing || typeof existing !== "object" || Array.isArray(existing))
98
+ throw new RelayError("invalid_config", "MCP configuration section must be an object.");
99
+ const servers = existing;
100
+ if (servers.context_relay !== undefined &&
101
+ digest(servers.context_relay) !== digest(entry))
102
+ throw new RelayError("config_conflict", "An existing context_relay entry differs. Inspect it before reconnecting.", 409);
103
+ servers.context_relay = entry;
104
+ document[section] = servers;
105
+ replace(path, previous, JSON.stringify(document, null, 2) + "\n");
106
+ return { path, format: "json", section, value: entry };
107
+ }
108
+ export function removeMcp(receipt) {
109
+ const previous = read(receipt.path);
110
+ if (previous === null)
111
+ return;
112
+ if (receipt.format === "toml") {
113
+ const start = previous.indexOf(begin);
114
+ const finish = previous.indexOf(end);
115
+ if (start < 0 && finish < 0)
116
+ return;
117
+ if (start < 0 ||
118
+ finish < start ||
119
+ previous.slice(start, finish + end.length) !== receipt.value)
120
+ throw new RelayError("config_changed", "Managed MCP block was edited; inspect it before removal.", 409);
121
+ replace(receipt.path, previous, previous.slice(0, start) +
122
+ previous.slice(finish + end.length).replace(/^\r?\n/, ""));
123
+ return;
124
+ }
125
+ const document = jsonDocument(previous);
126
+ const section = document[receipt.section];
127
+ if (!section || typeof section !== "object" || Array.isArray(section))
128
+ throw new RelayError("config_changed", "MCP section changed.");
129
+ const servers = section;
130
+ if (servers.context_relay === undefined)
131
+ return;
132
+ if (canonical(servers.context_relay) !== canonical(receipt.value))
133
+ throw new RelayError("config_changed", "Managed MCP entry was edited; inspect it before removal.", 409);
134
+ delete servers.context_relay;
135
+ if (Object.keys(servers).length === 0)
136
+ delete document[receipt.section];
137
+ replace(receipt.path, previous, JSON.stringify(document, null, 2) + "\n");
138
+ }
139
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../packages/relay/src/adapters/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { RelayStore } from "../store.js";
2
+ import { type HarnessConnection, type DiscoveredSession } from "./types.js";
3
+ import { type ConfigReceipt } from "./config.js";
4
+ interface SavedConnection extends HarnessConnection {
5
+ receipt: ConfigReceipt | null;
6
+ lastSync: string | null;
7
+ lastError: string | null;
8
+ }
9
+ export interface CaptureJob {
10
+ id: string;
11
+ connectionId: string;
12
+ state: "running" | "completed" | "failed" | "cancelled" | "interrupted";
13
+ createdAt: string;
14
+ completed: number;
15
+ total: number;
16
+ imported: {
17
+ sessionId: string;
18
+ added: number;
19
+ }[];
20
+ errors: {
21
+ externalId: string;
22
+ message: string;
23
+ }[];
24
+ error: string | null;
25
+ }
26
+ export declare class AdapterManager {
27
+ readonly store: RelayStore;
28
+ private busy;
29
+ private running;
30
+ constructor(store: RelayStore);
31
+ jobs(): CaptureJob[];
32
+ job(jobId: string): CaptureJob;
33
+ private saveJob;
34
+ cancel(jobId: string): CaptureJob;
35
+ close(): Promise<void>;
36
+ startSync(connectionId: string, externalIds?: string[]): CaptureJob;
37
+ connections(projectId?: string): SavedConnection[];
38
+ connection(connectionId: string): SavedConnection;
39
+ connect(input: unknown): SavedConnection;
40
+ disconnect(connectionId: string): {
41
+ disconnected: true;
42
+ };
43
+ discover(connectionId: string): Promise<DiscoveredSession[]>;
44
+ sync(connectionId: string, externalIds?: string[], job?: CaptureJob, cancelled?: () => boolean): Promise<{
45
+ imported: {
46
+ sessionId: string;
47
+ added: number;
48
+ }[];
49
+ errors: {
50
+ externalId: string;
51
+ message: string;
52
+ }[];
53
+ }>;
54
+ command(connectionId: string): string[];
55
+ private save;
56
+ }
57
+ export {};