@cocaxcode/ai-context-inspector 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -229,8 +229,8 @@ async function introspectServers(servers, timeout) {
229
229
  }
230
230
 
231
231
  // src/scanner/index.ts
232
- import { readFile as readFile4 } from "fs/promises";
233
- import { join as join5, basename } from "path";
232
+ import { readFile as readFile6 } from "fs/promises";
233
+ import { join as join6, basename as basename2 } from "path";
234
234
  import { resolve } from "path";
235
235
 
236
236
  // src/scanner/context-files.ts
@@ -381,6 +381,50 @@ var AI_FILE_CATALOG = [
381
381
  scope: "project",
382
382
  description: "Directorio de configuraci\xF3n de Codex"
383
383
  },
384
+ // ── OpenCode ──
385
+ {
386
+ path: "OPENCODE.md",
387
+ tool: "opencode",
388
+ type: "file",
389
+ scope: "project",
390
+ description: "Instrucciones de proyecto para OpenCode CLI"
391
+ },
392
+ {
393
+ path: ".opencode",
394
+ tool: "opencode",
395
+ type: "directory",
396
+ scope: "project",
397
+ description: "Directorio de configuraci\xF3n de OpenCode"
398
+ },
399
+ {
400
+ path: "opencode.json",
401
+ tool: "opencode",
402
+ type: "file",
403
+ scope: "project",
404
+ description: "Configuraci\xF3n de OpenCode"
405
+ },
406
+ // ── Roo Code (ex-Cline fork) ──
407
+ {
408
+ path: ".roo/rules",
409
+ tool: "roo",
410
+ type: "directory",
411
+ scope: "project",
412
+ description: "Directorio de reglas de Roo Code"
413
+ },
414
+ {
415
+ path: ".roorules",
416
+ tool: "roo",
417
+ type: "file",
418
+ scope: "project",
419
+ description: "Reglas de Roo Code (archivo \xFAnico)"
420
+ },
421
+ {
422
+ path: ".rooignore",
423
+ tool: "roo",
424
+ type: "file",
425
+ scope: "project",
426
+ description: "Archivos excluidos de Roo Code"
427
+ },
384
428
  // ── Aider ──
385
429
  {
386
430
  path: ".aider.conf.yml",
@@ -487,6 +531,37 @@ var AI_FILE_CATALOG = [
487
531
  scope: "project",
488
532
  description: "Convenciones de c\xF3digo (multi-tool)"
489
533
  },
534
+ // ── Tabnine ──
535
+ {
536
+ path: ".tabnine.yaml",
537
+ tool: "tabnine",
538
+ type: "file",
539
+ scope: "project",
540
+ description: "Configuraci\xF3n de Tabnine AI"
541
+ },
542
+ // ── Sourcegraph / Cody ──
543
+ {
544
+ path: ".sourcegraph",
545
+ tool: "sourcegraph",
546
+ type: "directory",
547
+ scope: "project",
548
+ description: "Directorio de Sourcegraph Cody"
549
+ },
550
+ // ── Continue.dev (project level) ──
551
+ {
552
+ path: ".continuerules",
553
+ tool: "continue",
554
+ type: "file",
555
+ scope: "project",
556
+ description: "Reglas de Continue.dev"
557
+ },
558
+ {
559
+ path: ".continue/config.yaml",
560
+ tool: "continue",
561
+ type: "file",
562
+ scope: "project",
563
+ description: "Configuraci\xF3n de Continue.dev"
564
+ },
490
565
  // ── User-level entries ──
491
566
  {
492
567
  path: "~/.claude",
@@ -564,11 +639,25 @@ var AI_FILE_CATALOG = [
564
639
  type: "directory",
565
640
  scope: "user",
566
641
  description: "Configuraci\xF3n global de Codeium/Windsurf"
642
+ },
643
+ {
644
+ path: "~/.opencode",
645
+ tool: "opencode",
646
+ type: "directory",
647
+ scope: "user",
648
+ description: "Configuraci\xF3n global de OpenCode CLI"
649
+ },
650
+ {
651
+ path: "~/.tabnine",
652
+ tool: "tabnine",
653
+ type: "directory",
654
+ scope: "user",
655
+ description: "Configuraci\xF3n global de Tabnine"
567
656
  }
568
657
  ];
569
658
 
570
659
  // src/scanner/context-files.ts
571
- var PREVIEW_MAX_CHARS = 500;
660
+ var PREVIEW_MAX_CHARS = 2e3;
572
661
  function resolveHome(p) {
573
662
  return p.startsWith("~/") ? join2(homedir2(), p.slice(2)) : p;
574
663
  }
@@ -674,28 +763,67 @@ async function scanContextFiles(config) {
674
763
  }
675
764
 
676
765
  // src/scanner/skills.ts
677
- import { readFile as readFile3, readdir as readdir2, stat as stat2 } from "fs/promises";
766
+ import { readFile as readFile3, readdir as readdir2, stat as stat2, lstat } from "fs/promises";
678
767
  import { join as join3 } from "path";
679
768
  import { homedir as homedir3 } from "os";
680
769
  var SKILL_DIRS_PROJECT = [".claude/skills"];
681
770
  var SKILL_DIRS_USER = ["~/.claude/skills"];
771
+ function parseFrontmatter(content) {
772
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
773
+ if (!match) return null;
774
+ const result = {};
775
+ let currentKey = "";
776
+ let currentValue = "";
777
+ for (const line of match[1].split("\n")) {
778
+ const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)$/);
779
+ if (kvMatch) {
780
+ if (currentKey) result[currentKey] = currentValue.trim();
781
+ currentKey = kvMatch[1];
782
+ currentValue = kvMatch[2].replace(/^["'>-]\s*/, "").replace(/"$/, "");
783
+ } else if (currentKey && line.match(/^\s+/)) {
784
+ currentValue += " " + line.trim();
785
+ }
786
+ }
787
+ if (currentKey) result[currentKey] = currentValue.trim();
788
+ return result;
789
+ }
682
790
  async function scanSkillDir(dirPath, scope) {
683
791
  const skills = [];
684
792
  try {
685
793
  const entries = await readdir2(dirPath, { withFileTypes: true });
686
794
  for (const entry of entries) {
687
- if (!entry.isDirectory()) continue;
688
- if (entry.name.startsWith("_") || entry.name.startsWith("sdd-")) continue;
689
- const skillMdPath = join3(dirPath, entry.name, "SKILL.md");
795
+ if (entry.name.startsWith("_")) continue;
796
+ const entryPath = join3(dirPath, entry.name);
797
+ let isDir = entry.isDirectory();
798
+ if (entry.isSymbolicLink()) {
799
+ try {
800
+ const targetStat = await stat2(entryPath);
801
+ isDir = targetStat.isDirectory();
802
+ } catch {
803
+ continue;
804
+ }
805
+ }
806
+ if (!isDir) continue;
807
+ const skillMdPath = join3(entryPath, "SKILL.md");
690
808
  try {
691
809
  await stat2(skillMdPath);
692
810
  const content = await readFile3(skillMdPath, "utf-8");
693
811
  let description;
694
- const purposeMatch = content.match(/##\s*Purpose\s*\n+(.+)/i);
695
- if (purposeMatch) {
696
- description = purposeMatch[1].trim().slice(0, 200);
697
- }
812
+ let name = entry.name;
698
813
  const triggers = [];
814
+ const frontmatter = parseFrontmatter(content);
815
+ if (frontmatter) {
816
+ if (frontmatter.name) name = frontmatter.name;
817
+ if (frontmatter.description) {
818
+ description = frontmatter.description.slice(0, 200);
819
+ }
820
+ }
821
+ if (!description) {
822
+ const purposeMatch = content.match(/##\s*Purpose\s*\n+(.+)/i);
823
+ if (purposeMatch) {
824
+ description = purposeMatch[1].trim().slice(0, 200);
825
+ }
826
+ }
699
827
  const triggerMatch = content.match(
700
828
  /(?:trigger|triggers?):\s*(.+)/gi
701
829
  );
@@ -705,12 +833,19 @@ async function scanSkillDir(dirPath, scope) {
705
833
  if (value) triggers.push(value);
706
834
  }
707
835
  }
836
+ let isSymlink = false;
837
+ try {
838
+ const lstats = await lstat(entryPath);
839
+ isSymlink = lstats.isSymbolicLink();
840
+ } catch {
841
+ }
708
842
  skills.push({
709
- name: entry.name,
843
+ name,
710
844
  path: skillMdPath,
711
845
  scope,
712
846
  description,
713
- triggers: triggers.length > 0 ? triggers : void 0
847
+ triggers: triggers.length > 0 ? triggers : void 0,
848
+ isSymlink
714
849
  });
715
850
  } catch {
716
851
  }
@@ -776,25 +911,119 @@ async function scanSkills(config) {
776
911
  return { skills: allSkills, warnings };
777
912
  }
778
913
 
779
- // src/scanner/memories.ts
780
- import { readdir as readdir3, stat as stat3 } from "fs/promises";
914
+ // src/scanner/agents.ts
915
+ import { readFile as readFile4, readdir as readdir3, stat as stat3 } from "fs/promises";
781
916
  import { join as join4 } from "path";
917
+ import { homedir as homedir4 } from "os";
918
+ var AGENT_DIRS_PROJECT = [".claude/agents"];
919
+ var AGENT_DIRS_USER = ["~/.claude/agents"];
920
+ var AGENT_MEMORY_DIRS_USER = ["~/.claude/agent-memory"];
921
+ function parseFrontmatter2(content) {
922
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
923
+ if (!match) return null;
924
+ const result = {};
925
+ let currentKey = "";
926
+ let currentValue = "";
927
+ for (const line of match[1].split("\n")) {
928
+ const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)$/);
929
+ if (kvMatch) {
930
+ if (currentKey) result[currentKey] = currentValue.trim();
931
+ currentKey = kvMatch[1];
932
+ currentValue = kvMatch[2].replace(/^["'>-]\s*/, "").replace(/"$/, "");
933
+ } else if (currentKey && line.match(/^\s+/)) {
934
+ currentValue += " " + line.trim();
935
+ }
936
+ }
937
+ if (currentKey) result[currentKey] = currentValue.trim();
938
+ return result;
939
+ }
940
+ async function scanAgentDir(dirPath, memoryDirPath, scope) {
941
+ const agents = [];
942
+ try {
943
+ const entries = await readdir3(dirPath);
944
+ for (const entry of entries) {
945
+ if (!entry.endsWith(".md")) continue;
946
+ const filePath = join4(dirPath, entry);
947
+ try {
948
+ const s = await stat3(filePath);
949
+ if (!s.isFile()) continue;
950
+ const content = await readFile4(filePath, "utf-8");
951
+ const agentName = entry.replace(/\.md$/, "");
952
+ let name = agentName;
953
+ let description;
954
+ let model;
955
+ const frontmatter = parseFrontmatter2(content);
956
+ if (frontmatter) {
957
+ if (frontmatter.name) name = frontmatter.name;
958
+ if (frontmatter.description) {
959
+ description = frontmatter.description.slice(0, 300);
960
+ }
961
+ if (frontmatter.model) model = frontmatter.model;
962
+ }
963
+ let hasMemory = false;
964
+ if (memoryDirPath) {
965
+ try {
966
+ await stat3(join4(memoryDirPath, agentName));
967
+ hasMemory = true;
968
+ } catch {
969
+ }
970
+ }
971
+ agents.push({
972
+ name,
973
+ path: filePath,
974
+ scope,
975
+ description,
976
+ model,
977
+ hasMemory
978
+ });
979
+ } catch {
980
+ }
981
+ }
982
+ } catch {
983
+ }
984
+ return agents;
985
+ }
986
+ async function scanAgents(config) {
987
+ const allAgents = [];
988
+ const warnings = [];
989
+ for (const dir of AGENT_DIRS_PROJECT) {
990
+ const fullPath = join4(config.dir, dir);
991
+ const found = await scanAgentDir(fullPath, null, "project");
992
+ allAgents.push(...found);
993
+ }
994
+ if (config.includeUser) {
995
+ for (let i = 0; i < AGENT_DIRS_USER.length; i++) {
996
+ const dir = AGENT_DIRS_USER[i];
997
+ const memDir = AGENT_MEMORY_DIRS_USER[i];
998
+ const fullPath = dir.startsWith("~/") ? join4(homedir4(), dir.slice(2)) : dir;
999
+ const memPath = memDir?.startsWith("~/") ? join4(homedir4(), memDir.slice(2)) : memDir ?? null;
1000
+ const found = await scanAgentDir(fullPath, memPath, "user");
1001
+ allAgents.push(...found);
1002
+ }
1003
+ }
1004
+ return { agents: allAgents, warnings };
1005
+ }
1006
+
1007
+ // src/scanner/memories.ts
1008
+ import { readFile as readFile5, readdir as readdir4, stat as stat4 } from "fs/promises";
1009
+ import { join as join5, basename } from "path";
1010
+ import { homedir as homedir5 } from "os";
782
1011
  async function detectOpenspec(dir) {
783
- const openspecDir = join4(dir, "openspec");
1012
+ const openspecDir = join5(dir, "openspec");
784
1013
  try {
785
- const s = await stat3(openspecDir);
1014
+ const s = await stat4(openspecDir);
786
1015
  if (!s.isDirectory()) return null;
787
1016
  let specsCount = 0;
788
1017
  let changesCount = 0;
789
1018
  try {
790
- const specsDir = join4(openspecDir, "specs");
791
- const specs = await readdir3(specsDir);
1019
+ const specsDir = join5(openspecDir, "specs");
1020
+ const specs = await readdir4(specsDir);
792
1021
  specsCount = specs.filter((f) => !f.startsWith(".")).length;
793
1022
  } catch {
794
1023
  }
795
1024
  try {
796
- const changesDir = join4(openspecDir, "changes");
797
- const changes = await readdir3(changesDir);
1025
+ const changesDir = join5(openspecDir, "changes");
1026
+ const changes = await readdir4(changesDir);
798
1027
  changesCount = changes.filter(
799
1028
  (f) => !f.startsWith(".") && f !== "archive"
800
1029
  ).length;
@@ -812,13 +1041,13 @@ async function detectOpenspec(dir) {
812
1041
  }
813
1042
  }
814
1043
  async function detectAtl(dir) {
815
- const atlDir = join4(dir, ".atl");
1044
+ const atlDir = join5(dir, ".atl");
816
1045
  try {
817
- const s = await stat3(atlDir);
1046
+ const s = await stat4(atlDir);
818
1047
  if (!s.isDirectory()) return null;
819
1048
  let files = [];
820
1049
  try {
821
- files = await readdir3(atlDir);
1050
+ files = await readdir4(atlDir);
822
1051
  } catch {
823
1052
  }
824
1053
  return {
@@ -832,7 +1061,7 @@ async function detectAtl(dir) {
832
1061
  return null;
833
1062
  }
834
1063
  }
835
- function detectEngram(mcpServers) {
1064
+ function detectEngramMcp(mcpServers) {
836
1065
  const engram = mcpServers.find(
837
1066
  (s) => s.name.toLowerCase().includes("engram") || s.config.command && s.config.command.includes("engram") || s.config.args && s.config.args.some((a) => a.toLowerCase().includes("engram"))
838
1067
  );
@@ -844,6 +1073,99 @@ function detectEngram(mcpServers) {
844
1073
  details: { server: engram.name }
845
1074
  };
846
1075
  }
1076
+ async function detectEngramPlugin() {
1077
+ try {
1078
+ const settingsPath = join5(homedir5(), ".claude", "settings.json");
1079
+ const content = await readFile5(settingsPath, "utf-8");
1080
+ const settings = JSON.parse(content);
1081
+ if (!settings.enabledPlugins) return null;
1082
+ const engramKey = Object.keys(settings.enabledPlugins).find(
1083
+ (k) => k.toLowerCase().includes("engram") && settings.enabledPlugins[k]
1084
+ );
1085
+ if (!engramKey) return null;
1086
+ return {
1087
+ type: "engram",
1088
+ source: "plugin",
1089
+ status: "active",
1090
+ details: { plugin: engramKey }
1091
+ };
1092
+ } catch {
1093
+ return null;
1094
+ }
1095
+ }
1096
+ async function detectClaudeMemories(_dir) {
1097
+ const memories = [];
1098
+ const projectsDir = join5(homedir5(), ".claude", "projects");
1099
+ try {
1100
+ const entries = await readdir4(projectsDir);
1101
+ for (const entry of entries) {
1102
+ const memoryPath = join5(projectsDir, entry, "memory", "MEMORY.md");
1103
+ try {
1104
+ const s = await stat4(memoryPath);
1105
+ if (!s.isFile()) continue;
1106
+ const content = await readFile5(memoryPath, "utf-8");
1107
+ const previewLength = Math.min(content.length, 300);
1108
+ const preview = content.slice(0, previewLength);
1109
+ const projectName = entry.replace(/--/g, "/").replace(/-/g, "/");
1110
+ memories.push({
1111
+ type: "claude-memory",
1112
+ path: memoryPath,
1113
+ source: "filesystem",
1114
+ status: "active",
1115
+ details: {
1116
+ project: projectName,
1117
+ size: s.size,
1118
+ preview
1119
+ }
1120
+ });
1121
+ } catch {
1122
+ }
1123
+ }
1124
+ } catch {
1125
+ }
1126
+ return memories;
1127
+ }
1128
+ async function detectAgentMemories() {
1129
+ const memories = [];
1130
+ const agentMemDir = join5(homedir5(), ".claude", "agent-memory");
1131
+ try {
1132
+ const entries = await readdir4(agentMemDir, { withFileTypes: true });
1133
+ for (const entry of entries) {
1134
+ if (entry.isDirectory()) {
1135
+ const memDir = join5(agentMemDir, entry.name);
1136
+ try {
1137
+ const files = await readdir4(memDir);
1138
+ const mdFiles = files.filter((f) => f.endsWith(".md"));
1139
+ if (mdFiles.length > 0) {
1140
+ memories.push({
1141
+ type: "agent-memory",
1142
+ path: memDir,
1143
+ source: "filesystem",
1144
+ status: "active",
1145
+ details: {
1146
+ agent: entry.name,
1147
+ files: mdFiles.length
1148
+ }
1149
+ });
1150
+ }
1151
+ } catch {
1152
+ }
1153
+ } else if (entry.name.endsWith(".md")) {
1154
+ memories.push({
1155
+ type: "agent-memory",
1156
+ path: join5(agentMemDir, entry.name),
1157
+ source: "filesystem",
1158
+ status: "active",
1159
+ details: {
1160
+ agent: basename(entry.name, ".md")
1161
+ }
1162
+ });
1163
+ }
1164
+ }
1165
+ } catch {
1166
+ }
1167
+ return memories;
1168
+ }
847
1169
  async function scanMemories(config, mcpServers) {
848
1170
  const memories = [];
849
1171
  const warnings = [];
@@ -851,20 +1173,31 @@ async function scanMemories(config, mcpServers) {
851
1173
  if (openspec) memories.push(openspec);
852
1174
  const atl = await detectAtl(config.dir);
853
1175
  if (atl) memories.push(atl);
854
- const engram = detectEngram(mcpServers);
855
- if (engram) memories.push(engram);
1176
+ const engramMcp = detectEngramMcp(mcpServers);
1177
+ if (engramMcp) {
1178
+ memories.push(engramMcp);
1179
+ } else if (config.includeUser) {
1180
+ const engramPlugin = await detectEngramPlugin();
1181
+ if (engramPlugin) memories.push(engramPlugin);
1182
+ }
1183
+ if (config.includeUser) {
1184
+ const claudeMemories = await detectClaudeMemories(config.dir);
1185
+ memories.push(...claudeMemories);
1186
+ const agentMemories = await detectAgentMemories();
1187
+ memories.push(...agentMemories);
1188
+ }
856
1189
  return { memories, warnings };
857
1190
  }
858
1191
 
859
1192
  // src/scanner/index.ts
860
1193
  async function detectProjectName(dir) {
861
1194
  try {
862
- const pkg = await readFile4(join5(dir, "package.json"), "utf-8");
1195
+ const pkg = await readFile6(join6(dir, "package.json"), "utf-8");
863
1196
  const parsed = JSON.parse(pkg);
864
1197
  if (parsed.name) return parsed.name;
865
1198
  } catch {
866
1199
  }
867
- return basename(dir);
1200
+ return basename2(dir);
868
1201
  }
869
1202
  async function runAllScanners(config) {
870
1203
  const start = performance.now();
@@ -876,14 +1209,16 @@ async function runAllScanners(config) {
876
1209
  path: absDir,
877
1210
  scannedAt: (/* @__PURE__ */ new Date()).toISOString()
878
1211
  };
879
- const [contextResult, mcpResult, skillsResult] = await Promise.all([
1212
+ const [contextResult, mcpResult, skillsResult, agentsResult] = await Promise.all([
880
1213
  scanContextFiles({ ...config, dir: absDir }),
881
1214
  scanMcpConfigs({ dir: absDir, includeUser: config.includeUser }),
882
- scanSkills({ ...config, dir: absDir })
1215
+ scanSkills({ ...config, dir: absDir }),
1216
+ scanAgents({ ...config, dir: absDir })
883
1217
  ]);
884
1218
  warnings.push(...contextResult.warnings);
885
1219
  warnings.push(...mcpResult.warnings);
886
1220
  warnings.push(...skillsResult.warnings);
1221
+ warnings.push(...agentsResult.warnings);
887
1222
  if (config.introspect && mcpResult.servers.length > 0) {
888
1223
  await introspectServers(mcpResult.servers, config.timeout);
889
1224
  }
@@ -898,6 +1233,7 @@ async function runAllScanners(config) {
898
1233
  contextFiles: contextResult.files,
899
1234
  mcpServers: mcpResult.servers,
900
1235
  skills: skillsResult.skills,
1236
+ agents: agentsResult.agents,
901
1237
  memories: memoriesResult.memories,
902
1238
  warnings,
903
1239
  scanDuration
@@ -1000,6 +1336,7 @@ body {
1000
1336
  .badge--green { border-color: var(--green); color: var(--green); }
1001
1337
  .badge--purple { border-color: var(--purple); color: var(--purple); }
1002
1338
  .badge--orange { border-color: var(--orange); color: var(--orange); }
1339
+ .badge--blue { border-color: #4285f4; color: #4285f4; }
1003
1340
 
1004
1341
  /* \u2500\u2500 Search \u2500\u2500 */
1005
1342
  .search-bar {
@@ -1139,6 +1476,10 @@ body {
1139
1476
  .tool-badge--augment { background: #9c27b020; color: #9c27b0; border: 1px solid #9c27b040; }
1140
1477
  .tool-badge--replit { background: #f2620020; color: #f26200; border: 1px solid #f2620040; }
1141
1478
  .tool-badge--firebase { background: #ffca2820; color: #ffca28; border: 1px solid #ffca2840; }
1479
+ .tool-badge--opencode { background: #22c55e20; color: #22c55e; border: 1px solid #22c55e40; }
1480
+ .tool-badge--roo { background: #06b6d420; color: #06b6d4; border: 1px solid #06b6d440; }
1481
+ .tool-badge--tabnine { background: #e8596820; color: #e85968; border: 1px solid #e8596840; }
1482
+ .tool-badge--sourcegraph { background: #a112ff20; color: #a112ff; border: 1px solid #a112ff40; }
1142
1483
  .tool-badge--vscode { background: #007acc20; color: #007acc; border: 1px solid #007acc40; }
1143
1484
  .tool-badge--universal { background: #78909c20; color: #78909c; border: 1px solid #78909c40; }
1144
1485
 
@@ -1340,6 +1681,7 @@ function renderHeader(project, summary, scanDuration) {
1340
1681
  <span class="badge badge--green">${summary.totalTools} tools</span>
1341
1682
  <span class="badge badge--purple">${summary.totalFiles} archivos</span>
1342
1683
  <span class="badge badge--orange">${summary.totalSkills} skills</span>
1684
+ <span class="badge badge--blue">${summary.totalAgents} agents</span>
1343
1685
  <span class="badge badge--accent">${summary.totalMemories} memorias</span>
1344
1686
  </div>
1345
1687
  </header>`;
@@ -1469,6 +1811,34 @@ function renderSkills(skills) {
1469
1811
  <div class="section-content">${items}</div>
1470
1812
  </div>`;
1471
1813
  }
1814
+ function renderAgents(agents) {
1815
+ if (agents.length === 0) return "";
1816
+ const items = agents.map((a) => {
1817
+ const modelHtml = a.model ? `<span class="badge badge--green">${esc(a.model)}</span>` : "";
1818
+ const memoryHtml = a.hasMemory ? '<span class="badge badge--accent">memoria</span>' : "";
1819
+ return `
1820
+ <div class="card" data-searchable="${esc(a.name + " " + (a.description ?? ""))}">
1821
+ <div class="card-title">
1822
+ ${esc(a.name)}
1823
+ ${modelHtml}
1824
+ ${memoryHtml}
1825
+ <span class="scope-badge scope-badge--${a.scope}">${a.scope}</span>
1826
+ </div>
1827
+ ${a.description ? `<div class="card-meta">${esc(a.description)}</div>` : ""}
1828
+ </div>`;
1829
+ }).join("");
1830
+ return `
1831
+ <div class="section">
1832
+ <div class="section-header">
1833
+ <h2>Agents</h2>
1834
+ <div>
1835
+ <span class="count">${agents.length}</span>
1836
+ <span class="arrow">&#9660;</span>
1837
+ </div>
1838
+ </div>
1839
+ <div class="section-content">${items}</div>
1840
+ </div>`;
1841
+ }
1472
1842
  function renderMemories(memories) {
1473
1843
  if (memories.length === 0) return "";
1474
1844
  const items = memories.map((m) => {
@@ -1517,17 +1887,19 @@ function computeSummary(result) {
1517
1887
  ),
1518
1888
  totalFiles: result.contextFiles.length,
1519
1889
  totalSkills: result.skills.length,
1890
+ totalAgents: result.agents.length,
1520
1891
  totalMemories: result.memories.length
1521
1892
  };
1522
1893
  }
1523
1894
  function generateHtml(result) {
1524
1895
  const summary = computeSummary(result);
1525
- const isEmpty = summary.totalMcpServers === 0 && summary.totalFiles === 0 && summary.totalSkills === 0 && summary.totalMemories === 0;
1896
+ const isEmpty = summary.totalMcpServers === 0 && summary.totalFiles === 0 && summary.totalSkills === 0 && summary.totalAgents === 0 && summary.totalMemories === 0;
1526
1897
  const header = renderHeader(result.project, summary, result.scanDuration);
1527
1898
  const content = isEmpty ? renderEmptyState() : [
1528
1899
  renderMcpServers(result.mcpServers),
1529
1900
  renderContextFiles(result.contextFiles),
1530
1901
  renderSkills(result.skills),
1902
+ renderAgents(result.agents),
1531
1903
  renderMemories(result.memories)
1532
1904
  ].join("");
1533
1905
  return `<!DOCTYPE html>
@@ -1542,7 +1914,7 @@ function generateHtml(result) {
1542
1914
  <div class="container">
1543
1915
  ${header}
1544
1916
  <div class="search-bar">
1545
- <input type="text" id="search-input" placeholder="Buscar tools, archivos, skills..." />
1917
+ <input type="text" id="search-input" placeholder="Buscar tools, archivos, skills, agents..." />
1546
1918
  </div>
1547
1919
  ${content}
1548
1920
  <footer class="footer">
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  generateHtml,
4
4
  runAllScanners
5
- } from "./chunk-6HBCUZQJ.js";
5
+ } from "./chunk-UFTX3Z5M.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { parseArgs } from "util";
@@ -97,7 +97,7 @@ async function main() {
97
97
  const options = parseCliArgs(process.argv.slice(2));
98
98
  if (options.mcp) {
99
99
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
100
- const { createServer } = await import("./server-6EILEUO5.js");
100
+ const { createServer } = await import("./server-AOHGLJDI.js");
101
101
  const server = createServer();
102
102
  const transport = new StdioServerTransport();
103
103
  await server.connect(transport);
@@ -4,7 +4,7 @@ import {
4
4
  introspectServers,
5
5
  runAllScanners,
6
6
  scanMcpConfigs
7
- } from "./chunk-6HBCUZQJ.js";
7
+ } from "./chunk-UFTX3Z5M.js";
8
8
 
9
9
  // src/server.ts
10
10
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocaxcode/ai-context-inspector",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Scan any project to discover its complete AI ecosystem: MCP servers, tools, context files, skills, memories. Generates an interactive HTML dashboard. Works as CLI and MCP server.",
5
5
  "type": "module",
6
6
  "bin": {