obsbot-mcp 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -20
- package/dist/build-info.json +5 -0
- package/dist/device/manager.d.ts +8 -0
- package/dist/device/manager.js +37 -4
- package/dist/device/manager.js.map +1 -1
- package/dist/geometry/aim.d.ts +24 -13
- package/dist/geometry/aim.js +26 -13
- package/dist/geometry/aim.js.map +1 -1
- package/dist/ipc/build-id.d.ts +25 -0
- package/dist/ipc/build-id.js +60 -0
- package/dist/ipc/build-id.js.map +1 -0
- package/dist/ipc/client.d.ts +36 -0
- package/dist/ipc/client.js +106 -4
- package/dist/ipc/client.js.map +1 -1
- package/dist/ipc/coordinator.d.ts +91 -12
- package/dist/ipc/coordinator.js +293 -57
- package/dist/ipc/coordinator.js.map +1 -1
- package/dist/ipc/gate.d.ts +14 -0
- package/dist/ipc/gate.js +45 -0
- package/dist/ipc/gate.js.map +1 -0
- package/dist/ipc/owner.d.ts +27 -1
- package/dist/ipc/owner.js +67 -4
- package/dist/ipc/owner.js.map +1 -1
- package/dist/ipc/protocol.d.ts +30 -0
- package/dist/ipc/protocol.js +40 -0
- package/dist/ipc/protocol.js.map +1 -1
- package/dist/ipc/rendezvous.d.ts +37 -11
- package/dist/ipc/rendezvous.js +143 -30
- package/dist/ipc/rendezvous.js.map +1 -1
- package/dist/mcp/server.js +40 -12
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +6 -0
- package/dist/mcp/tools.js +123 -17
- package/dist/mcp/tools.js.map +1 -1
- package/dist/tail2/api.d.ts +218 -0
- package/dist/tail2/api.js +267 -0
- package/dist/tail2/api.js.map +1 -0
- package/dist/tail2/mdns.d.ts +48 -0
- package/dist/tail2/mdns.js +216 -0
- package/dist/tail2/mdns.js.map +1 -0
- package/dist/tail2/registry.d.ts +100 -0
- package/dist/tail2/registry.js +200 -0
- package/dist/tail2/registry.js.map +1 -0
- package/dist/tail2/snapshot.d.ts +54 -0
- package/dist/tail2/snapshot.js +157 -0
- package/dist/tail2/snapshot.js.map +1 -0
- package/dist/tail2/tools.d.ts +7 -0
- package/dist/tail2/tools.js +370 -0
- package/dist/tail2/tools.js.map +1 -0
- package/dist/transport/helper-process.d.ts +11 -0
- package/dist/transport/helper-process.js +10 -0
- package/dist/transport/helper-process.js.map +1 -1
- package/dist/transport/linux.d.ts +59 -9
- package/dist/transport/linux.js +163 -21
- package/dist/transport/linux.js.map +1 -1
- package/dist/transport/macos.d.ts +8 -0
- package/dist/transport/macos.js +11 -0
- package/dist/transport/macos.js.map +1 -1
- package/dist/transport/transport.d.ts +22 -0
- package/dist/transport/transport.js +20 -0
- package/dist/transport/transport.js.map +1 -1
- package/dist/transport/windows.d.ts +6 -0
- package/dist/transport/windows.js +9 -0
- package/dist/transport/windows.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/native/prebuilt/darwin-arm64/obsbot-helper +0 -0
- package/native/prebuilt/darwin-x64/obsbot-helper +0 -0
- package/native/prebuilt/linux-x64/obsbot-helper +0 -0
- package/native/prebuilt/win32-x64/obsbot-helper.exe +0 -0
- package/package.json +4 -1
package/dist/ipc/client.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
|
-
import {
|
|
2
|
+
import { isBuildId } from "./build-id.js";
|
|
3
|
+
import { encodeFrame, FrameDecoder, NOTICE_ID, isSteppingDown } from "./protocol.js";
|
|
4
|
+
class ReplyTimeout extends Error {
|
|
5
|
+
}
|
|
3
6
|
export class OwnerClient {
|
|
4
7
|
socket;
|
|
5
|
-
nextId = 1;
|
|
8
|
+
nextId = NOTICE_ID + 1;
|
|
6
9
|
pending = new Map();
|
|
7
10
|
dec = new FrameDecoder();
|
|
11
|
+
closeListeners = [];
|
|
8
12
|
closedErr;
|
|
13
|
+
gotNotice = false;
|
|
9
14
|
constructor(socket) {
|
|
10
15
|
this.socket = socket;
|
|
11
16
|
this.socket.on("data", (chunk) => this.onData(chunk));
|
|
@@ -34,19 +39,109 @@ export class OwnerClient {
|
|
|
34
39
|
return reply.result;
|
|
35
40
|
throw new Error(reply.error);
|
|
36
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Exchange identities with the owner.
|
|
44
|
+
*
|
|
45
|
+
* Anything other than a well-formed hello back means the owner cannot take
|
|
46
|
+
* part in a handover: an error reply (a legacy owner rejecting what it takes
|
|
47
|
+
* for a tool call), a reply that is not a hello, or no reply in `timeoutMs`.
|
|
48
|
+
* Throws only if the connection itself closes first.
|
|
49
|
+
*/
|
|
50
|
+
async hello(build, pid, timeoutMs) {
|
|
51
|
+
let reply;
|
|
52
|
+
try {
|
|
53
|
+
reply = await this.send({ ipc: "hello", build, pid }, timeoutMs);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
if (e instanceof ReplyTimeout)
|
|
57
|
+
return { kind: "legacy" };
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
if (!reply.ok)
|
|
61
|
+
return { kind: "legacy" };
|
|
62
|
+
const r = reply.result;
|
|
63
|
+
if (typeof r === "object" &&
|
|
64
|
+
r !== null &&
|
|
65
|
+
r.ipc === "hello" &&
|
|
66
|
+
isBuildId(r.build) &&
|
|
67
|
+
typeof r.pid === "number" &&
|
|
68
|
+
Number.isInteger(r.pid) &&
|
|
69
|
+
r.pid > 0) {
|
|
70
|
+
return { kind: "peer", build: r.build, pid: r.pid };
|
|
71
|
+
}
|
|
72
|
+
return { kind: "legacy" };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Ask the owner for the endpoint. True if it agreed to step down.
|
|
76
|
+
*
|
|
77
|
+
* No answer in `timeoutMs` is a no: an owner that stalls between the hello
|
|
78
|
+
* and the takeover must not leave the asker waiting for ever. Throws only if
|
|
79
|
+
* the connection itself closes first.
|
|
80
|
+
*/
|
|
81
|
+
async takeover(build, pid, timeoutMs) {
|
|
82
|
+
let reply;
|
|
83
|
+
try {
|
|
84
|
+
reply = await this.send({ ipc: "takeover", build, pid }, timeoutMs);
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
if (e instanceof ReplyTimeout)
|
|
88
|
+
return false;
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
if (!reply.ok)
|
|
92
|
+
return false;
|
|
93
|
+
const r = reply.result;
|
|
94
|
+
return typeof r === "object" && r !== null && r.ipc === "takeover" && r.granted === true;
|
|
95
|
+
}
|
|
37
96
|
get closed() {
|
|
38
97
|
return this.closedErr !== undefined;
|
|
39
98
|
}
|
|
99
|
+
/** True once the owner has said it is stepping down for a newer build. */
|
|
100
|
+
get noticed() {
|
|
101
|
+
return this.gotNotice;
|
|
102
|
+
}
|
|
103
|
+
/** Call `fn` once, when the connection closes for any reason. */
|
|
104
|
+
onClose(fn) {
|
|
105
|
+
if (this.closedErr)
|
|
106
|
+
queueMicrotask(fn);
|
|
107
|
+
else
|
|
108
|
+
this.closeListeners.push(fn);
|
|
109
|
+
}
|
|
110
|
+
/** Resolve true when the connection closes, or false if it is still open after `timeoutMs`. */
|
|
111
|
+
waitClosed(timeoutMs) {
|
|
112
|
+
if (this.closedErr)
|
|
113
|
+
return Promise.resolve(true);
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
const timer = setTimeout(() => resolve(false), timeoutMs);
|
|
116
|
+
this.closeListeners.push(() => {
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
resolve(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
40
122
|
close() {
|
|
41
123
|
this.socket.destroy();
|
|
42
124
|
this.failAll(new Error("owner connection closed by client"));
|
|
43
125
|
}
|
|
44
|
-
send(body) {
|
|
126
|
+
send(body, timeoutMs) {
|
|
45
127
|
if (this.closedErr)
|
|
46
128
|
return Promise.reject(this.closedErr);
|
|
47
129
|
const id = this.nextId++;
|
|
48
130
|
return new Promise((resolve, reject) => {
|
|
49
|
-
|
|
131
|
+
let timer;
|
|
132
|
+
const settle = (fn) => (v) => {
|
|
133
|
+
if (timer)
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
fn(v);
|
|
136
|
+
};
|
|
137
|
+
this.pending.set(id, { resolve: settle(resolve), reject: settle(reject) });
|
|
138
|
+
if (timeoutMs !== undefined) {
|
|
139
|
+
timer = setTimeout(() => {
|
|
140
|
+
// Forget the request: a reply that turns up later matches no waiter.
|
|
141
|
+
this.pending.delete(id);
|
|
142
|
+
reject(new ReplyTimeout(`no reply within ${timeoutMs} ms`));
|
|
143
|
+
}, timeoutMs);
|
|
144
|
+
}
|
|
50
145
|
this.socket.write(encodeFrame({ id, body }));
|
|
51
146
|
});
|
|
52
147
|
}
|
|
@@ -61,6 +156,11 @@ export class OwnerClient {
|
|
|
61
156
|
return;
|
|
62
157
|
}
|
|
63
158
|
for (const m of msgs) {
|
|
159
|
+
if (m.id === NOTICE_ID) {
|
|
160
|
+
if (isSteppingDown(m.body))
|
|
161
|
+
this.gotNotice = true;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
64
164
|
const w = this.pending.get(m.id);
|
|
65
165
|
if (w) {
|
|
66
166
|
this.pending.delete(m.id);
|
|
@@ -76,6 +176,8 @@ export class OwnerClient {
|
|
|
76
176
|
for (const w of this.pending.values())
|
|
77
177
|
w.reject(err);
|
|
78
178
|
this.pending.clear();
|
|
179
|
+
for (const fn of this.closeListeners.splice(0))
|
|
180
|
+
fn();
|
|
79
181
|
}
|
|
80
182
|
}
|
|
81
183
|
//# sourceMappingURL=client.js.map
|
package/dist/ipc/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ipc/client.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ipc/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +1,108 @@
|
|
|
1
|
+
import { type Role } from "./rendezvous.js";
|
|
2
|
+
import { type BuildId } from "./build-id.js";
|
|
1
3
|
export type RunLocal = (tool: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
|
|
4
|
+
export interface Timing {
|
|
5
|
+
/** How long a client waits for its hello to be answered. */
|
|
6
|
+
helloTimeoutMs: number;
|
|
7
|
+
/** How long everyone but the successor waits before re-electing after a step-down. */
|
|
8
|
+
stepDownGraceMs: number;
|
|
9
|
+
/** Upper bound of the random delay that spreads simultaneous re-elections. */
|
|
10
|
+
electionJitterMs: number;
|
|
11
|
+
/** Longest a successor waits for the owner's running call and release. */
|
|
12
|
+
stepDownTimeoutMs: number;
|
|
13
|
+
/** Longest a stepping-down owner waits for its own release. Must be under stepDownTimeoutMs. */
|
|
14
|
+
releaseTimeoutMs: number;
|
|
15
|
+
/** How many owners one election will take the endpoint from before settling. */
|
|
16
|
+
maxTakeoverRounds: number;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_TIMING: Timing;
|
|
19
|
+
export interface CoordinatorOptions {
|
|
20
|
+
/** Rendezvous endpoint. Default: the one OBSBOT_IPC_NAME selects. */
|
|
21
|
+
path?: string;
|
|
22
|
+
/** What this process loaded. Default: an unstamped build. */
|
|
23
|
+
build?: BuildId;
|
|
24
|
+
/** Reported to peers in the hello. Default: process.pid. */
|
|
25
|
+
pid?: number;
|
|
26
|
+
/** Drop everything that holds the camera. Runs when this instance steps down. */
|
|
27
|
+
release?: () => Promise<void>;
|
|
28
|
+
/** Receives the `obsbot-mcp: ipc …` lines. Default: discard. */
|
|
29
|
+
log?: (line: string) => void;
|
|
30
|
+
timing?: Partial<Timing>;
|
|
31
|
+
/** The election primitive. Injectable so a test can decide who binds first. */
|
|
32
|
+
elect?: (path: string) => Promise<Role>;
|
|
33
|
+
}
|
|
9
34
|
type RoleName = "none" | "owner" | "client";
|
|
10
35
|
export declare class Coordinator {
|
|
11
36
|
private readonly runLocal;
|
|
12
|
-
private readonly path;
|
|
13
37
|
private role;
|
|
14
38
|
private client?;
|
|
15
39
|
private ownerServer?;
|
|
16
|
-
private
|
|
17
|
-
/**
|
|
18
|
-
|
|
40
|
+
private steppingDown;
|
|
41
|
+
/** Client of an owner that is older than us and could not be made to hand over. */
|
|
42
|
+
private blocked;
|
|
43
|
+
/** Counts the owners this instance has been a client of. Tells one connection from the next. */
|
|
44
|
+
private connection;
|
|
45
|
+
private closing;
|
|
46
|
+
/** A role change in progress — an election, or stepping down. Never rejects. */
|
|
47
|
+
private pending?;
|
|
48
|
+
/** THE single-camera lock: the owner's own calls and the ones forwarded to it. */
|
|
49
|
+
private readonly gate;
|
|
50
|
+
private readonly path;
|
|
51
|
+
private readonly build;
|
|
52
|
+
private readonly pid;
|
|
53
|
+
private readonly release;
|
|
54
|
+
private readonly log;
|
|
55
|
+
private readonly t;
|
|
56
|
+
private readonly elect;
|
|
57
|
+
constructor(runLocal: RunLocal, opts?: CoordinatorOptions);
|
|
19
58
|
/** Establish the initial role eagerly at startup. */
|
|
20
59
|
start(): Promise<void>;
|
|
21
60
|
get roleName(): RoleName;
|
|
22
61
|
dispatch(tool: string, args: Record<string, unknown>): Promise<unknown>;
|
|
23
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Wait until this instance has a role it may use, and say where a call goes:
|
|
64
|
+
* run here, or forward over this connection.
|
|
65
|
+
*
|
|
66
|
+
* The answer is taken in the same tick the decision is made and handed to the
|
|
67
|
+
* caller. Calls arrive in parallel, and one of them may be reconnecting while
|
|
68
|
+
* another resumes: a caller that re-read `this.client` after an await could
|
|
69
|
+
* find it gone, or pointing at an owner nobody has checked yet.
|
|
70
|
+
*/
|
|
71
|
+
private settle;
|
|
24
72
|
close(): Promise<void>;
|
|
25
73
|
private reset;
|
|
74
|
+
private jitter;
|
|
75
|
+
/** Queue a role change behind any already under way. The result never rejects. */
|
|
76
|
+
private begin;
|
|
26
77
|
private ensureRole;
|
|
78
|
+
/**
|
|
79
|
+
* Settle on a role: bind the endpoint, or connect to whoever holds it and
|
|
80
|
+
* compare builds. If ours is newer, ask for the endpoint and go round again.
|
|
81
|
+
*/
|
|
27
82
|
private doElect;
|
|
83
|
+
private becomeOwner;
|
|
84
|
+
private becomeClient;
|
|
85
|
+
/**
|
|
86
|
+
* The owner is older and still there. Try once more: a fresh connection,
|
|
87
|
+
* hello, takeover.
|
|
88
|
+
*
|
|
89
|
+
* Queued like any other role change, so calls that arrive together wait for
|
|
90
|
+
* it instead of finding the role half torn down. `seen` is the connection the
|
|
91
|
+
* caller was looking at: if that is no longer the current one, someone has
|
|
92
|
+
* asked again since, and asking a second time would tell us nothing new.
|
|
93
|
+
*/
|
|
94
|
+
private tryAgain;
|
|
95
|
+
private blockedMessage;
|
|
96
|
+
/**
|
|
97
|
+
* The owner has gone. Re-elect — after the grace period if it stepped down
|
|
98
|
+
* for someone, so the successor binds first; after jitter alone if it simply
|
|
99
|
+
* went, so clients that all lost it at once do not stampede.
|
|
100
|
+
*/
|
|
101
|
+
private ownerLost;
|
|
102
|
+
/** A client asks for the endpoint. Both sides run the same comparison, so this cannot disagree with it. */
|
|
103
|
+
private onTakeover;
|
|
104
|
+
private stepDown;
|
|
105
|
+
/** A release that throws or never settles must not stop the handover. */
|
|
106
|
+
private releaseBounded;
|
|
28
107
|
}
|
|
29
108
|
export {};
|