machine-bridge-mcp 1.2.2 → 1.2.5
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/CHANGELOG.md +28 -1
- package/README.md +2 -0
- package/SECURITY.md +1 -1
- package/browser-extension/manifest.json +2 -2
- package/docs/AGENT_CONTEXT.md +1 -1
- package/docs/ARCHITECTURE.md +13 -12
- package/docs/AUDIT.md +12 -0
- package/docs/ENGINEERING.md +1 -1
- package/docs/LOGGING.md +6 -6
- package/docs/OPERATIONS.md +6 -3
- package/docs/TESTING.md +3 -3
- package/docs/UPGRADING.md +3 -3
- package/package.json +1 -1
- package/src/local/capability-ranking.mjs +3 -2
- package/src/local/relay-connection.mjs +83 -17
- package/src/local/runtime.mjs +31 -11
- package/src/worker/daemon-liveness.ts +63 -0
- package/src/worker/daemon-sockets.ts +107 -0
- package/src/worker/index.ts +153 -97
- package/src/worker/observability.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.5 - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### End-to-end relay readiness and safe daemon handover
|
|
6
|
+
|
|
7
|
+
- Separate authenticated WebSocket transport from verified service readiness. A daemon now becomes externally usable only after the Worker sends a random readiness probe and receives its result through the same local message dispatch, relay-session binding, and `tool_result` delivery path used by real calls. `hello_ack` and heartbeats alone can no longer produce `daemon.connected=true` when result delivery is broken. The local runtime also rejects pre-ready tool calls and a premature `ready_ack` that was not preceded by a successfully delivered probe result.
|
|
8
|
+
- Keep the incumbent verified daemon active while a replacement is authenticated and probed. A failed, malformed, silent, or incompatible candidate is closed without displacing the working connection; only a successful `ready_ack` handover replaces the incumbent. Candidate hello, readiness, and steady-state liveness have independent bounded deadlines enforced by Durable Object alarms.
|
|
9
|
+
- Extract daemon attachment/state transitions into `DaemonSocketRegistry`, expose authenticated/probing/ready counts and readiness timestamps through `server_info`, and add fault-injection coverage for missing acknowledgements, invalid probe results, replacement races, reconnect backoff, session-generation propagation, and full OAuth/MCP/WebSocket routing.
|
|
10
|
+
- Correct capability ranking after the local research-skill rename: generic identity tokens such as `web`, `cli`, and `tool` no longer dominate selection, while concrete Chinese research/search intent maps to `research`, `search`, and `find`. This prevents a browser-form task from selecting a web-research skill without weakening explicit research requests.
|
|
11
|
+
- Remove a duplicate Worker route guard, require awaited alarm rescheduling after inbound activity, retain zero production dependency vulnerabilities, and refresh architecture, operations, logging, testing, upgrade, and audit documentation. State schema 6 and policy revision 5 remain unchanged.
|
|
12
|
+
|
|
13
|
+
## 1.2.4 - 2026-07-17
|
|
14
|
+
|
|
15
|
+
### Relay tool_result session context regression
|
|
16
|
+
|
|
17
|
+
- Pass the authenticated relay session generation into every inbound WebSocket `onMessage` callback. The 1.2.2 session-binding change discarded every `tool_result` with `session_ended` because handlers received `sessionId=0` even while heartbeats kept the socket live, so MCP tools timed out despite `daemon.connected=true`.
|
|
18
|
+
- Emit an explicit error when a tool result is discarded because the inbound call context lacked a session id, and include both expected and active session ids in the structured event.
|
|
19
|
+
- Add a regression that proves message dispatch attaches the current authenticated session generation.
|
|
20
|
+
|
|
21
|
+
## 1.2.3 - 2026-07-17
|
|
22
|
+
|
|
23
|
+
### Worker daemon false-online liveness
|
|
24
|
+
|
|
25
|
+
- Treat authenticated daemon sockets as live only when inbound traffic is recent. `role=daemon` plus `readyState=OPEN` is no longer enough after Durable Object hibernation or a half-closed transport, which previously left `daemon.connected=true` while every `tool_call` timed out.
|
|
26
|
+
- Persist `lastSeenAt` on daemon attachments, refresh it on `hello`, heartbeats, and `tool_result`, and reclaim silent sockets through the Durable Object alarm as well as on tool send failure or prolonged silence during a timed-out call.
|
|
27
|
+
- Report `daemon.last_seen_at`, `daemon.liveness_timeout_ms`, and `worker.sockets_live` from `server_info` so control-plane counters that reset on DO wake are not mistaken for live authenticated sockets.
|
|
28
|
+
- Add pure liveness helpers and regression coverage for fresh, silent, candidate, and legacy attachments without `lastSeenAt`.
|
|
29
|
+
|
|
3
30
|
## 1.2.2 - 2026-07-17
|
|
4
31
|
|
|
5
32
|
### Relay result lifecycle and human-readable diagnostics
|
|
@@ -318,7 +345,7 @@
|
|
|
318
345
|
|
|
319
346
|
- Register bounded `package.*` commands from safe root `package.json` script names, while preserving explicit manifest override/deletion and never injecting script bodies. Windows uses a fixed `cmd.exe` wrapper for package-manager shims; Unix keeps direct executable argv. Extend default skill discovery to project `.codex/skills` and unrestricted `CODEX_HOME/skills` compatibility roots.
|
|
320
347
|
- Match installed applications by their actual names for every canonical-full task instead of requiring generic “app/window” words, with a bounded discovery cache to avoid repeated filesystem scans.
|
|
321
|
-
- Normalize a bounded set of common English inflections and Chinese workflow intents before skill/command ranking, and weight capability-name matches above incidental description overlap. This fixes Chinese selection of `skill-creator`, `
|
|
348
|
+
- Normalize a bounded set of common English inflections and Chinese workflow intents before skill/command ranking, and weight capability-name matches above incidental description overlap. This fixes Chinese selection of `skill-creator`, `web-research-cli`, and `skill-installer` and prevents generic “create” wording from preferring unrelated design skills.
|
|
322
349
|
- Record privacy-preserving bootstrap and task-resolution telemetry in `server_info` and `project_overview`: counts, timestamps, source/load flags, selected capability metadata, and a runtime-keyed task fingerprint rather than raw task text. Suppress weak skill-overlap recommendations and clarify that the MCP host still controls whether the resolver and recommended tools are invoked.
|
|
323
350
|
|
|
324
351
|
### Process and network lifecycle
|
package/README.md
CHANGED
|
@@ -49,6 +49,8 @@ Local clients such as Claude Desktop, Cursor, and Codex CLI
|
|
|
49
49
|
|
|
50
50
|
The remote Worker authenticates and relays calls. It cannot directly read local files or start local processes. File, Git, image, patch, process, diagnostic, and managed-job operations execute in the local runtime.
|
|
51
51
|
|
|
52
|
+
Remote readiness is end-to-end: a daemon is advertised only after a Worker probe returns through the same local dispatch and session-bound result path used by real tools. A replacement is verified before it displaces the current healthy daemon.
|
|
53
|
+
|
|
52
54
|
New users should follow the end-to-end [installation and first-use guide](docs/GETTING_STARTED.md). Before sharing a deployment or connecting several accounts, read [multi-client, multi-account, and tenancy architecture](docs/MULTI_ACCOUNT.md).
|
|
53
55
|
|
|
54
56
|
## Default behavior and policy profiles
|
package/SECURITY.md
CHANGED
|
@@ -172,7 +172,7 @@ Public health and metadata do not expose live workspace or daemon status. The da
|
|
|
172
172
|
|
|
173
173
|
## Relay and denial of service
|
|
174
174
|
|
|
175
|
-
Only one authenticated daemon is active. Candidates have a handshake deadline and cannot displace the current daemon before success. Pending calls are socket-bound, client-request-bound, concurrency-limited, size-limited, and timed out. Duplicate in-flight request IDs are rejected only within the same authenticated MCP session. Initialization returns a stateless HMAC-bound `MCP-Session-Id`; the signature binds the session nonce to the OAuth token identity, so one account can use multiple concurrent chat windows without sharing a cancellation or request-id namespace. Independent sessionless POST requests are not indexed by token and request id. A session id is an integrity/correlation token, not a second authorization credential.
|
|
175
|
+
Only one authenticated daemon is active. Candidates have a handshake deadline and cannot displace the current daemon before success. Authenticated sockets also carry a liveness deadline based on inbound traffic so half-open transports cannot remain the active daemon indefinitely. Pending calls are socket-bound, client-request-bound, concurrency-limited, size-limited, and timed out. Duplicate in-flight request IDs are rejected only within the same authenticated MCP session. Initialization returns a stateless HMAC-bound `MCP-Session-Id`; the signature binds the session nonce to the OAuth token identity, so one account can use multiple concurrent chat windows without sharing a cancellation or request-id namespace. Independent sessionless POST requests are not indexed by token and request id. A session id is an integrity/correlation token, not a second authorization credential.
|
|
176
176
|
|
|
177
177
|
Request bodies, WebSocket messages, tool outputs, traversals, sessions, stdin writes, OAuth records, clients, codes, access tokens, refresh tokens, and failure identities are bounded. Disconnect/replacement terminates active child process trees.
|
|
178
178
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Machine Bridge Browser",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.5",
|
|
5
5
|
"description": "Connects the current Chromium browser profile to the local Machine Bridge runtime for user-authorized automation.",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"tabs",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"action": {
|
|
31
31
|
"default_title": "Machine Bridge Browser"
|
|
32
32
|
},
|
|
33
|
-
"version_name": "1.2.
|
|
33
|
+
"version_name": "1.2.5"
|
|
34
34
|
}
|
package/docs/AGENT_CONTEXT.md
CHANGED
|
@@ -196,7 +196,7 @@ No persistent skill or project-context index is trusted as authoritative. `sessi
|
|
|
196
196
|
|
|
197
197
|
`agent_context` returns bounded skill metadata. `load_local_skill` returns full instructions only for one selected bundle. `resolve_task_capabilities` tokenizes the current task, ranks skill names/descriptions and command names/descriptions/argv, returns matches with scores, and loads the leading skill only when its relevance threshold is met. Under canonical `full`, it also compares the task with installed application names on every call; application discovery is cached briefly and refreshed after a bounded interval.
|
|
198
198
|
|
|
199
|
-
Matching remains deterministic and local. Hyphens, underscores, dots, and whitespace are normalized; common English inflections are reduced to a small canonical form; and a bounded Chinese/English workflow vocabulary covers creation, improvement, installation, search, current/official documentation, verification, testing, frontend/design, browser/web, email, performance, and security intents. Capability-name token matches receive more weight than incidental words in a long description. This lets Chinese tasks select English-metadata skills such as `skill-creator`, `
|
|
199
|
+
Matching remains deterministic and local. Hyphens, underscores, dots, and whitespace are normalized; common English inflections are reduced to a small canonical form; and a bounded Chinese/English workflow vocabulary covers creation, improvement, installation, search, current/official documentation, verification, testing, frontend/design, browser/web, email, performance, and security intents. Capability-name token matches receive more weight than incidental words in a long description. This lets Chinese tasks select English-metadata skills such as `skill-creator`, `web-research-cli`, and `skill-installer`, while avoiding the prior tie where generic “create” wording could select `frontend-design`. An explicitly named skill or registered command still receives the strongest deterministic boost.
|
|
200
200
|
|
|
201
201
|
This ranking is deterministic local assistance, not semantic certainty. Weak positive matches remain visible for diagnosis, but only a skill meeting the selection threshold is recommended for loading. The model must still evaluate whether the selected skill applies. Machine Bridge does not execute skill scripts implicitly and does not fabricate a dynamically named MCP tool per skill.
|
|
202
202
|
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -34,7 +34,7 @@ A canonical workspace receives an independent profile, Worker name, secret set,
|
|
|
34
34
|
- `runtime-capabilities.mjs` composes agent, application, and browser capability results;
|
|
35
35
|
- managed jobs, local resources, application automation, and browser automation remain separate managers.
|
|
36
36
|
|
|
37
|
-
Architecture tests cap the orchestration module and each extracted service independently and reject a return of low-level process, patch, diagnostic, or capability-scoring logic to `LocalRuntime`. `RelayConnection` owns remote WebSocket transport,
|
|
37
|
+
Architecture tests cap the orchestration module and each extracted service independently and reject a return of low-level process, patch, diagnostic, or capability-scoring logic to `LocalRuntime`. `RelayConnection` owns remote WebSocket transport, `hello_ack` authentication, end-to-end `relay_probe`/`ready_ack` readiness, heartbeat liveness, reconnect backoff, outage logging, and a monotonically increasing in-memory session generation. Every relayed tool result is bound to the generation that delivered its call; a disconnected generation cannot send a late result over its replacement socket. Inbound WebSocket dispatch captures that generation at receive time and passes it to the runtime handler, so a successful local tool execution can publish only on the same generation. Stdio mode invokes `LocalRuntime` directly without that adapter.
|
|
38
38
|
|
|
39
39
|
`daemon-process.mjs` owns workspace-daemon inspection and takeover. It distinguishes platform service state from the lock-owning Node process, validates PID and process-start identity, canonicalizes workspace/state paths before comparison, parses bounded process command lines without executing them, and sends `SIGTERM` only to a verified same-workspace `--daemon-only` process. POSIX daemons may ignore that signal and reach the bounded non-escalating timeout; Node's Windows signal mapping terminates the verified process directly. CLI orchestration never treats a missing launchd/systemd job as proof that the process exited.
|
|
40
40
|
|
|
@@ -99,7 +99,7 @@ The stdio server implements newline-delimited JSON-RPC over stdin/stdout. It neg
|
|
|
99
99
|
All requests for a deployed Worker route to one named Durable Object. It owns:
|
|
100
100
|
|
|
101
101
|
- OAuth clients, authorization codes, hashed access-token records, an independently versioned hashed refresh-token store, and throttling metadata;
|
|
102
|
-
- one active
|
|
102
|
+
- one active end-to-end-verified daemon WebSocket plus bounded candidate and probing sockets;
|
|
103
103
|
- policy/tool metadata attached to the active socket;
|
|
104
104
|
- a bounded in-memory map of pending daemon calls.
|
|
105
105
|
|
|
@@ -151,12 +151,13 @@ Remote OAuth binds each code, access token, and refresh token to a named Machine
|
|
|
151
151
|
5. The Worker creates a five-minute code bound to client, redirect, resource, normalized scope, and PKCE challenge.
|
|
152
152
|
6. A valid verifier exchanges the one-time code for an expiring access token and refresh token; only their hashes are stored. A refresh request is bound to the original public client, account, scope, resource, and deployment token version, and atomically replaces the refresh token so replay returns `invalid_grant`.
|
|
153
153
|
7. The MCP client initializes against the sole current protocol version; an obsolete client must upgrade rather than enter a legacy execution path. The Worker returns a stateless HMAC-bound `MCP-Session-Id`, and later request/cancellation correlation is scoped by OAuth token, MCP session, JSON-RPC id type, and id value. Two clients may therefore reuse the same JSON-RPC id concurrently without collision. Sessionless POSTs remain independent and are not inserted into a token-global cancellation index. When the daemon advertises `session_bootstrap`, the Worker requests bounded local instructions and appends them to the initialization result; failure degrades to static instructions.
|
|
154
|
-
8. `
|
|
155
|
-
9. `tools/
|
|
156
|
-
10.
|
|
157
|
-
11. The
|
|
158
|
-
12.
|
|
159
|
-
13.
|
|
154
|
+
8. A new daemon first authenticates as a bounded `probing` socket. The Worker sends a random `relay_probe`; the local runtime returns it through the normal session-bound result-delivery path; only the matching result produces `ready_ack`, promotion to the active daemon, and safe replacement of an incumbent connection.
|
|
155
|
+
9. `tools/list` is derived only from the active end-to-end-verified daemon; without one, only `server_info` is advertised.
|
|
156
|
+
10. `tools/call` receives a random relay call ID and is bound to the current daemon socket, authenticated client request key, incoming HTTP abort signal, and local relay-session generation.
|
|
157
|
+
11. The runtime validates policy and arguments, executes the tool, and returns a bounded result.
|
|
158
|
+
12. The Durable Object accepts a result only from the daemon socket that received that call, and the local runtime sends it only through the relay generation that delivered its call.
|
|
159
|
+
13. A matching cancellation notification or incoming HTTP client disconnect removes the pending indexes, tells the daemon to cancel, and terminates ordinary child processes bound to the call. If local completion races with cancellation, the eventual result is discarded rather than treated as a user-visible delivery failure.
|
|
160
|
+
14. `start_job` is different: after durable acceptance, the detached runner is no longer bound to the relay call or socket. Later cancellation uses `cancel_job` or the local CLI.
|
|
160
161
|
|
|
161
162
|
Duplicate in-flight JSON-RPC IDs are rejected only within the same authenticated MCP session. The request key includes OAuth token identity, the HMAC-bound MCP session, JSON-RPC id type, and id value, so separate initialized clients may safely reuse the same numeric id.
|
|
162
163
|
|
|
@@ -220,13 +221,13 @@ Worker-name mutation is a separate identity transition. Existing state rejects a
|
|
|
220
221
|
|
|
221
222
|
## Daemon reconnect and replacement
|
|
222
223
|
|
|
223
|
-
The local `RelayConnection` treats proxy selection, transport construction,
|
|
224
|
+
The local `RelayConnection` treats proxy selection, transport construction, WebSocket open, authentication, end-to-end readiness, and outage recovery as separate states. The shared proxy module maps WebSocket targets to standard HTTP(S) environment-proxy resolution, honors `NO_PROXY`, rejects non-HTTP(S) proxy schemes, and creates the proxy agent without exposing its URL or credentials. Invalid proxy configuration is a fatal configuration error rather than a retryable outage.
|
|
224
225
|
|
|
225
|
-
|
|
226
|
+
A connection-attempt deadline terminates sockets stuck in `CONNECTING`. After open, the daemon sends `hello`; `hello_ack` establishes an authenticated relay generation and starts heartbeats, but does not resolve startup or advertise readiness. The Worker then sends a random `relay_probe`. Its result must traverse the local runtime dispatcher and `sendForSession` on that generation before `ready_ack` marks the connection usable. The daemon rejects ordinary tool calls before that state and rejects a premature readiness acknowledgement without locally recorded probe delivery. Independent handshake and readiness deadlines terminate candidates that authenticate but cannot return results. Once ready, application heartbeats require inbound activity; a silent half-open socket is terminated and reconnected. Outage reminders run on their own exponential-backoff timer rather than depending on another transport callback.
|
|
226
227
|
|
|
227
228
|
Reconnect uses bounded exponential backoff with jitter. Brief self-healing interruptions are debug-only. An unresolved outage is promoted to a rate-limited warning after a grace period, and recovery produces one summary. Raw close codes and reason strings remain debug-only.
|
|
228
229
|
|
|
229
|
-
The Worker
|
|
230
|
+
The Worker stores socket transitions in `DaemonSocketRegistry`: `candidate` before hello, `probing` after authentication, `daemon` only after the end-to-end result probe, and `expired` after terminal failure. Durable Object alarms enforce separate hello, readiness, and steady-state liveness deadlines across hibernation. A healthy incumbent remains active while a replacement is probed; a malformed, silent, or incompatible replacement is closed without displacing it. Only a verified candidate receives `ready_ack` and then replaces the old socket. Ready daemons stay live only while inbound traffic refreshes `lastSeenAt`; silent half-open or hibernation-restored sockets are reclaimed instead of advertising `daemon.connected` while tool calls time out. Pending calls retain their originating socket reference. A stale socket cannot complete or cancel replacement-socket calls. Closing a socket rejects only calls assigned to it. The local relay generation supplies the symmetric boundary: work accepted by an older authenticated connection cannot publish its result through a newer connection even when the call IDs are otherwise well formed.
|
|
230
231
|
|
|
231
232
|
## Persistence
|
|
232
233
|
|
|
@@ -246,7 +247,7 @@ Browser-origin handling separates CORS response sharing from protocol authentica
|
|
|
246
247
|
|
|
247
248
|
## Observability
|
|
248
249
|
|
|
249
|
-
Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
|
|
250
|
+
Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, managed-job counts, resource alias names without paths or values, relay route state without endpoint details, authenticated/probing/ready socket counts, end-to-end readiness evidence, and privacy-preserving capability-routing evidence. It separates the daemon capability ceiling from the authenticated account authority: `daemon.policy`/`daemon.tools` retain the pre-role ceiling, while `authorization.effective_policy`/`authorization.effective_tools` and the top-level `tools` report the role-intersected authority before any host-side filtering. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
|
|
250
251
|
|
|
251
252
|
Foreground logging defaults to `info`; autostart uses `warn`. Authenticated readiness, persistent degradation, and recovery are user-visible state transitions. Brief relay interruptions, raw transport close details, retry timing, and all per-tool starts/successes/failures/cancellations/durations are debug-only. Unexpected local and Worker infrastructure errors are reduced to classes. Messages, strings, arrays, object depth/key counts, and serialized fields are bounded.
|
|
252
253
|
|
package/docs/AUDIT.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Engineering and security audit
|
|
2
2
|
|
|
3
|
+
## 2026-07-17 version 1.2.5 end-to-end relay-readiness audit
|
|
4
|
+
|
|
5
|
+
The incident sequence disproved the previous meaning of “connected.” Version 1.2.3 correctly stopped treating every hibernation-restored `OPEN` WebSocket as live, and version 1.2.4 restored the missing local relay-session generation. Those changes repaired two concrete defects, but the startup contract still established readiness from `hello_ack` and heartbeat traffic. Both signals exercise transport authentication and one-way control messages; neither proves that an inbound request can traverse the local dispatcher and return on the same authenticated relay generation. A regression in that return path could therefore keep heartbeats healthy while every user tool timed out.
|
|
6
|
+
|
|
7
|
+
Version 1.2.5 replaces that proxy signal with direct evidence. After `hello`, the Worker stores the socket as `probing`, returns `hello_ack`, and sends a random `relay_probe`. The local runtime validates the probe and returns `relay_probe_result` through `deliverRelayToolResult` and `sendForSession`, using the exact session-generation boundary that protects real tool results. Only then does the Worker promote the socket to `daemon`, send `ready_ack`, advertise tools, and allow the local startup promise to resolve. The local side independently records successful probe-result delivery; it rejects `ready_ack` before that evidence and rejects any ordinary `tool_call` while the relay is authenticated but not ready. The probe identifier is random, bounded, short-lived attachment metadata; it contains no tool arguments, paths, commands, output, account data, or credentials.
|
|
8
|
+
|
|
9
|
+
Replacement is now fail-safe rather than eager. The current verified daemon remains authoritative while a candidate authenticates and completes the probe. Malformed or mismatched results close the candidate with a protocol error; missing results reach an independent readiness deadline; neither path rejects calls assigned to the incumbent or changes its advertised policy. Only a verified candidate closes the old socket. Durable Object alarms independently enforce candidate hello, probing readiness, and steady-state liveness deadlines across hibernation. `server_info` distinguishes current authenticated, probing, and ready socket counts and reports `readiness_verified`; control-plane consumers no longer need to infer service health from cumulative socket counters.
|
|
10
|
+
|
|
11
|
+
The review also found a lower-severity routing defect in the user's pending skill rename. The ranking algorithm gave short generic identity words such as `web` the same strong weight as a distinctive capability name, so unrelated browser work could cross the selection threshold. Removing only that weight exposed a hidden dependence on the same generic token for Chinese research requests. The correction suppresses strong identity credit for generic words and adds an explicit Chinese research/search semantic mapping. Positive and negative regressions now encode both sides of the decision boundary.
|
|
12
|
+
|
|
13
|
+
Architecture review extracted daemon attachment mutation from the Worker composition root into `DaemonSocketRegistry`, added an independent line cap and responsibility assertions, removed a duplicate HTTP method guard, and made inbound liveness updates await alarm rescheduling rather than leaving an unobserved promise. Fault injection covers no-ready-ack reconnect, invalid replacement probes, incumbent preservation, verified handover, session-bound probe return, and current observability. The complete package gate, Worker dry run, dependency/signature/privacy checks, and cross-platform CI remain the release boundary. This source change does not deploy the Worker, replace the running daemon, rotate credentials, publish npm, create a tag, or create a GitHub Release; a live installation remains on its old behavior until Worker, daemon, and extension converge on 1.2.5.
|
|
14
|
+
|
|
3
15
|
## 2026-07-17 version 1.2.2 relay-lifecycle and logging audit
|
|
4
16
|
|
|
5
17
|
The reported warning was the visible symptom of a call-lifecycle mismatch rather than a failed local tool. The Worker could remove a pending call after MCP cancellation, timeout, daemon disconnect, or client abandonment, while the local runtime still completed its asynchronous operation and entered one unconditional result-delivery path. When the original WebSocket had closed, the daemon emitted one `relay.tool_result.delivery_failed` warning per late completion. More seriously, if a replacement relay had already authenticated, the old result could be written to the new socket; the Worker rejected it because its pending record was socket-bound, but the local transport did not enforce the symmetric session boundary.
|
package/docs/ENGINEERING.md
CHANGED
|
@@ -53,7 +53,7 @@ Rules:
|
|
|
53
53
|
- Pure classification and normalization functions are exported and tested directly when practical.
|
|
54
54
|
- Adapters may translate data but should not duplicate policy or schemas.
|
|
55
55
|
- Every protocol control message emitted by one side must be explicitly accepted, rejected, or version-gated by the other side, with an end-to-end contract test covering the message name and semantics.
|
|
56
|
-
- State transitions are explicit; readiness is not inferred from a lower-level event.
|
|
56
|
+
- State transitions are explicit; readiness is not inferred from a lower-level event. An open WebSocket is not authenticated until `hello_ack`, and authenticated transport is not service readiness until an end-to-end result probe has returned on the same relay session. Pre-ready work and premature readiness acknowledgements fail closed.
|
|
57
57
|
- Every externally controlled input is bounded before expensive allocation, traversal, parsing, storage, or execution.
|
|
58
58
|
- Externally controlled string keys must not use prototype-chain membership or truthiness on ordinary objects. Use `Map`, `Set`, `Object.hasOwn`, or null-prototype records for command dispatch, enums, ACLs, form fields, registries, and other key-addressed contracts.
|
|
59
59
|
- Repository text must not contain invisible ASCII controls other than tab, CR, and LF; architecture tests enforce this even when JavaScript syntax remains valid.
|
package/docs/LOGGING.md
CHANGED
|
@@ -45,7 +45,7 @@ Autostart installation and daemon startup may report the names of allowlisted pr
|
|
|
45
45
|
|
|
46
46
|
## Relay connection event policy
|
|
47
47
|
|
|
48
|
-
A TCP/WebSocket `open` event is only transport availability. The daemon is reported as
|
|
48
|
+
A TCP/WebSocket `open` event is only transport availability, and `hello_ack` proves only authenticated bidirectional control traffic. The daemon is reported as ready only after a random Worker probe returns through the ordinary local dispatcher and session-bound result path and the Worker sends `ready_ack`.
|
|
49
49
|
|
|
50
50
|
Brief network interruptions are expected on laptop network changes, Worker deployment, proxy rotation, and ordinary internet transport. They are handled as follows:
|
|
51
51
|
|
|
@@ -57,10 +57,10 @@ Brief network interruptions are expected on laptop network changes, Worker deplo
|
|
|
57
57
|
- while the outage remains unresolved, reminders are scheduled independently of reconnect callbacks and use exponential backoff capped at 15 minutes;
|
|
58
58
|
- a WebSocket that remains in `CONNECTING` beyond its deadline is terminated so one stalled network attempt cannot freeze the reconnect loop;
|
|
59
59
|
- relay identity/version mismatch, authentication rejection, and unexpected protocol messages are non-transient: they produce an immediate actionable error and terminate that daemon instead of entering the reconnect loop;
|
|
60
|
-
-
|
|
60
|
+
- Worker `daemon_hello_timeout` and `daemon_ready_timeout` errors are transient and follow the normal reconnect path rather than being misclassified as authentication rejection;
|
|
61
61
|
- recovery after a visible outage produces one information summary with a human-readable duration and attempt count; exact seconds and error classes remain debug-only;
|
|
62
|
-
-
|
|
63
|
-
- failure to receive `hello_ack` within the handshake deadline terminates the candidate socket and retries;
|
|
62
|
+
- a verified replacement is a distinct warning and permanently stops the older daemon;
|
|
63
|
+
- failure to receive `hello_ack` within the handshake deadline, or `ready_ack` within the independent end-to-end readiness deadline, terminates the candidate socket and retries;
|
|
64
64
|
- lack of inbound heartbeat activity terminates a half-open socket and reconnects.
|
|
65
65
|
|
|
66
66
|
A WebSocket close code such as `1006` means the transport ended without a normal close handshake. It is useful for debug diagnosis but not useful as the default user message. Default logs therefore describe the effect and recovery behavior rather than printing `{"code":1006,"reason":""}`.
|
|
@@ -68,7 +68,7 @@ A WebSocket close code such as `1006` means the transport ended without a normal
|
|
|
68
68
|
Examples:
|
|
69
69
|
|
|
70
70
|
```text
|
|
71
|
-
[info] daemon: remote relay connected
|
|
71
|
+
[info] daemon: remote relay connected and end-to-end result delivery verified
|
|
72
72
|
[warn] daemon: remote relay unavailable for 12 seconds; reconnecting automatically (3 reconnect attempts; connection interrupted).
|
|
73
73
|
[info] daemon: remote relay connection restored after 18 seconds (4 reconnect attempts)
|
|
74
74
|
```
|
|
@@ -117,7 +117,7 @@ This is defense in depth, not content classification. Unknown, split, transforme
|
|
|
117
117
|
|
|
118
118
|
The local execution middleware emits bounded events such as `tool.call.started`, `tool.call.completed`, `tool.call.failed`, `tool.call.slow`, and `tool.call.cancel_requested`. Stable fields include a shortened call ID, tool name, origin, duration, error code, and retryability. The Worker emits JSON events for HTTP failures and daemon socket errors. Structured values still pass through field-name and value redaction; JSON format is not permission to log arguments or results.
|
|
119
119
|
|
|
120
|
-
`server_info` is the operational metrics surface. Local metrics include lifecycle state, active and maximum calls, oldest-call age, active-process ownership, per-tool duration buckets, and error-code counts. Worker metrics include HTTP status classes, pending internal/request-key indexes, per-tool outcomes, daemon candidate/authenticated/disconnected counts, and protocol-error counts. Metrics contain counts and bounded identifiers, not request arguments or result contents.
|
|
120
|
+
`server_info` is the operational metrics surface. Local metrics include lifecycle state, active and maximum calls, oldest-call age, active-process ownership, per-tool duration buckets, and error-code counts. Worker metrics include HTTP status classes, pending internal/request-key indexes, per-tool outcomes, daemon candidate/authenticated/ready/disconnected event counts, current authenticated/probing/ready socket counts, and protocol-error counts. Metrics contain counts and bounded identifiers, not request arguments or result contents.
|
|
121
121
|
|
|
122
122
|
## Files
|
|
123
123
|
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -34,6 +34,7 @@ Run these commands from the same environment used for startup so `HTTPS_PROXY`,
|
|
|
34
34
|
|---|---|
|
|
35
35
|
| `authorization.effective_policy.profile` is `full` and the tool is in `authorization.effective_tools`, but the current session UI exposes fewer tools | Host/connector post-relay filtering; Machine Bridge cannot enumerate or override that subset |
|
|
36
36
|
| `daemon.policy.profile` is `full` but `authorization.effective_policy.profile` is `review`, `edit`, or `agent` | Expected account-role narrowing; the daemon field is only a capability ceiling and must not be reported as the account permission |
|
|
37
|
+
| `worker.sockets_live.authenticated` is nonzero but `worker.sockets_live.ready` is zero | Transport authentication exists, but the end-to-end result probe has not completed; no daemon tools are advertised and the candidate will be closed at the readiness deadline |
|
|
37
38
|
| `capability_routing.bootstrap_observed` is false | The current local runtime has not received `session_bootstrap`; reconnect or inspect host initialization handling |
|
|
38
39
|
| `task_resolution_observed` is false after a substantive task | The host/model did not call `resolve_task_capabilities`; server-side discovery cannot force that host decision |
|
|
39
40
|
| Task resolution ran but all match counts are zero | The resolver ran successfully but found no sufficiently relevant local skill, command, or application |
|
|
@@ -50,13 +51,13 @@ A successful diagnostic result applies only to that probe. An MCP host can still
|
|
|
50
51
|
|
|
51
52
|
Machine Bridge supports concurrent calls: the Worker admits up to 32 pending daemon calls and the local runtime admits up to 16 active tool calls. These are capacity limits, not a single global execution queue. Each successful MCP initialization receives a signed `MCP-Session-Id`; JSON-RPC ids and cancellation are scoped to that session, so separate chat windows may reuse the same numeric ids safely even when they share one OAuth account and token.
|
|
52
53
|
|
|
53
|
-
`server_info.worker.pending_calls` reports `active`, `request_keys`, `maximum`, `oldest_ms`, and `by_tool`. A nonzero `active` count means work is in flight, not that the bridge is locked. Calls for simple reads and probes should continue while another independent process call runs. Explicit MCP cancellation, an incoming HTTP client disconnect, timeout, and daemon-socket closure remove the pending record and its session request key. Local results are bound to the authenticated relay session that originated the call, so a result that finishes after cancellation or reconnection is discarded instead of being sent over a replacement socket. Refreshing a chat page is not the recovery mechanism and should not be required.
|
|
54
|
+
`server_info.worker.pending_calls` reports `active`, `request_keys`, `maximum`, `oldest_ms`, and `by_tool`. `worker.sockets_live` separately reports `authenticated`, `probing`, `ready`, and `candidates`; only `ready` sockets contribute to `daemon.connected` and tool advertisement. A nonzero `active` count means work is in flight, not that the bridge is locked. Calls for simple reads and probes should continue while another independent process call runs. Explicit MCP cancellation, an incoming HTTP client disconnect, timeout, and daemon-socket closure remove the pending record and its session request key. Local results are bound to the authenticated relay session that originated the call, so a result that finishes after cancellation or reconnection is discarded instead of being sent over a replacement socket. Refreshing a chat page is not the recovery mechanism and should not be required.
|
|
54
55
|
|
|
55
56
|
`server_info.worker.observability.calls.unmatched_results` counts results that reached the Worker after their pending record was already removed. A small increase can accompany cancellation or timeout races, especially during mixed-version upgrade convergence; sustained growth together with old pending calls indicates incompatible components or a lifecycle defect. The counter contains no tool arguments or result data.
|
|
56
57
|
|
|
57
58
|
### Relay interruption messages
|
|
58
59
|
|
|
59
|
-
A brief relay interruption is retried automatically and is visible only with `--verbose`. Default logs do not print raw WebSocket values such as `code=1006` with an empty reason. If a transient outage persists for 10 seconds, the daemon emits a readable duration/cause/reconnect summary; later reminders use autonomous exponential backoff capped at 15 minutes, and recovery produces one readable summary. Each transport connection attempt also has a deadline, so a socket stuck in `CONNECTING` cannot freeze retries. Identity/version mismatch, authentication rejection, and unexpected protocol messages are not retried as ordinary network faults: the daemon emits an immediate actionable error and exits, requiring upgrade/redeployment or credential repair.
|
|
60
|
+
A brief relay interruption is retried automatically and is visible only with `--verbose`. Default logs do not print raw WebSocket values such as `code=1006` with an empty reason. If a transient outage persists for 10 seconds, the daemon emits a readable duration/cause/reconnect summary; later reminders use autonomous exponential backoff capped at 15 minutes, and recovery produces one readable summary. Each transport connection attempt also has a deadline, so a socket stuck in `CONNECTING` cannot freeze retries. Identity/version mismatch, authentication rejection, and unexpected protocol messages are not retried as ordinary network faults: the daemon emits an immediate actionable error and exits, requiring upgrade/redeployment or credential repair. Worker-side hello and end-to-end readiness timeouts remain retryable. Authentication is not reported as usable service readiness until a session-bound probe result returns.
|
|
60
61
|
|
|
61
62
|
Use `--verbose` only when close codes, close reasons, heartbeat timeouts, and retry delays are needed for diagnosis. A close code of 1006 means the transport ended without a normal close handshake; it does not by itself identify the cause.
|
|
62
63
|
|
|
@@ -230,7 +231,9 @@ Claude and Copilot Studio call the public Worker from their cloud connectivity l
|
|
|
230
231
|
|
|
231
232
|
## Reconnect and replacement
|
|
232
233
|
|
|
233
|
-
The daemon sends heartbeats and reconnects with bounded exponential backoff and jitter. A new socket
|
|
234
|
+
The daemon sends heartbeats and reconnects with bounded exponential backoff and jitter. A new socket progresses through candidate, authenticated/probing, and ready states. After `hello_ack`, the Worker sends a random probe that must return through the exact local dispatcher and relay-session result path used by real calls. Only the matching result produces `ready_ack`, `daemon.connected=true`, and tool advertisement. A healthy incumbent remains active until that proof succeeds, so a bad replacement cannot create an avoidable outage.
|
|
235
|
+
|
|
236
|
+
The Worker tracks inbound `lastSeenAt` and reclaims ready or probing sockets that go silent past their applicable liveness/readiness windows. Diagnose with `daemon.readiness_verified`, `worker.sockets_live.ready`, `worker.sockets_live.probing`, and `daemon.last_seen_at`; cumulative `worker.observability.sockets.authenticated` is an event counter, not current liveness. A state with no ready daemon is unavailable by construction rather than falsely online. Restart the daemon only after inspecting the classified timeout/protocol error; refreshing an MCP client does not repair the local transport.
|
|
234
237
|
|
|
235
238
|
Pending calls are bound to the socket that received them. Results from another socket are ignored. A lost or replaced socket rejects only its own pending calls and terminates locally tracked child process trees. Process sessions are in-memory and do not survive daemon restart or replacement.
|
|
236
239
|
|
package/docs/TESTING.md
CHANGED
|
@@ -49,7 +49,7 @@ The suite includes:
|
|
|
49
49
|
- guarded state-root removal, unsafe state-root/workspace overlap rejection before creation, all-profile lock/daemon scanning, strict current-schema validation, corrupt-JSON isolation, and policy-origin persistence;
|
|
50
50
|
- no filename-based sensitive-file denial under unrestricted policy;
|
|
51
51
|
- log redaction, control-character handling, message/field bounds, suppression of both successful and failed per-tool events outside debug, service warning-level configuration, current-schema reset, and bounded tail trimming;
|
|
52
|
-
- deterministic relay connection lifecycle coverage for transport construction/error/deadline, pre-handshake `welcome` validation,
|
|
52
|
+
- deterministic relay connection lifecycle coverage for transport construction/error/deadline, pre-handshake `welcome` validation, separate `hello_ack` authentication and `ready_ack` end-to-end readiness, session-bound probe return, pre-ready tool rejection, premature-ready rejection, identity/version mismatch, retryable Worker hello/readiness errors, fatal protocol errors, autonomous outage-reminder backoff, handshake/readiness/heartbeat timeout, brief-outage suppression, sustained-outage escalation, recovery summaries, and supersession;
|
|
53
53
|
- shared no-follow bounded-file reads for normal files, over-limit data, directories, and symbolic links;
|
|
54
54
|
- owner-only directory enforcement rejecting final symlinks, failing closed on POSIX chmod errors, verifying `0700`, and retaining Windows portability; Worker temporary-secret lifecycle coverage for process-start-bound names, valid stale-owner reclamation, ambiguous-owner retention, `0600` mode, deletion failures, and simultaneous deployment/cleanup failures;
|
|
55
55
|
- SARIF security-gate behavior for unknown findings, exact accepted rule/path matches, path mismatch rejection, rationale quality, and exception expiry;
|
|
@@ -60,7 +60,7 @@ The suite includes:
|
|
|
60
60
|
- independently injected service CLI status/install/start/stop/uninstall/remove paths, including provider failure, no selected workspace, no deployed Worker, aliases, and default output/exit adapters;
|
|
61
61
|
- CLI parsing, policy profiles, and client configuration boundaries;
|
|
62
62
|
- live stdio MCP initialization with session instructions, capability resolution, discovery, calls, rich content, sessions, cancellation, managed-job acceptance, and a detached job/finally phase that survives stdio shutdown;
|
|
63
|
-
- live local Worker OAuth registration, the unauthenticated `resource_metadata` challenge, protected-resource and authorization-server discovery, Streamable transport metadata, consent, URL-constructed `303` callbacks including the ChatGPT and hosted Claude redirect URIs with encoded state, PKCE, `offline_access`, form-encoded authorization-code and refresh-token exchanges, access/refresh rotation, stale refresh replay rejection, account-version refresh revocation, authorization-code replay rejection, pending-registration throttling that excludes already authorized DCR clients, exact built-in ChatGPT/Grok browser origins, additive custom origins, unrelated-origin preflight rejection, no CORS response sharing for unrelated or opaque origins, opaque-origin authorization-form routing, exact per-request redirect-origin CSP with narrowly scoped Microsoft regional-consent and final Copilot Studio handoff exceptions, accessible credential-error rendering, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure. The metadata/refresh contract is the path used by Claude DCR and Copilot Studio Dynamic discovery. The same integration runs an `editor` account against a canonical `full` daemon and proves that `server_info` and remote `project_overview` report effective `edit` authority while retaining the full daemon ceiling only in explicitly scoped fields.
|
|
63
|
+
- live local Worker OAuth registration, the unauthenticated `resource_metadata` challenge, protected-resource and authorization-server discovery, Streamable transport metadata, consent, URL-constructed `303` callbacks including the ChatGPT and hosted Claude redirect URIs with encoded state, PKCE, `offline_access`, form-encoded authorization-code and refresh-token exchanges, access/refresh rotation, stale refresh replay rejection, account-version refresh revocation, authorization-code replay rejection, pending-registration throttling that excludes already authorized DCR clients, exact built-in ChatGPT/Grok browser origins, additive custom origins, unrelated-origin preflight rejection, no CORS response sharing for unrelated or opaque origins, opaque-origin authorization-form routing, exact per-request redirect-origin CSP with narrowly scoped Microsoft regional-consent and final Copilot Studio handoff exceptions, accessible credential-error rendering, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, candidate/probing/ready transitions, invalid readiness-result rejection, incumbent preservation until verified handover, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure. The metadata/refresh contract is the path used by Claude DCR and Copilot Studio Dynamic discovery. The same integration runs an `editor` account against a canonical `full` daemon and proves that `server_info` and remote `project_overview` report effective `edit` authority while retaining the full daemon ceiling only in explicitly scoped fields.
|
|
64
64
|
- local runtime proof that one blocked tool handler does not serialize an independent handler, plus relay fault injection proving an undeliverable terminal result interrupts the ambiguous socket and enters reconnect backoff.
|
|
65
65
|
- a real headless-Chrome OAuth navigation regression with four cases: `form-action 'self'` blocks the first cross-origin callback, allowing only the registered callback blocks the regional redirect, allowing the registered and regional callbacks blocks the final Copilot Studio redirect, and the complete policy preserves `code` and `state` through all three cross-origin hops. Linux CI fails if Chrome is unavailable; other environments skip only this browser executable check while retaining the Worker CSP assertions.
|
|
66
66
|
|
|
@@ -108,7 +108,7 @@ GitHub Actions executes the main suite on Linux, macOS, and Windows using the pi
|
|
|
108
108
|
- Every permission-expanding feature needs a denial test. Browser/application features also require a token/value/content non-disclosure assertion.
|
|
109
109
|
- Every bounded resource needs an over-limit test.
|
|
110
110
|
- Every multi-stage mutation needs a no-partial-commit test.
|
|
111
|
-
- Every remote call correlation change needs daemon replacement and cancellation coverage.
|
|
111
|
+
- Every remote call correlation or readiness change needs daemon replacement, incumbent-preservation, timeout, malformed-result, and cancellation coverage.
|
|
112
112
|
- Every durable workflow needs disconnect, cancellation, cleanup-failure, dead-runner, and plan-scrubbing coverage.
|
|
113
113
|
- Secret-bearing resource tests must assert absence of raw, path, base64, and hex forms from MCP-visible results.
|
|
114
114
|
- Logs and public metadata should be tested for absence of sensitive fields, arguments, outputs, and routine success noise—not only presence of expected fields.
|
package/docs/UPGRADING.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Machine Bridge does not retain parallel implementations for obsolete MCP protocol dates, policy revisions, state schemas, lock formats, or browser-extension protocols. The supported path is a direct upgrade from the immediately preceding published package while its state already uses the current schema.
|
|
6
6
|
|
|
7
|
-
Version 1.2.
|
|
7
|
+
Version 1.2.5 keeps local state schema version 6 and policy revision 5 unchanged. Existing 1.2.4 workspaces, named accounts, resource registrations, managed-job history, Worker identity, and browser pairing state are reused without a schema conversion. The package change replaces relay startup/replacement semantics and capability ranking; it does not alter stored authority or credential records.
|
|
8
8
|
|
|
9
|
-
Version 1.2.
|
|
9
|
+
Version 1.2.5 requires the Worker, local daemon, and browser extension to converge on the same package version. The new Worker expects candidate → probing → ready negotiation and the new daemon waits for `ready_ack`; mixed 1.2.4/1.2.5 components therefore fail closed rather than falling back to the old false-ready handshake. Normal startup redeploys the versioned Worker when required and restarts only a verified same-workspace daemon. Reload the unpacked extension after convergence even though this release does not change its browser protocol.
|
|
10
10
|
|
|
11
11
|
Version 1.2.0 could accept prototype-shaped account roles through malformed administration input. On the first 1.2.1 or later Worker access, such an account is preserved for recovery but repaired fail-closed: its role becomes `reviewer`, it is disabled, its account version advances, and its authorization codes and tokens are removed. An operator can then assign a valid role, enable the account, and rotate its password through the normal account administration flow. A local policy record with an unknown profile label is normalized to `custom` while retaining its explicit capability fields; an invalid explicit `--profile` is rejected.
|
|
12
12
|
|
|
@@ -29,6 +29,6 @@ Machine Bridge never treats an unreadable or foreign-schema state file as empty
|
|
|
29
29
|
|
|
30
30
|
## Rollback
|
|
31
31
|
|
|
32
|
-
Rollback is supported only when the older package understands every persisted schema and protocol already written by the newer package. Version 1.2.
|
|
32
|
+
Rollback is supported only when the older package understands every persisted schema and protocol already written by the newer package. Version 1.2.5 does not advance local state or policy schemas, so a complete rollback to 1.2.4 is structurally possible. The Worker, daemon, and extension must be rolled back together; a 1.2.5 daemon cannot negotiate the old handshake safely, and restoring only one component recreates an unavailable mixed-version system. The preferred recovery is still to fix forward because 1.2.4 can report authenticated transport before proving the result path.
|
|
33
33
|
|
|
34
34
|
Never roll back by copying only selected state files or changing version fields. Restore one complete verified state backup, package version, Worker build, and browser extension as a single operational unit.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "machine-bridge-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Cross-client MCP bridge for local agent context, structured browser and application automation, files, Git, processes, resources, and durable jobs over stdio or OAuth relay.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
const TOKEN_STOP_WORDS = new Set(["the", "and", "for", "with", "from", "this", "that", "use", "using", "into", "of", "to", "a", "an", "in", "on", "is", "are", "or", "及", "和", "的", "了", "在", "用", "使用", "进行", "根据"]);
|
|
3
|
+
const GENERIC_IDENTITY_TOKENS = new Set(["app", "application", "cli", "local", "tool", "web"]);
|
|
3
4
|
const ENGLISH_TOKEN_CANONICAL = new Map([
|
|
4
5
|
["created", "create"], ["creating", "create"], ["creation", "create"], ["creator", "create"],
|
|
5
6
|
["improved", "improve"], ["improving", "improve"], ["improvement", "improve"],
|
|
@@ -17,7 +18,7 @@ const HAN_TOKEN_ALIASES = Object.freeze([
|
|
|
17
18
|
[/技能/u, ["skill"]],
|
|
18
19
|
[/安装/u, ["install", "installer"]],
|
|
19
20
|
[/部署/u, ["deploy", "deployment"]],
|
|
20
|
-
[
|
|
21
|
+
[/查找|搜索|检索|调研|研究/u, ["search", "find", "research"]],
|
|
21
22
|
[/最新|当前/u, ["latest", "current"]],
|
|
22
23
|
[/官方/u, ["official"]],
|
|
23
24
|
[/文档|资料/u, ["docs", "documentation"]],
|
|
@@ -47,7 +48,7 @@ export function relevanceScore(task, candidate, identity = "") {
|
|
|
47
48
|
let score = 0;
|
|
48
49
|
for (const token of taskTokens) {
|
|
49
50
|
if (candidateTokens.has(token)) score += token.length >= 6 ? 2 : 1;
|
|
50
|
-
if (identityTokens.has(token)) score += token.length >= 6 ? 4 : 3;
|
|
51
|
+
if (identityTokens.has(token) && !GENERIC_IDENTITY_TOKENS.has(token)) score += token.length >= 6 ? 4 : 3;
|
|
51
52
|
}
|
|
52
53
|
const taskComparable = comparableText(task);
|
|
53
54
|
const candidateComparable = comparableText(candidate);
|