chain-insights 0.19.0 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -121
- package/bin/cli.js +4 -4
- package/bin/install.cjs +137 -113
- package/bin/mcp-proxy.cjs +7 -5
- package/dist/{action-log-Dfe88TwV.cjs → action-log-HniMMF7f.cjs} +1 -1
- package/dist/action-log-diTHyMbV.mjs.map +1 -1
- package/dist/active-BQopLul8.mjs.map +1 -1
- package/dist/{active-Bj6dohpc.cjs → active-Bc13hJIm.cjs} +1 -1
- package/dist/{app-CJwx_2Rr.mjs → app-7NRCqx_Q.mjs} +2 -2
- package/dist/app-7NRCqx_Q.mjs.map +1 -0
- package/dist/{app-D4Cm69ob.cjs → app-l9JE6bt3.cjs} +5 -5
- package/dist/{artifact-server-sJBFGcum.cjs → artifact-server-CH-asxF5.cjs} +3 -2
- package/dist/{artifact-server-D1D-_t5l.mjs → artifact-server-DoxJr0z8.mjs} +4 -3
- package/dist/artifact-server-DoxJr0z8.mjs.map +1 -0
- package/dist/{capabilities-CxvK7LKZ.mjs → capabilities-BZI6qROg.mjs} +2 -2
- package/dist/capabilities-BZI6qROg.mjs.map +1 -0
- package/dist/{capabilities-CZYijWbg.cjs → capabilities-CPcrxodx.cjs} +2 -2
- package/dist/cli.cjs +42 -216
- package/dist/cli.mjs +36 -210
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Bjxo7AEa.cjs → client-CqAzD519.cjs} +4 -4
- package/dist/{client-i3WtsKA4.mjs → client-D4aM4bzP.mjs} +4 -4
- package/dist/client-D4aM4bzP.mjs.map +1 -0
- package/dist/{config-DE0dUT3P.cjs → config-BVFf3v8-.cjs} +2 -2
- package/dist/{config-DA6KRx60.mjs → config-CnNMdt4M.mjs} +2 -2
- package/dist/config-CnNMdt4M.mjs.map +1 -0
- package/dist/graph-normalizer-BA3Rbd6l.mjs.map +1 -1
- package/dist/graph-reports-B6yoYbPq.mjs.map +1 -1
- package/dist/{graph-reports-DSHSp5HL.cjs → graph-reports-_gqzxvvs.cjs} +2 -2
- package/dist/{html-generator-Ui29DLSD.cjs → html-generator-B9f_GIi2.cjs} +4 -3
- package/dist/{html-generator-ClysZjfY.mjs → html-generator-D2BDzLED.mjs} +3 -2
- package/dist/{html-generator-ClysZjfY.mjs.map → html-generator-D2BDzLED.mjs.map} +1 -1
- package/dist/index.cjs +9 -9
- package/dist/index.d.cts +3 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -9
- package/dist/{init-BT3STWBv.mjs → init-Djhml4ih.mjs} +3 -3
- package/dist/init-Djhml4ih.mjs.map +1 -0
- package/dist/{init-BR4SRTAY.cjs → init-DvrKxK15.cjs} +3 -3
- package/dist/limits-D3Mn-gig.mjs.map +1 -1
- package/dist/mcp-endpoint-DbWtLcba.mjs.map +1 -1
- package/dist/mcp-proxy.cjs +19 -18
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +13 -12
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{merge-CJRZpuZ4.mjs → merge-BZw-pMPN.mjs} +2 -2
- package/dist/merge-BZw-pMPN.mjs.map +1 -0
- package/dist/{merge-B_5kxbGv.cjs → merge-C52eaAGU.cjs} +1 -1
- package/dist/{output-root-C1PFNCqb.cjs → output-root-BewoQaTx.cjs} +2 -2
- package/dist/{public-tools-CgiKgYgf.cjs → public-tools-BFs_7U_Z.cjs} +8 -7
- package/dist/{public-tools-B9_wXs2o.mjs → public-tools-BjqZGGAC.mjs} +7 -6
- package/dist/public-tools-BjqZGGAC.mjs.map +1 -0
- package/dist/{rolldown-runtime-DakpK96I.cjs → rolldown-runtime-C0BPl7ul.cjs} +1 -1
- package/dist/{schema-DF0aOXII.cjs → schema-BpeV3xDV.cjs} +5 -2
- package/dist/{schema-0BVyF-aL.mjs → schema-DOJA2nNi.mjs} +5 -2
- package/dist/schema-DOJA2nNi.mjs.map +1 -0
- package/dist/{schema-cache-DwDvPy4e.mjs → schema-cache-DJdU4MIP.mjs} +2 -2
- package/dist/{schema-cache-DwDvPy4e.mjs.map → schema-cache-DJdU4MIP.mjs.map} +1 -1
- package/dist/{schema-cache-CX0r2UQp.cjs → schema-cache-n7Gbhvsj.cjs} +2 -2
- package/dist/{server-ta1oyJ2a.cjs → server-CmvzYu7v.cjs} +4 -3
- package/dist/{server-BXj6BRI1.mjs → server-mDSRgk1X.mjs} +4 -3
- package/dist/server-mDSRgk1X.mjs.map +1 -0
- package/dist/tool-visibility-C0ALejXI.mjs.map +1 -1
- package/dist/{tool-visibility-DMIEexib.cjs → tool-visibility-DZBAP62b.cjs} +1 -1
- package/dist/{tools-CWwX4yth.mjs → tools-BKLnlBG1.mjs} +8 -6
- package/dist/tools-BKLnlBG1.mjs.map +1 -0
- package/dist/{tools-BPfUpCUR.cjs → tools-lPY6k-vJ.cjs} +8 -6
- package/dist/{topup-server-VGl8-Fz5.cjs → topup-server-DAqmAuu1.cjs} +23 -21
- package/dist/{topup-server-D2X7My7i.mjs → topup-server-rqI7bqem.mjs} +23 -21
- package/dist/topup-server-rqI7bqem.mjs.map +1 -0
- package/dist/update-CJUfGCxs.mjs.map +1 -1
- package/dist/{usage-status-H1xgCu99.cjs → usage-status-BdwwgYsu.cjs} +2 -2
- package/dist/{usage-status-D2uosC7s.mjs → usage-status-CHiOPA-2.mjs} +2 -2
- package/dist/usage-status-CHiOPA-2.mjs.map +1 -0
- package/dist/version-BA3J8hu4.mjs.map +1 -1
- package/dist/{viz-HSwLcKr6.cjs → viz-BJ_kyRjI.cjs} +7 -5
- package/dist/{viz-Cq1jSWSH.mjs → viz-Uh_EF-qB.mjs} +6 -4
- package/dist/viz-Uh_EF-qB.mjs.map +1 -0
- package/dist/{wallet-C2yVjcSY.cjs → wallet-BEvHrHi3.cjs} +3 -2
- package/dist/{wallet-BrTTnf7w.mjs → wallet-fMbhvKXT.mjs} +3 -2
- package/dist/wallet-fMbhvKXT.mjs.map +1 -0
- package/docs/architecture.md +18 -18
- package/docs/debugging.md +2 -42
- package/docs/development.md +0 -27
- package/docs/graph-query-compatibility.md +66 -57
- package/docs/graph-tools.md +6 -6
- package/docs/investigation-workspaces.md +0 -35
- package/docs/mcp-proxy.md +8 -9
- package/docs/search-limits.md +8 -8
- package/docs/stability.md +4 -5
- package/package.json +1 -5
- package/skills/chain-insights-cypher/SKILL.md +7 -7
- package/skills/chain-insights-cypher/agents/openai.yaml +3 -3
- package/skills/chain-insights-schema-bittensor/SKILL.md +26 -26
- package/skills/chain-insights-schema-evm/SKILL.md +37 -37
- package/dist/app-CJwx_2Rr.mjs.map +0 -1
- package/dist/artifact-server-D1D-_t5l.mjs.map +0 -1
- package/dist/capabilities-CxvK7LKZ.mjs.map +0 -1
- package/dist/cases-C1XewLdx.mjs +0 -155
- package/dist/cases-C1XewLdx.mjs.map +0 -1
- package/dist/cases-CVtc7Rf8.cjs +0 -160
- package/dist/client-i3WtsKA4.mjs.map +0 -1
- package/dist/config-CwIb-tav.mjs +0 -33
- package/dist/config-CwIb-tav.mjs.map +0 -1
- package/dist/config-Cy-qzx4W.cjs +0 -33
- package/dist/config-DA6KRx60.mjs.map +0 -1
- package/dist/init-9jY5rCcH.cjs +0 -24
- package/dist/init-BT3STWBv.mjs.map +0 -1
- package/dist/init-BiRfMQcA.mjs +0 -26
- package/dist/init-BiRfMQcA.mjs.map +0 -1
- package/dist/lock-Cs-a3Ng1.cjs +0 -38
- package/dist/lock-D_sWGS7W.mjs +0 -40
- package/dist/lock-D_sWGS7W.mjs.map +0 -1
- package/dist/merge-CJRZpuZ4.mjs.map +0 -1
- package/dist/paths-CffVTUCv.cjs +0 -31
- package/dist/paths-_3isihzD.mjs +0 -21
- package/dist/paths-_3isihzD.mjs.map +0 -1
- package/dist/public-tools-B9_wXs2o.mjs.map +0 -1
- package/dist/render-TmSq0f4f.cjs +0 -207
- package/dist/render-mxE0Tdsf.mjs +0 -206
- package/dist/render-mxE0Tdsf.mjs.map +0 -1
- package/dist/report-BFXFrJmj.mjs +0 -36
- package/dist/report-BFXFrJmj.mjs.map +0 -1
- package/dist/report-BwKQqOCR.cjs +0 -36
- package/dist/runner-CSss8Hvy.mjs +0 -33
- package/dist/runner-CSss8Hvy.mjs.map +0 -1
- package/dist/runner-aErdz2zn.cjs +0 -31
- package/dist/schema-0BVyF-aL.mjs.map +0 -1
- package/dist/server-BXj6BRI1.mjs.map +0 -1
- package/dist/tools-CWwX4yth.mjs.map +0 -1
- package/dist/topup-server-D2X7My7i.mjs.map +0 -1
- package/dist/usage-status-D2uosC7s.mjs.map +0 -1
- package/dist/viz-Cq1jSWSH.mjs.map +0 -1
- package/dist/wallet-BrTTnf7w.mjs.map +0 -1
- package/docs/monitoring.md +0 -277
package/bin/install.cjs
CHANGED
|
@@ -1,50 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict'
|
|
2
|
+
'use strict'
|
|
3
3
|
|
|
4
4
|
// Chain Insights installer — CJS, stdlib-only.
|
|
5
5
|
// Runs before node_modules exists; zero npm imports allowed.
|
|
6
6
|
// Extension is .cjs (not .js) because package.json has "type": "module" —
|
|
7
7
|
// a .js file would be treated as ESM and require() calls would crash.
|
|
8
8
|
|
|
9
|
-
const fs
|
|
10
|
-
const path = require('path')
|
|
11
|
-
const os
|
|
9
|
+
const fs = require('fs')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
const os = require('os')
|
|
12
12
|
|
|
13
13
|
// ANSI colors — no chalk
|
|
14
|
-
const cyan
|
|
15
|
-
const green = '\x1b[32m'
|
|
16
|
-
const bold
|
|
17
|
-
const dim
|
|
18
|
-
const reset = '\x1b[0m'
|
|
14
|
+
const cyan = '\x1b[36m'
|
|
15
|
+
const green = '\x1b[32m'
|
|
16
|
+
const bold = '\x1b[1m'
|
|
17
|
+
const dim = '\x1b[2m'
|
|
18
|
+
const reset = '\x1b[0m'
|
|
19
19
|
|
|
20
20
|
// Parse args
|
|
21
|
-
const args
|
|
22
|
-
const hasClaude = args.includes('--claude')
|
|
23
|
-
const hasCodex
|
|
24
|
-
const hasHermes = args.includes('--hermes')
|
|
25
|
-
const hasLocal
|
|
21
|
+
const args = process.argv.slice(2)
|
|
22
|
+
const hasClaude = args.includes('--claude')
|
|
23
|
+
const hasCodex = args.includes('--codex')
|
|
24
|
+
const hasHermes = args.includes('--hermes')
|
|
25
|
+
const hasLocal = args.includes('--local')
|
|
26
26
|
|
|
27
27
|
if (!hasClaude && !hasCodex && !hasHermes && !hasLocal) {
|
|
28
|
-
console.log(`\n${bold}chain-insights installer${reset}`)
|
|
29
|
-
console.log(`\nUsage: node bin/install.cjs --claude | --codex | --hermes`)
|
|
30
|
-
console.log(` ${cyan}--claude${reset} Install Claude Code skills globally to ~/.claude/skills/`)
|
|
31
|
-
console.log(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
console.log(
|
|
35
|
-
|
|
28
|
+
console.log(`\n${bold}chain-insights installer${reset}`)
|
|
29
|
+
console.log(`\nUsage: node bin/install.cjs --claude | --codex | --hermes`)
|
|
30
|
+
console.log(` ${cyan}--claude${reset} Install Claude Code skills globally to ~/.claude/skills/`)
|
|
31
|
+
console.log(
|
|
32
|
+
` ${cyan}--codex${reset} Install Codex skills globally to ~/.codex/skills/ and register MCP`
|
|
33
|
+
)
|
|
34
|
+
console.log(
|
|
35
|
+
` ${cyan}--hermes${reset} Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP`
|
|
36
|
+
)
|
|
37
|
+
console.log(
|
|
38
|
+
` ${cyan}--local${reset} Install skills locally to ./.claude/commands/chain-insights/`
|
|
39
|
+
)
|
|
40
|
+
console.log('')
|
|
41
|
+
process.exit(0)
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
const homeDir
|
|
39
|
-
const dataDir
|
|
40
|
-
const configPath = path.join(dataDir, 'config.json')
|
|
41
|
-
const srcSkillsDir = path.join(__dirname, '..', 'skills')
|
|
44
|
+
const homeDir = os.homedir()
|
|
45
|
+
const dataDir = path.join(homeDir, '.chain-insights')
|
|
46
|
+
const configPath = path.join(dataDir, 'config.json')
|
|
47
|
+
const srcSkillsDir = path.join(__dirname, '..', 'skills')
|
|
42
48
|
const PUBLIC_SKILL_NAMES = Object.freeze([
|
|
43
49
|
'chain-insights-address-risk',
|
|
44
50
|
'chain-insights-cypher',
|
|
45
51
|
'chain-insights-schema-bittensor',
|
|
46
52
|
'chain-insights-schema-evm',
|
|
47
|
-
])
|
|
53
|
+
])
|
|
48
54
|
const RETIRED_SKILL_NAMES = Object.freeze([
|
|
49
55
|
'chain-insights-bittensor-cypher',
|
|
50
56
|
'chain-insights-developer-experience',
|
|
@@ -52,65 +58,74 @@ const RETIRED_SKILL_NAMES = Object.freeze([
|
|
|
52
58
|
'chain-insights-monitoring',
|
|
53
59
|
'ci-status',
|
|
54
60
|
'test-chain-insights-graph',
|
|
55
|
-
])
|
|
61
|
+
])
|
|
56
62
|
|
|
57
63
|
// Determine skills targets
|
|
58
|
-
const skillsTargets = []
|
|
59
|
-
if (hasClaude)
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
64
|
+
const skillsTargets = []
|
|
65
|
+
if (hasClaude)
|
|
66
|
+
skillsTargets.push({ name: 'Claude Code', dir: path.join(homeDir, '.claude', 'skills') })
|
|
67
|
+
if (hasCodex) skillsTargets.push({ name: 'Codex', dir: path.join(homeDir, '.codex', 'skills') })
|
|
68
|
+
if (hasHermes)
|
|
69
|
+
skillsTargets.push({
|
|
70
|
+
name: 'Hermes',
|
|
71
|
+
dir: path.join(homeDir, '.hermes', 'skills', 'chain-insights'),
|
|
72
|
+
})
|
|
73
|
+
if (hasLocal)
|
|
74
|
+
skillsTargets.push({
|
|
75
|
+
name: 'Local Claude commands',
|
|
76
|
+
dir: path.join(process.cwd(), '.claude', 'commands', 'chain-insights'),
|
|
77
|
+
})
|
|
63
78
|
|
|
64
79
|
// ─── 1. Copy agent skills ─────────────────────────────────────────────────
|
|
65
80
|
|
|
66
81
|
function copyCommandsAsClaudeSkills(srcDir, targetDir) {
|
|
67
82
|
if (!fs.existsSync(srcDir)) {
|
|
68
|
-
throw new Error(`Skills source not found: ${srcDir}`)
|
|
83
|
+
throw new Error(`Skills source not found: ${srcDir}`)
|
|
69
84
|
}
|
|
70
85
|
|
|
71
|
-
fs.mkdirSync(targetDir, { recursive: true })
|
|
86
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
72
87
|
|
|
73
88
|
// The target is shared with user-owned skills. Remove only the exact retired
|
|
74
89
|
// names from older Chain Insights releases, then replace the reviewed set.
|
|
75
90
|
// Never delete by prefix or enumerate arbitrary source directories.
|
|
76
91
|
|
|
77
92
|
const copyTree = (src, dest) => {
|
|
78
|
-
const stat = fs.statSync(src)
|
|
93
|
+
const stat = fs.statSync(src)
|
|
79
94
|
if (stat.isDirectory()) {
|
|
80
|
-
fs.mkdirSync(dest, { recursive: true })
|
|
95
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
81
96
|
for (const child of fs.readdirSync(src)) {
|
|
82
|
-
copyTree(path.join(src, child), path.join(dest, child))
|
|
97
|
+
copyTree(path.join(src, child), path.join(dest, child))
|
|
83
98
|
}
|
|
84
|
-
return
|
|
99
|
+
return
|
|
85
100
|
}
|
|
86
101
|
if (stat.isFile()) {
|
|
87
|
-
fs.copyFileSync(src, dest)
|
|
102
|
+
fs.copyFileSync(src, dest)
|
|
88
103
|
}
|
|
89
|
-
}
|
|
104
|
+
}
|
|
90
105
|
|
|
91
106
|
for (const skillName of RETIRED_SKILL_NAMES) {
|
|
92
|
-
fs.rmSync(path.join(targetDir, skillName), { recursive: true, force: true })
|
|
107
|
+
fs.rmSync(path.join(targetDir, skillName), { recursive: true, force: true })
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
for (const skillName of PUBLIC_SKILL_NAMES) {
|
|
96
|
-
const skillSrc
|
|
97
|
-
const skillDest = path.join(targetDir, skillName)
|
|
111
|
+
const skillSrc = path.join(srcDir, skillName)
|
|
112
|
+
const skillDest = path.join(targetDir, skillName)
|
|
98
113
|
if (!fs.existsSync(skillSrc) || !fs.statSync(skillSrc).isDirectory()) {
|
|
99
|
-
throw new Error(`Reviewed skill source not found: ${skillSrc}`)
|
|
114
|
+
throw new Error(`Reviewed skill source not found: ${skillSrc}`)
|
|
100
115
|
}
|
|
101
|
-
fs.rmSync(skillDest, { recursive: true, force: true })
|
|
102
|
-
copyTree(skillSrc, skillDest)
|
|
116
|
+
fs.rmSync(skillDest, { recursive: true, force: true })
|
|
117
|
+
copyTree(skillSrc, skillDest)
|
|
103
118
|
}
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
for (const target of skillsTargets) {
|
|
107
|
-
copyCommandsAsClaudeSkills(srcSkillsDir, target.dir)
|
|
122
|
+
copyCommandsAsClaudeSkills(srcSkillsDir, target.dir)
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
// ─── 2. Create ~/.chain-insights/ config directory ────────────────────────
|
|
111
126
|
|
|
112
127
|
if (!fs.existsSync(dataDir)) {
|
|
113
|
-
fs.mkdirSync(dataDir, { recursive: true })
|
|
128
|
+
fs.mkdirSync(dataDir, { recursive: true })
|
|
114
129
|
}
|
|
115
130
|
|
|
116
131
|
// ─── 3. Write default config.json if absent ───────────────────────────────
|
|
@@ -119,20 +134,20 @@ if (!fs.existsSync(configPath)) {
|
|
|
119
134
|
const defaultConfig = {
|
|
120
135
|
graphMcpEndpoint: 'http://127.0.0.1:8012/mcp',
|
|
121
136
|
walletAddress: '',
|
|
122
|
-
graphMcpMode:
|
|
123
|
-
serverPort:
|
|
124
|
-
dataDir:
|
|
125
|
-
version:
|
|
126
|
-
}
|
|
127
|
-
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf8')
|
|
137
|
+
graphMcpMode: 'paid',
|
|
138
|
+
serverPort: 4321,
|
|
139
|
+
dataDir: dataDir,
|
|
140
|
+
version: '1',
|
|
141
|
+
}
|
|
142
|
+
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf8')
|
|
128
143
|
// Owner-readable only — config may contain MCP auth token (ASVS L1 V4.3.2 / T-02-01)
|
|
129
|
-
fs.chmodSync(configPath, 0o600)
|
|
144
|
+
fs.chmodSync(configPath, 0o600)
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
// ─── 4. Register MCP proxy in supported clients ───────────────────────────
|
|
133
148
|
|
|
134
|
-
const proxyBinPath = path.resolve(__dirname, 'mcp-proxy.cjs')
|
|
135
|
-
const { execFileSync } = require('child_process')
|
|
149
|
+
const proxyBinPath = path.resolve(__dirname, 'mcp-proxy.cjs')
|
|
150
|
+
const { execFileSync } = require('child_process')
|
|
136
151
|
|
|
137
152
|
if (hasClaude) {
|
|
138
153
|
try {
|
|
@@ -140,72 +155,74 @@ if (hasClaude) {
|
|
|
140
155
|
'claude',
|
|
141
156
|
['mcp', 'add', 'chain-insights-proxy', '--scope', 'user', '--', 'node', proxyBinPath],
|
|
142
157
|
{ stdio: 'pipe' }
|
|
143
|
-
)
|
|
144
|
-
console.log(` ${cyan}Claude MCP:${reset} registered (chain-insights-proxy) at ${proxyBinPath}`)
|
|
158
|
+
)
|
|
159
|
+
console.log(` ${cyan}Claude MCP:${reset} registered (chain-insights-proxy) at ${proxyBinPath}`)
|
|
145
160
|
} catch {
|
|
146
|
-
console.log(
|
|
161
|
+
console.log(
|
|
162
|
+
` ${dim}Claude MCP:${reset} run manually: claude mcp add chain-insights-proxy --scope user -- node ${proxyBinPath}`
|
|
163
|
+
)
|
|
147
164
|
}
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
function tomlQuoted(value) {
|
|
151
|
-
return JSON.stringify(value)
|
|
168
|
+
return JSON.stringify(value)
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
function installCodexMcp(configFile, proxyPath) {
|
|
155
|
-
fs.mkdirSync(path.dirname(configFile), { recursive: true })
|
|
156
|
-
let content = fs.existsSync(configFile) ? fs.readFileSync(configFile, 'utf8') : ''
|
|
172
|
+
fs.mkdirSync(path.dirname(configFile), { recursive: true })
|
|
173
|
+
let content = fs.existsSync(configFile) ? fs.readFileSync(configFile, 'utf8') : ''
|
|
157
174
|
const block = [
|
|
158
175
|
'[mcp_servers.chain-insights]',
|
|
159
176
|
'command = "node"',
|
|
160
177
|
`args = [${tomlQuoted(proxyPath)}]`,
|
|
161
178
|
'',
|
|
162
|
-
].join('\n')
|
|
179
|
+
].join('\n')
|
|
163
180
|
|
|
164
|
-
const heading = '[mcp_servers.chain-insights]'
|
|
165
|
-
const start = content.indexOf(heading)
|
|
181
|
+
const heading = '[mcp_servers.chain-insights]'
|
|
182
|
+
const start = content.indexOf(heading)
|
|
166
183
|
if (start >= 0) {
|
|
167
|
-
let end = content.length
|
|
168
|
-
const rest = content.slice(start + heading.length)
|
|
169
|
-
const nextSection = rest.search(/\n\[/)
|
|
170
|
-
if (nextSection >= 0) end = start + heading.length + nextSection + 1
|
|
171
|
-
content = `${content.slice(0, start)}${block}${content.slice(end)}
|
|
184
|
+
let end = content.length
|
|
185
|
+
const rest = content.slice(start + heading.length)
|
|
186
|
+
const nextSection = rest.search(/\n\[/)
|
|
187
|
+
if (nextSection >= 0) end = start + heading.length + nextSection + 1
|
|
188
|
+
content = `${content.slice(0, start)}${block}${content.slice(end)}`
|
|
172
189
|
} else {
|
|
173
|
-
const separator = content.endsWith('\n') || content.length === 0 ? '' : '\n'
|
|
174
|
-
content = `${content}${separator}\n${block}
|
|
190
|
+
const separator = content.endsWith('\n') || content.length === 0 ? '' : '\n'
|
|
191
|
+
content = `${content}${separator}\n${block}`
|
|
175
192
|
}
|
|
176
193
|
|
|
177
|
-
fs.writeFileSync(configFile, content, 'utf8')
|
|
194
|
+
fs.writeFileSync(configFile, content, 'utf8')
|
|
178
195
|
}
|
|
179
196
|
|
|
180
197
|
if (hasCodex) {
|
|
181
|
-
const codexConfig = path.join(homeDir, '.codex', 'config.toml')
|
|
182
|
-
installCodexMcp(codexConfig, proxyBinPath)
|
|
183
|
-
console.log(` ${cyan}Codex MCP:${reset} registered in ${codexConfig}`)
|
|
198
|
+
const codexConfig = path.join(homeDir, '.codex', 'config.toml')
|
|
199
|
+
installCodexMcp(codexConfig, proxyBinPath)
|
|
200
|
+
console.log(` ${cyan}Codex MCP:${reset} registered in ${codexConfig}`)
|
|
184
201
|
}
|
|
185
202
|
|
|
186
203
|
function yamlQuoted(value) {
|
|
187
|
-
return JSON.stringify(value)
|
|
204
|
+
return JSON.stringify(value)
|
|
188
205
|
}
|
|
189
206
|
|
|
190
207
|
function findTopLevelSectionEnd(lines, start) {
|
|
191
208
|
for (let i = start + 1; i < lines.length; i++) {
|
|
192
|
-
const line = lines[i]
|
|
193
|
-
if (line.trim() === '') continue
|
|
194
|
-
if (!line.startsWith(' ') && !line.startsWith('\t')) return i
|
|
209
|
+
const line = lines[i]
|
|
210
|
+
if (line.trim() === '') continue
|
|
211
|
+
if (!line.startsWith(' ') && !line.startsWith('\t')) return i
|
|
195
212
|
}
|
|
196
|
-
return lines.length
|
|
213
|
+
return lines.length
|
|
197
214
|
}
|
|
198
215
|
|
|
199
216
|
function findHermesServerEnd(lines, start, sectionEnd) {
|
|
200
217
|
for (let i = start + 1; i < sectionEnd; i++) {
|
|
201
|
-
const line = lines[i]
|
|
202
|
-
if (/^ [^ ].*:/.test(line)) return i
|
|
218
|
+
const line = lines[i]
|
|
219
|
+
if (/^ [^ ].*:/.test(line)) return i
|
|
203
220
|
}
|
|
204
|
-
return sectionEnd
|
|
221
|
+
return sectionEnd
|
|
205
222
|
}
|
|
206
223
|
|
|
207
224
|
function installHermesMcp(configFile, proxyPath) {
|
|
208
|
-
fs.mkdirSync(path.dirname(configFile), { recursive: true })
|
|
225
|
+
fs.mkdirSync(path.dirname(configFile), { recursive: true })
|
|
209
226
|
|
|
210
227
|
const serverBlock = [
|
|
211
228
|
' chain-insights:',
|
|
@@ -213,50 +230,57 @@ function installHermesMcp(configFile, proxyPath) {
|
|
|
213
230
|
' args:',
|
|
214
231
|
` - ${yamlQuoted(proxyPath)}`,
|
|
215
232
|
' enabled: true',
|
|
216
|
-
]
|
|
233
|
+
]
|
|
217
234
|
|
|
218
|
-
let content = fs.existsSync(configFile) ? fs.readFileSync(configFile, 'utf8') : ''
|
|
235
|
+
let content = fs.existsSync(configFile) ? fs.readFileSync(configFile, 'utf8') : ''
|
|
219
236
|
if (/^mcp_servers:\s*\{\s*\}\s*$/m.test(content)) {
|
|
220
|
-
content = content.replace(
|
|
221
|
-
|
|
222
|
-
|
|
237
|
+
content = content.replace(
|
|
238
|
+
/^mcp_servers:\s*\{\s*\}\s*$/m,
|
|
239
|
+
['mcp_servers:', ...serverBlock].join('\n')
|
|
240
|
+
)
|
|
241
|
+
fs.writeFileSync(configFile, content.endsWith('\n') ? content : `${content}\n`, 'utf8')
|
|
242
|
+
return
|
|
223
243
|
}
|
|
224
244
|
|
|
225
|
-
const lines = content.length ? content.split(/\r?\n/) : []
|
|
226
|
-
if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()
|
|
245
|
+
const lines = content.length ? content.split(/\r?\n/) : []
|
|
246
|
+
if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()
|
|
227
247
|
|
|
228
|
-
const sectionStart = lines.findIndex(line => line === 'mcp_servers:')
|
|
248
|
+
const sectionStart = lines.findIndex((line) => line === 'mcp_servers:')
|
|
229
249
|
if (sectionStart < 0) {
|
|
230
|
-
if (lines.length > 0) lines.push('')
|
|
231
|
-
lines.push('mcp_servers:', ...serverBlock)
|
|
232
|
-
fs.writeFileSync(configFile, `${lines.join('\n')}\n`, 'utf8')
|
|
233
|
-
return
|
|
250
|
+
if (lines.length > 0) lines.push('')
|
|
251
|
+
lines.push('mcp_servers:', ...serverBlock)
|
|
252
|
+
fs.writeFileSync(configFile, `${lines.join('\n')}\n`, 'utf8')
|
|
253
|
+
return
|
|
234
254
|
}
|
|
235
255
|
|
|
236
|
-
const sectionEnd = findTopLevelSectionEnd(lines, sectionStart)
|
|
237
|
-
const serverStart = lines.findIndex(
|
|
256
|
+
const sectionEnd = findTopLevelSectionEnd(lines, sectionStart)
|
|
257
|
+
const serverStart = lines.findIndex(
|
|
258
|
+
(line, index) => index > sectionStart && index < sectionEnd && line === ' chain-insights:'
|
|
259
|
+
)
|
|
238
260
|
if (serverStart >= 0) {
|
|
239
|
-
const serverEnd = findHermesServerEnd(lines, serverStart, sectionEnd)
|
|
240
|
-
lines.splice(serverStart, serverEnd - serverStart, ...serverBlock)
|
|
261
|
+
const serverEnd = findHermesServerEnd(lines, serverStart, sectionEnd)
|
|
262
|
+
lines.splice(serverStart, serverEnd - serverStart, ...serverBlock)
|
|
241
263
|
} else {
|
|
242
|
-
lines.splice(sectionStart + 1, 0, ...serverBlock)
|
|
264
|
+
lines.splice(sectionStart + 1, 0, ...serverBlock)
|
|
243
265
|
}
|
|
244
266
|
|
|
245
|
-
fs.writeFileSync(configFile, `${lines.join('\n')}\n`, 'utf8')
|
|
267
|
+
fs.writeFileSync(configFile, `${lines.join('\n')}\n`, 'utf8')
|
|
246
268
|
}
|
|
247
269
|
|
|
248
270
|
if (hasHermes) {
|
|
249
|
-
const hermesConfig = path.join(homeDir, '.hermes', 'config.yaml')
|
|
250
|
-
installHermesMcp(hermesConfig, proxyBinPath)
|
|
251
|
-
console.log(` ${cyan}Hermes MCP:${reset} registered in ${hermesConfig}`)
|
|
271
|
+
const hermesConfig = path.join(homeDir, '.hermes', 'config.yaml')
|
|
272
|
+
installHermesMcp(hermesConfig, proxyBinPath)
|
|
273
|
+
console.log(` ${cyan}Hermes MCP:${reset} registered in ${hermesConfig}`)
|
|
252
274
|
}
|
|
253
275
|
|
|
254
276
|
// ─── 5. Print installation summary ────────────────────────────────────────
|
|
255
277
|
|
|
256
|
-
console.log(`\n${bold}${green}Chain Insights installed${reset}`)
|
|
278
|
+
console.log(`\n${bold}${green}Chain Insights installed${reset}`)
|
|
257
279
|
for (const target of skillsTargets) {
|
|
258
|
-
console.log(` ${cyan}${target.name} skills:${reset} ${target.dir}`)
|
|
280
|
+
console.log(` ${cyan}${target.name} skills:${reset} ${target.dir}`)
|
|
259
281
|
}
|
|
260
|
-
console.log(` ${cyan}Config:${reset} ${configPath}`)
|
|
261
|
-
console.log(` ${cyan}Data dir:${reset} ${dataDir}`)
|
|
262
|
-
console.log(
|
|
282
|
+
console.log(` ${cyan}Config:${reset} ${configPath}`)
|
|
283
|
+
console.log(` ${cyan}Data dir:${reset} ${dataDir}`)
|
|
284
|
+
console.log(
|
|
285
|
+
`\n${dim}Run ${reset}${cyan}chain-insights status${reset}${dim} to verify the installation.${reset}\n`
|
|
286
|
+
)
|
package/bin/mcp-proxy.cjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict'
|
|
2
|
+
'use strict'
|
|
3
3
|
|
|
4
4
|
// CJS shim for stdio MCP proxy — spawned by Claude Code via ~/.claude.json mcpServers config.
|
|
5
5
|
// IMPORTANT: Do not write to stdout here — stdout is owned by StdioServerTransport.
|
|
6
6
|
// Use process.stderr.write() exclusively for pre-load errors.
|
|
7
|
-
import('../dist/mcp-proxy.mjs')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
})
|
|
7
|
+
import('../dist/mcp-proxy.mjs')
|
|
8
|
+
.then(({ createProxy }) => createProxy())
|
|
9
|
+
.catch((err) => {
|
|
10
|
+
process.stderr.write(`Failed to load chain-insights MCP proxy: ${err.message}\n`)
|
|
11
|
+
process.exit(1)
|
|
12
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
2
|
let node_path = require("node:path");
|
|
3
3
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
4
4
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-log-diTHyMbV.mjs","names":[],"sources":["../src/mcp/action-log.ts"],"sourcesContent":["// src/mcp/action-log.ts\n// Optional append-only record of every MCP tool invocation, for operators\n// running cia unattended who need to audit what ran and why a result looked\n// the way it did. Off unless CIA_ACTION_LOG names a path.\n//\n// `warnings` and `search_limits` are captured deliberately: they are how a\n// reader tells \"found nothing\" from \"hit a cap\", which is invisible in the\n// result alone.\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport interface ActionLogEntry {\n timestamp: number\n tool: string\n args: Record<string, unknown>\n outcome: 'ok' | 'error'\n duration_ms: number\n result_counts?: Record<string, number>\n warnings?: string[]\n search_limits?: Record<string, unknown>\n error?: string\n}\n\nexport function actionLogPath(): string | undefined {\n const configured = process.env.CIA_ACTION_LOG?.trim()\n return configured ? configured : undefined\n}\n\n// Some special filesystems (notably /proc) answer mkdir on a child with\n// ENOENT even though the parent visibly exists. Node's fs.mkdir(dir,\n// {recursive: true}) treats that as a transient race and retries with no\n// cap, which spins forever rather than rejecting — confirmed via strace\n// (an unbounded, rapid mkdir/statx loop; the event loop stays live and the\n// process never blocks, it just never stops). Walking the path ourselves,\n// one plain mkdir per component with no retry, makes every case settle in\n// a bounded number of syscalls: EEXIST is expected and skipped, anything\n// else (including that ENOENT-on-existing-parent case) fails once instead\n// of retrying.\nasync function ensureDir(dir: string): Promise<void> {\n const segments = dir.split(path.sep).filter(Boolean)\n let current = path.isAbsolute(dir) ? path.sep : ''\n for (const segment of segments) {\n current = current ? path.join(current, segment) : segment\n try {\n await mkdir(current)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') continue\n throw err\n }\n }\n}\n\n// A residual, undemonstrated risk remains distinct from the mkdir retry loop\n// above: a single mkdir/appendFile syscall genuinely wedged on a stalled\n// filesystem (e.g. a hung network mount) blocks like any normal blocking I/O\n// would. Node's fs promises do not support cancelling an in-flight mkdir, so\n// a bounded wait here only frees the *caller* — the wedged operation itself\n// keeps running in the background until the OS/filesystem gives up on its\n// own. That is an accepted, documented limitation, not a bug this module can\n// fix from userland; it is unrelated to (and much rarer than) the retry-loop\n// case ensureDir() eliminates above.\nconst WRITE_TIMEOUT_MS = 2000\n\nasync function writeEntry(file: string, entry: ActionLogEntry): Promise<void> {\n await ensureDir(path.dirname(file))\n await appendFile(file, JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n// Never throws, and never hangs beyond WRITE_TIMEOUT_MS. A failure (or a\n// stall) recording an action must not fail (or stall) the action:\n// observability that can break the thing it observes is worse than none.\nexport async function appendActionLog(entry: ActionLogEntry): Promise<void> {\n const file = actionLogPath()\n if (!file) return\n try {\n await Promise.race([\n writeEntry(file, entry),\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, WRITE_TIMEOUT_MS)\n timer.unref?.()\n }),\n ])\n } catch {\n // Intentionally swallowed.\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n// Exported so BOTH client paths log identically: the MCP proxy's remote client\n// and the CLI's own client. They are separate clients, and wiring only one is how\n// an unattended instance ends up with an empty log while the mechanism 'works'.\nexport function actionLogSignalsFromResult(result: unknown): {
|
|
1
|
+
{"version":3,"file":"action-log-diTHyMbV.mjs","names":[],"sources":["../src/mcp/action-log.ts"],"sourcesContent":["// src/mcp/action-log.ts\n// Optional append-only record of every MCP tool invocation, for operators\n// running cia unattended who need to audit what ran and why a result looked\n// the way it did. Off unless CIA_ACTION_LOG names a path.\n//\n// `warnings` and `search_limits` are captured deliberately: they are how a\n// reader tells \"found nothing\" from \"hit a cap\", which is invisible in the\n// result alone.\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport interface ActionLogEntry {\n timestamp: number\n tool: string\n args: Record<string, unknown>\n outcome: 'ok' | 'error'\n duration_ms: number\n result_counts?: Record<string, number>\n warnings?: string[]\n search_limits?: Record<string, unknown>\n error?: string\n}\n\nexport function actionLogPath(): string | undefined {\n const configured = process.env.CIA_ACTION_LOG?.trim()\n return configured ? configured : undefined\n}\n\n// Some special filesystems (notably /proc) answer mkdir on a child with\n// ENOENT even though the parent visibly exists. Node's fs.mkdir(dir,\n// {recursive: true}) treats that as a transient race and retries with no\n// cap, which spins forever rather than rejecting — confirmed via strace\n// (an unbounded, rapid mkdir/statx loop; the event loop stays live and the\n// process never blocks, it just never stops). Walking the path ourselves,\n// one plain mkdir per component with no retry, makes every case settle in\n// a bounded number of syscalls: EEXIST is expected and skipped, anything\n// else (including that ENOENT-on-existing-parent case) fails once instead\n// of retrying.\nasync function ensureDir(dir: string): Promise<void> {\n const segments = dir.split(path.sep).filter(Boolean)\n let current = path.isAbsolute(dir) ? path.sep : ''\n for (const segment of segments) {\n current = current ? path.join(current, segment) : segment\n try {\n await mkdir(current)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') continue\n throw err\n }\n }\n}\n\n// A residual, undemonstrated risk remains distinct from the mkdir retry loop\n// above: a single mkdir/appendFile syscall genuinely wedged on a stalled\n// filesystem (e.g. a hung network mount) blocks like any normal blocking I/O\n// would. Node's fs promises do not support cancelling an in-flight mkdir, so\n// a bounded wait here only frees the *caller* — the wedged operation itself\n// keeps running in the background until the OS/filesystem gives up on its\n// own. That is an accepted, documented limitation, not a bug this module can\n// fix from userland; it is unrelated to (and much rarer than) the retry-loop\n// case ensureDir() eliminates above.\nconst WRITE_TIMEOUT_MS = 2000\n\nasync function writeEntry(file: string, entry: ActionLogEntry): Promise<void> {\n await ensureDir(path.dirname(file))\n await appendFile(file, JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n// Never throws, and never hangs beyond WRITE_TIMEOUT_MS. A failure (or a\n// stall) recording an action must not fail (or stall) the action:\n// observability that can break the thing it observes is worse than none.\nexport async function appendActionLog(entry: ActionLogEntry): Promise<void> {\n const file = actionLogPath()\n if (!file) return\n try {\n await Promise.race([\n writeEntry(file, entry),\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, WRITE_TIMEOUT_MS)\n timer.unref?.()\n }),\n ])\n } catch {\n // Intentionally swallowed.\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n// Exported so BOTH client paths log identically: the MCP proxy's remote client\n// and the CLI's own client. They are separate clients, and wiring only one is how\n// an unattended instance ends up with an empty log while the mechanism 'works'.\nexport function actionLogSignalsFromResult(result: unknown): {\n warnings?: string[]\n search_limits?: Record<string, unknown>\n} {\n const structuredContent = isRecord(result) ? result['structuredContent'] : undefined\n if (!isRecord(structuredContent)) return {}\n const warnings = Array.isArray(structuredContent['warnings'])\n ? (structuredContent['warnings'] as string[])\n : undefined\n const input = structuredContent['input']\n const search_limits =\n isRecord(input) && isRecord(input['search_limits'])\n ? (input['search_limits'] as Record<string, unknown>)\n : undefined\n return { warnings, search_limits }\n}\n\ntype CallToolFn = (...args: never[]) => Promise<unknown>\n\n// Wrap a client's callTool so every invocation is recorded. Returns the client.\n// Idempotent-unsafe: call once per client.\nexport function installActionLogging<T extends { callTool: CallToolFn }>(client: T): T {\n const original = client.callTool.bind(client) as CallToolFn\n const wrapped = (async (...args: never[]) => {\n const startedAt = Date.now()\n const input = (args[0] ?? {}) as { name?: unknown; arguments?: Record<string, unknown> }\n const tool = String(input.name ?? 'unknown')\n const toolArgs = input.arguments ?? {}\n try {\n const result = await original(...args)\n const { warnings, search_limits } = actionLogSignalsFromResult(result)\n await appendActionLog({\n timestamp: startedAt,\n tool,\n args: toolArgs,\n outcome: 'ok',\n duration_ms: Date.now() - startedAt,\n warnings,\n search_limits,\n })\n return result\n } catch (err) {\n await appendActionLog({\n timestamp: startedAt,\n tool,\n args: toolArgs,\n outcome: 'error',\n duration_ms: Date.now() - startedAt,\n error: (err as Error).message,\n })\n throw err\n }\n }) as CallToolFn\n client.callTool = wrapped as T['callTool']\n return client\n}\n"],"mappings":";;;;;;;;;;AAuBA,SAAgB,gBAAoC;CAClD,MAAM,aAAa,QAAQ,IAAI,gBAAgB,KAAK;CACpD,OAAO,aAAa,aAAa,KAAA;AACnC;AAYA,eAAe,UAAU,KAA4B;CACnD,MAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,OAAO;CACnD,IAAI,UAAU,KAAK,WAAW,GAAG,IAAI,KAAK,MAAM;CAChD,KAAK,MAAM,WAAW,UAAU;EAC9B,UAAU,UAAU,KAAK,KAAK,SAAS,OAAO,IAAI;EAClD,IAAI;GACF,MAAM,MAAM,OAAO;EACrB,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAAU;GACtD,MAAM;EACR;CACF;AACF;AAWA,MAAM,mBAAmB;AAEzB,eAAe,WAAW,MAAc,OAAsC;CAC5E,MAAM,UAAU,KAAK,QAAQ,IAAI,CAAC;CAClC,MAAM,WAAW,MAAM,KAAK,UAAU,KAAK,IAAI,MAAM,MAAM;AAC7D;AAKA,eAAsB,gBAAgB,OAAsC;CAC1E,MAAM,OAAO,cAAc;CAC3B,IAAI,CAAC,MAAM;CACX,IAAI;EACF,MAAM,QAAQ,KAAK,CACjB,WAAW,MAAM,KAAK,GACtB,IAAI,SAAe,YAAY;GAE7B,WADyB,SAAS,gBAC9B,CAAC,CAAC,QAAQ;EAChB,CAAC,CACH,CAAC;CACH,QAAQ,CAER;AACF;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAKA,SAAgB,2BAA2B,QAGzC;CACA,MAAM,oBAAoB,SAAS,MAAM,IAAI,OAAO,uBAAuB,KAAA;CAC3E,IAAI,CAAC,SAAS,iBAAiB,GAAG,OAAO,CAAC;CAC1C,MAAM,WAAW,MAAM,QAAQ,kBAAkB,WAAW,IACvD,kBAAkB,cACnB,KAAA;CACJ,MAAM,QAAQ,kBAAkB;CAKhC,OAAO;EAAE;EAAU,eAHjB,SAAS,KAAK,KAAK,SAAS,MAAM,gBAAgB,IAC7C,MAAM,mBACP,KAAA;CAC2B;AACnC;AAMA,SAAgB,qBAAyD,QAAc;CACrF,MAAM,WAAW,OAAO,SAAS,KAAK,MAAM;CAC5C,MAAM,WAAW,OAAO,GAAG,SAAkB;EAC3C,MAAM,YAAY,KAAK,IAAI;EAC3B,MAAM,QAAS,KAAK,MAAM,CAAC;EAC3B,MAAM,OAAO,OAAO,MAAM,QAAQ,SAAS;EAC3C,MAAM,WAAW,MAAM,aAAa,CAAC;EACrC,IAAI;GACF,MAAM,SAAS,MAAM,SAAS,GAAG,IAAI;GACrC,MAAM,EAAE,UAAU,kBAAkB,2BAA2B,MAAM;GACrE,MAAM,gBAAgB;IACpB,WAAW;IACX;IACA,MAAM;IACN,SAAS;IACT,aAAa,KAAK,IAAI,IAAI;IAC1B;IACA;GACF,CAAC;GACD,OAAO;EACT,SAAS,KAAK;GACZ,MAAM,gBAAgB;IACpB,WAAW;IACX;IACA,MAAM;IACN,SAAS;IACT,aAAa,KAAK,IAAI,IAAI;IAC1B,OAAQ,IAAc;GACxB,CAAC;GACD,MAAM;EACR;CACF;CACA,OAAO,WAAW;CAClB,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-BQopLul8.mjs","names":[],"sources":["../src/workspace/active.ts"],"sourcesContent":["import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\ninterface WorkspaceConfig {\n schema?: string\n workspace_root?: string\n artifacts_dir?: string\n domain_hints?: unknown\n}\n\nexport interface ActiveWorkspace {\n root: string\n metadataDir: string\n artifactsRoot: string\n domainHints: string[]\n}\n\nfunction workspaceFromRoot(rootCandidate: string): ActiveWorkspace | null {\n const root = path.resolve(rootCandidate)\n const metadataDir = path.join(root, '.chain-insights')\n const markerPath = path.join(metadataDir, 'workspace.json')\n if (!fs.existsSync(markerPath)) return null\n\n const parsed = JSON.parse(fs.readFileSync(markerPath, 'utf8')) as WorkspaceConfig\n if (parsed.schema !== 'chain-insights.workspace.v1') return null\n\n const workspaceRoot = path.resolve(parsed.workspace_root ?? root)\n const artifactsDir = parsed.artifacts_dir ?? 'artifacts'\n const domainHints = Array.isArray(parsed.domain_hints)\n ? parsed.domain_hints.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n : []\n return {\n root: workspaceRoot,\n metadataDir: path.join(workspaceRoot, '.chain-insights'),\n artifactsRoot: path.resolve(workspaceRoot, artifactsDir),\n domainHints,\n }\n}\n\nexport function findActiveWorkspace(startDir = process.cwd()): ActiveWorkspace | null {\n const envWorkspace = process.env['CHAIN_INSIGHTS_WORKSPACE']?.trim()\n if (envWorkspace) {\n const active = workspaceFromRoot(envWorkspace)\n if (active) return active\n }\n\n let current = path.resolve(startDir)\n while (true) {\n const active = workspaceFromRoot(current)\n if (active) return active\n\n const parent = path.dirname(current)\n if (parent === current) return null\n current = parent\n }\n}\n\nexport function activeMetadataDir(): string {\n return findActiveWorkspace()?.metadataDir ?? path.join(os.homedir(), '.chain-insights')\n}\n\nexport function activeArtifactsRoot(): string {\n return findActiveWorkspace()?.artifactsRoot ?? path.join(os.homedir(), '.chain-insights', 'artifacts')\n}\n\nexport function activeDataDir(fallbackDataDir?: string): string {\n return findActiveWorkspace()?.root ?? fallbackDataDir ?? path.join(os.homedir(), '.chain-insights')\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAS,kBAAkB,eAA+C;CACxE,MAAM,OAAO,KAAK,QAAQ,aAAa;CACvC,MAAM,cAAc,KAAK,KAAK,MAAM,iBAAiB;CACrD,MAAM,aAAa,KAAK,KAAK,aAAa,gBAAgB;CAC1D,IAAI,CAAC,GAAG,WAAW,UAAU,GAAG,OAAO;CAEvC,MAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,MAAM,CAAC;CAC7D,IAAI,OAAO,WAAW,+BAA+B,OAAO;CAE5D,MAAM,gBAAgB,KAAK,QAAQ,OAAO,kBAAkB,IAAI;CAChE,MAAM,eAAe,OAAO,iBAAiB;CAC7C,MAAM,cAAc,MAAM,QAAQ,OAAO,YAAY,IACjD,OAAO,aAAa,
|
|
1
|
+
{"version":3,"file":"active-BQopLul8.mjs","names":[],"sources":["../src/workspace/active.ts"],"sourcesContent":["import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\ninterface WorkspaceConfig {\n schema?: string\n workspace_root?: string\n artifacts_dir?: string\n domain_hints?: unknown\n}\n\nexport interface ActiveWorkspace {\n root: string\n metadataDir: string\n artifactsRoot: string\n domainHints: string[]\n}\n\nfunction workspaceFromRoot(rootCandidate: string): ActiveWorkspace | null {\n const root = path.resolve(rootCandidate)\n const metadataDir = path.join(root, '.chain-insights')\n const markerPath = path.join(metadataDir, 'workspace.json')\n if (!fs.existsSync(markerPath)) return null\n\n const parsed = JSON.parse(fs.readFileSync(markerPath, 'utf8')) as WorkspaceConfig\n if (parsed.schema !== 'chain-insights.workspace.v1') return null\n\n const workspaceRoot = path.resolve(parsed.workspace_root ?? root)\n const artifactsDir = parsed.artifacts_dir ?? 'artifacts'\n const domainHints = Array.isArray(parsed.domain_hints)\n ? parsed.domain_hints.filter(\n (value): value is string => typeof value === 'string' && value.trim().length > 0\n )\n : []\n return {\n root: workspaceRoot,\n metadataDir: path.join(workspaceRoot, '.chain-insights'),\n artifactsRoot: path.resolve(workspaceRoot, artifactsDir),\n domainHints,\n }\n}\n\nexport function findActiveWorkspace(startDir = process.cwd()): ActiveWorkspace | null {\n const envWorkspace = process.env['CHAIN_INSIGHTS_WORKSPACE']?.trim()\n if (envWorkspace) {\n const active = workspaceFromRoot(envWorkspace)\n if (active) return active\n }\n\n let current = path.resolve(startDir)\n while (true) {\n const active = workspaceFromRoot(current)\n if (active) return active\n\n const parent = path.dirname(current)\n if (parent === current) return null\n current = parent\n }\n}\n\nexport function activeMetadataDir(): string {\n return findActiveWorkspace()?.metadataDir ?? path.join(os.homedir(), '.chain-insights')\n}\n\nexport function activeArtifactsRoot(): string {\n return (\n findActiveWorkspace()?.artifactsRoot ?? path.join(os.homedir(), '.chain-insights', 'artifacts')\n )\n}\n\nexport function activeDataDir(fallbackDataDir?: string): string {\n return (\n findActiveWorkspace()?.root ?? fallbackDataDir ?? path.join(os.homedir(), '.chain-insights')\n )\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAS,kBAAkB,eAA+C;CACxE,MAAM,OAAO,KAAK,QAAQ,aAAa;CACvC,MAAM,cAAc,KAAK,KAAK,MAAM,iBAAiB;CACrD,MAAM,aAAa,KAAK,KAAK,aAAa,gBAAgB;CAC1D,IAAI,CAAC,GAAG,WAAW,UAAU,GAAG,OAAO;CAEvC,MAAM,SAAS,KAAK,MAAM,GAAG,aAAa,YAAY,MAAM,CAAC;CAC7D,IAAI,OAAO,WAAW,+BAA+B,OAAO;CAE5D,MAAM,gBAAgB,KAAK,QAAQ,OAAO,kBAAkB,IAAI;CAChE,MAAM,eAAe,OAAO,iBAAiB;CAC7C,MAAM,cAAc,MAAM,QAAQ,OAAO,YAAY,IACjD,OAAO,aAAa,QACjB,UAA2B,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS,CACjF,IACA,CAAC;CACL,OAAO;EACL,MAAM;EACN,aAAa,KAAK,KAAK,eAAe,iBAAiB;EACvD,eAAe,KAAK,QAAQ,eAAe,YAAY;EACvD;CACF;AACF;AAEA,SAAgB,oBAAoB,WAAW,QAAQ,IAAI,GAA2B;CACpF,MAAM,eAAe,QAAQ,IAAI,2BAA2B,EAAE,KAAK;CACnE,IAAI,cAAc;EAChB,MAAM,SAAS,kBAAkB,YAAY;EAC7C,IAAI,QAAQ,OAAO;CACrB;CAEA,IAAI,UAAU,KAAK,QAAQ,QAAQ;CACnC,OAAO,MAAM;EACX,MAAM,SAAS,kBAAkB,OAAO;EACxC,IAAI,QAAQ,OAAO;EAEnB,MAAM,SAAS,KAAK,QAAQ,OAAO;EACnC,IAAI,WAAW,SAAS,OAAO;EAC/B,UAAU;CACZ;AACF;AAYA,SAAgB,cAAc,iBAAkC;CAC9D,OACE,oBAAoB,CAAC,EAAE,QAAQ,mBAAmB,KAAK,KAAK,GAAG,QAAQ,GAAG,iBAAiB;AAE/F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
2
|
let node_path = require("node:path");
|
|
3
3
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
4
4
|
let node_fs = require("node:fs");
|
|
@@ -82,7 +82,7 @@ function createApp() {
|
|
|
82
82
|
ts: Date.now()
|
|
83
83
|
}));
|
|
84
84
|
app.get("/status", async (c) => {
|
|
85
|
-
const { loadConfig } = await import("./config-
|
|
85
|
+
const { loadConfig } = await import("./config-CnNMdt4M.mjs").then((n) => n.t);
|
|
86
86
|
const config = await loadConfig();
|
|
87
87
|
return c.json({
|
|
88
88
|
dataDir: config.dataDir,
|
|
@@ -137,4 +137,4 @@ function createApp() {
|
|
|
137
137
|
//#endregion
|
|
138
138
|
export { createApp as t };
|
|
139
139
|
|
|
140
|
-
//# sourceMappingURL=app-
|
|
140
|
+
//# sourceMappingURL=app-7NRCqx_Q.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-7NRCqx_Q.mjs","names":[],"sources":["../src/server/app.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport { lstat, readFile, readdir, realpath } from 'node:fs/promises'\nimport path from 'node:path'\nimport { workspaceOutputPaths } from '../workspace/output-root.js'\n\nconst WORKSPACE_TREE_ROOTS = [\n 'artifacts',\n 'entities',\n 'reports',\n 'sessions',\n '.chain-insights/schema',\n]\nconst WORKSPACE_TREE_MAX_DEPTH = 4\n\ninterface WorkspaceTreeEntry {\n path: string\n type: 'file' | 'directory' | 'symlink'\n size?: number\n}\n\nfunction withinRoot(root: string, target: string): boolean {\n const relative = path.relative(path.resolve(root), path.resolve(target))\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))\n}\n\nasync function realPathWithinRoot(root: string, target: string): Promise<boolean> {\n try {\n const [realRoot, realTarget] = await Promise.all([realpath(root), realpath(target)])\n return withinRoot(realRoot, realTarget)\n } catch {\n return false\n }\n}\n\nfunction toWorkspaceRelative(root: string, target: string): string {\n return path.relative(root, target).split(path.sep).join('/')\n}\n\nasync function listWorkspaceEntries(\n workspaceRoot: string,\n roots = WORKSPACE_TREE_ROOTS,\n maxDepth = WORKSPACE_TREE_MAX_DEPTH\n): Promise<WorkspaceTreeEntry[]> {\n const entries: WorkspaceTreeEntry[] = []\n const root = path.resolve(workspaceRoot)\n\n async function visit(target: string, depth: number): Promise<void> {\n const resolved = path.resolve(target)\n if (!withinRoot(root, resolved)) return\n\n let info: Awaited<ReturnType<typeof lstat>>\n try {\n info = await lstat(resolved)\n } catch {\n return\n }\n\n const type = info.isSymbolicLink()\n ? 'symlink'\n : info.isDirectory()\n ? 'directory'\n : info.isFile()\n ? 'file'\n : null\n if (!type) return\n\n const entry: WorkspaceTreeEntry = {\n path: toWorkspaceRelative(root, resolved),\n type,\n }\n if (type === 'file') entry.size = info.size\n entries.push(entry)\n\n if (type !== 'directory' || depth >= maxDepth) return\n if (!(await realPathWithinRoot(root, resolved))) return\n\n let children: string[]\n try {\n children = await readdir(resolved)\n } catch {\n return\n }\n\n for (const child of children.sort()) {\n await visit(path.join(resolved, child), depth + 1)\n }\n }\n\n for (const rootName of roots) {\n const target = path.resolve(root, rootName)\n if (withinRoot(root, target)) await visit(target, 0)\n }\n\n return entries\n}\n\nasync function findVizHtml(vizId: string): Promise<string | null> {\n const filename = `${vizId}.html`\n const paths = workspaceOutputPaths()\n const vizPath = path.join(paths.publishedRoot, 'viz', filename)\n try {\n return await readFile(vizPath, 'utf-8')\n } catch {\n return null\n }\n}\n\nfunction isSafeGraphReportFilename(filename: string): boolean {\n return (\n filename.endsWith('.graph.json') &&\n /^[A-Za-z0-9._-]+$/.test(filename) &&\n !filename.includes('..') &&\n !filename.includes('/') &&\n !filename.includes('\\\\')\n )\n}\n\nexport function createApp(): Hono {\n const app = new Hono()\n\n app.get('/health', (c) => c.json({ ok: true, ts: Date.now() }))\n\n app.get('/status', async (c) => {\n const { loadConfig } = await import('../config/index.js')\n const config = await loadConfig()\n return c.json({\n dataDir: config.dataDir,\n graphMcpMode: config.graphMcpMode,\n server: 'running',\n })\n })\n\n app.get('/viz/:id', async (c) => {\n const id = c.req.param('id')\n if (!/^[a-zA-Z0-9_-]+$/.test(id)) {\n return c.json({ error: 'Invalid visualization ID' }, 400)\n }\n const html = await findVizHtml(id)\n if (!html) {\n return c.json({ error: 'Visualization not found' }, 404)\n }\n return c.html(html)\n })\n\n app.get('/graph-reports/:filename', async (c) => {\n const filename = c.req.param('filename')\n if (!isSafeGraphReportFilename(filename)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const graphPath = path.resolve(paths.reportGraphsRoot, filename)\n if (!withinRoot(paths.reportGraphsRoot, graphPath)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n if (!(await realPathWithinRoot(paths.reportGraphsRoot, graphPath))) {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n\n try {\n const graph = await readFile(graphPath, 'utf-8')\n return c.body(graph, 200, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n })\n } catch {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n })\n\n app.get('/graph-reports/*', (c) => {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n })\n\n app.get('/workspace/tree', async (c) => {\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const entries = await listWorkspaceEntries(paths.root, WORKSPACE_TREE_ROOTS)\n return c.json({\n schema: 'chain-insights.workspace-tree.v1',\n root: paths.root,\n entries,\n })\n })\n\n app.onError((err, c) => {\n console.error(err)\n return c.json({ error: 'Internal server error' }, 500)\n })\n\n return app\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
2
|
-
const require_output_root = require("./output-root-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
|
+
const require_output_root = require("./output-root-BewoQaTx.cjs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -84,7 +84,7 @@ function createApp() {
|
|
|
84
84
|
ts: Date.now()
|
|
85
85
|
}));
|
|
86
86
|
app.get("/status", async (c) => {
|
|
87
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
87
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BVFf3v8-.cjs")).then((n) => n.config_exports);
|
|
88
88
|
const config = await loadConfig();
|
|
89
89
|
return c.json({
|
|
90
90
|
dataDir: config.dataDir,
|
|
@@ -102,7 +102,7 @@ function createApp() {
|
|
|
102
102
|
app.get("/graph-reports/:filename", async (c) => {
|
|
103
103
|
const filename = c.req.param("filename");
|
|
104
104
|
if (!isSafeGraphReportFilename(filename)) return c.json({ error: "Invalid graph report filename" }, 400);
|
|
105
|
-
const { workspaceOutputPaths } = await Promise.resolve().then(() => require("./output-root-
|
|
105
|
+
const { workspaceOutputPaths } = await Promise.resolve().then(() => require("./output-root-BewoQaTx.cjs")).then((n) => n.output_root_exports);
|
|
106
106
|
const paths = workspaceOutputPaths();
|
|
107
107
|
const graphPath = node_path.default.resolve(paths.reportGraphsRoot, filename);
|
|
108
108
|
if (!withinRoot(paths.reportGraphsRoot, graphPath)) return c.json({ error: "Invalid graph report filename" }, 400);
|
|
@@ -121,7 +121,7 @@ function createApp() {
|
|
|
121
121
|
return c.json({ error: "Invalid graph report filename" }, 400);
|
|
122
122
|
});
|
|
123
123
|
app.get("/workspace/tree", async (c) => {
|
|
124
|
-
const { workspaceOutputPaths } = await Promise.resolve().then(() => require("./output-root-
|
|
124
|
+
const { workspaceOutputPaths } = await Promise.resolve().then(() => require("./output-root-BewoQaTx.cjs")).then((n) => n.output_root_exports);
|
|
125
125
|
const paths = workspaceOutputPaths();
|
|
126
126
|
const entries = await listWorkspaceEntries(paths.root, WORKSPACE_TREE_ROOTS);
|
|
127
127
|
return c.json({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_app = require("./app-
|
|
1
|
+
const require_app = require("./app-l9JE6bt3.cjs");
|
|
2
2
|
let _hono_node_server = require("@hono/node-server");
|
|
3
3
|
let node_timers_promises = require("node:timers/promises");
|
|
4
4
|
//#region src/mcp/artifact-server.ts
|
|
@@ -24,8 +24,9 @@ async function waitUntilHealthy(port) {
|
|
|
24
24
|
async function ensureArtifactServer(port) {
|
|
25
25
|
if (servers.has(port)) return;
|
|
26
26
|
if (await isHealthy(port)) return;
|
|
27
|
+
const app = require_app.createApp();
|
|
27
28
|
const server = (0, _hono_node_server.serve)({
|
|
28
|
-
fetch:
|
|
29
|
+
fetch: app.fetch,
|
|
29
30
|
hostname: "127.0.0.1",
|
|
30
31
|
port
|
|
31
32
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createApp } from "./app-
|
|
1
|
+
import { t as createApp } from "./app-7NRCqx_Q.mjs";
|
|
2
2
|
import { serve } from "@hono/node-server";
|
|
3
3
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
4
4
|
//#region src/mcp/artifact-server.ts
|
|
@@ -24,8 +24,9 @@ async function waitUntilHealthy(port) {
|
|
|
24
24
|
async function ensureArtifactServer(port) {
|
|
25
25
|
if (servers.has(port)) return;
|
|
26
26
|
if (await isHealthy(port)) return;
|
|
27
|
+
const app = createApp();
|
|
27
28
|
const server = serve({
|
|
28
|
-
fetch:
|
|
29
|
+
fetch: app.fetch,
|
|
29
30
|
hostname: "127.0.0.1",
|
|
30
31
|
port
|
|
31
32
|
});
|
|
@@ -45,4 +46,4 @@ async function ensureArtifactServer(port) {
|
|
|
45
46
|
//#endregion
|
|
46
47
|
export { ensureArtifactServer };
|
|
47
48
|
|
|
48
|
-
//# sourceMappingURL=artifact-server-
|
|
49
|
+
//# sourceMappingURL=artifact-server-DoxJr0z8.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-server-DoxJr0z8.mjs","names":["delay"],"sources":["../src/mcp/artifact-server.ts"],"sourcesContent":["import { serve } from '@hono/node-server'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { createApp } from '../server/app.js'\n\ntype ArtifactServer = ReturnType<typeof serve>\n\nconst servers = new Map<number, ArtifactServer>()\n\nasync function isHealthy(port: number): Promise<boolean> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), 500)\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n })\n return response.ok\n } catch {\n return false\n } finally {\n clearTimeout(timeout)\n }\n}\n\nasync function waitUntilHealthy(port: number): Promise<void> {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (await isHealthy(port)) return\n await delay(50)\n }\n throw new Error(`Graph report server did not become healthy on 127.0.0.1:${port}`)\n}\n\nexport async function ensureArtifactServer(port: number): Promise<void> {\n if (servers.has(port)) return\n if (await isHealthy(port)) return\n\n const app = createApp()\n const server = serve({\n fetch: app.fetch,\n hostname: '127.0.0.1',\n port,\n })\n servers.set(port, server)\n server.on('error', (err) => {\n servers.delete(port)\n process.stderr.write(\n `Chain Insights graph report server failed on 127.0.0.1:${port}: ${(err as Error).message}\\n`\n )\n })\n\n try {\n await waitUntilHealthy(port)\n } catch (err) {\n servers.delete(port)\n server.close()\n throw err\n }\n}\n\nexport function closeArtifactServers(): void {\n for (const [port, server] of servers.entries()) {\n server.close()\n servers.delete(port)\n }\n}\n"],"mappings":";;;;AAMA,MAAM,0BAAU,IAAI,IAA4B;AAEhD,eAAe,UAAU,MAAgC;CACvD,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,UAAU,iBAAiB,WAAW,MAAM,GAAG,GAAG;CACxD,IAAI;EAIF,QAAO,MAHgB,MAAM,oBAAoB,KAAK,UAAU,EAC9D,QAAQ,WAAW,OACrB,CAAC,EAAA,CACe;CAClB,QAAQ;EACN,OAAO;CACT,UAAU;EACR,aAAa,OAAO;CACtB;AACF;AAEA,eAAe,iBAAiB,MAA6B;CAC3D,KAAK,IAAI,UAAU,GAAG,UAAU,IAAI,WAAW,GAAG;EAChD,IAAI,MAAM,UAAU,IAAI,GAAG;EAC3B,MAAMA,aAAM,EAAE;CAChB;CACA,MAAM,IAAI,MAAM,2DAA2D,MAAM;AACnF;AAEA,eAAsB,qBAAqB,MAA6B;CACtE,IAAI,QAAQ,IAAI,IAAI,GAAG;CACvB,IAAI,MAAM,UAAU,IAAI,GAAG;CAE3B,MAAM,MAAM,UAAU;CACtB,MAAM,SAAS,MAAM;EACnB,OAAO,IAAI;EACX,UAAU;EACV;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,MAAM;CACxB,OAAO,GAAG,UAAU,QAAQ;EAC1B,QAAQ,OAAO,IAAI;EACnB,QAAQ,OAAO,MACb,0DAA0D,KAAK,IAAK,IAAc,QAAQ,GAC5F;CACF,CAAC;CAED,IAAI;EACF,MAAM,iBAAiB,IAAI;CAC7B,SAAS,KAAK;EACZ,QAAQ,OAAO,IAAI;EACnB,OAAO,MAAM;EACb,MAAM;CACR;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { a as resolveGraphMcpEndpoint, n as applyMcpAuthHeaders } from "./client-
|
|
2
|
+
import { a as resolveGraphMcpEndpoint, n as applyMcpAuthHeaders } from "./client-D4aM4bzP.mjs";
|
|
3
3
|
//#region src/mcp/capabilities.ts
|
|
4
4
|
var capabilities_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS: () => PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,
|
|
@@ -126,4 +126,4 @@ function formatNetworkCapabilities(document) {
|
|
|
126
126
|
//#endregion
|
|
127
127
|
export { mirrorGraphNetworkCapabilities as n, capabilities_exports as t };
|
|
128
128
|
|
|
129
|
-
//# sourceMappingURL=capabilities-
|
|
129
|
+
//# sourceMappingURL=capabilities-BZI6qROg.mjs.map
|