trace-mcp 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ @echo off
2
+ REM trace-mcp-launcher v0.2.0 (Windows)
3
+ REM Tiny .cmd shim that invokes the PowerShell launcher. MCP clients spawn
4
+ REM this .cmd because they rely on %PATHEXT% resolution which prefers .cmd.
5
+ REM Do not edit — re-run `trace-mcp init` to refresh.
6
+ powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%~dp0trace-mcp-launcher.ps1" %*
7
+ exit /b %ERRORLEVEL%
@@ -0,0 +1,162 @@
1
+ # trace-mcp-launcher v0.2.0 (Windows)
2
+ # Stable shim backend: resolves node + cli.js at runtime from launcher.env,
3
+ # with a probe fallback for nvm-windows/nvs/Volta/system installs.
4
+ # Managed by trace-mcp — do not edit by hand. Re-run `trace-mcp init` to refresh.
5
+
6
+ #Requires -Version 5.1
7
+
8
+ $ErrorActionPreference = 'Stop'
9
+
10
+ $TraceHome = if ($env:TRACE_MCP_HOME) { $env:TRACE_MCP_HOME } else { Join-Path $env:USERPROFILE '.trace-mcp' }
11
+ $ConfigPath = Join-Path $TraceHome 'launcher.env'
12
+ $LogPath = Join-Path $TraceHome 'launcher.log'
13
+
14
+ function Write-LauncherLog {
15
+ param([string]$Message)
16
+ try {
17
+ $stamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
18
+ Add-Content -Path $LogPath -Value "[$stamp] $Message" -ErrorAction SilentlyContinue
19
+ } catch {
20
+ # Never abort on log failure.
21
+ }
22
+ }
23
+
24
+ function Die {
25
+ param([string]$Message)
26
+ Write-LauncherLog "ERROR: $Message"
27
+ [Console]::Error.WriteLine("trace-mcp launcher: $Message")
28
+ [Console]::Error.WriteLine('Recovery: npm i -g trace-mcp && trace-mcp init')
29
+ [Console]::Error.WriteLine(' (or set TRACE_MCP_NODE_OVERRIDE / TRACE_MCP_CLI_OVERRIDE)')
30
+ exit 127
31
+ }
32
+
33
+ # --- 1. Parse config safely (no Invoke-Expression, whitelist keys) ---
34
+ $NodePath = ''
35
+ $CliPath = ''
36
+
37
+ if (Test-Path -LiteralPath $ConfigPath -PathType Leaf) {
38
+ foreach ($line in [System.IO.File]::ReadAllLines($ConfigPath)) {
39
+ $trimmed = $line.TrimStart()
40
+ if (-not $trimmed -or $trimmed.StartsWith('#')) { continue }
41
+ $idx = $trimmed.IndexOf('=')
42
+ if ($idx -le 0) { continue }
43
+ $key = $trimmed.Substring(0, $idx).Trim()
44
+ $val = $trimmed.Substring($idx + 1).Trim()
45
+ # Strip exactly one pair of surrounding double-quotes if present.
46
+ if ($val.Length -ge 2 -and $val.StartsWith('"') -and $val.EndsWith('"')) {
47
+ $val = $val.Substring(1, $val.Length - 2)
48
+ }
49
+ switch ($key) {
50
+ 'TRACE_MCP_NODE' { $NodePath = $val }
51
+ 'TRACE_MCP_CLI' { $CliPath = $val }
52
+ # TRACE_MCP_VERSION ignored (informational only)
53
+ }
54
+ }
55
+ }
56
+
57
+ # --- 2. Env overrides ---
58
+ if ($env:TRACE_MCP_NODE_OVERRIDE) { $NodePath = $env:TRACE_MCP_NODE_OVERRIDE }
59
+ if ($env:TRACE_MCP_CLI_OVERRIDE) { $CliPath = $env:TRACE_MCP_CLI_OVERRIDE }
60
+
61
+ function Test-NodeBinary {
62
+ param([string]$Path)
63
+ if (-not $Path) { return $false }
64
+ if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return $false }
65
+ return $true
66
+ }
67
+
68
+ function Test-CliFile {
69
+ param([string]$Path)
70
+ if (-not $Path) { return $false }
71
+ return (Test-Path -LiteralPath $Path -PathType Leaf)
72
+ }
73
+
74
+ # --- 3. Fast path: config is good → exec directly ---
75
+ if ((Test-NodeBinary $NodePath) -and (Test-CliFile $CliPath)) {
76
+ Write-LauncherLog "exec(config) node=$NodePath cli=$CliPath argc=$($args.Count)"
77
+ & $NodePath $CliPath @args
78
+ exit $LASTEXITCODE
79
+ }
80
+
81
+ # --- 4. Probe fallback (stable sources only) ---
82
+
83
+ function Find-Node {
84
+ # 4a. System-wide official installer
85
+ $candidates = @(
86
+ (Join-Path $env:ProgramFiles 'nodejs\node.exe'),
87
+ (Join-Path ${env:ProgramFiles(x86)} 'nodejs\node.exe'),
88
+ (Join-Path $env:LOCALAPPDATA 'Programs\nodejs\node.exe')
89
+ )
90
+ foreach ($c in $candidates) {
91
+ if ($c -and (Test-NodeBinary $c)) { return $c }
92
+ }
93
+
94
+ # 4b. Volta (stable shim dir)
95
+ $volta = Join-Path $env:USERPROFILE '.volta\bin\node.exe'
96
+ if (Test-NodeBinary $volta) { return $volta }
97
+
98
+ # 4c. nvm-windows: $APPDATA\nvm\<ver>\node.exe; active one symlinked via %NVM_SYMLINK%
99
+ if ($env:NVM_SYMLINK) {
100
+ $nvmActive = Join-Path $env:NVM_SYMLINK 'node.exe'
101
+ if (Test-NodeBinary $nvmActive) { return $nvmActive }
102
+ }
103
+ $nvmRoot = Join-Path $env:APPDATA 'nvm'
104
+ if (Test-Path -LiteralPath $nvmRoot -PathType Container) {
105
+ $latest = Get-ChildItem -LiteralPath $nvmRoot -Directory -ErrorAction SilentlyContinue |
106
+ Where-Object { $_.Name -match '^v?\d+\.\d+\.\d+$' } |
107
+ Sort-Object -Property Name -Descending |
108
+ Select-Object -First 1
109
+ if ($latest) {
110
+ $candidate = Join-Path $latest.FullName 'node.exe'
111
+ if (Test-NodeBinary $candidate) { return $candidate }
112
+ }
113
+ }
114
+
115
+ # 4d. nvs: %LOCALAPPDATA%\nvs\default\<arch>\<ver>\node.exe (default alias)
116
+ $nvsDefault = Join-Path $env:LOCALAPPDATA 'nvs\default'
117
+ if (Test-Path -LiteralPath $nvsDefault -PathType Container) {
118
+ $nodeExe = Get-ChildItem -LiteralPath $nvsDefault -Recurse -Filter 'node.exe' -ErrorAction SilentlyContinue |
119
+ Select-Object -First 1
120
+ if ($nodeExe) { return $nodeExe.FullName }
121
+ }
122
+
123
+ return $null
124
+ }
125
+
126
+ function Find-Cli {
127
+ param([string]$NodeExe)
128
+ # npm-global layout on Windows places global modules in %APPDATA%\npm\node_modules\,
129
+ # not next to node.exe. Check both layouts for robustness.
130
+ $candidates = @(
131
+ (Join-Path $env:APPDATA 'npm\node_modules\trace-mcp\dist\cli.js'),
132
+ (Join-Path (Split-Path -Parent $NodeExe) 'node_modules\trace-mcp\dist\cli.js'),
133
+ # Unix-style layout (some cross-platform setups)
134
+ (Join-Path (Split-Path -Parent $NodeExe) '..\lib\node_modules\trace-mcp\dist\cli.js')
135
+ )
136
+ foreach ($c in $candidates) {
137
+ if (Test-Path -LiteralPath $c -PathType Leaf) {
138
+ return (Resolve-Path -LiteralPath $c).Path
139
+ }
140
+ }
141
+ return $null
142
+ }
143
+
144
+ if (-not (Test-NodeBinary $NodePath)) {
145
+ $NodePath = Find-Node
146
+ if (-not $NodePath) {
147
+ Die 'node binary not found — install Node.js (nodejs.org / nvs / nvm-windows / volta) or set TRACE_MCP_NODE_OVERRIDE'
148
+ }
149
+ Write-LauncherLog "probe: node=$NodePath"
150
+ }
151
+
152
+ if (-not (Test-CliFile $CliPath)) {
153
+ $CliPath = Find-Cli $NodePath
154
+ if (-not $CliPath) {
155
+ Die "trace-mcp package not found for node=$NodePath — run: npm i -g trace-mcp && trace-mcp init"
156
+ }
157
+ Write-LauncherLog "probe: cli=$CliPath"
158
+ }
159
+
160
+ Write-LauncherLog "exec(probe) node=$NodePath cli=$CliPath argc=$($args.Count)"
161
+ & $NodePath $CliPath @args
162
+ exit $LASTEXITCODE
@@ -0,0 +1,169 @@
1
+ #!/bin/bash
2
+ # trace-mcp-launcher v0.2.0
3
+ # Stable shim: MCP clients invoke this path forever; it resolves node + cli.js
4
+ # at runtime from a config file written by `trace-mcp init`, with a minimal
5
+ # probe fallback for when the config is stale (e.g. Node was reinstalled).
6
+ #
7
+ # Managed by trace-mcp — do not edit by hand. Re-run `trace-mcp init` to refresh.
8
+
9
+ set -u
10
+
11
+ TRACE_HOME="${TRACE_MCP_HOME:-$HOME/.trace-mcp}"
12
+ CONFIG="$TRACE_HOME/launcher.env"
13
+ LOG="$TRACE_HOME/launcher.log"
14
+
15
+ log() {
16
+ # Best-effort append; never abort on log failure.
17
+ printf '[%s] %s\n' "$(date -u +%FT%TZ 2>/dev/null || echo '-')" "$1" >> "$LOG" 2>/dev/null || true
18
+ }
19
+
20
+ die() {
21
+ log "ERROR: $1"
22
+ printf 'trace-mcp launcher: %s\n' "$1" >&2
23
+ printf 'Recovery: npm i -g trace-mcp && trace-mcp init\n' >&2
24
+ printf ' (or set TRACE_MCP_NODE_OVERRIDE / TRACE_MCP_CLI_OVERRIDE)\n' >&2
25
+ exit 127
26
+ }
27
+
28
+ # --- 1. Parse config safely (no `source` — RCE-safe, whitelist keys) ---
29
+ NODE_PATH=""
30
+ CLI_PATH=""
31
+
32
+ if [ -r "$CONFIG" ]; then
33
+ # Read line by line, split on first `=`, whitelist allowed keys, strip one
34
+ # layer of surrounding quotes. Unknown keys and shell metacharacters in
35
+ # values are never evaluated — values are treated as opaque strings.
36
+ while IFS='=' read -r key value || [ -n "$key" ]; do
37
+ # Skip comments and blank lines
38
+ case "$key" in
39
+ ''|\#*) continue ;;
40
+ esac
41
+ # Strip surrounding double-quotes (emitted by init for safety)
42
+ value="${value%\"}"
43
+ value="${value#\"}"
44
+ case "$key" in
45
+ TRACE_MCP_NODE) NODE_PATH="$value" ;;
46
+ TRACE_MCP_CLI) CLI_PATH="$value" ;;
47
+ # TRACE_MCP_VERSION exists but is informational only
48
+ esac
49
+ done < "$CONFIG"
50
+ fi
51
+
52
+ # --- 2. Env overrides (escape hatch for debugging) ---
53
+ if [ -n "${TRACE_MCP_NODE_OVERRIDE:-}" ]; then NODE_PATH="$TRACE_MCP_NODE_OVERRIDE"; fi
54
+ if [ -n "${TRACE_MCP_CLI_OVERRIDE:-}" ]; then CLI_PATH="$TRACE_MCP_CLI_OVERRIDE"; fi
55
+
56
+ # --- 3. Fast path: config is good → exec directly ---
57
+ if [ -n "$NODE_PATH" ] && [ -x "$NODE_PATH" ] && [ -n "$CLI_PATH" ] && [ -f "$CLI_PATH" ]; then
58
+ log "exec(config) node=$NODE_PATH cli=$CLI_PATH argc=$#"
59
+ exec "$NODE_PATH" "$CLI_PATH" "$@"
60
+ fi
61
+
62
+ # --- 4. Probe fallback (stable sources only, no version globs) ---
63
+
64
+ # Resolve node from an nvm-layout tree ($1 = root, e.g. ~/.nvm or ~/Library/.../Herd/config/nvm).
65
+ # Handles: concrete aliases (v22.22.2), chained aliases (default → lts/hydrogen), and
66
+ # major-only shortcuts (default=22 → glob versions/node/v22.*).
67
+ node_from_nvm_tree() {
68
+ local root="$1"
69
+ [ -f "$root/alias/default" ] || return 1
70
+
71
+ local ver
72
+ ver=$(head -1 "$root/alias/default" 2>/dev/null)
73
+ # Follow up to 2 levels of alias indirection (default → lts/hydrogen → v18.x.y)
74
+ local i
75
+ for i in 1 2; do
76
+ if [ -n "$ver" ] && [ -f "$root/alias/$ver" ]; then
77
+ ver=$(head -1 "$root/alias/$ver" 2>/dev/null)
78
+ fi
79
+ done
80
+ [ -n "$ver" ] || return 1
81
+
82
+ # Exact-match: v22.22.2 or bare v22.22.2 (no leading v is legal too)
83
+ if [ -x "$root/versions/node/$ver/bin/node" ]; then
84
+ echo "$root/versions/node/$ver/bin/node"
85
+ return 0
86
+ fi
87
+ if [ -x "$root/versions/node/v$ver/bin/node" ]; then
88
+ echo "$root/versions/node/v$ver/bin/node"
89
+ return 0
90
+ fi
91
+
92
+ # Major-only shortcut: alias=`22` → expand to newest v22.* (sort -V = version-sort)
93
+ if [[ "$ver" =~ ^[0-9]+$ ]]; then
94
+ local match
95
+ match=$(ls -d "$root/versions/node/v$ver".* 2>/dev/null | sort -V | tail -1)
96
+ if [ -n "$match" ] && [ -x "$match/bin/node" ]; then
97
+ echo "$match/bin/node"
98
+ return 0
99
+ fi
100
+ fi
101
+
102
+ return 1
103
+ }
104
+
105
+ probe_node() {
106
+ # 4a. System-wide stable paths (Homebrew, /usr/local)
107
+ for candidate in /opt/homebrew/bin/node /usr/local/bin/node; do
108
+ if [ -x "$candidate" ]; then
109
+ echo "$candidate"
110
+ return 0
111
+ fi
112
+ done
113
+
114
+ # 4b. Volta — stable symlink regardless of active version
115
+ if [ -x "$HOME/.volta/bin/node" ]; then
116
+ echo "$HOME/.volta/bin/node"
117
+ return 0
118
+ fi
119
+
120
+ # 4c. nvm default alias (dereference chained aliases; handle major-only shortcuts)
121
+ if node_from_nvm_tree "$HOME/.nvm"; then return 0; fi
122
+
123
+ # 4d. Herd (same nvm-compatible tree)
124
+ if node_from_nvm_tree "$HOME/Library/Application Support/Herd/config/nvm"; then return 0; fi
125
+
126
+ # 4e. fnm default alias (three possible locations)
127
+ for fnm_dir in \
128
+ "$HOME/.local/share/fnm/aliases/default" \
129
+ "$HOME/.fnm/aliases/default" \
130
+ "$HOME/Library/Application Support/fnm/aliases/default"; do
131
+ if [ -x "$fnm_dir/bin/node" ]; then
132
+ echo "$fnm_dir/bin/node"
133
+ return 0
134
+ fi
135
+ done
136
+
137
+ return 1
138
+ }
139
+
140
+ probe_cli() {
141
+ # Standard layout across nvm/Herd/brew/npm: dist/cli.js sits under
142
+ # <node_prefix>/lib/node_modules/trace-mcp/dist/cli.js
143
+ local node_bin="$1"
144
+ local candidate
145
+ candidate="$(dirname "$node_bin")/../lib/node_modules/trace-mcp/dist/cli.js"
146
+ if [ -f "$candidate" ]; then
147
+ # Normalise the .. path for cleaner logging (best-effort; leave as-is if realpath is missing)
148
+ if command -v realpath >/dev/null 2>&1; then
149
+ realpath "$candidate" 2>/dev/null || echo "$candidate"
150
+ else
151
+ echo "$candidate"
152
+ fi
153
+ return 0
154
+ fi
155
+ return 1
156
+ }
157
+
158
+ if [ -z "$NODE_PATH" ] || [ ! -x "$NODE_PATH" ]; then
159
+ NODE_PATH=$(probe_node) || die "node binary not found — install Node.js (brew install node / nvm / volta) or set TRACE_MCP_NODE_OVERRIDE"
160
+ log "probe: node=$NODE_PATH"
161
+ fi
162
+
163
+ if [ -z "$CLI_PATH" ] || [ ! -f "$CLI_PATH" ]; then
164
+ CLI_PATH=$(probe_cli "$NODE_PATH") || die "trace-mcp package not found next to node=$NODE_PATH — run: npm i -g trace-mcp && trace-mcp init"
165
+ log "probe: cli=$CLI_PATH"
166
+ fi
167
+
168
+ log "exec(probe) node=$NODE_PATH cli=$CLI_PATH argc=$#"
169
+ exec "$NODE_PATH" "$CLI_PATH" "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trace-mcp",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "mcpName": "io.github.nikolai-vysotskyi/trace-mcp",
5
5
  "description": "Framework-aware code intelligence MCP server — 60 framework integrations, 81 languages, up to 99% token reduction",
6
6
  "type": "module",