@wirecat/cli-template 0.9.0 → 0.11.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 (119) hide show
  1. package/.github/workflows/ci.yml +18 -0
  2. package/.github/workflows/release.yml +63 -0
  3. package/CHANGELOG.md +72 -1
  4. package/CLAUDE.md +1 -3
  5. package/bin/release +5 -3
  6. package/contracts/help.snap +2 -0
  7. package/dist/bin/clidev.js +34 -12
  8. package/dist/bundle/all-profiles-MJ6XSFOO.js +24 -0
  9. package/dist/bundle/anthropic-W5UKBZUB.js +70 -0
  10. package/dist/bundle/app-server-EZ46JAHB.js +217 -0
  11. package/dist/bundle/bun-HB6O2TTT.js +169 -0
  12. package/dist/bundle/bun-sqlite-KBXOW2ES.js +69 -0
  13. package/dist/bundle/chunk-2B5U4Z5H.js +100 -0
  14. package/dist/bundle/chunk-35KYY65W.js +122 -0
  15. package/dist/bundle/chunk-4LURWBVV.js +752 -0
  16. package/dist/bundle/chunk-5D4AEUVA.js +24783 -0
  17. package/dist/bundle/chunk-7IXL4UFK.js +158 -0
  18. package/dist/bundle/chunk-ADLS6FVG.js +24600 -0
  19. package/dist/bundle/chunk-AK257OMS.js +8353 -0
  20. package/dist/bundle/chunk-CXQXVKUY.js +24 -0
  21. package/dist/bundle/chunk-DFDN6AUB.js +21 -0
  22. package/dist/bundle/chunk-E42W72PQ.js +151 -0
  23. package/dist/bundle/chunk-EFHLQXG6.js +5104 -0
  24. package/dist/bundle/chunk-EGRB55FF.js +264 -0
  25. package/dist/bundle/chunk-ERGB4NJA.js +53 -0
  26. package/dist/bundle/chunk-ERKR3VJ5.js +1146 -0
  27. package/dist/bundle/chunk-FDBINRWA.js +884 -0
  28. package/dist/bundle/chunk-FZZIU4B7.js +34514 -0
  29. package/dist/bundle/chunk-GOO67PDU.js +2 -0
  30. package/dist/bundle/chunk-HDY5X3WQ.js +281 -0
  31. package/dist/bundle/chunk-HTQTIKWP.js +928 -0
  32. package/dist/bundle/chunk-IBBN7Z3A.js +630 -0
  33. package/dist/bundle/chunk-IDWW4TU2.js +18 -0
  34. package/dist/bundle/chunk-IGHEW777.js +164 -0
  35. package/dist/bundle/chunk-IN3FVRPK.js +76 -0
  36. package/dist/bundle/chunk-JAOGZMKQ.js +48 -0
  37. package/dist/bundle/chunk-JHO2LL2J.js +459 -0
  38. package/dist/bundle/chunk-JRK73FOW.js +78 -0
  39. package/dist/bundle/chunk-KAREKBUZ.js +24 -0
  40. package/dist/bundle/chunk-KJTNT4SW.js +82 -0
  41. package/dist/bundle/chunk-L5WWMP5M.js +1904 -0
  42. package/dist/bundle/chunk-MFS52LTZ.js +570 -0
  43. package/dist/bundle/chunk-MJRSEUKG.js +442 -0
  44. package/dist/bundle/chunk-MUSYGFCY.js +3556 -0
  45. package/dist/bundle/chunk-N2Z3MCOF.js +779 -0
  46. package/dist/bundle/chunk-NOVLCHDV.js +45 -0
  47. package/dist/bundle/chunk-O3UXNU3S.js +54 -0
  48. package/dist/bundle/chunk-O5EHUB2V.js +2 -0
  49. package/dist/bundle/chunk-OV6PHTAY.js +36226 -0
  50. package/dist/bundle/chunk-PBN4RBHS.js +2315 -0
  51. package/dist/bundle/chunk-PDGXMKJS.js +31 -0
  52. package/dist/bundle/chunk-PJOVK7PG.js +191 -0
  53. package/dist/bundle/chunk-QBP7OMN5.js +58 -0
  54. package/dist/bundle/chunk-QJ6XW4DM.js +7556 -0
  55. package/dist/bundle/chunk-QKWRL4OD.js +1028 -0
  56. package/dist/bundle/chunk-RUKDZEID.js +73 -0
  57. package/dist/bundle/chunk-SVDF6NJF.js +215 -0
  58. package/dist/bundle/chunk-TAYOKLGF.js +193 -0
  59. package/dist/bundle/chunk-TGB5F7NC.js +288 -0
  60. package/dist/bundle/chunk-V3ZTQ24B.js +161 -0
  61. package/dist/bundle/chunk-VLNKTMV7.js +3103 -0
  62. package/dist/bundle/chunk-VYSUKHKL.js +63 -0
  63. package/dist/bundle/chunk-Y5E2WNWB.js +35 -0
  64. package/dist/bundle/chunk-YJNUDHJD.js +3390 -0
  65. package/dist/bundle/chunk-Z7MSIRSQ.js +6848 -0
  66. package/dist/bundle/chunk-ZLY6GUAS.js +82 -0
  67. package/dist/bundle/chunk-ZVVMGPBJ.js +50 -0
  68. package/dist/bundle/clidev.js +22 -0
  69. package/dist/bundle/command-contract-75VJ36U4.js +29 -0
  70. package/dist/bundle/decode-AMXUVKNY.js +158 -0
  71. package/dist/bundle/dist-ESHIQU4M.js +7577 -0
  72. package/dist/bundle/echarts-GJDMQ2AQ.js +42501 -0
  73. package/dist/bundle/embed-L4CRZ2XQ.js +35 -0
  74. package/dist/bundle/embedder-IBGV4M2K.js +108 -0
  75. package/dist/bundle/first-run-VTKC2IBV.js +23 -0
  76. package/dist/bundle/first-screen-X5IJKBSU.js +27 -0
  77. package/dist/bundle/instructions-YJECS4KN.js +11 -0
  78. package/dist/bundle/mcp-G6XP2IRO.js +151 -0
  79. package/dist/bundle/mcp-OQBZXELQ.js +165 -0
  80. package/dist/bundle/mcp-RDZGYPSY.js +78 -0
  81. package/dist/bundle/node-NQG4EVZR.js +176 -0
  82. package/dist/bundle/node-P4E63KXA.js +2340 -0
  83. package/dist/bundle/node-TLZSIHIJ.js +21 -0
  84. package/dist/bundle/node-sqlite-BR7F3BLB.js +61 -0
  85. package/dist/bundle/oauth-J7UAWNIK.js +17 -0
  86. package/dist/bundle/open-BR47R5UE.js +19 -0
  87. package/dist/bundle/process-66I7RDPJ.js +91 -0
  88. package/dist/bundle/program-K6347XBZ.js +17279 -0
  89. package/dist/bundle/prompt-NE5JJ7UP.js +12 -0
  90. package/dist/bundle/recognize-GC3YFVIA.js +21 -0
  91. package/dist/bundle/remote-QELOMKQM.js +26 -0
  92. package/dist/bundle/rerank-BH6TZ2SP.js +49 -0
  93. package/dist/bundle/serve-WWLRNDT2.js +19 -0
  94. package/dist/bundle/server-DE6NLNUF.js +52 -0
  95. package/dist/bundle/server-ZPSQKOAH.js +39 -0
  96. package/dist/bundle/state-2BEGXAMO.js +33 -0
  97. package/dist/bundle/store-AH6WZMCF.js +120 -0
  98. package/dist/bundle/store-maintenance-command-PBXX3IEV.js +40 -0
  99. package/dist/version.d.ts +1 -1
  100. package/dist/version.d.ts.map +1 -1
  101. package/dist/version.js +1 -1
  102. package/dist/version.js.map +1 -1
  103. package/docs/commands.md +9 -13
  104. package/docs/dev/TESTING.md +10 -0
  105. package/docs/dev/reference-clis.md +7 -5
  106. package/docs/dev/skills/release/SKILL.md +15 -8
  107. package/docs/dev/skills/release/fresh-audit.md +4 -0
  108. package/docs/dev/test-matrix.md +1 -1
  109. package/kit/dist/new.js +1 -0
  110. package/package.json +8 -5
  111. package/scripts/audit.sh +14 -3
  112. package/scripts/smoke-bundle.ts +64 -0
  113. package/scripts/smoke.ts +18 -0
  114. package/scripts/test-matrix-untested.ts +1 -1
  115. package/scripts/version-level.test.ts +17 -1
  116. package/scripts/version-level.ts +35 -7
  117. package/skills/clidev-cli/SKILL.md +8 -0
  118. package/src/version.ts +1 -1
  119. package/lint/baseline/unknown-verb.json +0 -1
@@ -0,0 +1,73 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ alive
5
+ } from "./chunk-VYSUKHKL.js";
6
+ import {
7
+ resolvePaths,
8
+ writeSecurely
9
+ } from "./chunk-EFHLQXG6.js";
10
+ import {
11
+ __name
12
+ } from "./chunk-ZVVMGPBJ.js";
13
+
14
+ // node_modules/.pnpm/@wirecat+cli-core@0.495.0_@wirecat+cli-base@0.65.0_commander@15.0.0_esbuild@0.28.2_type_24cca5e5c8b0984f2f26e7d1ba6b6d47/node_modules/@wirecat/cli-core/dist/background/lock.js
15
+ import { existsSync, linkSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
16
+ import { dirname, join } from "node:path";
17
+ var lockPath = /* @__PURE__ */ __name((app, profile, env) => join(resolvePaths({ appName: app.appName, prefix: app.envPrefix, env }).state, "serve", `${profile}.lock`), "lockPath");
18
+ var readLock = /* @__PURE__ */ __name((path) => {
19
+ try {
20
+ const lock = JSON.parse(readFileSync(path, "utf8"));
21
+ return typeof lock.pid === "number" && typeof lock.startedAt === "string" ? lock : void 0;
22
+ } catch {
23
+ return void 0;
24
+ }
25
+ }, "readLock");
26
+ var holdLock = /* @__PURE__ */ __name((path, lock) => writeSecurely(path, `${JSON.stringify(lock)}
27
+ `, 384), "holdLock");
28
+ var takeLock = /* @__PURE__ */ __name((path, lock) => {
29
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
30
+ const draft = `${path}.${lock.pid}.tmp`;
31
+ writeFileSync(draft, `${JSON.stringify(lock)}
32
+ `, { mode: 384 });
33
+ try {
34
+ for (let attempt = 0; attempt < 5; attempt++) {
35
+ try {
36
+ linkSync(draft, path);
37
+ return void 0;
38
+ } catch (error) {
39
+ if (error.code !== "EEXIST")
40
+ throw error;
41
+ }
42
+ const held = readLock(path);
43
+ if (held && held.pid !== lock.pid && alive(held.pid))
44
+ return held;
45
+ rmSync(path, { force: true });
46
+ }
47
+ throw new Error(`could not take the lock ${path}: it keeps changing`);
48
+ } finally {
49
+ rmSync(draft, { force: true });
50
+ }
51
+ }, "takeLock");
52
+ var releaseLock = /* @__PURE__ */ __name((path, pid = process.pid) => {
53
+ if (readLock(path)?.pid === pid)
54
+ rmSync(path, { force: true });
55
+ }, "releaseLock");
56
+ var servingProfiles = /* @__PURE__ */ __name((app, env) => {
57
+ const dir = dirname(lockPath(app, "default", env));
58
+ if (!existsSync(dir))
59
+ return [];
60
+ return readdirSync(dir).filter((name) => name.endsWith(".lock")).map((name) => name.slice(0, -".lock".length)).filter((profile) => {
61
+ const lock = readLock(lockPath(app, profile, env));
62
+ return lock !== void 0 && alive(lock.pid);
63
+ });
64
+ }, "servingProfiles");
65
+
66
+ export {
67
+ lockPath,
68
+ readLock,
69
+ holdLock,
70
+ takeLock,
71
+ releaseLock,
72
+ servingProfiles
73
+ };
@@ -0,0 +1,215 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ installerOf,
5
+ updateCommand
6
+ } from "./chunk-E42W72PQ.js";
7
+ import {
8
+ DEFAULT_STEMMERS,
9
+ LANGUAGES
10
+ } from "./chunk-PBN4RBHS.js";
11
+ import {
12
+ QUESTIONS,
13
+ readSetupAnswers,
14
+ unanswered,
15
+ writeSetupAnswers
16
+ } from "./chunk-O3UXNU3S.js";
17
+ import {
18
+ sharedConfigPath
19
+ } from "./chunk-FDBINRWA.js";
20
+ import {
21
+ storePath
22
+ } from "./chunk-IDWW4TU2.js";
23
+ import {
24
+ __name
25
+ } from "./chunk-ZVVMGPBJ.js";
26
+
27
+ // node_modules/.pnpm/@wirecat+cli-core@0.495.0_@wirecat+cli-base@0.65.0_commander@15.0.0_esbuild@0.28.2_type_24cca5e5c8b0984f2f26e7d1ba6b6d47/node_modules/@wirecat/cli-core/dist/cli/first-run.js
28
+ import { spawnSync } from "node:child_process";
29
+ import { accessSync, constants, realpathSync } from "node:fs";
30
+ import { delimiter, join } from "node:path";
31
+ var SKIPPED = /* @__PURE__ */ new Set(["help", "guide", "completion", "mcp", "serve", "server", "update", "store"]);
32
+ var asksAtStart = /* @__PURE__ */ __name((start) => !start.headless && start.terminal && !start.env.AI_AGENT && !start.env.CLAUDECODE && start.readOnlyLock === void 0 && !SKIPPED.has(start.path[0] ?? ""), "asksAtStart");
33
+ var systemLanguage = /* @__PURE__ */ __name((env) => {
34
+ const named = [env.LC_ALL, env.LC_MESSAGES, env.LANG, ...(env.LANGUAGE ?? "").split(":")].map((value) => value?.trim()).find((value) => value && value !== "C" && value !== "POSIX" && !value.startsWith("C."));
35
+ return (named ?? Intl.DateTimeFormat().resolvedOptions().locale).slice(0, 2).toLowerCase();
36
+ }, "systemLanguage");
37
+ var stemmersOf = /* @__PURE__ */ __name((languages) => {
38
+ const latin = LANGUAGES.filter(({ name, script }) => script === "latin" && languages.includes(name));
39
+ return {
40
+ cyrillic: languages.includes("russian") ? "russian" : "none",
41
+ latin: latin.length ? latin.map(({ name }) => name).join(",") : "none"
42
+ };
43
+ }, "stemmersOf");
44
+ var languagesOf = /* @__PURE__ */ __name((stemmers) => LANGUAGES.filter(({ name }) => stemmers.cyrillic === name || stemmers.latin.split(",").includes(name)).map(({ name }) => name), "languagesOf");
45
+ var choose = /* @__PURE__ */ __name(async (io, prompt, count, chosen) => {
46
+ for (let attempt = 0; attempt < 3; attempt++) {
47
+ const answer = (await io.ask(prompt)).trim();
48
+ if (!answer)
49
+ return chosen;
50
+ if (/^(none|-)$/i.test(answer))
51
+ return [];
52
+ const numbers = answer.split(/[\s,]+/).filter(Boolean).map(Number);
53
+ if (numbers.every((number) => Number.isInteger(number) && number >= 1 && number <= count))
54
+ return [...new Set(numbers)].sort((a, b) => a - b);
55
+ io.say(`Choose numbers from 1 to ${count}, separated by commas.`);
56
+ }
57
+ return chosen;
58
+ }, "choose");
59
+ var yes = /* @__PURE__ */ __name(async (io, prompt) => /^y(es)?$/i.test((await io.ask(prompt)).trim()), "yes");
60
+ var onPath = /* @__PURE__ */ __name((command, env) => {
61
+ const names = process.platform === "win32" ? [".cmd", ".exe", ""].map((ending) => command + ending) : [command];
62
+ return (env.PATH ?? env.Path ?? "").split(delimiter).some((folder) => names.some((name) => {
63
+ try {
64
+ accessSync(join(folder, name), process.platform === "win32" ? constants.F_OK : constants.X_OK);
65
+ return true;
66
+ } catch {
67
+ return false;
68
+ }
69
+ }));
70
+ }, "onPath");
71
+ var installWith = /* @__PURE__ */ __name((argv) => spawnSync(argv[0], argv.slice(1), { stdio: ["inherit", 2, 2] }).status === 0, "installWith");
72
+ var installerHere = /* @__PURE__ */ __name(() => {
73
+ try {
74
+ return installerOf(realpathSync(process.argv[1] ?? ""));
75
+ } catch {
76
+ return "unknown";
77
+ }
78
+ }, "installerHere");
79
+ var suggested = /* @__PURE__ */ __name((env, contentLanguages) => {
80
+ const own = LANGUAGES.filter(({ code }) => contentLanguages?.includes(code));
81
+ const system = systemLanguage(env);
82
+ return (own.length ? own : LANGUAGES.filter(({ code }) => code === "en" || code === system)).map(({ name }) => name);
83
+ }, "suggested");
84
+ var askLanguages = /* @__PURE__ */ __name(async ({ command, env, io, contentLanguages }) => {
85
+ const { openStore } = await import("./store-AH6WZMCF.js");
86
+ const store = await openStore({ env });
87
+ let rebuild = false;
88
+ try {
89
+ const saved = await store.searchIndex.stemmers() ?? void 0;
90
+ const inUse = saved !== void 0 || (await store.accounts.accounts()).length > 0;
91
+ const ticked = inUse ? languagesOf(saved ?? DEFAULT_STEMMERS) : suggested(env, contentLanguages);
92
+ const numbers = ticked.map((name) => LANGUAGES.findIndex((one) => one.name === name) + 1);
93
+ io.say("Languages you write and speak \u2014 search finds every form of their words, and spellings speech mangles:");
94
+ LANGUAGES.forEach(({ name, label }, at) => {
95
+ io.say(` ${at + 1}. ${label}${ticked.includes(name) ? " \u2713" : ""}`);
96
+ });
97
+ const chosen = await choose(io, `Numbers (${numbers.join(",")}): `, LANGUAGES.length, numbers);
98
+ const next = stemmersOf(chosen.map((number) => LANGUAGES[number - 1].name));
99
+ const before = saved ?? DEFAULT_STEMMERS;
100
+ if (inUse && before.cyrillic === next.cyrillic && before.latin === next.latin)
101
+ return;
102
+ if (inUse && !await yes(io, "Rebuild the word forms of every stored message now? Word search waits for it; a large store takes minutes. [y/N] ")) {
103
+ io.say(`Languages kept as they were; \`${command} setup\` asks again.`);
104
+ return;
105
+ }
106
+ await store.searchIndex.saveStemmers(next);
107
+ rebuild = inUse;
108
+ } finally {
109
+ await store.close();
110
+ }
111
+ if (!rebuild)
112
+ return;
113
+ const [{ openCache }, { buildStems }] = await Promise.all([
114
+ import("./open-BR47R5UE.js"),
115
+ import("./store-maintenance-command-PBXX3IEV.js")
116
+ ]);
117
+ const database = await openCache(storePath(env));
118
+ try {
119
+ buildStems(database, (note) => io.say(` ${note}`), { force: true });
120
+ } finally {
121
+ database.close();
122
+ }
123
+ }, "askLanguages");
124
+ var askTools = /* @__PURE__ */ __name(async (run) => {
125
+ const { command, env, io } = run;
126
+ const installed = run.installed ?? ((name) => onPath(name, env));
127
+ const { WIRECAT_TOOLS } = await import("./first-screen-X5IJKBSU.js");
128
+ const others = WIRECAT_TOOLS.filter((tool) => tool.command !== command);
129
+ const missing = others.filter((tool) => !installed(tool.command));
130
+ io.say("Other WireCat tools \u2014 they share this store, so one search finds everything:");
131
+ for (const tool of others) {
132
+ const at = missing.indexOf(tool);
133
+ io.say(` ${at < 0 ? "\u2713 " : `${at + 1}.`} ${tool.command} \u2014 ${tool.does}`);
134
+ }
135
+ if (!missing.length)
136
+ return;
137
+ const chosen = await choose(io, "Numbers to install (none): ", missing.length, []);
138
+ const installer = run.installer ?? installerHere();
139
+ for (const number of chosen) {
140
+ const tool = missing[number - 1];
141
+ const argv = updateCommand(installer, tool.package);
142
+ if (!argv) {
143
+ io.say(`Install ${tool.command} with \`npm install -g ${tool.package}\`.`);
144
+ continue;
145
+ }
146
+ io.say(`Installing ${tool.command}: ${argv.join(" ")}`);
147
+ if (!(run.install ?? installWith)(argv))
148
+ io.say(`${tool.command} was not installed; run \`${argv.join(" ")}\`.`);
149
+ }
150
+ }, "askTools");
151
+ var PERMISSION_CHOICES = [
152
+ { answer: "readonly", text: "read only \u2014 search and read; nothing sends or changes" },
153
+ { answer: "allow", text: "read and write \u2014 as each profile's permissions allow" }
154
+ ];
155
+ var askPermissions = /* @__PURE__ */ __name(async ({ io }, answers) => {
156
+ const now = answers.permissions ?? "allow";
157
+ const current = Math.max(1, PERMISSION_CHOICES.findIndex(({ answer }) => answer === now) + 1);
158
+ io.say("Read only, or read and write? The same for you, scripts and agents over MCP, in every WireCat tool:");
159
+ PERMISSION_CHOICES.forEach(({ text }, at) => {
160
+ io.say(` ${at + 1}. ${text}`);
161
+ });
162
+ const [chosen = current] = await choose(io, `Number (${current}): `, PERMISSION_CHOICES.length, [current]);
163
+ return PERMISSION_CHOICES[chosen - 1].answer;
164
+ }, "askPermissions");
165
+ var answersAt = /* @__PURE__ */ __name((path) => {
166
+ try {
167
+ return readSetupAnswers(path);
168
+ } catch {
169
+ return {};
170
+ }
171
+ }, "answersAt");
172
+ var askSetupQuestions = /* @__PURE__ */ __name(async (run) => {
173
+ const path = sharedConfigPath(storePath(run.env), run.env);
174
+ const answers = answersAt(path);
175
+ const asking = run.all ? [...QUESTIONS] : unanswered(answers);
176
+ for (const question of asking) {
177
+ run.io.say("");
178
+ if (question === "languages") {
179
+ await askLanguages(run);
180
+ writeSetupAnswers(path, { languages: true });
181
+ } else if (question === "tools") {
182
+ await askTools(run);
183
+ writeSetupAnswers(path, { tools: true });
184
+ } else
185
+ writeSetupAnswers(path, { permissions: await askPermissions(run, answers) });
186
+ }
187
+ return asking;
188
+ }, "askSetupQuestions");
189
+ var setupAtStart = /* @__PURE__ */ __name(async (start) => {
190
+ const input = start.input ?? process.stdin;
191
+ const terminal = start.terminal ?? (input.isTTY === true && process.stderr.isTTY === true);
192
+ if (!asksAtStart({ ...start, terminal, readOnlyLock: start.readOnlyLock }))
193
+ return;
194
+ await askSetupQuestions({
195
+ command: start.command,
196
+ env: start.env,
197
+ contentLanguages: start.contentLanguages,
198
+ all: start.path[0] === "setup",
199
+ io: {
200
+ ask: /* @__PURE__ */ __name(async (prompt) => (await import("./prompt-NE5JJ7UP.js")).readSecret(prompt, { input, echo: true }), "ask"),
201
+ say: /* @__PURE__ */ __name((text) => process.stderr.write(`${text}
202
+ `), "say")
203
+ }
204
+ }).catch((error) => {
205
+ process.stderr.write(`setup questions skipped: ${error instanceof Error ? error.message : String(error)} \u2014 \`${start.command} setup\` asks them again
206
+ `);
207
+ });
208
+ }, "setupAtStart");
209
+
210
+ export {
211
+ asksAtStart,
212
+ systemLanguage,
213
+ askSetupQuestions,
214
+ setupAtStart
215
+ };
@@ -0,0 +1,193 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ listen
5
+ } from "./chunk-JRK73FOW.js";
6
+ import {
7
+ ownerLogin
8
+ } from "./chunk-TGB5F7NC.js";
9
+ import {
10
+ WebStandardStreamableHTTPServerTransport,
11
+ createMcpHandler,
12
+ getOAuthProtectedResourceMetadataUrl,
13
+ hostHeaderValidationResponse,
14
+ isLegacyRequest,
15
+ oauthMetadataResponse,
16
+ requireBearerAuth
17
+ } from "./chunk-5D4AEUVA.js";
18
+ import {
19
+ activityRecorder,
20
+ calledTools,
21
+ httpActivityFile,
22
+ httpLock
23
+ } from "./chunk-V3ZTQ24B.js";
24
+ import {
25
+ CliError
26
+ } from "./chunk-EFHLQXG6.js";
27
+ import {
28
+ __name
29
+ } from "./chunk-ZVVMGPBJ.js";
30
+
31
+ // node_modules/.pnpm/@wirecat+cli-core@0.495.0_@wirecat+cli-base@0.65.0_commander@15.0.0_esbuild@0.28.2_type_24cca5e5c8b0984f2f26e7d1ba6b6d47/node_modules/@wirecat/cli-core/dist/mcp/http/serve.js
32
+ import { randomUUID } from "node:crypto";
33
+ var MCP_PATH = "/mcp";
34
+ var AS_METADATA = "/.well-known/oauth-authorization-server";
35
+ var LOCAL = ["localhost", "127.0.0.1"];
36
+ var MAX_SESSIONS = 20;
37
+ var MAX_LOGIN_BODY = 64 * 1024;
38
+ var SESSION_IDLE_MS = 60 * 60 * 1e3;
39
+ var sessionMissing = /* @__PURE__ */ __name(() => new Response(JSON.stringify({ jsonrpc: "2.0", error: { code: -32001, message: "Session not found" }, id: null }), {
40
+ status: 404,
41
+ headers: { "content-type": "application/json" }
42
+ }), "sessionMissing");
43
+ var legacySessions = /* @__PURE__ */ __name((build, now) => {
44
+ const sessions = /* @__PURE__ */ new Map();
45
+ const drop = /* @__PURE__ */ __name(async (id) => {
46
+ const one = sessions.get(id);
47
+ sessions.delete(id);
48
+ await one?.close();
49
+ }, "drop");
50
+ const handle = /* @__PURE__ */ __name(async (request, auth) => {
51
+ for (const [id2, one] of sessions)
52
+ if (now() - one.seen > SESSION_IDLE_MS)
53
+ await drop(id2);
54
+ const id = request.headers.get("mcp-session-id");
55
+ if (id) {
56
+ const known = sessions.get(id);
57
+ if (!known || known.clientId !== auth.clientId)
58
+ return sessionMissing();
59
+ known.seen = now();
60
+ return known.transport.handleRequest(request, { authInfo: auth });
61
+ }
62
+ const server = build();
63
+ const transport = new WebStandardStreamableHTTPServerTransport({
64
+ sessionIdGenerator: /* @__PURE__ */ __name(() => randomUUID(), "sessionIdGenerator"),
65
+ onsessionclosed: /* @__PURE__ */ __name((closed) => void sessions.delete(closed), "onsessionclosed")
66
+ });
67
+ await server.connect(transport);
68
+ const response = await transport.handleRequest(request, { authInfo: auth });
69
+ if (!transport.sessionId) {
70
+ await server.close();
71
+ return response;
72
+ }
73
+ sessions.set(transport.sessionId, { transport, close: /* @__PURE__ */ __name(() => server.close(), "close"), clientId: auth.clientId, seen: now() });
74
+ while (sessions.size > MAX_SESSIONS)
75
+ await drop(sessions.keys().next().value);
76
+ return response;
77
+ }, "handle");
78
+ return {
79
+ handle,
80
+ close: /* @__PURE__ */ __name(async () => {
81
+ for (const id of [...sessions.keys()])
82
+ await drop(id);
83
+ }, "close")
84
+ };
85
+ }, "legacySessions");
86
+ var metadataRequest = /* @__PURE__ */ __name((request, path, base) => {
87
+ const url = new URL(request.url);
88
+ const inserted = base && path === `${AS_METADATA}${base}`;
89
+ if (!inserted && url.pathname === path)
90
+ return request;
91
+ url.pathname = inserted ? AS_METADATA : path;
92
+ return new Request(url, { method: request.method, headers: request.headers });
93
+ }, "metadataRequest");
94
+ var toolsIn = /* @__PURE__ */ __name(async (request) => {
95
+ if (request.method !== "POST")
96
+ return [];
97
+ try {
98
+ return calledTools(await request.clone().json());
99
+ } catch {
100
+ return [];
101
+ }
102
+ }, "toolsIn");
103
+ var serveOverHttp = /* @__PURE__ */ __name(async (build, options) => {
104
+ const { publicUrl, port, tokenFile, appName, onCode, onError, now, lockFile, version } = options;
105
+ const lock = lockFile ? httpLock(lockFile, {
106
+ pid: process.pid,
107
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
108
+ port,
109
+ publicUrl: publicUrl.href,
110
+ ...version ? { version } : {}
111
+ }) : void 0;
112
+ if (lock?.held)
113
+ throw new CliError("validation_error", `${appName} already serves MCP over HTTP for this profile on port ${lock.held.port} (PID ${lock.held.pid}, since ${lock.held.startedAt})`);
114
+ const base = publicUrl.pathname === "/" ? "" : publicUrl.pathname.replace(/\/+$/, "");
115
+ const issuer = new URL(`${publicUrl.origin}${base}`);
116
+ const resource = new URL(`${base}${MCP_PATH}`, publicUrl.origin);
117
+ const mcpPath = resource.pathname;
118
+ const publicPath = /* @__PURE__ */ __name((path) => base && path !== base && !path.startsWith(`${base}/`) && !path.startsWith("/.well-known/") ? `${base}${path}` : path, "publicPath");
119
+ const login = ownerLogin({
120
+ issuer,
121
+ resource,
122
+ file: tokenFile,
123
+ appName,
124
+ onCode: /* @__PURE__ */ __name((code, expires) => {
125
+ lock?.update({ loginCode: code, loginCodeExpiresAt: expires.toISOString() });
126
+ onCode(code, expires);
127
+ }, "onCode"),
128
+ ...now ? { now } : {}
129
+ });
130
+ const insecure = issuer.protocol === "http:" && LOCAL.includes(issuer.hostname);
131
+ const mcp = createMcpHandler(build, { legacy: "reject", ...onError ? { onerror: onError } : {} });
132
+ const legacy = legacySessions(build, now ?? Date.now);
133
+ const bearer = requireBearerAuth({
134
+ verifier: login.verifier,
135
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(resource)
136
+ });
137
+ const activity = activityRecorder(httpActivityFile(tokenFile), now);
138
+ const allowedHosts = [.../* @__PURE__ */ new Set([publicUrl.hostname, ...LOCAL])];
139
+ const allowedOrigins = [publicUrl.origin];
140
+ const listening = await listen(async (request) => {
141
+ const refused = hostHeaderValidationResponse(request, allowedHosts);
142
+ if (refused)
143
+ return refused;
144
+ const path = publicPath(new URL(request.url).pathname);
145
+ const discovery = oauthMetadataResponse(metadataRequest(request, path, base), {
146
+ oauthMetadata: login.metadata,
147
+ resourceServerUrl: resource,
148
+ resourceName: appName,
149
+ ...insecure ? { dangerouslyAllowInsecureIssuerUrl: true } : {}
150
+ });
151
+ if (discovery)
152
+ return discovery;
153
+ if (Number(request.headers.get("content-length") ?? 0) > MAX_LOGIN_BODY && path !== mcpPath)
154
+ return new Response("Request too large", { status: 413 });
155
+ const origin = request.headers.get("origin");
156
+ if (origin && !allowedOrigins.includes(origin))
157
+ return new Response("Origin not allowed", { status: 403 });
158
+ const answered = await login.handle(request, path);
159
+ if (answered)
160
+ return answered;
161
+ if (path !== mcpPath)
162
+ return new Response("Not found", { status: 404 });
163
+ const auth = await bearer(request);
164
+ if (auth instanceof Response)
165
+ return auth;
166
+ activity.record(auth.clientId, await toolsIn(request));
167
+ return await isLegacyRequest(request) ? legacy.handle(request, auth) : mcp.fetch(request, { authInfo: auth });
168
+ }, { host: "127.0.0.1", port }).catch((error) => {
169
+ login.close();
170
+ lock?.release();
171
+ throw error;
172
+ });
173
+ lock?.update({ listeningAt: (/* @__PURE__ */ new Date()).toISOString() });
174
+ return {
175
+ url: listening.url,
176
+ close: /* @__PURE__ */ __name(async () => {
177
+ login.close();
178
+ activity.flush();
179
+ try {
180
+ await listening.close();
181
+ await legacy.close();
182
+ await mcp.close();
183
+ } finally {
184
+ lock?.release();
185
+ }
186
+ }, "close")
187
+ };
188
+ }, "serveOverHttp");
189
+
190
+ export {
191
+ MCP_PATH,
192
+ serveOverHttp
193
+ };