@bridge_gpt/mcp-server 0.2.68 → 0.2.69
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 +99 -41
- package/build/bridge-permissions.js +627 -94
- package/build/check-update-cli.js +74 -0
- package/build/claude-settings.js +84 -2
- package/build/cli-help.js +7 -1
- package/build/codex-home.js +9 -1
- package/build/codex-launcher-pin.js +598 -0
- package/build/commands.generated.js +5 -5
- package/build/connect-github-api.js +33 -14
- package/build/docs.generated.js +2 -2
- package/build/doctor.js +109 -6
- package/build/epic-implementer-bin.js +80 -85
- package/build/executor/completion-contract.js +2 -0
- package/build/executor/http-client.js +43 -4
- package/build/index.js +464 -246
- package/build/install-bridge.js +260 -297
- package/build/launcher-config-inspection.js +184 -19
- package/build/mcp-host-targets.js +4 -0
- package/build/mcp-identity.js +7 -0
- package/build/pipelines.generated.js +4 -4
- package/build/readme.generated.js +1 -1
- package/build/session-upgrade-notice.js +86 -0
- package/build/start-tickets.js +15 -0
- package/build/tool-call-advisory.js +162 -0
- package/build/tool-surface-gating.js +28 -89
- package/build/update-check.js +97 -16
- package/build/update-status.js +61 -71
- package/build/upgrade-advice.js +15 -11
- package/build/upgrade-cli.js +347 -20
- package/build/version.generated.js +3 -3
- package/package.json +1 -1
package/build/update-status.js
CHANGED
|
@@ -1,69 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Process-wide
|
|
2
|
+
* Process-wide settled update status (BAPI-728, reshaped by BAPI-1446).
|
|
3
3
|
*
|
|
4
|
-
* The staleness signal already existed
|
|
5
|
-
* start and computed the right answer
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* The staleness signal already existed: `checkForUpdate()` ran on every server
|
|
5
|
+
* start and computed the right answer, then announced it to a log sink nobody
|
|
6
|
+
* reads. BAPI-1446 moved delivery to surfaces a session actually reads (startup
|
|
7
|
+
* instructions, the first completed tool result, the SessionStart hook). This
|
|
8
|
+
* manager is now only the source of one fact for those surfaces: what the live
|
|
9
|
+
* check concluded, once it has settled.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* per process (humans), and a `tools/list` advisory (models). It is:
|
|
11
|
+
* The settled-status contract:
|
|
13
12
|
*
|
|
14
13
|
* - **single-flight** — one `checkForUpdate()` per process, cached forever;
|
|
15
|
-
* - **non-blocking** —
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* - **non-blocking** — `start()` returns at once and is never awaited before
|
|
15
|
+
* `connect`; `getStatus()` is synchronous and never waits for the lookup;
|
|
16
|
+
* - **known versus unknown** — `known: true` means a reliable live result
|
|
17
|
+
* settled, including "you are current". Initial, in-flight, disabled,
|
|
18
|
+
* rejected, null, and malformed outcomes are `known: false` and not stale, so
|
|
19
|
+
* the tool-result channel never mistakes "unknown" for "confirmed current"
|
|
20
|
+
* and can fall back to the local cache;
|
|
21
|
+
* - **fail-open** — nothing here throws, and `whenSettled()` never rejects.
|
|
18
22
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* `stale` is kept for existing production consumers and is only ever true for a
|
|
24
|
+
* reliable newer result.
|
|
25
|
+
*
|
|
26
|
+
* Passing `enabled: false` (BAPI-917) makes the manager permanently unknown from
|
|
27
|
+
* the moment `start()` returns, without invoking the checker, touching the update
|
|
28
|
+
* cache, or making a registry request — used so a hermetic measurement capture
|
|
29
|
+
* cannot be perturbed by runtime update state.
|
|
24
30
|
*/
|
|
25
|
-
import { checkForUpdate } from "./update-check.js";
|
|
26
|
-
import {
|
|
27
|
-
/** The
|
|
28
|
-
const
|
|
31
|
+
import { checkForUpdate, isNewerVersion, isPlainReleaseVersion, readFakeLatestOverride, } from "./update-check.js";
|
|
32
|
+
import { VERSION } from "./version.generated.js";
|
|
33
|
+
/** The unknown conclusion, used for every fail-open branch. */
|
|
34
|
+
const UNKNOWN = { stale: false, known: false };
|
|
29
35
|
/**
|
|
30
36
|
* Build the manager. Nothing runs until `start()` is called, so importing this
|
|
31
37
|
* module never performs I/O.
|
|
32
38
|
*/
|
|
33
39
|
export function createUpdateStatusManager(options = {}) {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
40
|
+
const env = options.env ?? process.env;
|
|
41
|
+
const check = options.check ?? (() => checkForUpdate({ env }));
|
|
36
42
|
const enabled = options.enabled !== false;
|
|
43
|
+
const runningVersion = options.currentVersion ?? VERSION;
|
|
37
44
|
let started = false;
|
|
38
45
|
let settled = null;
|
|
39
46
|
let settledPromise = null;
|
|
40
|
-
let warned = false;
|
|
41
|
-
let listServed = false;
|
|
42
|
-
let lateNotified = false;
|
|
43
47
|
function conclude(result) {
|
|
44
|
-
// Every uncertain shape is
|
|
45
|
-
//
|
|
48
|
+
// Every uncertain shape is unknown. A malformed payload must never produce a
|
|
49
|
+
// claim about a version that may not exist.
|
|
46
50
|
if (!result || typeof result !== "object")
|
|
47
|
-
return
|
|
48
|
-
if (result.updateAvailable !==
|
|
49
|
-
return
|
|
51
|
+
return UNKNOWN;
|
|
52
|
+
if (typeof result.updateAvailable !== "boolean")
|
|
53
|
+
return UNKNOWN;
|
|
50
54
|
const { currentVersion, latestVersion } = result;
|
|
51
|
-
if (
|
|
52
|
-
return
|
|
53
|
-
if (
|
|
54
|
-
return
|
|
55
|
-
return { stale: true, currentVersion, latestVersion };
|
|
55
|
+
if (!isPlainReleaseVersion(currentVersion))
|
|
56
|
+
return UNKNOWN;
|
|
57
|
+
if (!isPlainReleaseVersion(latestVersion))
|
|
58
|
+
return UNKNOWN;
|
|
59
|
+
return { stale: result.updateAvailable, known: true, currentVersion, latestVersion };
|
|
56
60
|
}
|
|
57
61
|
function start() {
|
|
58
62
|
if (started)
|
|
59
63
|
return;
|
|
60
64
|
started = true;
|
|
61
65
|
if (!enabled) {
|
|
62
|
-
// Disabled: settle immediately, without ever invoking `check
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
// Disabled: settle immediately, without ever invoking `check`. `whenSettled()`
|
|
67
|
+
// stays usable — it just resolves to the same already-known conclusion.
|
|
68
|
+
settled = UNKNOWN;
|
|
69
|
+
settledPromise = Promise.resolve(UNKNOWN);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// A valid fake-latest override settles at once, before any filesystem or
|
|
73
|
+
// registry work, exactly as `checkForUpdate` honors it.
|
|
74
|
+
const override = readFakeLatestOverride(env);
|
|
75
|
+
if (override && isPlainReleaseVersion(runningVersion)) {
|
|
76
|
+
const status = {
|
|
77
|
+
stale: isNewerVersion(runningVersion, override),
|
|
78
|
+
known: true,
|
|
79
|
+
currentVersion: runningVersion,
|
|
80
|
+
latestVersion: override,
|
|
81
|
+
};
|
|
82
|
+
settled = status;
|
|
83
|
+
settledPromise = Promise.resolve(status);
|
|
67
84
|
return;
|
|
68
85
|
}
|
|
69
86
|
settledPromise = (async () => {
|
|
@@ -72,46 +89,19 @@ export function createUpdateStatusManager(options = {}) {
|
|
|
72
89
|
status = conclude(await check());
|
|
73
90
|
}
|
|
74
91
|
catch {
|
|
75
|
-
status =
|
|
92
|
+
status = UNKNOWN; // `checkForUpdate` is contracted not to reject; belt and braces.
|
|
76
93
|
}
|
|
77
94
|
settled = status;
|
|
78
|
-
if (status.stale && !warned) {
|
|
79
|
-
warned = true;
|
|
80
|
-
// stderr, never stdout: stdout is the JSON-RPC frame channel and any
|
|
81
|
-
// stray write there corrupts the protocol stream.
|
|
82
|
-
warn(formatUpdateAdvice(status.currentVersion, status.latestVersion));
|
|
83
|
-
if (listServed && !lateNotified) {
|
|
84
|
-
lateNotified = true;
|
|
85
|
-
try {
|
|
86
|
-
options.onLateStale?.();
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// A notification failure must never affect server operation.
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
95
|
return status;
|
|
94
96
|
})();
|
|
95
97
|
}
|
|
96
98
|
return {
|
|
97
99
|
start,
|
|
98
|
-
getStatus: () => settled ??
|
|
100
|
+
getStatus: () => settled ?? UNKNOWN,
|
|
99
101
|
whenSettled: async () => {
|
|
100
102
|
if (!started)
|
|
101
103
|
start();
|
|
102
|
-
return (await settledPromise) ??
|
|
103
|
-
},
|
|
104
|
-
markListServed: () => {
|
|
105
|
-
listServed = true;
|
|
104
|
+
return (await settledPromise) ?? UNKNOWN;
|
|
106
105
|
},
|
|
107
106
|
};
|
|
108
107
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Produce the model-visible advisory for a settled status, or null when the
|
|
111
|
-
* status is not (yet) known-stale. Pure — safe to call on every list request.
|
|
112
|
-
*/
|
|
113
|
-
export function updateAdvisoryFor(status) {
|
|
114
|
-
if (!status.stale || !status.currentVersion || !status.latestVersion)
|
|
115
|
-
return null;
|
|
116
|
-
return formatToolSurfaceUpdateAdvisory(status.currentVersion, status.latestVersion);
|
|
117
|
-
}
|
package/build/upgrade-advice.js
CHANGED
|
@@ -29,20 +29,24 @@ function sanitizeVersion(value) {
|
|
|
29
29
|
return typeof value === "string" && SAFE_VERSION_RE.test(value) ? value : "unknown";
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* Format the
|
|
33
|
-
*
|
|
32
|
+
* Format the human-facing staleness line (stderr, terminal, `doctor`, and the
|
|
33
|
+
* `ping` advice item). It names both versions and the slash command, and carries
|
|
34
|
+
* no instruction for a model; the model-directed text is
|
|
35
|
+
* {@link formatSessionUpgradeNotice}.
|
|
34
36
|
*/
|
|
35
37
|
export function formatUpdateAdvice(currentVersion, latestVersion) {
|
|
36
|
-
return (`Bridge
|
|
37
|
-
`latest ${sanitizeVersion(latestVersion)} — run
|
|
38
|
+
return (`Bridge MCP: installed ${sanitizeVersion(currentVersion)}, ` +
|
|
39
|
+
`latest ${sanitizeVersion(latestVersion)} — upgrade available — run /upgrade-bridge`);
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
42
|
+
* Format the one-line, plain-text notice delivered to a model session (startup
|
|
43
|
+
* instructions, the first completed tool result, the SessionStart hook). It tells
|
|
44
|
+
* the model to inform the user, offer the upgrade, and run `/upgrade-bridge`
|
|
45
|
+
* only if they say yes. Both versions go through `sanitizeVersion`, so no
|
|
46
|
+
* caller can interpolate arbitrary text.
|
|
43
47
|
*/
|
|
44
|
-
export function
|
|
45
|
-
return (`
|
|
46
|
-
`
|
|
47
|
-
|
|
48
|
+
export function formatSessionUpgradeNotice(current, latest) {
|
|
49
|
+
return (`Bridge MCP upgrade available: this session is running ${sanitizeVersion(current)} ` +
|
|
50
|
+
`and ${sanitizeVersion(latest)} is published. Tell the user an upgrade is available, ` +
|
|
51
|
+
"offer to run /upgrade-bridge, and run it only if they say yes.");
|
|
48
52
|
}
|