@triedotdev/mcp 1.0.78 → 1.0.80

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.
Files changed (39) hide show
  1. package/README.md +27 -2
  2. package/dist/{chunk-UPKBO5EM.js → chunk-432E2RYB.js} +29 -20
  3. package/dist/chunk-432E2RYB.js.map +1 -0
  4. package/dist/{chunk-RRDDAD5N.js → chunk-45NUFTNV.js} +6 -6
  5. package/dist/{chunk-35FAFFHE.js → chunk-75J4HQTD.js} +2 -2
  6. package/dist/{chunk-53URTRWH.js → chunk-D3F7VKCN.js} +2 -2
  7. package/dist/{chunk-P6VLSYXN.js → chunk-EWIEXQES.js} +2 -2
  8. package/dist/{chunk-LNLLZQWH.js → chunk-KCAWTZ7P.js} +12 -11
  9. package/dist/{chunk-LNLLZQWH.js.map → chunk-KCAWTZ7P.js.map} +1 -1
  10. package/dist/{chunk-3RKY55HZ.js → chunk-LKXDJESG.js} +671 -81
  11. package/dist/chunk-LKXDJESG.js.map +1 -0
  12. package/dist/{chunk-AIC4HOOQ.js → chunk-U5P3O5G5.js} +3 -3
  13. package/dist/{chunk-6QKDEGWR.js → chunk-WGECLUDQ.js} +4 -4
  14. package/dist/chunk-WGECLUDQ.js.map +1 -0
  15. package/dist/cli/main.js +115 -7
  16. package/dist/cli/main.js.map +1 -1
  17. package/dist/cli/yolo-daemon.js +8 -8
  18. package/dist/{goal-manager-NI4LJ2SX.js → goal-manager-NHPEUWFY.js} +4 -4
  19. package/dist/{guardian-agent-R5HX7UWJ.js → guardian-agent-UPLAQWJK.js} +6 -6
  20. package/dist/index.js +39 -41
  21. package/dist/index.js.map +1 -1
  22. package/dist/{issue-store-MULGOF6B.js → issue-store-RKJVOKSJ.js} +2 -2
  23. package/dist/ui/memory-viewer.html +4 -4
  24. package/dist/ui/pr-review.html +4 -4
  25. package/dist/ui/scan-dashboard.html +4 -4
  26. package/dist/ui/visual-qa.html +4 -4
  27. package/dist/workers/agent-worker.js +3 -3
  28. package/package.json +1 -1
  29. package/dist/chunk-3RKY55HZ.js.map +0 -1
  30. package/dist/chunk-6QKDEGWR.js.map +0 -1
  31. package/dist/chunk-UPKBO5EM.js.map +0 -1
  32. /package/dist/{chunk-RRDDAD5N.js.map → chunk-45NUFTNV.js.map} +0 -0
  33. /package/dist/{chunk-35FAFFHE.js.map → chunk-75J4HQTD.js.map} +0 -0
  34. /package/dist/{chunk-53URTRWH.js.map → chunk-D3F7VKCN.js.map} +0 -0
  35. /package/dist/{chunk-P6VLSYXN.js.map → chunk-EWIEXQES.js.map} +0 -0
  36. /package/dist/{chunk-AIC4HOOQ.js.map → chunk-U5P3O5G5.js.map} +0 -0
  37. /package/dist/{goal-manager-NI4LJ2SX.js.map → goal-manager-NHPEUWFY.js.map} +0 -0
  38. /package/dist/{guardian-agent-R5HX7UWJ.js.map → guardian-agent-UPLAQWJK.js.map} +0 -0
  39. /package/dist/{issue-store-MULGOF6B.js.map → issue-store-RKJVOKSJ.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  recordToGlobalMemory,
3
3
  updateGlobalMemoryMd
4
- } from "./chunk-P6VLSYXN.js";
4
+ } from "./chunk-EWIEXQES.js";
5
5
  import {
6
6
  checkFileLevelIssues,
7
7
  getVibeCodeTrie,
@@ -20,7 +20,7 @@ import {
20
20
  atomicWriteFile,
21
21
  atomicWriteJSON,
22
22
  storeIssues
23
- } from "./chunk-6QKDEGWR.js";
23
+ } from "./chunk-WGECLUDQ.js";
24
24
  import {
25
25
  getWorkingDirectory
26
26
  } from "./chunk-CM7EHNQK.js";
@@ -8849,10 +8849,8 @@ Output STRICT JSON:
8849
8849
  };
8850
8850
 
8851
8851
  // src/skills/installer.ts
8852
- import { mkdir as mkdir2, rm, writeFile as writeFile2, readdir, readFile as readFile3, access, cp, stat } from "fs/promises";
8853
- import { join as join3, basename as basename2, extname as extname2 } from "path";
8854
- import { exec } from "child_process";
8855
- import { promisify } from "util";
8852
+ import { mkdir as mkdir3, rm, writeFile as writeFile3, readdir as readdir3, readFile as readFile5, access, cp, stat as stat2 } from "fs/promises";
8853
+ import { join as join5, basename as basename2, extname as extname2 } from "path";
8856
8854
  import { homedir } from "os";
8857
8855
  import { existsSync as existsSync3 } from "fs";
8858
8856
 
@@ -8901,13 +8899,551 @@ function parseYamlFrontmatter(yaml) {
8901
8899
  return result;
8902
8900
  }
8903
8901
 
8904
- // src/skills/installer.ts
8902
+ // src/skills/security-scanner.ts
8903
+ import { readFile as readFile3, readdir, stat } from "fs/promises";
8904
+ import { join as join3, relative } from "path";
8905
+ var DANGEROUS_PATTERNS = [
8906
+ // Network exfiltration
8907
+ {
8908
+ pattern: /curl\s+.*-X\s+POST.*https?:\/\/(?!github\.com|githubusercontent\.com|npmjs\.org|pypi\.org)/gi,
8909
+ severity: "critical",
8910
+ category: "exfiltration",
8911
+ description: "HTTP POST to external domain - possible data exfiltration",
8912
+ recommendation: "Review the destination URL. Only allow posts to trusted domains."
8913
+ },
8914
+ {
8915
+ pattern: /wget\s+.*--post/gi,
8916
+ severity: "critical",
8917
+ category: "exfiltration",
8918
+ description: "wget POST request - possible data exfiltration",
8919
+ recommendation: "Verify the destination and data being sent."
8920
+ },
8921
+ // Credential access
8922
+ {
8923
+ pattern: /\.env(?!\.example)/gi,
8924
+ severity: "critical",
8925
+ category: "credential-access",
8926
+ description: "Access to .env file - may expose secrets",
8927
+ recommendation: "Skills should not access .env files. Use explicit configuration instead."
8928
+ },
8929
+ {
8930
+ pattern: /\.ssh[\/\\](?:id_rsa|id_ed25519|authorized_keys)/gi,
8931
+ severity: "critical",
8932
+ category: "credential-access",
8933
+ description: "Access to SSH keys - credential theft attempt",
8934
+ recommendation: "Block this skill. SSH key access is never legitimate for code analysis."
8935
+ },
8936
+ {
8937
+ pattern: /\.aws[\/\\]credentials/gi,
8938
+ severity: "critical",
8939
+ category: "credential-access",
8940
+ description: "Access to AWS credentials",
8941
+ recommendation: "Block this skill. AWS credential access indicates malicious intent."
8942
+ },
8943
+ {
8944
+ pattern: /(?:AWS|ANTHROPIC|OPENAI|GITHUB)_(?:ACCESS_)?(?:SECRET_)?KEY/gi,
8945
+ severity: "high",
8946
+ category: "credential-access",
8947
+ description: "API key access pattern detected",
8948
+ recommendation: "Verify this is necessary for skill functionality."
8949
+ },
8950
+ // Persistence mechanisms
8951
+ {
8952
+ pattern: /crontab\s+-e|crontab.*<<.*EOF/gi,
8953
+ severity: "critical",
8954
+ category: "persistence",
8955
+ description: "Crontab modification - persistence mechanism",
8956
+ recommendation: "Block this skill. Cron modification indicates malware behavior."
8957
+ },
8958
+ {
8959
+ pattern: /\.(?:bashrc|zshrc|profile|bash_profile)\s*>>/gi,
8960
+ severity: "critical",
8961
+ category: "persistence",
8962
+ description: "Shell profile modification - persistence mechanism",
8963
+ recommendation: "Block this skill. Shell profile modification is malicious."
8964
+ },
8965
+ // Shell execution (context-dependent)
8966
+ {
8967
+ pattern: /(?:bash|sh)\s+-c\s+["'].*(?:curl|wget)/gi,
8968
+ severity: "high",
8969
+ category: "shell-execution",
8970
+ description: "Shell command with network access",
8971
+ recommendation: "Review the command. Should use proper APIs instead of shell."
8972
+ },
8973
+ {
8974
+ pattern: /eval\s*\(/gi,
8975
+ severity: "high",
8976
+ category: "shell-execution",
8977
+ description: "eval() usage - potential code injection",
8978
+ recommendation: "eval() should be avoided. Review for necessity."
8979
+ },
8980
+ // Reconnaissance
8981
+ {
8982
+ pattern: /\b(?:hostname|whoami|uname|id)\b(?:\s|$|;|\||&)/gi,
8983
+ severity: "medium",
8984
+ category: "reconnaissance",
8985
+ description: "System reconnaissance command",
8986
+ recommendation: "Review if system info is necessary for skill functionality."
8987
+ },
8988
+ {
8989
+ pattern: /env\s*(?:$|;|\||>>)/gim,
8990
+ severity: "medium",
8991
+ category: "reconnaissance",
8992
+ description: "Environment variable enumeration",
8993
+ recommendation: "Skills should not need to enumerate all env variables."
8994
+ },
8995
+ // File enumeration
8996
+ {
8997
+ pattern: /find\s+.*-name\s+['"].*\.(?:env|pem|key|credentials)/gi,
8998
+ severity: "high",
8999
+ category: "credential-access",
9000
+ description: "Searching for credential files",
9001
+ recommendation: "Block this skill. Credential file enumeration is malicious."
9002
+ },
9003
+ {
9004
+ pattern: /grep\s+-r.*(?:password|secret|token|key)/gi,
9005
+ severity: "high",
9006
+ category: "credential-access",
9007
+ description: "Recursive search for secrets",
9008
+ recommendation: "Skills should use static analysis, not grep for secrets."
9009
+ },
9010
+ // Encoding/obfuscation (often used for evasion)
9011
+ {
9012
+ pattern: /base64.*\|\s*(?:curl|wget|bash|sh)/gi,
9013
+ severity: "critical",
9014
+ category: "exfiltration",
9015
+ description: "Base64 encoding with command execution - obfuscation technique",
9016
+ recommendation: "Block this skill. Base64 piping indicates malicious behavior."
9017
+ },
9018
+ {
9019
+ pattern: /tar\s+.*\|\s*(?:curl|wget)/gi,
9020
+ severity: "critical",
9021
+ category: "exfiltration",
9022
+ description: "Archiving and sending data externally",
9023
+ recommendation: "Block this skill. Tar piping indicates data exfiltration."
9024
+ },
9025
+ // Network access to suspicious TLDs
9026
+ {
9027
+ pattern: /https?:\/\/[^\s'"]+\.(?:tk|ml|ga|cf|gq|top|xyz)\b/gi,
9028
+ severity: "high",
9029
+ category: "network-access",
9030
+ description: "Access to domain with suspicious TLD",
9031
+ recommendation: "Free TLDs are often used for malicious infrastructure. Verify legitimacy."
9032
+ }
9033
+ ];
9034
+ var SAFE_DOMAINS = [
9035
+ "github.com",
9036
+ "githubusercontent.com",
9037
+ "api.github.com",
9038
+ "raw.githubusercontent.com",
9039
+ "npmjs.org",
9040
+ "registry.npmjs.org",
9041
+ "pypi.org",
9042
+ "anthropic.com",
9043
+ "openai.com"
9044
+ ];
9045
+ async function findAllFiles(dir, files = []) {
9046
+ const entries = await readdir(dir, { withFileTypes: true });
9047
+ for (const entry of entries) {
9048
+ const fullPath = join3(dir, entry.name);
9049
+ if (entry.isDirectory()) {
9050
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
9051
+ await findAllFiles(fullPath, files);
9052
+ }
9053
+ } else if (entry.isFile()) {
9054
+ const ext = entry.name.split(".").pop()?.toLowerCase();
9055
+ if (ext && ["md", "txt", "js", "ts", "py", "sh", "bash", "json", "yaml", "yml"].includes(ext)) {
9056
+ files.push(fullPath);
9057
+ }
9058
+ }
9059
+ }
9060
+ return files;
9061
+ }
9062
+ function getLineNumber(text, index) {
9063
+ return text.substring(0, index).split("\n").length;
9064
+ }
9065
+ function extractUrls(text) {
9066
+ const urlPattern = /https?:\/\/[^\s'"<>)]+/gi;
9067
+ return Array.from(text.matchAll(urlPattern), (m) => m[0]);
9068
+ }
9069
+ function isSafeDomain(url) {
9070
+ try {
9071
+ const hostname = new URL(url).hostname.toLowerCase();
9072
+ return SAFE_DOMAINS.some(
9073
+ (safe) => hostname === safe || hostname.endsWith("." + safe)
9074
+ );
9075
+ } catch {
9076
+ return false;
9077
+ }
9078
+ }
9079
+ async function scanSkillForThreats(skillPath) {
9080
+ const startTime = Date.now();
9081
+ const risks = [];
9082
+ const permissions = /* @__PURE__ */ new Set();
9083
+ const files = await findAllFiles(skillPath);
9084
+ for (const file of files) {
9085
+ const relPath = relative(skillPath, file);
9086
+ try {
9087
+ const stats = await stat(file);
9088
+ if (stats.size > 1024 * 1024) {
9089
+ continue;
9090
+ }
9091
+ const content = await readFile3(file, "utf-8");
9092
+ for (const rule of DANGEROUS_PATTERNS) {
9093
+ const matches = content.matchAll(rule.pattern);
9094
+ for (const match of matches) {
9095
+ const lineNum = getLineNumber(content, match.index ?? 0);
9096
+ risks.push({
9097
+ severity: rule.severity,
9098
+ category: rule.category,
9099
+ description: rule.description,
9100
+ location: `${relPath}:${lineNum}`,
9101
+ pattern: match[0].substring(0, 100),
9102
+ // Limit pattern length
9103
+ recommendation: rule.recommendation
9104
+ });
9105
+ if (rule.category === "shell-execution") {
9106
+ permissions.add("shell:execute");
9107
+ } else if (rule.category === "network-access") {
9108
+ permissions.add("network:access");
9109
+ } else if (rule.category === "credential-access") {
9110
+ permissions.add("credential:read");
9111
+ }
9112
+ }
9113
+ }
9114
+ const urls = extractUrls(content);
9115
+ for (const url of urls) {
9116
+ if (!isSafeDomain(url)) {
9117
+ risks.push({
9118
+ severity: "medium",
9119
+ category: "network-access",
9120
+ description: `External URL: ${url}`,
9121
+ location: relPath,
9122
+ pattern: url,
9123
+ recommendation: "Verify this domain is necessary and trustworthy."
9124
+ });
9125
+ permissions.add("network:access");
9126
+ }
9127
+ }
9128
+ } catch (error) {
9129
+ continue;
9130
+ }
9131
+ }
9132
+ const criticalRisks = risks.filter((r) => r.severity === "critical");
9133
+ const highRisks = risks.filter((r) => r.severity === "high");
9134
+ const safe = criticalRisks.length === 0 && highRisks.length < 3;
9135
+ const requiredPermissions = Array.from(permissions).map((perm) => ({
9136
+ name: perm,
9137
+ description: getPermissionDescription(perm),
9138
+ required: true
9139
+ }));
9140
+ return {
9141
+ safe,
9142
+ risks: risks.sort((a, b) => {
9143
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
9144
+ return severityOrder[a.severity] - severityOrder[b.severity];
9145
+ }),
9146
+ requiredPermissions,
9147
+ filesScanned: files.length,
9148
+ scanDuration: Date.now() - startTime
9149
+ };
9150
+ }
9151
+ function getPermissionDescription(permission) {
9152
+ const descriptions = {
9153
+ "shell:execute": "Execute shell commands on your system",
9154
+ "network:access": "Make network requests to external servers",
9155
+ "credential:read": "Access credential files and environment variables",
9156
+ "file:write": "Modify files in your project",
9157
+ "file:read": "Read files in your project"
9158
+ };
9159
+ return descriptions[permission] || permission;
9160
+ }
9161
+ function formatSecuritySummary(result) {
9162
+ if (result.risks.length === 0) {
9163
+ return "\u2705 No security risks detected";
9164
+ }
9165
+ const critical = result.risks.filter((r) => r.severity === "critical").length;
9166
+ const high = result.risks.filter((r) => r.severity === "high").length;
9167
+ const medium = result.risks.filter((r) => r.severity === "medium").length;
9168
+ const low = result.risks.filter((r) => r.severity === "low").length;
9169
+ const parts = [];
9170
+ if (critical > 0) parts.push(`\u{1F534} ${critical} critical`);
9171
+ if (high > 0) parts.push(`\u{1F7E0} ${high} high`);
9172
+ if (medium > 0) parts.push(`\u{1F7E1} ${medium} medium`);
9173
+ if (low > 0) parts.push(`\u{1F535} ${low} low`);
9174
+ return parts.join(", ") + " risk" + (result.risks.length === 1 ? "" : "s");
9175
+ }
9176
+
9177
+ // src/utils/command-runner.ts
9178
+ import { exec, execFile, execSync } from "child_process";
9179
+ import { promisify } from "util";
9180
+
9181
+ // src/skills/audit-logger.ts
9182
+ import { writeFile as writeFile2, mkdir as mkdir2, readdir as readdir2, readFile as readFile4 } from "fs/promises";
9183
+ import { join as join4 } from "path";
9184
+ async function logSkillExecution(execution) {
9185
+ const workDir = getWorkingDirectory(void 0, true);
9186
+ const auditDir = join4(workDir, ".trie", "audit");
9187
+ await mkdir2(auditDir, { recursive: true });
9188
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9189
+ const safeSkillName = execution.skillName.replace(/[^a-z0-9-]/gi, "_");
9190
+ const filename = `${timestamp}_${safeSkillName}.json`;
9191
+ const filepath = join4(auditDir, filename);
9192
+ if (!execution.endTime) {
9193
+ execution.endTime = Date.now();
9194
+ }
9195
+ if (!execution.duration) {
9196
+ execution.duration = execution.endTime - execution.startTime;
9197
+ }
9198
+ await writeFile2(filepath, JSON.stringify(execution, null, 2), "utf-8");
9199
+ }
9200
+ function createAuditEntry(skillName, skillSource, triggeredBy, targetPath) {
9201
+ return {
9202
+ skillName,
9203
+ skillSource,
9204
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9205
+ startTime: Date.now(),
9206
+ success: false,
9207
+ triggeredBy,
9208
+ targetPath,
9209
+ commands: [],
9210
+ networkCalls: [],
9211
+ filesAccessed: [],
9212
+ filesModified: []
9213
+ };
9214
+ }
9215
+ function completeAuditEntry(entry, success, error) {
9216
+ const base = {
9217
+ ...entry,
9218
+ success,
9219
+ endTime: Date.now(),
9220
+ duration: Date.now() - entry.startTime
9221
+ };
9222
+ return error ? { ...base, error } : base;
9223
+ }
9224
+ async function getRecentAuditLogs(limit = 10) {
9225
+ const workDir = getWorkingDirectory(void 0, true);
9226
+ const auditDir = join4(workDir, ".trie", "audit");
9227
+ try {
9228
+ const files = await readdir2(auditDir);
9229
+ const sorted = files.filter((f) => f.endsWith(".json")).sort().reverse().slice(0, limit);
9230
+ const logs = [];
9231
+ for (const file of sorted) {
9232
+ try {
9233
+ const content = await readFile4(join4(auditDir, file), "utf-8");
9234
+ logs.push(JSON.parse(content));
9235
+ } catch {
9236
+ }
9237
+ }
9238
+ return logs;
9239
+ } catch {
9240
+ return [];
9241
+ }
9242
+ }
9243
+ async function getSkillAuditLogs(skillName) {
9244
+ const workDir = getWorkingDirectory(void 0, true);
9245
+ const auditDir = join4(workDir, ".trie", "audit");
9246
+ const safeSkillName = skillName.replace(/[^a-z0-9-]/gi, "_");
9247
+ try {
9248
+ const files = await readdir2(auditDir);
9249
+ const skillFiles = files.filter(
9250
+ (f) => f.includes(`_${safeSkillName}.json`)
9251
+ );
9252
+ const logs = [];
9253
+ for (const file of skillFiles) {
9254
+ try {
9255
+ const content = await readFile4(join4(auditDir, file), "utf-8");
9256
+ logs.push(JSON.parse(content));
9257
+ } catch {
9258
+ }
9259
+ }
9260
+ return logs.sort(
9261
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
9262
+ );
9263
+ } catch {
9264
+ return [];
9265
+ }
9266
+ }
9267
+ async function getAuditStatistics() {
9268
+ const logs = await getRecentAuditLogs(1e3);
9269
+ const skills = /* @__PURE__ */ new Set();
9270
+ let totalCommands = 0;
9271
+ let totalNetworkCalls = 0;
9272
+ let blockedCommands = 0;
9273
+ let blockedNetworkCalls = 0;
9274
+ for (const log of logs) {
9275
+ skills.add(log.skillName);
9276
+ totalCommands += log.commands?.length ?? 0;
9277
+ totalNetworkCalls += log.networkCalls?.length ?? 0;
9278
+ blockedCommands += log.commands?.filter((c) => c.blockedBy).length ?? 0;
9279
+ blockedNetworkCalls += log.networkCalls?.filter((c) => c.blocked).length ?? 0;
9280
+ }
9281
+ return {
9282
+ totalExecutions: logs.length,
9283
+ successfulExecutions: logs.filter((l) => l.success).length,
9284
+ failedExecutions: logs.filter((l) => !l.success).length,
9285
+ uniqueSkills: skills.size,
9286
+ totalCommands,
9287
+ totalNetworkCalls,
9288
+ blockedCommands,
9289
+ blockedNetworkCalls
9290
+ };
9291
+ }
9292
+ function formatAuditLog(log) {
9293
+ const lines = [];
9294
+ const status = log.success ? "\u2705" : "\u274C";
9295
+ const duration = log.duration ? `${log.duration}ms` : "unknown";
9296
+ lines.push(`${status} ${log.skillName} (${duration})`);
9297
+ lines.push(` Time: ${new Date(log.timestamp).toLocaleString()}`);
9298
+ lines.push(` Triggered by: ${log.triggeredBy}`);
9299
+ lines.push(` Target: ${log.targetPath}`);
9300
+ if (log.commands && log.commands.length > 0) {
9301
+ lines.push(` Commands executed: ${log.commands.length}`);
9302
+ const blocked = log.commands.filter((c) => c.blockedBy).length;
9303
+ if (blocked > 0) {
9304
+ lines.push(` \u26A0\uFE0F Commands blocked: ${blocked}`);
9305
+ }
9306
+ }
9307
+ if (log.networkCalls && log.networkCalls.length > 0) {
9308
+ lines.push(` Network calls: ${log.networkCalls.length}`);
9309
+ const blocked = log.networkCalls.filter((c) => c.blocked).length;
9310
+ if (blocked > 0) {
9311
+ lines.push(` \u26A0\uFE0F Network calls blocked: ${blocked}`);
9312
+ }
9313
+ }
9314
+ if (log.error) {
9315
+ lines.push(` Error: ${log.error}`);
9316
+ }
9317
+ return lines.join("\n");
9318
+ }
9319
+
9320
+ // src/utils/command-runner.ts
8905
9321
  var execAsync = promisify(exec);
9322
+ var execFileAsync = promisify(execFile);
9323
+ function redact(text) {
9324
+ return text.replace(/\b(AWS|ANTHROPIC|OPENAI|GITHUB)_[A-Z0-9_]*\s*=\s*([^\s"'`]+)/gi, "$1_<REDACTED>=<REDACTED>").replace(/\bBearer\s+[A-Za-z0-9\-._~+/]+=*\b/g, "Bearer <REDACTED>").replace(/\bghp_[A-Za-z0-9]{20,}\b/g, "ghp_<REDACTED>").replace(/\b(?:xox[baprs]-)[A-Za-z0-9-]{10,}\b/g, "<REDACTED_SLACK_TOKEN>").replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA<REDACTED>");
9325
+ }
9326
+ function clampOutput(text, maxChars) {
9327
+ if (text.length <= maxChars) return text;
9328
+ return text.slice(0, maxChars) + `
9329
+ \u2026(truncated ${text.length - maxChars} chars)`;
9330
+ }
9331
+ function buildCommandRecord(command) {
9332
+ return {
9333
+ command,
9334
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
9335
+ };
9336
+ }
9337
+ async function finalizeAndWrite(entry, cmd, outcome, options) {
9338
+ const duration = Date.now() - outcome.startedAt;
9339
+ cmd.duration = duration;
9340
+ if (outcome.exitCode !== void 0) {
9341
+ cmd.exitCode = outcome.exitCode;
9342
+ }
9343
+ const captureOutput = options?.captureOutput ?? false;
9344
+ const redactOutput = options?.redactOutput ?? true;
9345
+ const maxOutputChars = options?.maxOutputChars ?? 2e3;
9346
+ if (captureOutput) {
9347
+ const out = outcome.stdout ?? "";
9348
+ const err = outcome.stderr ?? "";
9349
+ cmd.stdout = redactOutput ? redact(clampOutput(out, maxOutputChars)) : clampOutput(out, maxOutputChars);
9350
+ cmd.stderr = redactOutput ? redact(clampOutput(err, maxOutputChars)) : clampOutput(err, maxOutputChars);
9351
+ }
9352
+ const completed = completeAuditEntry(entry, outcome.success, outcome.error);
9353
+ await logSkillExecution(completed);
9354
+ }
9355
+ async function runShellCommand(command, audit, options) {
9356
+ const startedAt = Date.now();
9357
+ const entry = createAuditEntry(audit.actor, audit.source ?? "trie", audit.triggeredBy, audit.targetPath);
9358
+ const cmd = buildCommandRecord(command);
9359
+ entry.commands?.push(cmd);
9360
+ try {
9361
+ const { stdout, stderr } = await execAsync(command, {
9362
+ cwd: options?.cwd,
9363
+ timeout: options?.timeoutMs,
9364
+ maxBuffer: options?.maxBuffer
9365
+ });
9366
+ await finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout, stderr, startedAt }, options);
9367
+ return { stdout: stdout ?? "", stderr: stderr ?? "", exitCode: 0 };
9368
+ } catch (e) {
9369
+ const err = e;
9370
+ const stdout = typeof err.stdout === "string" ? err.stdout : "";
9371
+ const stderr = typeof err.stderr === "string" ? err.stderr : "";
9372
+ const exitCode = typeof err.code === "number" ? err.code : 1;
9373
+ await finalizeAndWrite(
9374
+ entry,
9375
+ cmd,
9376
+ { success: false, exitCode, stdout, stderr, error: err.message, startedAt },
9377
+ // Capture output for failures by default (so audits are useful)
9378
+ { ...options, captureOutput: options?.captureOutput ?? true }
9379
+ );
9380
+ return { stdout, stderr, exitCode };
9381
+ }
9382
+ }
9383
+ function runShellCommandSync(command, audit, options) {
9384
+ const startedAt = Date.now();
9385
+ const entry = createAuditEntry(audit.actor, audit.source ?? "trie", audit.triggeredBy, audit.targetPath);
9386
+ const cmd = buildCommandRecord(command);
9387
+ entry.commands?.push(cmd);
9388
+ try {
9389
+ const stdout = execSync(command, {
9390
+ cwd: options?.cwd,
9391
+ timeout: options?.timeoutMs,
9392
+ maxBuffer: options?.maxBuffer,
9393
+ encoding: "utf-8",
9394
+ stdio: ["pipe", "pipe", "pipe"]
9395
+ });
9396
+ void finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout, stderr: "", startedAt }, options);
9397
+ return { stdout: stdout ?? "", exitCode: 0 };
9398
+ } catch (e) {
9399
+ const err = e;
9400
+ const stdout = typeof err.stdout === "string" ? err.stdout : "";
9401
+ const stderr = typeof err.stderr === "string" ? err.stderr : "";
9402
+ const exitCode = typeof err.status === "number" ? err.status : 1;
9403
+ void finalizeAndWrite(
9404
+ entry,
9405
+ cmd,
9406
+ { success: false, exitCode, stdout, stderr, error: err.message, startedAt },
9407
+ { ...options, captureOutput: options?.captureOutput ?? true }
9408
+ );
9409
+ return { stdout, exitCode };
9410
+ }
9411
+ }
9412
+ async function runExecFile(file, args, audit, options) {
9413
+ const startedAt = Date.now();
9414
+ const command = [file, ...args].join(" ");
9415
+ const entry = createAuditEntry(audit.actor, audit.source ?? "trie", audit.triggeredBy, audit.targetPath);
9416
+ const cmd = buildCommandRecord(command);
9417
+ entry.commands?.push(cmd);
9418
+ try {
9419
+ const { stdout, stderr } = await execFileAsync(file, args, {
9420
+ cwd: options?.cwd,
9421
+ timeout: options?.timeoutMs,
9422
+ maxBuffer: options?.maxBuffer
9423
+ });
9424
+ await finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), startedAt }, options);
9425
+ return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), exitCode: 0 };
9426
+ } catch (e) {
9427
+ const err = e;
9428
+ const stdout = typeof err.stdout === "string" ? err.stdout : "";
9429
+ const stderr = typeof err.stderr === "string" ? err.stderr : "";
9430
+ const exitCode = typeof err.code === "number" ? err.code : 1;
9431
+ await finalizeAndWrite(
9432
+ entry,
9433
+ cmd,
9434
+ { success: false, exitCode, stdout, stderr, error: err.message, startedAt },
9435
+ { ...options, captureOutput: options?.captureOutput ?? true }
9436
+ );
9437
+ return { stdout, stderr, exitCode };
9438
+ }
9439
+ }
9440
+
9441
+ // src/skills/installer.ts
8906
9442
  var GLOBAL_SKILLS_DIRS = {
8907
- trie: join3(homedir(), ".trie", "skills"),
8908
- cursor: join3(homedir(), ".cursor", "skills"),
8909
- claude: join3(homedir(), ".claude", "skills"),
8910
- opencode: join3(homedir(), ".config", "opencode", "skills")
9443
+ trie: join5(homedir(), ".trie", "skills"),
9444
+ cursor: join5(homedir(), ".cursor", "skills"),
9445
+ claude: join5(homedir(), ".claude", "skills"),
9446
+ opencode: join5(homedir(), ".config", "opencode", "skills")
8911
9447
  };
8912
9448
  var GLOBAL_SKILLS_DIR = GLOBAL_SKILLS_DIRS.trie;
8913
9449
  function getAllGlobalSkillDirs() {
@@ -8941,26 +9477,74 @@ async function installSkill(source, skillName) {
8941
9477
  }
8942
9478
  const { owner, repo, skill: parsedSkill } = parsed;
8943
9479
  const specifiedSkill = skillName || parsedSkill;
8944
- const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
8945
- const tempDir = join3(skillsDir, `.temp-${Date.now()}`);
9480
+ const skillsDir = join5(getWorkingDirectory(void 0, true), ".trie", "skills");
9481
+ const tempDir = join5(skillsDir, `.temp-${Date.now()}`);
8946
9482
  try {
8947
- await mkdir2(skillsDir, { recursive: true });
9483
+ await mkdir3(skillsDir, { recursive: true });
9484
+ console.log("Cloning repository...");
8948
9485
  const repoUrl = `https://github.com/${owner}/${repo}.git`;
8949
- await execAsync(`git clone --depth 1 "${repoUrl}" "${tempDir}"`, { timeout: 6e4 });
9486
+ if (!repoUrl.startsWith("https://github.com/") || repoUrl.includes("..") || repoUrl.includes("~")) {
9487
+ throw new Error("Invalid repository URL");
9488
+ }
9489
+ await runShellCommand(
9490
+ `git clone --depth 1 "${repoUrl}" "${tempDir}"`,
9491
+ { actor: "internal:skills-installer", triggeredBy: "manual", targetPath: getWorkingDirectory(void 0, true) },
9492
+ { timeoutMs: 6e4, captureOutput: false }
9493
+ );
8950
9494
  const sourcePath = await findSkillPath(tempDir, specifiedSkill);
8951
9495
  if (!sourcePath) {
8952
9496
  throw new Error(`SKILL.md not found in repository. Searched in: root, skills/, ${specifiedSkill || "subdirectories"}`);
8953
9497
  }
9498
+ console.log("Running security scan...");
9499
+ const securityScan = await scanSkillForThreats(sourcePath);
9500
+ console.log(`Security scan: ${formatSecuritySummary(securityScan)}`);
9501
+ if (securityScan.risks.length > 0) {
9502
+ console.warn("\n\u26A0\uFE0F SECURITY RISKS DETECTED\n");
9503
+ const criticalRisks = securityScan.risks.filter((r) => r.severity === "critical");
9504
+ const highRisks = securityScan.risks.filter((r) => r.severity === "high");
9505
+ for (const risk of criticalRisks) {
9506
+ console.warn(`\u{1F534} CRITICAL: ${risk.description}`);
9507
+ console.warn(` ${risk.location}: ${risk.pattern}`);
9508
+ console.warn(` \u2192 ${risk.recommendation}
9509
+ `);
9510
+ }
9511
+ for (const risk of highRisks) {
9512
+ console.warn(`\u{1F7E0} HIGH: ${risk.description}`);
9513
+ console.warn(` ${risk.location}`);
9514
+ console.warn(` \u2192 ${risk.recommendation}
9515
+ `);
9516
+ }
9517
+ if (criticalRisks.length > 0) {
9518
+ console.warn("\u26A0\uFE0F This skill has CRITICAL security risks. Use with extreme caution.\n");
9519
+ } else {
9520
+ console.warn("\u26A0\uFE0F Review these risks before using this skill.\n");
9521
+ }
9522
+ }
8954
9523
  const parsed2 = await parseSkillMd(sourcePath);
8955
9524
  const name = parsed2.frontmatter.name;
8956
- const targetPath = join3(skillsDir, name);
9525
+ const targetPath = join5(skillsDir, name);
8957
9526
  await rm(targetPath, { recursive: true, force: true });
8958
9527
  await cp(sourcePath, targetPath, { recursive: true });
8959
- await writeFile2(join3(targetPath, ".installed.json"), JSON.stringify({
9528
+ await writeFile3(join5(targetPath, ".installed.json"), JSON.stringify({
8960
9529
  installedFrom: source,
8961
9530
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
8962
- repository: `${owner}/${repo}`
9531
+ repository: `${owner}/${repo}`,
9532
+ securityScan: {
9533
+ safe: securityScan.safe,
9534
+ riskCount: securityScan.risks.length,
9535
+ criticalRisks: securityScan.risks.filter((r) => r.severity === "critical").length,
9536
+ highRisks: securityScan.risks.filter((r) => r.severity === "high").length,
9537
+ scannedAt: (/* @__PURE__ */ new Date()).toISOString()
9538
+ },
9539
+ risks: securityScan.risks,
9540
+ // Store full risk details
9541
+ permissions: securityScan.requiredPermissions
8963
9542
  }, null, 2));
9543
+ if (securityScan.risks.length > 0) {
9544
+ console.log(`
9545
+ \u26A0\uFE0F View security details with: trie skills info ${name}
9546
+ `);
9547
+ }
8964
9548
  return { success: true, name, path: targetPath };
8965
9549
  } catch (error) {
8966
9550
  const message = error instanceof Error ? error.message : String(error);
@@ -8974,22 +9558,22 @@ async function findSkillPath(repoPath, skillName) {
8974
9558
  const searchPaths = [];
8975
9559
  if (skillName) {
8976
9560
  searchPaths.push(
8977
- join3(repoPath, "skills", skillName),
8978
- join3(repoPath, skillName)
9561
+ join5(repoPath, "skills", skillName),
9562
+ join5(repoPath, skillName)
8979
9563
  );
8980
9564
  }
8981
9565
  searchPaths.push(
8982
9566
  repoPath,
8983
- join3(repoPath, "skill")
9567
+ join5(repoPath, "skill")
8984
9568
  );
8985
9569
  if (!skillName) {
8986
9570
  try {
8987
- const skillsSubdir = join3(repoPath, "skills");
9571
+ const skillsSubdir = join5(repoPath, "skills");
8988
9572
  await access(skillsSubdir);
8989
- const entries = await readdir(skillsSubdir, { withFileTypes: true });
9573
+ const entries = await readdir3(skillsSubdir, { withFileTypes: true });
8990
9574
  for (const entry of entries) {
8991
9575
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
8992
- searchPaths.push(join3(skillsSubdir, entry.name));
9576
+ searchPaths.push(join5(skillsSubdir, entry.name));
8993
9577
  }
8994
9578
  }
8995
9579
  } catch {
@@ -9019,10 +9603,10 @@ async function findClaudeCodeSubagent(repoPath, skillName) {
9019
9603
  skillName.replace(/-expert$/, "-expert.md")
9020
9604
  ];
9021
9605
  for (const fileName of searchNames) {
9022
- const filePath = join3(repoPath, fileName);
9606
+ const filePath = join5(repoPath, fileName);
9023
9607
  try {
9024
9608
  await access(filePath);
9025
- const content = await readFile3(filePath, "utf-8");
9609
+ const content = await readFile5(filePath, "utf-8");
9026
9610
  if (content.startsWith("---")) {
9027
9611
  return await convertClaudeCodeToSkillMd(repoPath, filePath, skillName);
9028
9612
  }
@@ -9030,7 +9614,7 @@ async function findClaudeCodeSubagent(repoPath, skillName) {
9030
9614
  }
9031
9615
  }
9032
9616
  try {
9033
- const entries = await readdir(repoPath);
9617
+ const entries = await readdir3(repoPath);
9034
9618
  const mdFiles = entries.filter((e) => e.endsWith(".md") && !e.toLowerCase().includes("readme") && !e.toLowerCase().includes("license"));
9035
9619
  if (mdFiles.length > 0) {
9036
9620
  const availableSkills = mdFiles.map((f) => f.replace(".md", "")).join(", ");
@@ -9044,7 +9628,7 @@ async function findClaudeCodeSubagent(repoPath, skillName) {
9044
9628
  return null;
9045
9629
  }
9046
9630
  async function convertClaudeCodeToSkillMd(repoPath, filePath, skillName) {
9047
- const content = await readFile3(filePath, "utf-8");
9631
+ const content = await readFile5(filePath, "utf-8");
9048
9632
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
9049
9633
  if (!fmMatch) {
9050
9634
  throw new Error("Invalid frontmatter format");
@@ -9057,8 +9641,8 @@ async function convertClaudeCodeToSkillMd(repoPath, filePath, skillName) {
9057
9641
  const name = nameMatch ? nameMatch[1].trim() : skillName;
9058
9642
  const description = descMatch ? descMatch[1].trim() : `Skill from Claude Code subagent: ${name}`;
9059
9643
  const model = modelMatch ? modelMatch[1].trim() : void 0;
9060
- const tempSkillDir = join3(repoPath, ".converted-skill", name);
9061
- await mkdir2(tempSkillDir, { recursive: true });
9644
+ const tempSkillDir = join5(repoPath, ".converted-skill", name);
9645
+ await mkdir3(tempSkillDir, { recursive: true });
9062
9646
  let newContent = `---
9063
9647
  name: ${name}
9064
9648
  description: ${description}
@@ -9070,23 +9654,23 @@ tags: [claude-code, subagent${model ? `, ${model}` : ""}]
9070
9654
 
9071
9655
  ${body}
9072
9656
  `;
9073
- await writeFile2(join3(tempSkillDir, "SKILL.md"), newContent, "utf-8");
9657
+ await writeFile3(join5(tempSkillDir, "SKILL.md"), newContent, "utf-8");
9074
9658
  return tempSkillDir;
9075
9659
  }
9076
9660
  async function listInstalledSkills() {
9077
- const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
9661
+ const skillsDir = join5(getWorkingDirectory(void 0, true), ".trie", "skills");
9078
9662
  const skills = [];
9079
9663
  try {
9080
- const entries = await readdir(skillsDir, { withFileTypes: true });
9664
+ const entries = await readdir3(skillsDir, { withFileTypes: true });
9081
9665
  for (const entry of entries) {
9082
9666
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9083
- const skillPath = join3(skillsDir, entry.name);
9667
+ const skillPath = join5(skillsDir, entry.name);
9084
9668
  try {
9085
9669
  const parsed = await parseSkillMd(skillPath);
9086
- const metaPath = join3(skillPath, ".installed.json");
9670
+ const metaPath = join5(skillPath, ".installed.json");
9087
9671
  let meta = { installedFrom: "unknown", installedAt: (/* @__PURE__ */ new Date()).toISOString() };
9088
9672
  try {
9089
- meta = JSON.parse(await readFile3(metaPath, "utf-8"));
9673
+ meta = JSON.parse(await readFile5(metaPath, "utf-8"));
9090
9674
  } catch {
9091
9675
  }
9092
9676
  skills.push({
@@ -9104,8 +9688,8 @@ async function listInstalledSkills() {
9104
9688
  return skills;
9105
9689
  }
9106
9690
  async function removeSkill(skillName) {
9107
- const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
9108
- const skillPath = join3(skillsDir, skillName);
9691
+ const skillsDir = join5(getWorkingDirectory(void 0, true), ".trie", "skills");
9692
+ const skillPath = join5(skillsDir, skillName);
9109
9693
  try {
9110
9694
  await rm(skillPath, { recursive: true });
9111
9695
  return true;
@@ -9116,16 +9700,16 @@ async function removeSkill(skillName) {
9116
9700
  async function listGlobalSkills() {
9117
9701
  const skills = [];
9118
9702
  try {
9119
- const entries = await readdir(GLOBAL_SKILLS_DIR, { withFileTypes: true });
9703
+ const entries = await readdir3(GLOBAL_SKILLS_DIR, { withFileTypes: true });
9120
9704
  for (const entry of entries) {
9121
9705
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
9122
- const skillPath = join3(GLOBAL_SKILLS_DIR, entry.name);
9706
+ const skillPath = join5(GLOBAL_SKILLS_DIR, entry.name);
9123
9707
  try {
9124
9708
  const parsed = await parseSkillMd(skillPath);
9125
- const metaPath = join3(skillPath, ".installed.json");
9709
+ const metaPath = join5(skillPath, ".installed.json");
9126
9710
  let meta = { installedFrom: "custom", installedAt: (/* @__PURE__ */ new Date()).toISOString() };
9127
9711
  try {
9128
- meta = JSON.parse(await readFile3(metaPath, "utf-8"));
9712
+ meta = JSON.parse(await readFile5(metaPath, "utf-8"));
9129
9713
  } catch {
9130
9714
  }
9131
9715
  skills.push({
@@ -9147,14 +9731,14 @@ async function writeSkillToAllDirs(name, skillMdContent, metadata) {
9147
9731
  let primaryPath = "";
9148
9732
  for (const [tool, baseDir] of Object.entries(GLOBAL_SKILLS_DIRS)) {
9149
9733
  try {
9150
- await mkdir2(baseDir, { recursive: true });
9151
- const skillPath = join3(baseDir, name);
9734
+ await mkdir3(baseDir, { recursive: true });
9735
+ const skillPath = join5(baseDir, name);
9152
9736
  if (existsSync3(skillPath)) {
9153
9737
  continue;
9154
9738
  }
9155
- await mkdir2(skillPath, { recursive: true });
9156
- await writeFile2(join3(skillPath, "SKILL.md"), skillMdContent, "utf-8");
9157
- await writeFile2(join3(skillPath, ".installed.json"), JSON.stringify(metadata, null, 2));
9739
+ await mkdir3(skillPath, { recursive: true });
9740
+ await writeFile3(join5(skillPath, "SKILL.md"), skillMdContent, "utf-8");
9741
+ await writeFile3(join5(skillPath, ".installed.json"), JSON.stringify(metadata, null, 2));
9158
9742
  writtenTo.push(tool);
9159
9743
  if (tool === "trie") {
9160
9744
  primaryPath = skillPath;
@@ -9165,25 +9749,25 @@ async function writeSkillToAllDirs(name, skillMdContent, metadata) {
9165
9749
  if (!primaryPath && writtenTo.length > 0) {
9166
9750
  const firstTool = writtenTo[0];
9167
9751
  if (firstTool) {
9168
- primaryPath = join3(GLOBAL_SKILLS_DIRS[firstTool], name);
9752
+ primaryPath = join5(GLOBAL_SKILLS_DIRS[firstTool], name);
9169
9753
  }
9170
9754
  }
9171
9755
  return { primaryPath, writtenTo };
9172
9756
  }
9173
9757
  async function createSkillFromFile(filePath, skillName, description) {
9174
9758
  try {
9175
- const stats = await stat(filePath);
9759
+ const stats = await stat2(filePath);
9176
9760
  if (!stats.isFile()) {
9177
9761
  return { success: false, name: "unknown", error: "Path is not a file" };
9178
9762
  }
9179
- const content = await readFile3(filePath, "utf-8");
9763
+ const content = await readFile5(filePath, "utf-8");
9180
9764
  if (!content.trim()) {
9181
9765
  return { success: false, name: "unknown", error: "File is empty" };
9182
9766
  }
9183
9767
  const ext = extname2(filePath);
9184
9768
  const baseFileName = basename2(filePath, ext);
9185
9769
  const name = skillName || baseFileName.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
9186
- const primarySkillPath = join3(GLOBAL_SKILLS_DIR, name);
9770
+ const primarySkillPath = join5(GLOBAL_SKILLS_DIR, name);
9187
9771
  if (existsSync3(primarySkillPath)) {
9188
9772
  return { success: false, name, error: `Skill "${name}" already exists. Use a different name or remove the existing skill.` };
9189
9773
  }
@@ -9223,7 +9807,7 @@ ${content}
9223
9807
  async function removeGlobalSkill(skillName) {
9224
9808
  let removed = false;
9225
9809
  for (const baseDir of getAllGlobalSkillDirs()) {
9226
- const skillPath = join3(baseDir, skillName);
9810
+ const skillPath = join5(baseDir, skillName);
9227
9811
  try {
9228
9812
  if (existsSync3(skillPath)) {
9229
9813
  await rm(skillPath, { recursive: true });
@@ -9236,18 +9820,18 @@ async function removeGlobalSkill(skillName) {
9236
9820
  }
9237
9821
 
9238
9822
  // src/utils/context-state.ts
9239
- import { readFile as readFile4, mkdir as mkdir3 } from "fs/promises";
9823
+ import { readFile as readFile6, mkdir as mkdir4 } from "fs/promises";
9240
9824
  import { existsSync as existsSync4 } from "fs";
9241
- import { join as join4, basename as basename3 } from "path";
9825
+ import { join as join6, basename as basename3 } from "path";
9242
9826
  var AGENTS_MD_PATH = ".trie/AGENTS.md";
9243
9827
  var STATE_JSON_PATH = ".trie/state.json";
9244
9828
  async function loadContextState() {
9245
9829
  const workDir = getWorkingDirectory(void 0, true);
9246
- const statePath = join4(workDir, STATE_JSON_PATH);
9830
+ const statePath = join6(workDir, STATE_JSON_PATH);
9247
9831
  const defaults = getDefaultState();
9248
9832
  try {
9249
9833
  if (existsSync4(statePath)) {
9250
- const content = await readFile4(statePath, "utf-8");
9834
+ const content = await readFile6(statePath, "utf-8");
9251
9835
  const loaded = JSON.parse(content);
9252
9836
  return {
9253
9837
  ...defaults,
@@ -9261,9 +9845,9 @@ async function loadContextState() {
9261
9845
  }
9262
9846
  async function saveContextState(state) {
9263
9847
  const workDir = getWorkingDirectory(void 0, true);
9264
- const trieDir = join4(workDir, ".trie");
9265
- const statePath = join4(workDir, STATE_JSON_PATH);
9266
- await mkdir3(trieDir, { recursive: true });
9848
+ const trieDir = join6(workDir, ".trie");
9849
+ const statePath = join6(workDir, STATE_JSON_PATH);
9850
+ await mkdir4(trieDir, { recursive: true });
9267
9851
  await atomicWriteJSON(statePath, state);
9268
9852
  }
9269
9853
  async function updateContextAfterScan(results, filesScanned, contextSignals, duration) {
@@ -9322,10 +9906,10 @@ async function updateContextAfterScan(results, filesScanned, contextSignals, dur
9322
9906
  }
9323
9907
  async function updateAgentsMd(state) {
9324
9908
  const workDir = getWorkingDirectory(void 0, true);
9325
- const mdPath = join4(workDir, AGENTS_MD_PATH);
9909
+ const mdPath = join6(workDir, AGENTS_MD_PATH);
9326
9910
  let content;
9327
9911
  try {
9328
- content = await readFile4(mdPath, "utf-8");
9912
+ content = await readFile6(mdPath, "utf-8");
9329
9913
  } catch {
9330
9914
  content = getAgentsMdTemplate();
9331
9915
  }
@@ -9658,9 +10242,8 @@ async function getContextForAI() {
9658
10242
 
9659
10243
  // src/skills/gating.ts
9660
10244
  import { existsSync as existsSync5 } from "fs";
9661
- import { readFile as readFile5 } from "fs/promises";
9662
- import { join as join5 } from "path";
9663
- import { execSync } from "child_process";
10245
+ import { readFile as readFile7 } from "fs/promises";
10246
+ import { join as join7 } from "path";
9664
10247
  async function checkSkillRequirements(frontmatter, projectDir) {
9665
10248
  const result = { allowed: true };
9666
10249
  if (frontmatter.requires && frontmatter.requires.length > 0) {
@@ -9716,7 +10299,7 @@ async function checkSkillRequirements(frontmatter, projectDir) {
9716
10299
  }
9717
10300
  }
9718
10301
  if (reqs.configFiles && reqs.configFiles.length > 0) {
9719
- const missing = reqs.configFiles.filter((file) => !existsSync5(join5(projectDir, file)));
10302
+ const missing = reqs.configFiles.filter((file) => !existsSync5(join7(projectDir, file)));
9720
10303
  if (missing.length > 0) {
9721
10304
  result.allowed = false;
9722
10305
  result.missingConfigs = missing;
@@ -9728,11 +10311,11 @@ async function checkSkillRequirements(frontmatter, projectDir) {
9728
10311
  }
9729
10312
  async function getProjectDependencies(projectDir) {
9730
10313
  try {
9731
- const pkgPath = join5(projectDir, "package.json");
10314
+ const pkgPath = join7(projectDir, "package.json");
9732
10315
  if (!existsSync5(pkgPath)) {
9733
10316
  return /* @__PURE__ */ new Set();
9734
10317
  }
9735
- const pkg = JSON.parse(await readFile5(pkgPath, "utf-8"));
10318
+ const pkg = JSON.parse(await readFile7(pkgPath, "utf-8"));
9736
10319
  return /* @__PURE__ */ new Set([
9737
10320
  ...Object.keys(pkg.dependencies || {}),
9738
10321
  ...Object.keys(pkg.devDependencies || {})
@@ -9742,13 +10325,13 @@ async function getProjectDependencies(projectDir) {
9742
10325
  }
9743
10326
  }
9744
10327
  function isBinaryAvailable(binary) {
9745
- try {
9746
- const command = process.platform === "win32" ? `where ${binary}` : `which ${binary}`;
9747
- execSync(command, { stdio: "ignore" });
9748
- return true;
9749
- } catch {
9750
- return false;
9751
- }
10328
+ const command = process.platform === "win32" ? `where ${binary}` : `which ${binary}`;
10329
+ const { exitCode } = runShellCommandSync(
10330
+ command,
10331
+ { actor: "internal:skill-gating", triggeredBy: "scan", targetPath: process.cwd() },
10332
+ { captureOutput: false }
10333
+ );
10334
+ return exitCode === 0;
9752
10335
  }
9753
10336
  function formatGatingReason(result) {
9754
10337
  if (result.allowed) return "Allowed";
@@ -10198,8 +10781,8 @@ var CustomSkill = class extends BaseSkill {
10198
10781
  };
10199
10782
 
10200
10783
  // src/skills/built-in/registry.ts
10201
- import { readdir as readdir2, readFile as readFile6 } from "fs/promises";
10202
- import { join as join6 } from "path";
10784
+ import { readdir as readdir4, readFile as readFile8 } from "fs/promises";
10785
+ import { join as join8 } from "path";
10203
10786
  var SkillRegistryImpl = class {
10204
10787
  skills = /* @__PURE__ */ new Map();
10205
10788
  customSkillsLoaded = false;
@@ -10255,14 +10838,14 @@ var SkillRegistryImpl = class {
10255
10838
  async loadCustomSkills() {
10256
10839
  if (this.customSkillsLoaded) return;
10257
10840
  try {
10258
- const skillsDir = join6(getWorkingDirectory(void 0, true), ".trie", "agents");
10259
- const files = await readdir2(skillsDir);
10841
+ const skillsDir = join8(getWorkingDirectory(void 0, true), ".trie", "agents");
10842
+ const files = await readdir4(skillsDir);
10260
10843
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
10261
10844
  let loadedCount = 0;
10262
10845
  for (const file of jsonFiles) {
10263
10846
  try {
10264
- const configPath = join6(skillsDir, file);
10265
- const content = await readFile6(configPath, "utf-8");
10847
+ const configPath = join8(skillsDir, file);
10848
+ const content = await readFile8(configPath, "utf-8");
10266
10849
  const config = JSON.parse(content);
10267
10850
  const skill = new CustomSkill(config);
10268
10851
  this.skills.set(skill.name, skill);
@@ -10430,6 +11013,13 @@ function getSkillRegistry() {
10430
11013
  export {
10431
11014
  SuperReviewerSkill,
10432
11015
  CRITICAL_REVIEW_CHECKLIST,
11016
+ getRecentAuditLogs,
11017
+ getSkillAuditLogs,
11018
+ getAuditStatistics,
11019
+ formatAuditLog,
11020
+ runShellCommand,
11021
+ runShellCommandSync,
11022
+ runExecFile,
10433
11023
  installSkill,
10434
11024
  listInstalledSkills,
10435
11025
  removeSkill,
@@ -10451,4 +11041,4 @@ export {
10451
11041
  CustomSkill,
10452
11042
  getSkillRegistry
10453
11043
  };
10454
- //# sourceMappingURL=chunk-3RKY55HZ.js.map
11044
+ //# sourceMappingURL=chunk-LKXDJESG.js.map