Skip to content
Merged
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
10ca803
chore(code-intel): QA re-review NOG-3 + entity-registry updates [Epic…
Pedrovaleriolopez Feb 21, 2026
8334b4c
feat(code-intel): QA gate enhancement with blast radius + coverage [S…
Pedrovaleriolopez Feb 21, 2026
dcd3e1f
feat(code-intel): planning helper for brownfield & PRD workflows [Sto…
Pedrovaleriolopez Feb 21, 2026
ef40334
feat(code-intel): story creation awareness with duplicate detection […
Pedrovaleriolopez Feb 21, 2026
d216d22
fix(cli): correct aios info paths and YAML parse errors (#173, #104)
Pedrovaleriolopez Feb 21, 2026
f8a4662
feat(code-intel): devops pre-push impact analysis and PR enrichment […
Pedrovaleriolopez Feb 21, 2026
10cb3b3
feat(code-intel): squad creator codebase awareness and integration pa…
Pedrovaleriolopez Feb 21, 2026
356e71a
chore: sync pending changes (synapse, installer, pro-cli, story updat…
Pedrovaleriolopez Feb 21, 2026
82debb2
feat(graph-dashboard): CLI Graph Dashboard MVP — PRD, architecture, s…
Pedrovaleriolopez Feb 21, 2026
62295a3
test(graph-dashboard): QA review pass — resolve coverage observations…
Pedrovaleriolopez Feb 21, 2026
cefdf97
fix(updater): use correct package name aios-core instead of @synkra/a…
Pedrovaleriolopez Feb 21, 2026
0384ddf
feat(graph-dashboard): entity stats and cache metrics ASCII view [Sto…
Pedrovaleriolopez Feb 21, 2026
a979d81
fix: rename @synkra/aios-core to aios-core across entire codebase (#159)
Pedrovaleriolopez Feb 21, 2026
9af3d9e
fix(docs): remove non-existent email references, redirect to GitHub I…
Pedrovaleriolopez Feb 21, 2026
db88179
feat(graph-dashboard): provider status and output formats [Story GD-3]
Pedrovaleriolopez Feb 21, 2026
858d1fd
fix(ide-sync): implement GitHub Copilot custom agents format (#138)
Pedrovaleriolopez Feb 21, 2026
1b73e84
docs(graph-dashboard): research + stories GD-4/5/6 for dynamic visual…
Pedrovaleriolopez Feb 21, 2026
d5c0cf3
feat(devops): add GitHub issues triage and resolve tasks
Pedrovaleriolopez Feb 21, 2026
fd396d9
feat(graph-dashboard): live DOT watch mode with QA pass [Story GD-4]
Pedrovaleriolopez Feb 21, 2026
c11791c
feat(github): implement issue management system [Story GHIM-001]
Pedrovaleriolopez Feb 21, 2026
dece053
feat(code-intel): UAP & SYNAPSE deep research + Wave 6 stories [Story…
Pedrovaleriolopez Feb 21, 2026
7e89ecd
feat(code-intel): add Wave 6 performance journey log system
Pedrovaleriolopez Feb 21, 2026
0266bc5
feat(code-intel): safe quick wins — session wiring, token estimation,…
Pedrovaleriolopez Feb 21, 2026
f0a1f78
feat(graph-dashboard): HTML web viewer with vis-network, QA pass [Sto…
Pedrovaleriolopez Feb 21, 2026
d76b4bb
docs(research): graph taxonomy, filtering & query capabilities
Pedrovaleriolopez Feb 21, 2026
5fdddb5
docs(code-intel): close Story NOG-10 — Phase 0A Safe Quick Wins [Done]
Pedrovaleriolopez Feb 21, 2026
b2f7ebb
docs(code-intel): NOG-11 token usage source discovery — research comp…
Pedrovaleriolopez Feb 21, 2026
3581eaa
feat(graph-dashboard): improve code-intel source, HTML formatter, and…
Pedrovaleriolopez Feb 21, 2026
0f19f77
feat(code-intel): NOG-15 tests + QA PASS, NOG-16A/B/C stories, regist…
Pedrovaleriolopez Feb 21, 2026
184850a
feat(synapse): atomic writes + session cleanup wiring [Story NOG-12]
Pedrovaleriolopez Feb 21, 2026
29f0e64
feat(doctor): git fsmonitor detection + opt-in suggestion [Story NOG-13]
Pedrovaleriolopez Feb 22, 2026
182dc85
chore(registry): regenerate entity-registry after QA concern fixes [S…
Pedrovaleriolopez Feb 22, 2026
73b58c3
feat(code-intel): dependency classification and entity lifecycle [Sto…
Pedrovaleriolopez Feb 22, 2026
b8d64d8
docs(architecture): ADR memory self-editing security model [Story NOG…
Pedrovaleriolopez Feb 22, 2026
9b1d008
feat(code-intel): graph filtering, focus mode, and lifecycle styling …
Pedrovaleriolopez Feb 22, 2026
9c4a460
chore: sync pending changes (synapse, installer, pro-cli, story updat…
Pedrovaleriolopez Feb 22, 2026
5ccf5da
feat(code-intel): E2E pipeline audit with QA pass [Story NOG-17]
Pedrovaleriolopez Feb 22, 2026
692db85
feat(graph-dashboard): tooltip redesign and physics control panel [St…
Pedrovaleriolopez Feb 22, 2026
724a964
chore: sync graph dashboard stories, research, and pending changes
Pedrovaleriolopez Feb 22, 2026
23b18b1
docs(code-intel): NOG-18 story + native-first research [Story NOG-18]
Pedrovaleriolopez Feb 22, 2026
ee678cb
feat(graph-dashboard): multi-level depth expansion with BFS neighborh…
Pedrovaleriolopez Feb 22, 2026
bb24c53
feat(graph-dashboard): node sizing by degree centrality and layout sw…
Pedrovaleriolopez Feb 22, 2026
d4aa0a5
feat(code-intel): SYNAPSE native-first migration — UAP streamlined, L…
Pedrovaleriolopez Feb 22, 2026
540befd
feat(graph-dashboard): export PNG/JSON and minimap navigation overvie…
Pedrovaleriolopez Feb 22, 2026
6d1c16e
feat(graph-dashboard): category clustering and statistics panel [Stor…
Pedrovaleriolopez Feb 22, 2026
ac4b97d
docs(code-intel): pipeline audit validation — benchmarks and QA gate …
Pedrovaleriolopez Feb 22, 2026
b7e4d18
feat(code-intel): agent frontmatter validation — hooks, skills, memor…
Pedrovaleriolopez Feb 22, 2026
54397f7
feat(boundary): permission deny rules and toggleable framework protec…
Pedrovaleriolopez Feb 22, 2026
3d7a8e2
refactor(code-intel): native greeting migration — replace UAP/Greetin…
Pedrovaleriolopez Feb 22, 2026
f0b1662
docs(boundary): close story BM-2 — CLAUDE.md boundary section [Story …
Pedrovaleriolopez Feb 22, 2026
372cbbd
feat(boundary): pre-commit framework guard with dynamic config [Story…
Pedrovaleriolopez Feb 22, 2026
6259058
docs(code-intel): QA review NOG-22 — expand checklist-runner to all 8…
Pedrovaleriolopez Feb 22, 2026
d3e3d35
feat(boundary): config schema enrichment and template customization s…
Pedrovaleriolopez Feb 22, 2026
b1d5651
docs(code-intel): close stories NOG-8, NOG-17→NOG-22 — epic 25/25 com…
Pedrovaleriolopez Feb 22, 2026
8b3daac
docs(code-intel): post-migration validation & benchmark — QA PASS 100…
Pedrovaleriolopez Feb 22, 2026
2dc19be
chore: sync boundary-mapping stories, agent configs, rules and utilities
Pedrovaleriolopez Feb 22, 2026
ee1f2f1
feat(boundary): entity registry layer classification L1-L4 [Story BM-5]
Pedrovaleriolopez Feb 22, 2026
1f02fee
feat(boundary): agent memory lifecycle and CLAUDE.md ownership annota…
Pedrovaleriolopez Feb 23, 2026
31cd46f
chore: force-track gitignored .claude files for worktree compatibility
Pedrovaleriolopez Feb 23, 2026
8ef32fe
feat(token-opt): unified tool registry — 34 tools, 10 profiles, 5 bin…
Pedrovaleriolopez Feb 23, 2026
962199e
docs(token-opt): baseline metrics & full epic token-optimization setu…
Pedrovaleriolopez Feb 23, 2026
337213d
feat(doctor): rewrite aios doctor with 12 modular checks, --fix, --js…
Pedrovaleriolopez Feb 23, 2026
1daf8d8
feat(token-opt): capability-aware deferred loading with 3-level fallb…
Pedrovaleriolopez Feb 23, 2026
4a8d9f9
feat(boundary): deterministic settings.json generator from core-confi…
Pedrovaleriolopez Feb 23, 2026
f41977c
docs(installation-health): close INS-4.2, approve INS-4.3 with valida…
Pedrovaleriolopez Feb 23, 2026
8c92b01
feat(installer): full artifact copy pipeline — skills, commands, hook…
Pedrovaleriolopez Feb 23, 2026
bbf3b23
feat(token-opt): PTC batch templates, execution_mode schema, 21-task …
Pedrovaleriolopez Feb 23, 2026
853b719
feat(installer): CLAUDE.md template v5 — 4 new AIOS-MANAGED sections …
Pedrovaleriolopez Feb 23, 2026
7c5d200
feat(token-opt): agent handoff context compaction — 65% reduction in …
Pedrovaleriolopez Feb 23, 2026
374788f
feat(installer): IDE sync integration via adapter pattern after artif…
Pedrovaleriolopez Feb 23, 2026
3c721d2
feat(token-opt): input examples registry + client-layer injection for…
Pedrovaleriolopez Feb 23, 2026
5513df9
feat(publish): publish safety gate — submodule + file count validatio…
Pedrovaleriolopez Feb 23, 2026
1777ee8
feat(installer): entity registry bootstrap on install [Story INS-4.6]
Pedrovaleriolopez Feb 23, 2026
d02df25
feat(token-opt): tool usage analytics pipeline with promote/demote en…
Pedrovaleriolopez Feb 23, 2026
8af115a
feat(token-opt): dynamic filtering engine with 3 filter types and SYN…
Pedrovaleriolopez Feb 23, 2026
12aa5c7
feat(installer): YAML merger strategy + config smart merge Phase 1 [S…
Pedrovaleriolopez Feb 23, 2026
891b14f
docs(token-opt): close TOK-6 and mark Epic Token Optimization complet…
Pedrovaleriolopez Feb 23, 2026
40e54d5
feat(doctor): unify health-check task + 3 new checks (skills, command…
Pedrovaleriolopez Feb 23, 2026
1152f37
docs(stories): create story CODEINTEL-RP-001 — Code-Intel RegistryPro…
Pedrovaleriolopez Feb 24, 2026
4eac54d
docs(epic): close INS-4.8 and mark Epic INS-4 Installation Health com…
Pedrovaleriolopez Feb 24, 2026
0ecbf5e
fix(doctor): update orchestrator tests from 12 to 15 checks [Story IN…
Pedrovaleriolopez Feb 24, 2026
a220f87
feat(devops): wire *health-check command and task dependency [Story I…
Pedrovaleriolopez Feb 24, 2026
f21dfe2
chore(release): bump version to 4.3.0
Pedrovaleriolopez Feb 24, 2026
1176c89
Merge remote-tracking branch 'origin/main' into feat/epic-nogic-code-…
Pedrovaleriolopez Feb 24, 2026
3b61af1
fix: resolve CI failures — lint errors and test drift from NOG-18 merge
Pedrovaleriolopez Feb 24, 2026
f115d28
chore: regenerate manifest and sync IDE command files for CI
Pedrovaleriolopez Feb 24, 2026
cff9be3
chore: update entity-registry and regenerate manifest for CI parity
Pedrovaleriolopez Feb 24, 2026
c4bece5
chore: sync IDE command files for all IDEs (devops health-check)
Pedrovaleriolopez Feb 24, 2026
1c22492
chore: add review-contributor-pr task, sync github-copilot agent, reg…
Pedrovaleriolopez Feb 24, 2026
19a6690
feat(code-intel): implement RegistryProvider — native T1 code intelli…
Pedrovaleriolopez Feb 24, 2026
9533dec
docs(code-intel): update architecture flowcharts and rewrite doctor c…
Pedrovaleriolopez Feb 24, 2026
ab10cae
fix(installer): v4.3.0 post-release installer fixes and open-source a…
Pedrovaleriolopez Feb 24, 2026
1470b57
Merge remote-tracking branch 'origin/main' into feat/epic-nogic-code-…
Pedrovaleriolopez Feb 24, 2026
ac62c2b
chore: regenerate manifest after merge with main
Pedrovaleriolopez Feb 24, 2026
b2eaa63
fix(manifest): regenerate install-manifest from clean git state
Pedrovaleriolopez Feb 24, 2026
71ee0c6
feat(workflow): workflow-aware greeting suggestions & task handoff me…
Pedrovaleriolopez Feb 24, 2026
780dbff
fix(manifest): remove untracked workflow-chains.yaml from manifest
Pedrovaleriolopez Feb 24, 2026
121df5d
fix(manifest): regenerate from clean HEAD state (include workflow-cha…
Pedrovaleriolopez Feb 24, 2026
704c513
fix: address CodeRabbit review issues (9 Major findings)
Pedrovaleriolopez Feb 24, 2026
ef94e75
chore(manifest): regenerate after IDS hook entity-registry sync
Pedrovaleriolopez Feb 24, 2026
39b9242
chore: sync corrected agent IDE files (npm run sync:ide)
Pedrovaleriolopez Feb 24, 2026
5a3c346
fix: address remaining CodeRabbit Major issues (round 2)
Pedrovaleriolopez Feb 24, 2026
58db535
chore(manifest): regenerate after IDS hook sync
Pedrovaleriolopez Feb 24, 2026
946f3a5
fix(agents): resolve CodeRabbit round 3 — grammar, STEP 4 duplication…
Pedrovaleriolopez Feb 24, 2026
aa15bfe
fix(manifest): regenerate without transient healing backup file
Pedrovaleriolopez Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .aios-core/core/code-intel/code-intel-client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const { CodeGraphProvider } = require('./providers/code-graph-provider');
const { RegistryProvider } = require('./providers/registry-provider');

// --- Constants (adjustable, not hardcoded magic numbers) ---
const CIRCUIT_BREAKER_THRESHOLD = 3;
Expand Down Expand Up @@ -51,10 +52,19 @@ class CodeIntelClient {

/**
* Register default providers based on configuration.
* Provider priority: RegistryProvider FIRST (native, T1), then CodeGraphProvider (MCP, T3).
* First provider with isAvailable() === true wins.
* @private
*/
_registerDefaultProviders(options) {
// Code Graph MCP is the primary (and currently only) provider
// RegistryProvider — native, T1, always available when registry exists
const registryProvider = new RegistryProvider({
registryPath: options.registryPath || null,
projectRoot: options.projectRoot || null,
});
this._providers.push(registryProvider);

// Code Graph MCP — T3, available when mcpCallFn is configured
const codeGraphProvider = new CodeGraphProvider({
mcpServerName: options.mcpServerName || 'code-graph',
mcpCallFn: options.mcpCallFn || null,
Expand All @@ -74,15 +84,15 @@ class CodeIntelClient {

/**
* Detect and return the first available provider.
* Uses polymorphic isAvailable() — first provider that returns true wins.
* @returns {import('./providers/provider-interface').CodeIntelProvider|null}
* @private
*/
_detectProvider() {
if (this._activeProvider) return this._activeProvider;

for (const provider of this._providers) {
// A provider is considered "available" if it has a configured mcpCallFn
if (provider.options && typeof provider.options.mcpCallFn === 'function') {
if (typeof provider.isAvailable === 'function' && provider.isAvailable()) {
this._activeProvider = provider;
return provider;
}
Expand Down
177 changes: 177 additions & 0 deletions .aios-core/core/code-intel/hook-runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
'use strict';

const path = require('path');
const { RegistryProvider } = require('./providers/registry-provider');

/** Cached provider instance (survives across hook invocations in same process). */
let _provider = null;

/**
* Get or create a RegistryProvider singleton.
* @param {string} projectRoot - Project root directory
* @returns {RegistryProvider}
*/
function getProvider(projectRoot) {
if (!_provider) {
_provider = new RegistryProvider({ projectRoot });
}
return _provider;
}
Comment on lines 16 to 22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Singleton ignores projectRoot after first initialization.

getProvider caches the first RegistryProvider instance and returns it for all subsequent calls regardless of the projectRoot argument. If this module is ever called with different project roots within the same process (e.g., a multi-workspace scenario), the second call silently uses the wrong project's registry.

🔧 Suggested fix: key the cache by projectRoot
-/** Cached provider instance (survives across hook invocations in same process). */
-let _provider = null;
+/** Cached provider instances keyed by projectRoot. */
+const _providers = new Map();

 function getProvider(projectRoot) {
-  if (!_provider) {
-    _provider = new RegistryProvider({ projectRoot });
-  }
-  return _provider;
+  const key = projectRoot || '';
+  if (!_providers.has(key)) {
+    _providers.set(key, new RegistryProvider({ projectRoot }));
+  }
+  return _providers.get(key);
 }

 function _resetForTesting() {
-  _provider = null;
+  _providers.clear();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aios-core/core/code-intel/hook-runtime.js around lines 14 - 19, getProvider
currently stores a single _provider and ignores later projectRoot args, so
change the cache to be keyed by projectRoot (e.g., use a Map or object) and
return the RegistryProvider instance for the requested projectRoot; update
references to _provider to use a per-root cache (lookup by projectRoot,
instantiate new RegistryProvider({ projectRoot }) when missing) so
getProvider(projectRoot) always returns the provider for that root while
preserving the RegistryProvider construction and return behavior.


/**
* Resolve code intelligence context for a file being written/edited.
*
* Queries RegistryProvider for:
* - Entity definition (path, layer, purpose, type)
* - References (files that use this entity)
* - Dependencies (entities this file depends on)
*
* @param {string} filePath - Absolute or relative path to the target file
* @param {string} cwd - Project root / working directory
* @returns {{ entity: Object|null, references: Array|null, dependencies: Object|null }|null}
*/
async function resolveCodeIntel(filePath, cwd) {
if (!filePath || !cwd) return null;

const provider = getProvider(cwd);
if (!provider.isAvailable()) return null;

// Normalize to relative path (registry uses relative paths)
let relativePath = filePath;
if (path.isAbsolute(filePath)) {
relativePath = path.relative(cwd, filePath).replace(/\\/g, '/');
} else {
relativePath = filePath.replace(/\\/g, '/');
}

// Run all three queries in parallel
const [definition, references, dependencies] = await Promise.all([
provider.findDefinition(relativePath),
provider.findReferences(relativePath),
provider.analyzeDependencies(relativePath),
]);

// Treat empty dependency graph as no data
const hasUsefulDeps = dependencies && dependencies.nodes && dependencies.nodes.length > 0;

// If nothing found at all, try searching by the file basename
if (!definition && !references && !hasUsefulDeps) {
const basename = path.basename(relativePath, path.extname(relativePath));
const fallbackDef = await provider.findDefinition(basename);
if (!fallbackDef) return null;

const [fallbackRefs, fallbackDeps] = await Promise.all([
provider.findReferences(basename),
provider.analyzeDependencies(basename),
]);

return {
entity: fallbackDef,
references: fallbackRefs,
dependencies: fallbackDeps,
};
}

return {
entity: definition,
references,
dependencies,
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard provider calls to avoid unhandled rejections.

Promise.all will reject if any provider method throws; without a try/catch this can bubble into hook runtime callers. Wrap the body to return null with a warning on error.

🛡️ Suggested fix
 async function resolveCodeIntel(filePath, cwd) {
   if (!filePath || !cwd) return null;

-  const provider = getProvider(cwd);
-  if (!provider.isAvailable()) return null;
-
-  // Normalize to relative path (registry uses relative paths)
-  let relativePath = filePath;
-  if (path.isAbsolute(filePath)) {
-    relativePath = path.relative(cwd, filePath).replace(/\\/g, '/');
-  } else {
-    relativePath = filePath.replace(/\\/g, '/');
-  }
-
-  // Run all three queries in parallel
-  const [definition, references, dependencies] = await Promise.all([
-    provider.findDefinition(relativePath),
-    provider.findReferences(relativePath),
-    provider.analyzeDependencies(relativePath),
-  ]);
-
-  // Treat empty dependency graph as no data
-  const hasUsefulDeps = dependencies && dependencies.nodes && dependencies.nodes.length > 0;
-
-  // If nothing found at all, try searching by the file basename
-  if (!definition && !references && !hasUsefulDeps) {
-    const basename = path.basename(relativePath, path.extname(relativePath));
-    const fallbackDef = await provider.findDefinition(basename);
-    if (!fallbackDef) return null;
-
-    const [fallbackRefs, fallbackDeps] = await Promise.all([
-      provider.findReferences(basename),
-      provider.analyzeDependencies(basename),
-    ]);
-
-    return {
-      entity: fallbackDef,
-      references: fallbackRefs,
-      dependencies: fallbackDeps,
-    };
-  }
-
-  return {
-    entity: definition,
-    references,
-    dependencies,
-  };
+  try {
+    const provider = getProvider(cwd);
+    if (!provider.isAvailable()) return null;
+
+    // Normalize to relative path (registry uses relative paths)
+    let relativePath = filePath;
+    if (path.isAbsolute(filePath)) {
+      relativePath = path.relative(cwd, filePath).replace(/\\/g, '/');
+    } else {
+      relativePath = filePath.replace(/\\/g, '/');
+    }
+
+    // Run all three queries in parallel
+    const [definition, references, dependencies] = await Promise.all([
+      provider.findDefinition(relativePath),
+      provider.findReferences(relativePath),
+      provider.analyzeDependencies(relativePath),
+    ]);
+
+    // Treat empty dependency graph as no data
+    const hasUsefulDeps = dependencies && dependencies.nodes && dependencies.nodes.length > 0;
+
+    // If nothing found at all, try searching by the file basename
+    if (!definition && !references && !hasUsefulDeps) {
+      const basename = path.basename(relativePath, path.extname(relativePath));
+      const fallbackDef = await provider.findDefinition(basename);
+      if (!fallbackDef) return null;
+
+      const [fallbackRefs, fallbackDeps] = await Promise.all([
+        provider.findReferences(basename),
+        provider.analyzeDependencies(basename),
+      ]);
+
+      return {
+        entity: fallbackDef,
+        references: fallbackRefs,
+        dependencies: fallbackDeps,
+      };
+    }
+
+    return {
+      entity: definition,
+      references,
+      dependencies,
+    };
+  } catch (error) {
+    console.warn(`[code-intel:hook-runtime] resolveCodeIntel failed: ${error.message}`);
+    return null;
+  }
 }

As per coding guidelines, ".aios-core/core/**: Verify error handling is comprehensive with proper try/catch and error context. Validate async/await patterns and ensure no unhandled promise rejections."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aios-core/core/code-intel/hook-runtime.js around lines 33 - 79, The
provider calls in resolveCodeIntel (including getProvider(cwd),
provider.isAvailable(), and the three async methods provider.findDefinition,
provider.findReferences, provider.analyzeDependencies, plus the fallback
provider calls) must be wrapped in a try/catch so any thrown/rejected promise is
caught; update resolveCodeIntel to run those provider interactions inside a
single try block and on any error call the module logger (e.g.,
processLogger.warn or console.warn) with a concise message including the error
and then return null to avoid bubbling unhandled rejections. Ensure you
reference resolveCodeIntel and the provider methods (provider.findDefinition,
provider.findReferences, provider.analyzeDependencies) when locating where to
add the try/catch and the fallback block.

}

/**
* Format code intelligence data as XML for injection into Claude context.
*
* @param {Object|null} intel - Result from resolveCodeIntel()
* @param {string} filePath - Target file path (for display)
* @returns {string|null} XML string or null if no data
*/
function formatAsXml(intel, filePath) {
if (!intel) return null;

const { entity, references, dependencies } = intel;

// At least one piece of data must exist
if (!entity && !references && !dependencies) return null;

const lines = ['<code-intel-context>'];
lines.push(` <target-file>${escapeXml(filePath)}</target-file>`);

// Entity definition
if (entity) {
lines.push(' <existing-entity>');
if (entity.file) lines.push(` <path>${escapeXml(entity.file)}</path>`);
if (entity.context) lines.push(` <purpose>${escapeXml(entity.context)}</purpose>`);
lines.push(' </existing-entity>');
}

// References
if (references && references.length > 0) {
// Deduplicate by file path
const uniqueRefs = [];
const seen = new Set();
for (const ref of references) {
if (ref.file && !seen.has(ref.file)) {
seen.add(ref.file);
uniqueRefs.push(ref);
}
}

lines.push(` <referenced-by count="${uniqueRefs.length}">`);
for (const ref of uniqueRefs.slice(0, 15)) {
const ctx = ref.context ? ` context="${escapeXml(ref.context)}"` : '';
lines.push(` <ref file="${escapeXml(ref.file)}"${ctx} />`);
}
if (uniqueRefs.length > 15) {
lines.push(` <!-- ...and ${uniqueRefs.length - 15} more -->`);
}
lines.push(' </referenced-by>');
}

// Dependencies
if (dependencies && dependencies.nodes && dependencies.nodes.length > 1) {
// First node is the target itself, rest are dependencies
const depNodes = dependencies.nodes.slice(1);
lines.push(` <dependencies count="${depNodes.length}">`);
for (const dep of depNodes.slice(0, 10)) {
const layer = dep.layer ? ` layer="${dep.layer}"` : '';
lines.push(` <dep name="${escapeXml(dep.name)}"${layer} />`);
}
if (depNodes.length > 10) {
lines.push(` <!-- ...and ${depNodes.length - 10} more -->`);
}
lines.push(' </dependencies>');
}

lines.push('</code-intel-context>');
return lines.join('\n');
}

/**
* Escape special XML characters.
* @param {string} str
* @returns {string}
*/
function escapeXml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}

/**
* Reset cached provider (for testing).
*/
function _resetForTesting() {
_provider = null;
}

module.exports = {
resolveCodeIntel,
formatAsXml,
escapeXml,
getProvider,
_resetForTesting,
};
2 changes: 2 additions & 0 deletions .aios-core/core/code-intel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { CodeIntelClient } = require('./code-intel-client');
const { CodeIntelEnricher } = require('./code-intel-enricher');
const { CodeIntelProvider, CAPABILITIES } = require('./providers/provider-interface');
const { CodeGraphProvider, TOOL_MAP } = require('./providers/code-graph-provider');
const { RegistryProvider } = require('./providers/registry-provider');

// Singleton client instance (lazily initialized)
let _defaultClient = null;
Expand Down Expand Up @@ -127,6 +128,7 @@ module.exports = {
CodeIntelEnricher,
CodeIntelProvider,
CodeGraphProvider,
RegistryProvider,

// Constants
CAPABILITIES,
Expand Down
8 changes: 8 additions & 0 deletions .aios-core/core/code-intel/providers/code-graph-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ class CodeGraphProvider extends CodeIntelProvider {
this._mcpServerName = options.mcpServerName || 'code-graph';
}

/**
* Code Graph provider is available when mcpCallFn is configured.
* @returns {boolean}
*/
isAvailable() {
return typeof this.options.mcpCallFn === 'function';
}

/**
* Execute an MCP tool call via the configured server.
* This method is the single point of MCP communication — all capabilities route through here.
Expand Down
9 changes: 9 additions & 0 deletions .aios-core/core/code-intel/providers/provider-interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ class CodeIntelProvider {
this.options = options;
}

/**
* Check if this provider is available and can serve requests.
* Subclasses MUST override this to indicate availability.
* @returns {boolean}
*/
isAvailable() {
return false;
}
Comment on lines +17 to +24
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all CodeIntelProvider subclasses
echo "=== Finding all classes extending CodeIntelProvider ==="
rg -n "extends CodeIntelProvider" -g '*.js'

echo -e "\n=== Finding all isAvailable() implementations ==="
rg -n "isAvailable\s*\(" -g '*.js' .aios-core/core/code-intel/providers/

echo -e "\n=== Check provider-interface.js file to understand the base class ==="
head -40 .aios-core/core/code-intel/providers/provider-interface.js

Repository: SynkraAI/aios-core

Length of output: 1737


🏁 Script executed:

#!/bin/bash
# List all files in the providers directory
echo "=== All files in providers directory ==="
find .aios-core/core/code-intel/providers -type f -name '*.js' | sort

echo -e "\n=== Check each provider for class definition and isAvailable ==="
for file in $(find .aios-core/core/code-intel/providers -type f -name '*.js' | grep -v test); do
  echo "--- $file ---"
  grep -n "^class\|isAvailable" "$file" | head -5
done

echo -e "\n=== Search for all imports of CodeIntelProvider to find subclasses ==="
rg -B2 "extends CodeIntelProvider" -g '*.js' --type js

echo -e "\n=== Check how providers are exported and used ==="
cat .aios-core/core/code-intel/providers/index.js 2>/dev/null || echo "No index.js found"

Repository: SynkraAI/aios-core

Length of output: 1083


🏁 Script executed:

#!/bin/bash
# Find where isAvailable() is being called/used
echo "=== Where isAvailable() is being called ==="
rg "isAvailable\(\)" -B2 -A2 -g '*.js' | grep -v ".test.js" | head -50

echo -e "\n=== Check the code-intel registry or selection logic ==="
fd -t f -name '*registry*' .aios-core/core/code-intel/ -o -name '*select*' .aios-core/core/code-intel/

echo -e "\n=== Look for provider selection/filtering logic ==="
rg "provider.*isAvailable|isAvailable.*provider" -B3 -A3 -g '*.js' | head -60

Repository: SynkraAI/aios-core

Length of output: 5339


🏁 Script executed:

#!/bin/bash
# Search for any selection or orchestration logic
echo "=== Search for provider selection logic ==="
rg "provider" -g '*.js' .aios-core/core/code-intel/ -B2 -A2 | grep -i "select\|choose\|filter\|available" | head -30

echo -e "\n=== Look in code-intel index or orchestration files ==="
find .aios-core/core/code-intel -type f -name '*.js' | grep -v test | xargs wc -l | sort -rn | head -10

echo -e "\n=== Check the code-intel module structure ==="
ls -la .aios-core/core/code-intel/

echo -e "\n=== Look for any references to 'isAvailable' in all production code ==="
rg "\.isAvailable" -g '*.js' .aios-core/core/ | grep -v test

Repository: SynkraAI/aios-core

Length of output: 4266


🏁 Script executed:

#!/bin/bash
# Get the full context of the selection flow in code-intel-client.js
echo "=== code-intel-client.js - getAvailableProvider method ==="
rg -B5 -A10 "First provider with isAvailable" .aios-core/core/code-intel/code-intel-client.js

echo -e "\n=== hook-runtime.js - where isAvailable is called ==="
rg -B5 -A5 "if (!provider.isAvailable())" .aios-core/core/code-intel/hook-runtime.js

echo -e "\n=== Check how providers are instantiated and registered ==="
head -100 .aios-core/core/code-intel/code-intel-client.js | tail -80

Repository: SynkraAI/aios-core

Length of output: 3234


🏁 Script executed:

#!/bin/bash
# Check the full _detectProvider method and fallback behavior
echo "=== Full _detectProvider method ==="
rg -A20 "_detectProvider\(\)" .aios-core/core/code-intel/code-intel-client.js

echo -e "\n=== Check what happens when no provider available ==="
rg -B3 -A3 "No provider available" .aios-core/core/code-intel/code-intel-client.js

Repository: SynkraAI/aios-core

Length of output: 1925


Confirm all providers override isAvailable() or add a compatibility layer.

All existing providers (RegistryProvider, CodeGraphProvider) properly implement isAvailable(), and the selection flow in code-intel-client.js includes a defensive check before calling it. However, the concern about external providers that haven't overridden isAvailable() remains valid—they would inherit the base class's false and be silently skipped. Consider either: (a) documenting the requirement more prominently (already noted in code but worth reinforcing), or (b) implementing a compatibility shim that treats missing/base implementations as "unknown" with a deprecation warning rather than auto-disabling them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aios-core/core/code-intel/providers/provider-interface.js around lines 17 -
24, The base ProviderInterface.isAvailable currently returns false and silently
disables providers that don't override it; change ProviderInterface.isAvailable
to detect an un-overridden call (e.g., this.isAvailable ===
ProviderInterface.prototype.isAvailable), emit a deprecation/compatibility
warning via the project's logger or console.warn mentioning
ProviderInterface/isAvailable, and return a non-failing value (e.g., true or a
sentinel that the selection flow in code-intel-client.js can treat as "unknown")
so external providers aren't silently skipped; update any consumer in
code-intel-client.js to handle that sentinel if you choose a non-boolean return.


/**
* Locate the definition of a symbol.
* @param {string} symbol - Symbol name to find
Expand Down
Loading
Loading