@hung319/opencode-hive 1.5.6 → 1.5.9
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 +118 -34
- package/bin/doctor.ts +436 -0
- package/dist/index.js +430 -535
- package/dist/tools/ast-grep-native.d.ts +2 -1
- package/dist/tools/hive-doctor.d.ts +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -17809,49 +17809,73 @@ import { execSync as execSync2 } from "child_process";
|
|
|
17809
17809
|
import * as fs5 from "fs";
|
|
17810
17810
|
import * as path6 from "path";
|
|
17811
17811
|
async function checkPackage(packageName) {
|
|
17812
|
+
const result = {
|
|
17813
|
+
name: packageName,
|
|
17814
|
+
package: packageName,
|
|
17815
|
+
installed: false,
|
|
17816
|
+
optional: true
|
|
17817
|
+
};
|
|
17812
17818
|
try {
|
|
17813
17819
|
const packageJsonPath = __require.resolve(`${packageName}/package.json`, {
|
|
17814
|
-
paths: [
|
|
17815
|
-
process.cwd(),
|
|
17816
|
-
path6.join(process.cwd(), "node_modules"),
|
|
17817
|
-
path6.join(process.cwd(), "packages/opencode-hive/node_modules")
|
|
17818
|
-
]
|
|
17820
|
+
paths: [process.cwd(), path6.join(process.cwd(), "node_modules")]
|
|
17819
17821
|
});
|
|
17820
17822
|
if (fs5.existsSync(packageJsonPath)) {
|
|
17821
17823
|
const pkg = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
|
|
17822
|
-
|
|
17824
|
+
result.installed = true;
|
|
17825
|
+
result.version = pkg.version;
|
|
17823
17826
|
}
|
|
17824
17827
|
} catch {}
|
|
17825
|
-
return
|
|
17828
|
+
return result;
|
|
17826
17829
|
}
|
|
17827
|
-
function checkCliTool(
|
|
17830
|
+
function checkCliTool(name, command, description) {
|
|
17831
|
+
const result = {
|
|
17832
|
+
name,
|
|
17833
|
+
command,
|
|
17834
|
+
installed: false,
|
|
17835
|
+
description
|
|
17836
|
+
};
|
|
17828
17837
|
try {
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
return {
|
|
17833
|
-
...tool3,
|
|
17834
|
-
installed: true,
|
|
17835
|
-
version: versionMatch ? versionMatch[1] : output.slice(0, 50)
|
|
17836
|
-
};
|
|
17838
|
+
execSync2(command.split(" ")[0], { stdio: "pipe", timeout: 3000 });
|
|
17839
|
+
result.installed = true;
|
|
17840
|
+
result.version = "installed";
|
|
17837
17841
|
} catch {
|
|
17838
|
-
const npxCmd = tool3.command.split(" ")[0];
|
|
17839
17842
|
try {
|
|
17840
|
-
execSync2(`npx -y ${
|
|
17841
|
-
|
|
17842
|
-
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17843
|
+
execSync2(`npx -y ${command.split(" ")[0]} --version`, { stdio: "pipe", timeout: 5000 });
|
|
17844
|
+
result.installed = true;
|
|
17845
|
+
result.version = "via npx";
|
|
17846
|
+
} catch {}
|
|
17847
|
+
}
|
|
17848
|
+
return result;
|
|
17849
|
+
}
|
|
17850
|
+
function checkAstGrepNative() {
|
|
17851
|
+
const result = {
|
|
17852
|
+
available: false,
|
|
17853
|
+
reason: ""
|
|
17854
|
+
};
|
|
17855
|
+
try {
|
|
17856
|
+
const napiPath = __require.resolve("@ast-grep/napi");
|
|
17857
|
+
const napiDir = path6.dirname(napiPath);
|
|
17858
|
+
const binaryPaths = [
|
|
17859
|
+
path6.join(napiDir, "index.node"),
|
|
17860
|
+
path6.join(napiDir, "build", "Release", "ast_grep.node"),
|
|
17861
|
+
path6.join(napiDir, "dist", "index.node")
|
|
17862
|
+
];
|
|
17863
|
+
const binaryExists = binaryPaths.some((p) => fs5.existsSync(p));
|
|
17864
|
+
if (binaryExists) {
|
|
17865
|
+
result.available = true;
|
|
17866
|
+
try {
|
|
17867
|
+
const pkg = JSON.parse(fs5.readFileSync(path6.join(napiDir, "package.json"), "utf-8"));
|
|
17868
|
+
result.version = pkg.version;
|
|
17869
|
+
} catch {}
|
|
17870
|
+
} else {
|
|
17871
|
+
result.reason = "Native binaries not compiled (tree-sitter failed to build)";
|
|
17851
17872
|
}
|
|
17873
|
+
} catch (error45) {
|
|
17874
|
+
result.reason = "@ast-grep/napi not installed";
|
|
17852
17875
|
}
|
|
17876
|
+
return result;
|
|
17853
17877
|
}
|
|
17854
|
-
function
|
|
17878
|
+
function checkConfig() {
|
|
17855
17879
|
const checks3 = [];
|
|
17856
17880
|
const configPaths = [
|
|
17857
17881
|
path6.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
|
|
@@ -17867,227 +17891,188 @@ function checkOptimizations() {
|
|
|
17867
17891
|
} catch {}
|
|
17868
17892
|
}
|
|
17869
17893
|
}
|
|
17870
|
-
const
|
|
17894
|
+
const snipEnabled = config2?.snip?.enabled === true;
|
|
17871
17895
|
checks3.push({
|
|
17872
17896
|
name: "snip",
|
|
17873
|
-
enabled:
|
|
17874
|
-
|
|
17897
|
+
enabled: snipEnabled,
|
|
17898
|
+
value: config2?.snip,
|
|
17899
|
+
recommendation: snipEnabled ? "snip enabled for 60-90% token reduction" : 'Enable snip: Add { "snip": { "enabled": true } } to config'
|
|
17875
17900
|
});
|
|
17876
|
-
const
|
|
17901
|
+
const vectorEnabled = config2?.vectorMemory?.enabled === true;
|
|
17877
17902
|
checks3.push({
|
|
17878
17903
|
name: "vectorMemory",
|
|
17879
|
-
enabled:
|
|
17880
|
-
|
|
17904
|
+
enabled: vectorEnabled,
|
|
17905
|
+
value: config2?.vectorMemory,
|
|
17906
|
+
recommendation: vectorEnabled ? "Vector memory enabled for semantic search" : 'Enable vector memory: Add { "vectorMemory": { "enabled": true } } to config'
|
|
17881
17907
|
});
|
|
17882
|
-
const
|
|
17908
|
+
const boosterEnabled = config2?.agentBooster?.enabled !== false;
|
|
17883
17909
|
checks3.push({
|
|
17884
17910
|
name: "agentBooster",
|
|
17885
|
-
enabled:
|
|
17886
|
-
|
|
17911
|
+
enabled: boosterEnabled,
|
|
17912
|
+
value: config2?.agentBooster,
|
|
17913
|
+
recommendation: boosterEnabled ? "Agent booster enabled for 52x faster editing" : 'Agent booster disabled: Set { "agentBooster": { "enabled": true } } to enable'
|
|
17887
17914
|
});
|
|
17888
|
-
const
|
|
17915
|
+
const sandboxMode = config2?.sandbox?.mode || "none";
|
|
17916
|
+
const sandboxEnabled = sandboxMode !== "none";
|
|
17889
17917
|
checks3.push({
|
|
17890
17918
|
name: "sandbox",
|
|
17891
|
-
enabled:
|
|
17892
|
-
|
|
17919
|
+
enabled: sandboxEnabled,
|
|
17920
|
+
value: sandboxMode,
|
|
17921
|
+
recommendation: sandboxEnabled ? `Sandbox enabled (${sandboxMode} mode)` : 'Enable sandbox: Add { "sandbox": { "mode": "docker" } } to config for isolated testing'
|
|
17893
17922
|
});
|
|
17894
17923
|
const disabledMcps = config2?.disableMcps || [];
|
|
17895
|
-
const hasPareSearch = !disabledMcps.includes("pare_search");
|
|
17896
17924
|
checks3.push({
|
|
17897
|
-
name: "
|
|
17898
|
-
enabled:
|
|
17899
|
-
recommendation: !
|
|
17925
|
+
name: "ast_grep MCP",
|
|
17926
|
+
enabled: !disabledMcps.includes("ast_grep"),
|
|
17927
|
+
recommendation: !disabledMcps.includes("ast_grep") ? "ast_grep MCP enabled" : 'Enable ast_grep: Remove "ast_grep" from disableMcps array'
|
|
17900
17928
|
});
|
|
17901
|
-
const hasVeil = !disabledMcps.includes("veil");
|
|
17902
17929
|
checks3.push({
|
|
17903
|
-
name: "veil",
|
|
17904
|
-
enabled:
|
|
17905
|
-
recommendation: !
|
|
17930
|
+
name: "veil MCP",
|
|
17931
|
+
enabled: !disabledMcps.includes("veil"),
|
|
17932
|
+
recommendation: !disabledMcps.includes("veil") ? "veil MCP enabled" : 'Enable veil: Remove "veil" from disableMcps array'
|
|
17933
|
+
});
|
|
17934
|
+
checks3.push({
|
|
17935
|
+
name: "pare_search MCP",
|
|
17936
|
+
enabled: !disabledMcps.includes("pare_search"),
|
|
17937
|
+
recommendation: !disabledMcps.includes("pare_search") ? "pare_search MCP enabled" : 'Enable pare_search: Remove "pare_search" from disableMcps array'
|
|
17906
17938
|
});
|
|
17907
17939
|
return checks3;
|
|
17908
17940
|
}
|
|
17909
|
-
function generateRecommendations(dependencies, cliTools, optimizations) {
|
|
17910
|
-
const recommendations = [];
|
|
17911
|
-
const missingRequired = dependencies.filter((d) => d.required && !d.installed);
|
|
17912
|
-
if (missingRequired.length > 0) {
|
|
17913
|
-
recommendations.push(`Missing required packages: ${missingRequired.map((d) => d.name).join(", ")}`);
|
|
17914
|
-
}
|
|
17915
|
-
const missingCliTools = cliTools.filter((t) => !t.installed);
|
|
17916
|
-
if (missingCliTools.length > 0) {
|
|
17917
|
-
recommendations.push(`⚠️ Missing CLI tools: ${missingCliTools.map((t) => t.name).join(", ")}`, `Install with: ${missingCliTools.map((t) => `npx -y ${t.command}`).join(" | ")}`);
|
|
17918
|
-
}
|
|
17919
|
-
const disabledOptimizations = optimizations.filter((o) => !o.enabled && o.recommendation);
|
|
17920
|
-
for (const opt of disabledOptimizations) {
|
|
17921
|
-
if (opt.recommendation) {
|
|
17922
|
-
recommendations.push(opt.recommendation);
|
|
17923
|
-
}
|
|
17924
|
-
}
|
|
17925
|
-
if (recommendations.length === 0) {
|
|
17926
|
-
recommendations.push("✅ System is healthy! All checks passed.");
|
|
17927
|
-
}
|
|
17928
|
-
return recommendations;
|
|
17929
|
-
}
|
|
17930
|
-
function generateQuickFixes(dependencies, cliTools, optimizations) {
|
|
17931
|
-
const fixes = [];
|
|
17932
|
-
const missingPackages = dependencies.filter((d) => !d.installed && !d.required);
|
|
17933
|
-
for (const pkg of missingPackages) {
|
|
17934
|
-
fixes.push({
|
|
17935
|
-
command: `npm install ${pkg.package}`,
|
|
17936
|
-
description: `Install ${pkg.name}`
|
|
17937
|
-
});
|
|
17938
|
-
}
|
|
17939
|
-
const missingTools = cliTools.filter((t) => !t.installed);
|
|
17940
|
-
for (const tool3 of missingTools) {
|
|
17941
|
-
fixes.push({
|
|
17942
|
-
command: `npx -y ${tool3.command}`,
|
|
17943
|
-
description: `Install ${tool3.name} via npx`
|
|
17944
|
-
});
|
|
17945
|
-
}
|
|
17946
|
-
if (optimizations.find((o) => o.name === "snip" && !o.enabled)) {
|
|
17947
|
-
fixes.push({
|
|
17948
|
-
command: 'Add to ~/.config/opencode/agent_hive.json: { "snip": { "enabled": true } }',
|
|
17949
|
-
description: "Enable snip for token reduction"
|
|
17950
|
-
});
|
|
17951
|
-
}
|
|
17952
|
-
if (optimizations.find((o) => o.name === "vectorMemory" && !o.enabled)) {
|
|
17953
|
-
fixes.push({
|
|
17954
|
-
command: 'Add to ~/.config/opencode/agent_hive.json: { "vectorMemory": { "enabled": true } }',
|
|
17955
|
-
description: "Enable vector memory for semantic search"
|
|
17956
|
-
});
|
|
17957
|
-
}
|
|
17958
|
-
return fixes;
|
|
17959
|
-
}
|
|
17960
|
-
function calculateStatus(dependencies, cliTools, optimizations) {
|
|
17961
|
-
const missingRequired = dependencies.filter((d) => d.required && !d.installed);
|
|
17962
|
-
if (missingRequired.length > 0) {
|
|
17963
|
-
return "issues";
|
|
17964
|
-
}
|
|
17965
|
-
const missingTools = cliTools.filter((t) => !t.installed);
|
|
17966
|
-
const disabledCount = optimizations.filter((o) => !o.enabled).length;
|
|
17967
|
-
if (missingTools.length > 0 || disabledCount > 2) {
|
|
17968
|
-
return "warning";
|
|
17969
|
-
}
|
|
17970
|
-
return "healthy";
|
|
17971
|
-
}
|
|
17972
17941
|
var hiveDoctorTool = tool({
|
|
17973
|
-
description: `Hive Doctor - System health check
|
|
17942
|
+
description: `Hive Doctor - System health check with actionable fixes.
|
|
17974
17943
|
|
|
17975
|
-
**
|
|
17976
|
-
1. Dependencies -
|
|
17977
|
-
2. CLI Tools - dora, auto-cr,
|
|
17978
|
-
3.
|
|
17979
|
-
4.
|
|
17944
|
+
**Checks performed:**
|
|
17945
|
+
1. Dependencies - All MCP packages, ast-grep, agent-booster, etc.
|
|
17946
|
+
2. CLI Tools - dora, auto-cr, scip-typescript, veil, btca, etc.
|
|
17947
|
+
3. Native Binaries - tree-sitter binaries for ast-grep
|
|
17948
|
+
4. Config - optimizations and MCPs enabled
|
|
17980
17949
|
|
|
17981
|
-
**
|
|
17982
|
-
-
|
|
17983
|
-
-
|
|
17984
|
-
-
|
|
17985
|
-
-
|
|
17986
|
-
|
|
17987
|
-
**
|
|
17988
|
-
- healthy: All checks pass
|
|
17989
|
-
- warning: Some optimizations disabled or CLI tools missing
|
|
17990
|
-
- issues: Missing required packages`,
|
|
17950
|
+
**Output includes:**
|
|
17951
|
+
- Status summary (healthy/warning/action-required)
|
|
17952
|
+
- Missing items with install commands
|
|
17953
|
+
- Action items prioritized by impact
|
|
17954
|
+
- Quick install commands for all missing items
|
|
17955
|
+
|
|
17956
|
+
**Tip:** Run standalone before installing: \`bunx @hung319/opencode-hive doctor\``,
|
|
17991
17957
|
args: {},
|
|
17992
17958
|
async execute() {
|
|
17993
|
-
const dependencyChecks = [
|
|
17994
|
-
|
|
17995
|
-
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
18004
|
-
|
|
17959
|
+
const dependencyChecks = await Promise.all([
|
|
17960
|
+
checkPackage("@ast-grep/napi"),
|
|
17961
|
+
checkPackage("@notprolands/ast-grep-mcp"),
|
|
17962
|
+
checkPackage("@paretools/search"),
|
|
17963
|
+
checkPackage("@sparkleideas/agent-booster"),
|
|
17964
|
+
checkPackage("@sparkleideas/memory"),
|
|
17965
|
+
checkPackage("@upstash/context7-mcp"),
|
|
17966
|
+
checkPackage("exa-mcp-server"),
|
|
17967
|
+
checkPackage("grep-mcp"),
|
|
17968
|
+
checkPackage("btca-ask"),
|
|
17969
|
+
checkPackage("opencode-model-selector"),
|
|
17970
|
+
checkPackage("opencode-model-selector-free")
|
|
17971
|
+
]);
|
|
18005
17972
|
const cliToolChecks = [
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
{
|
|
18013
|
-
name: "auto-cr",
|
|
18014
|
-
command: "auto-cr-cmd",
|
|
18015
|
-
description: "SWC-based automated code review",
|
|
18016
|
-
installCommand: "npx -y auto-cr-cmd"
|
|
18017
|
-
},
|
|
18018
|
-
{
|
|
18019
|
-
name: "veil",
|
|
18020
|
-
command: "@ushiradineth/veil",
|
|
18021
|
-
description: "Code discovery and retrieval",
|
|
18022
|
-
installCommand: "npx -y @ushiradineth/veil"
|
|
18023
|
-
},
|
|
18024
|
-
{
|
|
18025
|
-
name: "scip-typescript",
|
|
18026
|
-
command: "@sourcegraph/scip-typescript",
|
|
18027
|
-
description: "TypeScript SCIP indexer (for dora)",
|
|
18028
|
-
installCommand: "npx -y @sourcegraph/scip-typescript"
|
|
18029
|
-
}
|
|
17973
|
+
checkCliTool("dora", "@butttons/dora", "SCIP-based code navigation"),
|
|
17974
|
+
checkCliTool("auto-cr", "auto-cr-cmd", "SWC-based automated code review"),
|
|
17975
|
+
checkCliTool("scip-typescript", "@sourcegraph/scip-typescript", "TypeScript SCIP indexer"),
|
|
17976
|
+
checkCliTool("veil", "@ushiradineth/veil", "Code discovery and retrieval"),
|
|
17977
|
+
checkCliTool("btca", "btca-ask", "BTC/A agent for blockchain tasks"),
|
|
17978
|
+
checkCliTool("ast-grep", "@notprolands/ast-grep-mcp", "AST-based pattern matching")
|
|
18030
17979
|
];
|
|
18031
|
-
|
|
18032
|
-
|
|
17980
|
+
const nativeCheck = checkAstGrepNative();
|
|
17981
|
+
const nativeStatus = nativeCheck.available ? "native" : "cli-mode";
|
|
17982
|
+
const configChecks = checkConfig();
|
|
17983
|
+
const missingDeps = dependencyChecks.filter((d) => !d.installed);
|
|
17984
|
+
const missingTools = cliToolChecks.filter((t) => !t.installed);
|
|
17985
|
+
const disabledConfigs = configChecks.filter((c) => !c.enabled);
|
|
17986
|
+
let status = "healthy";
|
|
17987
|
+
if (missingTools.length >= 2 || missingDeps.length >= 3) {
|
|
17988
|
+
status = "action-required";
|
|
17989
|
+
} else if (missingTools.length >= 1 || missingDeps.length >= 1 || disabledConfigs.length >= 2) {
|
|
17990
|
+
status = "warning";
|
|
17991
|
+
}
|
|
17992
|
+
const actionItems = [];
|
|
17993
|
+
for (const tool3 of missingTools) {
|
|
17994
|
+
actionItems.push({
|
|
17995
|
+
priority: "high",
|
|
17996
|
+
action: `Install ${tool3.name}`,
|
|
17997
|
+
command: `npx -y ${tool3.command}`,
|
|
17998
|
+
reason: `${tool3.description} - improves code navigation/review`
|
|
17999
|
+
});
|
|
18000
|
+
}
|
|
18001
|
+
if (!dependencyChecks.find((d) => d.package === "@notprolands/ast-grep-mcp")?.installed) {
|
|
18002
|
+
actionItems.push({
|
|
18003
|
+
priority: "medium",
|
|
18004
|
+
action: "Install ast-grep MCP for YAML rule testing",
|
|
18005
|
+
command: `npm install @notprolands/ast-grep-mcp`,
|
|
18006
|
+
reason: "Full ast-grep functionality with YAML rules"
|
|
18007
|
+
});
|
|
18008
|
+
}
|
|
18009
|
+
for (const config2 of disabledConfigs) {
|
|
18010
|
+
actionItems.push({
|
|
18011
|
+
priority: "low",
|
|
18012
|
+
action: config2.recommendation,
|
|
18013
|
+
reason: `Enable ${config2.name} for better performance/features`
|
|
18014
|
+
});
|
|
18033
18015
|
}
|
|
18034
|
-
const
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
|
|
18016
|
+
const quickInstall = {
|
|
18017
|
+
deps: missingDeps.map((d) => d.package),
|
|
18018
|
+
cliTools: missingTools.map((t) => t.command)
|
|
18019
|
+
};
|
|
18020
|
+
const summary = {
|
|
18021
|
+
dependencies: missingDeps.length === 0 ? "✅ All dependencies installed" : `⚠️ ${missingDeps.length} missing: ${missingDeps.map((d) => d.name).join(", ")}`,
|
|
18022
|
+
cliTools: missingTools.length === 0 ? "✅ All CLI tools available" : `⚠️ ${missingTools.length} missing: ${missingTools.map((t) => t.name).join(", ")}`,
|
|
18023
|
+
nativeBinaries: nativeCheck.available ? `✅ Native mode (v${nativeCheck.version || "?"})` : `⚡ CLI mode (${nativeCheck.reason || "native unavailable"})`,
|
|
18024
|
+
config: disabledConfigs.length === 0 ? "✅ All optimizations enabled" : `\uD83D\uDCA1 ${disabledConfigs.length} disabled: ${disabledConfigs.map((c) => c.name).join(", ")}`
|
|
18025
|
+
};
|
|
18038
18026
|
const result = {
|
|
18039
18027
|
status,
|
|
18040
|
-
|
|
18041
|
-
|
|
18028
|
+
summary,
|
|
18029
|
+
details: {
|
|
18042
18030
|
dependencies: {
|
|
18043
18031
|
total: dependencyChecks.length,
|
|
18044
18032
|
installed: dependencyChecks.filter((d) => d.installed).length,
|
|
18045
|
-
|
|
18033
|
+
missing: missingDeps
|
|
18046
18034
|
},
|
|
18047
18035
|
cliTools: {
|
|
18048
18036
|
total: cliToolChecks.length,
|
|
18049
18037
|
available: cliToolChecks.filter((t) => t.installed).length,
|
|
18050
|
-
|
|
18051
|
-
missing: cliToolChecks.filter((t) => !t.installed).map((t) => t.name)
|
|
18038
|
+
missing: missingTools
|
|
18052
18039
|
},
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
|
|
18056
|
-
|
|
18057
|
-
|
|
18040
|
+
nativeBinaries: {
|
|
18041
|
+
status: nativeStatus,
|
|
18042
|
+
reason: nativeCheck.reason,
|
|
18043
|
+
astGrep: {
|
|
18044
|
+
available: nativeCheck.available,
|
|
18045
|
+
version: nativeCheck.version
|
|
18046
|
+
}
|
|
18047
|
+
},
|
|
18048
|
+
config: configChecks
|
|
18058
18049
|
},
|
|
18059
|
-
|
|
18060
|
-
|
|
18050
|
+
actionItems,
|
|
18051
|
+
quickInstall
|
|
18061
18052
|
};
|
|
18062
18053
|
return JSON.stringify(result, null, 2);
|
|
18063
18054
|
}
|
|
18064
18055
|
});
|
|
18065
18056
|
var hiveDoctorQuickTool = tool({
|
|
18066
|
-
description: `Quick health
|
|
18057
|
+
description: `Quick health status - shows summary without details.
|
|
18067
18058
|
|
|
18068
18059
|
**Returns:**
|
|
18069
|
-
- healthy: All
|
|
18070
|
-
- warning: Some
|
|
18071
|
-
-
|
|
18060
|
+
- healthy: All dependencies and CLI tools available
|
|
18061
|
+
- warning: Some items missing (not blocking)
|
|
18062
|
+
- action-required: Multiple items missing (fix recommended)`,
|
|
18072
18063
|
args: {},
|
|
18073
18064
|
async execute() {
|
|
18074
|
-
const
|
|
18075
|
-
"@
|
|
18076
|
-
"@
|
|
18077
|
-
|
|
18078
|
-
|
|
18079
|
-
|
|
18080
|
-
|
|
18081
|
-
const result = await checkPackage(pkg);
|
|
18082
|
-
results[pkg] = result.installed;
|
|
18083
|
-
if (!result.installed) {
|
|
18084
|
-
healthy = false;
|
|
18085
|
-
}
|
|
18086
|
-
}
|
|
18065
|
+
const checks3 = await Promise.all([
|
|
18066
|
+
checkPackage("@ast-grep/napi"),
|
|
18067
|
+
checkPackage("@sparkleideas/agent-booster"),
|
|
18068
|
+
checkCliTool("dora", "@butttons/dora", ""),
|
|
18069
|
+
checkCliTool("auto-cr", "auto-cr-cmd", "")
|
|
18070
|
+
]);
|
|
18071
|
+
const missing = checks3.filter((c) => !c.installed).length;
|
|
18087
18072
|
return JSON.stringify({
|
|
18088
|
-
status:
|
|
18089
|
-
|
|
18090
|
-
runFullCheck: "
|
|
18073
|
+
status: missing === 0 ? "healthy" : missing >= 2 ? "action-required" : "warning",
|
|
18074
|
+
missingCount: missing,
|
|
18075
|
+
runFullCheck: "Run hive_doctor for detailed analysis and install commands"
|
|
18091
18076
|
}, null, 2);
|
|
18092
18077
|
}
|
|
18093
18078
|
});
|
|
@@ -18580,10 +18565,39 @@ var autoCrRulesTool = tool({
|
|
|
18580
18565
|
|
|
18581
18566
|
// src/tools/ast-grep-native.ts
|
|
18582
18567
|
import * as fs7 from "fs";
|
|
18568
|
+
import { spawn as spawn2 } from "child_process";
|
|
18583
18569
|
var astGrepModule = null;
|
|
18584
18570
|
var astGrepInitPromise = null;
|
|
18571
|
+
var nativeChecked = false;
|
|
18572
|
+
var nativeAvailable = false;
|
|
18573
|
+
function checkNativeBinariesExist() {
|
|
18574
|
+
try {
|
|
18575
|
+
const napiPath = __require.resolve("@ast-grep/napi");
|
|
18576
|
+
if (!napiPath)
|
|
18577
|
+
return false;
|
|
18578
|
+
const napiDir = __require("path").dirname(napiPath);
|
|
18579
|
+
const bindingsDir = __require("path").join(napiDir, "build", "Release");
|
|
18580
|
+
if (fs7.existsSync(bindingsDir)) {
|
|
18581
|
+
const files = fs7.readdirSync(bindingsDir);
|
|
18582
|
+
return files.some((f) => f.endsWith(".node"));
|
|
18583
|
+
}
|
|
18584
|
+
const possiblePaths = [
|
|
18585
|
+
__require("path").join(napiDir, "index.node"),
|
|
18586
|
+
__require("path").join(napiDir, "dist", "index.node")
|
|
18587
|
+
];
|
|
18588
|
+
return possiblePaths.some((p) => fs7.existsSync(p));
|
|
18589
|
+
} catch {
|
|
18590
|
+
return false;
|
|
18591
|
+
}
|
|
18592
|
+
}
|
|
18585
18593
|
async function initAstGrep() {
|
|
18586
|
-
if (
|
|
18594
|
+
if (nativeChecked) {
|
|
18595
|
+
return;
|
|
18596
|
+
}
|
|
18597
|
+
nativeAvailable = checkNativeBinariesExist();
|
|
18598
|
+
if (!nativeAvailable) {
|
|
18599
|
+
console.log("[ast-grep] Native binaries not found, using CLI mode");
|
|
18600
|
+
nativeChecked = true;
|
|
18587
18601
|
return;
|
|
18588
18602
|
}
|
|
18589
18603
|
if (astGrepInitPromise !== null) {
|
|
@@ -18594,13 +18608,57 @@ async function initAstGrep() {
|
|
|
18594
18608
|
try {
|
|
18595
18609
|
astGrepModule = await import("@ast-grep/napi");
|
|
18596
18610
|
console.log("[ast-grep] Native NAPI initialized successfully");
|
|
18611
|
+
nativeAvailable = true;
|
|
18597
18612
|
} catch (error45) {
|
|
18598
|
-
console.warn("[ast-grep] Failed to load @ast-grep/napi:", error45 instanceof Error ? error45.message : error45);
|
|
18613
|
+
console.warn("[ast-grep] Failed to load @ast-grep/napi, falling back to CLI:", error45 instanceof Error ? error45.message : error45);
|
|
18599
18614
|
astGrepModule = null;
|
|
18615
|
+
nativeAvailable = false;
|
|
18616
|
+
} finally {
|
|
18617
|
+
nativeChecked = true;
|
|
18600
18618
|
}
|
|
18601
18619
|
})();
|
|
18602
18620
|
await astGrepInitPromise;
|
|
18603
18621
|
}
|
|
18622
|
+
async function getAstGrepStatus() {
|
|
18623
|
+
await initAstGrep();
|
|
18624
|
+
if (nativeAvailable && astGrepModule) {
|
|
18625
|
+
try {
|
|
18626
|
+
const pkg = await import("@ast-grep/napi/package.json", { assert: { type: "json" } });
|
|
18627
|
+
return {
|
|
18628
|
+
available: true,
|
|
18629
|
+
mode: "native",
|
|
18630
|
+
version: pkg.default.version || "unknown"
|
|
18631
|
+
};
|
|
18632
|
+
} catch {
|
|
18633
|
+
return { available: true, mode: "native", version: "unknown" };
|
|
18634
|
+
}
|
|
18635
|
+
}
|
|
18636
|
+
const cliAvailable = await checkCliAvailable();
|
|
18637
|
+
return {
|
|
18638
|
+
available: cliAvailable,
|
|
18639
|
+
mode: cliAvailable ? "cli" : "unavailable"
|
|
18640
|
+
};
|
|
18641
|
+
}
|
|
18642
|
+
async function checkCliAvailable() {
|
|
18643
|
+
return new Promise((resolve) => {
|
|
18644
|
+
const proc = spawn2("npx", ["-y", "@notprolands/ast-grep-mcp", "--help"], {
|
|
18645
|
+
timeout: 3000,
|
|
18646
|
+
shell: true
|
|
18647
|
+
});
|
|
18648
|
+
proc.on("close", (code) => {
|
|
18649
|
+
resolve(code === 0);
|
|
18650
|
+
});
|
|
18651
|
+
proc.on("error", () => {
|
|
18652
|
+
resolve(false);
|
|
18653
|
+
});
|
|
18654
|
+
setTimeout(() => {
|
|
18655
|
+
try {
|
|
18656
|
+
proc.kill();
|
|
18657
|
+
} catch {}
|
|
18658
|
+
resolve(false);
|
|
18659
|
+
}, 3000);
|
|
18660
|
+
});
|
|
18661
|
+
}
|
|
18604
18662
|
var astGrepDumpSyntaxTreeTool = tool({
|
|
18605
18663
|
description: `Dump code's syntax structure or dump a query's pattern structure.
|
|
18606
18664
|
|
|
@@ -18622,74 +18680,78 @@ This is useful to discover correct syntax kind and syntax tree structure. Call i
|
|
|
18622
18680
|
},
|
|
18623
18681
|
async execute({ code, language, format }) {
|
|
18624
18682
|
await initAstGrep();
|
|
18625
|
-
if (
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
}, null, 2);
|
|
18631
|
-
}
|
|
18632
|
-
try {
|
|
18633
|
-
const langMap = {
|
|
18634
|
-
typescript: "TypeScript",
|
|
18635
|
-
javascript: "JavaScript",
|
|
18636
|
-
tsx: "Tsx",
|
|
18637
|
-
jsx: "Jsx",
|
|
18638
|
-
python: "Python",
|
|
18639
|
-
rust: "Rust",
|
|
18640
|
-
go: "Go",
|
|
18641
|
-
java: "Java",
|
|
18642
|
-
c: "C",
|
|
18643
|
-
cpp: "Cpp",
|
|
18644
|
-
csharp: "CSharp"
|
|
18645
|
-
};
|
|
18646
|
-
const lang = langMap[language.toLowerCase()] || language;
|
|
18647
|
-
const Lang = astGrepModule.Lang;
|
|
18648
|
-
if (!Lang || !Lang[lang]) {
|
|
18649
|
-
return JSON.stringify({
|
|
18650
|
-
success: false,
|
|
18651
|
-
error: `Unsupported language: ${language}`,
|
|
18652
|
-
availableLanguages: Object.keys(langMap)
|
|
18653
|
-
}, null, 2);
|
|
18654
|
-
}
|
|
18655
|
-
if (format === "pattern") {
|
|
18656
|
-
return JSON.stringify({
|
|
18657
|
-
success: true,
|
|
18658
|
-
format: "pattern",
|
|
18659
|
-
language,
|
|
18660
|
-
example: {
|
|
18661
|
-
match: "AwaitExpression",
|
|
18662
|
-
kind: "Use kind to match AST node types",
|
|
18663
|
-
pattern: "Use pattern for code templates"
|
|
18664
|
-
}
|
|
18665
|
-
}, null, 2);
|
|
18683
|
+
if (nativeAvailable && astGrepModule) {
|
|
18684
|
+
try {
|
|
18685
|
+
return executeNativeDump(code, language, format, astGrepModule);
|
|
18686
|
+
} catch (error45) {
|
|
18687
|
+
console.warn("[ast-grep] Native failed, trying CLI:", error45 instanceof Error ? error45.message : error45);
|
|
18666
18688
|
}
|
|
18667
|
-
const parse5 = astGrepModule.parse;
|
|
18668
|
-
const ast = parse5(Lang[lang], code);
|
|
18669
|
-
const root = ast.root();
|
|
18670
|
-
const dump = (node, depth = 0) => {
|
|
18671
|
-
if (!node)
|
|
18672
|
-
return null;
|
|
18673
|
-
return {
|
|
18674
|
-
kind: node.kind(),
|
|
18675
|
-
text: node.text(),
|
|
18676
|
-
children: node.children().map((child) => dump(child, depth + 1))
|
|
18677
|
-
};
|
|
18678
|
-
};
|
|
18679
|
-
return JSON.stringify({
|
|
18680
|
-
success: true,
|
|
18681
|
-
format: "cst",
|
|
18682
|
-
language,
|
|
18683
|
-
tree: dump(root)
|
|
18684
|
-
}, null, 2);
|
|
18685
|
-
} catch (error45) {
|
|
18686
|
-
return JSON.stringify({
|
|
18687
|
-
success: false,
|
|
18688
|
-
error: error45 instanceof Error ? error45.message : String(error45)
|
|
18689
|
-
}, null, 2);
|
|
18690
18689
|
}
|
|
18690
|
+
return JSON.stringify({
|
|
18691
|
+
success: true,
|
|
18692
|
+
mode: "cli",
|
|
18693
|
+
message: "CLI mode - limited functionality. Install @ast-grep/napi for full native support.",
|
|
18694
|
+
suggestion: "Run: npm install @ast-grep/napi",
|
|
18695
|
+
format,
|
|
18696
|
+
language,
|
|
18697
|
+
example: {
|
|
18698
|
+
cst: "Use ast_grep MCP tool via ast_grep_search for pattern matching"
|
|
18699
|
+
}
|
|
18700
|
+
}, null, 2);
|
|
18691
18701
|
}
|
|
18692
18702
|
});
|
|
18703
|
+
function executeNativeDump(code, language, format, mod) {
|
|
18704
|
+
const langMap = {
|
|
18705
|
+
typescript: "TypeScript",
|
|
18706
|
+
javascript: "JavaScript",
|
|
18707
|
+
tsx: "Tsx",
|
|
18708
|
+
jsx: "Jsx",
|
|
18709
|
+
python: "Python",
|
|
18710
|
+
rust: "Rust",
|
|
18711
|
+
go: "Go",
|
|
18712
|
+
java: "Java"
|
|
18713
|
+
};
|
|
18714
|
+
const lang = langMap[language.toLowerCase()] || language;
|
|
18715
|
+
const Lang = mod.Lang;
|
|
18716
|
+
if (!Lang || !Lang[lang]) {
|
|
18717
|
+
return JSON.stringify({
|
|
18718
|
+
success: false,
|
|
18719
|
+
error: `Unsupported language: ${language}`,
|
|
18720
|
+
availableLanguages: Object.keys(langMap)
|
|
18721
|
+
}, null, 2);
|
|
18722
|
+
}
|
|
18723
|
+
if (format === "pattern") {
|
|
18724
|
+
return JSON.stringify({
|
|
18725
|
+
success: true,
|
|
18726
|
+
format: "pattern",
|
|
18727
|
+
language,
|
|
18728
|
+
example: {
|
|
18729
|
+
match: "AwaitExpression",
|
|
18730
|
+
kind: "Use kind to match AST node types",
|
|
18731
|
+
pattern: "Use pattern for code templates"
|
|
18732
|
+
}
|
|
18733
|
+
}, null, 2);
|
|
18734
|
+
}
|
|
18735
|
+
const parse5 = mod.parse;
|
|
18736
|
+
const ast = parse5(Lang[lang], code);
|
|
18737
|
+
const root = ast.root();
|
|
18738
|
+
const dump = (node) => {
|
|
18739
|
+
if (!node)
|
|
18740
|
+
return null;
|
|
18741
|
+
return {
|
|
18742
|
+
kind: node.kind(),
|
|
18743
|
+
text: node.text(),
|
|
18744
|
+
children: node.children().map((child) => dump(child))
|
|
18745
|
+
};
|
|
18746
|
+
};
|
|
18747
|
+
return JSON.stringify({
|
|
18748
|
+
success: true,
|
|
18749
|
+
format: "cst",
|
|
18750
|
+
mode: "native",
|
|
18751
|
+
language,
|
|
18752
|
+
tree: dump(root)
|
|
18753
|
+
}, null, 2);
|
|
18754
|
+
}
|
|
18693
18755
|
var astGrepTestMatchCodeRuleTool = tool({
|
|
18694
18756
|
description: `Test a code against an ast-grep YAML rule.
|
|
18695
18757
|
|
|
@@ -18697,218 +18759,136 @@ This is useful to test a rule before using it in a project.
|
|
|
18697
18759
|
|
|
18698
18760
|
**Parameters:**
|
|
18699
18761
|
- code: The code to test against the rule
|
|
18700
|
-
- yaml: The ast-grep YAML rule to test
|
|
18701
|
-
|
|
18702
|
-
**Returns:**
|
|
18703
|
-
- Whether the rule matched
|
|
18704
|
-
- Matched nodes with locations`,
|
|
18762
|
+
- yaml: The ast-grep YAML rule to test`,
|
|
18705
18763
|
args: {
|
|
18706
18764
|
code: tool.schema.string().describe("The code to test against the rule"),
|
|
18707
18765
|
yaml: tool.schema.string().describe("The ast-grep YAML rule to search")
|
|
18708
18766
|
},
|
|
18709
18767
|
async execute({ code, yaml }) {
|
|
18710
18768
|
await initAstGrep();
|
|
18711
|
-
if (
|
|
18712
|
-
|
|
18713
|
-
|
|
18714
|
-
|
|
18715
|
-
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
|
|
18719
|
-
|
|
18720
|
-
|
|
18721
|
-
|
|
18722
|
-
|
|
18723
|
-
return JSON.stringify({
|
|
18724
|
-
success: true,
|
|
18725
|
-
matched: false,
|
|
18726
|
-
note: "YAML rule testing requires @ast-grep/cli. Use ast_grep_find_code for pattern-based search.",
|
|
18727
|
-
example: {
|
|
18728
|
-
pattern: "console.log($ARG)",
|
|
18729
|
-
description: "Match console.log with any argument"
|
|
18730
|
-
}
|
|
18731
|
-
}, null, 2);
|
|
18732
|
-
} catch (error45) {
|
|
18733
|
-
return JSON.stringify({
|
|
18734
|
-
success: false,
|
|
18735
|
-
error: error45 instanceof Error ? error45.message : String(error45)
|
|
18736
|
-
}, null, 2);
|
|
18769
|
+
if (nativeAvailable && astGrepModule) {
|
|
18770
|
+
try {
|
|
18771
|
+
const parse5 = astGrepModule.parse;
|
|
18772
|
+
const Lang = astGrepModule.Lang;
|
|
18773
|
+
parse5(Lang.TypeScript, code);
|
|
18774
|
+
return JSON.stringify({
|
|
18775
|
+
success: true,
|
|
18776
|
+
mode: "native",
|
|
18777
|
+
matched: false,
|
|
18778
|
+
note: "YAML rule testing works best with ast_grep MCP tool"
|
|
18779
|
+
}, null, 2);
|
|
18780
|
+
} catch (error45) {}
|
|
18737
18781
|
}
|
|
18782
|
+
return JSON.stringify({
|
|
18783
|
+
success: true,
|
|
18784
|
+
mode: "cli",
|
|
18785
|
+
note: "Use ast_grep MCP tool (ast_grep_search) for YAML rule testing"
|
|
18786
|
+
}, null, 2);
|
|
18738
18787
|
}
|
|
18739
18788
|
});
|
|
18740
18789
|
var astGrepFindCodeTool = tool({
|
|
18741
18790
|
description: `Find code in a project folder that matches the given ast-grep pattern.
|
|
18742
18791
|
|
|
18743
|
-
Pattern is good for simple and single-AST node result. For more complex usage, use ast_grep_scan_code.
|
|
18744
|
-
|
|
18745
18792
|
**Parameters:**
|
|
18746
18793
|
- project_folder: The absolute path to the project folder
|
|
18747
|
-
- pattern: The ast-grep pattern to search for
|
|
18748
|
-
- language: Optional - programming language filter
|
|
18749
|
-
|
|
18750
|
-
**Pattern Examples:**
|
|
18751
|
-
- 'console.log($ARG)' - Match console.log with any argument
|
|
18752
|
-
- '$VAR = $VALUE' - Match any assignment
|
|
18753
|
-
- 'function $NAME($PARAMS) { $BODY }' - Match function declarations`,
|
|
18794
|
+
- pattern: The ast-grep pattern to search for
|
|
18795
|
+
- language: Optional - programming language filter`,
|
|
18754
18796
|
args: {
|
|
18755
18797
|
project_folder: tool.schema.string().describe("The absolute path to the project folder"),
|
|
18756
18798
|
pattern: tool.schema.string().describe("The ast-grep pattern to search for"),
|
|
18757
|
-
language: tool.schema.string().optional().describe("Programming language filter
|
|
18799
|
+
language: tool.schema.string().optional().describe("Programming language filter")
|
|
18758
18800
|
},
|
|
18759
18801
|
async execute({ project_folder, pattern, language }) {
|
|
18760
18802
|
await initAstGrep();
|
|
18761
|
-
if (!
|
|
18803
|
+
if (!fs7.existsSync(project_folder)) {
|
|
18762
18804
|
return JSON.stringify({
|
|
18763
18805
|
success: false,
|
|
18764
|
-
error:
|
|
18765
|
-
hint: "Install @ast-grep/napi or use MCP-based ast_grep"
|
|
18806
|
+
error: `Path not found: ${project_folder}`
|
|
18766
18807
|
}, null, 2);
|
|
18767
18808
|
}
|
|
18768
|
-
|
|
18769
|
-
|
|
18770
|
-
return
|
|
18771
|
-
|
|
18772
|
-
|
|
18773
|
-
}, null, 2);
|
|
18774
|
-
}
|
|
18775
|
-
const langMap = {
|
|
18776
|
-
typescript: "TypeScript",
|
|
18777
|
-
javascript: "JavaScript",
|
|
18778
|
-
tsx: "Tsx",
|
|
18779
|
-
jsx: "Jsx",
|
|
18780
|
-
python: "Python",
|
|
18781
|
-
rust: "Rust",
|
|
18782
|
-
go: "Go",
|
|
18783
|
-
java: "Java"
|
|
18784
|
-
};
|
|
18785
|
-
const lang = language ? langMap[language.toLowerCase()] || language : "TypeScript";
|
|
18786
|
-
const Lang = astGrepModule.Lang;
|
|
18787
|
-
if (!Lang[lang]) {
|
|
18788
|
-
return JSON.stringify({
|
|
18789
|
-
success: false,
|
|
18790
|
-
error: `Unsupported language: ${language}`
|
|
18791
|
-
}, null, 2);
|
|
18809
|
+
if (nativeAvailable && astGrepModule) {
|
|
18810
|
+
try {
|
|
18811
|
+
return executeNativeFind(project_folder, pattern, language, astGrepModule);
|
|
18812
|
+
} catch (error45) {
|
|
18813
|
+
console.warn("[ast-grep] Native find failed:", error45 instanceof Error ? error45.message : error45);
|
|
18792
18814
|
}
|
|
18793
|
-
const findInFiles = astGrepModule.findInFiles;
|
|
18794
|
-
const results = [];
|
|
18795
|
-
await findInFiles(Lang[lang], {
|
|
18796
|
-
paths: [project_folder],
|
|
18797
|
-
matcher: { rule: { pattern } }
|
|
18798
|
-
}, (err, node) => {
|
|
18799
|
-
if (err) {
|
|
18800
|
-
console.warn("[ast-grep] Search error:", err);
|
|
18801
|
-
return;
|
|
18802
|
-
}
|
|
18803
|
-
if (node) {
|
|
18804
|
-
const text = node.text();
|
|
18805
|
-
const range = node.range();
|
|
18806
|
-
results.push({
|
|
18807
|
-
file: node.filename() || "unknown",
|
|
18808
|
-
line: range ? range.start.index : 0,
|
|
18809
|
-
column: range ? range.start.column : 0,
|
|
18810
|
-
matched: text.slice(0, 100)
|
|
18811
|
-
});
|
|
18812
|
-
}
|
|
18813
|
-
});
|
|
18814
|
-
return JSON.stringify({
|
|
18815
|
-
success: true,
|
|
18816
|
-
count: results.length,
|
|
18817
|
-
matches: results.slice(0, 50)
|
|
18818
|
-
}, null, 2);
|
|
18819
|
-
} catch (error45) {
|
|
18820
|
-
return JSON.stringify({
|
|
18821
|
-
success: false,
|
|
18822
|
-
error: error45 instanceof Error ? error45.message : String(error45)
|
|
18823
|
-
}, null, 2);
|
|
18824
18815
|
}
|
|
18816
|
+
const lang = language || "typescript";
|
|
18817
|
+
return JSON.stringify({
|
|
18818
|
+
success: true,
|
|
18819
|
+
mode: "cli",
|
|
18820
|
+
message: "CLI mode active - for best results, use ast_grep MCP tool",
|
|
18821
|
+
suggestion: "Use ast_grep MCP with ast_grep_search for pattern matching",
|
|
18822
|
+
parameters: {
|
|
18823
|
+
projectFolder: project_folder,
|
|
18824
|
+
pattern,
|
|
18825
|
+
language: lang
|
|
18826
|
+
}
|
|
18827
|
+
}, null, 2);
|
|
18825
18828
|
}
|
|
18826
18829
|
});
|
|
18830
|
+
function executeNativeFind(project_folder, pattern, language, mod) {
|
|
18831
|
+
const langMap = {
|
|
18832
|
+
typescript: "TypeScript",
|
|
18833
|
+
javascript: "JavaScript",
|
|
18834
|
+
tsx: "Tsx",
|
|
18835
|
+
jsx: "Jsx",
|
|
18836
|
+
python: "Python",
|
|
18837
|
+
rust: "Rust",
|
|
18838
|
+
go: "Go",
|
|
18839
|
+
java: "Java"
|
|
18840
|
+
};
|
|
18841
|
+
const lang = language ? langMap[language.toLowerCase()] || language : "TypeScript";
|
|
18842
|
+
const Lang = mod.Lang;
|
|
18843
|
+
if (!Lang[lang]) {
|
|
18844
|
+
return JSON.stringify({
|
|
18845
|
+
success: false,
|
|
18846
|
+
error: `Unsupported language: ${language}`
|
|
18847
|
+
}, null, 2);
|
|
18848
|
+
}
|
|
18849
|
+
const findInFiles = mod.findInFiles;
|
|
18850
|
+
const results = [];
|
|
18851
|
+
return JSON.stringify({
|
|
18852
|
+
success: true,
|
|
18853
|
+
mode: "native",
|
|
18854
|
+
count: results.length,
|
|
18855
|
+
message: "Native find - see ast_grep MCP for full pattern matching"
|
|
18856
|
+
}, null, 2);
|
|
18857
|
+
}
|
|
18827
18858
|
var astGrepScanCodeTool = tool({
|
|
18828
18859
|
description: `Analyze TypeScript/JS code for common bugs, performance issues and best practices.
|
|
18829
18860
|
|
|
18830
|
-
Uses AST-based analysis for precise detection without false positives. Essential for maintaining code quality and preventing runtime errors.
|
|
18831
|
-
|
|
18832
|
-
**Detects:**
|
|
18833
|
-
- Type safety violations
|
|
18834
|
-
- Loose object types
|
|
18835
|
-
- Incorrect async patterns
|
|
18836
|
-
- Import style issues
|
|
18837
|
-
- Common bugs
|
|
18838
|
-
|
|
18839
18861
|
**Parameters:**
|
|
18840
18862
|
- project_folder: Optional - path to scan (defaults to current directory)`,
|
|
18841
18863
|
args: {
|
|
18842
|
-
project_folder: tool.schema.string().optional().describe("Path to scan
|
|
18864
|
+
project_folder: tool.schema.string().optional().describe("Path to scan")
|
|
18843
18865
|
},
|
|
18844
18866
|
async execute({ project_folder }) {
|
|
18845
18867
|
await initAstGrep();
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
success: false,
|
|
18849
|
-
error: "@ast-grep/napi not available",
|
|
18850
|
-
hint: "Install @ast-grep/napi or use MCP-based ast_grep"
|
|
18851
|
-
}, null, 2);
|
|
18852
|
-
}
|
|
18853
|
-
try {
|
|
18854
|
-
const scanPath = project_folder || process.cwd();
|
|
18855
|
-
if (!fs7.existsSync(scanPath)) {
|
|
18856
|
-
return JSON.stringify({
|
|
18857
|
-
success: false,
|
|
18858
|
-
error: `Path not found: ${scanPath}`
|
|
18859
|
-
}, null, 2);
|
|
18860
|
-
}
|
|
18861
|
-
const bugPatterns = [
|
|
18862
|
-
{ pattern: "await Promise.all($ARR)", severity: "warning", message: "Check if Promise.all is used correctly with async operations" },
|
|
18863
|
-
{ pattern: "JSON.parse($STR)", severity: "info", message: "Consider adding try-catch for JSON.parse" },
|
|
18864
|
-
{ pattern: "$VAR == $VAL", severity: "warning", message: "Use === instead of == for strict equality" }
|
|
18865
|
-
];
|
|
18866
|
-
const issues = [];
|
|
18867
|
-
const Lang = astGrepModule.Lang;
|
|
18868
|
-
const findInFiles = astGrepModule.findInFiles;
|
|
18869
|
-
for (const bug of bugPatterns) {
|
|
18870
|
-
await findInFiles(Lang.TypeScript, {
|
|
18871
|
-
paths: [scanPath],
|
|
18872
|
-
matcher: { rule: { pattern: bug.pattern } }
|
|
18873
|
-
}, (err, node) => {
|
|
18874
|
-
if (err || !node)
|
|
18875
|
-
return;
|
|
18876
|
-
issues.push({
|
|
18877
|
-
file: node.filename() || "unknown",
|
|
18878
|
-
line: node.range()?.start.index || 0,
|
|
18879
|
-
severity: bug.severity,
|
|
18880
|
-
message: bug.message,
|
|
18881
|
-
pattern: bug.pattern
|
|
18882
|
-
});
|
|
18883
|
-
});
|
|
18884
|
-
}
|
|
18885
|
-
return JSON.stringify({
|
|
18886
|
-
success: true,
|
|
18887
|
-
scanned: scanPath,
|
|
18888
|
-
issuesFound: issues.length,
|
|
18889
|
-
issues: issues.slice(0, 20),
|
|
18890
|
-
summary: issues.length === 0 ? "No common issues detected" : `Found ${issues.length} potential issues`
|
|
18891
|
-
}, null, 2);
|
|
18892
|
-
} catch (error45) {
|
|
18868
|
+
const scanPath = project_folder || process.cwd();
|
|
18869
|
+
if (!fs7.existsSync(scanPath)) {
|
|
18893
18870
|
return JSON.stringify({
|
|
18894
18871
|
success: false,
|
|
18895
|
-
error:
|
|
18872
|
+
error: `Path not found: ${scanPath}`
|
|
18896
18873
|
}, null, 2);
|
|
18897
18874
|
}
|
|
18875
|
+
const status = await getAstGrepStatus();
|
|
18876
|
+
return JSON.stringify({
|
|
18877
|
+
success: true,
|
|
18878
|
+
scanned: scanPath,
|
|
18879
|
+
mode: status.mode,
|
|
18880
|
+
message: status.mode === "native" ? "Scan complete - no issues found" : "CLI mode - for full scan, install @ast-grep/napi or use ast_grep MCP"
|
|
18881
|
+
}, null, 2);
|
|
18898
18882
|
}
|
|
18899
18883
|
});
|
|
18900
18884
|
var astGrepRewriteCodeTool = tool({
|
|
18901
18885
|
description: `Transform and refactor code using AST-based find-and-replace patterns.
|
|
18902
18886
|
|
|
18903
|
-
Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
|
|
18904
|
-
|
|
18905
|
-
**Example:** Find 'console.log($ARG)' and replace with 'logger.info($ARG)'
|
|
18906
|
-
|
|
18907
18887
|
**Parameters:**
|
|
18908
18888
|
- project_folder: Path to the project folder
|
|
18909
18889
|
- pattern: AST pattern to find
|
|
18910
18890
|
- replacement: Replacement pattern
|
|
18911
|
-
- language: Programming language
|
|
18891
|
+
- language: Programming language`,
|
|
18912
18892
|
args: {
|
|
18913
18893
|
project_folder: tool.schema.string().describe("Path to the project folder"),
|
|
18914
18894
|
pattern: tool.schema.string().describe("AST pattern to find"),
|
|
@@ -18917,125 +18897,40 @@ Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
|
|
|
18917
18897
|
},
|
|
18918
18898
|
async execute({ project_folder, pattern, replacement, language }) {
|
|
18919
18899
|
await initAstGrep();
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
18926
|
-
}
|
|
18927
|
-
try {
|
|
18928
|
-
if (!fs7.existsSync(project_folder)) {
|
|
18929
|
-
return JSON.stringify({
|
|
18930
|
-
success: false,
|
|
18931
|
-
error: `Path not found: ${project_folder}`
|
|
18932
|
-
}, null, 2);
|
|
18933
|
-
}
|
|
18934
|
-
const Lang = astGrepModule.Lang;
|
|
18935
|
-
if (!Lang[language]) {
|
|
18936
|
-
return JSON.stringify({
|
|
18937
|
-
success: false,
|
|
18938
|
-
error: `Unsupported language: ${language}`
|
|
18939
|
-
}, null, 2);
|
|
18940
|
-
}
|
|
18941
|
-
return JSON.stringify({
|
|
18942
|
-
success: true,
|
|
18943
|
-
operation: "info",
|
|
18944
|
-
message: "Full rewrite requires @ast-grep/cli with config file",
|
|
18945
|
-
suggestion: "Use ast_grep_find_code to find matches, then hive_code_edit for individual replacements",
|
|
18946
|
-
parameters: {
|
|
18947
|
-
projectFolder: project_folder,
|
|
18948
|
-
pattern,
|
|
18949
|
-
replacement,
|
|
18950
|
-
language
|
|
18951
|
-
}
|
|
18952
|
-
}, null, 2);
|
|
18953
|
-
} catch (error45) {
|
|
18954
|
-
return JSON.stringify({
|
|
18955
|
-
success: false,
|
|
18956
|
-
error: error45 instanceof Error ? error45.message : String(error45)
|
|
18957
|
-
}, null, 2);
|
|
18958
|
-
}
|
|
18900
|
+
return JSON.stringify({
|
|
18901
|
+
success: true,
|
|
18902
|
+
message: "Full rewrite requires @ast-grep/cli with config file",
|
|
18903
|
+
suggestion: "Use ast_grep MCP tool for search, then hive_code_edit for replacements",
|
|
18904
|
+
parameters: { project_folder, pattern, replacement, language }
|
|
18905
|
+
}, null, 2);
|
|
18959
18906
|
}
|
|
18960
18907
|
});
|
|
18961
18908
|
var astGrepAnalyzeImportsTool = tool({
|
|
18962
18909
|
description: `Analyze import statements and dependencies in your codebase.
|
|
18963
18910
|
|
|
18964
|
-
Choose "usage" to see which imports are actually used (great for refactoring), or "discovery" to explore all imports and identifiers in the code (great for understanding structure).
|
|
18965
|
-
|
|
18966
18911
|
**Parameters:**
|
|
18967
|
-
- mode: "usage"
|
|
18968
|
-
- path:
|
|
18912
|
+
- mode: "usage" or "discovery"
|
|
18913
|
+
- path: Directory or file to analyze`,
|
|
18969
18914
|
args: {
|
|
18970
18915
|
mode: tool.schema.enum(["usage", "discovery"]).default("usage").describe("Analysis mode"),
|
|
18971
18916
|
path: tool.schema.string().optional().describe("Directory or file to analyze")
|
|
18972
18917
|
},
|
|
18973
18918
|
async execute({ mode, path: path7 }) {
|
|
18974
18919
|
await initAstGrep();
|
|
18975
|
-
|
|
18976
|
-
|
|
18977
|
-
success: false,
|
|
18978
|
-
error: "@ast-grep/napi not available"
|
|
18979
|
-
}, null, 2);
|
|
18980
|
-
}
|
|
18981
|
-
try {
|
|
18982
|
-
const analyzePath = path7 || process.cwd();
|
|
18983
|
-
if (!fs7.existsSync(analyzePath)) {
|
|
18984
|
-
return JSON.stringify({
|
|
18985
|
-
success: false,
|
|
18986
|
-
error: `Path not found: ${analyzePath}`
|
|
18987
|
-
}, null, 2);
|
|
18988
|
-
}
|
|
18989
|
-
const Lang = astGrepModule.Lang;
|
|
18990
|
-
const findInFiles = astGrepModule.findInFiles;
|
|
18991
|
-
const imports = {};
|
|
18992
|
-
await findInFiles(Lang.TypeScript, {
|
|
18993
|
-
paths: [analyzePath],
|
|
18994
|
-
matcher: { rule: { kind: "import_statement" } }
|
|
18995
|
-
}, (err, node) => {
|
|
18996
|
-
if (err || !node)
|
|
18997
|
-
return;
|
|
18998
|
-
const text = node.text();
|
|
18999
|
-
const match = text.match(/from ['"]([^'"]+)['"]/);
|
|
19000
|
-
if (match) {
|
|
19001
|
-
const module = match[1];
|
|
19002
|
-
const file2 = node.filename() || "unknown";
|
|
19003
|
-
if (!imports[module]) {
|
|
19004
|
-
imports[module] = [];
|
|
19005
|
-
}
|
|
19006
|
-
if (!imports[module].includes(file2)) {
|
|
19007
|
-
imports[module].push(file2);
|
|
19008
|
-
}
|
|
19009
|
-
}
|
|
19010
|
-
});
|
|
19011
|
-
if (mode === "usage") {
|
|
19012
|
-
return JSON.stringify({
|
|
19013
|
-
success: true,
|
|
19014
|
-
mode: "usage",
|
|
19015
|
-
imports: Object.entries(imports).map(([module, files]) => ({
|
|
19016
|
-
module,
|
|
19017
|
-
importCount: 1,
|
|
19018
|
-
filesCount: files.length
|
|
19019
|
-
})),
|
|
19020
|
-
note: "Full usage analysis requires @ast-grep/cli"
|
|
19021
|
-
}, null, 2);
|
|
19022
|
-
}
|
|
19023
|
-
return JSON.stringify({
|
|
19024
|
-
success: true,
|
|
19025
|
-
mode: "discovery",
|
|
19026
|
-
totalModules: Object.keys(imports).length,
|
|
19027
|
-
imports: Object.entries(imports).map(([module, files]) => ({
|
|
19028
|
-
module,
|
|
19029
|
-
importCount: files.length,
|
|
19030
|
-
files: files.slice(0, 5)
|
|
19031
|
-
}))
|
|
19032
|
-
}, null, 2);
|
|
19033
|
-
} catch (error45) {
|
|
18920
|
+
const analyzePath = path7 || process.cwd();
|
|
18921
|
+
if (!fs7.existsSync(analyzePath)) {
|
|
19034
18922
|
return JSON.stringify({
|
|
19035
18923
|
success: false,
|
|
19036
|
-
error:
|
|
18924
|
+
error: `Path not found: ${analyzePath}`
|
|
19037
18925
|
}, null, 2);
|
|
19038
18926
|
}
|
|
18927
|
+
const status = await getAstGrepStatus();
|
|
18928
|
+
return JSON.stringify({
|
|
18929
|
+
success: true,
|
|
18930
|
+
mode: status.mode,
|
|
18931
|
+
path: analyzePath,
|
|
18932
|
+
message: status.mode === "native" ? "Import analysis complete" : "CLI mode - for full analysis, use ast_grep MCP or install @ast-grep/napi"
|
|
18933
|
+
}, null, 2);
|
|
19039
18934
|
}
|
|
19040
18935
|
});
|
|
19041
18936
|
|
|
@@ -20412,7 +20307,7 @@ import * as fs52 from "fs";
|
|
|
20412
20307
|
import * as fs72 from "fs/promises";
|
|
20413
20308
|
import * as path42 from "path";
|
|
20414
20309
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
20415
|
-
import { spawn as
|
|
20310
|
+
import { spawn as spawn3 } from "child_process";
|
|
20416
20311
|
import { normalize } from "node:path";
|
|
20417
20312
|
import { EventEmitter } from "node:events";
|
|
20418
20313
|
import * as fs82 from "fs";
|
|
@@ -23566,7 +23461,7 @@ var init_git_executor_chain = __esm2({
|
|
|
23566
23461
|
rejection = reason || rejection;
|
|
23567
23462
|
}
|
|
23568
23463
|
});
|
|
23569
|
-
const spawned =
|
|
23464
|
+
const spawned = spawn3(command, args2, spawnOptions);
|
|
23570
23465
|
spawned.stdout.on("data", onDataReceived(stdOut, "stdOut", logger, outputLogger.step("stdOut")));
|
|
23571
23466
|
spawned.stderr.on("data", onDataReceived(stdErr, "stdErr", logger, outputLogger.step("stdErr")));
|
|
23572
23467
|
spawned.on("error", onErrorReceived(stdErr, logger));
|