@springbrand/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -0
- package/dist/commands/auth.d.ts +4 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +241 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/check-version.d.ts +3 -0
- package/dist/commands/check-version.d.ts.map +1 -0
- package/dist/commands/check-version.js +112 -0
- package/dist/commands/check-version.js.map +1 -0
- package/dist/commands/config-claude.d.ts +4 -0
- package/dist/commands/config-claude.d.ts.map +1 -0
- package/dist/commands/config-claude.js +78 -0
- package/dist/commands/config-claude.js.map +1 -0
- package/dist/commands/connect.d.ts +41 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +901 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/doctor.d.ts +6 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +124 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/upgrade.d.ts +9 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +133 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agent-detect.d.ts +33 -0
- package/dist/lib/agent-detect.d.ts.map +1 -0
- package/dist/lib/agent-detect.js +81 -0
- package/dist/lib/agent-detect.js.map +1 -0
- package/dist/lib/agent-launcher.d.ts +22 -0
- package/dist/lib/agent-launcher.d.ts.map +1 -0
- package/dist/lib/agent-launcher.js +67 -0
- package/dist/lib/agent-launcher.js.map +1 -0
- package/dist/lib/auth.d.ts +90 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +327 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/bundled-skill.d.ts +5 -0
- package/dist/lib/bundled-skill.d.ts.map +1 -0
- package/dist/lib/bundled-skill.js +13 -0
- package/dist/lib/bundled-skill.js.map +1 -0
- package/dist/lib/claude-config.d.ts +19 -0
- package/dist/lib/claude-config.d.ts.map +1 -0
- package/dist/lib/claude-config.js +202 -0
- package/dist/lib/claude-config.js.map +1 -0
- package/dist/lib/cli-install.d.ts +40 -0
- package/dist/lib/cli-install.d.ts.map +1 -0
- package/dist/lib/cli-install.js +42 -0
- package/dist/lib/cli-install.js.map +1 -0
- package/dist/lib/command-code-config.d.ts +5 -0
- package/dist/lib/command-code-config.d.ts.map +1 -0
- package/dist/lib/command-code-config.js +16 -0
- package/dist/lib/command-code-config.js.map +1 -0
- package/dist/lib/connect-all-auth.d.ts +21 -0
- package/dist/lib/connect-all-auth.d.ts.map +1 -0
- package/dist/lib/connect-all-auth.js +113 -0
- package/dist/lib/connect-all-auth.js.map +1 -0
- package/dist/lib/connect-all-summary.d.ts +10 -0
- package/dist/lib/connect-all-summary.d.ts.map +1 -0
- package/dist/lib/connect-all-summary.js +153 -0
- package/dist/lib/connect-all-summary.js.map +1 -0
- package/dist/lib/connect-all-uninstall.d.ts +7 -0
- package/dist/lib/connect-all-uninstall.d.ts.map +1 -0
- package/dist/lib/connect-all-uninstall.js +249 -0
- package/dist/lib/connect-all-uninstall.js.map +1 -0
- package/dist/lib/connect-all.d.ts +42 -0
- package/dist/lib/connect-all.d.ts.map +1 -0
- package/dist/lib/connect-all.js +438 -0
- package/dist/lib/connect-all.js.map +1 -0
- package/dist/lib/connect-auth.d.ts +7 -0
- package/dist/lib/connect-auth.d.ts.map +1 -0
- package/dist/lib/connect-auth.js +50 -0
- package/dist/lib/connect-auth.js.map +1 -0
- package/dist/lib/connect-clients.d.ts +108 -0
- package/dist/lib/connect-clients.d.ts.map +1 -0
- package/dist/lib/connect-clients.js +358 -0
- package/dist/lib/connect-clients.js.map +1 -0
- package/dist/lib/connect-fallback.d.ts +27 -0
- package/dist/lib/connect-fallback.d.ts.map +1 -0
- package/dist/lib/connect-fallback.js +166 -0
- package/dist/lib/connect-fallback.js.map +1 -0
- package/dist/lib/connect-picker.d.ts +19 -0
- package/dist/lib/connect-picker.d.ts.map +1 -0
- package/dist/lib/connect-picker.js +155 -0
- package/dist/lib/connect-picker.js.map +1 -0
- package/dist/lib/connect-preflight.d.ts +17 -0
- package/dist/lib/connect-preflight.d.ts.map +1 -0
- package/dist/lib/connect-preflight.js +81 -0
- package/dist/lib/connect-preflight.js.map +1 -0
- package/dist/lib/connect-runtime.d.ts +109 -0
- package/dist/lib/connect-runtime.d.ts.map +1 -0
- package/dist/lib/connect-runtime.js +360 -0
- package/dist/lib/connect-runtime.js.map +1 -0
- package/dist/lib/constants.d.ts +23 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +87 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/cursor-config.d.ts +16 -0
- package/dist/lib/cursor-config.d.ts.map +1 -0
- package/dist/lib/cursor-config.js +34 -0
- package/dist/lib/cursor-config.js.map +1 -0
- package/dist/lib/doctor-checks.d.ts +21 -0
- package/dist/lib/doctor-checks.d.ts.map +1 -0
- package/dist/lib/doctor-checks.js +312 -0
- package/dist/lib/doctor-checks.js.map +1 -0
- package/dist/lib/doctor-repairs.d.ts +11 -0
- package/dist/lib/doctor-repairs.d.ts.map +1 -0
- package/dist/lib/doctor-repairs.js +130 -0
- package/dist/lib/doctor-repairs.js.map +1 -0
- package/dist/lib/doctor-report.d.ts +195 -0
- package/dist/lib/doctor-report.d.ts.map +1 -0
- package/dist/lib/doctor-report.js +102 -0
- package/dist/lib/doctor-report.js.map +1 -0
- package/dist/lib/doctor-telemetry.d.ts +9 -0
- package/dist/lib/doctor-telemetry.d.ts.map +1 -0
- package/dist/lib/doctor-telemetry.js +63 -0
- package/dist/lib/doctor-telemetry.js.map +1 -0
- package/dist/lib/harness-detect.d.ts +33 -0
- package/dist/lib/harness-detect.d.ts.map +1 -0
- package/dist/lib/harness-detect.js +70 -0
- package/dist/lib/harness-detect.js.map +1 -0
- package/dist/lib/harness-spec.d.ts +285 -0
- package/dist/lib/harness-spec.d.ts.map +1 -0
- package/dist/lib/harness-spec.js +268 -0
- package/dist/lib/harness-spec.js.map +1 -0
- package/dist/lib/harness.d.ts +27 -0
- package/dist/lib/harness.d.ts.map +1 -0
- package/dist/lib/harness.js +125 -0
- package/dist/lib/harness.js.map +1 -0
- package/dist/lib/hermes-config.d.ts +22 -0
- package/dist/lib/hermes-config.d.ts.map +1 -0
- package/dist/lib/hermes-config.js +76 -0
- package/dist/lib/hermes-config.js.map +1 -0
- package/dist/lib/hermes-env.d.ts +19 -0
- package/dist/lib/hermes-env.d.ts.map +1 -0
- package/dist/lib/hermes-env.js +169 -0
- package/dist/lib/hermes-env.js.map +1 -0
- package/dist/lib/hermes-plugin.d.ts +40 -0
- package/dist/lib/hermes-plugin.d.ts.map +1 -0
- package/dist/lib/hermes-plugin.js +168 -0
- package/dist/lib/hermes-plugin.js.map +1 -0
- package/dist/lib/install-root.d.ts +18 -0
- package/dist/lib/install-root.d.ts.map +1 -0
- package/dist/lib/install-root.js +55 -0
- package/dist/lib/install-root.js.map +1 -0
- package/dist/lib/mcp-config.d.ts +36 -0
- package/dist/lib/mcp-config.d.ts.map +1 -0
- package/dist/lib/mcp-config.js +90 -0
- package/dist/lib/mcp-config.js.map +1 -0
- package/dist/lib/mcp-endpoint.d.ts +16 -0
- package/dist/lib/mcp-endpoint.d.ts.map +1 -0
- package/dist/lib/mcp-endpoint.js +41 -0
- package/dist/lib/mcp-endpoint.js.map +1 -0
- package/dist/lib/mcp-json-config.d.ts +43 -0
- package/dist/lib/mcp-json-config.d.ts.map +1 -0
- package/dist/lib/mcp-json-config.js +164 -0
- package/dist/lib/mcp-json-config.js.map +1 -0
- package/dist/lib/notice.d.ts +13 -0
- package/dist/lib/notice.d.ts.map +1 -0
- package/dist/lib/notice.js +73 -0
- package/dist/lib/notice.js.map +1 -0
- package/dist/lib/omp-config.d.ts +18 -0
- package/dist/lib/omp-config.d.ts.map +1 -0
- package/dist/lib/omp-config.js +73 -0
- package/dist/lib/omp-config.js.map +1 -0
- package/dist/lib/output.d.ts +22 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +92 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pi-config.d.ts +27 -0
- package/dist/lib/pi-config.d.ts.map +1 -0
- package/dist/lib/pi-config.js +113 -0
- package/dist/lib/pi-config.js.map +1 -0
- package/dist/lib/registration-detect.d.ts +28 -0
- package/dist/lib/registration-detect.d.ts.map +1 -0
- package/dist/lib/registration-detect.js +563 -0
- package/dist/lib/registration-detect.js.map +1 -0
- package/dist/lib/setup-telemetry.d.ts +273 -0
- package/dist/lib/setup-telemetry.d.ts.map +1 -0
- package/dist/lib/setup-telemetry.js +309 -0
- package/dist/lib/setup-telemetry.js.map +1 -0
- package/dist/lib/signals.d.ts +14 -0
- package/dist/lib/signals.d.ts.map +1 -0
- package/dist/lib/signals.js +29 -0
- package/dist/lib/signals.js.map +1 -0
- package/dist/lib/skill-install.d.ts +10 -0
- package/dist/lib/skill-install.d.ts.map +1 -0
- package/dist/lib/skill-install.js +94 -0
- package/dist/lib/skill-install.js.map +1 -0
- package/dist/lib/skill-paths.d.ts +7 -0
- package/dist/lib/skill-paths.d.ts.map +1 -0
- package/dist/lib/skill-paths.js +37 -0
- package/dist/lib/skill-paths.js.map +1 -0
- package/dist/lib/skill-vendor.d.ts +20 -0
- package/dist/lib/skill-vendor.d.ts.map +1 -0
- package/dist/lib/skill-vendor.js +215 -0
- package/dist/lib/skill-vendor.js.map +1 -0
- package/dist/lib/skill.d.ts +14 -0
- package/dist/lib/skill.d.ts.map +1 -0
- package/dist/lib/skill.js +87 -0
- package/dist/lib/skill.js.map +1 -0
- package/dist/lib/verify.d.ts +35 -0
- package/dist/lib/verify.d.ts.map +1 -0
- package/dist/lib/verify.js +169 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +54 -0
- package/dist/program.js.map +1 -0
- package/package.json +55 -0
- package/skill/springbrand-action-api/SKILL.md +49 -0
- package/skill/springbrand-action-api/references/action-aliases.md +156 -0
- package/skill/springbrand-action-api/references/action-discovery.md +95 -0
- package/skill/springbrand-connector/SKILL.md +49 -0
- package/skill/springbrand-gtm/SKILL.md +34 -0
- package/skill/springbrand-platform/SKILL.md +55 -0
- package/skill/springbrand-platform/references/plugin-discovery.md +94 -0
- package/skill/use-springbrand/SKILL.md +70 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:doctor-checks.d.ts + doctor-checks.impl.js */
|
|
2
|
+
import { apiKeyStatus } from './auth.js';
|
|
3
|
+
import { CLI_VERSION } from './constants.js';
|
|
4
|
+
import { AuthMode, Registered } from './harness-detect.js';
|
|
5
|
+
import { resolveHermesHome } from './hermes-env.js';
|
|
6
|
+
import { hermesWebBackendsOurs, readHermesPluginStatus, } from './hermes-plugin.js';
|
|
7
|
+
import { endpointOf, isDefaultEndpoint } from './mcp-endpoint.js';
|
|
8
|
+
import { PI_ADAPTER_INSTALL_COMMAND, piMcpAdapterState } from './pi-config.js';
|
|
9
|
+
import { boundedVersion } from './output.js';
|
|
10
|
+
import { verifyMcpHealth } from './verify.js';
|
|
11
|
+
// A green auth mode with a red auth call proves nothing, so the call's verdict gates the claim.
|
|
12
|
+
export function provesHarnessReach(status, keyAuth, healthOk, mcpUrl) {
|
|
13
|
+
// An endpoint doctor could not reach proves nothing about a harness pointed at it.
|
|
14
|
+
if (!healthOk)
|
|
15
|
+
return false;
|
|
16
|
+
if (pointsElsewhere(status.registeredUrl, mcpUrl))
|
|
17
|
+
return false;
|
|
18
|
+
if (status.registered !== Registered.Yes)
|
|
19
|
+
return false;
|
|
20
|
+
if (status.connected === true)
|
|
21
|
+
return true;
|
|
22
|
+
// Symmetric with registrationVerdict: a harness saying it cannot reach us is decisive.
|
|
23
|
+
if (status.connected === false)
|
|
24
|
+
return false;
|
|
25
|
+
// The harness's own key must have verified; the CLI's verdict says nothing about it.
|
|
26
|
+
return status.authMode === AuthMode.ApiKey && keyAuth?.ok === true;
|
|
27
|
+
}
|
|
28
|
+
// Reports the version, never judges it: staleness is the server's call via X-SP-Notice.
|
|
29
|
+
export function checkCliVersion() {
|
|
30
|
+
return {
|
|
31
|
+
id: 'cli-version',
|
|
32
|
+
title: `CLI ${CLI_VERSION}`,
|
|
33
|
+
status: 'pass',
|
|
34
|
+
detail: `${CLI_VERSION}; the server reports staleness via X-SP-Notice`,
|
|
35
|
+
harness: null,
|
|
36
|
+
scope: 'info',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function checkConnectivity(mcpUrl) {
|
|
40
|
+
const health = await verifyMcpHealth(mcpUrl);
|
|
41
|
+
return {
|
|
42
|
+
id: 'mcp-connectivity',
|
|
43
|
+
title: 'MCP endpoint reachable',
|
|
44
|
+
status: health.ok ? 'pass' : 'fail',
|
|
45
|
+
detail: health.ok ? mcpUrl : (health.code ?? 'the endpoint is unreachable'),
|
|
46
|
+
// Harness-scoped: the CLI's own reachability is `cli-auth-call`'s claim.
|
|
47
|
+
harness: null,
|
|
48
|
+
scope: 'harness',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Host alone let `/wrong-path` and plain `http://` through and claim the harness reaches us. */
|
|
52
|
+
function pointsElsewhere(registeredUrl, mcpUrl) {
|
|
53
|
+
if (!registeredUrl)
|
|
54
|
+
return undefined;
|
|
55
|
+
try {
|
|
56
|
+
const registered = endpointOf(registeredUrl);
|
|
57
|
+
return registered === endpointOf(mcpUrl) ? undefined : registered;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// An endpoint that will not parse cannot be shown to match, so it does not.
|
|
61
|
+
return 'an unparseable endpoint';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Either it reads the CLI's key at runtime or it holds a copy: the CLI's own verdict covers both. */
|
|
65
|
+
function runsOnCliCredential(status) {
|
|
66
|
+
return status.usesCliKey === true || status.keyMatchesCliKey === true;
|
|
67
|
+
}
|
|
68
|
+
function keyedVerdict(status, keyAuth, cliKeyMissing) {
|
|
69
|
+
if (!keyAuth) {
|
|
70
|
+
// Its auth is the CLI credential; a warn would exit 0.
|
|
71
|
+
if (runsOnCliCredential(status)) {
|
|
72
|
+
return cliKeyMissing
|
|
73
|
+
? {
|
|
74
|
+
status: 'fail',
|
|
75
|
+
detail: 'registered, but it runs on the CLI credential, which is missing or unusable',
|
|
76
|
+
}
|
|
77
|
+
: // Reachable with a key only when `--url` skipped verification.
|
|
78
|
+
{
|
|
79
|
+
status: 'warn',
|
|
80
|
+
detail: 'registered, but its CLI credential was not verified against this endpoint',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// A bare warn beside exit 0 reads as a pass.
|
|
84
|
+
const because = status.keyReason ?? 'the CLI cannot verify a key it does not hold';
|
|
85
|
+
return { status: 'warn', detail: `registered, but ${because}, so its reach is unproven` };
|
|
86
|
+
}
|
|
87
|
+
if (keyAuth.ok) {
|
|
88
|
+
return {
|
|
89
|
+
status: 'pass',
|
|
90
|
+
detail: 'registered, auth mode api-key (key accepted by the SpringBrand MCP endpoint)',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Only a refusal blames the key; a rate limit or a verification outage would have connect loop.
|
|
94
|
+
if (keyAuth.kind === 'credential_rejected') {
|
|
95
|
+
return { status: 'fail', detail: `registered, but SpringBrand refused its API key: ${keyAuth.code ?? 'unknown'}` };
|
|
96
|
+
}
|
|
97
|
+
return { status: 'warn', detail: `registered, key could not be verified (${keyAuth.code ?? 'unknown'})` };
|
|
98
|
+
}
|
|
99
|
+
function registrationVerdict(status, mcpUrl, keyAuth, cliKeyMissing) {
|
|
100
|
+
if (!status.detected)
|
|
101
|
+
return { status: 'skip', detail: 'harness not installed' };
|
|
102
|
+
if (status.registered === Registered.Unknown) {
|
|
103
|
+
return { status: 'warn', detail: status.reason ?? 'could not determine registration' };
|
|
104
|
+
}
|
|
105
|
+
if (status.registered === Registered.Yes) {
|
|
106
|
+
// A `springbrand` entry aimed at a dev server is registered and still cannot reach SpringBrand.
|
|
107
|
+
const elsewhere = pointsElsewhere(status.registeredUrl, mcpUrl);
|
|
108
|
+
if (elsewhere) {
|
|
109
|
+
return {
|
|
110
|
+
status: 'fail',
|
|
111
|
+
detail: `registered, but points at ${elsewhere} rather than ${endpointOf(mcpUrl)}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Ordered before the key check: the harness's own verdict wins.
|
|
115
|
+
if (status.connected === false) {
|
|
116
|
+
return {
|
|
117
|
+
status: 'warn',
|
|
118
|
+
detail: 'registered, but the harness reports it cannot reach SpringBrand; sign in again there',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Symmetric with provesHarnessReach, which already reads a handshake as decisive.
|
|
122
|
+
if (status.connected === true) {
|
|
123
|
+
return { status: 'pass', detail: 'registered, and the harness reports it reaches SpringBrand' };
|
|
124
|
+
}
|
|
125
|
+
// Widening past api-key would warn every healthy oauth install.
|
|
126
|
+
if (status.authMode === AuthMode.ApiKey)
|
|
127
|
+
return keyedVerdict(status, keyAuth, cliKeyMissing);
|
|
128
|
+
// Recorded, not verified: it never feeds provesHarnessReach.
|
|
129
|
+
if (status.recordedAuthMode) {
|
|
130
|
+
return {
|
|
131
|
+
status: 'pass',
|
|
132
|
+
detail: `registered, auth mode ${status.recordedAuthMode} ` +
|
|
133
|
+
'(recorded at connect; this harness does not report its headers)',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// A probe that had to explain itself to reach `yes` is the only thing that explains `unknown`.
|
|
137
|
+
const because = status.reason ? ` (${status.reason})` : '';
|
|
138
|
+
return { status: 'pass', detail: `registered, auth mode ${status.authMode}${because}` };
|
|
139
|
+
}
|
|
140
|
+
// Connected once and now absent is a broken install; never connected is just not set up.
|
|
141
|
+
return status.connectedBefore
|
|
142
|
+
? { status: 'fail', detail: 'connected previously but SpringBrand is no longer registered' }
|
|
143
|
+
: { status: 'warn', detail: 'installed but SpringBrand was never connected' };
|
|
144
|
+
}
|
|
145
|
+
export function checkRegistration(status, mcpUrl, keyAuth, cliKeyMissing) {
|
|
146
|
+
return {
|
|
147
|
+
id: 'harness-registration',
|
|
148
|
+
title: `${status.harness} registration`,
|
|
149
|
+
harness: status.harness,
|
|
150
|
+
scope: 'harness',
|
|
151
|
+
...registrationVerdict(status, mcpUrl, keyAuth, cliKeyMissing),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export function checkCredential() {
|
|
155
|
+
const resolved = apiKeyStatus();
|
|
156
|
+
const check = {
|
|
157
|
+
id: 'cli-credential',
|
|
158
|
+
title: 'CLI credential',
|
|
159
|
+
status: 'key' in resolved ? 'pass' : 'fail',
|
|
160
|
+
detail: 'key' in resolved ? `key present from ${resolved.source}` : resolved.error,
|
|
161
|
+
harness: null,
|
|
162
|
+
scope: 'cli',
|
|
163
|
+
};
|
|
164
|
+
return 'key' in resolved ? { check, key: resolved.key } : { check };
|
|
165
|
+
}
|
|
166
|
+
export function checkAuthCall(auth) {
|
|
167
|
+
if (!auth) {
|
|
168
|
+
return {
|
|
169
|
+
id: 'cli-auth-call',
|
|
170
|
+
title: 'Authenticated call',
|
|
171
|
+
status: 'skip',
|
|
172
|
+
detail: 'no credential to test',
|
|
173
|
+
harness: null,
|
|
174
|
+
scope: 'cli',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// A rate limit or a verification outage is not a broken setup, so only a refusal fails.
|
|
178
|
+
const failed = auth.kind === 'credential_rejected';
|
|
179
|
+
return {
|
|
180
|
+
id: 'cli-auth-call',
|
|
181
|
+
title: 'Authenticated call',
|
|
182
|
+
status: auth.ok ? 'pass' : failed ? 'fail' : 'warn',
|
|
183
|
+
detail: auth.ok
|
|
184
|
+
? `the SpringBrand MCP endpoint accepted the CLI key${auth.identity ? ` (account ${auth.identity.accountId}, ${auth.identity.environment})` : ''}`
|
|
185
|
+
: (auth.code ?? 'the authenticated call failed'),
|
|
186
|
+
harness: null,
|
|
187
|
+
scope: 'cli',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
export function verifyHarnessKey(status, cliAuth, mcpUrl) {
|
|
191
|
+
if (!isDefaultEndpoint(mcpUrl))
|
|
192
|
+
return undefined;
|
|
193
|
+
// `pointsElsewhere` already fails; a second reason only misleads.
|
|
194
|
+
if (pointsElsewhere(status.registeredUrl, mcpUrl))
|
|
195
|
+
return undefined;
|
|
196
|
+
// The CLI never holds a harness's key, so only its own credential can be verified.
|
|
197
|
+
return runsOnCliCredential(status) ? cliAuth : undefined;
|
|
198
|
+
}
|
|
199
|
+
// `ok` is backends && key; provider_available re-reads the key through the provider.
|
|
200
|
+
function hermesPluginStatusVerdict(status) {
|
|
201
|
+
if (status.ok) {
|
|
202
|
+
return status.provider_available === false
|
|
203
|
+
? { status: 'warn', detail: 'plugin configured, but its provider cannot see the key' }
|
|
204
|
+
: {
|
|
205
|
+
status: 'pass',
|
|
206
|
+
detail: `plugin ${status.plugin_version ?? 'installed'}; backends and key configured`,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (!status.web_backend_configured) {
|
|
210
|
+
return {
|
|
211
|
+
status: 'warn',
|
|
212
|
+
detail: 'plugin installed but the web backends do not point at springbrand',
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
status: 'fail',
|
|
217
|
+
detail: 'web backends point at springbrand but no key resolves from ' +
|
|
218
|
+
'SPRINGBRAND_API_KEY or MCP_SPRINGBRAND_API_KEY',
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/** An unreadable config cannot prove the backends are ours, so doctor never fails on it. */
|
|
222
|
+
function backendsOurs(home) {
|
|
223
|
+
try {
|
|
224
|
+
return hermesWebBackendsOurs(home);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function hermesPluginVerdict(home) {
|
|
231
|
+
const probe = readHermesPluginStatus(home);
|
|
232
|
+
if (probe.state === 'not_installed') {
|
|
233
|
+
// Backends naming an absent provider are broken; never-installed keeps exit 0.
|
|
234
|
+
return backendsOurs(home)
|
|
235
|
+
? {
|
|
236
|
+
status: 'fail',
|
|
237
|
+
detail: 'web backends point at springbrand but the plugin is not installed or not enabled',
|
|
238
|
+
}
|
|
239
|
+
: { status: 'warn', detail: 'the SpringBrand web plugin is not installed or not enabled' };
|
|
240
|
+
}
|
|
241
|
+
if (probe.state === 'unreachable') {
|
|
242
|
+
return { status: 'warn', detail: '`hermes springbrand status` did not respond in time' };
|
|
243
|
+
}
|
|
244
|
+
if (probe.state === 'unparseable') {
|
|
245
|
+
return {
|
|
246
|
+
status: 'warn',
|
|
247
|
+
detail: '`hermes springbrand status --json` returned unparseable output',
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
...hermesPluginStatusVerdict(probe.status),
|
|
252
|
+
// Machine-supplied, so it is bounded here rather than trusted onward.
|
|
253
|
+
observedVersion: boundedVersion(probe.status.plugin_version ?? ''),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
// Warn, not fail: the SpringBrand skill works in pi with no adapter, so nothing is broken.
|
|
257
|
+
export function checkPiAdapter(status) {
|
|
258
|
+
const base = {
|
|
259
|
+
id: 'pi-adapter',
|
|
260
|
+
title: 'Pi MCP adapter',
|
|
261
|
+
harness: 'pi',
|
|
262
|
+
scope: 'harness',
|
|
263
|
+
};
|
|
264
|
+
if (!status.detected)
|
|
265
|
+
return { ...base, status: 'skip', detail: 'harness not installed' };
|
|
266
|
+
if (status.registered !== Registered.Yes) {
|
|
267
|
+
const why = status.registered === Registered.Unknown
|
|
268
|
+
? 'pi registration could not be determined'
|
|
269
|
+
: 'SpringBrand is not registered in pi';
|
|
270
|
+
return { ...base, status: 'skip', detail: why };
|
|
271
|
+
}
|
|
272
|
+
const state = piMcpAdapterState();
|
|
273
|
+
if (state === 'installed') {
|
|
274
|
+
return { ...base, status: 'pass', detail: 'installed, so pi reads the springbrand MCP entry' };
|
|
275
|
+
}
|
|
276
|
+
if (state === 'unknown') {
|
|
277
|
+
return {
|
|
278
|
+
...base,
|
|
279
|
+
status: 'warn',
|
|
280
|
+
detail: "could not read pi's settings.json, so whether the adapter is installed is unknown",
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
...base,
|
|
285
|
+
status: 'warn',
|
|
286
|
+
detail: 'not installed, so the springbrand MCP entry is dormant (the SpringBrand skill works without it). ' +
|
|
287
|
+
`Fix: ${PI_ADAPTER_INSTALL_COMMAND}`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
export function checkHermesPlugin(status) {
|
|
291
|
+
const base = {
|
|
292
|
+
id: 'hermes-plugin',
|
|
293
|
+
title: 'Hermes web plugin',
|
|
294
|
+
harness: 'hermes',
|
|
295
|
+
scope: 'harness',
|
|
296
|
+
};
|
|
297
|
+
if (!status.detected) {
|
|
298
|
+
return { check: { ...base, status: 'skip', detail: 'harness not installed' } };
|
|
299
|
+
}
|
|
300
|
+
if (status.registered !== Registered.Yes) {
|
|
301
|
+
return { check: { ...base, status: 'skip', detail: 'SpringBrand is not registered in Hermes' } };
|
|
302
|
+
}
|
|
303
|
+
const resolved = resolveHermesHome();
|
|
304
|
+
if (typeof resolved !== 'string') {
|
|
305
|
+
return {
|
|
306
|
+
check: { ...base, status: 'warn', detail: "could not determine Hermes' home directory" },
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const { observedVersion, ...verdict } = hermesPluginVerdict(resolved);
|
|
310
|
+
return { check: { ...base, ...verdict }, observedVersion };
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=doctor-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-checks.js","sourceRoot":"","sources":["../../src/lib/doctor-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:doctor-repairs.d.ts + doctor-repairs.impl.js */
|
|
2
|
+
import type { DoctorCheck, DoctorOptions, DoctorRepair } from './doctor-report.js';
|
|
3
|
+
import type { RegistrationStatus } from './registration-detect.js';
|
|
4
|
+
export declare function repairsFor(checks: DoctorCheck[], statuses: RegistrationStatus[]): DoctorRepair[];
|
|
5
|
+
export declare function applyRepairs(repairs: DoctorRepair[], options: DoctorOptions): Promise<RepairOutcome[]>;
|
|
6
|
+
export interface RepairOutcome {
|
|
7
|
+
repair: DoctorRepair;
|
|
8
|
+
status: 'repaired' | 'skipped' | 'failed';
|
|
9
|
+
reason?: string;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=doctor-repairs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-repairs.d.ts","sourceRoot":"","sources":["../../src/lib/doctor-repairs.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,YAAY,EAAE,CAgDhG;AAiCD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAwC5G;AAGD,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:doctor-repairs.d.ts + doctor-repairs.impl.js */
|
|
2
|
+
import spawn from 'cross-spawn';
|
|
3
|
+
import { connectHarness } from '../commands/connect.js';
|
|
4
|
+
import { OAUTH_SIGN_IN_TIMEOUT_MS } from './connect-all-auth.js';
|
|
5
|
+
import { Registered } from './harness-detect.js';
|
|
6
|
+
import { detectHumanInitiated } from './harness.js';
|
|
7
|
+
import { errLine } from './output.js';
|
|
8
|
+
export function repairsFor(checks, statuses) {
|
|
9
|
+
const repairs = [];
|
|
10
|
+
// A revoked-but-well-formed key passes the credential check and fails the call; both need login.
|
|
11
|
+
const credentialBroken = checks.some((c) => (c.id === 'cli-credential' || c.id === 'cli-auth-call') && c.status === 'fail');
|
|
12
|
+
// connect writes the stored key, so replace a dead one first.
|
|
13
|
+
if (credentialBroken) {
|
|
14
|
+
repairs.push({
|
|
15
|
+
for: 'cli-credential-invalid',
|
|
16
|
+
action: 'auth-login',
|
|
17
|
+
harness: null,
|
|
18
|
+
command: 'sp auth login',
|
|
19
|
+
unattended_safe: false,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const authCallPassed = checks.some((c) => c.id === 'cli-auth-call' && c.status === 'pass');
|
|
23
|
+
for (const status of statuses) {
|
|
24
|
+
// `unknown` earns nothing: connect would contradict the check's detail.
|
|
25
|
+
// A registered entry that still fails earns one too.
|
|
26
|
+
// `connected: false` is the harness's own no; it only warns, so it earns a repair here.
|
|
27
|
+
const brokenRegistration = status.connected === false ||
|
|
28
|
+
checks.some((c) => c.harness === status.harness && c.id !== 'hermes-plugin' && c.status === 'fail');
|
|
29
|
+
if (!status.detected || (status.registered !== Registered.No && !brokenRegistration))
|
|
30
|
+
continue;
|
|
31
|
+
repairs.push({
|
|
32
|
+
for: status.registered === Registered.Yes
|
|
33
|
+
? `${status.harness}-registration-broken`
|
|
34
|
+
: status.connectedBefore
|
|
35
|
+
? `${status.harness}-registration-lost`
|
|
36
|
+
: `${status.harness}-not-connected`,
|
|
37
|
+
action: 'connect',
|
|
38
|
+
harness: status.harness,
|
|
39
|
+
command: `sp connect ${status.harness}`,
|
|
40
|
+
// Every harness takes a key, so a live one is the only gate.
|
|
41
|
+
unattended_safe: authCallPassed,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// connect hermes reinstalls the plugin; a second row would double it.
|
|
45
|
+
const pluginBroken = checks.some((c) => c.id === 'hermes-plugin' && c.status === 'fail');
|
|
46
|
+
if (pluginBroken && !repairs.some((repair) => repair.harness === 'hermes')) {
|
|
47
|
+
repairs.push({
|
|
48
|
+
for: 'hermes-plugin-broken',
|
|
49
|
+
action: 'connect',
|
|
50
|
+
harness: 'hermes',
|
|
51
|
+
command: 'sp connect hermes',
|
|
52
|
+
unattended_safe: authCallPassed,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return repairs;
|
|
56
|
+
}
|
|
57
|
+
// Shell out rather than import the login flow: `auth login` owns its own browser and prompts.
|
|
58
|
+
// Re-invoke this same entry script, never a global `sp` — under `npx` there is no such
|
|
59
|
+
// binary on PATH, and npx is the install-nothing path doctor exists to serve.
|
|
60
|
+
function runAuthLogin() {
|
|
61
|
+
const entry = process.argv[1];
|
|
62
|
+
if (!entry)
|
|
63
|
+
throw new Error('Could not locate the SpringBrand CLI entry point to re-invoke');
|
|
64
|
+
const result = spawn.sync(process.execPath, [entry, 'auth', 'login', '--source', 'doctor'], {
|
|
65
|
+
stdio: 'inherit',
|
|
66
|
+
});
|
|
67
|
+
if (result.error)
|
|
68
|
+
throw new Error('Could not run `sp auth login`', { cause: result.error });
|
|
69
|
+
if (result.status !== 0) {
|
|
70
|
+
throw new Error(`\`sp auth login\` exited ${result.status ?? 'unknown'}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Dispatches on `action`, never on a null harness: that conflation made the credential fix a no-op. */
|
|
74
|
+
async function runRepair(repair, options, unattended) {
|
|
75
|
+
if (repair.action === 'auth-login')
|
|
76
|
+
return runAuthLogin();
|
|
77
|
+
if (!repair.harness)
|
|
78
|
+
return;
|
|
79
|
+
await connectHarness(repair.harness, {
|
|
80
|
+
mcpUrl: options.mcpUrl,
|
|
81
|
+
launch: false,
|
|
82
|
+
// Unattended: refuse a keyless install, bound the spawns.
|
|
83
|
+
keyAuthOnly: unattended || undefined,
|
|
84
|
+
authTimeoutMs: unattended ? OAUTH_SIGN_IN_TIMEOUT_MS : undefined,
|
|
85
|
+
// Doctor is the CLI; reinstalling it to fix a harness is circular.
|
|
86
|
+
cliInstall: unattended ? false : undefined,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export async function applyRepairs(repairs, options) {
|
|
90
|
+
const interactive = detectHumanInitiated();
|
|
91
|
+
const outcomes = [];
|
|
92
|
+
for (const repair of repairs) {
|
|
93
|
+
if (!interactive && !options.yes) {
|
|
94
|
+
outcomes.push({
|
|
95
|
+
repair,
|
|
96
|
+
status: 'skipped',
|
|
97
|
+
reason: 'no terminal; re-run with --yes to repair unattended',
|
|
98
|
+
});
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (!interactive && !repair.unattended_safe) {
|
|
102
|
+
outcomes.push({
|
|
103
|
+
repair,
|
|
104
|
+
status: 'skipped',
|
|
105
|
+
reason: repair.action === 'auth-login'
|
|
106
|
+
? 'needs a browser sign-in, which has no unattended path'
|
|
107
|
+
: 'credential missing or failing; run sp auth login',
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await runRepair(repair, options, !interactive);
|
|
113
|
+
outcomes.push({ repair, status: 'repaired' });
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
// Connect quotes absolute config paths in its errors, so the raw text stays behind
|
|
117
|
+
// --debug and the user is told where to find it rather than handed a generic dead end.
|
|
118
|
+
if (process.env['SPRINGBRAND_DEBUG']) {
|
|
119
|
+
errLine(e instanceof Error ? (e.stack ?? e.message) : String(e));
|
|
120
|
+
}
|
|
121
|
+
outcomes.push({
|
|
122
|
+
repair,
|
|
123
|
+
status: 'failed',
|
|
124
|
+
reason: `\`${repair.command}\` failed; re-run it directly, or --debug for the raw error`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return outcomes;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=doctor-repairs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-repairs.js","sourceRoot":"","sources":["../../src/lib/doctor-repairs.ts"],"names":[],"mappings":"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"}
|