blun-king-cli 9.1.602 → 9.1.603
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/CHANGELOG.md +103 -97
- package/LIESMICH.txt +57 -57
- package/README.md +90 -90
- package/bin/agentspine-king-goal-inbox.mjs +127 -127
- package/bin/agentspine-king-goal-intake.mjs +106 -106
- package/bin/agentspine-king-host-runner.mjs +109 -109
- package/bin/agentspine-king-snapshot-policy.cjs +80 -80
- package/bin/agentspine-king-status-policy.mjs +226 -226
- package/bin/agentspine-king-worker-host.mjs +160 -160
- package/bin/core-bootstrap.js +77 -77
- package/bin/launcher-mode.js +93 -93
- package/bin/launcher-restart-policy.cjs +131 -131
- package/bin/launcher-runtime.js +491 -491
- package/bin/managed-node.js +186 -186
- package/bin/managed-plugin-selection.cjs +115 -115
- package/bin/native-module-repair.js +201 -201
- package/bin/node-runtime.js +34 -34
- package/bin/node-version.js +49 -49
- package/bin/plugin-bootstrap.js +162 -162
- package/bin/private-paths.js +1606 -1606
- package/bin/runtime-exit-ledger.cjs +144 -144
- package/bin/runtime-exit-ledger.d.cts +23 -23
- package/bin/standard-tools-bootstrap.js +272 -272
- package/bin/turn-thinking-policy.cjs +82 -82
- package/bin/update-copy.js +200 -200
- package/bin/update-lease.js +597 -597
- package/bin/update-notice.js +1568 -1568
- package/bin/verify-agent-behavior.cjs +122 -122
- package/bin/verify-agent-components.cjs +104 -104
- package/bin/verify-bundled-agent-sources.cjs +83 -83
- package/bin/windows-node-crash-dump.cjs +289 -289
- package/blun.mjs +115 -7
- package/codebase-index/codebase_index.py +470 -470
- package/dist-web/assets/{CodeBlockNode-CXnTLMNr.js → CodeBlockNode-TKKkJX8L.js} +1 -1
- package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-CCF8Ntnq.js → CodeBlockShell.vue_vue_type_style_index_0_lang-CUj2Ds5x.js} +1 -1
- package/dist-web/assets/DesignSystemView-DwK1aQMo.js +12 -0
- package/dist-web/assets/DesignSystemView-szjTj7ns.css +1 -0
- package/dist-web/assets/{Tooltip-CFQEzqC-.js → Tooltip-CTWv7WCU.js} +1 -1
- package/dist-web/assets/{abnfDiagram-N423BO3Z-Z1APZG5m.js → abnfDiagram-N423BO3Z-DA8V8Zjh.js} +1 -1
- package/dist-web/assets/{arc-C4VyWloT.js → arc-YtddKbdY.js} +1 -1
- package/dist-web/assets/{architectureDiagram-T3A2C74G-DpddbUcM.js → architectureDiagram-T3A2C74G-CGEiObmo.js} +1 -1
- package/dist-web/assets/{blockDiagram-VBNYF7ZC-BqccOSMr.js → blockDiagram-VBNYF7ZC-Bd5Vt50e.js} +1 -1
- package/dist-web/assets/{c4Diagram-5PPSVZJV-OHAcJrTy.js → c4Diagram-5PPSVZJV-D2ApPM54.js} +1 -1
- package/dist-web/assets/channel-BnluexuN.js +1 -0
- package/dist-web/assets/{chunk-2GRJ4B5K-DqJHs8Fw.js → chunk-2GRJ4B5K-BDcIEZSl.js} +1 -1
- package/dist-web/assets/{chunk-2Q5K7J3B-B1nCd91o.js → chunk-2Q5K7J3B-6aSabCX7.js} +1 -1
- package/dist-web/assets/{chunk-5RXB4S5H-neG70kZx.js → chunk-5RXB4S5H-BFRQvIJS.js} +1 -1
- package/dist-web/assets/{chunk-5VM5RSS4-l7biGqeH.js → chunk-5VM5RSS4-ChAa-DNY.js} +1 -1
- package/dist-web/assets/{chunk-6Q2QTUOP-BO-F11Gs.js → chunk-6Q2QTUOP-BIfrb2Jc.js} +1 -1
- package/dist-web/assets/{chunk-GF5L2VYU-BtC69fw0.js → chunk-GF5L2VYU-BR0gvtWI.js} +1 -1
- package/dist-web/assets/{chunk-JWPE2WC7-DIOubEqr.js → chunk-JWPE2WC7-BgXKsx5E.js} +1 -1
- package/dist-web/assets/{chunk-KBJHAD2P-DDUeH_Ba.js → chunk-KBJHAD2P-I8mrZhpz.js} +1 -1
- package/dist-web/assets/{chunk-RYQCIY6F-B9gFMVbS.js → chunk-RYQCIY6F-BMPaem92.js} +1 -1
- package/dist-web/assets/{chunk-XXDRQBXY-Bn1Xz6TQ.js → chunk-XXDRQBXY-COy0J-0j.js} +1 -1
- package/dist-web/assets/classDiagram-JCYQIIEL-BliFdSD9.js +1 -0
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BliFdSD9.js +1 -0
- package/dist-web/assets/{cose-bilkent-JH36ORCC-DqigO3T4.js → cose-bilkent-JH36ORCC-MosTTRdo.js} +1 -1
- package/dist-web/assets/{cynefin-VYW2F7L2-rpD93tQ-.js → cynefin-VYW2F7L2-5tjPgrkP.js} +1 -1
- package/dist-web/assets/{cynefinDiagram-MW4NZA55-DbTqnkVJ.js → cynefinDiagram-MW4NZA55-CbDcdInR.js} +1 -1
- package/dist-web/assets/{dagre-VZM6K2ZE-DcM8aEVY.js → dagre-VZM6K2ZE-YaBom1ZH.js} +1 -1
- package/dist-web/assets/{diagram-7IWD3JNH-UymgsBNa.js → diagram-7IWD3JNH-Da4m-Hgz.js} +1 -1
- package/dist-web/assets/{diagram-B4RE2ZJO-BiYu5WPF.js → diagram-B4RE2ZJO-CAUUegxg.js} +1 -1
- package/dist-web/assets/{diagram-LBJQPF4R-BD3kkgOO.js → diagram-LBJQPF4R-o21mWKG4.js} +1 -1
- package/dist-web/assets/{diagram-Q27KOJAE-D1mYQ_cI.js → diagram-Q27KOJAE-BA3z3sXf.js} +1 -1
- package/dist-web/assets/{diagram-UB23O5K3-BtX8u6HG.js → diagram-UB23O5K3-CGRdSSDK.js} +1 -1
- package/dist-web/assets/{ebnfDiagram-BXEA7PRR-CBAnFkRF.js → ebnfDiagram-BXEA7PRR-Bw-iU9FP.js} +1 -1
- package/dist-web/assets/{erDiagram-JOGREHBK-3vKcWsxm.js → erDiagram-JOGREHBK-BwM1yiR0.js} +1 -1
- package/dist-web/assets/{flowDiagram-UKHOOZJN-D9wBbHm2.js → flowDiagram-UKHOOZJN-z05eOR1Q.js} +1 -1
- package/dist-web/assets/{ganttDiagram-PKOTCBZU-Cd_dViF-.js → ganttDiagram-PKOTCBZU-BMUubNTl.js} +1 -1
- package/dist-web/assets/{gitGraphDiagram-DS77QQ5N-BiEEtTo7.js → gitGraphDiagram-DS77QQ5N-Dccbi1wU.js} +1 -1
- package/dist-web/assets/{index-DdEakFJM.js → index-BBbC5LRF.js} +1 -1
- package/dist-web/assets/{index-BmKj7CB1.css → index-C9eDH3u-.css} +1 -1
- package/dist-web/assets/{index-Ba1OvLjf.js → index-D48p0M2S.js} +2 -2
- package/dist-web/assets/{index-CiPA8Kex.js → index-h0KEOmkU.js} +14 -14
- package/dist-web/assets/{index10-CNr4U-Nw.js → index10-Qbuw1N6u.js} +1 -1
- package/dist-web/assets/{index11-Dto_yZNz.js → index11-g8v025wN.js} +1 -1
- package/dist-web/assets/{index5-B2PldaO2.js → index5-BYNcV8BY.js} +1 -1
- package/dist-web/assets/{index6-CBdZmmyx.js → index6-BetANtnV.js} +1 -1
- package/dist-web/assets/{index7-Dz9oCsUF.js → index7-BcPbgCKN.js} +1 -1
- package/dist-web/assets/{index8-B6k25jtU.js → index8-B1lp-RvF.js} +2 -2
- package/dist-web/assets/{infoDiagram-6WML65LV-D4ph2sIH.js → infoDiagram-6WML65LV-BF_pbUnN.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-WSZJBQD7-DjKjbMm9.js → ishikawaDiagram-WSZJBQD7-Dedv4urS.js} +1 -1
- package/dist-web/assets/{journeyDiagram-NVQOT4AX-DttHDfPQ.js → journeyDiagram-NVQOT4AX-B1Ex3b6o.js} +1 -1
- package/dist-web/assets/{kanban-definition-27J2QSJJ-C5gB-W0d.js → kanban-definition-27J2QSJJ-BtCGliBH.js} +1 -1
- package/dist-web/assets/{linear-BRGe4-d6.js → linear-ByItc8Qr.js} +1 -1
- package/dist-web/assets/{mermaid.core-D-9Sx1No.js → mermaid.core-B1M2O7nN.js} +4 -4
- package/dist-web/assets/{mindmap-definition-FAOFIHXS-Cg_hoVIq.js → mindmap-definition-FAOFIHXS-D0UHKUyj.js} +1 -1
- package/dist-web/assets/{pegDiagram-VL7TDLO6-CSX9hitD.js → pegDiagram-VL7TDLO6-D7zYCVmG.js} +1 -1
- package/dist-web/assets/{pieDiagram-7S7Q4E2Y-0L0mxahZ.js → pieDiagram-7S7Q4E2Y-Bd0i9CHa.js} +1 -1
- package/dist-web/assets/{quadrantDiagram-CIZ2JOQS-U483z0er.js → quadrantDiagram-CIZ2JOQS-MG-Ug47d.js} +1 -1
- package/dist-web/assets/{railroadDiagram-AXF67PYL-D80a2_DJ.js → railroadDiagram-AXF67PYL-AZdl90Gj.js} +1 -1
- package/dist-web/assets/{requirementDiagram-LRYGKXZP-CeyHfq8t.js → requirementDiagram-LRYGKXZP-DjplF9kt.js} +1 -1
- package/dist-web/assets/{sankeyDiagram-W5VNT64P-CCISkkrR.js → sankeyDiagram-W5VNT64P-Bi9Zgfjs.js} +1 -1
- package/dist-web/assets/{sequenceDiagram-SI44F4Z6-jQfm2XS7.js → sequenceDiagram-SI44F4Z6-ChEpdCvb.js} +1 -1
- package/dist-web/assets/{sizeCapture-X5ZJPWSS-lRZsmCoS.js → sizeCapture-X5ZJPWSS-B5RFUdaa.js} +1 -1
- package/dist-web/assets/{stateDiagram-OKZ733FA-ClCgTdUm.js → stateDiagram-OKZ733FA-BkRblSKp.js} +1 -1
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fVkQcACW.js +1 -0
- package/dist-web/assets/{swimlanes-SLNWSIFB-BCdOUN05.js → swimlanes-SLNWSIFB-DLXH6Zhc.js} +2 -2
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-Bg-BiZJQ.js +8 -0
- package/dist-web/assets/{timeline-definition-Z64GVDOM-DpWutSKa.js → timeline-definition-Z64GVDOM-C_N88siO.js} +1 -1
- package/dist-web/assets/{vennDiagram-T6HMQDX7-DVC5JVsc.js → vennDiagram-T6HMQDX7-DMsnvDt0.js} +1 -1
- package/dist-web/assets/{vue.runtime.esm-bundler-BwwRtQwQ.js → vue.runtime.esm-bundler-B-3uIy85.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-T6FBY63Y-BK2mrq7L.js → wardleyDiagram-T6FBY63Y-C9SJIPzq.js} +1 -1
- package/dist-web/assets/{xychartDiagram-ELKLHX3M-DUJu9F7-.js → xychartDiagram-ELKLHX3M-DZLWA6Go.js} +1 -1
- package/dist-web/index.html +32 -32
- package/dist-web/vis/index.html.gz +0 -0
- package/package.json +1 -1
- package/scripts/fix-node-pty-perms.js +53 -53
- package/standard-skills/blun-app-design-system/SKILL.md +30 -30
- package/standard-skills/blun-app-design-system/provenance.json +17 -17
- package/standard-skills/blun-app-design-system/references/tokens.md +48 -48
- package/standard-skills/blun-app-design-system/scripts/check-blun-design.mjs +49 -49
- package/telegram-plugin/blun.plugin.json +20 -20
- package/telegram-plugin/commands/access.md +37 -37
- package/worker-host.mjs +5 -5
- package/dist-web/assets/DesignSystemView-6HgAUEmC.css +0 -1
- package/dist-web/assets/DesignSystemView-BbMOu-XO.js +0 -12
- package/dist-web/assets/channel-B2VOQOI-.js +0 -1
- package/dist-web/assets/classDiagram-JCYQIIEL-BA1TjAxj.js +0 -1
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BA1TjAxj.js +0 -1
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fi_lrTAx.js +0 -1
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-BUd_uYK3.js +0 -8
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { spawnSync } = require('node:child_process');
|
|
4
|
-
const fs = require('node:fs');
|
|
5
|
-
const path = require('node:path');
|
|
6
|
-
|
|
7
|
-
const SQLITE_PROBE = [
|
|
8
|
-
"const Database = require('better-sqlite3');",
|
|
9
|
-
"const db = new Database(':memory:');",
|
|
10
|
-
"const row = db.prepare('SELECT 1 AS ok').get();",
|
|
11
|
-
'db.close();',
|
|
12
|
-
"if (row?.ok !== 1) throw new Error('SQLITE_PROBE_FAILED');",
|
|
13
|
-
].join(' ');
|
|
14
|
-
|
|
15
|
-
function commandFailure(result) {
|
|
16
|
-
return String(result?.stderr || result?.stdout || result?.error?.message || '').trim();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function packageHasDependency(document, dependency) {
|
|
20
|
-
return ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']
|
|
21
|
-
.some((field) => Object.hasOwn(document?.[field] || {}, dependency));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function nearestPackageDirectory(startDir) {
|
|
25
|
-
let current = path.resolve(startDir);
|
|
26
|
-
while (true) {
|
|
27
|
-
if (fs.existsSync(path.join(current, 'package.json'))) return current;
|
|
28
|
-
const parent = path.dirname(current);
|
|
29
|
-
if (parent === current) return null;
|
|
30
|
-
current = parent;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function projectRoot(startDir) {
|
|
35
|
-
let current = path.resolve(startDir);
|
|
36
|
-
while (true) {
|
|
37
|
-
if (fs.existsSync(path.join(current, '.git'))) return current;
|
|
38
|
-
const parent = path.dirname(current);
|
|
39
|
-
if (parent === current) return path.resolve(startDir);
|
|
40
|
-
current = parent;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function readMcpDocument(configPath) {
|
|
45
|
-
if (!fs.existsSync(configPath)) return null;
|
|
46
|
-
try {
|
|
47
|
-
const document = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
48
|
-
return document && typeof document === 'object' ? document : null;
|
|
49
|
-
} catch {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function serverProjectDirectory(server, configPath) {
|
|
55
|
-
if (!server || typeof server !== 'object' || server.enabled === false) return null;
|
|
56
|
-
if (typeof server.cwd === 'string' && server.cwd.trim()) {
|
|
57
|
-
const cwd = server.cwd.trim();
|
|
58
|
-
return nearestPackageDirectory(
|
|
59
|
-
path.isAbsolute(cwd) ? cwd : path.resolve(path.dirname(configPath), cwd),
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
const args = Array.isArray(server.args) ? server.args : [];
|
|
63
|
-
const script = args.find((arg) => typeof arg === 'string' && /\.[cm]?js$/iu.test(arg));
|
|
64
|
-
if (!script) return null;
|
|
65
|
-
const scriptPath = path.isAbsolute(script)
|
|
66
|
-
? script
|
|
67
|
-
: path.resolve(path.dirname(configPath), script);
|
|
68
|
-
return nearestPackageDirectory(path.dirname(scriptPath));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function configuredNativeProjectPaths({ blunDir, callerCwd }) {
|
|
72
|
-
const root = projectRoot(callerCwd);
|
|
73
|
-
const configPaths = [...new Set([
|
|
74
|
-
path.join(blunDir, 'mcp.json'),
|
|
75
|
-
path.join(root, '.mcp.json'),
|
|
76
|
-
path.join(callerCwd, '.blun', 'mcp.json'),
|
|
77
|
-
].map((entry) => path.resolve(entry)))];
|
|
78
|
-
const candidates = [nearestPackageDirectory(callerCwd)];
|
|
79
|
-
for (const configPath of configPaths) {
|
|
80
|
-
const document = readMcpDocument(configPath);
|
|
81
|
-
const servers = document?.mcpServers;
|
|
82
|
-
if (!servers || typeof servers !== 'object' || Array.isArray(servers)) continue;
|
|
83
|
-
for (const server of Object.values(servers)) {
|
|
84
|
-
candidates.push(serverProjectDirectory(server, configPath));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const seen = new Set();
|
|
89
|
-
const projects = [];
|
|
90
|
-
for (const candidate of candidates) {
|
|
91
|
-
if (!candidate) continue;
|
|
92
|
-
const absolute = path.resolve(candidate);
|
|
93
|
-
const key = process.platform === 'win32' ? absolute.toLowerCase() : absolute;
|
|
94
|
-
if (seen.has(key)) continue;
|
|
95
|
-
seen.add(key);
|
|
96
|
-
projects.push(absolute);
|
|
97
|
-
}
|
|
98
|
-
return projects;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function probeBetterSqlite({ nodeBinary, projectDir, spawnSyncImpl }) {
|
|
102
|
-
return spawnSyncImpl(nodeBinary, ['-e', SQLITE_PROBE], {
|
|
103
|
-
cwd: projectDir,
|
|
104
|
-
encoding: 'utf8',
|
|
105
|
-
timeout: 30_000,
|
|
106
|
-
windowsHide: true,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function npmInvocation(nodeBinary) {
|
|
111
|
-
const candidates = [
|
|
112
|
-
path.join(path.dirname(nodeBinary), 'node_modules', 'npm', 'bin', 'npm-cli.js'),
|
|
113
|
-
path.resolve(path.dirname(nodeBinary), '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
|
|
114
|
-
];
|
|
115
|
-
const npmCli = candidates.find((candidate) => fs.existsSync(candidate));
|
|
116
|
-
if (!npmCli) {
|
|
117
|
-
throw new Error('npm-cli.js wurde fuer die aktive Node.js-Laufzeit nicht gefunden.');
|
|
118
|
-
}
|
|
119
|
-
return { args: [npmCli], command: nodeBinary };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function repairNativeProject({
|
|
123
|
-
nodeBinary = process.execPath,
|
|
124
|
-
npmCommand,
|
|
125
|
-
onRepairStart,
|
|
126
|
-
projectDir,
|
|
127
|
-
spawnSyncImpl = spawnSync,
|
|
128
|
-
}) {
|
|
129
|
-
if (typeof projectDir !== 'string' || !path.isAbsolute(projectDir)) {
|
|
130
|
-
throw new Error('Der Projektpfad fuer die native Ladeprobe muss absolut sein.');
|
|
131
|
-
}
|
|
132
|
-
const absoluteProjectDir = path.resolve(projectDir);
|
|
133
|
-
const packagePath = path.join(absoluteProjectDir, 'package.json');
|
|
134
|
-
let packageDocument;
|
|
135
|
-
try {
|
|
136
|
-
packageDocument = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
137
|
-
} catch {
|
|
138
|
-
return { kind: 'skipped', reason: 'package_unreadable' };
|
|
139
|
-
}
|
|
140
|
-
if (!packageHasDependency(packageDocument, 'better-sqlite3')) {
|
|
141
|
-
return { kind: 'skipped', reason: 'dependency_missing' };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const before = probeBetterSqlite({ nodeBinary, projectDir: absoluteProjectDir, spawnSyncImpl });
|
|
145
|
-
if (before.status === 0) return { kind: 'healthy' };
|
|
146
|
-
|
|
147
|
-
const npm = npmCommand === undefined
|
|
148
|
-
? npmInvocation(nodeBinary)
|
|
149
|
-
: { args: [], command: npmCommand };
|
|
150
|
-
onRepairStart?.(absoluteProjectDir);
|
|
151
|
-
const rebuilt = spawnSyncImpl(npm.command, [...npm.args, 'rebuild', 'better-sqlite3'], {
|
|
152
|
-
cwd: absoluteProjectDir,
|
|
153
|
-
encoding: 'utf8',
|
|
154
|
-
timeout: 300_000,
|
|
155
|
-
windowsHide: true,
|
|
156
|
-
});
|
|
157
|
-
if (rebuilt.status !== 0) {
|
|
158
|
-
throw new Error(
|
|
159
|
-
`Native Node.js-Module konnten nicht repariert werden: ${commandFailure(rebuilt) || 'ohne Fehlertext'}`,
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const after = probeBetterSqlite({ nodeBinary, projectDir: absoluteProjectDir, spawnSyncImpl });
|
|
164
|
-
if (after.status !== 0) {
|
|
165
|
-
throw new Error(
|
|
166
|
-
`Ladeprobe nach dem Rebuild fehlgeschlagen: ${commandFailure(after) || 'ohne Fehlertext'}`,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
return { kind: 'repaired' };
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function repairConfiguredNativeModules({
|
|
173
|
-
blunDir,
|
|
174
|
-
callerCwd,
|
|
175
|
-
nodeBinary = process.execPath,
|
|
176
|
-
onRepairStart,
|
|
177
|
-
projectPaths,
|
|
178
|
-
repairProject = repairNativeProject,
|
|
179
|
-
spawnSyncImpl = spawnSync,
|
|
180
|
-
}) {
|
|
181
|
-
const projects = projectPaths || configuredNativeProjectPaths({ blunDir, callerCwd });
|
|
182
|
-
const result = { checked: projects.length, healthy: [], repaired: [], skipped: [] };
|
|
183
|
-
for (const projectDir of projects) {
|
|
184
|
-
const firstResult = repairProject({
|
|
185
|
-
nodeBinary,
|
|
186
|
-
projectDir,
|
|
187
|
-
spawnSyncImpl,
|
|
188
|
-
onRepairStart,
|
|
189
|
-
});
|
|
190
|
-
if (firstResult.kind === 'healthy') result.healthy.push(projectDir);
|
|
191
|
-
else if (firstResult.kind === 'repaired') result.repaired.push(projectDir);
|
|
192
|
-
else result.skipped.push(projectDir);
|
|
193
|
-
}
|
|
194
|
-
return result;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
module.exports = {
|
|
198
|
-
configuredNativeProjectPaths,
|
|
199
|
-
repairConfiguredNativeModules,
|
|
200
|
-
repairNativeProject,
|
|
201
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require('node:child_process');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const SQLITE_PROBE = [
|
|
8
|
+
"const Database = require('better-sqlite3');",
|
|
9
|
+
"const db = new Database(':memory:');",
|
|
10
|
+
"const row = db.prepare('SELECT 1 AS ok').get();",
|
|
11
|
+
'db.close();',
|
|
12
|
+
"if (row?.ok !== 1) throw new Error('SQLITE_PROBE_FAILED');",
|
|
13
|
+
].join(' ');
|
|
14
|
+
|
|
15
|
+
function commandFailure(result) {
|
|
16
|
+
return String(result?.stderr || result?.stdout || result?.error?.message || '').trim();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function packageHasDependency(document, dependency) {
|
|
20
|
+
return ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']
|
|
21
|
+
.some((field) => Object.hasOwn(document?.[field] || {}, dependency));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function nearestPackageDirectory(startDir) {
|
|
25
|
+
let current = path.resolve(startDir);
|
|
26
|
+
while (true) {
|
|
27
|
+
if (fs.existsSync(path.join(current, 'package.json'))) return current;
|
|
28
|
+
const parent = path.dirname(current);
|
|
29
|
+
if (parent === current) return null;
|
|
30
|
+
current = parent;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function projectRoot(startDir) {
|
|
35
|
+
let current = path.resolve(startDir);
|
|
36
|
+
while (true) {
|
|
37
|
+
if (fs.existsSync(path.join(current, '.git'))) return current;
|
|
38
|
+
const parent = path.dirname(current);
|
|
39
|
+
if (parent === current) return path.resolve(startDir);
|
|
40
|
+
current = parent;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function readMcpDocument(configPath) {
|
|
45
|
+
if (!fs.existsSync(configPath)) return null;
|
|
46
|
+
try {
|
|
47
|
+
const document = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
48
|
+
return document && typeof document === 'object' ? document : null;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function serverProjectDirectory(server, configPath) {
|
|
55
|
+
if (!server || typeof server !== 'object' || server.enabled === false) return null;
|
|
56
|
+
if (typeof server.cwd === 'string' && server.cwd.trim()) {
|
|
57
|
+
const cwd = server.cwd.trim();
|
|
58
|
+
return nearestPackageDirectory(
|
|
59
|
+
path.isAbsolute(cwd) ? cwd : path.resolve(path.dirname(configPath), cwd),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const args = Array.isArray(server.args) ? server.args : [];
|
|
63
|
+
const script = args.find((arg) => typeof arg === 'string' && /\.[cm]?js$/iu.test(arg));
|
|
64
|
+
if (!script) return null;
|
|
65
|
+
const scriptPath = path.isAbsolute(script)
|
|
66
|
+
? script
|
|
67
|
+
: path.resolve(path.dirname(configPath), script);
|
|
68
|
+
return nearestPackageDirectory(path.dirname(scriptPath));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function configuredNativeProjectPaths({ blunDir, callerCwd }) {
|
|
72
|
+
const root = projectRoot(callerCwd);
|
|
73
|
+
const configPaths = [...new Set([
|
|
74
|
+
path.join(blunDir, 'mcp.json'),
|
|
75
|
+
path.join(root, '.mcp.json'),
|
|
76
|
+
path.join(callerCwd, '.blun', 'mcp.json'),
|
|
77
|
+
].map((entry) => path.resolve(entry)))];
|
|
78
|
+
const candidates = [nearestPackageDirectory(callerCwd)];
|
|
79
|
+
for (const configPath of configPaths) {
|
|
80
|
+
const document = readMcpDocument(configPath);
|
|
81
|
+
const servers = document?.mcpServers;
|
|
82
|
+
if (!servers || typeof servers !== 'object' || Array.isArray(servers)) continue;
|
|
83
|
+
for (const server of Object.values(servers)) {
|
|
84
|
+
candidates.push(serverProjectDirectory(server, configPath));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const seen = new Set();
|
|
89
|
+
const projects = [];
|
|
90
|
+
for (const candidate of candidates) {
|
|
91
|
+
if (!candidate) continue;
|
|
92
|
+
const absolute = path.resolve(candidate);
|
|
93
|
+
const key = process.platform === 'win32' ? absolute.toLowerCase() : absolute;
|
|
94
|
+
if (seen.has(key)) continue;
|
|
95
|
+
seen.add(key);
|
|
96
|
+
projects.push(absolute);
|
|
97
|
+
}
|
|
98
|
+
return projects;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function probeBetterSqlite({ nodeBinary, projectDir, spawnSyncImpl }) {
|
|
102
|
+
return spawnSyncImpl(nodeBinary, ['-e', SQLITE_PROBE], {
|
|
103
|
+
cwd: projectDir,
|
|
104
|
+
encoding: 'utf8',
|
|
105
|
+
timeout: 30_000,
|
|
106
|
+
windowsHide: true,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function npmInvocation(nodeBinary) {
|
|
111
|
+
const candidates = [
|
|
112
|
+
path.join(path.dirname(nodeBinary), 'node_modules', 'npm', 'bin', 'npm-cli.js'),
|
|
113
|
+
path.resolve(path.dirname(nodeBinary), '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
|
|
114
|
+
];
|
|
115
|
+
const npmCli = candidates.find((candidate) => fs.existsSync(candidate));
|
|
116
|
+
if (!npmCli) {
|
|
117
|
+
throw new Error('npm-cli.js wurde fuer die aktive Node.js-Laufzeit nicht gefunden.');
|
|
118
|
+
}
|
|
119
|
+
return { args: [npmCli], command: nodeBinary };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function repairNativeProject({
|
|
123
|
+
nodeBinary = process.execPath,
|
|
124
|
+
npmCommand,
|
|
125
|
+
onRepairStart,
|
|
126
|
+
projectDir,
|
|
127
|
+
spawnSyncImpl = spawnSync,
|
|
128
|
+
}) {
|
|
129
|
+
if (typeof projectDir !== 'string' || !path.isAbsolute(projectDir)) {
|
|
130
|
+
throw new Error('Der Projektpfad fuer die native Ladeprobe muss absolut sein.');
|
|
131
|
+
}
|
|
132
|
+
const absoluteProjectDir = path.resolve(projectDir);
|
|
133
|
+
const packagePath = path.join(absoluteProjectDir, 'package.json');
|
|
134
|
+
let packageDocument;
|
|
135
|
+
try {
|
|
136
|
+
packageDocument = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
137
|
+
} catch {
|
|
138
|
+
return { kind: 'skipped', reason: 'package_unreadable' };
|
|
139
|
+
}
|
|
140
|
+
if (!packageHasDependency(packageDocument, 'better-sqlite3')) {
|
|
141
|
+
return { kind: 'skipped', reason: 'dependency_missing' };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const before = probeBetterSqlite({ nodeBinary, projectDir: absoluteProjectDir, spawnSyncImpl });
|
|
145
|
+
if (before.status === 0) return { kind: 'healthy' };
|
|
146
|
+
|
|
147
|
+
const npm = npmCommand === undefined
|
|
148
|
+
? npmInvocation(nodeBinary)
|
|
149
|
+
: { args: [], command: npmCommand };
|
|
150
|
+
onRepairStart?.(absoluteProjectDir);
|
|
151
|
+
const rebuilt = spawnSyncImpl(npm.command, [...npm.args, 'rebuild', 'better-sqlite3'], {
|
|
152
|
+
cwd: absoluteProjectDir,
|
|
153
|
+
encoding: 'utf8',
|
|
154
|
+
timeout: 300_000,
|
|
155
|
+
windowsHide: true,
|
|
156
|
+
});
|
|
157
|
+
if (rebuilt.status !== 0) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Native Node.js-Module konnten nicht repariert werden: ${commandFailure(rebuilt) || 'ohne Fehlertext'}`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const after = probeBetterSqlite({ nodeBinary, projectDir: absoluteProjectDir, spawnSyncImpl });
|
|
164
|
+
if (after.status !== 0) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`Ladeprobe nach dem Rebuild fehlgeschlagen: ${commandFailure(after) || 'ohne Fehlertext'}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return { kind: 'repaired' };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function repairConfiguredNativeModules({
|
|
173
|
+
blunDir,
|
|
174
|
+
callerCwd,
|
|
175
|
+
nodeBinary = process.execPath,
|
|
176
|
+
onRepairStart,
|
|
177
|
+
projectPaths,
|
|
178
|
+
repairProject = repairNativeProject,
|
|
179
|
+
spawnSyncImpl = spawnSync,
|
|
180
|
+
}) {
|
|
181
|
+
const projects = projectPaths || configuredNativeProjectPaths({ blunDir, callerCwd });
|
|
182
|
+
const result = { checked: projects.length, healthy: [], repaired: [], skipped: [] };
|
|
183
|
+
for (const projectDir of projects) {
|
|
184
|
+
const firstResult = repairProject({
|
|
185
|
+
nodeBinary,
|
|
186
|
+
projectDir,
|
|
187
|
+
spawnSyncImpl,
|
|
188
|
+
onRepairStart,
|
|
189
|
+
});
|
|
190
|
+
if (firstResult.kind === 'healthy') result.healthy.push(projectDir);
|
|
191
|
+
else if (firstResult.kind === 'repaired') result.repaired.push(projectDir);
|
|
192
|
+
else result.skipped.push(projectDir);
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = {
|
|
198
|
+
configuredNativeProjectPaths,
|
|
199
|
+
repairConfiguredNativeModules,
|
|
200
|
+
repairNativeProject,
|
|
201
|
+
};
|
package/bin/node-runtime.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { ensureManagedNode } = require('./managed-node');
|
|
4
|
-
const { unsupportedNodeMessage } = require('./node-version');
|
|
5
|
-
|
|
6
|
-
async function prepareManagedNodeRuntime(options = {}) {
|
|
7
|
-
const version = options.version || process.versions.node;
|
|
8
|
-
const platform = options.platform || process.platform;
|
|
9
|
-
const arch = options.arch || process.arch;
|
|
10
|
-
const message = unsupportedNodeMessage(version, platform);
|
|
11
|
-
if (message === null) return { kind: 'current' };
|
|
12
|
-
if (platform !== 'darwin' && platform !== 'win32') return { kind: 'failed', message };
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const blunDir = options.blunDir || options.getBlunDir?.();
|
|
16
|
-
const binary = await (options.ensureManagedNode || ensureManagedNode)(
|
|
17
|
-
blunDir,
|
|
18
|
-
platform,
|
|
19
|
-
arch,
|
|
20
|
-
);
|
|
21
|
-
return { binary, kind: 'managed' };
|
|
22
|
-
} catch (error) {
|
|
23
|
-
return {
|
|
24
|
-
kind: 'failed',
|
|
25
|
-
message: [
|
|
26
|
-
'Die automatische Node.js-Einrichtung ist fehlgeschlagen.',
|
|
27
|
-
error && error.message ? error.message : String(error),
|
|
28
|
-
message,
|
|
29
|
-
].join('\n'),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = { prepareManagedNodeRuntime };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ensureManagedNode } = require('./managed-node');
|
|
4
|
+
const { unsupportedNodeMessage } = require('./node-version');
|
|
5
|
+
|
|
6
|
+
async function prepareManagedNodeRuntime(options = {}) {
|
|
7
|
+
const version = options.version || process.versions.node;
|
|
8
|
+
const platform = options.platform || process.platform;
|
|
9
|
+
const arch = options.arch || process.arch;
|
|
10
|
+
const message = unsupportedNodeMessage(version, platform);
|
|
11
|
+
if (message === null) return { kind: 'current' };
|
|
12
|
+
if (platform !== 'darwin' && platform !== 'win32') return { kind: 'failed', message };
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const blunDir = options.blunDir || options.getBlunDir?.();
|
|
16
|
+
const binary = await (options.ensureManagedNode || ensureManagedNode)(
|
|
17
|
+
blunDir,
|
|
18
|
+
platform,
|
|
19
|
+
arch,
|
|
20
|
+
);
|
|
21
|
+
return { binary, kind: 'managed' };
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return {
|
|
24
|
+
kind: 'failed',
|
|
25
|
+
message: [
|
|
26
|
+
'Die automatische Node.js-Einrichtung ist fehlgeschlagen.',
|
|
27
|
+
error && error.message ? error.message : String(error),
|
|
28
|
+
message,
|
|
29
|
+
].join('\n'),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = { prepareManagedNodeRuntime };
|
package/bin/node-version.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const MINIMUM_NODE_VERSION = '24.15.0';
|
|
4
|
-
|
|
5
|
-
function parseNodeVersion(version) {
|
|
6
|
-
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version));
|
|
7
|
-
return match ? match.slice(1).map(Number) : null;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function supportsNodeVersion(version) {
|
|
11
|
-
const actual = parseNodeVersion(version);
|
|
12
|
-
const minimum = parseNodeVersion(MINIMUM_NODE_VERSION);
|
|
13
|
-
if (!actual || !minimum) return false;
|
|
14
|
-
|
|
15
|
-
for (let index = 0; index < minimum.length; index += 1) {
|
|
16
|
-
if (actual[index] > minimum[index]) return true;
|
|
17
|
-
if (actual[index] < minimum[index]) return false;
|
|
18
|
-
}
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function unsupportedNodeMessage(version, platform) {
|
|
23
|
-
if (supportsNodeVersion(version)) return null;
|
|
24
|
-
|
|
25
|
-
const lines = [
|
|
26
|
-
'',
|
|
27
|
-
'BLUN kann mit dieser Node.js-Version nicht starten.',
|
|
28
|
-
`Installiert: Node.js ${version}`,
|
|
29
|
-
`Benoetigt: Node.js ${MINIMUM_NODE_VERSION} oder neuer`,
|
|
30
|
-
'',
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
if (platform === 'darwin') {
|
|
34
|
-
lines.push(`Falls die automatische Einrichtung scheitert: nvm install ${MINIMUM_NODE_VERSION}`);
|
|
35
|
-
} else if (platform === 'win32') {
|
|
36
|
-
lines.push(`Falls die automatische Einrichtung scheitert: Node.js ${MINIMUM_NODE_VERSION} oder neuer von https://nodejs.org/ installieren.`);
|
|
37
|
-
} else {
|
|
38
|
-
lines.push(`Node.js ${MINIMUM_NODE_VERSION} oder neuer installieren: https://nodejs.org/`);
|
|
39
|
-
}
|
|
40
|
-
lines.push('Danach BLUN aktualisieren: npm i -g blun-king-cli@latest', '');
|
|
41
|
-
return lines.join('\n');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
module.exports = {
|
|
45
|
-
MINIMUM_NODE_VERSION,
|
|
46
|
-
parseNodeVersion,
|
|
47
|
-
supportsNodeVersion,
|
|
48
|
-
unsupportedNodeMessage,
|
|
49
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MINIMUM_NODE_VERSION = '24.15.0';
|
|
4
|
+
|
|
5
|
+
function parseNodeVersion(version) {
|
|
6
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version));
|
|
7
|
+
return match ? match.slice(1).map(Number) : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function supportsNodeVersion(version) {
|
|
11
|
+
const actual = parseNodeVersion(version);
|
|
12
|
+
const minimum = parseNodeVersion(MINIMUM_NODE_VERSION);
|
|
13
|
+
if (!actual || !minimum) return false;
|
|
14
|
+
|
|
15
|
+
for (let index = 0; index < minimum.length; index += 1) {
|
|
16
|
+
if (actual[index] > minimum[index]) return true;
|
|
17
|
+
if (actual[index] < minimum[index]) return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function unsupportedNodeMessage(version, platform) {
|
|
23
|
+
if (supportsNodeVersion(version)) return null;
|
|
24
|
+
|
|
25
|
+
const lines = [
|
|
26
|
+
'',
|
|
27
|
+
'BLUN kann mit dieser Node.js-Version nicht starten.',
|
|
28
|
+
`Installiert: Node.js ${version}`,
|
|
29
|
+
`Benoetigt: Node.js ${MINIMUM_NODE_VERSION} oder neuer`,
|
|
30
|
+
'',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
if (platform === 'darwin') {
|
|
34
|
+
lines.push(`Falls die automatische Einrichtung scheitert: nvm install ${MINIMUM_NODE_VERSION}`);
|
|
35
|
+
} else if (platform === 'win32') {
|
|
36
|
+
lines.push(`Falls die automatische Einrichtung scheitert: Node.js ${MINIMUM_NODE_VERSION} oder neuer von https://nodejs.org/ installieren.`);
|
|
37
|
+
} else {
|
|
38
|
+
lines.push(`Node.js ${MINIMUM_NODE_VERSION} oder neuer installieren: https://nodejs.org/`);
|
|
39
|
+
}
|
|
40
|
+
lines.push('Danach BLUN aktualisieren: npm i -g blun-king-cli@latest', '');
|
|
41
|
+
return lines.join('\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
MINIMUM_NODE_VERSION,
|
|
46
|
+
parseNodeVersion,
|
|
47
|
+
supportsNodeVersion,
|
|
48
|
+
unsupportedNodeMessage,
|
|
49
|
+
};
|