@vantaloom/cli 0.15.36 → 0.15.37
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/package.json +23 -23
- package/src/cli.mjs +528 -495
- package/src/lib/install.mjs +16 -3
- package/src/lib/mcp.mjs +264 -0
- package/src/lib/package.mjs +61 -56
package/src/lib/install.mjs
CHANGED
|
@@ -151,7 +151,7 @@ export async function applyPackage(packageRoot, prefix, options) {
|
|
|
151
151
|
|
|
152
152
|
// Copy package contents to install prefix
|
|
153
153
|
const optionalDirs = new Set()
|
|
154
|
-
for (const name of ["bin", "web", "cli"]) {
|
|
154
|
+
for (const name of ["bin", "web", "cli", "skills"]) {
|
|
155
155
|
const src = path.join(packageRoot, name)
|
|
156
156
|
const dst = path.join(prefix, name)
|
|
157
157
|
if (!existsSync(src)) {
|
|
@@ -243,7 +243,7 @@ export async function applyPackage(packageRoot, prefix, options) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
export function assertRuntimePackage(packageRoot) {
|
|
246
|
-
for (const name of ["bin", "web", "cli", "manifest.json"]) {
|
|
246
|
+
for (const name of ["bin", "web", "cli", "skills", "manifest.json"]) {
|
|
247
247
|
if (!existsSync(path.join(packageRoot, name))) {
|
|
248
248
|
throw new Error(`invalid Vantaloom package, missing ${name}: ${packageRoot}`)
|
|
249
249
|
}
|
|
@@ -352,6 +352,19 @@ export function assertSourceRoot(sourceRoot) {
|
|
|
352
352
|
return sourceRoot
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
// copyAgentSkills 把仓库里的 agent skill 打进 runtime 包。skill 是给外部 agent
|
|
356
|
+
// (Claude Code / Cursor / Codex)读的使用手册,"vantaloom mcp install --skill"
|
|
357
|
+
// 从这里取——装了 runtime 的机器上通常没有源码仓库,不随包分发就等于没有。
|
|
358
|
+
export async function copyAgentSkills(sourceRoot, buildSkills) {
|
|
359
|
+
const src = path.join(sourceRoot, "integrations", "agent-skills")
|
|
360
|
+
if (!existsSync(src)) {
|
|
361
|
+
console.error(" warning: integrations/agent-skills not found; runtime package ships without skills")
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
removeKnownPath(buildSkills, path.dirname(buildSkills))
|
|
365
|
+
await copyDir(src, buildSkills)
|
|
366
|
+
}
|
|
367
|
+
|
|
355
368
|
export async function copyStaticWeb(sourceRoot, buildWeb) {
|
|
356
369
|
const exportRoot = path.join(sourceRoot, "apps", "vantaloom", "out")
|
|
357
370
|
if (!existsSync(exportRoot)) {
|
|
@@ -464,7 +477,7 @@ export function writeRuntimePackageMetadata(packageRoot, sourceRoot, platform) {
|
|
|
464
477
|
type: "module",
|
|
465
478
|
os: [runtimeOS],
|
|
466
479
|
cpu: [cpu],
|
|
467
|
-
files: ["bin", "web", "cli", "manifest.json", "VERSION", "README.md"],
|
|
480
|
+
files: ["bin", "web", "cli", "skills", "manifest.json", "VERSION", "README.md"],
|
|
468
481
|
publishConfig: {
|
|
469
482
|
access: "public",
|
|
470
483
|
},
|
package/src/lib/mcp.mjs
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// vantaloom mcp —— 把跨机执行信道(vantaloom-mcp)注册给外部 agent。
|
|
2
|
+
//
|
|
3
|
+
// 为什么需要这条命令:MCP 服务端是随 runtime 分发的一个二进制,装在
|
|
4
|
+
// <prefix>/bin/ 下。要用它,用户(或一个 agent)得先知道那个绝对路径,再手动
|
|
5
|
+
// 编辑三家客户端各自格式不同的配置文件——这一步足以劝退绝大多数人,也让「让
|
|
6
|
+
// 另一个 agent 自己接上」变成一次寻宝游戏。这条命令把路径与配置都算好,能自动
|
|
7
|
+
// 写的就直接写。
|
|
8
|
+
//
|
|
9
|
+
// 三家客户端的配置位置与格式(都用「读—合并—原子写」,先备份):
|
|
10
|
+
// - Claude Code:~/.claude.json JSON,mcpServers 顶层键
|
|
11
|
+
// - Cursor: ~/.cursor/mcp.json JSON,mcpServers 顶层键
|
|
12
|
+
// - Codex: ~/.codex/config.toml TOML,[mcp_servers.<name>] 段
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
copyFileSync,
|
|
16
|
+
cpSync,
|
|
17
|
+
existsSync,
|
|
18
|
+
mkdirSync,
|
|
19
|
+
readFileSync,
|
|
20
|
+
renameSync,
|
|
21
|
+
rmSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
} from "node:fs"
|
|
24
|
+
import os from "node:os"
|
|
25
|
+
import path from "node:path"
|
|
26
|
+
import { binaryName, defaultPrefix, safeDirectory } from "./platform.mjs"
|
|
27
|
+
|
|
28
|
+
// serverName 是注册进各客户端的 MCP 服务端名字,与 skill 同名以便对应。
|
|
29
|
+
const serverName = "vantaloom-fleet"
|
|
30
|
+
|
|
31
|
+
// mcpBinaryPath 返回本机 MCP 服务端的绝对路径(不校验存在性)。
|
|
32
|
+
export function mcpBinaryPath(prefix) {
|
|
33
|
+
return path.join(safeDirectory(prefix ?? defaultPrefix()), "bin", binaryName("vantaloom-mcp"))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// clientTargets 描述三家客户端的配置落点。
|
|
37
|
+
function clientTargets() {
|
|
38
|
+
const home = os.homedir()
|
|
39
|
+
return {
|
|
40
|
+
claude: { label: "Claude Code", file: path.join(home, ".claude.json"), kind: "json" },
|
|
41
|
+
cursor: { label: "Cursor", file: path.join(home, ".cursor", "mcp.json"), kind: "json" },
|
|
42
|
+
codex: { label: "Codex", file: path.join(home, ".codex", "config.toml"), kind: "toml" },
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// serverEntry 是 JSON 客户端的服务端条目。env 里显式写上 VANTALOOM_API:本机
|
|
47
|
+
// 换过端口时用户改一处就够,不必去猜默认值。
|
|
48
|
+
function serverEntry(binary, apiBase) {
|
|
49
|
+
return { command: binary, env: { VANTALOOM_API: apiBase } }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// tomlBlock 是 Codex 的 TOML 段(它的配置不是 JSON,得单独拼)。
|
|
53
|
+
function tomlBlock(binary, apiBase) {
|
|
54
|
+
const escaped = binary.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
|
|
55
|
+
return [
|
|
56
|
+
`[mcp_servers.${serverName}]`,
|
|
57
|
+
`command = "${escaped}"`,
|
|
58
|
+
`args = []`,
|
|
59
|
+
``,
|
|
60
|
+
`[mcp_servers.${serverName}.env]`,
|
|
61
|
+
`VANTALOOM_API = "${apiBase}"`,
|
|
62
|
+
``,
|
|
63
|
+
].join("\n")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// writeAtomic 先落临时文件再 rename,避免写到一半把用户的配置写坏。
|
|
67
|
+
function writeAtomic(file, content) {
|
|
68
|
+
mkdirSync(path.dirname(file), { recursive: true })
|
|
69
|
+
const tmp = `${file}.vantaloom-tmp`
|
|
70
|
+
writeFileSync(tmp, content, "utf8")
|
|
71
|
+
renameSync(tmp, file)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// backupOnce 在首次改动前留一份 .bak(已存在则不覆盖——保住最原始那份)。
|
|
75
|
+
function backupOnce(file) {
|
|
76
|
+
if (!existsSync(file)) return
|
|
77
|
+
const bak = `${file}.vantaloom-bak`
|
|
78
|
+
if (existsSync(bak)) return
|
|
79
|
+
try {
|
|
80
|
+
copyFileSync(file, bak)
|
|
81
|
+
} catch {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// installJSONClient 把服务端条目合并进 JSON 配置的 mcpServers。
|
|
85
|
+
function installJSONClient(target, binary, apiBase, force) {
|
|
86
|
+
let config = {}
|
|
87
|
+
if (existsSync(target.file)) {
|
|
88
|
+
const raw = readFileSync(target.file, "utf8").trim()
|
|
89
|
+
if (raw) {
|
|
90
|
+
try {
|
|
91
|
+
config = JSON.parse(raw)
|
|
92
|
+
} catch (error) {
|
|
93
|
+
// 解析不了就停手:这是用户的配置文件,宁可让他自己看一眼,也不能拿一个
|
|
94
|
+
// 空对象覆盖掉(那会静默清空 Claude Code 的全部本地状态)。
|
|
95
|
+
return { ok: false, detail: `配置文件不是合法 JSON,未改动:${error.message}` }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
100
|
+
return { ok: false, detail: "配置文件顶层不是对象,未改动" }
|
|
101
|
+
}
|
|
102
|
+
const servers = config.mcpServers && typeof config.mcpServers === "object" ? config.mcpServers : {}
|
|
103
|
+
const existing = servers[serverName]
|
|
104
|
+
if (existing && !force) {
|
|
105
|
+
const same = existing.command === binary
|
|
106
|
+
return {
|
|
107
|
+
ok: true,
|
|
108
|
+
detail: same ? "已注册(未改动)" : `已存在同名条目且路径不同(${existing.command})——加 --force 覆盖`,
|
|
109
|
+
skipped: true,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
servers[serverName] = serverEntry(binary, apiBase)
|
|
113
|
+
config.mcpServers = servers
|
|
114
|
+
backupOnce(target.file)
|
|
115
|
+
writeAtomic(target.file, `${JSON.stringify(config, null, 2)}\n`)
|
|
116
|
+
return { ok: true, detail: existing ? "已更新" : "已注册" }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// installTOMLClient 往 Codex 的 config.toml 追加一段。TOML 只做「不存在才追加」:
|
|
120
|
+
// 就地改写 TOML 需要一个完整的解析器,为了一段配置引入那种复杂度不划算,而
|
|
121
|
+
// 追加对合法 TOML 恒安全。
|
|
122
|
+
function installTOMLClient(target, binary, apiBase, force) {
|
|
123
|
+
let existing = ""
|
|
124
|
+
if (existsSync(target.file)) {
|
|
125
|
+
existing = readFileSync(target.file, "utf8")
|
|
126
|
+
}
|
|
127
|
+
if (existing.includes(`[mcp_servers.${serverName}]`)) {
|
|
128
|
+
if (!force) {
|
|
129
|
+
return { ok: true, detail: "已注册(未改动)", skipped: true }
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
detail: `已存在 [mcp_servers.${serverName}] 段,请手动编辑 ${target.file}(TOML 就地改写不做自动合并)`,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
backupOnce(target.file)
|
|
137
|
+
const prefix = existing && !existing.endsWith("\n") ? "\n" : ""
|
|
138
|
+
writeAtomic(target.file, `${existing}${prefix}\n${tomlBlock(binary, apiBase)}`)
|
|
139
|
+
return { ok: true, detail: "已注册" }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// installSkill 把 vantaloom-fleet skill 复制到 Claude Code 的技能目录。
|
|
143
|
+
function installSkill(prefix) {
|
|
144
|
+
const src = path.join(safeDirectory(prefix ?? defaultPrefix()), "skills", serverName)
|
|
145
|
+
if (!existsSync(src)) {
|
|
146
|
+
return { ok: false, detail: `runtime 未附带 skill(缺 ${src})——需要 ≥0.15.37 的 runtime` }
|
|
147
|
+
}
|
|
148
|
+
const dst = path.join(os.homedir(), ".claude", "skills", serverName)
|
|
149
|
+
mkdirSync(path.dirname(dst), { recursive: true })
|
|
150
|
+
rmSync(dst, { recursive: true, force: true })
|
|
151
|
+
cpSync(src, dst, { recursive: true, force: true })
|
|
152
|
+
return { ok: true, detail: dst }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// runMcp 是 "vantaloom mcp [path|print|install]" 的入口。
|
|
156
|
+
export async function runMcp(subcommand, options) {
|
|
157
|
+
const prefix = safeDirectory(options.prefix ?? defaultPrefix())
|
|
158
|
+
const binary = mcpBinaryPath(prefix)
|
|
159
|
+
const apiBase = (options.api ?? "http://127.0.0.1:8780").replace(/\/+$/, "")
|
|
160
|
+
const action = subcommand ?? "status"
|
|
161
|
+
|
|
162
|
+
if (action === "path") {
|
|
163
|
+
console.log(binary)
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (action === "print") {
|
|
168
|
+
printSnippets(binary, apiBase)
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (action === "status") {
|
|
173
|
+
printStatus(binary, apiBase, prefix)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (action !== "install") {
|
|
178
|
+
throw new Error(`unknown "vantaloom mcp" subcommand "${action}" (expected: status|path|print|install)`)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!existsSync(binary)) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`未找到 MCP 服务端:${binary}\n` +
|
|
184
|
+
`请先安装/更新 runtime(vantaloom update),或用 --prefix 指定安装目录。`
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const targets = clientTargets()
|
|
189
|
+
const requested = String(options.client ?? "all").toLowerCase()
|
|
190
|
+
const names = requested === "all" ? Object.keys(targets) : requested.split(",").map((s) => s.trim())
|
|
191
|
+
|
|
192
|
+
console.log(`MCP 服务端:${binary}`)
|
|
193
|
+
for (const name of names) {
|
|
194
|
+
const target = targets[name]
|
|
195
|
+
if (!target) {
|
|
196
|
+
console.error(` ${name}: 未知客户端(可选 claude / cursor / codex / all)`)
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
let result
|
|
200
|
+
try {
|
|
201
|
+
result =
|
|
202
|
+
target.kind === "json"
|
|
203
|
+
? installJSONClient(target, binary, apiBase, Boolean(options.force))
|
|
204
|
+
: installTOMLClient(target, binary, apiBase, Boolean(options.force))
|
|
205
|
+
} catch (error) {
|
|
206
|
+
result = { ok: false, detail: error.message }
|
|
207
|
+
}
|
|
208
|
+
const mark = result.ok ? (result.skipped ? "•" : "✓") : "✗"
|
|
209
|
+
console.log(` ${mark} ${target.label}: ${result.detail} (${target.file})`)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (options.skill !== false) {
|
|
213
|
+
const skill = installSkill(prefix)
|
|
214
|
+
console.log(` ${skill.ok ? "✓" : "✗"} skill: ${skill.detail}`)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
console.log(
|
|
218
|
+
`\n重启对应客户端后,让它「列出我的 Vantaloom 机器」即可验证(会调用 machines_list)。` +
|
|
219
|
+
`\n注意:MCP 服务端由客户端拉起,与 Vantaloom 运行时各自独立——但它需要本机运行时在跑。`
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function printStatus(binary, apiBase, prefix) {
|
|
224
|
+
const installed = existsSync(binary)
|
|
225
|
+
console.log(`MCP 服务端:${binary}${installed ? "" : " (未找到——先跑 vantaloom update)"}`)
|
|
226
|
+
console.log(`本机 API: ${apiBase}`)
|
|
227
|
+
console.log(`skill: ${path.join(prefix, "skills", serverName)}`)
|
|
228
|
+
console.log("")
|
|
229
|
+
const targets = clientTargets()
|
|
230
|
+
for (const [, target] of Object.entries(targets)) {
|
|
231
|
+
let state = "未注册"
|
|
232
|
+
if (existsSync(target.file)) {
|
|
233
|
+
const raw = readFileSync(target.file, "utf8")
|
|
234
|
+
if (target.kind === "json") {
|
|
235
|
+
try {
|
|
236
|
+
const parsed = JSON.parse(raw || "{}")
|
|
237
|
+
if (parsed?.mcpServers?.[serverName]) state = "已注册"
|
|
238
|
+
} catch {
|
|
239
|
+
state = "配置文件无法解析"
|
|
240
|
+
}
|
|
241
|
+
} else if (raw.includes(`[mcp_servers.${serverName}]`)) {
|
|
242
|
+
state = "已注册"
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
state = "未找到配置文件"
|
|
246
|
+
}
|
|
247
|
+
console.log(` ${target.label.padEnd(12)} ${state} (${target.file})`)
|
|
248
|
+
}
|
|
249
|
+
console.log(`\n一键注册:vantaloom mcp install (全部客户端 + skill)`)
|
|
250
|
+
console.log(`单独注册:vantaloom mcp install --client cursor`)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function printSnippets(binary, apiBase) {
|
|
254
|
+
const jsonSnippet = JSON.stringify({ mcpServers: { [serverName]: serverEntry(binary, apiBase) } }, null, 2)
|
|
255
|
+
console.log("# Claude Code (~/.claude.json) / Cursor (~/.cursor/mcp.json)")
|
|
256
|
+
console.log(jsonSnippet)
|
|
257
|
+
console.log("\n# Codex (~/.codex/config.toml)")
|
|
258
|
+
console.log(tomlBlock(binary, apiBase))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// mcpHint 是 install/update 结束时打印的一行指引。
|
|
262
|
+
export function mcpHint(prefix) {
|
|
263
|
+
return `提示:让 Claude Code / Cursor / Codex 驱动这台机器与整个组网 —— vantaloom mcp install(MCP 服务端在 ${mcpBinaryPath(prefix)})`
|
|
264
|
+
}
|
package/src/lib/package.mjs
CHANGED
|
@@ -1,56 +1,61 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs"
|
|
2
|
-
import path from "node:path"
|
|
3
|
-
import { platformId, removeKnownPath, runPnpm } from "./platform.mjs"
|
|
4
|
-
import {
|
|
5
|
-
buildGo,
|
|
6
|
-
copyStaticWeb,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
buildGo(sourceRoot, buildBin, "vantaloom-
|
|
33
|
-
buildGo(sourceRoot, buildBin, "
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
await
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
import { mkdirSync } from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { platformId, removeKnownPath, runPnpm } from "./platform.mjs"
|
|
4
|
+
import {
|
|
5
|
+
buildGo,
|
|
6
|
+
copyStaticWeb,
|
|
7
|
+
copyAgentSkills,
|
|
8
|
+
copyCliDirectory,
|
|
9
|
+
writeBuildManifest,
|
|
10
|
+
writeRuntimePackageMetadata,
|
|
11
|
+
runtimeConfigFromSource,
|
|
12
|
+
gitVersion,
|
|
13
|
+
npmPackageVersion,
|
|
14
|
+
} from "./install.mjs"
|
|
15
|
+
|
|
16
|
+
export async function buildRuntimePackage(sourceRoot, packageRoot, options) {
|
|
17
|
+
// Every build — npm release AND local/dev — stamps VERSION/manifest with the
|
|
18
|
+
// npm package version. There is exactly ONE product version (the npm semver);
|
|
19
|
+
// the git hash is recorded separately as manifest `commit` for diagnostics.
|
|
20
|
+
// History: pre-0.13.5 local builds stamped the git hash into VERSION, which
|
|
21
|
+
// split the version universe in two (the desktop shell read VERSION, the
|
|
22
|
+
// settings page read cli/package.json) and broke update prompts both ways.
|
|
23
|
+
const version = npmPackageVersion(sourceRoot)
|
|
24
|
+
const commit = gitVersion(sourceRoot)
|
|
25
|
+
const platform = options.target ?? platformId()
|
|
26
|
+
const buildBin = path.join(packageRoot, "bin")
|
|
27
|
+
const buildWeb = path.join(packageRoot, "web")
|
|
28
|
+
|
|
29
|
+
removeKnownPath(packageRoot, path.dirname(packageRoot))
|
|
30
|
+
mkdirSync(buildBin, { recursive: true })
|
|
31
|
+
|
|
32
|
+
buildGo(sourceRoot, buildBin, "vantaloom-api", platform)
|
|
33
|
+
buildGo(sourceRoot, buildBin, "vantaloom-agent", platform)
|
|
34
|
+
buildGo(sourceRoot, buildBin, "vantaloomctl", platform)
|
|
35
|
+
// vantaloom-mcp:跨机执行信道的 MCP 服务端(agent-bridge)。随 runtime bin 分发,
|
|
36
|
+
// 外部 agent(Claude Code / Codex / Cursor)配置指向它即可驱动整个组网。
|
|
37
|
+
buildGo(sourceRoot, buildBin, "vantaloom-mcp", platform)
|
|
38
|
+
// 0.14.26: the browser moved into the official optional PLUGIN
|
|
39
|
+
// (@vantaloom/browser-plugin-<platform>, built by scripts/build-browser-plugin.ps1) —
|
|
40
|
+
// the runtime no longer builds the vantaloom-browser sidecar nor bundles the
|
|
41
|
+
// Obscura engine. The Windows system-tray app (vantaloom-tray) was removed
|
|
42
|
+
// earlier — it crash-looped on some Windows 11 builds. Neither is built here.
|
|
43
|
+
|
|
44
|
+
if (options.buildWeb) {
|
|
45
|
+
runPnpm(["--filter", "vantaloom-app", "build"], { cwd: sourceRoot })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await copyStaticWeb(sourceRoot, buildWeb)
|
|
49
|
+
await copyCliDirectory(path.join(packageRoot, "cli"), sourceRoot, runtimeConfigFromSource(sourceRoot))
|
|
50
|
+
// agent skill:外部 agent(Claude Code 等)用来学会怎么用 vantaloom-mcp。
|
|
51
|
+
// 随 runtime 分发,"vantaloom mcp install --skill" 才有东西可装——否则用户
|
|
52
|
+
// 得先去仓库里找它,而装了 runtime 的机器上多半没有仓库。
|
|
53
|
+
await copyAgentSkills(sourceRoot, path.join(packageRoot, "skills"))
|
|
54
|
+
writeBuildManifest(packageRoot, version, platform, commit)
|
|
55
|
+
|
|
56
|
+
return { platform, version }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// copyObscura was removed in 0.14.26: the Obscura engine ships inside the
|
|
60
|
+
// official browser PLUGIN packages (scripts/build-browser-plugin.ps1), not the
|
|
61
|
+
// runtime.
|