🎉 init: 小龙的工作空间
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Guard 5: Tool Trace Guard
|
||||
* Inventories tool call sites and checks for trace/log coverage.
|
||||
*
|
||||
* → Architecture Freeze v2 (PR-1): docs/architecture-freeze-v2.md
|
||||
* → Future: PR-10 Trace Model enforcement
|
||||
*
|
||||
* SOFT GUARD — Trace model not yet implemented (PR-10).
|
||||
* Currently inventories tool call entry points and reports gaps.
|
||||
* No hard failure at this stage.
|
||||
*/
|
||||
|
||||
import { readdirSync, readFileSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { execSync } from "node:child_process";
|
||||
|
||||
const OPENCLAW_HOME = process.env.OPENCLAW_HOME || "/opt/homebrew/lib/node_modules/openclaw";
|
||||
const DIST_DIR = join(OPENCLAW_HOME, "dist");
|
||||
|
||||
function guardToolTrace() {
|
||||
const issues = [];
|
||||
const toolSites = [];
|
||||
let totalToolCallSites = 0;
|
||||
let sitesWithTrace = 0;
|
||||
|
||||
// Search for tool call patterns in dist
|
||||
const searchTerms = [
|
||||
"tool_call",
|
||||
"toolCall",
|
||||
"tool.call",
|
||||
"tool_exec",
|
||||
"toolExec",
|
||||
"invokeTool",
|
||||
"runTool",
|
||||
];
|
||||
|
||||
try {
|
||||
const grepResult = execSync(
|
||||
`grep -rln -E "(tool_call|toolCall|tool\\.call|tool_exec|toolExec|executeTool|invokeTool|runTool)" "${DIST_DIR}" 2>/dev/null | grep -v ".d.ts$" | grep -v "node_modules" | grep ".js$" | head -30`,
|
||||
{ timeout: 30000, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 }
|
||||
).trim();
|
||||
|
||||
if (grepResult) {
|
||||
const files = grepResult.split("\n").filter(Boolean);
|
||||
totalToolCallSites = files.length;
|
||||
|
||||
for (const file of files) {
|
||||
const relativePath = file.replace(DIST_DIR + "/", "");
|
||||
|
||||
// Check if this file has trace/log instrumentation
|
||||
try {
|
||||
const content = readFileSync(file, "utf8");
|
||||
const hasTrace =
|
||||
content.includes("trace") ||
|
||||
content.includes("Trace") ||
|
||||
content.includes("span") ||
|
||||
content.includes("log") ||
|
||||
content.includes("event") ||
|
||||
content.includes("audit") ||
|
||||
content.includes("diagnostics");
|
||||
|
||||
if (hasTrace) sitesWithTrace++;
|
||||
|
||||
toolSites.push({
|
||||
file: relativePath,
|
||||
hasTrace,
|
||||
module: relativePath.split("/")[0] || "unknown",
|
||||
});
|
||||
} catch {
|
||||
toolSites.push({
|
||||
file: relativePath,
|
||||
hasTrace: false,
|
||||
module: relativePath.split("/")[0] || "unknown",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.status !== 1) {
|
||||
console.log(` Warning: grep failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const sitesWithoutTrace = toolSites.filter(s => !s.hasTrace);
|
||||
|
||||
console.log("");
|
||||
console.log("═══════════════════════════════════════");
|
||||
console.log(" Guard 5: Tool Trace Guard");
|
||||
console.log("═══════════════════════════════════════");
|
||||
console.log("");
|
||||
|
||||
console.log(` Tool call entry points found: ${totalToolCallSites}`);
|
||||
console.log(` Sites with trace/log: ${sitesWithTrace}`);
|
||||
console.log(` Sites without trace: ${sitesWithoutTrace.length}`);
|
||||
|
||||
// Group by module
|
||||
const moduleSummary = {};
|
||||
for (const s of toolSites) {
|
||||
if (!moduleSummary[s.module]) {
|
||||
moduleSummary[s.module] = { total: 0, traced: 0 };
|
||||
}
|
||||
moduleSummary[s.module].total++;
|
||||
if (s.hasTrace) moduleSummary[s.module].traced++;
|
||||
}
|
||||
|
||||
if (Object.keys(moduleSummary).length > 0) {
|
||||
console.log("\n Trace coverage by module:");
|
||||
for (const [mod, stats] of Object.entries(moduleSummary)) {
|
||||
const pct = stats.total > 0 ? Math.round(stats.traced / stats.total * 100) : 0;
|
||||
const bar = "█".repeat(Math.round(pct / 10)) + "░".repeat(10 - Math.round(pct / 10));
|
||||
console.log(` ${bar} ${mod}: ${stats.traced}/${stats.total} (${pct}%)`);
|
||||
}
|
||||
}
|
||||
|
||||
if (sitesWithoutTrace.length > 0 && sitesWithoutTrace.length <= 10) {
|
||||
console.log("\n Sites without trace:");
|
||||
for (const s of sitesWithoutTrace) {
|
||||
console.log(` • ${s.file}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log(" ⚠ WARN: Trace model not yet enforced");
|
||||
console.log(` Current coverage: ${sitesWithTrace}/${totalToolCallSites} sites have tracing`);
|
||||
console.log(" After PR-10 (Trace Model), all tool calls will require trace spans.");
|
||||
|
||||
// No hard fail — soft guard
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
guardToolTrace();
|
||||
Reference in New Issue
Block a user