@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,125 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:harness.d.ts + harness.impl.js */
|
|
2
|
+
// Detects the coding-agent harness that shelled out to the CLI, so usage events
|
|
3
|
+
// can be split by harness (PF-3168). Names become the `X-SP-Client-Name` header
|
|
4
|
+
// value (unenumerated, lowercase-kebab, matching MCP client_name like
|
|
5
|
+
// "claude-code"). Explicit TF_CLIENT_NAME always wins upstream in client.ts.
|
|
6
|
+
//
|
|
7
|
+
// Fingerprints verified by running scripts/harness-probe.mjs (repo root) in each harness.
|
|
8
|
+
// Order matters: wrappers that embed another agent must precede the embedded
|
|
9
|
+
// one. OpenClaw drives Claude Code via `sdk-cli`, so its env carries both
|
|
10
|
+
// CLAUDECODE=1 and OPENCLAW_MCP_*; it must be checked before claude-code.
|
|
11
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
+
const hasVarWithPrefix = (env, prefix) => Object.keys(env).some((key) => key.startsWith(prefix));
|
|
13
|
+
// A new name here must also join KNOWN_CALLING_HARNESSES in
|
|
14
|
+
// frontend/app/api/cli/connect-event/route.ts, or connect telemetry buckets it as `other`.
|
|
15
|
+
// First match wins. Base agents (claude-code) go last so embedding wrappers win.
|
|
16
|
+
const HARNESS_FINGERPRINTS = [
|
|
17
|
+
{ name: 'openclaw', matches: (env) => hasVarWithPrefix(env, 'OPENCLAW_MCP_') },
|
|
18
|
+
// omp hardcodes CLAUDECODE=1, so it must precede claude-code.
|
|
19
|
+
{ name: 'omp', matches: (env) => env['OMPCODE'] === '1' },
|
|
20
|
+
{ name: 'grok', matches: (env) => env['GROK_AGENT'] === '1' },
|
|
21
|
+
// Cursor's VS Code host sets CURSOR_* broadly; CURSOR_AGENT=1 flags the
|
|
22
|
+
// agent specifically, so gate on it rather than the prefix.
|
|
23
|
+
{ name: 'cursor', matches: (env) => env['CURSOR_AGENT'] === '1' },
|
|
24
|
+
// Antigravity is Google's successor to the (deprecated) gemini-cli.
|
|
25
|
+
{ name: 'antigravity', matches: (env) => env['ANTIGRAVITY_AGENT'] === '1' },
|
|
26
|
+
// CODEX_CI seen in probe; CODEX_SANDBOX* appear under seatbelt. Match the
|
|
27
|
+
// prefix so we catch a Codex run regardless of which of its vars are set.
|
|
28
|
+
{ name: 'codex', matches: (env) => hasVarWithPrefix(env, 'CODEX_') },
|
|
29
|
+
{ name: 'hermes', matches: (env) => hasVarWithPrefix(env, 'HERMES_') },
|
|
30
|
+
// COMMANDCODE_SCRATCHPAD lands on every child; a disabled scratchpad leaves no marker.
|
|
31
|
+
{ name: 'command-code', matches: (env) => hasVarWithPrefix(env, 'COMMANDCODE_') },
|
|
32
|
+
// Exact key, not a prefix: opencode writes OPENCODE=1 at startup, reads every OPENCODE_* as config.
|
|
33
|
+
{ name: 'opencode', matches: (env) => Boolean(env['OPENCODE']) },
|
|
34
|
+
// Observed: pi launched from Claude Code inherits CLAUDECODE=1.
|
|
35
|
+
{ name: 'pi', matches: (env) => env['PI_CODING_AGENT'] === 'true' },
|
|
36
|
+
{
|
|
37
|
+
name: 'claude-code',
|
|
38
|
+
matches: (env) => env['CLAUDECODE'] === '1' || Boolean(env['CLAUDE_CODE_ENTRYPOINT']),
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
/** Returns the detected harness name, or null when none match. */
|
|
42
|
+
export function detectHarness(env) {
|
|
43
|
+
const resolved = env ?? process.env;
|
|
44
|
+
return HARNESS_FINGERPRINTS.find((fingerprint) => fingerprint.matches(resolved))?.name ?? null;
|
|
45
|
+
}
|
|
46
|
+
// Markers verified live (PF-3778); exact names only — substring "SANDBOX" misfires.
|
|
47
|
+
const SANDBOX_ENV_VARS = [
|
|
48
|
+
// Codex cloud task container.
|
|
49
|
+
'CODEX_PROXY_CERT',
|
|
50
|
+
// ChatGPT agent-mode container; absent in some sessions, NETWORK below backstops.
|
|
51
|
+
'CAAS_ARTIFACTORY_BASE_URL',
|
|
52
|
+
'CLAUDE_CODE_REMOTE_SESSION_ID',
|
|
53
|
+
'E2B_SANDBOX',
|
|
54
|
+
'MODAL_TASK_ID',
|
|
55
|
+
'MODAL_SANDBOX_ID',
|
|
56
|
+
];
|
|
57
|
+
// Real humans in containerized dev clouds; still container.
|
|
58
|
+
const DEV_CLOUD_ENV_VARS = [
|
|
59
|
+
'CODESPACES',
|
|
60
|
+
'GITPOD_WORKSPACE_ID',
|
|
61
|
+
'CLOUD_SHELL',
|
|
62
|
+
'REPL_ID',
|
|
63
|
+
'KUBERNETES_SERVICE_HOST',
|
|
64
|
+
];
|
|
65
|
+
const CONTAINER_FILES = ['/.dockerenv', '/run/.containerenv'];
|
|
66
|
+
// Container-side line shape only: host mountinfo carries .../containers/<id>/mounts/shm.
|
|
67
|
+
const MOUNTINFO_MARKER = /\/docker\/containers\/[0-9a-f]{64}\/(?:resolv\.conf|hostname|hosts)/;
|
|
68
|
+
const CGROUP_MARKERS = /docker|containerd|kubepods|libpod|lxc/;
|
|
69
|
+
// Per-read isolation: a missing mountinfo must not skip the cgroup probe.
|
|
70
|
+
const safeRead = (fsApi, path) => {
|
|
71
|
+
try {
|
|
72
|
+
return fsApi.readFileSync(path, 'utf8');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
// One verdict per process, like CLI_INVOCATION_ID: events must never disagree.
|
|
79
|
+
let cachedRuntimeEnv;
|
|
80
|
+
// CODEX_CI / CODEX_SANDBOX* / CLAUDECODE mean agent-spawned, not containerized: never here.
|
|
81
|
+
/** Fails open to desktop: a probe error must never break telemetry. */
|
|
82
|
+
export function detectRuntimeEnv(env, fsApi) {
|
|
83
|
+
// Injected args bypass the cache so tests stay independent.
|
|
84
|
+
if (env || fsApi) {
|
|
85
|
+
return computeRuntimeEnv(env ?? process.env, fsApi ?? { existsSync, readFileSync });
|
|
86
|
+
}
|
|
87
|
+
cachedRuntimeEnv ??= computeRuntimeEnv(process.env, { existsSync, readFileSync });
|
|
88
|
+
return cachedRuntimeEnv;
|
|
89
|
+
}
|
|
90
|
+
function computeRuntimeEnv(env, fsApi) {
|
|
91
|
+
// Docs guarantee it is never true locally.
|
|
92
|
+
if (env['CLAUDE_CODE_REMOTE'] === 'true')
|
|
93
|
+
return 'container';
|
|
94
|
+
// Generic name, so match the value (ChatGPT agent mode).
|
|
95
|
+
if (env['NETWORK'] === 'caas_packages_only')
|
|
96
|
+
return 'container';
|
|
97
|
+
if (SANDBOX_ENV_VARS.some((name) => env[name]))
|
|
98
|
+
return 'container';
|
|
99
|
+
if (hasVarWithPrefix(env, 'CODEX_ENV_'))
|
|
100
|
+
return 'container';
|
|
101
|
+
if (DEV_CLOUD_ENV_VARS.some((name) => env[name]))
|
|
102
|
+
return 'container';
|
|
103
|
+
try {
|
|
104
|
+
if (CONTAINER_FILES.some((file) => fsApi.existsSync(file)))
|
|
105
|
+
return 'container';
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// A failed probe is not evidence of a container.
|
|
109
|
+
}
|
|
110
|
+
// Modern docker cgroup is bare 0::/; mountinfo still carries the path.
|
|
111
|
+
if (MOUNTINFO_MARKER.test(safeRead(fsApi, '/proc/self/mountinfo')))
|
|
112
|
+
return 'container';
|
|
113
|
+
if (CGROUP_MARKERS.test(safeRead(fsApi, '/proc/self/cgroup')))
|
|
114
|
+
return 'container';
|
|
115
|
+
return 'desktop';
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* True only when both ends are a real terminal — a human at a prompt. Agents
|
|
119
|
+
* shell out without a TTY, so this reads false for every harness above and is
|
|
120
|
+
* the free agent-vs-human signal behind `X-SP-Human-Initiated`.
|
|
121
|
+
*/
|
|
122
|
+
export function detectHumanInitiated(streams) {
|
|
123
|
+
return Boolean(streams?.stdin.isTTY && streams?.stdout.isTTY);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/lib/harness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:hermes-config.d.ts + hermes-config.impl.js */
|
|
2
|
+
/** Every message about the entry names this path. */
|
|
3
|
+
export declare function hermesConfigPath(home: string): string;
|
|
4
|
+
export declare const HERMES_HEADER_TEMPLATE = "Bearer ${MCP_SPRINGBRAND_API_KEY}";
|
|
5
|
+
/** Both the writer and the gate key on this, so they cannot disagree. */
|
|
6
|
+
export declare const HERMES_MCP_SERVER_KEY = "springbrand";
|
|
7
|
+
/** Connect's gate and doctor's probe share this, so they cannot disagree. */
|
|
8
|
+
export declare function readHermesEntry(home: string): HermesEntry;
|
|
9
|
+
export type HermesEntry = {
|
|
10
|
+
state: 'unreadable';
|
|
11
|
+
} | {
|
|
12
|
+
state: 'unparseable';
|
|
13
|
+
} | {
|
|
14
|
+
state: 'absent';
|
|
15
|
+
} | {
|
|
16
|
+
state: 'disabled';
|
|
17
|
+
usesKeyHeader: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
state: 'enabled';
|
|
20
|
+
usesKeyHeader: boolean;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=hermes-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-config.d.ts","sourceRoot":"","sources":["../../src/lib/hermes-config.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAOxE,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,eAAO,MAAM,sBAAsB,sCAAiC,CAAC;AACrE,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAsCnD,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAsBzD;AAGD,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,YAAY,CAAC;CACvB,GAAG;IACA,KAAK,EAAE,aAAa,CAAC;CACxB,GAAG;IACA,KAAK,EAAE,QAAQ,CAAC;CACnB,GAAG;IACA,KAAK,EAAE,UAAU,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CAC1B,GAAG;IACA,KAAK,EAAE,SAAS,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CAC1B,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:hermes-config.d.ts + hermes-config.impl.js */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { parse } from 'yaml';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { HERMES_KEY_VAR } from './hermes-env.js';
|
|
7
|
+
/** Every message about the entry names this path. */
|
|
8
|
+
export function hermesConfigPath(home) {
|
|
9
|
+
return path.join(home, 'config.yaml');
|
|
10
|
+
}
|
|
11
|
+
// Hermes persists the key as an interpolation template (mcp_config.py:174-182).
|
|
12
|
+
export const HERMES_HEADER_TEMPLATE = `Bearer \${${HERMES_KEY_VAR}}`;
|
|
13
|
+
/** Both the writer and the gate key on this, so they cannot disagree. */
|
|
14
|
+
export const HERMES_MCP_SERVER_KEY = 'springbrand';
|
|
15
|
+
// Foreign file: model only what we read, tolerate the rest.
|
|
16
|
+
const entrySchema = z.looseObject({
|
|
17
|
+
// Anything goes: the runtime defaults unrecognised values to enabled.
|
|
18
|
+
enabled: z.unknown().optional(),
|
|
19
|
+
headers: z.record(z.string(), z.unknown()).optional(),
|
|
20
|
+
});
|
|
21
|
+
const configSchema = z
|
|
22
|
+
.looseObject({
|
|
23
|
+
mcp_servers: z.looseObject({ [HERMES_MCP_SERVER_KEY]: entrySchema.nullish() }).nullish(),
|
|
24
|
+
})
|
|
25
|
+
.nullish();
|
|
26
|
+
const TRUTHY_STRINGS = new Set(['true', '1', 'yes', 'on']);
|
|
27
|
+
const FALSY_STRINGS = new Set(['false', '0', 'no', 'off']);
|
|
28
|
+
/**
|
|
29
|
+
* Mirrors the runtime's _parse_boolish (mcp_tool.py:5656), which decides whether
|
|
30
|
+
* tools are served. `hermes mcp list` coerces differently and disagrees on
|
|
31
|
+
* numbers and "on"; the runtime wins because it is what actually serves.
|
|
32
|
+
*/
|
|
33
|
+
function isEnabled(value) {
|
|
34
|
+
if (value === undefined || value === null)
|
|
35
|
+
return true;
|
|
36
|
+
if (typeof value === 'boolean')
|
|
37
|
+
return value;
|
|
38
|
+
if (typeof value === 'string') {
|
|
39
|
+
const lowered = value.trim().toLowerCase();
|
|
40
|
+
if (TRUTHY_STRINGS.has(lowered))
|
|
41
|
+
return true;
|
|
42
|
+
if (FALSY_STRINGS.has(lowered))
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
/** Only the header template proves this entry uses the seeded key. */
|
|
48
|
+
function hasKeyHeader(headers) {
|
|
49
|
+
const authorization = Object.entries(headers ?? {}).find(([name]) => name.toLowerCase() === 'authorization');
|
|
50
|
+
return authorization?.[1] === HERMES_HEADER_TEMPLATE;
|
|
51
|
+
}
|
|
52
|
+
/** Connect's gate and doctor's probe share this, so they cannot disagree. */
|
|
53
|
+
export function readHermesEntry(home) {
|
|
54
|
+
let raw;
|
|
55
|
+
try {
|
|
56
|
+
raw = fs.readFileSync(hermesConfigPath(home), 'utf8');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { state: 'unreadable' };
|
|
60
|
+
}
|
|
61
|
+
let config;
|
|
62
|
+
try {
|
|
63
|
+
config = configSchema.parse(parse(raw));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return { state: 'unparseable' };
|
|
67
|
+
}
|
|
68
|
+
const entry = config?.mcp_servers?.[HERMES_MCP_SERVER_KEY];
|
|
69
|
+
if (!entry)
|
|
70
|
+
return { state: 'absent' };
|
|
71
|
+
const usesKeyHeader = hasKeyHeader(entry.headers);
|
|
72
|
+
return isEnabled(entry.enabled)
|
|
73
|
+
? { state: 'enabled', usesKeyHeader }
|
|
74
|
+
: { state: 'disabled', usesKeyHeader };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=hermes-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-config.js","sourceRoot":"","sources":["../../src/lib/hermes-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:hermes-env.d.ts + hermes-env.impl.js */
|
|
2
|
+
/** Tests share one process; the resolver result must not. */
|
|
3
|
+
export declare function resetHermesHomeCache(): void;
|
|
4
|
+
/** Asking Hermes beats reimplementing its profile override, which we'd drift from. */
|
|
5
|
+
export declare function resolveHermesHome(): string | HermesHomeFailure;
|
|
6
|
+
export declare const HERMES_KEY_VAR = "MCP_SPRINGBRAND_API_KEY";
|
|
7
|
+
/** Named in every message about the seeded key, so no caller rebuilds the path. */
|
|
8
|
+
export declare function hermesEnvPath(home: string): string;
|
|
9
|
+
export declare function writeHermesKey(home: string, key: string): void;
|
|
10
|
+
/** Doctor needs this to tell key auth from OAuth. */
|
|
11
|
+
export declare function readHermesKey(home: string): string | undefined;
|
|
12
|
+
/** Restores the exact line writeHermesKey replaces, quotes and comment included. */
|
|
13
|
+
export declare function captureHermesKeyRestore(home: string): () => void;
|
|
14
|
+
export declare function removeHermesKey(home: string): boolean;
|
|
15
|
+
export type HermesHomeReason = 'timeout' | 'exit' | 'no_line' | 'relative';
|
|
16
|
+
export interface HermesHomeFailure {
|
|
17
|
+
reason: HermesHomeReason;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=hermes-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-env.d.ts","sourceRoot":"","sources":["../../src/lib/hermes-env.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAclE,6DAA6D;AAC7D,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AACD,sFAAsF;AACtF,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,iBAAiB,CAS9D;AAkBD,eAAO,MAAM,cAAc,4BAA4B,CAAC;AACxD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAiDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAuB9D;AACD,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9D;AACD,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,cAoBnD;AACD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUrD;AAGD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;AAE3E,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,gBAAgB,CAAC;CAC5B"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:hermes-env.d.ts + hermes-env.impl.js */
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import spawn from 'cross-spawn';
|
|
7
|
+
import { HARNESS_PROBE_TIMEOUT_MS } from './constants.js';
|
|
8
|
+
import { sanitizeLine } from './output.js';
|
|
9
|
+
// display_hermes_home() abbreviates under $HOME, so the value is not always absolute.
|
|
10
|
+
const HERMES_HOME_LINE = /^\s*hermes_home:\s*(\S.*?)\s*$/m;
|
|
11
|
+
// Consistency, not speed: doctor's second probe timing out would downgrade
|
|
12
|
+
// hermes-plugin from fail to warn, and doctor --fix skips the repair.
|
|
13
|
+
let cachedHermesHome;
|
|
14
|
+
/** Tests share one process; the resolver result must not. */
|
|
15
|
+
export function resetHermesHomeCache() {
|
|
16
|
+
cachedHermesHome = undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Asking Hermes beats reimplementing its profile override, which we'd drift from. */
|
|
19
|
+
export function resolveHermesHome() {
|
|
20
|
+
if (cachedHermesHome)
|
|
21
|
+
return cachedHermesHome.value;
|
|
22
|
+
const value = probeHermesHome();
|
|
23
|
+
// A timeout is load-dependent; caching it would sink a run a retry still saves.
|
|
24
|
+
if (typeof value === 'string' || value.reason !== 'timeout') {
|
|
25
|
+
cachedHermesHome = { value };
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function probeHermesHome() {
|
|
30
|
+
const result = spawn.sync('hermes', ['dump'], {
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
|
33
|
+
timeout: HARNESS_PROBE_TIMEOUT_MS,
|
|
34
|
+
});
|
|
35
|
+
if (result.error?.code === 'ETIMEDOUT') {
|
|
36
|
+
return { reason: 'timeout' };
|
|
37
|
+
}
|
|
38
|
+
if (result.error || result.status !== 0)
|
|
39
|
+
return { reason: 'exit' };
|
|
40
|
+
const raw = HERMES_HOME_LINE.exec(sanitizeLine(`${result.stdout ?? ''}\n${result.stderr ?? ''}`))?.[1];
|
|
41
|
+
if (!raw)
|
|
42
|
+
return { reason: 'no_line' };
|
|
43
|
+
const expanded = raw === '~' || raw.startsWith('~/') ? path.join(os.homedir(), raw.slice(2)) : raw;
|
|
44
|
+
return path.isAbsolute(expanded) ? expanded : { reason: 'relative' };
|
|
45
|
+
}
|
|
46
|
+
export const HERMES_KEY_VAR = 'MCP_SPRINGBRAND_API_KEY';
|
|
47
|
+
/** Named in every message about the seeded key, so no caller rebuilds the path. */
|
|
48
|
+
export function hermesEnvPath(home) {
|
|
49
|
+
return path.join(home, '.env');
|
|
50
|
+
}
|
|
51
|
+
const MARKER_HEAD = `# springbrand-cli: SpringBrand MCP key, managed by \`sp connect hermes\``;
|
|
52
|
+
const MARKER_TAIL = '# springbrand-cli: end';
|
|
53
|
+
// Keys are `sk-springbrand-<alnum>`; refusing anything else beats shipping unreachable escaping.
|
|
54
|
+
const BARE_SAFE = /^[A-Za-z0-9._\-/:+=]+$/;
|
|
55
|
+
/** Mirrors Hermes' _env_line_defines_key: load_env() parses the export form too. */
|
|
56
|
+
function definesKey(line) {
|
|
57
|
+
const stripped = line.trim().replace(/^export\s+/, '');
|
|
58
|
+
return stripped.startsWith(`${HERMES_KEY_VAR}=`);
|
|
59
|
+
}
|
|
60
|
+
function isMarker(line) {
|
|
61
|
+
return line.trim() === MARKER_HEAD || line.trim() === MARKER_TAIL;
|
|
62
|
+
}
|
|
63
|
+
// A leading BOM would otherwise ride into the first key's name.
|
|
64
|
+
function readLines(envPath) {
|
|
65
|
+
if (!fs.existsSync(envPath))
|
|
66
|
+
return [];
|
|
67
|
+
const raw = fs.readFileSync(envPath);
|
|
68
|
+
// A valid UTF-8 .env has no NUL; every wide encoding does.
|
|
69
|
+
if (raw.includes(0)) {
|
|
70
|
+
throw new Error(`${envPath} contains NUL bytes, so it is a wide encoding or corrupt; SpringBrand can only ` +
|
|
71
|
+
`edit a UTF-8 .env. Re-save it as UTF-8 and retry.`);
|
|
72
|
+
}
|
|
73
|
+
return raw
|
|
74
|
+
.toString('utf8')
|
|
75
|
+
.replace(/^\uFEFF/, '')
|
|
76
|
+
.split(/(?<=\n)/);
|
|
77
|
+
}
|
|
78
|
+
// Hermes preserves the original mode so Docker volume mounts survive (config.py:3921-3929).
|
|
79
|
+
function writeAtomic(envPath, lines) {
|
|
80
|
+
let mode = 0o600;
|
|
81
|
+
try {
|
|
82
|
+
mode = fs.statSync(envPath).mode & 0o777;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// No existing file: 0600 is the right default for credentials.
|
|
86
|
+
}
|
|
87
|
+
const tmp = `${envPath}.${randomUUID()}.tmp`;
|
|
88
|
+
try {
|
|
89
|
+
fs.writeFileSync(tmp, lines.join(''), { encoding: 'utf8', mode });
|
|
90
|
+
// open() applies mode through umask; chmod bypasses it, preserving bits.
|
|
91
|
+
fs.chmodSync(tmp, mode);
|
|
92
|
+
fs.renameSync(tmp, envPath);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
fs.rmSync(tmp, { force: true });
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function writeHermesKey(home, key) {
|
|
100
|
+
const clean = key.replace(/[\r\n]/g, '').trim();
|
|
101
|
+
// An empty key reads as "bad characters" without its own branch.
|
|
102
|
+
if (!clean)
|
|
103
|
+
throw new Error("SpringBrand API key is empty; nothing to write to Hermes' .env");
|
|
104
|
+
if (!BARE_SAFE.test(clean)) {
|
|
105
|
+
throw new Error('SpringBrand API key contains characters that cannot be written to a .env file');
|
|
106
|
+
}
|
|
107
|
+
const envPath = hermesEnvPath(home);
|
|
108
|
+
fs.mkdirSync(home, { recursive: true });
|
|
109
|
+
const lines = readLines(envPath);
|
|
110
|
+
const assignment = `${HERMES_KEY_VAR}=${clean}\n`;
|
|
111
|
+
const index = lines.findIndex(definesKey);
|
|
112
|
+
if (index < 0) {
|
|
113
|
+
if (lines.length && !lines[lines.length - 1].endsWith('\n'))
|
|
114
|
+
lines[lines.length - 1] += '\n';
|
|
115
|
+
lines.push(`${MARKER_HEAD}\n`, assignment, `${MARKER_TAIL}\n`);
|
|
116
|
+
writeAtomic(envPath, lines);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
lines[index] = assignment;
|
|
120
|
+
// load_env() is last-wins; a surviving duplicate would beat this value.
|
|
121
|
+
writeAtomic(envPath, lines.filter((line, i) => i === index || !definesKey(line)));
|
|
122
|
+
}
|
|
123
|
+
/** Doctor needs this to tell key auth from OAuth. */
|
|
124
|
+
export function readHermesKey(home) {
|
|
125
|
+
const line = readLines(hermesEnvPath(home)).find(definesKey);
|
|
126
|
+
if (!line)
|
|
127
|
+
return undefined;
|
|
128
|
+
// We never write quoted values, so a quoted one isn't ours.
|
|
129
|
+
const raw = line
|
|
130
|
+
.trim()
|
|
131
|
+
.replace(/^export\s+/, '')
|
|
132
|
+
.slice(HERMES_KEY_VAR.length + 1)
|
|
133
|
+
.trim();
|
|
134
|
+
return BARE_SAFE.test(raw) ? raw : undefined;
|
|
135
|
+
}
|
|
136
|
+
/** Restores the exact line writeHermesKey replaces, quotes and comment included. */
|
|
137
|
+
export function captureHermesKeyRestore(home) {
|
|
138
|
+
// Raw, not readHermesKey: its parse drops quoted and comment-trailed values.
|
|
139
|
+
const previous = readLines(hermesEnvPath(home)).find(definesKey);
|
|
140
|
+
return () => {
|
|
141
|
+
if (previous === undefined) {
|
|
142
|
+
removeHermesKey(home);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const envPath = hermesEnvPath(home);
|
|
146
|
+
let restored = false;
|
|
147
|
+
const lines = readLines(envPath).flatMap((line) => {
|
|
148
|
+
if (!definesKey(line))
|
|
149
|
+
return [line];
|
|
150
|
+
if (restored)
|
|
151
|
+
return [];
|
|
152
|
+
restored = true;
|
|
153
|
+
return [previous];
|
|
154
|
+
});
|
|
155
|
+
writeAtomic(envPath, restored ? lines : [...lines, previous]);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export function removeHermesKey(home) {
|
|
159
|
+
const envPath = hermesEnvPath(home);
|
|
160
|
+
const lines = readLines(envPath);
|
|
161
|
+
if (!lines.length)
|
|
162
|
+
return false;
|
|
163
|
+
const kept = lines.filter((line) => !definesKey(line) && !isMarker(line));
|
|
164
|
+
if (kept.length === lines.length)
|
|
165
|
+
return false;
|
|
166
|
+
writeAtomic(envPath, kept);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=hermes-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-env.js","sourceRoot":"","sources":["../../src/lib/hermes-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** 复刻自 tiny-fish CLI 编译产物:hermes-plugin.d.ts + hermes-plugin.impl.js */
|
|
2
|
+
import type { InstallOptions } from './cli-install.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export declare const HERMES_PLUGIN_SHA = "496cd63fefd982bbaa8a85ce78ef2270d700984f";
|
|
5
|
+
export declare const HERMES_PLUGIN_VERSION = "0.1.0";
|
|
6
|
+
export declare const HERMES_PLUGIN_MANUAL_INSTALL = "hermes plugins install springbrand-lab/springbrand-web-agent-integrations/hermes --ref 496cd63fefd982bbaa8a85ce78ef2270d700984f --enable";
|
|
7
|
+
export declare function installHermesPlugin(home: string, apiKey: string, { verbose }: Pick<InstallOptions, 'verbose'>): void;
|
|
8
|
+
/** Absent `enabled` reads as enabled, so never write this field-by-field. */
|
|
9
|
+
export declare function writeHermesMcpEntry(home: string, mcpUrl: string): void;
|
|
10
|
+
/** Retracts our row; an absent `enabled` reads as enabled, so a partial one is live. */
|
|
11
|
+
export declare function removeHermesMcpEntry(home: string): void;
|
|
12
|
+
/** After install only: backends must never name an absent provider. */
|
|
13
|
+
export declare function setHermesWebBackends(home: string): void;
|
|
14
|
+
/** Ours-only unsets: a user-chosen backend value survives the uninstall. */
|
|
15
|
+
export declare function clearHermesWebBackends(home: string): void;
|
|
16
|
+
declare const hermesPluginStatusSchema: z.ZodObject<{
|
|
17
|
+
ok: z.ZodBoolean;
|
|
18
|
+
api_key_configured: z.ZodBoolean;
|
|
19
|
+
api_key_env_var: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
plugin_version: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
|
+
provider_available: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
22
|
+
web_backend_configured: z.ZodBoolean;
|
|
23
|
+
}, z.core.$loose>;
|
|
24
|
+
/** `status --json` always exits 0; a non-zero exit means the subcommand is absent. */
|
|
25
|
+
export declare function readHermesPluginStatus(home: string): HermesPluginProbe;
|
|
26
|
+
/** Fallback verdict input when the plugin CLI cannot answer. */
|
|
27
|
+
export declare function hermesWebBackendsOurs(home: string): boolean;
|
|
28
|
+
export type HermesPluginStatus = z.infer<typeof hermesPluginStatusSchema>;
|
|
29
|
+
export type HermesPluginProbe = {
|
|
30
|
+
state: 'not_installed';
|
|
31
|
+
} | {
|
|
32
|
+
state: 'unreachable';
|
|
33
|
+
} | {
|
|
34
|
+
state: 'unparseable';
|
|
35
|
+
} | {
|
|
36
|
+
state: 'ok';
|
|
37
|
+
status: HermesPluginStatus;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=hermes-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-plugin.d.ts","sourceRoot":"","sources":["../../src/lib/hermes-plugin.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAExE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,iBAAiB,6CAA6C,CAAC;AAE5E,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAI7C,eAAO,MAAM,4BAA4B,6IAAgF,CAAC;AAgD1H,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG,IAAI,CAcpH;AAkBD,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAStE;AACD,wFAAwF;AACxF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAID,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAGvD;AAUD,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAKzD;AACD,QAAA,MAAM,wBAAwB;;;;;;;iBAO5B,CAAC;AACH,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAetE;AACD,gEAAgE;AAChE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAGD,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,EAAE,eAAe,CAAC;CAC1B,GAAG;IACA,KAAK,EAAE,aAAa,CAAC;CACxB,GAAG;IACA,KAAK,EAAE,aAAa,CAAC;CACxB,GAAG;IACA,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,kBAAkB,CAAC;CAC9B,CAAC"}
|