@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.
Files changed (222) hide show
  1. package/README.md +167 -0
  2. package/dist/commands/auth.d.ts +4 -0
  3. package/dist/commands/auth.d.ts.map +1 -0
  4. package/dist/commands/auth.js +241 -0
  5. package/dist/commands/auth.js.map +1 -0
  6. package/dist/commands/check-version.d.ts +3 -0
  7. package/dist/commands/check-version.d.ts.map +1 -0
  8. package/dist/commands/check-version.js +112 -0
  9. package/dist/commands/check-version.js.map +1 -0
  10. package/dist/commands/config-claude.d.ts +4 -0
  11. package/dist/commands/config-claude.d.ts.map +1 -0
  12. package/dist/commands/config-claude.js +78 -0
  13. package/dist/commands/config-claude.js.map +1 -0
  14. package/dist/commands/connect.d.ts +41 -0
  15. package/dist/commands/connect.d.ts.map +1 -0
  16. package/dist/commands/connect.js +901 -0
  17. package/dist/commands/connect.js.map +1 -0
  18. package/dist/commands/doctor.d.ts +6 -0
  19. package/dist/commands/doctor.d.ts.map +1 -0
  20. package/dist/commands/doctor.js +124 -0
  21. package/dist/commands/doctor.js.map +1 -0
  22. package/dist/commands/upgrade.d.ts +9 -0
  23. package/dist/commands/upgrade.d.ts.map +1 -0
  24. package/dist/commands/upgrade.js +133 -0
  25. package/dist/commands/upgrade.js.map +1 -0
  26. package/dist/index.d.ts +4 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +15 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/lib/agent-detect.d.ts +33 -0
  31. package/dist/lib/agent-detect.d.ts.map +1 -0
  32. package/dist/lib/agent-detect.js +81 -0
  33. package/dist/lib/agent-detect.js.map +1 -0
  34. package/dist/lib/agent-launcher.d.ts +22 -0
  35. package/dist/lib/agent-launcher.d.ts.map +1 -0
  36. package/dist/lib/agent-launcher.js +67 -0
  37. package/dist/lib/agent-launcher.js.map +1 -0
  38. package/dist/lib/auth.d.ts +90 -0
  39. package/dist/lib/auth.d.ts.map +1 -0
  40. package/dist/lib/auth.js +327 -0
  41. package/dist/lib/auth.js.map +1 -0
  42. package/dist/lib/bundled-skill.d.ts +5 -0
  43. package/dist/lib/bundled-skill.d.ts.map +1 -0
  44. package/dist/lib/bundled-skill.js +13 -0
  45. package/dist/lib/bundled-skill.js.map +1 -0
  46. package/dist/lib/claude-config.d.ts +19 -0
  47. package/dist/lib/claude-config.d.ts.map +1 -0
  48. package/dist/lib/claude-config.js +202 -0
  49. package/dist/lib/claude-config.js.map +1 -0
  50. package/dist/lib/cli-install.d.ts +40 -0
  51. package/dist/lib/cli-install.d.ts.map +1 -0
  52. package/dist/lib/cli-install.js +42 -0
  53. package/dist/lib/cli-install.js.map +1 -0
  54. package/dist/lib/command-code-config.d.ts +5 -0
  55. package/dist/lib/command-code-config.d.ts.map +1 -0
  56. package/dist/lib/command-code-config.js +16 -0
  57. package/dist/lib/command-code-config.js.map +1 -0
  58. package/dist/lib/connect-all-auth.d.ts +21 -0
  59. package/dist/lib/connect-all-auth.d.ts.map +1 -0
  60. package/dist/lib/connect-all-auth.js +113 -0
  61. package/dist/lib/connect-all-auth.js.map +1 -0
  62. package/dist/lib/connect-all-summary.d.ts +10 -0
  63. package/dist/lib/connect-all-summary.d.ts.map +1 -0
  64. package/dist/lib/connect-all-summary.js +153 -0
  65. package/dist/lib/connect-all-summary.js.map +1 -0
  66. package/dist/lib/connect-all-uninstall.d.ts +7 -0
  67. package/dist/lib/connect-all-uninstall.d.ts.map +1 -0
  68. package/dist/lib/connect-all-uninstall.js +249 -0
  69. package/dist/lib/connect-all-uninstall.js.map +1 -0
  70. package/dist/lib/connect-all.d.ts +42 -0
  71. package/dist/lib/connect-all.d.ts.map +1 -0
  72. package/dist/lib/connect-all.js +438 -0
  73. package/dist/lib/connect-all.js.map +1 -0
  74. package/dist/lib/connect-auth.d.ts +7 -0
  75. package/dist/lib/connect-auth.d.ts.map +1 -0
  76. package/dist/lib/connect-auth.js +50 -0
  77. package/dist/lib/connect-auth.js.map +1 -0
  78. package/dist/lib/connect-clients.d.ts +108 -0
  79. package/dist/lib/connect-clients.d.ts.map +1 -0
  80. package/dist/lib/connect-clients.js +358 -0
  81. package/dist/lib/connect-clients.js.map +1 -0
  82. package/dist/lib/connect-fallback.d.ts +27 -0
  83. package/dist/lib/connect-fallback.d.ts.map +1 -0
  84. package/dist/lib/connect-fallback.js +166 -0
  85. package/dist/lib/connect-fallback.js.map +1 -0
  86. package/dist/lib/connect-picker.d.ts +19 -0
  87. package/dist/lib/connect-picker.d.ts.map +1 -0
  88. package/dist/lib/connect-picker.js +155 -0
  89. package/dist/lib/connect-picker.js.map +1 -0
  90. package/dist/lib/connect-preflight.d.ts +17 -0
  91. package/dist/lib/connect-preflight.d.ts.map +1 -0
  92. package/dist/lib/connect-preflight.js +81 -0
  93. package/dist/lib/connect-preflight.js.map +1 -0
  94. package/dist/lib/connect-runtime.d.ts +109 -0
  95. package/dist/lib/connect-runtime.d.ts.map +1 -0
  96. package/dist/lib/connect-runtime.js +360 -0
  97. package/dist/lib/connect-runtime.js.map +1 -0
  98. package/dist/lib/constants.d.ts +23 -0
  99. package/dist/lib/constants.d.ts.map +1 -0
  100. package/dist/lib/constants.js +87 -0
  101. package/dist/lib/constants.js.map +1 -0
  102. package/dist/lib/cursor-config.d.ts +16 -0
  103. package/dist/lib/cursor-config.d.ts.map +1 -0
  104. package/dist/lib/cursor-config.js +34 -0
  105. package/dist/lib/cursor-config.js.map +1 -0
  106. package/dist/lib/doctor-checks.d.ts +21 -0
  107. package/dist/lib/doctor-checks.d.ts.map +1 -0
  108. package/dist/lib/doctor-checks.js +312 -0
  109. package/dist/lib/doctor-checks.js.map +1 -0
  110. package/dist/lib/doctor-repairs.d.ts +11 -0
  111. package/dist/lib/doctor-repairs.d.ts.map +1 -0
  112. package/dist/lib/doctor-repairs.js +130 -0
  113. package/dist/lib/doctor-repairs.js.map +1 -0
  114. package/dist/lib/doctor-report.d.ts +195 -0
  115. package/dist/lib/doctor-report.d.ts.map +1 -0
  116. package/dist/lib/doctor-report.js +102 -0
  117. package/dist/lib/doctor-report.js.map +1 -0
  118. package/dist/lib/doctor-telemetry.d.ts +9 -0
  119. package/dist/lib/doctor-telemetry.d.ts.map +1 -0
  120. package/dist/lib/doctor-telemetry.js +63 -0
  121. package/dist/lib/doctor-telemetry.js.map +1 -0
  122. package/dist/lib/harness-detect.d.ts +33 -0
  123. package/dist/lib/harness-detect.d.ts.map +1 -0
  124. package/dist/lib/harness-detect.js +70 -0
  125. package/dist/lib/harness-detect.js.map +1 -0
  126. package/dist/lib/harness-spec.d.ts +285 -0
  127. package/dist/lib/harness-spec.d.ts.map +1 -0
  128. package/dist/lib/harness-spec.js +268 -0
  129. package/dist/lib/harness-spec.js.map +1 -0
  130. package/dist/lib/harness.d.ts +27 -0
  131. package/dist/lib/harness.d.ts.map +1 -0
  132. package/dist/lib/harness.js +125 -0
  133. package/dist/lib/harness.js.map +1 -0
  134. package/dist/lib/hermes-config.d.ts +22 -0
  135. package/dist/lib/hermes-config.d.ts.map +1 -0
  136. package/dist/lib/hermes-config.js +76 -0
  137. package/dist/lib/hermes-config.js.map +1 -0
  138. package/dist/lib/hermes-env.d.ts +19 -0
  139. package/dist/lib/hermes-env.d.ts.map +1 -0
  140. package/dist/lib/hermes-env.js +169 -0
  141. package/dist/lib/hermes-env.js.map +1 -0
  142. package/dist/lib/hermes-plugin.d.ts +40 -0
  143. package/dist/lib/hermes-plugin.d.ts.map +1 -0
  144. package/dist/lib/hermes-plugin.js +168 -0
  145. package/dist/lib/hermes-plugin.js.map +1 -0
  146. package/dist/lib/install-root.d.ts +18 -0
  147. package/dist/lib/install-root.d.ts.map +1 -0
  148. package/dist/lib/install-root.js +55 -0
  149. package/dist/lib/install-root.js.map +1 -0
  150. package/dist/lib/mcp-config.d.ts +36 -0
  151. package/dist/lib/mcp-config.d.ts.map +1 -0
  152. package/dist/lib/mcp-config.js +90 -0
  153. package/dist/lib/mcp-config.js.map +1 -0
  154. package/dist/lib/mcp-endpoint.d.ts +16 -0
  155. package/dist/lib/mcp-endpoint.d.ts.map +1 -0
  156. package/dist/lib/mcp-endpoint.js +41 -0
  157. package/dist/lib/mcp-endpoint.js.map +1 -0
  158. package/dist/lib/mcp-json-config.d.ts +43 -0
  159. package/dist/lib/mcp-json-config.d.ts.map +1 -0
  160. package/dist/lib/mcp-json-config.js +164 -0
  161. package/dist/lib/mcp-json-config.js.map +1 -0
  162. package/dist/lib/notice.d.ts +13 -0
  163. package/dist/lib/notice.d.ts.map +1 -0
  164. package/dist/lib/notice.js +73 -0
  165. package/dist/lib/notice.js.map +1 -0
  166. package/dist/lib/omp-config.d.ts +18 -0
  167. package/dist/lib/omp-config.d.ts.map +1 -0
  168. package/dist/lib/omp-config.js +73 -0
  169. package/dist/lib/omp-config.js.map +1 -0
  170. package/dist/lib/output.d.ts +22 -0
  171. package/dist/lib/output.d.ts.map +1 -0
  172. package/dist/lib/output.js +92 -0
  173. package/dist/lib/output.js.map +1 -0
  174. package/dist/lib/pi-config.d.ts +27 -0
  175. package/dist/lib/pi-config.d.ts.map +1 -0
  176. package/dist/lib/pi-config.js +113 -0
  177. package/dist/lib/pi-config.js.map +1 -0
  178. package/dist/lib/registration-detect.d.ts +28 -0
  179. package/dist/lib/registration-detect.d.ts.map +1 -0
  180. package/dist/lib/registration-detect.js +563 -0
  181. package/dist/lib/registration-detect.js.map +1 -0
  182. package/dist/lib/setup-telemetry.d.ts +273 -0
  183. package/dist/lib/setup-telemetry.d.ts.map +1 -0
  184. package/dist/lib/setup-telemetry.js +309 -0
  185. package/dist/lib/setup-telemetry.js.map +1 -0
  186. package/dist/lib/signals.d.ts +14 -0
  187. package/dist/lib/signals.d.ts.map +1 -0
  188. package/dist/lib/signals.js +29 -0
  189. package/dist/lib/signals.js.map +1 -0
  190. package/dist/lib/skill-install.d.ts +10 -0
  191. package/dist/lib/skill-install.d.ts.map +1 -0
  192. package/dist/lib/skill-install.js +94 -0
  193. package/dist/lib/skill-install.js.map +1 -0
  194. package/dist/lib/skill-paths.d.ts +7 -0
  195. package/dist/lib/skill-paths.d.ts.map +1 -0
  196. package/dist/lib/skill-paths.js +37 -0
  197. package/dist/lib/skill-paths.js.map +1 -0
  198. package/dist/lib/skill-vendor.d.ts +20 -0
  199. package/dist/lib/skill-vendor.d.ts.map +1 -0
  200. package/dist/lib/skill-vendor.js +215 -0
  201. package/dist/lib/skill-vendor.js.map +1 -0
  202. package/dist/lib/skill.d.ts +14 -0
  203. package/dist/lib/skill.d.ts.map +1 -0
  204. package/dist/lib/skill.js +87 -0
  205. package/dist/lib/skill.js.map +1 -0
  206. package/dist/lib/verify.d.ts +35 -0
  207. package/dist/lib/verify.d.ts.map +1 -0
  208. package/dist/lib/verify.js +169 -0
  209. package/dist/lib/verify.js.map +1 -0
  210. package/dist/program.d.ts +8 -0
  211. package/dist/program.d.ts.map +1 -0
  212. package/dist/program.js +54 -0
  213. package/dist/program.js.map +1 -0
  214. package/package.json +55 -0
  215. package/skill/springbrand-action-api/SKILL.md +49 -0
  216. package/skill/springbrand-action-api/references/action-aliases.md +156 -0
  217. package/skill/springbrand-action-api/references/action-discovery.md +95 -0
  218. package/skill/springbrand-connector/SKILL.md +49 -0
  219. package/skill/springbrand-gtm/SKILL.md +34 -0
  220. package/skill/springbrand-platform/SKILL.md +55 -0
  221. package/skill/springbrand-platform/references/plugin-discovery.md +94 -0
  222. package/skill/use-springbrand/SKILL.md +70 -0
@@ -0,0 +1,164 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:mcp-json-config.d.ts + mcp-json-config.impl.js */
2
+ import * as fs from 'fs';
3
+ import { matchesCliKey } from './auth.js';
4
+ function isPlainRecord(value) {
5
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
6
+ }
7
+ // Footgun: the key lands plaintext in mcp.json (0600) — per-device keys are the GA hardening.
8
+ // `Authorization: Bearer` is the only place the Gateway reads a key from; a key in any other
9
+ // header reaches `/mcp` as no credential at all and the client is pushed back into OAuth.
10
+ export function buildSpringbrandServerEntry(mcpUrl, apiKey) {
11
+ return apiKey ? { url: mcpUrl, headers: { Authorization: `Bearer ${apiKey}` } } : { url: mcpUrl };
12
+ }
13
+ function parseMcpJson(raw) {
14
+ try {
15
+ const parsed = JSON.parse(raw);
16
+ if (!isPlainRecord(parsed))
17
+ return { ok: false, error: 'mcp.json root is not a JSON object' };
18
+ if ('mcpServers' in parsed && !isPlainRecord(parsed.mcpServers)) {
19
+ return { ok: false, error: 'mcp.json mcpServers is not a JSON object' };
20
+ }
21
+ return { ok: true, value: parsed };
22
+ }
23
+ catch (e) {
24
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
25
+ }
26
+ }
27
+ // Non-ENOENT read failures count as corruption: skip, never clobber.
28
+ function readExisting(target) {
29
+ let raw;
30
+ try {
31
+ raw = fs.readFileSync(target.file(), 'utf8');
32
+ }
33
+ catch (e) {
34
+ if (e.code === 'ENOENT')
35
+ return { parsed: {} };
36
+ return { error: e instanceof Error ? e.message : String(e) };
37
+ }
38
+ const parsed = parseMcpJson(raw);
39
+ if (!parsed.ok)
40
+ return { error: parsed.error ?? 'mcp.json could not be parsed' };
41
+ return { raw, parsed: parsed.value };
42
+ }
43
+ /** Dry-run description of the pending write; touches nothing. */
44
+ export function planWrite(target, mcpUrl, apiKey) {
45
+ const existing = readExisting(target);
46
+ const filePath = target.file();
47
+ if ('error' in existing) {
48
+ return `${filePath}: existing file is corrupt (${existing.error}) — would skip and leave it untouched`;
49
+ }
50
+ const authNote = apiKey
51
+ ? ' with an API-key header — the key is stored in plaintext in that file (value not shown here)'
52
+ : '';
53
+ const servers = existing.parsed.mcpServers;
54
+ const current = isPlainRecord(servers) ? servers[target.serverKey] : undefined;
55
+ if (JSON.stringify(current) === JSON.stringify(buildSpringbrandServerEntry(mcpUrl, apiKey))) {
56
+ return `${filePath}: already has the ${target.serverKey} MCP entry — no change`;
57
+ }
58
+ return existing.raw === undefined
59
+ ? `${filePath}: would create with a "${target.serverKey}" MCP server entry${authNote}`
60
+ : `${filePath}: would back up to a timestamped copy, then merge in the "${target.serverKey}" MCP server entry${authNote}`;
61
+ }
62
+ // omp expands `${VAR}` / `${VAR:-default}` header values at load.
63
+ const ENV_TEMPLATE_VALUE = /^\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-[^}]*)?\}$/;
64
+ /** Reports the header's shape, never its value. */
65
+ export function readSpringbrandEntry(target) {
66
+ const existing = readExisting(target);
67
+ if ('error' in existing)
68
+ return { present: false, hasApiKeyHeader: false, error: existing.error };
69
+ const servers = existing.parsed.mcpServers;
70
+ const entry = isPlainRecord(servers) ? servers[target.serverKey] : undefined;
71
+ if (!isPlainRecord(entry))
72
+ return { present: false, hasApiKeyHeader: false };
73
+ const key = readKeyHeader(entry.headers, target.keyHeader);
74
+ const templateVar = key ? ENV_TEMPLATE_VALUE.exec(key.value)?.[1] : undefined;
75
+ return {
76
+ present: true,
77
+ hasApiKeyHeader: key !== undefined,
78
+ ...(entry.enabled === false ? { enabled: false } : {}),
79
+ ...(key?.legacy ? { legacyKeyHeader: true } : {}),
80
+ ...(matchesCliKey(key?.value) ? { keyMatchesCliKey: true } : {}),
81
+ ...(templateVar ? { keyTemplateVar: templateVar } : {}),
82
+ ...(typeof entry.url === 'string' ? { url: entry.url } : {}),
83
+ };
84
+ }
85
+ // What CLIs before the Bearer switch wrote. The Gateway never read it, so an entry carrying one
86
+ // is a broken install rather than a keyless one, and saying so earns the user a repair.
87
+ const LEGACY_KEY_HEADER = { name: 'x-api-key', valuePrefix: '' };
88
+ /** Reports the key header's shape, never its value. */
89
+ function readKeyHeader(headers, keyHeader) {
90
+ const current = keyHeader ?? { name: 'Authorization', valuePrefix: 'Bearer ' };
91
+ return findKeyHeader(headers, current) ?? findKeyHeader(headers, LEGACY_KEY_HEADER, true);
92
+ }
93
+ function findKeyHeader(headers, keyHeader, legacy = false) {
94
+ const { name, valuePrefix = '' } = keyHeader;
95
+ // Header names are case-insensitive, and this file is hand-editable — matching only the
96
+ // casing we write would understate auth mode for a user who typed it differently.
97
+ const found = isPlainRecord(headers)
98
+ ? Object.entries(headers).find((entry) => entry[0].toLowerCase() === name.toLowerCase() && typeof entry[1] === 'string')
99
+ : undefined;
100
+ if (!found)
101
+ return undefined;
102
+ // The scheme is case-insensitive too, and a hand-edited header may omit it entirely.
103
+ const headerValue = found[1];
104
+ if (typeof headerValue !== 'string')
105
+ return undefined;
106
+ const hasPrefix = headerValue.toLowerCase().startsWith(valuePrefix.toLowerCase());
107
+ return {
108
+ value: hasPrefix ? headerValue.slice(valuePrefix.length) : headerValue,
109
+ ...(legacy ? { legacy: true } : {}),
110
+ };
111
+ }
112
+ // Backup, then atomic temp+rename; pid avoids same-millisecond backup collisions.
113
+ function commitServers(target, existing, servers) {
114
+ const filePath = target.file();
115
+ fs.mkdirSync(target.dir(), { recursive: true, mode: 0o700 });
116
+ let backupPath;
117
+ if (existing.raw !== undefined) {
118
+ backupPath = `${filePath}.bak-${Date.now()}-${process.pid}`;
119
+ fs.writeFileSync(backupPath, existing.raw, { mode: 0o600 });
120
+ }
121
+ const next = { ...existing.parsed, mcpServers: servers };
122
+ const tmpPath = `${filePath}.tmp-${process.pid}`;
123
+ fs.writeFileSync(tmpPath, JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
124
+ try {
125
+ fs.renameSync(tmpPath, filePath);
126
+ }
127
+ catch (e) {
128
+ fs.rmSync(tmpPath, { force: true });
129
+ throw e;
130
+ }
131
+ return { status: 'written', backupPath };
132
+ }
133
+ /** Merges only the target's key; skips unreadable/corrupt files rather than clobber. */
134
+ export function writeMcpConfig(target, mcpUrl, apiKey) {
135
+ const existing = readExisting(target);
136
+ if ('error' in existing)
137
+ return { status: 'corrupt_skip', error: existing.error };
138
+ const servers = isPlainRecord(existing.parsed.mcpServers)
139
+ ? { ...existing.parsed.mcpServers }
140
+ : {};
141
+ const nextEntry = buildSpringbrandServerEntry(mcpUrl, apiKey);
142
+ if (JSON.stringify(servers[target.serverKey]) === JSON.stringify(nextEntry)) {
143
+ return { status: 'unchanged' };
144
+ }
145
+ const repaired = target.serverKey in servers;
146
+ servers[target.serverKey] = nextEntry;
147
+ return { ...commitServers(target, existing, servers), repaired };
148
+ }
149
+ /** Removes only the target's key. */
150
+ export function removeServer(target) {
151
+ const existing = readExisting(target);
152
+ if ('error' in existing)
153
+ return { status: 'corrupt_skip', error: existing.error };
154
+ if (existing.raw === undefined)
155
+ return { status: 'unchanged' };
156
+ const servers = isPlainRecord(existing.parsed.mcpServers)
157
+ ? { ...existing.parsed.mcpServers }
158
+ : {};
159
+ if (!(target.serverKey in servers))
160
+ return { status: 'unchanged' };
161
+ delete servers[target.serverKey];
162
+ return commitServers(target, existing, servers);
163
+ }
164
+ //# sourceMappingURL=mcp-json-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-json-config.js","sourceRoot":"","sources":["../../src/lib/mcp-json-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:notice.d.ts + notice.impl.js */
2
+ import type { Command } from 'commander';
3
+ /** Test-only: the capture slot and the once-per-invocation latch are module state. */
4
+ export declare function resetNoticeState(): void;
5
+ /** Records the first notice seen; printing is deferred so it lands at the end of a command. */
6
+ export declare function captureNotice(headers: Headers): void;
7
+ /** Advisory only, never changes stdout, the exit code, or control flow. */
8
+ export declare function emitNotice(): void;
9
+ /** For commands that are the fix themselves, such as `upgrade`, where the nudge is noise. */
10
+ export declare function suppressNotice(): void;
11
+ /** postAction covers clean completions, the exit hook covers the process.exit and rejection paths, the latch keeps it to one. */
12
+ export declare function installNoticeEmit(program: Command): () => NodeJS.Process;
13
+ //# sourceMappingURL=notice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notice.d.ts","sourceRoot":"","sources":["../../src/lib/notice.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,sFAAsF;AACtF,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AACD,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBpD;AASD,2EAA2E;AAC3E,wBAAgB,UAAU,IAAI,IAAI,CAUjC;AACD,6FAA6F;AAC7F,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AACD,iIAAiI;AACjI,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,wBAKjD"}
@@ -0,0 +1,73 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:notice.d.ts + notice.impl.js */
2
+ import { CLI_VERSION } from './constants.js';
3
+ import { detectHumanInitiated } from './harness.js';
4
+ import { err, sanitizeLine, warnLine } from './output.js';
5
+ const NOTICE_HEADER = 'x-sp-notice';
6
+ const LEVEL_HEADER = 'x-sp-notice-level';
7
+ const LATEST_HEADER = 'x-sp-notice-latest';
8
+ const MAX_LENGTH = 300;
9
+ const PLAIN_VERSION = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
10
+ const VALID_LEVELS = new Set(['required', 'recommended']);
11
+ let captured;
12
+ let printed = false;
13
+ /** Test-only: the capture slot and the once-per-invocation latch are module state. */
14
+ export function resetNoticeState() {
15
+ captured = undefined;
16
+ printed = false;
17
+ }
18
+ /** Records the first notice seen; printing is deferred so it lands at the end of a command. */
19
+ export function captureNotice(headers) {
20
+ if (captured)
21
+ return;
22
+ if (typeof headers?.get !== 'function')
23
+ return;
24
+ const message = sanitizeLine(headers.get(NOTICE_HEADER) ?? '')
25
+ .trim()
26
+ .slice(0, MAX_LENGTH);
27
+ if (!message)
28
+ return;
29
+ const rawLevel = headers.get(LEVEL_HEADER)?.trim().toLowerCase();
30
+ const rawLatest = headers.get(LATEST_HEADER)?.trim() ?? '';
31
+ // Spread rather than `level: undefined`, which exactOptionalPropertyTypes rejects.
32
+ const level = rawLevel && VALID_LEVELS.has(rawLevel)
33
+ ? rawLevel
34
+ : undefined;
35
+ captured = {
36
+ message,
37
+ ...(level ? { level } : {}),
38
+ ...(PLAIN_VERSION.test(rawLatest) ? { latest: rawLatest } : {}),
39
+ };
40
+ }
41
+ /** Built here, not by the server, so nothing it sends can reach an agent's context as instructions. */
42
+ function agentMessage({ level, latest }) {
43
+ // Latest is the registry version, not the required floor; only the soft level names it.
44
+ const target = latest ? ` (latest ${latest})` : '';
45
+ return level === 'required'
46
+ ? `This SpringBrand CLI (${CLI_VERSION}) is below the required minimum. Run: sp upgrade`
47
+ : `A SpringBrand CLI update is available${target} (you have ${CLI_VERSION}). Run: sp upgrade`;
48
+ }
49
+ /** Advisory only, never changes stdout, the exit code, or control flow. */
50
+ export function emitNotice() {
51
+ if (printed || !captured)
52
+ return;
53
+ printed = true;
54
+ const { message, ...rest } = captured;
55
+ if (detectHumanInitiated()) {
56
+ warnLine(message);
57
+ return;
58
+ }
59
+ err({ notice: agentMessage(rest), ...rest });
60
+ }
61
+ /** For commands that are the fix themselves, such as `upgrade`, where the nudge is noise. */
62
+ export function suppressNotice() {
63
+ captured = undefined;
64
+ printed = true;
65
+ }
66
+ /** postAction covers clean completions, the exit hook covers the process.exit and rejection paths, the latch keeps it to one. */
67
+ export function installNoticeEmit(program) {
68
+ const backstop = () => emitNotice();
69
+ program.hook('postAction', () => emitNotice());
70
+ process.once('exit', backstop);
71
+ return () => process.removeListener('exit', backstop);
72
+ }
73
+ //# sourceMappingURL=notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notice.js","sourceRoot":"","sources":["../../src/lib/notice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:omp-config.d.ts + omp-config.impl.js */
2
+ import type { McpJsonServerEntry, McpJsonTarget, McpJsonWriteResult } from './mcp-json-config.js';
3
+ /** Tests share one process; the resolver result must not. */
4
+ export declare function resetOmpAgentDirCache(): void;
5
+ /** Profiles move the dir; a guessed path is written unread. */
6
+ export declare function ompAgentDir(): string | undefined;
7
+ /** Undefined means unresolved; connect fails closed via requireOmpTarget. */
8
+ export declare function ompMcpTarget(): McpJsonTarget | undefined;
9
+ export declare function ompMcpPath(): string;
10
+ /** Reports the header's shape, never its value; undefined means unresolved. */
11
+ export declare function readOmpSpringbrandEntry(): McpJsonServerEntry | undefined;
12
+ /** Merges only the `springbrand` key; throws when the dir is unresolved. */
13
+ export declare function writeOmpMcpConfig(mcpUrl: string, apiKey?: string): McpJsonWriteResult;
14
+ /** Dry-run description of the pending write; touches nothing. */
15
+ export declare function planOmpWrite(mcpUrl: string, apiKey?: string): string;
16
+ /** Removes only the `springbrand` key. */
17
+ export declare function removeOmpMcpServer(): McpJsonWriteResult;
18
+ //# sourceMappingURL=omp-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omp-config.d.ts","sourceRoot":"","sources":["../../src/lib/omp-config.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAElE,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AASlG,6DAA6D;AAC7D,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AACD,+DAA+D;AAC/D,wBAAgB,WAAW,IAAI,MAAM,GAAG,SAAS,CAGhD;AAeD,6EAA6E;AAC7E,wBAAgB,YAAY,IAAI,aAAa,GAAG,SAAS,CAKxD;AAQD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AACD,+EAA+E;AAC/E,wBAAgB,uBAAuB,IAAI,kBAAkB,GAAG,SAAS,CAGxE;AACD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAErF;AACD,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAKpE;AACD,0CAA0C;AAC1C,wBAAgB,kBAAkB,IAAI,kBAAkB,CAKvD"}
@@ -0,0 +1,73 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:omp-config.d.ts + omp-config.impl.js */
2
+ import * as path from 'path';
3
+ import spawn from 'cross-spawn';
4
+ import { ConnectStepError } from './connect-runtime.js';
5
+ import { HARNESS_PROBE_TIMEOUT_MS } from './constants.js';
6
+ import { planWrite, readSpringbrandEntry, removeServer, writeMcpConfig, } from './mcp-json-config.js';
7
+ const UNRESOLVED_REASON = '`omp config path` did not report a config directory';
8
+ // Cached: every later read must agree with the write.
9
+ let cachedAgentDir;
10
+ /** Tests share one process; the resolver result must not. */
11
+ export function resetOmpAgentDirCache() {
12
+ cachedAgentDir = undefined;
13
+ }
14
+ /** Profiles move the dir; a guessed path is written unread. */
15
+ export function ompAgentDir() {
16
+ cachedAgentDir ??= { dir: resolveAgentDir() };
17
+ return cachedAgentDir.dir;
18
+ }
19
+ function resolveAgentDir() {
20
+ const result = spawn.sync('omp', ['config', 'path'], {
21
+ encoding: 'utf8',
22
+ timeout: HARNESS_PROBE_TIMEOUT_MS,
23
+ });
24
+ if (result.error || result.status !== 0)
25
+ return undefined;
26
+ const dir = (result.stdout ?? '')
27
+ .split('\n')
28
+ .map((line) => line.trim())
29
+ .filter(Boolean)
30
+ .at(-1);
31
+ return dir && path.isAbsolute(dir) ? dir : undefined;
32
+ }
33
+ /** Undefined means unresolved; connect fails closed via requireOmpTarget. */
34
+ export function ompMcpTarget() {
35
+ const dir = ompAgentDir();
36
+ if (!dir)
37
+ return undefined;
38
+ return { serverKey: 'springbrand', dir: () => dir, file: () => path.join(dir, 'mcp.json') };
39
+ }
40
+ function requireOmpTarget() {
41
+ const target = ompMcpTarget();
42
+ if (target)
43
+ return target;
44
+ throw new ConnectStepError("Could not locate omp's config directory: `omp config path` did not print one. " +
45
+ 'Check that omp is installed and `omp config path` works, then re-run: sp connect omp', 'invalid_config', { failureDetail: 'omp_agent_dir_unresolved' });
46
+ }
47
+ export function ompMcpPath() {
48
+ return requireOmpTarget().file();
49
+ }
50
+ /** Reports the header's shape, never its value; undefined means unresolved. */
51
+ export function readOmpSpringbrandEntry() {
52
+ const target = ompMcpTarget();
53
+ return target ? readSpringbrandEntry(target) : undefined;
54
+ }
55
+ /** Merges only the `springbrand` key; throws when the dir is unresolved. */
56
+ export function writeOmpMcpConfig(mcpUrl, apiKey) {
57
+ return writeMcpConfig(requireOmpTarget(), mcpUrl, apiKey);
58
+ }
59
+ /** Dry-run description of the pending write; touches nothing. */
60
+ export function planOmpWrite(mcpUrl, apiKey) {
61
+ const target = ompMcpTarget();
62
+ if (!target)
63
+ return `${UNRESOLVED_REASON} — connect omp would fail the same way`;
64
+ return planWrite(target, mcpUrl, apiKey);
65
+ }
66
+ /** Removes only the `springbrand` key. */
67
+ export function removeOmpMcpServer() {
68
+ const target = ompMcpTarget();
69
+ if (!target)
70
+ return { status: 'corrupt_skip', error: UNRESOLVED_REASON };
71
+ return removeServer(target);
72
+ }
73
+ //# sourceMappingURL=omp-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omp-config.js","sourceRoot":"","sources":["../../src/lib/omp-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:output.d.ts + output.impl.js */
2
+ export declare class ApiError extends Error {
3
+ readonly status: number;
4
+ readonly code?: string | undefined;
5
+ constructor(status: number, message: string, code?: string | undefined);
6
+ }
7
+ export declare function out(data: unknown): void;
8
+ /** The only writer for untrusted text: strips ANSI and C0/C1 controls. */
9
+ export declare function sanitizeLine(text: string): string;
10
+ /** Every version the route caps at 32 printable ASCII chars. */
11
+ export declare function boundedVersion(text: string): string | undefined;
12
+ export declare function outLine(line: string): void;
13
+ /** `connect --all` nests a harness's own lines under its step header. */
14
+ export declare function setErrIndent(prefix: string): void;
15
+ export declare function errLine(line: string): void;
16
+ /** Advisory stderr line, yellow on a terminal and plain everywhere else so piped output stays clean. */
17
+ export declare function warnLine(line: string): void;
18
+ export declare function err(data: unknown): void;
19
+ export declare function handleApiError(e: unknown): never;
20
+ /** Undefined, not a throw: callers hand the value to a Zod safeParse. */
21
+ export declare function parseJson(text: string): unknown;
22
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAG1D,qBAAa,QAAS,SAAQ,KAAK;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;gBACvB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS;CAMzE;AACD,wBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAEvC;AACD,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AACD,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO/D;AACD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjD;AACD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI1C;AAID,wGAAwG;AACxG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI3C;AACD,wBAAgB,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAIvC;AACD,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,KAAK,CAyBhD;AACD,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/C"}
@@ -0,0 +1,92 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:output.d.ts + output.impl.js */
2
+ import { stripVTControlCharacters } from 'node:util';
3
+ export class ApiError extends Error {
4
+ status;
5
+ code;
6
+ constructor(status, message, code) {
7
+ super(message);
8
+ this.status = status;
9
+ this.code = code;
10
+ this.name = 'ApiError';
11
+ }
12
+ }
13
+ export function out(data) {
14
+ process.stdout.write(JSON.stringify(data) + '\n');
15
+ }
16
+ /** The only writer for untrusted text: strips ANSI and C0/C1 controls. */
17
+ export function sanitizeLine(text) {
18
+ // eslint-disable-next-line no-control-regex
19
+ return stripVTControlCharacters(text).replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, '');
20
+ }
21
+ /** Every version the route caps at 32 printable ASCII chars. */
22
+ export function boundedVersion(text) {
23
+ // First line only: sanitizeLine keeps newlines, so stripping splices lines.
24
+ const version = sanitizeLine(text)
25
+ .split('\n')[0]
26
+ .replace(/[^\x20-\x7E]/g, '')
27
+ .trim();
28
+ return version ? version.slice(0, 32) : undefined;
29
+ }
30
+ export function outLine(line) {
31
+ process.stdout.write(sanitizeLine(line) + '\n');
32
+ }
33
+ let errIndent = '';
34
+ /** `connect --all` nests a harness's own lines under its step header. */
35
+ export function setErrIndent(prefix) {
36
+ errIndent = prefix;
37
+ }
38
+ export function errLine(line) {
39
+ const text = sanitizeLine(line);
40
+ // Per line, not once: a replayed capture carries newlines.
41
+ process.stderr.write((errIndent ? text.replace(/^(?=.)/gm, errIndent) : text) + '\n');
42
+ }
43
+ const WARN_ON = '\x1b[33m';
44
+ const WARN_OFF = '\x1b[39m';
45
+ const VAULT_RECONNECT_REQUIRED = 'VAULT_RECONNECT_REQUIRED';
46
+ /** Advisory stderr line, yellow on a terminal and plain everywhere else so piped output stays clean. */
47
+ export function warnLine(line) {
48
+ const text = sanitizeLine(line);
49
+ const colour = Boolean(process.stderr.isTTY) && !process.env['NO_COLOR'];
50
+ process.stderr.write(colour ? `${WARN_ON}${text}${WARN_OFF}\n` : `${text}\n`);
51
+ }
52
+ export function err(data) {
53
+ const payload = typeof data === 'string' ? { error: data } : data;
54
+ const serialized = JSON.stringify(payload) ?? 'undefined';
55
+ process.stderr.write(sanitizeLine(serialized) + '\n');
56
+ }
57
+ export function handleApiError(e) {
58
+ if (e instanceof ApiError) {
59
+ const payload = {
60
+ error: e.message,
61
+ status: e.status,
62
+ };
63
+ if (e.code)
64
+ payload.code = e.code;
65
+ if (e.code === VAULT_RECONNECT_REQUIRED) {
66
+ payload.hint =
67
+ 'Reconnect the provider with `sp vault connection add --provider 1password` or `sp vault connection add --provider bitwarden --client-id <client-id>`. Vault secrets are read from SPRINGBRAND_VAULT_TOKEN, SPRINGBRAND_VAULT_CLIENT_SECRET, and SPRINGBRAND_VAULT_MASTER_PASSWORD.';
68
+ }
69
+ else if (e.status === 401) {
70
+ payload.hint =
71
+ 'Clear the SPRINGBRAND_API_KEY environment variable, run `sp auth login`, then try again.';
72
+ }
73
+ err(payload);
74
+ }
75
+ else if (e instanceof Error) {
76
+ err({ error: e.message });
77
+ }
78
+ else {
79
+ err({ error: String(e) });
80
+ }
81
+ process.exit(1);
82
+ }
83
+ /** Undefined, not a throw: callers hand the value to a Zod safeParse. */
84
+ export function parseJson(text) {
85
+ try {
86
+ return JSON.parse(text);
87
+ }
88
+ catch {
89
+ return undefined;
90
+ }
91
+ }
92
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /** 复刻自 tiny-fish CLI 编译产物:pi-config.d.ts + pi-config.impl.js */
2
+ import type { McpJsonServerEntry, McpJsonWriteResult } from './mcp-json-config.js';
3
+ /** Mirrors pi's own getAgentDir: the override wins, else `~/.pi/agent`. */
4
+ export declare function piAgentDir(): string;
5
+ export declare function piMcpPath(): string;
6
+ /** Reports the header's shape, never its value. */
7
+ export declare function readPiSpringbrandEntry(): McpJsonServerEntry;
8
+ /** Merges only the `springbrand` key. */
9
+ export declare function writePiMcpConfig(mcpUrl: string, apiKey?: string): McpJsonWriteResult;
10
+ /** Dry-run description of the pending write; touches nothing. */
11
+ export declare function planPiWrite(mcpUrl: string, apiKey?: string): string;
12
+ /** Removes only the `springbrand` key. */
13
+ export declare function removePiMcpServer(): McpJsonWriteResult;
14
+ export declare const PI_ADAPTER_INSTALL_COMMAND = "pi install npm:pi-mcp-adapter";
15
+ /** Core pi has no MCP, so without this package the entry we write is never read. */
16
+ export declare function piMcpAdapterState(cwd?: string): PiAdapterState;
17
+ /** Tests share one process; the probe result must not. */
18
+ export declare function resetPiBinaryCache(): void;
19
+ /** npm ships an unrelated `pi` that prints `3`; only a semver answer is the harness. */
20
+ export declare function piBinaryIsPi(): boolean;
21
+ /** `skills` hardcodes the default dir, so an override leaves the skill where pi will not look. */
22
+ export declare function piSkillDirMismatch(): {
23
+ installedTo: string;
24
+ readFrom: string;
25
+ } | undefined;
26
+ export type PiAdapterState = 'installed' | 'absent' | 'unknown';
27
+ //# sourceMappingURL=pi-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-config.d.ts","sourceRoot":"","sources":["../../src/lib/pi-config.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAenF,2EAA2E;AAC3E,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAOD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AACD,mDAAmD;AACnD,wBAAgB,sBAAsB,IAAI,kBAAkB,CAE3D;AACD,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAEpF;AACD,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnE;AACD,0CAA0C;AAC1C,wBAAgB,iBAAiB,IAAI,kBAAkB,CAEtD;AACD,eAAO,MAAM,0BAA0B,kCAAkC,CAAC;AA4B1E,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAS9D;AAGD,0DAA0D;AAC1D,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AACD,wFAAwF;AACxF,wBAAgB,YAAY,IAAI,OAAO,CAGtC;AAUD,kGAAkG;AAClG,wBAAgB,kBAAkB,IAAI;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB,GAAG,SAAS,CAMZ;AAGD,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC"}