aios-core 4.3.0 → 4.4.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.
Files changed (54) hide show
  1. package/.aios-core/core/code-intel/code-intel-client.js +19 -5
  2. package/.aios-core/core/code-intel/hook-runtime.js +186 -0
  3. package/.aios-core/core/code-intel/index.js +2 -0
  4. package/.aios-core/core/code-intel/providers/code-graph-provider.js +8 -0
  5. package/.aios-core/core/code-intel/providers/provider-interface.js +9 -0
  6. package/.aios-core/core/code-intel/providers/registry-provider.js +515 -0
  7. package/.aios-core/core/doctor/checks/code-intel.js +95 -21
  8. package/.aios-core/core/doctor/checks/hooks-claude-count.js +15 -4
  9. package/.aios-core/core/doctor/checks/ide-sync.js +24 -7
  10. package/.aios-core/core/synapse/memory/memory-bridge.js +17 -43
  11. package/.aios-core/core/synapse/memory/synapse-memory-provider.js +201 -0
  12. package/.aios-core/data/entity-registry.yaml +836 -812
  13. package/.aios-core/data/workflow-chains.yaml +156 -0
  14. package/.aios-core/development/agents/aios-master.md +17 -10
  15. package/.aios-core/development/agents/analyst.md +17 -10
  16. package/.aios-core/development/agents/architect.md +17 -10
  17. package/.aios-core/development/agents/data-engineer.md +17 -10
  18. package/.aios-core/development/agents/dev.md +17 -10
  19. package/.aios-core/development/agents/devops.md +22 -10
  20. package/.aios-core/development/agents/pm.md +17 -10
  21. package/.aios-core/development/agents/po.md +17 -10
  22. package/.aios-core/development/agents/qa.md +17 -10
  23. package/.aios-core/development/agents/sm.md +17 -10
  24. package/.aios-core/development/agents/squad-creator.md +18 -9
  25. package/.aios-core/development/agents/ux-design-expert.md +16 -9
  26. package/.aios-core/development/tasks/apply-qa-fixes.md +7 -0
  27. package/.aios-core/development/tasks/architect-analyze-impact.md +8 -1
  28. package/.aios-core/development/tasks/brownfield-create-story.md +7 -0
  29. package/.aios-core/development/tasks/build-autonomous.md +7 -0
  30. package/.aios-core/development/tasks/create-deep-research-prompt.md +7 -0
  31. package/.aios-core/development/tasks/create-next-story.md +7 -0
  32. package/.aios-core/development/tasks/create-suite.md +7 -0
  33. package/.aios-core/development/tasks/dev-develop-story.md +8 -0
  34. package/.aios-core/development/tasks/execute-checklist.md +7 -0
  35. package/.aios-core/development/tasks/github-devops-github-pr-automation.md +7 -0
  36. package/.aios-core/development/tasks/github-devops-pre-push-quality-gate.md +7 -0
  37. package/.aios-core/development/tasks/po-close-story.md +7 -0
  38. package/.aios-core/development/tasks/qa-create-fix-request.md +7 -0
  39. package/.aios-core/development/tasks/qa-fix-issues.md +7 -0
  40. package/.aios-core/development/tasks/qa-gate.md +8 -0
  41. package/.aios-core/development/tasks/qa-review-story.md +8 -0
  42. package/.aios-core/development/tasks/release-management.md +7 -0
  43. package/.aios-core/development/tasks/spec-critique.md +8 -0
  44. package/.aios-core/development/tasks/spec-gather-requirements.md +7 -0
  45. package/.aios-core/development/tasks/spec-write-spec.md +5 -0
  46. package/.aios-core/development/tasks/validate-next-story.md +7 -0
  47. package/.aios-core/install-manifest.yaml +105 -89
  48. package/.aios-core/product/templates/ide-rules/claude-rules.md +48 -0
  49. package/package.json +1 -1
  50. package/packages/installer/src/config/templates/core-config-template.js +25 -0
  51. package/packages/installer/src/wizard/ide-config-generator.js +24 -3
  52. package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +15 -5
  53. package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +3 -3
  54. package/packages/installer/tests/unit/doctor/doctor-checks.test.js +68 -9
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { CodeGraphProvider } = require('./providers/code-graph-provider');
4
+ const { RegistryProvider } = require('./providers/registry-provider');
4
5
 
5
6
  // --- Constants (adjustable, not hardcoded magic numbers) ---
6
7
  const CIRCUIT_BREAKER_THRESHOLD = 3;
@@ -51,10 +52,19 @@ class CodeIntelClient {
51
52
 
52
53
  /**
53
54
  * Register default providers based on configuration.
55
+ * Provider priority: RegistryProvider FIRST (native, T1), then CodeGraphProvider (MCP, T3).
56
+ * First provider with isAvailable() === true wins.
54
57
  * @private
55
58
  */
56
59
  _registerDefaultProviders(options) {
57
- // Code Graph MCP is the primary (and currently only) provider
60
+ // RegistryProvider native, T1, always available when registry exists
61
+ const registryProvider = new RegistryProvider({
62
+ registryPath: options.registryPath || null,
63
+ projectRoot: options.projectRoot || null,
64
+ });
65
+ this._providers.push(registryProvider);
66
+
67
+ // Code Graph MCP — T3, available when mcpCallFn is configured
58
68
  const codeGraphProvider = new CodeGraphProvider({
59
69
  mcpServerName: options.mcpServerName || 'code-graph',
60
70
  mcpCallFn: options.mcpCallFn || null,
@@ -74,6 +84,7 @@ class CodeIntelClient {
74
84
 
75
85
  /**
76
86
  * Detect and return the first available provider.
87
+ * Uses polymorphic isAvailable() — first provider that returns true wins.
77
88
  * @returns {import('./providers/provider-interface').CodeIntelProvider|null}
78
89
  * @private
79
90
  */
@@ -81,10 +92,13 @@ class CodeIntelClient {
81
92
  if (this._activeProvider) return this._activeProvider;
82
93
 
83
94
  for (const provider of this._providers) {
84
- // A provider is considered "available" if it has a configured mcpCallFn
85
- if (provider.options && typeof provider.options.mcpCallFn === 'function') {
86
- this._activeProvider = provider;
87
- return provider;
95
+ try {
96
+ if (typeof provider.isAvailable === 'function' && provider.isAvailable()) {
97
+ this._activeProvider = provider;
98
+ return provider;
99
+ }
100
+ } catch (_err) {
101
+ // Provider threw during availability check — treat as unavailable
88
102
  }
89
103
  }
90
104
 
@@ -0,0 +1,186 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { RegistryProvider } = require('./providers/registry-provider');
5
+
6
+ /** Cached provider instance (survives across hook invocations in same process). */
7
+ let _provider = null;
8
+ let _providerRoot = null;
9
+
10
+ /**
11
+ * Get or create a RegistryProvider singleton.
12
+ * Resets if projectRoot changes between calls.
13
+ * @param {string} projectRoot - Project root directory
14
+ * @returns {RegistryProvider}
15
+ */
16
+ function getProvider(projectRoot) {
17
+ if (!_provider || _providerRoot !== projectRoot) {
18
+ _provider = new RegistryProvider({ projectRoot });
19
+ _providerRoot = projectRoot;
20
+ }
21
+ return _provider;
22
+ }
23
+
24
+ /**
25
+ * Resolve code intelligence context for a file being written/edited.
26
+ *
27
+ * Queries RegistryProvider for:
28
+ * - Entity definition (path, layer, purpose, type)
29
+ * - References (files that use this entity)
30
+ * - Dependencies (entities this file depends on)
31
+ *
32
+ * @param {string} filePath - Absolute or relative path to the target file
33
+ * @param {string} cwd - Project root / working directory
34
+ * @returns {{ entity: Object|null, references: Array|null, dependencies: Object|null }|null}
35
+ */
36
+ async function resolveCodeIntel(filePath, cwd) {
37
+ if (!filePath || !cwd) return null;
38
+
39
+ try {
40
+ const provider = getProvider(cwd);
41
+ if (!provider.isAvailable()) return null;
42
+
43
+ // Normalize to relative path (registry uses relative paths)
44
+ let relativePath = filePath;
45
+ if (path.isAbsolute(filePath)) {
46
+ relativePath = path.relative(cwd, filePath).replace(/\\/g, '/');
47
+ } else {
48
+ relativePath = filePath.replace(/\\/g, '/');
49
+ }
50
+
51
+ // Run all three queries in parallel
52
+ const [definition, references, dependencies] = await Promise.all([
53
+ provider.findDefinition(relativePath),
54
+ provider.findReferences(relativePath),
55
+ provider.analyzeDependencies(relativePath),
56
+ ]);
57
+
58
+ // Treat empty dependency graph as no data
59
+ const hasUsefulDeps = dependencies && dependencies.nodes && dependencies.nodes.length > 0;
60
+
61
+ // If nothing found at all, try searching by the file basename
62
+ if (!definition && !references && !hasUsefulDeps) {
63
+ const basename = path.basename(relativePath, path.extname(relativePath));
64
+ const fallbackDef = await provider.findDefinition(basename);
65
+ if (!fallbackDef) return null;
66
+
67
+ const [fallbackRefs, fallbackDeps] = await Promise.all([
68
+ provider.findReferences(basename),
69
+ provider.analyzeDependencies(basename),
70
+ ]);
71
+
72
+ return {
73
+ entity: fallbackDef,
74
+ references: fallbackRefs,
75
+ dependencies: fallbackDeps,
76
+ };
77
+ }
78
+
79
+ return {
80
+ entity: definition,
81
+ references,
82
+ dependencies,
83
+ };
84
+ } catch (_err) {
85
+ // Guard against provider exceptions to avoid unhandled rejections in hook runtime
86
+ return null;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Format code intelligence data as XML for injection into Claude context.
92
+ *
93
+ * @param {Object|null} intel - Result from resolveCodeIntel()
94
+ * @param {string} filePath - Target file path (for display)
95
+ * @returns {string|null} XML string or null if no data
96
+ */
97
+ function formatAsXml(intel, filePath) {
98
+ if (!intel) return null;
99
+
100
+ const { entity, references, dependencies } = intel;
101
+
102
+ // At least one piece of data must exist
103
+ if (!entity && !references && !dependencies) return null;
104
+
105
+ const lines = ['<code-intel-context>'];
106
+ lines.push(` <target-file>${escapeXml(filePath)}</target-file>`);
107
+
108
+ // Entity definition
109
+ if (entity) {
110
+ lines.push(' <existing-entity>');
111
+ if (entity.file) lines.push(` <path>${escapeXml(entity.file)}</path>`);
112
+ if (entity.context) lines.push(` <purpose>${escapeXml(entity.context)}</purpose>`);
113
+ lines.push(' </existing-entity>');
114
+ }
115
+
116
+ // References
117
+ if (references && references.length > 0) {
118
+ // Deduplicate by file path
119
+ const uniqueRefs = [];
120
+ const seen = new Set();
121
+ for (const ref of references) {
122
+ if (ref.file && !seen.has(ref.file)) {
123
+ seen.add(ref.file);
124
+ uniqueRefs.push(ref);
125
+ }
126
+ }
127
+
128
+ lines.push(` <referenced-by count="${uniqueRefs.length}">`);
129
+ for (const ref of uniqueRefs.slice(0, 15)) {
130
+ const ctx = ref.context ? ` context="${escapeXml(ref.context)}"` : '';
131
+ lines.push(` <ref file="${escapeXml(ref.file)}"${ctx} />`);
132
+ }
133
+ if (uniqueRefs.length > 15) {
134
+ lines.push(` <!-- ...and ${uniqueRefs.length - 15} more -->`);
135
+ }
136
+ lines.push(' </referenced-by>');
137
+ }
138
+
139
+ // Dependencies
140
+ if (dependencies && dependencies.nodes && dependencies.nodes.length > 1) {
141
+ // First node is the target itself, rest are dependencies
142
+ const depNodes = dependencies.nodes.slice(1);
143
+ lines.push(` <dependencies count="${depNodes.length}">`);
144
+ for (const dep of depNodes.slice(0, 10)) {
145
+ const layer = dep.layer ? ` layer="${dep.layer}"` : '';
146
+ lines.push(` <dep name="${escapeXml(dep.name)}"${layer} />`);
147
+ }
148
+ if (depNodes.length > 10) {
149
+ lines.push(` <!-- ...and ${depNodes.length - 10} more -->`);
150
+ }
151
+ lines.push(' </dependencies>');
152
+ }
153
+
154
+ lines.push('</code-intel-context>');
155
+ return lines.join('\n');
156
+ }
157
+
158
+ /**
159
+ * Escape special XML characters.
160
+ * @param {string} str
161
+ * @returns {string}
162
+ */
163
+ function escapeXml(str) {
164
+ if (!str) return '';
165
+ return String(str)
166
+ .replace(/&/g, '&amp;')
167
+ .replace(/</g, '&lt;')
168
+ .replace(/>/g, '&gt;')
169
+ .replace(/"/g, '&quot;');
170
+ }
171
+
172
+ /**
173
+ * Reset cached provider (for testing).
174
+ */
175
+ function _resetForTesting() {
176
+ _provider = null;
177
+ _providerRoot = null;
178
+ }
179
+
180
+ module.exports = {
181
+ resolveCodeIntel,
182
+ formatAsXml,
183
+ escapeXml,
184
+ getProvider,
185
+ _resetForTesting,
186
+ };
@@ -4,6 +4,7 @@ const { CodeIntelClient } = require('./code-intel-client');
4
4
  const { CodeIntelEnricher } = require('./code-intel-enricher');
5
5
  const { CodeIntelProvider, CAPABILITIES } = require('./providers/provider-interface');
6
6
  const { CodeGraphProvider, TOOL_MAP } = require('./providers/code-graph-provider');
7
+ const { RegistryProvider } = require('./providers/registry-provider');
7
8
 
8
9
  // Singleton client instance (lazily initialized)
9
10
  let _defaultClient = null;
@@ -127,6 +128,7 @@ module.exports = {
127
128
  CodeIntelEnricher,
128
129
  CodeIntelProvider,
129
130
  CodeGraphProvider,
131
+ RegistryProvider,
130
132
 
131
133
  // Constants
132
134
  CAPABILITIES,
@@ -29,6 +29,14 @@ class CodeGraphProvider extends CodeIntelProvider {
29
29
  this._mcpServerName = options.mcpServerName || 'code-graph';
30
30
  }
31
31
 
32
+ /**
33
+ * Code Graph provider is available when mcpCallFn is configured.
34
+ * @returns {boolean}
35
+ */
36
+ isAvailable() {
37
+ return typeof this.options.mcpCallFn === 'function';
38
+ }
39
+
32
40
  /**
33
41
  * Execute an MCP tool call via the configured server.
34
42
  * This method is the single point of MCP communication — all capabilities route through here.
@@ -14,6 +14,15 @@ class CodeIntelProvider {
14
14
  this.options = options;
15
15
  }
16
16
 
17
+ /**
18
+ * Check if this provider is available and can serve requests.
19
+ * Subclasses MUST override this to indicate availability.
20
+ * @returns {boolean}
21
+ */
22
+ isAvailable() {
23
+ return false;
24
+ }
25
+
17
26
  /**
18
27
  * Locate the definition of a symbol.
19
28
  * @param {string} symbol - Symbol name to find