Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
219 changes: 219 additions & 0 deletions .aios-core/core/code-intel/helpers/dev-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
'use strict';

const { getEnricher, getClient, isCodeIntelAvailable } = require('../index');

// Risk level thresholds based on blast radius (reference count)
const RISK_THRESHOLDS = {
LOW_MAX: 4, // 0-4 refs = LOW
MEDIUM_MAX: 15, // 5-15 refs = MEDIUM
// >15 refs = HIGH
};

// Minimum references to suggest REUSE (>threshold = REUSE, <=threshold = ADAPT)
const REUSE_MIN_REFS = 2;

/**
* DevHelper — Code intelligence helper for @dev agent tasks.
*
* All functions return null gracefully when no provider is available.
* Never throws — safe to call unconditionally in task workflows.
*/

/**
* Check for duplicates and similar code before writing a new file or function.
* Used by IDS Gate G4 in dev-develop-story and build-autonomous tasks.
*
* @param {string} fileName - Name of the file/function to be created
* @param {string} description - Description of what it does
* @returns {Promise<{duplicates: Object, references: Array, suggestion: string}|null>}
*/
async function checkBeforeWriting(fileName, description) {
if (!fileName || !description) {
return null;
}
if (!isCodeIntelAvailable()) {
return null;
}

try {
const enricher = getEnricher();
const dupes = await enricher.detectDuplicates(description, { path: '.' });

// Also search for the fileName as a symbol reference
const client = getClient();
const nameRefs = await client.findReferences(fileName);

const hasMatches = (dupes && dupes.matches && dupes.matches.length > 0) ||
(nameRefs && nameRefs.length > 0);

if (!hasMatches) {
return null;
}

return {
duplicates: dupes,
references: nameRefs || [],
suggestion: _formatSuggestion(dupes, nameRefs),
};
} catch {
return null;
}
}

/**
* Suggest reuse of an existing symbol instead of creating a new one.
* Searches for definitions and references to determine REUSE vs ADAPT.
*
* @param {string} symbol - Symbol name to search for
* @returns {Promise<{file: string, line: number, references: number, suggestion: string}|null>}
*/
async function suggestReuse(symbol) {
if (!symbol) {
return null;
}
if (!isCodeIntelAvailable()) {
return null;
}

try {
const client = getClient();
const [definition, refs] = await Promise.all([
client.findDefinition(symbol),
client.findReferences(symbol),
]);

if (!definition && (!refs || refs.length === 0)) {
return null;
}

const refCount = refs ? refs.length : 0;
// REUSE if widely used, ADAPT if exists but lightly used
const suggestion = refCount > REUSE_MIN_REFS ? 'REUSE' : 'ADAPT';

return {
file: definition ? definition.file : (refs[0] ? refs[0].file : null),
line: definition ? definition.line : (refs[0] ? refs[0].line : null),
references: refCount,
suggestion,
};
} catch {
return null;
}
}

/**
* Get naming conventions and patterns for a given path.
* Used to ensure new code follows existing project conventions.
*
* @param {string} targetPath - Path to analyze conventions for
* @returns {Promise<{patterns: Array, stats: Object}|null>}
*/
async function getConventionsForPath(targetPath) {
if (!targetPath) {
return null;
}
if (!isCodeIntelAvailable()) {
return null;
}

try {
const enricher = getEnricher();
return await enricher.getConventions(targetPath);
} catch {
return null;
}
}

/**
* Assess refactoring impact with blast radius and risk level.
* Used by dev-suggest-refactoring to show impact before changes.
*
* @param {string[]} files - Files to assess impact for
* @returns {Promise<{blastRadius: number, riskLevel: string, references: Array, complexity: Object}|null>}
*/
async function assessRefactoringImpact(files) {
if (!Array.isArray(files) || files.length === 0) {
return null;
}
if (!isCodeIntelAvailable()) {
return null;
}

try {
const enricher = getEnricher();
const impact = await enricher.assessImpact(files);

if (!impact) {
return null;
}

return {
blastRadius: impact.blastRadius,
riskLevel: _calculateRiskLevel(impact.blastRadius),
references: impact.references,
complexity: impact.complexity,
};
} catch {
return null;
}
}

/**
* Format a Code Intelligence Suggestion message from duplicate detection results.
* @param {Object|null} dupes - Result from detectDuplicates
* @param {Array|null} nameRefs - Result from findReferences
* @returns {string} Formatted suggestion message
* @private
*/
function _formatSuggestion(dupes, nameRefs) {
const parts = [];

if (dupes && dupes.matches && dupes.matches.length > 0) {
parts.push(`Found ${dupes.matches.length} similar match(es) in codebase`);
const firstMatch = dupes.matches[0];
if (firstMatch.file) {
parts.push(`Closest: ${firstMatch.file}${firstMatch.line ? ':' + firstMatch.line : ''}`);
}
}

if (nameRefs && nameRefs.length > 0) {
parts.push(`Symbol already referenced in ${nameRefs.length} location(s)`);
const firstRef = nameRefs[0];
if (firstRef.file) {
parts.push(`First ref: ${firstRef.file}${firstRef.line ? ':' + firstRef.line : ''}`);
}
}

parts.push('Consider REUSE or ADAPT before creating new code (IDS Article IV-A)');

return parts.join('. ') + '.';
}

/**
* Calculate risk level from blast radius count.
* @param {number} blastRadius - Number of references affected
* @returns {string} 'LOW' | 'MEDIUM' | 'HIGH'
* @private
*/
function _calculateRiskLevel(blastRadius) {
const radius = typeof blastRadius === 'number' && !Number.isNaN(blastRadius) ? blastRadius : 0;
if (radius <= RISK_THRESHOLDS.LOW_MAX) {
return 'LOW';
}
if (radius <= RISK_THRESHOLDS.MEDIUM_MAX) {
return 'MEDIUM';
}
return 'HIGH';
}

module.exports = {
checkBeforeWriting,
suggestReuse,
getConventionsForPath,
assessRefactoringImpact,
// Exposed for testing
_formatSuggestion,
_calculateRiskLevel,
RISK_THRESHOLDS,
REUSE_MIN_REFS,
};
27 changes: 27 additions & 0 deletions .aios-core/data/entity-registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5997,6 +5997,33 @@ entities:
checksum: sha256:310884d94b81be976a346987822306a16a73ba812c08c3b805f4a03216ffef38
lastVerified: '2026-02-15T19:28:17.743Z'
modules:
dev-helper:
path: .aios-core/core/code-intel/helpers/dev-helper.js
type: module
purpose: Code intelligence helper for @dev agent tasks - IDS G4 automation, duplicate detection, conventions, blast radius
keywords:
- code-intel
- dev-helper
- ids-g4
- duplicate-detection
- blast-radius
- conventions
- reuse
usedBy:
- dev-develop-story
- create-service
- dev-suggest-refactoring
- build-autonomous
dependencies:
- code-intel
adaptability:
score: 0.7
constraints:
- Requires code-intel module (NOG-1)
extensionPoints:
- Additional helper functions for other agents
checksum: ''
lastVerified: '2026-02-16T00:00:00.000Z'
registry-syncer:
path: .aios-core/core/code-intel/registry-syncer.js
type: module
Expand Down
35 changes: 35 additions & 0 deletions .aios-core/development/checklists/issue-triage-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Issue Triage Checklist

## Per-Issue Checklist

For each issue being triaged, verify:

### Classification
- [ ] Issue has been read and understood
- [ ] ONE `type:` label applied (bug/feature/enhancement/docs/test/chore)
- [ ] ONE `priority:` label applied (P1/P2/P3/P4)
- [ ] At least ONE `area:` label applied
- [ ] `status: needs-triage` removed

### Status Resolution
- [ ] Status set to `status: confirmed` OR `status: needs-info`
- [ ] If `status: needs-info` — comment posted asking for specific details
- [ ] If duplicate — labeled `duplicate`, closed with reference to original issue

### Community
- [ ] Assessed for `community: good first issue` (clear scope, isolated, well-documented)
- [ ] Assessed for `community: help wanted` (valid but team lacks bandwidth)

### Quality
- [ ] Issue has sufficient information to act on (or `status: needs-info` applied)
- [ ] Related issues cross-referenced if applicable
- [ ] No sensitive information in issue (API keys, credentials)

## Session Checklist

After completing a triage session:

- [ ] All `status: needs-triage` issues reviewed
- [ ] Triage report generated
- [ ] Story GHIM-001 updated with triage count
- [ ] High-priority issues (P1/P2) flagged for immediate attention
Loading