@herbertgao/pi-extensions 2026.8.1 → 2026.8.2
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 +5 -2
- package/node_modules/@czottmann/pi-automode/README.md +16 -2
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +35 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +18 -9
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +6 -2
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +6 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +11 -7
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +100 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +32 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +78 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +16 -4
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +23 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +22 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +18 -2
- package/node_modules/@czottmann/pi-automode/package.json +4 -4
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +23 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +99 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +30 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +16 -0
- package/node_modules/@dietrichgebert/ponytail/AGENTS.md +32 -0
- package/node_modules/@dietrichgebert/ponytail/LICENSE +21 -0
- package/node_modules/@dietrichgebert/ponytail/README.es.md +298 -0
- package/node_modules/@dietrichgebert/ponytail/README.ko.md +315 -0
- package/node_modules/@dietrichgebert/ponytail/README.md +351 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +21 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +62 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +115 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +44 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +21 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +96 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +169 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +98 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +130 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +85 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.ps1 +24 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.sh +18 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +77 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +26 -0
- package/node_modules/@dietrichgebert/ponytail/package.json +47 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +211 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/package.json +8 -0
- package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +60 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +120 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +41 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +44 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +50 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +71 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +57 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +10 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary.ts +6 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -83
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/markdown-enhance.ts +119 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +73 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-hover.ts +130 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-interaction.ts +65 -542
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-layout.ts +160 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-packets.ts +143 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-scroll.ts +184 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/diff-renderer.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-grouping.ts +9 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +91 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/agent-summary.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +2 -2
- package/node_modules/@herbertgao/pi-stash/README.md +9 -9
- package/node_modules/@herbertgao/pi-stash/package.json +1 -1
- package/node_modules/@herbertgao/pi-stash/src/index.ts +2 -1
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +14 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +6 -2
- package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +85 -11
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +28 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +12 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +2 -0
- package/node_modules/@narumitw/pi-btw/LICENSE +21 -0
- package/node_modules/@narumitw/pi-btw/README.md +210 -0
- package/node_modules/@narumitw/pi-btw/package.json +53 -0
- package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +632 -0
- package/node_modules/@narumitw/pi-btw/src/btw.ts +996 -0
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +339 -0
- package/node_modules/@narumitw/pi-btw/src/index.ts +1 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +296 -0
- package/node_modules/@narumitw/pi-btw/src/settings.ts +237 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +238 -0
- package/node_modules/@narumitw/pi-btw/src/text.ts +10 -0
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +620 -0
- package/node_modules/@pi-plugins/fast-mode/LICENSE +21 -0
- package/node_modules/@pi-plugins/fast-mode/README.md +92 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts +6 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +2026 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/package.json +73 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +59 -0
- package/node_modules/pi-mcp-adapter/README.md +62 -13
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +377 -0
- package/node_modules/pi-mcp-adapter/commands.ts +9 -7
- package/node_modules/pi-mcp-adapter/config.ts +110 -49
- package/node_modules/pi-mcp-adapter/direct-tools.ts +34 -19
- package/node_modules/pi-mcp-adapter/elicitation-handler.ts +37 -36
- package/node_modules/pi-mcp-adapter/errors.ts +21 -17
- package/node_modules/pi-mcp-adapter/host-html-template.ts +13 -7
- package/node_modules/pi-mcp-adapter/index.ts +37 -14
- package/node_modules/pi-mcp-adapter/init.ts +9 -7
- package/node_modules/pi-mcp-adapter/json-schema-validator.ts +2 -2
- package/node_modules/pi-mcp-adapter/lifecycle.ts +8 -8
- package/node_modules/pi-mcp-adapter/logger.ts +1 -1
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +36 -22
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +120 -2
- package/node_modules/pi-mcp-adapter/mcp-code.ts +13 -11
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +19 -13
- package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +15 -11
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +34 -15
- package/node_modules/pi-mcp-adapter/mcp-probe.ts +131 -34
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +2 -2
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +7 -4
- package/node_modules/pi-mcp-adapter/mcp-trace.ts +59 -64
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +34 -26
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +6 -4
- package/node_modules/pi-mcp-adapter/oauth-handler.ts +1 -1
- package/node_modules/pi-mcp-adapter/onboarding-state.ts +19 -11
- package/node_modules/pi-mcp-adapter/package.json +13 -8
- package/node_modules/pi-mcp-adapter/panel-keys.ts +20 -4
- package/node_modules/pi-mcp-adapter/prompts.ts +2 -2
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +48 -11
- package/node_modules/pi-mcp-adapter/sampling-handler.ts +22 -15
- package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +165 -113
- package/node_modules/pi-mcp-adapter/session-recovery.ts +11 -12
- package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +3 -3
- package/node_modules/pi-mcp-adapter/state.ts +3 -1
- package/node_modules/pi-mcp-adapter/tool-approval.ts +67 -4
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -5
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +14 -2
- package/node_modules/pi-mcp-adapter/ts-shape.ts +9 -2
- package/node_modules/pi-mcp-adapter/types.ts +109 -22
- package/node_modules/pi-mcp-adapter/ui-app-bridge-helpers.ts +40 -0
- package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +28 -19
- package/node_modules/pi-mcp-adapter/ui-server.ts +90 -58
- package/node_modules/pi-mcp-adapter/ui-session.ts +16 -14
- package/node_modules/pi-mcp-adapter/unix-socket-transport.ts +4 -4
- package/node_modules/pi-mcp-adapter/utils.ts +23 -9
- package/package.json +22 -7
|
@@ -1,25 +1,102 @@
|
|
|
1
1
|
const PROBE_TIMEOUT_MS = 5_000;
|
|
2
|
+
const MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
3
|
+
const LEGACY_PROTOCOL_VERSION = "2025-06-18";
|
|
4
|
+
const JSON_ACCEPT = "application/json, text/event-stream";
|
|
5
|
+
const SSE_ACCEPT = "text/event-stream";
|
|
6
|
+
const MODERN_FALLBACK_STATUSES = new Set([400, 401, 404, 405, 406, 415]);
|
|
7
|
+
const POST_ENDPOINT_MISMATCH_STATUSES = new Set([404, 405, 406, 415]);
|
|
2
8
|
|
|
3
9
|
export interface McpProbeResult {
|
|
4
10
|
isMcp: boolean;
|
|
5
11
|
classification: string;
|
|
6
12
|
}
|
|
7
13
|
|
|
14
|
+
const DISCOVER_REQUEST = {
|
|
15
|
+
jsonrpc: "2.0",
|
|
16
|
+
id: 1,
|
|
17
|
+
method: "server/discover",
|
|
18
|
+
params: {},
|
|
19
|
+
};
|
|
20
|
+
|
|
8
21
|
const INITIALIZE_REQUEST = {
|
|
9
22
|
jsonrpc: "2.0",
|
|
10
23
|
id: 1,
|
|
11
24
|
method: "initialize",
|
|
12
25
|
params: {
|
|
13
|
-
protocolVersion:
|
|
26
|
+
protocolVersion: LEGACY_PROTOCOL_VERSION,
|
|
14
27
|
capabilities: {},
|
|
15
28
|
clientInfo: { name: "pi-mcp-probe", version: "2.1.2" },
|
|
16
29
|
},
|
|
17
30
|
};
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
type ProbeStrategy =
|
|
33
|
+
| { kind: "modern"; request: RequestInit; allowJson: true }
|
|
34
|
+
| { kind: "legacy-post"; request: RequestInit; allowJson: true }
|
|
35
|
+
| { kind: "legacy-sse"; request: RequestInit; allowJson: false };
|
|
36
|
+
|
|
37
|
+
const MODERN_STRATEGY: ProbeStrategy = {
|
|
38
|
+
kind: "modern",
|
|
39
|
+
request: {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
Accept: JSON_ACCEPT,
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
"MCP-Protocol-Version": MODERN_PROTOCOL_VERSION,
|
|
45
|
+
"Mcp-Method": "server/discover",
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify(DISCOVER_REQUEST),
|
|
48
|
+
},
|
|
49
|
+
allowJson: true,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const LEGACY_POST_STRATEGY: ProbeStrategy = {
|
|
53
|
+
kind: "legacy-post",
|
|
54
|
+
request: {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: {
|
|
57
|
+
Accept: JSON_ACCEPT,
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify(INITIALIZE_REQUEST),
|
|
61
|
+
},
|
|
62
|
+
allowJson: true,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const LEGACY_SSE_STRATEGY: ProbeStrategy = {
|
|
66
|
+
kind: "legacy-sse",
|
|
67
|
+
request: { headers: { Accept: SSE_ACCEPT } },
|
|
68
|
+
allowJson: false,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
type JsonRpcEnvelopeInfo =
|
|
72
|
+
| { kind: "result"; protocolVersion: unknown }
|
|
73
|
+
| { kind: "error" };
|
|
74
|
+
|
|
75
|
+
type ProbeOutcome =
|
|
76
|
+
| { kind: "mcp"; result: McpProbeResult }
|
|
77
|
+
| { kind: "unsupported-modern" }
|
|
78
|
+
| { kind: "unrecognized" };
|
|
79
|
+
|
|
80
|
+
interface ProbeResult {
|
|
81
|
+
response: Response;
|
|
82
|
+
outcome: ProbeOutcome;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function jsonRpcEnvelopeInfo(value: unknown): JsonRpcEnvelopeInfo | null {
|
|
86
|
+
if (typeof value !== "object" || value === null || (value as { jsonrpc?: unknown }).jsonrpc !== "2.0") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
if ("result" in value) {
|
|
90
|
+
const result = (value as { result?: unknown }).result;
|
|
91
|
+
return {
|
|
92
|
+
kind: "result",
|
|
93
|
+
protocolVersion: typeof result === "object" && result !== null
|
|
94
|
+
? (result as { protocolVersion?: unknown }).protocolVersion
|
|
95
|
+
: undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if ("error" in value) return { kind: "error" };
|
|
99
|
+
return null;
|
|
23
100
|
}
|
|
24
101
|
|
|
25
102
|
function isBearerChallenge(response: Response): boolean {
|
|
@@ -33,29 +110,56 @@ function responseKind(response: Response): string {
|
|
|
33
110
|
return "an untyped response";
|
|
34
111
|
}
|
|
35
112
|
|
|
36
|
-
async function
|
|
113
|
+
async function getJsonRpcEnvelopeInfo(response: Response): Promise<JsonRpcEnvelopeInfo | null> {
|
|
37
114
|
try {
|
|
38
|
-
return
|
|
115
|
+
return jsonRpcEnvelopeInfo(JSON.parse(await response.text()));
|
|
39
116
|
} catch {
|
|
40
|
-
return
|
|
117
|
+
return null;
|
|
41
118
|
}
|
|
42
119
|
}
|
|
43
120
|
|
|
44
|
-
async function classifyResponse(response: Response,
|
|
121
|
+
async function classifyResponse(response: Response, strategy: ProbeStrategy): Promise<ProbeOutcome> {
|
|
45
122
|
const isSse = response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream");
|
|
46
123
|
if (response.ok && isSse) {
|
|
47
|
-
return { isMcp: true, classification: "endpoint responded with an MCP event stream" };
|
|
124
|
+
return { kind: "mcp", result: { isMcp: true, classification: "endpoint responded with an MCP event stream" } };
|
|
48
125
|
}
|
|
49
126
|
|
|
50
|
-
const
|
|
51
|
-
if (response.ok && allowJson &&
|
|
52
|
-
|
|
127
|
+
const envelope = (strategy.allowJson || response.status === 401) ? await getJsonRpcEnvelopeInfo(response) : null;
|
|
128
|
+
if (response.ok && strategy.allowJson && envelope) {
|
|
129
|
+
if (strategy.kind === "modern" && (envelope.kind === "error" || envelope.protocolVersion !== MODERN_PROTOCOL_VERSION)) {
|
|
130
|
+
return { kind: "unsupported-modern" };
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
kind: "mcp",
|
|
134
|
+
result: {
|
|
135
|
+
isMcp: true,
|
|
136
|
+
classification: strategy.kind === "modern"
|
|
137
|
+
? `endpoint supports stateless MCP ${MODERN_PROTOCOL_VERSION} server/discover`
|
|
138
|
+
: "endpoint responded with a JSON-RPC 2.0 envelope",
|
|
139
|
+
},
|
|
140
|
+
};
|
|
53
141
|
}
|
|
54
|
-
if (response.status === 401 && isBearerChallenge(response) &&
|
|
55
|
-
return {
|
|
142
|
+
if (response.status === 401 && isBearerChallenge(response) && envelope) {
|
|
143
|
+
return {
|
|
144
|
+
kind: "mcp",
|
|
145
|
+
result: {
|
|
146
|
+
isMcp: true,
|
|
147
|
+
classification: strategy.kind === "modern"
|
|
148
|
+
? `endpoint requires Bearer authentication during MCP ${MODERN_PROTOCOL_VERSION} server/discover probing`
|
|
149
|
+
: "endpoint requires Bearer authentication and responded with a JSON-RPC 2.0 error",
|
|
150
|
+
},
|
|
151
|
+
};
|
|
56
152
|
}
|
|
57
153
|
|
|
58
|
-
return
|
|
154
|
+
return { kind: "unrecognized" };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function probe(url: string | URL, strategy: ProbeStrategy): Promise<ProbeResult> {
|
|
158
|
+
const response = await fetch(url, {
|
|
159
|
+
...strategy.request,
|
|
160
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
161
|
+
});
|
|
162
|
+
return { response, outcome: await classifyResponse(response, strategy) };
|
|
59
163
|
}
|
|
60
164
|
|
|
61
165
|
function notMcp(response: Response): McpProbeResult {
|
|
@@ -67,24 +171,17 @@ function notMcp(response: Response): McpProbeResult {
|
|
|
67
171
|
|
|
68
172
|
/** Makes one unauthenticated metadata-only request to identify an HTTP endpoint's protocol shape. */
|
|
69
173
|
export async function probeMcpEndpoint(url: string | URL): Promise<McpProbeResult> {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
headers: {
|
|
73
|
-
Accept: "application/json, text/event-stream",
|
|
74
|
-
"Content-Type": "application/json",
|
|
75
|
-
},
|
|
76
|
-
body: JSON.stringify(INITIALIZE_REQUEST),
|
|
77
|
-
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
78
|
-
});
|
|
79
|
-
const postClassification = await classifyResponse(postResponse, true);
|
|
80
|
-
if (postClassification) return postClassification;
|
|
174
|
+
const { response: modernResponse, outcome: modernOutcome } = await probe(url, MODERN_STRATEGY);
|
|
175
|
+
if (modernOutcome.kind === "mcp") return modernOutcome.result;
|
|
81
176
|
|
|
82
|
-
if (
|
|
177
|
+
if (modernOutcome.kind !== "unsupported-modern" && !MODERN_FALLBACK_STATUSES.has(modernResponse.status)) {
|
|
178
|
+
return notMcp(modernResponse);
|
|
179
|
+
}
|
|
83
180
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
return
|
|
181
|
+
const { response: postResponse, outcome: postOutcome } = await probe(url, LEGACY_POST_STRATEGY);
|
|
182
|
+
if (postOutcome.kind === "mcp") return postOutcome.result;
|
|
183
|
+
if (!POST_ENDPOINT_MISMATCH_STATUSES.has(postResponse.status)) return notMcp(postResponse);
|
|
184
|
+
|
|
185
|
+
const { response: getResponse, outcome: getOutcome } = await probe(url, LEGACY_SSE_STRATEGY);
|
|
186
|
+
return getOutcome.kind === "mcp" ? getOutcome.result : notMcp(getResponse);
|
|
90
187
|
}
|
|
@@ -113,9 +113,9 @@ try {
|
|
|
113
113
|
console: capturedConsole,
|
|
114
114
|
}), {
|
|
115
115
|
codeGeneration: { strings: false, wasm: false },
|
|
116
|
-
name: "
|
|
116
|
+
name: "mcpScript",
|
|
117
117
|
});
|
|
118
|
-
const script = new vm.Script(`(async () => {\n${workerData.code}\n})()`, { filename: "
|
|
118
|
+
const script = new vm.Script(`(async () => {\n${workerData.code}\n})()`, { filename: "mcpScript.js" });
|
|
119
119
|
const returnValue = await Promise.resolve(script.runInContext(context));
|
|
120
120
|
parentPort.postMessage(returnValue === undefined
|
|
121
121
|
? { type: "done" }
|
|
@@ -169,9 +169,9 @@ export class McpSetupPanel {
|
|
|
169
169
|
return [...new Set(paths)];
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
private getSelectedAction(): Action |
|
|
172
|
+
private getSelectedAction(): Action | undefined {
|
|
173
173
|
const actions = this.getActions();
|
|
174
|
-
return actions[this.actionCursor]
|
|
174
|
+
return actions[this.actionCursor];
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
handleInput(data: string): void {
|
|
@@ -414,6 +414,7 @@ export class McpSetupPanel {
|
|
|
414
414
|
}
|
|
415
415
|
for (let index = start; index < end; index++) {
|
|
416
416
|
const action = actions[index];
|
|
417
|
+
if (!action) continue;
|
|
417
418
|
if (action.id === "add-known-server" && (index === start || actions[index - 1]?.id !== "add-known-server")) {
|
|
418
419
|
lines.push(this.padLine(fg(this.t.title, "Add a known server"), innerW));
|
|
419
420
|
}
|
|
@@ -442,6 +443,7 @@ export class McpSetupPanel {
|
|
|
442
443
|
lines.push(this.padLine("", innerW));
|
|
443
444
|
for (let index = 0; index < this.discovery.imports.length; index++) {
|
|
444
445
|
const entry = this.discovery.imports[index];
|
|
446
|
+
if (!entry) continue;
|
|
445
447
|
const selected = this.selectedImports.has(entry.kind) ? "[x]" : "[ ]";
|
|
446
448
|
const cursor = index === this.importCursor ? fg(this.t.selected, "›") : " ";
|
|
447
449
|
lines.push(this.padLine(`${cursor} ${selected} ${entry.kind} ${entry.path}`, innerW));
|
|
@@ -462,7 +464,8 @@ export class McpSetupPanel {
|
|
|
462
464
|
const paths = this.getDetectedPaths();
|
|
463
465
|
for (let index = 0; index < paths.length; index++) {
|
|
464
466
|
const cursor = index === this.pathCursor ? fg(this.t.selected, "›") : " ";
|
|
465
|
-
|
|
467
|
+
const path = paths[index];
|
|
468
|
+
if (path !== undefined) lines.push(this.padLine(`${cursor} ${path}`, innerW));
|
|
466
469
|
}
|
|
467
470
|
return lines;
|
|
468
471
|
}
|
|
@@ -537,7 +540,7 @@ export class McpSetupPanel {
|
|
|
537
540
|
' "mcpServers": {',
|
|
538
541
|
' "chrome-devtools": {',
|
|
539
542
|
' "command": "npx",',
|
|
540
|
-
' "args": ["-y", "chrome-devtools-mcp@
|
|
543
|
+
' "args": ["-y", "chrome-devtools-mcp@1.6.0"]',
|
|
541
544
|
" }",
|
|
542
545
|
" }",
|
|
543
546
|
"}",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { appendFile, mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
3
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
4
|
-
import type { Transport } from "@modelcontextprotocol/
|
|
5
|
-
import type { JSONRPCMessage, MessageExtraInfo } from "@modelcontextprotocol/
|
|
4
|
+
import type { Transport } from "@modelcontextprotocol/client";
|
|
5
|
+
import type { JSONRPCMessage, MessageExtraInfo } from "@modelcontextprotocol/client";
|
|
6
6
|
|
|
7
7
|
export const MCP_TRACE_SCHEMA_VERSION = 1;
|
|
8
8
|
export const DEFAULT_MCP_TRACE_MAX_BYTES = 256 * 1024;
|
|
@@ -95,6 +95,7 @@ export function createMcpTraceEvent(
|
|
|
95
95
|
options?: { relatedRequestId?: unknown; durationMs?: number },
|
|
96
96
|
): McpTraceEvent {
|
|
97
97
|
const kind = messageKind(message);
|
|
98
|
+
const bytes = messageBytes(message);
|
|
98
99
|
const event: McpTraceEvent = {
|
|
99
100
|
version: MCP_TRACE_SCHEMA_VERSION,
|
|
100
101
|
timestamp: new Date().toISOString(),
|
|
@@ -103,7 +104,7 @@ export function createMcpTraceEvent(
|
|
|
103
104
|
transport,
|
|
104
105
|
kind,
|
|
105
106
|
status,
|
|
106
|
-
bytes:
|
|
107
|
+
...(bytes !== undefined ? { bytes } : {}),
|
|
107
108
|
};
|
|
108
109
|
if ("method" in message) event.method = redactTraceText(message.method, 120);
|
|
109
110
|
if ("id" in message) event.id = traceId(message.id) ?? null;
|
|
@@ -210,8 +211,8 @@ export function createMcpTraceWriter(
|
|
|
210
211
|
: resolve(sessionCwd ?? process.cwd(), ".pi", "mcp-traces", `mcp-${timestamp}-${randomSuffix}.jsonl`);
|
|
211
212
|
return new McpTraceWriter({
|
|
212
213
|
filePath,
|
|
213
|
-
maxBytes: settings.maxBytes,
|
|
214
|
-
maxEvents: settings.maxEvents,
|
|
214
|
+
...(settings.maxBytes !== undefined ? { maxBytes: settings.maxBytes } : {}),
|
|
215
|
+
...(settings.maxEvents !== undefined ? { maxEvents: settings.maxEvents } : {}),
|
|
215
216
|
});
|
|
216
217
|
}
|
|
217
218
|
|
|
@@ -227,17 +228,20 @@ export function isMcpTraceEnabled(
|
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
/**
|
|
230
|
-
* Compose the SDK's transport callbacks instead of replacing
|
|
231
|
-
*
|
|
232
|
-
*
|
|
231
|
+
* Compose the SDK's transport callbacks in place instead of replacing the
|
|
232
|
+
* transport object. SDK v2 detects its base stdio transport before connect so
|
|
233
|
+
* it can run `server/discover` on a disposable sibling process; returning a
|
|
234
|
+
* wrapper hides that identity and makes tracing change negotiation behavior.
|
|
233
235
|
*/
|
|
234
|
-
export function wrapTransportWithMcpTrace
|
|
235
|
-
transport:
|
|
236
|
+
export function wrapTransportWithMcpTrace(
|
|
237
|
+
transport: Transport,
|
|
236
238
|
server: string,
|
|
237
239
|
transportKind: McpTraceTransport,
|
|
238
240
|
observer: McpTraceObserver,
|
|
239
|
-
):
|
|
240
|
-
let messageHandler
|
|
241
|
+
): Transport {
|
|
242
|
+
let messageHandler = transport.onmessage;
|
|
243
|
+
let tracedMessageHandler: Transport["onmessage"];
|
|
244
|
+
const originalSend = transport.send;
|
|
241
245
|
const record = (event: McpTraceEvent): void => {
|
|
242
246
|
try {
|
|
243
247
|
observer.record(event);
|
|
@@ -245,60 +249,51 @@ export function wrapTransportWithMcpTrace<T extends Transport>(
|
|
|
245
249
|
// An observer failure must never alter SDK transport behavior.
|
|
246
250
|
}
|
|
247
251
|
};
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
Object.defineProperty(transport, "onmessage", {
|
|
255
|
+
configurable: true,
|
|
256
|
+
enumerable: true,
|
|
257
|
+
get() {
|
|
258
|
+
return tracedMessageHandler;
|
|
259
|
+
},
|
|
260
|
+
set(handler: Transport["onmessage"]) {
|
|
261
|
+
messageHandler = handler;
|
|
262
|
+
tracedMessageHandler = handler
|
|
263
|
+
? ((message: JSONRPCMessage, extra?: MessageExtraInfo) => {
|
|
264
|
+
record(createMcpTraceEvent("inbound", server, transportKind, message, "received"));
|
|
265
|
+
handler(message, extra);
|
|
266
|
+
})
|
|
267
|
+
: undefined;
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
transport.onmessage = messageHandler;
|
|
271
|
+
} catch {
|
|
272
|
+
// Some future transport may make onmessage non-configurable. Keep tracing
|
|
273
|
+
// best-effort rather than changing connection behavior.
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
transport.send = async (message: JSONRPCMessage, options?: Parameters<Transport["send"]>[1]) => {
|
|
277
|
+
const started = performance.now();
|
|
278
|
+
const messages = Array.isArray(message) ? message : [message];
|
|
279
|
+
try {
|
|
280
|
+
await originalSend.call(transport, message, options);
|
|
281
|
+
for (const item of messages) {
|
|
282
|
+
record(createMcpTraceEvent("outbound", server, transportKind, item, "sent", {
|
|
283
|
+
durationMs: performance.now() - started,
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
for (const item of messages) {
|
|
288
|
+
record(createMcpTraceEvent("outbound", server, transportKind, item, "error", {
|
|
289
|
+
durationMs: performance.now() - started,
|
|
290
|
+
}));
|
|
267
291
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
get onclose() {
|
|
271
|
-
return transport.onclose;
|
|
272
|
-
},
|
|
273
|
-
set onclose(handler) {
|
|
274
|
-
transport.onclose = handler;
|
|
275
|
-
},
|
|
276
|
-
get onerror() {
|
|
277
|
-
return transport.onerror;
|
|
278
|
-
},
|
|
279
|
-
set onerror(handler) {
|
|
280
|
-
transport.onerror = handler;
|
|
281
|
-
},
|
|
282
|
-
get onmessage() {
|
|
283
|
-
return messageHandler;
|
|
284
|
-
},
|
|
285
|
-
set onmessage(handler) {
|
|
286
|
-
messageHandler = handler;
|
|
287
|
-
transport.onmessage = handler
|
|
288
|
-
? ((message: JSONRPCMessage, extra?: MessageExtraInfo) => {
|
|
289
|
-
record(createMcpTraceEvent("inbound", server, transportKind, message, "received"));
|
|
290
|
-
handler(message, extra);
|
|
291
|
-
}) as Transport["onmessage"]
|
|
292
|
-
: undefined;
|
|
293
|
-
},
|
|
294
|
-
get sessionId() {
|
|
295
|
-
return transport.sessionId;
|
|
296
|
-
},
|
|
297
|
-
setProtocolVersion: transport.setProtocolVersion
|
|
298
|
-
? version => transport.setProtocolVersion!(version)
|
|
299
|
-
: undefined,
|
|
292
|
+
throw error;
|
|
293
|
+
}
|
|
300
294
|
};
|
|
301
|
-
|
|
295
|
+
|
|
296
|
+
return transport;
|
|
302
297
|
}
|
|
303
298
|
|
|
304
299
|
export function traceTransportKind(definition: { command?: string; url?: string; socket?: string }, transport: Transport): McpTraceTransport {
|
|
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from "
|
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import { getAgentPath } from "./agent-dir.ts";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
|
-
import { getToolUiResourceUri } from "
|
|
6
|
+
import { getToolUiResourceUri } from "./ui-app-bridge-helpers.ts";
|
|
7
7
|
import type {
|
|
8
8
|
CachedPrompt,
|
|
9
9
|
CachedResource,
|
|
@@ -91,6 +91,7 @@ export function computeServerHash(definition: ServerEntry): string {
|
|
|
91
91
|
url: resolveServerUrl(definition),
|
|
92
92
|
headers: interpolateEnvRecord(definition.headers),
|
|
93
93
|
auth: definition.auth,
|
|
94
|
+
protocolVersion: definition.protocolVersion,
|
|
94
95
|
bearerToken: resolveBearerToken(definition),
|
|
95
96
|
bearerTokenEnv: definition.bearerTokenEnv,
|
|
96
97
|
exposeResources: definition.exposeResources,
|
|
@@ -201,10 +202,10 @@ export function reconstructToolMetadata(
|
|
|
201
202
|
name,
|
|
202
203
|
originalName: tool.name,
|
|
203
204
|
description: tool.description ?? "",
|
|
204
|
-
inputSchema: tool.inputSchema,
|
|
205
|
-
uiResourceUri: tool.uiResourceUri,
|
|
206
|
-
uiVisibility: tool.uiVisibility,
|
|
207
|
-
uiStreamMode: tool.uiStreamMode,
|
|
205
|
+
...(tool.inputSchema !== undefined ? { inputSchema: tool.inputSchema } : {}),
|
|
206
|
+
...(tool.uiResourceUri !== undefined ? { uiResourceUri: tool.uiResourceUri } : {}),
|
|
207
|
+
...(tool.uiVisibility !== undefined ? { uiVisibility: tool.uiVisibility } : {}),
|
|
208
|
+
...(tool.uiStreamMode !== undefined ? { uiStreamMode: tool.uiStreamMode } : {}),
|
|
208
209
|
});
|
|
209
210
|
}
|
|
210
211
|
|
|
@@ -237,14 +238,19 @@ export function reconstructToolMetadata(
|
|
|
237
238
|
export function serializeTools(tools: McpTool[]): CachedTool[] {
|
|
238
239
|
return tools
|
|
239
240
|
.filter(t => t?.name)
|
|
240
|
-
.map(t =>
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
.map(t => {
|
|
242
|
+
const uiResourceUri = tryGetToolUiResourceUri(t);
|
|
243
|
+
const uiVisibility = extractUiToolVisibility(t._meta);
|
|
244
|
+
const uiStreamMode = extractToolUiStreamMode(t._meta);
|
|
245
|
+
return {
|
|
246
|
+
name: t.name,
|
|
247
|
+
...(t.description !== undefined ? { description: t.description } : {}),
|
|
248
|
+
...(t.inputSchema !== undefined ? { inputSchema: t.inputSchema } : {}),
|
|
249
|
+
...(uiResourceUri !== undefined ? { uiResourceUri } : {}),
|
|
250
|
+
...(uiVisibility !== undefined ? { uiVisibility } : {}),
|
|
251
|
+
...(uiStreamMode !== undefined ? { uiStreamMode } : {}),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
export function serializeResources(resources: McpResource[]): CachedResource[] {
|
|
@@ -253,7 +259,7 @@ export function serializeResources(resources: McpResource[]): CachedResource[] {
|
|
|
253
259
|
.map(r => ({
|
|
254
260
|
uri: r.uri,
|
|
255
261
|
name: r.name,
|
|
256
|
-
description: r.description,
|
|
262
|
+
...(r.description !== undefined ? { description: r.description } : {}),
|
|
257
263
|
}));
|
|
258
264
|
}
|
|
259
265
|
|
|
@@ -262,15 +268,17 @@ export function serializePrompts(prompts: McpPrompt[]): CachedPrompt[] {
|
|
|
262
268
|
.filter(prompt => prompt?.name)
|
|
263
269
|
.map(prompt => ({
|
|
264
270
|
name: prompt.name,
|
|
265
|
-
title: prompt.title,
|
|
266
|
-
description: prompt.description,
|
|
267
|
-
|
|
268
|
-
?
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
...(prompt.title !== undefined ? { title: prompt.title } : {}),
|
|
272
|
+
...(prompt.description !== undefined ? { description: prompt.description } : {}),
|
|
273
|
+
...(Array.isArray(prompt.arguments)
|
|
274
|
+
? {
|
|
275
|
+
arguments: prompt.arguments.filter(argument => argument?.name).map(argument => ({
|
|
276
|
+
name: argument.name,
|
|
277
|
+
...(argument.description !== undefined ? { description: argument.description } : {}),
|
|
278
|
+
...(argument.required !== undefined ? { required: argument.required } : {}),
|
|
279
|
+
})),
|
|
280
|
+
}
|
|
281
|
+
: {}),
|
|
274
282
|
}));
|
|
275
283
|
}
|
|
276
284
|
|
|
@@ -285,15 +293,15 @@ export function reconstructPromptMetadata(
|
|
|
285
293
|
const args: McpPromptArgument[] = Array.isArray(prompt.arguments)
|
|
286
294
|
? prompt.arguments.filter(argument => argument?.name).map(argument => ({
|
|
287
295
|
name: argument.name,
|
|
288
|
-
description: argument.description,
|
|
289
|
-
required: argument.required,
|
|
296
|
+
...(argument.description !== undefined ? { description: argument.description } : {}),
|
|
297
|
+
...(argument.required !== undefined ? { required: argument.required } : {}),
|
|
290
298
|
}))
|
|
291
299
|
: [];
|
|
292
300
|
return {
|
|
293
301
|
serverName,
|
|
294
302
|
originalName: prompt.name,
|
|
295
303
|
commandName: formatPromptCommandName(prompt.name, serverName, effectivePrefix),
|
|
296
|
-
title: prompt.title,
|
|
304
|
+
...(prompt.title !== undefined ? { title: prompt.title } : {}),
|
|
297
305
|
description: prompt.description ?? "",
|
|
298
306
|
arguments: args,
|
|
299
307
|
};
|
|
@@ -95,6 +95,7 @@ function parseNpxArgs(args: string[]): ParsedInvocation | null {
|
|
|
95
95
|
|
|
96
96
|
for (let i = 0; i < before.length; i++) {
|
|
97
97
|
const arg = before[i];
|
|
98
|
+
if (arg === undefined) return null;
|
|
98
99
|
if (foundFirstPositional) {
|
|
99
100
|
positionals.push(arg);
|
|
100
101
|
continue;
|
|
@@ -149,6 +150,7 @@ function parseNpmExecArgs(args: string[]): ParsedInvocation | null {
|
|
|
149
150
|
let packageSpec: string | undefined;
|
|
150
151
|
for (let i = 0; i < before.length; i++) {
|
|
151
152
|
const arg = before[i];
|
|
153
|
+
if (arg === undefined) return null;
|
|
152
154
|
if (arg === "-y" || arg === "--yes") continue;
|
|
153
155
|
if (arg === "--package") {
|
|
154
156
|
const value = before[i + 1];
|
|
@@ -239,7 +241,7 @@ function resolveFromNpmCache(packageSpec: string, binName?: string): NpxCacheEnt
|
|
|
239
241
|
return {
|
|
240
242
|
resolvedBin,
|
|
241
243
|
resolvedAt: Date.now(),
|
|
242
|
-
packageVersion: pkg
|
|
244
|
+
...(pkg?.version !== undefined ? { packageVersion: pkg.version } : {}),
|
|
243
245
|
isJs,
|
|
244
246
|
};
|
|
245
247
|
}
|
|
@@ -329,9 +331,9 @@ function parsePackageSpec(spec: string): ParsedPackageSpec | null {
|
|
|
329
331
|
const normalizedVersion = requestedVersion?.replace(/^=/, "").replace(/^v/i, "");
|
|
330
332
|
return {
|
|
331
333
|
packageName,
|
|
332
|
-
|
|
333
|
-
? normalizedVersion
|
|
334
|
-
:
|
|
334
|
+
...(normalizedVersion && EXACT_PACKAGE_VERSION_RE.test(normalizedVersion)
|
|
335
|
+
? { exactVersion: normalizedVersion }
|
|
336
|
+
: {}),
|
|
335
337
|
};
|
|
336
338
|
}
|
|
337
339
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// oauth-handler.ts - OAuth token compatibility helpers for MCP servers
|
|
2
|
-
import type { OAuthTokens } from "@modelcontextprotocol/
|
|
2
|
+
import type { OAuthTokens } from "@modelcontextprotocol/client";
|
|
3
3
|
import { getAuthEntry } from "./mcp-auth.ts";
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -30,7 +30,9 @@ export function loadOnboardingState(): McpOnboardingState {
|
|
|
30
30
|
version: 1,
|
|
31
31
|
sharedConfigHintShown: raw.sharedConfigHintShown === true,
|
|
32
32
|
setupCompleted: raw.setupCompleted === true,
|
|
33
|
-
|
|
33
|
+
...(typeof raw.lastDiscoveryFingerprint === "string"
|
|
34
|
+
? { lastDiscoveryFingerprint: raw.lastDiscoveryFingerprint }
|
|
35
|
+
: {}),
|
|
34
36
|
};
|
|
35
37
|
} catch {
|
|
36
38
|
return { ...DEFAULT_STATE };
|
|
@@ -52,17 +54,23 @@ export function updateOnboardingState(updater: (state: McpOnboardingState) => Mc
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export function markSharedConfigHintShown(fingerprint?: string): McpOnboardingState {
|
|
55
|
-
return updateOnboardingState((state) =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
return updateOnboardingState((state) => {
|
|
58
|
+
const lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;
|
|
59
|
+
return {
|
|
60
|
+
...state,
|
|
61
|
+
sharedConfigHintShown: true,
|
|
62
|
+
...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
export function markSetupCompleted(fingerprint?: string): McpOnboardingState {
|
|
63
|
-
return updateOnboardingState((state) =>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
return updateOnboardingState((state) => {
|
|
69
|
+
const lastDiscoveryFingerprint = fingerprint ?? state.lastDiscoveryFingerprint;
|
|
70
|
+
return {
|
|
71
|
+
...state,
|
|
72
|
+
setupCompleted: true,
|
|
73
|
+
...(lastDiscoveryFingerprint !== undefined ? { lastDiscoveryFingerprint } : {}),
|
|
74
|
+
};
|
|
75
|
+
});
|
|
68
76
|
}
|