diff --git a/.aiox-core/core/code-intel/helpers/dev-helper.js b/.aiox-core/core/code-intel/helpers/dev-helper.js index cc2c1c24b2..6da9f6be25 100644 --- a/.aiox-core/core/code-intel/helpers/dev-helper.js +++ b/.aiox-core/core/code-intel/helpers/dev-helper.js @@ -6,7 +6,7 @@ const { getEnricher, getClient, isCodeIntelAvailable } = require('../index'); const RISK_THRESHOLDS = { LOW_MAX: 4, // 0-4 refs = LOW MEDIUM_MAX: 15, // 5-15 refs = MEDIUM - // >15 refs = HIGH + // >15 refs = HIGH }; // Minimum references to suggest REUSE (>threshold = REUSE, <=threshold = ADAPT) diff --git a/.aiox-core/core/code-intel/helpers/devops-helper.js b/.aiox-core/core/code-intel/helpers/devops-helper.js index 9babd11e0f..45f2e868e7 100644 --- a/.aiox-core/core/code-intel/helpers/devops-helper.js +++ b/.aiox-core/core/code-intel/helpers/devops-helper.js @@ -78,7 +78,6 @@ async function generateImpactSummary(files) { } catch { /* skip — partial result ok */ } const riskLevel = classifyRiskLevel(impact.blastRadius); - const fileCount = impact.references ? impact.references.length : 0; const topFiles = (impact.references || []) .map((r) => r.file || r.path || 'unknown') .slice(0, 10); diff --git a/.aiox-core/core/code-intel/helpers/planning-helper.js b/.aiox-core/core/code-intel/helpers/planning-helper.js index 6f4c1bbc7c..5db795bfdb 100644 --- a/.aiox-core/core/code-intel/helpers/planning-helper.js +++ b/.aiox-core/core/code-intel/helpers/planning-helper.js @@ -7,7 +7,7 @@ const { getEnricher, getClient, isCodeIntelAvailable } = require('../index'); const RISK_THRESHOLDS = { LOW_MAX: 4, // 0-4 refs = LOW MEDIUM_MAX: 15, // 5-15 refs = MEDIUM - // >15 refs = HIGH + // >15 refs = HIGH }; /** diff --git a/.aiox-core/core/code-intel/helpers/qa-helper.js b/.aiox-core/core/code-intel/helpers/qa-helper.js index 8661660646..564421e5c8 100644 --- a/.aiox-core/core/code-intel/helpers/qa-helper.js +++ b/.aiox-core/core/code-intel/helpers/qa-helper.js @@ -7,14 +7,14 @@ const { getEnricher, getClient, isCodeIntelAvailable } = require('../index'); const RISK_THRESHOLDS = { LOW_MAX: 4, // 0-4 refs = LOW MEDIUM_MAX: 15, // 5-15 refs = MEDIUM - // >15 refs = HIGH + // >15 refs = HIGH }; // Coverage status thresholds based on test reference count const COVERAGE_THRESHOLDS = { INDIRECT_MAX: 2, // 1-2 test refs = INDIRECT MINIMAL_MAX: 5, // 3-5 test refs = MINIMAL - // >5 test refs = GOOD + // >5 test refs = GOOD }; /** diff --git a/.aiox-core/core/config/template-overrides.js b/.aiox-core/core/config/template-overrides.js index 6f806bb060..f78d2d40be 100644 --- a/.aiox-core/core/config/template-overrides.js +++ b/.aiox-core/core/config/template-overrides.js @@ -53,7 +53,7 @@ function getTemplateOverrides(resolvedConfig) { if (unknown.length > 0) { throw new Error( `Unknown story section ID(s) in template_overrides: ${unknown.join(', ')}. ` + - `Valid IDs: ${KNOWN_STORY_SECTIONS.join(', ')}` + `Valid IDs: ${KNOWN_STORY_SECTIONS.join(', ')}`, ); } diff --git a/.aiox-core/core/doctor/checks/rules-files.js b/.aiox-core/core/doctor/checks/rules-files.js index 98bebe6291..5d82ccfad6 100644 --- a/.aiox-core/core/doctor/checks/rules-files.js +++ b/.aiox-core/core/doctor/checks/rules-files.js @@ -47,7 +47,6 @@ async function run(context) { }; } - const present = EXPECTED_RULES.length - missing.length; const severity = missing.length > 3 ? 'FAIL' : 'WARN'; return { diff --git a/.aiox-core/core/graph-dashboard/cli.js b/.aiox-core/core/graph-dashboard/cli.js index 4ebc5b9565..9c82295c90 100644 --- a/.aiox-core/core/graph-dashboard/cli.js +++ b/.aiox-core/core/graph-dashboard/cli.js @@ -278,9 +278,8 @@ Examples: /** * Handle default summary view: dependency tree (compact) + stats + provider status. - * @param {Object} args - Parsed CLI args */ -async function handleSummary(args) { +async function handleSummary() { const codeIntelSource = new CodeIntelSource(); const registrySource = new RegistrySource(); const metricsSource = new MetricsSource(); diff --git a/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js b/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js index f9352d91d1..488448e524 100644 --- a/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +++ b/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js @@ -161,7 +161,7 @@ class CodeIntelSource { Object.entries(deps.dependencies).map(([key, val]) => ({ id: key, ...((typeof val === 'object' && val) || {}), - })) + })), ); } diff --git a/.aiox-core/core/ids/layer-classifier.js b/.aiox-core/core/ids/layer-classifier.js index 4b00e73ecf..24ecf29476 100644 --- a/.aiox-core/core/ids/layer-classifier.js +++ b/.aiox-core/core/ids/layer-classifier.js @@ -44,7 +44,7 @@ const LAYER_RULES = [ * @returns {'L1' | 'L2' | 'L3' | 'L4'} The boundary layer */ function classifyLayer(entityPath) { - if (typeof entityPath !== "string") return "L4"; + if (typeof entityPath !== 'string') return 'L4'; // Normalize: forward slashes, no leading ./ or / const normalized = entityPath diff --git a/.aiox-core/core/synapse/layers/layer-processor.js b/.aiox-core/core/synapse/layers/layer-processor.js index ab9273f33a..a20a177c15 100644 --- a/.aiox-core/core/synapse/layers/layer-processor.js +++ b/.aiox-core/core/synapse/layers/layer-processor.js @@ -50,7 +50,7 @@ class LayerProcessor { * @param {object[]} context.previousLayers - Results from previous layers * @returns {{ rules: string[], metadata: object } | null} Rules and metadata, or null to skip */ - process(context) { + process(_context) { throw new Error(`${this.name}: process() must be implemented by subclass`); } diff --git a/.aiox-core/data/capability-detection.js b/.aiox-core/data/capability-detection.js index a9bf1f0444..d69f9b6520 100644 --- a/.aiox-core/data/capability-detection.js +++ b/.aiox-core/data/capability-detection.js @@ -31,13 +31,13 @@ function detectToolSearch() { return { available: features.tengu_mcp_tool_search === true, source: 'cachedGrowthBookFeatures.tengu_mcp_tool_search', - detectionMethod: 'claude-json-feature-flag' + detectionMethod: 'claude-json-feature-flag', }; } catch { return { available: false, source: 'detection-failed', - detectionMethod: 'claude-json-feature-flag' + detectionMethod: 'claude-json-feature-flag', }; } } @@ -47,7 +47,7 @@ function detectDeferLoading() { return { available: false, reason: 'defer_loading is API-only (Python SDK). Not exposed in Claude Code CLI.', - source: 'ADR-7 / Codex CRITICO-1' + source: 'ADR-7 / Codex CRITICO-1', }; } @@ -60,7 +60,7 @@ function detectProjectMcps() { name, type: cfg.type || 'command', scope: 'project', - source: '.mcp.json' + source: '.mcp.json', })); } catch { return []; @@ -83,7 +83,7 @@ function detectGlobalMcps() { name: match[1], type: 'docker-gateway', scope: 'global', - source: '~/.docker/mcp/config.yaml' + source: '~/.docker/mcp/config.yaml', }); } } @@ -103,7 +103,7 @@ function detectGlobalMcps() { name, type: cfg.type || 'command', scope: 'global-settings', - source: '~/.claude/settings.json' + source: '~/.claude/settings.json', }); } } @@ -121,7 +121,7 @@ function detectDockerGateway() { return { available: exists, configPath: exists ? dockerMcpDir : null, - detectionMethod: 'filesystem-check' + detectionMethod: 'filesystem-check', }; } @@ -180,7 +180,7 @@ function loadToolRegistry() { tier2Count: tier2, tier3Count: tier3, essential, - nonEssential + nonEssential, }; } catch { return { available: false, totalTools: 0, tier1Count: 0, tier2Count: 0, tier3Count: 0, essential: [], nonEssential: [] }; @@ -197,7 +197,7 @@ function determineStrategy(toolSearch, deferLoading, dockerGateway) { return { primary: 'tool-search-auto', description: 'Claude Code Tool Search is active. Tier 3 MCP tools are automatically deferred via tool_search.', - fallbacks: ['mcp-discipline', 'claudemd-guidance'] + fallbacks: ['mcp-discipline', 'claudemd-guidance'], }; } @@ -205,14 +205,14 @@ function determineStrategy(toolSearch, deferLoading, dockerGateway) { return { primary: 'mcp-discipline', description: 'Tool Search not available. Using MCP discipline: disable non-essential servers in .mcp.json.', - fallbacks: ['claudemd-guidance'] + fallbacks: ['claudemd-guidance'], }; } return { primary: 'claudemd-guidance', description: 'Neither Tool Search nor Docker Gateway available. Using CLAUDE.md guidance for tool selection priority.', - fallbacks: [] + fallbacks: [], }; } @@ -236,20 +236,20 @@ function run() { methodology: { toolSearchLatency: 'Managed internally by Claude Code — not programmatically measurable. Guidance-level enforcement via CLAUDE.md.', - mcpCountUnit: 'servers (not individual tools). TOK-1.5 baseline uses tool count (e.g., Apify = 7 tools = 1 server).' + mcpCountUnit: 'servers (not individual tools). TOK-1.5 baseline uses tool count (e.g., Apify = 7 tools = 1 server).', }, runtime: { toolSearch, deferLoading, - dockerGateway + dockerGateway, }, mcpServers: { project: projectMcps, global: globalMcps, totalCount: projectMcps.length + globalMcps.length, - countUnit: 'servers' + countUnit: 'servers', }, toolRegistry, @@ -263,7 +263,7 @@ function run() { nonEssentialServers: toolRegistry.nonEssential.length > 0 ? toolRegistry.nonEssential - : [] + : [], }; // Ensure output directory exists diff --git a/.aiox-core/data/tok3-token-comparison.js b/.aiox-core/data/tok3-token-comparison.js index 5c6f4ecf7a..c9c919ff38 100644 --- a/.aiox-core/data/tok3-token-comparison.js +++ b/.aiox-core/data/tok3-token-comparison.js @@ -13,10 +13,6 @@ * Reference: TOK-1.5 Baseline (docs/stories/epics/epic-token-optimization/story-TOK-1.5-baseline-metrics.md) */ -const fs = require('fs'); -const path = require('path'); -const yaml = require ? null : null; // yaml not required — we parse manually - // --- Token estimation model --- // Based on tool-registry.yaml tokenCost and observed output patterns diff --git a/.aiox-core/data/tool-search-validation.js b/.aiox-core/data/tool-search-validation.js index 681a280f91..1c2aba4132 100644 --- a/.aiox-core/data/tool-search-validation.js +++ b/.aiox-core/data/tool-search-validation.js @@ -22,7 +22,7 @@ const TEST_QUERIES = [ { query: 'analyze code dependencies', expectedTool: 'code-graph', category: 'code-intelligence' }, { query: 'code analysis intelligence', expectedTool: 'nogic', category: 'code-intelligence' }, { query: 'look up library documentation', expectedTool: 'context7', category: 'documentation' }, - { query: 'database query optimization', expectedTool: 'supabase', category: 'database' } + { query: 'database query optimization', expectedTool: 'supabase', category: 'database' }, ]; function parseKeywords(content) { diff --git a/.aiox-core/install-manifest.yaml b/.aiox-core/install-manifest.yaml index e811e87e70..89e4b64c6b 100644 --- a/.aiox-core/install-manifest.yaml +++ b/.aiox-core/install-manifest.yaml @@ -8,7 +8,7 @@ # - File types for categorization # version: 5.0.3 -generated_at: "2026-05-05T22:31:55.669Z" +generated_at: "2026-05-05T22:37:53.053Z" generator: scripts/generate-install-manifest.js file_count: 1092 files: @@ -193,21 +193,21 @@ files: type: core size: 5637 - path: core/code-intel/helpers/dev-helper.js - hash: sha256:2418a5f541003c73cc284e88a6b0cb666896a47ffd5ed4c08648269d281efc4c + hash: sha256:7e7f9bb92725ca1d85b0a7151668bc5bcdd6fc9b73fed5b2b2c28217d14535ab type: core - size: 5770 + size: 5751 - path: core/code-intel/helpers/devops-helper.js - hash: sha256:c40cfa9ac2f554a707ff68c7709ae436349041bf00ad2f42811ccbe8ba842462 + hash: sha256:e72f95de2f3737b6e12094526eabfb4974a8339ce6d25f2e323f734fe567c155 type: core - size: 5115 + size: 5043 - path: core/code-intel/helpers/planning-helper.js - hash: sha256:2edcf275122125205a9e737035c8b25efdc4af13e7349ffc10c3ebe8ebe7654d + hash: sha256:9ca5b57b74b5729685369662659e15a91e35ec3a33691973be000ecd85974f3d type: core - size: 6863 + size: 6844 - path: core/code-intel/helpers/qa-helper.js - hash: sha256:ca069dad294224dd5c3369826fb39d5c24287d49d74360049f8bbc55f190eeda + hash: sha256:9dbb84c1c4ed1aa57385ad2a6c74520f2020e6f8883012dd57c51486172ee528 type: core - size: 5184 + size: 5146 - path: core/code-intel/helpers/story-helper.js hash: sha256:778466253ac66103ebc3b1caf71f44b06a0d5fb3d39fe8d3d473dd4bc73fefc6 type: core @@ -277,9 +277,9 @@ files: type: core size: 936 - path: core/config/template-overrides.js - hash: sha256:1708dc8764e7f88dfefd7684240afcd5f13657170ac104aed99145e2bb8ae82c + hash: sha256:202d141a292bc5a8dd0697e044d7627b260839ae8b7119fd40ae486b3a1b0825 type: core - size: 2223 + size: 2224 - path: core/config/templates/user-config.yaml hash: sha256:3505471b0adff9bfcea08f46cca3aeeda46a283bbe7ee711dd566e5974c3257f type: template @@ -337,9 +337,9 @@ files: type: core size: 2265 - path: core/doctor/checks/rules-files.js - hash: sha256:3996e6343a224021fa684d7930dc99b66469c59cb15d416b0c024a770d722ab6 + hash: sha256:ec58342215cede634f50c5b3164155c4f27fd8070af176ec0e02e6deec6fb218 type: core - size: 1426 + size: 1368 - path: core/doctor/checks/settings-json.js hash: sha256:bd26841b966fcfa003eca6f85416d4f877b9dcfea0e4017df9f2a97c14c33fbb type: core @@ -441,13 +441,13 @@ files: type: core size: 11060 - path: core/graph-dashboard/cli.js - hash: sha256:1f2fd6c6b5ace42f3bddc89695fe32d01949321d96057bbf50e2e48892f2c8f5 + hash: sha256:29f273a06fecc77eb3e39162ba1aaf28e1cbadb2a000158f009817021a30b4d1 type: core - size: 10251 + size: 10205 - path: core/graph-dashboard/data-sources/code-intel-source.js - hash: sha256:e508d6cbadcd2358fa7756dcaceefbaa510bd89155e036e2cbd386585408ff8f + hash: sha256:2b0534f57a8f6ca2ff5942e42faf147f1be84773b3af33c9e506ee8f318b558c type: core - size: 6799 + size: 6800 - path: core/graph-dashboard/data-sources/metrics-source.js hash: sha256:b1e4027f82350760b67ea8f58e04a5e739f87f010838487043e29dab7301ae9e type: core @@ -725,7 +725,7 @@ files: type: core size: 3624 - path: core/ids/layer-classifier.js - hash: sha256:4ae1e7d341076a13d08b8b5baf7a687ad2c7df673d50fc3554d522fe79debcdc + hash: sha256:2a240b70ac3507e50a64b96d580c4d933bf2116125fb52c8237db2ed9ebf27b7 type: core size: 2382 - path: core/ids/README.md @@ -1149,9 +1149,9 @@ files: type: core size: 4672 - path: core/synapse/layers/layer-processor.js - hash: sha256:73cb0e5b4bada80d8e256009004679e483792077fac4358c6466cd77136f79fa + hash: sha256:15f9e4c1525d3fa2186170705a26191ad87d94ffd7fa7d61f373b07b6fb3d874 type: core - size: 2881 + size: 2882 - path: core/synapse/memory/memory-bridge.js hash: sha256:820875f97ceea80fc6402c0dab1706cfe58de527897b22dea68db40b0d6ec368 type: core @@ -1221,13 +1221,13 @@ files: type: data size: 34235 - path: data/capability-detection.js - hash: sha256:5176849c01d90e5867f18962e03ff10a10628f40c30fe5c8cb65209f833c0884 + hash: sha256:317d1b51b5cda2e35ac6d468e33e05c0948e6d7f05f51d750d7ce6ff5a58535a type: data - size: 9575 + size: 9590 - path: data/entity-registry.yaml - hash: sha256:cc1bf74d3ef4e90b7a396d5b77259e540b2f9bd4a5b4b1da4977fe49ae83525d + hash: sha256:957d789341627c08c236d08a85914138d672c81d0b82a47cfa04b8ea26d937fa type: data - size: 521869 + size: 522833 - path: data/learned-patterns.yaml hash: sha256:24ac0b160615583a0ff783d3da8af80b7f94191575d6db2054ec8e10a3f945dc type: data @@ -1277,17 +1277,17 @@ files: type: data size: 7026 - path: data/tok3-token-comparison.js - hash: sha256:1f484f8054bec7a7e8055acbc9fddd7863a769948c30c6db42c5c8694410da8f + hash: sha256:da4e3cb3a09684d6fc6d0bb2b285d1837054b9fedc65b58e7fdc8d7a99b1d8a1 type: data - size: 4622 + size: 4486 - path: data/tool-registry.yaml hash: sha256:64e867d0eb36c7f7ac86f4f73f1b2ff89f43f37f28a6de34389be74b9346860c type: data size: 15178 - path: data/tool-search-validation.js - hash: sha256:8757bf087692f002d67115dbe1c8244bbd869600e4f52c49b0d9b07cb9fbb783 + hash: sha256:d83f0680d38996be4615c1f3425d35e0b20c5c93c09da470d2c6a42dcfc3583c type: data - size: 5754 + size: 5755 - path: data/workflow-chains.yaml hash: sha256:1fbf1625e267eedc315cf1e08e5827c250ddc6785fb2cb139e7702def9b66268 type: data diff --git a/.aiox-core/utils/filters/index.js b/.aiox-core/utils/filters/index.js index 440546babd..62fc14c1a3 100644 --- a/.aiox-core/utils/filters/index.js +++ b/.aiox-core/utils/filters/index.js @@ -112,7 +112,7 @@ function applyFilter(toolName, input, overrideConfig, registryPath) { filter_type: 'field', }; - default: + default: { // Unknown filter type — pass through const serialized = typeof input === 'string' ? input : JSON.stringify(input, null, 2); return { @@ -122,6 +122,7 @@ function applyFilter(toolName, input, overrideConfig, registryPath) { reduction_pct: 0, filter_type: 'unknown', }; + } } } diff --git a/.claude/hooks/precompact-session-digest.cjs b/.claude/hooks/precompact-session-digest.cjs index da24e0dd21..c5efdd8990 100644 --- a/.claude/hooks/precompact-session-digest.cjs +++ b/.claude/hooks/precompact-session-digest.cjs @@ -99,9 +99,9 @@ async function main() { contextJson = '{}'; } const inlineScript = [ - `const ctx = JSON.parse(process.env.AIOX_HOOK_CONTEXT || '{}');`, + 'const ctx = JSON.parse(process.env.AIOX_HOOK_CONTEXT || \'{}\');', `const { onPreCompact } = require(${JSON.stringify(runnerPath)});`, - `onPreCompact(ctx).catch(() => {});`, + 'onPreCompact(ctx).catch(() => {});', ].join('\n'); const child = spawn(process.execPath, ['-e', inlineScript], { detached: true, diff --git a/.gitignore b/.gitignore index caf87ee608..edc7232be1 100644 --- a/.gitignore +++ b/.gitignore @@ -347,6 +347,7 @@ scripts/glue/ .claude/agents/ .claude/agent-memory/ .claude/setup/ +.agents/ docs/guides/aiox-workflows/ # Local Gemini project rules generated/managed per workspace diff --git a/.synapse/.gitignore b/.synapse/.gitignore new file mode 100644 index 0000000000..fab6b7e720 --- /dev/null +++ b/.synapse/.gitignore @@ -0,0 +1,3 @@ +# SYNAPSE runtime data (auto-generated) +sessions/ +cache/ diff --git a/bin/aiox.js b/bin/aiox.js index 8ac133d450..48dd14708a 100755 --- a/bin/aiox.js +++ b/bin/aiox.js @@ -8,8 +8,6 @@ const path = require('path'); const fs = require('fs'); -const { execSync } = require('child_process'); - // Read package.json for version const packageJsonPath = path.join(__dirname, '..', 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); diff --git a/bin/utils/framework-guard.js b/bin/utils/framework-guard.js index f12053805a..d04f38aa2f 100644 --- a/bin/utils/framework-guard.js +++ b/bin/utils/framework-guard.js @@ -54,6 +54,7 @@ function globToRegex(glob) { pattern = pattern.replace(/\*/g, '[^/]+'); // 4. Restore ** placeholder to any-depth matcher + // eslint-disable-next-line no-control-regex pattern = pattern.replace(/\u0000/g, '.+'); // If pattern ends with .+ (was **), match prefix diff --git a/packages/installer/src/installer/brownfield-upgrader.js b/packages/installer/src/installer/brownfield-upgrader.js index 0a669683d1..209d6bb690 100644 --- a/packages/installer/src/installer/brownfield-upgrader.js +++ b/packages/installer/src/installer/brownfield-upgrader.js @@ -287,7 +287,7 @@ async function applyUpgrade(report, sourceDir, targetDir, options = {}) { result.mergeWarnings = result.mergeWarnings || []; for (const conflict of conflicts) { result.mergeWarnings.push( - `core-config.yaml: ${conflict.identifier} — ${conflict.reason}` + `core-config.yaml: ${conflict.identifier} — ${conflict.reason}`, ); } } diff --git a/packages/installer/src/pro/pro-scaffolder.js b/packages/installer/src/pro/pro-scaffolder.js index 5af37e27f8..0dc25de13d 100644 --- a/packages/installer/src/pro/pro-scaffolder.js +++ b/packages/installer/src/pro/pro-scaffolder.js @@ -160,7 +160,7 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) { result.errors.push(`Rollback errors: ${rollbackResult.errors.join(', ')}`); } result.warnings.push( - `Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up.` + `Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up.`, ); } @@ -425,7 +425,7 @@ async function installSquadCommands(targetDir) { for (const agentFile of agentFiles) { await fs.copy( path.join(agentsDir, agentFile), - path.join(destDir, agentFile) + path.join(destDir, agentFile), ); files.push(path.relative(targetDir, path.join(destDir, agentFile)).replace(/\\/g, '/')); } diff --git a/packages/installer/src/wizard/ide-config-generator.js b/packages/installer/src/wizard/ide-config-generator.js index 701a3a10b4..a18539caca 100644 --- a/packages/installer/src/wizard/ide-config-generator.js +++ b/packages/installer/src/wizard/ide-config-generator.js @@ -264,7 +264,7 @@ async function copyAgentFiles(projectRoot, agentFolder, ideConfig = null) { const targetPath = path.join(targetDir, filename); await fs.writeFile(targetPath, content, 'utf8'); copiedFiles.push(targetPath); - } catch (transformError) { + } catch (_transformError) { // Fallback: copy raw file with .agent.md extension const targetPath = path.join(targetDir, `${agentName}.agent.md`); await fs.copy(sourcePath, targetPath); diff --git a/packages/installer/src/wizard/index.js b/packages/installer/src/wizard/index.js index fde425068e..d855425ef1 100644 --- a/packages/installer/src/wizard/index.js +++ b/packages/installer/src/wizard/index.js @@ -554,7 +554,7 @@ async function runWizard(options = {}) { try { await commandValidate({ quiet: true }); answers.ideSyncValidation = 'pass'; - } catch (validateError) { + } catch (_validateError) { answers.ideSyncValidation = 'drift'; } finally { console.log = _origLog; diff --git a/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js b/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js index 1d567575a9..16e9234d53 100644 --- a/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +++ b/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js @@ -94,7 +94,7 @@ describe('artifact-copy-pipeline (Story INS-4.3)', () => { expect(result.count).toBe(1); const content = fs.readFileSync( path.join(targetRoot, '.claude', 'skills', 'test-skill', 'SKILL.md'), - 'utf8' + 'utf8', ); expect(content).toBe('# v2'); } finally { diff --git a/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js b/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js index 64e0a82bc4..b87d2cc027 100644 --- a/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +++ b/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js @@ -10,7 +10,7 @@ const { const TEMPLATE_PATH = path.join( __dirname, '..', '..', '..', '..', '..', '.aiox-core', - 'product', 'templates', 'ide-rules', 'claude-rules.md' + 'product', 'templates', 'ide-rules', 'claude-rules.md', ); describe('CLAUDE.md Template v5 (Story INS-4.4)', () => { diff --git a/packages/installer/tests/unit/entity-registry-bootstrap.test.js b/packages/installer/tests/unit/entity-registry-bootstrap.test.js index 7363a9f92c..eef4ee799f 100644 --- a/packages/installer/tests/unit/entity-registry-bootstrap.test.js +++ b/packages/installer/tests/unit/entity-registry-bootstrap.test.js @@ -12,17 +12,17 @@ const path = require('path'); const WIZARD_PATH = path.join(__dirname, '..', '..', 'src', 'wizard', 'index.js'); const POPULATE_SCRIPT = path.join( - __dirname, '..', '..', '..', '..', '.aiox-core', 'development', 'scripts', 'populate-entity-registry.js' + __dirname, '..', '..', '..', '..', '.aiox-core', 'development', 'scripts', 'populate-entity-registry.js', ); const DOCTOR_CHECK = path.join( - __dirname, '..', '..', '..', '..', '.aiox-core', 'core', 'doctor', 'checks', 'entity-registry.js' + __dirname, '..', '..', '..', '..', '.aiox-core', 'core', 'doctor', 'checks', 'entity-registry.js', ); const REGISTRY_PATH = path.join( - __dirname, '..', '..', '..', '..', '.aiox-core', 'data', 'entity-registry.yaml' + __dirname, '..', '..', '..', '..', '.aiox-core', 'data', 'entity-registry.yaml', ); const PRE_PUSH_HOOK = path.join(__dirname, '..', '..', '..', '..', '.husky', 'pre-push'); const IDS_PRE_PUSH = path.join( - __dirname, '..', '..', '..', '..', '.aiox-core', 'hooks', 'ids-pre-push.js' + __dirname, '..', '..', '..', '..', '.aiox-core', 'hooks', 'ids-pre-push.js', ); describe('Entity Registry Bootstrap (Story INS-4.6)', () => { diff --git a/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js b/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js index c6f5221f2c..42bb0e789c 100644 --- a/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +++ b/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js @@ -49,7 +49,7 @@ function createTempProject(boundary, existingSettings) { fs.writeFileSync( path.join(claudeDir, 'settings.json'), JSON.stringify(existingSettings, null, 2) + '\n', - 'utf8' + 'utf8', ); } @@ -256,7 +256,7 @@ describe('generate-settings-json', () => { protected: ['bin/aiox.js'], exceptions: [], }, - { language: 'pt', customSetting: true } + { language: 'pt', customSetting: true }, ); try { @@ -280,7 +280,7 @@ describe('generate-settings-json', () => { protected: ['bin/aiox.js'], exceptions: [], }, - { language: 'pt', permissions: { deny: ['old-rule'], allow: [] } } + { language: 'pt', permissions: { deny: ['old-rule'], allow: [] } }, ); try { diff --git a/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js b/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js index ba952fb080..cdb354bd83 100644 --- a/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +++ b/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js @@ -21,7 +21,7 @@ jest.mock('../../../../../.aiox-core/infrastructure/scripts/ide-sync/index', () // We need to verify that the wizard source code has the correct integration const fs = require('fs'); const WIZARD_PATH = path.join( - __dirname, '..', '..', '..', 'src', 'wizard', 'index.js' + __dirname, '..', '..', '..', 'src', 'wizard', 'index.js', ); describe('IDE Sync Integration (Story INS-4.5)', () => { @@ -34,7 +34,7 @@ describe('IDE Sync Integration (Story INS-4.5)', () => { describe('AC1: IDE sync called via adapter pattern', () => { test('wizard imports commandSync and commandValidate from ide-sync', () => { expect(wizardSource).toContain( - "const { commandSync, commandValidate } = require('../../../../.aiox-core/infrastructure/scripts/ide-sync/index')" + "const { commandSync, commandValidate } = require('../../../../.aiox-core/infrastructure/scripts/ide-sync/index')", ); }); @@ -61,7 +61,7 @@ describe('IDE Sync Integration (Story INS-4.5)', () => { }); test('commandSync called with { quiet: true }', () => { - expect(wizardSource).toContain("await commandSync({ quiet: true })"); + expect(wizardSource).toContain('await commandSync({ quiet: true })'); }); test('does NOT pass projectRoot or ides as parameters to commandSync', () => { @@ -78,7 +78,7 @@ describe('IDE Sync Integration (Story INS-4.5)', () => { }); test('failure message suggests aiox doctor --fix', () => { - expect(wizardSource).toContain("aiox doctor --fix"); + expect(wizardSource).toContain('aiox doctor --fix'); }); test('install summary includes sync status on success', () => { diff --git a/packages/installer/tests/unit/merger/yaml-merger.test.js b/packages/installer/tests/unit/merger/yaml-merger.test.js index 3ff33336bc..9e8054e053 100644 --- a/packages/installer/tests/unit/merger/yaml-merger.test.js +++ b/packages/installer/tests/unit/merger/yaml-merger.test.js @@ -15,7 +15,7 @@ const path = require('path'); const fs = require('fs'); const { YamlMerger } = require(path.join( - __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'yaml-merger.js' + __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'yaml-merger.js', )); describe('YamlMerger (Story INS-4.7)', () => { @@ -54,7 +54,7 @@ describe('YamlMerger (Story INS-4.7)', () => { describe('AC1: Strategy registration', () => { test('.yaml extension registered in strategies/index.js', () => { const { hasMergeStrategy, getMergeStrategy } = require(path.join( - __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'index.js' + __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'index.js', )); expect(hasMergeStrategy('config.yaml')).toBe(true); @@ -64,7 +64,7 @@ describe('YamlMerger (Story INS-4.7)', () => { test('.yml extension also registered', () => { const { hasMergeStrategy } = require(path.join( - __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'index.js' + __dirname, '..', '..', '..', 'src', 'merger', 'strategies', 'index.js', )); expect(hasMergeStrategy('config.yml')).toBe(true); @@ -72,7 +72,7 @@ describe('YamlMerger (Story INS-4.7)', () => { test('YamlMerger exported from merger/index.js', () => { const mergerModule = require(path.join( - __dirname, '..', '..', '..', 'src', 'merger', 'index.js' + __dirname, '..', '..', '..', 'src', 'merger', 'index.js', )); expect(mergerModule.YamlMerger).toBeDefined(); @@ -91,7 +91,7 @@ describe('YamlMerger (Story INS-4.7)', () => { expect(result.stats.added).toBeGreaterThanOrEqual(1); const addedChange = result.changes.find( - c => c.type === 'added' && c.identifier === 'newFeature' + c => c.type === 'added' && c.identifier === 'newFeature', ); expect(addedChange).toBeDefined(); }); @@ -107,7 +107,7 @@ describe('YamlMerger (Story INS-4.7)', () => { expect(result.stats.preserved).toBeGreaterThanOrEqual(1); const preservedChange = result.changes.find( - c => c.type === 'preserved' && c.identifier === 'key' + c => c.type === 'preserved' && c.identifier === 'key', ); expect(preservedChange).toBeDefined(); }); @@ -123,7 +123,7 @@ describe('YamlMerger (Story INS-4.7)', () => { expect(result.stats.conflicts).toBeGreaterThanOrEqual(1); const conflictChange = result.changes.find( - c => c.type === 'conflict' && c.identifier === 'setting' + c => c.type === 'conflict' && c.identifier === 'setting', ); expect(conflictChange).toBeDefined(); expect(conflictChange.reason).toContain('Keeping user value'); @@ -139,7 +139,7 @@ describe('YamlMerger (Story INS-4.7)', () => { expect(merged.legacyKey).toBe('old-value'); const deprecatedChange = result.changes.find( - c => c.type === 'conflict' && c.identifier === 'legacyKey' + c => c.type === 'conflict' && c.identifier === 'legacyKey', ); expect(deprecatedChange).toBeDefined(); expect(deprecatedChange.reason).toContain('Deprecated'); @@ -294,7 +294,7 @@ describe('Brownfield Upgrader Integration (Story INS-4.7)', () => { test('brownfield-upgrader imports YamlMerger', () => { const upgraderSource = fs.readFileSync( path.join(__dirname, '..', '..', '..', 'src', 'installer', 'brownfield-upgrader.js'), - 'utf8' + 'utf8', ); expect(upgraderSource).toContain('YamlMerger'); expect(upgraderSource).toContain('yaml-merger.js'); @@ -303,7 +303,7 @@ describe('Brownfield Upgrader Integration (Story INS-4.7)', () => { test('upgrader has core-config.yaml merge exception in userModifiedFiles loop', () => { const upgraderSource = fs.readFileSync( path.join(__dirname, '..', '..', '..', 'src', 'installer', 'brownfield-upgrader.js'), - 'utf8' + 'utf8', ); expect(upgraderSource).toContain("file.path.endsWith('core-config.yaml')"); expect(upgraderSource).toContain('merger.merge(sourceContent, targetContent)'); @@ -313,7 +313,7 @@ describe('Brownfield Upgrader Integration (Story INS-4.7)', () => { test('upgrader still skips non-yaml user-modified files', () => { const upgraderSource = fs.readFileSync( path.join(__dirname, '..', '..', '..', 'src', 'installer', 'brownfield-upgrader.js'), - 'utf8' + 'utf8', ); expect(upgraderSource).toContain('User modified - preserving local changes'); }); diff --git a/scripts/package-synapse.js b/scripts/package-synapse.js index bc7d932328..0e7f6319bb 100644 --- a/scripts/package-synapse.js +++ b/scripts/package-synapse.js @@ -217,19 +217,19 @@ cp hook/synapse-engine.cjs /.claude/hooks/ Add to \`.claude/settings.local.json\`: -\`\`\`json +~~~json { "hooks": { "UserPromptSubmit": [ { "type": "command", - "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/synapse-engine.cjs\"", + "command": "node \\"$CLAUDE_PROJECT_DIR/.claude/hooks/synapse-engine.cjs\\"", "timeout": 10 } ] } } -\`\`\` +~~~ ### 4. Copy Runtime Domains diff --git a/scripts/validate-package-completeness.js b/scripts/validate-package-completeness.js index b60291e083..3931204a36 100644 --- a/scripts/validate-package-completeness.js +++ b/scripts/validate-package-completeness.js @@ -185,20 +185,20 @@ function validateTarballContents(tarballFiles) { check( `Required: ${required}`, found, - found ? undefined : `Not found in tarball (${tarballFiles.length} files scanned)` + found ? undefined : `Not found in tarball (${tarballFiles.length} files scanned)`, ); } // Check excluded paths do NOT exist for (const excluded of EXCLUDED_PATHS) { const leaked = tarballFiles.filter( - (f) => f.startsWith(excluded) || f.startsWith(`package/${excluded}`) + (f) => f.startsWith(excluded) || f.startsWith(`package/${excluded}`), ); check( `Excluded: ${excluded} not in tarball`, leaked.length === 0, - leaked.length > 0 ? `LEAK DETECTED: ${leaked.slice(0, 3).join(', ')}` : undefined + leaked.length > 0 ? `LEAK DETECTED: ${leaked.slice(0, 3).join(', ')}` : undefined, ); } } @@ -214,7 +214,7 @@ function validatePackageJson(pkg) { check( `files[] includes "${entry}"`, found, - found ? undefined : `Add "${entry}" to package.json "files" array` + found ? undefined : `Add "${entry}" to package.json "files" array`, ); } @@ -232,7 +232,7 @@ function validatePackageJson(pkg) { check( `bin.${name} -> ${binPath} exists`, exists, - exists ? undefined : `File not found: ${fullPath}` + exists ? undefined : `File not found: ${fullPath}`, ); } @@ -242,7 +242,7 @@ function validatePackageJson(pkg) { check( `dependency: ${dep}`, dep in deps, - dep in deps ? undefined : `Missing runtime dependency "${dep}"` + dep in deps ? undefined : `Missing runtime dependency "${dep}"`, ); } } @@ -267,7 +267,7 @@ function validateBinScripts() { check( `${name} (${binPath}) has correct shebang`, hasShebang, - hasShebang ? undefined : `Expected "#!/usr/bin/env node", got "${firstLine.substring(0, 40)}"` + hasShebang ? undefined : `Expected "#!/usr/bin/env node", got "${firstLine.substring(0, 40)}"`, ); } } diff --git a/squads/claude-code-mastery/scripts/validate-setup.js b/squads/claude-code-mastery/scripts/validate-setup.js index c34cfb071f..ff7c69ac77 100644 --- a/squads/claude-code-mastery/scripts/validate-setup.js +++ b/squads/claude-code-mastery/scripts/validate-setup.js @@ -118,7 +118,7 @@ const checks = [ (rule) => typeof rule === 'string' ? rule.includes('.env') - : rule.pattern && rule.pattern.includes('.env') + : rule.pattern && rule.pattern.includes('.env'), ); } catch { return false; @@ -130,7 +130,7 @@ const checks = [ let totalScore = 0; let maxScore = 0; -console.log(`\nClaude Code Setup Validation`); +console.log('\nClaude Code Setup Validation'); console.log(`Project: ${projectPath}`); console.log(`${'='.repeat(60)}\n`); diff --git a/tests/cli/validate-publish.test.js b/tests/cli/validate-publish.test.js index ef0c5efadf..4e522d344e 100644 --- a/tests/cli/validate-publish.test.js +++ b/tests/cli/validate-publish.test.js @@ -22,9 +22,9 @@ describe('Publish Safety Gate (Story INS-4.10)', () => { describe('AC1: Submodule validation', () => { test('script checks pro/ directory exists', () => { - expect(scriptSource).toContain("PRO_DIR"); + expect(scriptSource).toContain('PRO_DIR'); expect(scriptSource).toContain("'pro'"); - expect(scriptSource).toContain("fs.existsSync(PRO_DIR)"); + expect(scriptSource).toContain('fs.existsSync(PRO_DIR)'); }); test('script checks pro/ is not empty (filters .git)', () => { @@ -32,8 +32,8 @@ describe('Publish Safety Gate (Story INS-4.10)', () => { }); test('script checks critical file pro/license/license-api.js', () => { - expect(scriptSource).toContain("license-api.js"); - expect(scriptSource).toContain("fs.existsSync(CRITICAL_FILE)"); + expect(scriptSource).toContain('license-api.js'); + expect(scriptSource).toContain('fs.existsSync(CRITICAL_FILE)'); }); test('error message includes fix command for submodule', () => { @@ -55,7 +55,7 @@ describe('Publish Safety Gate (Story INS-4.10)', () => { }); test('uses npm pack --dry-run for file counting', () => { - expect(scriptSource).toContain("npm pack --dry-run"); + expect(scriptSource).toContain('npm pack --dry-run'); }); test('error message includes file count on failure', () => { diff --git a/tests/code-intel/creation-helper.test.js b/tests/code-intel/creation-helper.test.js index 489f7d9ca1..af8cf9a55e 100644 --- a/tests/code-intel/creation-helper.test.js +++ b/tests/code-intel/creation-helper.test.js @@ -437,7 +437,7 @@ describe('CreationHelper', () => { const msg = _formatDuplicateWarning( 'my-task', { matches: [{ file: 'tasks/similar.md' }] }, - [{ file: 'agents/user.md', line: 2 }] + [{ file: 'agents/user.md', line: 2 }], ); expect(msg).toContain('Similar artefact exists: tasks/similar.md'); @@ -449,7 +449,7 @@ describe('CreationHelper', () => { const msg = _formatDuplicateWarning( 'my-task', { matches: [{ file: 'tasks/old.md' }] }, - null + null, ); expect(msg).toContain('Similar artefact exists'); @@ -460,7 +460,7 @@ describe('CreationHelper', () => { const msg = _formatDuplicateWarning( 'my-task', null, - [{ file: 'index.js', line: 5 }] + [{ file: 'index.js', line: 5 }], ); expect(msg).toContain('"my-task" already referenced'); @@ -471,7 +471,7 @@ describe('CreationHelper', () => { const msg = _formatDuplicateWarning( 'task', { matches: [{ path: 'alt/path.md' }] }, - null + null, ); expect(msg).toContain('Similar artefact exists: alt/path.md'); diff --git a/tests/code-intel/dev-helper.test.js b/tests/code-intel/dev-helper.test.js index c006e671c9..460c57a4c0 100644 --- a/tests/code-intel/dev-helper.test.js +++ b/tests/code-intel/dev-helper.test.js @@ -347,7 +347,7 @@ describe('DevHelper', () => { it('should format with both duplicates and refs', () => { const msg = _formatSuggestion( { matches: [{ file: 'a.js', line: 1 }] }, - [{ file: 'b.js', line: 2 }] + [{ file: 'b.js', line: 2 }], ); expect(msg).toContain('1 similar match'); @@ -359,7 +359,7 @@ describe('DevHelper', () => { it('should format with only duplicates', () => { const msg = _formatSuggestion( { matches: [{ file: 'a.js' }] }, - null + null, ); expect(msg).toContain('1 similar match'); diff --git a/tests/code-intel/registry-syncer.test.js b/tests/code-intel/registry-syncer.test.js index e5b06b45a4..45fe96774a 100644 --- a/tests/code-intel/registry-syncer.test.js +++ b/tests/code-intel/registry-syncer.test.js @@ -115,7 +115,7 @@ describe('RegistrySyncer', () => { expect(fs.writeFileSync).toHaveBeenCalledWith( expect.stringContaining('.tmp'), expect.any(String), - 'utf8' + 'utf8', ); expect(fs.renameSync).toHaveBeenCalled(); }); @@ -160,7 +160,7 @@ describe('RegistrySyncer', () => { const result = await syncer.syncEntity( { id: 'test-entity', category: 'tasks', data: entities.tasks['test-entity'] }, entities, - true + true, ); expect(result).toBe(true); @@ -280,11 +280,11 @@ describe('RegistrySyncer', () => { await syncer.syncEntity( { id: 'test-entity', category: 'tasks', data: entities.tasks['test-entity'] }, entities, - true + true, ); expect(entities.tasks['test-entity'].codeIntelMetadata.callerCount).toBe( - entities.tasks['test-entity'].usedBy.length + entities.tasks['test-entity'].usedBy.length, ); }); @@ -318,7 +318,7 @@ describe('RegistrySyncer', () => { expect(stats.aborted).toBe(true); expect(stats.processed).toBe(0); expect(logger).toHaveBeenCalledWith( - expect.stringContaining('No code intelligence provider available') + expect.stringContaining('No code intelligence provider available'), ); // Registry should NOT be written expect(fs.writeFileSync).not.toHaveBeenCalled(); @@ -424,7 +424,7 @@ describe('RegistrySyncer', () => { // renameSync should be called to replace original expect(fs.renameSync).toHaveBeenCalledWith( expect.stringContaining('.tmp'), - '/mock/entity-registry.yaml' + '/mock/entity-registry.yaml', ); }); diff --git a/tests/config/schema-validation.test.js b/tests/config/schema-validation.test.js index 00a2323d36..dfbef0eaa3 100644 --- a/tests/config/schema-validation.test.js +++ b/tests/config/schema-validation.test.js @@ -74,7 +74,7 @@ describe('schema-validation — enriched schemas', () => { const validate = ajv.compile(schema); const isValid = validate(data); if (!isValid) { - // eslint-disable-next-line no-console + console.log('Validation errors:', validate.errors); } expect(isValid).toBe(true); @@ -141,7 +141,7 @@ describe('schema-validation — enriched schemas', () => { const validate = ajv.compile(schema); const isValid = validate(data); if (!isValid) { - // eslint-disable-next-line no-console + console.log('Validation errors:', validate.errors); } expect(isValid).toBe(true); @@ -191,7 +191,7 @@ describe('schema-validation — enriched schemas', () => { const isValid = validate(data); expect(isValid).toBe(false); const fieldError = validate.errors.find( - (e) => e.instancePath === '/boundary/frameworkProtection' + (e) => e.instancePath === '/boundary/frameworkProtection', ); expect(fieldError).toBeDefined(); expect(fieldError.message).toContain('boolean'); @@ -207,7 +207,7 @@ describe('schema-validation — enriched schemas', () => { const isValid = validate(data); expect(isValid).toBe(false); expect( - validate.errors.some((e) => e.params?.missingProperty === 'frameworkProtection') + validate.errors.some((e) => e.params?.missingProperty === 'frameworkProtection'), ).toBe(true); }); }); diff --git a/tests/config/template-overrides.test.js b/tests/config/template-overrides.test.js index 065ded5bb7..2a44f18d03 100644 --- a/tests/config/template-overrides.test.js +++ b/tests/config/template-overrides.test.js @@ -86,7 +86,7 @@ describe('template-overrides — consumer helper', () => { }, }; expect(() => getTemplateOverrides(config)).toThrow( - /Unknown story section ID.*nonexistent-section/ + /Unknown story section ID.*nonexistent-section/, ); }); @@ -99,7 +99,7 @@ describe('template-overrides — consumer helper', () => { }, }; expect(() => getTemplateOverrides(config)).toThrow( - /Unknown story section ID.*invalid-id/ + /Unknown story section ID.*invalid-id/, ); }); diff --git a/tests/core/health-check/base-check.test.js b/tests/core/health-check/base-check.test.js index ba10e23043..54229a2560 100644 --- a/tests/core/health-check/base-check.test.js +++ b/tests/core/health-check/base-check.test.js @@ -67,7 +67,7 @@ describe('base-check', () => { describe('constructor', () => { test('throws when instantiated directly', () => { expect(() => new BaseCheck({ - id: 'test', name: 'Test', domain: 'project', severity: 'HIGH' + id: 'test', name: 'Test', domain: 'project', severity: 'HIGH', })).toThrow('BaseCheck is abstract'); }); diff --git a/tests/core/health-check/check-registry.test.js b/tests/core/health-check/check-registry.test.js index 184fbfa13f..70b17673ae 100644 --- a/tests/core/health-check/check-registry.test.js +++ b/tests/core/health-check/check-registry.test.js @@ -68,7 +68,7 @@ describe('check-registry', () => { test('throws for duplicate id', () => { registry.register(new ProjectCheck('dup')); - expect(() => registry.register(new ProjectCheck('dup'))).toThrow("already registered"); + expect(() => registry.register(new ProjectCheck('dup'))).toThrow('already registered'); }); test('indexes check by domain', () => { diff --git a/tests/core/registry/build-registry.test.js b/tests/core/registry/build-registry.test.js index 9e5ee4a658..25844e4d32 100644 --- a/tests/core/registry/build-registry.test.js +++ b/tests/core/registry/build-registry.test.js @@ -207,7 +207,7 @@ describe('buildRegistry', () => { return []; }); fs.readFile.mockResolvedValue( - '/**\n * @description Loads configuration from YAML files\n * @version 1.0\n */' + '/**\n * @description Loads configuration from YAML files\n * @version 1.0\n */', ); const registry = await buildRegistry('/fake'); @@ -221,7 +221,7 @@ describe('buildRegistry', () => { return []; }); fs.readFile.mockResolvedValue( - '/**\n * Validates YAML configuration files\n *\n * @module validator\n */' + '/**\n * Validates YAML configuration files\n *\n * @module validator\n */', ); const registry = await buildRegistry('/fake'); @@ -963,7 +963,7 @@ describe('saveRegistry', () => { expect(fs.writeFile).toHaveBeenCalledWith( '/output/registry.json', JSON.stringify(registry, null, 2), - 'utf8' + 'utf8', ); }); diff --git a/tests/graph-dashboard/code-intel-source.test.js b/tests/graph-dashboard/code-intel-source.test.js index 550ad2e980..c44ae29d24 100644 --- a/tests/graph-dashboard/code-intel-source.test.js +++ b/tests/graph-dashboard/code-intel-source.test.js @@ -71,7 +71,7 @@ describe('CodeIntelSource', () => { expect.arrayContaining([ expect.objectContaining({ from: 'task-a', to: 'task-b', type: 'depends' }), expect.objectContaining({ from: 'dev', to: 'task-a', type: 'depends' }), - ]) + ]), ); }); @@ -126,7 +126,7 @@ describe('CodeIntelSource', () => { expect(result.nodes).toHaveLength(2); expect(result.edges).toEqual( - expect.arrayContaining([expect.objectContaining({ from: 'a', to: 'b' })]) + expect.arrayContaining([expect.objectContaining({ from: 'a', to: 'b' })]), ); }); @@ -158,10 +158,10 @@ describe('CodeIntelSource', () => { expect.arrayContaining([ expect.objectContaining({ id: 'mod-x' }), expect.objectContaining({ id: 'mod-y' }), - ]) + ]), ); expect(result.edges).toEqual( - expect.arrayContaining([expect.objectContaining({ from: 'mod-x', to: 'mod-y' })]) + expect.arrayContaining([expect.objectContaining({ from: 'mod-x', to: 'mod-y' })]), ); }); }); diff --git a/tests/graph-dashboard/html-formatter.test.js b/tests/graph-dashboard/html-formatter.test.js index 6bba673866..d2657789ae 100644 --- a/tests/graph-dashboard/html-formatter.test.js +++ b/tests/graph-dashboard/html-formatter.test.js @@ -139,7 +139,7 @@ describe('html-formatter', () => { describe('_sanitize', () => { it('should escape HTML special characters', () => { expect(_sanitize('')).toBe( - '<script>alert("xss")</script>' + '<script>alert("xss")</script>', ); }); @@ -429,7 +429,7 @@ describe('html-formatter', () => { if (style.colorOverride !== null) { expect( style.colorOverride === THEME.text.tertiary || - style.colorOverride === THEME.text.muted + style.colorOverride === THEME.text.muted, ).toBe(true); } } diff --git a/tests/graph-dashboard/tree-renderer.test.js b/tests/graph-dashboard/tree-renderer.test.js index 81013f4a38..2a6e0a2895 100644 --- a/tests/graph-dashboard/tree-renderer.test.js +++ b/tests/graph-dashboard/tree-renderer.test.js @@ -45,7 +45,7 @@ describe('tree-renderer', () => { { id: 'task-a', label: 'task-a', type: 'task', path: 'a.md', category: 'tasks' }, { id: 'task-b', label: 'task-b', type: 'task', path: 'b.md', category: 'tasks' }, ], - [{ from: 'task-a', to: 'task-b', type: 'depends' }] + [{ from: 'task-a', to: 'task-b', type: 'depends' }], ); const output = renderTree(data); @@ -111,7 +111,7 @@ describe('tree-renderer', () => { const data = makeGraphData( [{ id: 'x', label: 'x', type: 'task', path: 'x.md', category: 'tasks' }], [], - { isFallback: false } + { isFallback: false }, ); const output = renderTree(data); @@ -129,7 +129,7 @@ describe('tree-renderer', () => { const data = makeGraphData(nodes); const output = renderTree(data); - expect(output).toContain(`... (5 more)`); + expect(output).toContain('... (5 more)'); }); it('should not truncate branches within limit', () => { diff --git a/tests/ids/layer-classifier.test.js b/tests/ids/layer-classifier.test.js index 27f763b0a6..78ca1b65d4 100644 --- a/tests/ids/layer-classifier.test.js +++ b/tests/ids/layer-classifier.test.js @@ -5,7 +5,7 @@ */ const path = require('path'); const { classifyLayer, LAYER_RULES } = require( - path.resolve(__dirname, '../../.aiox-core/core/ids/layer-classifier') + path.resolve(__dirname, '../../.aiox-core/core/ids/layer-classifier'), ); describe('classifyLayer', () => { diff --git a/tests/ids/layer-integration.test.js b/tests/ids/layer-integration.test.js index 25f1869808..2b57c1a2fe 100644 --- a/tests/ids/layer-integration.test.js +++ b/tests/ids/layer-integration.test.js @@ -87,7 +87,7 @@ describe('Layer Preservation — Registry Healer (AC: 6)', () => { expect(healerContent).toContain('orphaned-usedBy'); // The healer should NOT have any code that strips or deletes the 'layer' field - expect(healerContent).not.toContain("delete entity.layer"); + expect(healerContent).not.toContain('delete entity.layer'); expect(healerContent).not.toContain("delete entity['layer']"); }); diff --git a/tests/installer/pro-scaffolder.test.js b/tests/installer/pro-scaffolder.test.js index 5cea2a0689..ec4b6f421b 100644 --- a/tests/installer/pro-scaffolder.test.js +++ b/tests/installer/pro-scaffolder.test.js @@ -37,19 +37,19 @@ beforeEach(async () => { await fs.ensureDir(path.join(proSourceDir, 'squads', 'devops-squad')); await fs.writeFile( path.join(proSourceDir, 'squads', 'devops-squad', 'squad.yaml'), - yaml.dump({ name: 'devops-squad', version: '1.0.0' }) + yaml.dump({ name: 'devops-squad', version: '1.0.0' }), ); await fs.writeFile( path.join(proSourceDir, 'pro-config.yaml'), - yaml.dump({ pro: { enabled: true, tier: 'standard' } }) + yaml.dump({ pro: { enabled: true, tier: 'standard' } }), ); await fs.writeFile( path.join(proSourceDir, 'feature-registry.yaml'), - yaml.dump({ features: [{ id: 'squads-pro', enabled: true }] }) + yaml.dump({ features: [{ id: 'squads-pro', enabled: true }] }), ); await fs.writeJson( path.join(proSourceDir, 'package.json'), - { name: '@aiox-fullstack/pro', version: '2.0.0' } + { name: '@aiox-fullstack/pro', version: '2.0.0' }, ); }); @@ -67,17 +67,17 @@ describe('scaffoldProContent', () => { // AC1: squads exist expect(await fs.pathExists( - path.join(targetDir, 'squads', 'devops-squad', 'squad.yaml') + path.join(targetDir, 'squads', 'devops-squad', 'squad.yaml'), )).toBe(true); // AC2: pro-config.yaml exists in .aiox-core/ expect(await fs.pathExists( - path.join(targetDir, '.aiox-core', 'pro-config.yaml') + path.join(targetDir, '.aiox-core', 'pro-config.yaml'), )).toBe(true); // AC3: feature-registry.yaml exists in .aiox-core/ expect(await fs.pathExists( - path.join(targetDir, '.aiox-core', 'feature-registry.yaml') + path.join(targetDir, '.aiox-core', 'feature-registry.yaml'), )).toBe(true); }); @@ -119,7 +119,7 @@ describe('scaffoldProContent', () => { // Verify file content is still correct (not corrupted) const configContent = yaml.load( - await fs.readFile(path.join(targetDir, '.aiox-core', 'pro-config.yaml'), 'utf8') + await fs.readFile(path.join(targetDir, '.aiox-core', 'pro-config.yaml'), 'utf8'), ); expect(configContent.pro.enabled).toBe(true); }); @@ -138,7 +138,7 @@ describe('scaffoldProContent', () => { // Verify rollback: squads copied before failure should be cleaned up expect(await fs.pathExists( - path.join(targetDir, 'squads', 'devops-squad', 'squad.yaml') + path.join(targetDir, 'squads', 'devops-squad', 'squad.yaml'), )).toBe(false); // pro-version.json and pro-installed-manifest.yaml should not exist @@ -240,7 +240,7 @@ describe('generateProVersionJson', () => { const versionInfo = await generateProVersionJson( targetDir, proSourceDir, - ['test.yaml'] + ['test.yaml'], ); expect(versionInfo.proVersion).toBe('2.0.0'); @@ -256,7 +256,7 @@ describe('generateInstalledManifest', () => { const manifest = await generateInstalledManifest( targetDir, - ['manifest-test.yaml'] + ['manifest-test.yaml'], ); expect(manifest.totalFiles).toBe(1); diff --git a/tests/integration/code-intel/helpers-with-registry.test.js b/tests/integration/code-intel/helpers-with-registry.test.js index 8fd5ce8692..4e0f409c96 100644 --- a/tests/integration/code-intel/helpers-with-registry.test.js +++ b/tests/integration/code-intel/helpers-with-registry.test.js @@ -200,7 +200,7 @@ describe('AC8: Helper Functions Return Real Data with RegistryProvider', () => { // Log for visibility for (const r of results) { const status = r.result !== null ? 'non-null' : 'NULL'; - // eslint-disable-next-line no-console + console.log(` ${r.name}: ${status}`); } diff --git a/tests/integration/codex-skills-sync.test.js b/tests/integration/codex-skills-sync.test.js index f467df2a94..222be08617 100644 --- a/tests/integration/codex-skills-sync.test.js +++ b/tests/integration/codex-skills-sync.test.js @@ -7,6 +7,7 @@ const path = require('path'); const { syncSkills, buildSkillContent, + getLegacySkillId, } = require('../../.aiox-core/infrastructure/scripts/codex-skills-sync/index'); describe('Codex Skills Sync', () => { @@ -89,4 +90,9 @@ describe('Codex Skills Sync', () => { expect(content).toContain('name: aiox-dev'); expect(content).toContain('`*help` - Show commands'); }); + + it('derives legacy aliases for migrated core agents', () => { + expect(getLegacySkillId('dev')).toBe('aios-dev'); + expect(getLegacySkillId('aiox-master')).toBe('aios-master'); + }); }); diff --git a/tests/integration/onboarding-smoke.test.js b/tests/integration/onboarding-smoke.test.js index 10942ba590..afcb28af2f 100644 --- a/tests/integration/onboarding-smoke.test.js +++ b/tests/integration/onboarding-smoke.test.js @@ -87,7 +87,7 @@ describe('Onboarding smoke flow (AIOX-DIFF-4.0.5)', () => { const greeting = runNode(greetingScript, ['dev'], repoRoot); const elapsedSeconds = (Date.now() - startedAt) / 1000; - expect(greeting).toContain('Agent dev loaded'); + expect(greeting).toMatch(/Agent dev loaded|dev Agent ready/); // Greeting may use full format ("Available Commands:") or fallback ("*help") expect(greeting).toMatch(/Available Commands|\*help/); diff --git a/tests/memory/memory-format.test.js b/tests/memory/memory-format.test.js index 3f9472ddc0..40e6698cf3 100644 --- a/tests/memory/memory-format.test.js +++ b/tests/memory/memory-format.test.js @@ -7,7 +7,7 @@ const AGENTS_DIR = path.join(__dirname, '..', '..', '.aiox-core', 'development', const AGENT_IDS = [ 'dev', 'qa', 'devops', 'architect', 'po', 'pm', - 'analyst', 'sm', 'data-engineer', 'ux' + 'analyst', 'sm', 'data-engineer', 'ux', ]; describe('MEMORY.md Structured Format', () => { diff --git a/tests/pro-recover.test.js b/tests/pro-recover.test.js index 85f285d179..4123b76912 100644 --- a/tests/pro-recover.test.js +++ b/tests/pro-recover.test.js @@ -204,7 +204,7 @@ describe('CLI alias reset-password', () => { // Verify the CLI entry point has reset-password as a case that calls recoverLicense const cliSource = require('fs').readFileSync( require('path').join(__dirname, '../packages/aiox-pro-cli/bin/aiox-pro.js'), - 'utf-8' + 'utf-8', ); // Both cases should exist in the same switch block expect(cliSource).toContain("case 'recover':"); @@ -216,7 +216,7 @@ describe('CLI alias reset-password', () => { test('showHelp includes reset-password as alias for recover', () => { const cliSource = require('fs').readFileSync( require('path').join(__dirname, '../packages/aiox-pro-cli/bin/aiox-pro.js'), - 'utf-8' + 'utf-8', ); expect(cliSource).toMatch(/reset-password\s+.*alias/i); }); diff --git a/tests/synapse/benchmarks/wave6-journey.js b/tests/synapse/benchmarks/wave6-journey.js index 74d89a4712..4f6fc8fa80 100644 --- a/tests/synapse/benchmarks/wave6-journey.js +++ b/tests/synapse/benchmarks/wave6-journey.js @@ -426,7 +426,7 @@ function generateDiffMarkdown(beforeTag, afterTag, diffs) { } function writeReport(content) { - const header = `# Wave 6 — Performance Journey Log\n\n> Auto-generated by \`wave6-journey.js\`. Do not edit manually.\n\n---\n\n`; + const header = '# Wave 6 — Performance Journey Log\n\n> Auto-generated by `wave6-journey.js`. Do not edit manually.\n\n---\n\n'; if (!fs.existsSync(REPORT_PATH)) { fs.writeFileSync(REPORT_PATH, header + content, 'utf8'); diff --git a/tests/synapse/bridge/uap-session-bridge.test.js b/tests/synapse/bridge/uap-session-bridge.test.js index 7fc8194ac8..cfefc9d233 100644 --- a/tests/synapse/bridge/uap-session-bridge.test.js +++ b/tests/synapse/bridge/uap-session-bridge.test.js @@ -260,7 +260,7 @@ describe('UAP Session Bridge — Error Handling', () => { expect(warnSpy).toHaveBeenCalledTimes(1); expect(warnSpy).toHaveBeenCalledWith( - expect.stringContaining('[UnifiedActivationPipeline] SYNAPSE session write failed:') + expect.stringContaining('[UnifiedActivationPipeline] SYNAPSE session write failed:'), ); warnSpy.mockRestore(); @@ -548,7 +548,7 @@ describe('UAP Session Bridge — Timing Budget', () => { fs.rmSync(skipCtx.projectRoot, { recursive: true, force: true }); expect(skipMetrics.loaders.synapseSession.duration).toBeLessThanOrEqual( - writeMetrics.loaders.synapseSession.duration + 1 // +1ms tolerance + writeMetrics.loaders.synapseSession.duration + 1, // +1ms tolerance ); }); }); diff --git a/tests/synapse/diagnostics/collectors.test.js b/tests/synapse/diagnostics/collectors.test.js index f375e0aa8f..392553d872 100644 --- a/tests/synapse/diagnostics/collectors.test.js +++ b/tests/synapse/diagnostics/collectors.test.js @@ -26,7 +26,7 @@ jest.mock( domainNameToFile: jest.fn((name) => name.toLowerCase().replace(/_/g, '-')), KNOWN_SUFFIXES: [], GLOBAL_KEYS: [], - }) + }), ); const { collectHookStatus } = require('../../../.aiox-core/core/synapse/diagnostics/collectors/hook-collector'); @@ -79,7 +79,7 @@ describe('hook-collector: collectHookStatus', () => { // Create the hook file so check 2 + 3 also pass writeFile( path.join(tmpDir, '.claude', 'hooks', 'synapse-engine.cjs'), - 'module.exports = {};' + 'module.exports = {};', ); const result = collectHookStatus(tmpDir); @@ -118,7 +118,7 @@ describe('hook-collector: collectHookStatus', () => { }); writeFile( path.join(tmpDir, '.claude', 'hooks', 'synapse-engine.cjs'), - '// hook\nmodule.exports = {};' + '// hook\nmodule.exports = {};', ); const result = collectHookStatus(tmpDir); @@ -147,7 +147,7 @@ describe('hook-collector: collectHookStatus', () => { }); writeFile( path.join(tmpDir, '.claude', 'hooks', 'synapse-engine.cjs'), - 'module.exports = {};' + 'module.exports = {};', ); const result = collectHookStatus(tmpDir); @@ -178,7 +178,7 @@ describe('hook-collector: collectHookStatus', () => { }); writeFile( path.join(tmpDir, '.claude', 'hooks', 'synapse-engine.cjs'), - 'module.exports = {};' + 'module.exports = {};', ); const result = collectHookStatus(tmpDir); @@ -190,7 +190,7 @@ describe('hook-collector: collectHookStatus', () => { test('handles malformed JSON in settings.local.json', () => { writeFile( path.join(tmpDir, '.claude', 'settings.local.json'), - '{ invalid json' + '{ invalid json', ); const result = collectHookStatus(tmpDir); diff --git a/tests/synapse/e2e/pipeline-audit.e2e.js b/tests/synapse/e2e/pipeline-audit.e2e.js index 882843998c..543080f16b 100644 --- a/tests/synapse/e2e/pipeline-audit.e2e.js +++ b/tests/synapse/e2e/pipeline-audit.e2e.js @@ -147,7 +147,7 @@ async function auditAgentActivation(agents = ALL_AGENTS, runs = RUNS_PER_AGENT) for (let i = 0; i < runs; i++) { try { const { result, duration } = await timedRunAsync(() => - UnifiedActivationPipeline.activate(agentId) + UnifiedActivationPipeline.activate(agentId), ); timings.push(duration); qualities.push(result?.quality || 'unknown'); @@ -256,7 +256,7 @@ async function auditSessionSimulation(agents = SESSION_SIM_AGENTS, prompts = SES // Run SYNAPSE pipeline const { result: synapseResult, duration: synapseDuration } = await timedRunAsync(() => - engine.process(`Simulated prompt ${promptIdx} for ${agentId}`, session) + engine.process(`Simulated prompt ${promptIdx} for ${agentId}`, session), ); const metricsSummary = synapseResult?.metrics || {}; @@ -319,7 +319,7 @@ async function auditSessionSimulation(agents = SESSION_SIM_AGENTS, prompts = SES console.log(` ${agentId}: default=${transitions.length} transitions (final=${snapshots[snapshots.length - 1]?.bracket}), small=${smallTransitions.length} transitions (final=${snapshots[snapshots.length - 1]?.smallBracket}), avgSynapse=${results[agentId].summary.avgSynapseDuration.toFixed(2)}ms`); if (smallTransitions.length > 1) { - console.log(` Small context transitions:`); + console.log(' Small context transitions:'); smallTransitions.forEach(t => console.log(` prompt ${t.prompt}: ${t.from || 'START'} → ${t.to}`)); } } @@ -480,25 +480,25 @@ async function auditSynapseRules() { // Run engine for FRESH bracket (layers [0,1,2,7]) const freshSession = { prompt_count: bracketPromptCounts.FRESH, active_agent: { id: 'dev' }, context: {} }; const { result: freshResult, duration: freshDuration } = await timedRunAsync(() => - engine.process('Audit prompt for FRESH bracket', freshSession) + engine.process('Audit prompt for FRESH bracket', freshSession), ); // Run engine for MODERATE bracket (all 8 layers) const moderateSession = { prompt_count: bracketPromptCounts.MODERATE, active_agent: { id: 'dev' }, context: {} }; const { result: moderateResult, duration: moderateDuration } = await timedRunAsync(() => - engine.process('Audit prompt for MODERATE bracket', moderateSession) + engine.process('Audit prompt for MODERATE bracket', moderateSession), ); // Run engine for DEPLETED bracket (all layers + memory hints) const depletedSession = { prompt_count: bracketPromptCounts.DEPLETED, active_agent: { id: 'dev' }, context: {} }; const { result: depletedResult, duration: depletedDuration } = await timedRunAsync(() => - engine.process('Audit prompt for DEPLETED bracket', depletedSession) + engine.process('Audit prompt for DEPLETED bracket', depletedSession), ); // Run engine for CRITICAL bracket (all layers + memory + handoff) const criticalSession = { prompt_count: bracketPromptCounts.CRITICAL, active_agent: { id: 'dev' }, context: {} }; const { result: criticalResult, duration: criticalDuration } = await timedRunAsync(() => - engine.process('Audit prompt for CRITICAL bracket', criticalSession) + engine.process('Audit prompt for CRITICAL bracket', criticalSession), ); function analyzeResult(result, label, bracket) { @@ -671,7 +671,7 @@ async function auditProjectStatus(iterations = PROJECT_STATUS_ITERATIONS) { } else if (recommended) { results.recommendation = `TIMEOUT ${recommended.timeout}ms covers 95%+ of cases. Current 20ms is too aggressive.`; } else { - results.recommendation = `Consider restructuring: no timeout value covers 95% of commands.`; + results.recommendation = 'Consider restructuring: no timeout value covers 95% of commands.'; } console.log(` Total estimated p50: ${totalP50.toFixed(0)}ms`); @@ -804,7 +804,7 @@ function classifyFeatures(auditData) { 0, gitData.fullDetect?.stats?.p50 || 0, gitData.fullDetect?.stats?.p50 > 50 ? 'OPTIMIZE' : 'KEEP', - 'Branch awareness is essential for context. But _isGitRepository() execSync is overhead — use .git/HEAD existence check instead.' + 'Branch awareness is essential for context. But _isGitRepository() execSync is overhead — use .git/HEAD existence check instead.', ); } @@ -816,7 +816,7 @@ function classifyFeatures(auditData) { 0, psData.estimatedTotalP50 || 0, psData.estimatedTotalP50 > 100 ? 'OPTIMIZE' : 'KEEP', - `Provides commit/branch/dirty status for greeting. Takes ~${(psData.estimatedTotalP50 || 0).toFixed(0)}ms. Often times out at 20ms budget.` + `Provides commit/branch/dirty status for greeting. Takes ~${(psData.estimatedTotalP50 || 0).toFixed(0)}ms. Often times out at 20ms budget.`, ); } @@ -883,26 +883,26 @@ with sub-millisecond precision, classifying each feature as ESSENTIAL, USEFUL, C // AC1: Agent Activation if (auditData.agentActivation && !auditData.agentActivation.skipped) { - md += `## 1. Agent Activation (All Agents)\n\n`; - md += `| Agent | p50 (ms) | p95 (ms) | Quality | Slowest Loader | Slowest (ms) |\n`; - md += `|-------|----------|----------|---------|----------------|-------------|\n`; + md += '## 1. Agent Activation (All Agents)\n\n'; + md += '| Agent | p50 (ms) | p95 (ms) | Quality | Slowest Loader | Slowest (ms) |\n'; + md += '|-------|----------|----------|---------|----------------|-------------|\n'; for (const [agentId, data] of Object.entries(auditData.agentActivation)) { const primaryQ = Object.entries(data.qualityCounts || {}).sort((a, b) => b[1] - a[1])[0]?.[0] || 'unknown'; md += `| ${agentId} | ${data.timing.p50.toFixed(1)} | ${data.timing.p95.toFixed(1)} | ${primaryQ} | ${data.slowestLoader?.name || 'n/a'} | ${(data.slowestLoader?.avgDuration || 0).toFixed(1)} |\n`; } - md += `\n**Targets:** warm p50 <150ms, cold p95 <250ms\n\n`; + md += '\n**Targets:** warm p50 <150ms, cold p95 <250ms\n\n'; } // AC2: Session Simulation if (auditData.sessionSimulation) { - md += `## 2. Multi-Prompt Session Simulation\n\n`; - md += `> **Note:** With default maxContext=200000 tokens, each prompt uses only ~0.9% of context.\n`; - md += `> 15 prompts = ~13.5% used → stays FRESH. This is correct behavior.\n`; - md += `> A "small context" (20k) scenario shows bracket transitions working correctly.\n\n`; + md += '## 2. Multi-Prompt Session Simulation\n\n'; + md += '> **Note:** With default maxContext=200000 tokens, each prompt uses only ~0.9% of context.\n'; + md += '> 15 prompts = ~13.5% used → stays FRESH. This is correct behavior.\n'; + md += '> A "small context" (20k) scenario shows bracket transitions working correctly.\n\n'; for (const [agentId, data] of Object.entries(auditData.sessionSimulation)) { md += `### Agent: ${agentId}\n\n`; - md += `| Prompt | Bracket (200k) | Context% | Small Bracket (20k) | Small% | Layers | Rules | Tokens | SYNAPSE (ms) |\n`; - md += `|--------|---------------|----------|--------------------|---------| ------|-------|--------|-------------|\n`; + md += '| Prompt | Bracket (200k) | Context% | Small Bracket (20k) | Small% | Layers | Rules | Tokens | SYNAPSE (ms) |\n'; + md += '|--------|---------------|----------|--------------------|---------| ------|-------|--------|-------------|\n'; for (const snap of data.snapshots) { md += `| ${snap.promptIdx} | ${snap.bracket} | ${snap.contextPercent.toFixed(1)}% | ${snap.smallBracket} | ${(snap.smallContextPercent || 0).toFixed(1)}% | ${snap.activeLayers.join(',')} | ${snap.totalRules} | ${snap.estimatedTokens} | ${snap.synapseDuration.toFixed(2)} |\n`; } @@ -914,56 +914,56 @@ with sub-millisecond precision, classifying each feature as ESSENTIAL, USEFUL, C // AC3: Git Detection if (auditData.gitDetection) { const git = auditData.gitDetection; - md += `## 3. Git Detection Diagnostic\n\n`; - md += `| Method | p50 (ms) | p95 (ms) | p99 (ms) |\n`; - md += `|--------|----------|----------|----------|\n`; + md += '## 3. Git Detection Diagnostic\n\n'; + md += '| Method | p50 (ms) | p95 (ms) | p99 (ms) |\n'; + md += '|--------|----------|----------|----------|\n'; md += `| .git/HEAD direct read | ${git.directRead.stats.p50.toFixed(3)} | ${git.directRead.stats.p95.toFixed(3)} | ${git.directRead.stats.p99.toFixed(3)} |\n`; md += `| execSync (rev-parse HEAD) | ${git.execSync.stats.p50.toFixed(1)} | ${git.execSync.stats.p95.toFixed(1)} | ${git.execSync.stats.p99.toFixed(1)} |\n`; md += `| _isGitRepository (execSync) | ${git.isGitRepository.stats.p50.toFixed(1)} | ${git.isGitRepository.stats.p95.toFixed(1)} | ${git.isGitRepository.stats.p99.toFixed(1)} |\n`; md += `| Full detect() | ${git.fullDetect.stats.p50.toFixed(1)} | ${git.fullDetect.stats.p95.toFixed(1)} | ${git.fullDetect.stats.p99.toFixed(1)} |\n`; md += `| Cached get() | ${git.cachedGet.stats.p50.toFixed(3)} | ${git.cachedGet.stats.p95.toFixed(3)} | ${git.cachedGet.stats.p99.toFixed(3)} |\n`; md += `\n**Diagnosis:** ${git.diagnosis}\n\n`; - md += `**Key Finding:** The journey data showing 35-131ms gitConfig times is caused by \`_isGitRepository()\` calling \`execSync('git rev-parse --is-inside-work-tree')\` before the fast \`.git/HEAD\` read. The direct read itself is <1ms.\n\n`; + md += '**Key Finding:** The journey data showing 35-131ms gitConfig times is caused by `_isGitRepository()` calling `execSync(\'git rev-parse --is-inside-work-tree\')` before the fast `.git/HEAD` read. The direct read itself is <1ms.\n\n'; } // AC4: SYNAPSE Rules if (auditData.synapseRules) { - md += `## 4. SYNAPSE Rule Impact Analysis\n\n`; - md += `| Bracket | Rules | Tokens (est) | Adjusted (*1.2) | Layers Active | Layers Producing | Duration (ms) |\n`; - md += `|---------|-------|-------------|----------------|---------------|-----------------|---------------|\n`; + md += '## 4. SYNAPSE Rule Impact Analysis\n\n'; + md += '| Bracket | Rules | Tokens (est) | Adjusted (*1.2) | Layers Active | Layers Producing | Duration (ms) |\n'; + md += '|---------|-------|-------------|----------------|---------------|-----------------|---------------|\n'; for (const bracket of ['FRESH', 'MODERATE', 'DEPLETED', 'CRITICAL']) { const data = auditData.synapseRules[bracket]; if (data) { md += `| ${bracket} | ${data.totalRules} | ${data.estimatedTokens} | ${data.adjustedTokens} | ${data.layersAttempted}/8 | ${data.layersLoaded}/8 | ${data.totalDuration.toFixed(2)} |\n`; } } - md += `\n`; - md += `> **Note:** "Layers Active" = layers the bracket filter allows to execute. "Layers Producing" = layers that returned rules.\n`; - md += `> Layers 3-6 (workflow, task, squad, keyword) require active session context (workflow, task, squad, matching keywords) to produce rules.\n`; - md += `> In this audit with no active workflow/task/squad, only L0 (constitution), L1 (global), L2 (agent) produce rules regardless of bracket.\n`; - md += `> The bracket filter is working correctly: FRESH allows 4 layers (0,1,2,7), MODERATE+ allows all 8.\n\n`; + md += '\n'; + md += '> **Note:** "Layers Active" = layers the bracket filter allows to execute. "Layers Producing" = layers that returned rules.\n'; + md += '> Layers 3-6 (workflow, task, squad, keyword) require active session context (workflow, task, squad, matching keywords) to produce rules.\n'; + md += '> In this audit with no active workflow/task/squad, only L0 (constitution), L1 (global), L2 (agent) produce rules regardless of bracket.\n'; + md += '> The bracket filter is working correctly: FRESH allows 4 layers (0,1,2,7), MODERATE+ allows all 8.\n\n'; // Per-layer breakdown for MODERATE (all layers attempted) const mod = auditData.synapseRules.MODERATE; if (mod?.perLayer) { - md += `### Per-Layer Breakdown (MODERATE — all 8 layers attempted)\n\n`; - md += `| Layer | Bracket Active | Status | Rules | Skip Reason | Duration (ms) |\n`; - md += `|-------|---------------|--------|-------|-------------|---------------|\n`; + md += '### Per-Layer Breakdown (MODERATE — all 8 layers attempted)\n\n'; + md += '| Layer | Bracket Active | Status | Rules | Skip Reason | Duration (ms) |\n'; + md += '|-------|---------------|--------|-------|-------------|---------------|\n'; for (const [name, data] of Object.entries(mod.perLayer)) { md += `| ${name} | ${data.bracketActive ? 'YES' : 'no'} | ${data.status} | ${data.rules || 0} | ${data.skipReason || '-'} | ${(data.duration || 0).toFixed(3)} |\n`; } - md += `\n`; + md += '\n'; // Also show FRESH for comparison const fresh = auditData.synapseRules.FRESH; if (fresh?.perLayer) { - md += `### Per-Layer Breakdown (FRESH — 4 layers attempted)\n\n`; - md += `| Layer | Bracket Active | Status | Rules | Skip Reason | Duration (ms) |\n`; - md += `|-------|---------------|--------|-------|-------------|---------------|\n`; + md += '### Per-Layer Breakdown (FRESH — 4 layers attempted)\n\n'; + md += '| Layer | Bracket Active | Status | Rules | Skip Reason | Duration (ms) |\n'; + md += '|-------|---------------|--------|-------|-------------|---------------|\n'; for (const [name, data] of Object.entries(fresh.perLayer)) { md += `| ${name} | ${data.bracketActive ? 'YES' : 'no'} | ${data.status} | ${data.rules || 0} | ${data.skipReason || '-'} | ${(data.duration || 0).toFixed(3)} |\n`; } - md += `\n`; + md += '\n'; } } } @@ -971,18 +971,18 @@ with sub-millisecond precision, classifying each feature as ESSENTIAL, USEFUL, C // AC5: projectStatus if (auditData.projectStatus) { const ps = auditData.projectStatus; - md += `## 5. projectStatus Root Cause Analysis\n\n`; - md += `| Git Command | p50 (ms) | p95 (ms) |\n`; - md += `|-------------|----------|----------|\n`; + md += '## 5. projectStatus Root Cause Analysis\n\n'; + md += '| Git Command | p50 (ms) | p95 (ms) |\n'; + md += '|-------------|----------|----------|\n'; for (const [name, s] of Object.entries(ps.commandTimings)) { md += `| \`${name}\` | ${s.p50.toFixed(1)} | ${s.p95.toFixed(1)} |\n`; } md += `\n**Slowest:** \`${ps.slowestCommand.name}\` (p50=${ps.slowestCommand.p50.toFixed(0)}ms)\n`; md += `**Total estimated p50:** ${ps.estimatedTotalP50.toFixed(0)}ms\n`; md += `**fsmonitor:** ${ps.fsmonitorEnabled ? 'ENABLED' : 'disabled'}\n\n`; - md += `### Timeout Coverage Analysis\n\n`; - md += `| Timeout (ms) | Commands Within | Coverage |\n`; - md += `|-------------|-----------------|----------|\n`; + md += '### Timeout Coverage Analysis\n\n'; + md += '| Timeout (ms) | Commands Within | Coverage |\n'; + md += '|-------------|-----------------|----------|\n'; for (const t of ps.timeoutAnalysis) { md += `| ${t.timeout} | ${t.commandsWithinTimeout}/${t.totalCommands} | ${t.coveragePercent}% |\n`; } @@ -991,27 +991,27 @@ with sub-millisecond precision, classifying each feature as ESSENTIAL, USEFUL, C // AC6: Token Estimation if (auditData.tokenEstimation) { - md += `## 6. Token Estimation Accuracy\n\n`; - md += `| Content Type | Chars | Est. Tokens | Adjusted (*1.2) | Chars/Token |\n`; - md += `|-------------|-------|-------------|----------------|------------|\n`; + md += '## 6. Token Estimation Accuracy\n\n'; + md += '| Content Type | Chars | Est. Tokens | Adjusted (*1.2) | Chars/Token |\n'; + md += '|-------------|-------|-------------|----------------|------------|\n'; for (const s of auditData.tokenEstimation.samples) { md += `| ${s.name} | ${s.chars} | ${s.estimatedTokens} | ${s.adjustedTokens} | ${s.charsPerTokenRatio} |\n`; } - md += `\n**Formula:** \`Math.ceil(text.length / 4)\` with \`1.2x\` XML safety multiplier\n`; + md += '\n**Formula:** `Math.ceil(text.length / 4)` with `1.2x` XML safety multiplier\n'; if (auditData.tokenEstimation.existingSessions?.length > 0) { - md += `\n**Existing sessions with prompt_count > 0:**\n`; + md += '\n**Existing sessions with prompt_count > 0:**\n'; for (const s of auditData.tokenEstimation.existingSessions) { md += `- ${s.file}: prompt_count=${s.promptCount}, bracket=${s.lastBracket}, tokens_used=${s.lastTokensUsed}\n`; } } - md += `\n`; + md += '\n'; } // AC7: Classification Report if (classifications) { - md += `## 7. Feature Classification Report\n\n`; - md += `| Feature | Category | Tokens | Time (ms) | Verdict | Rationale |\n`; - md += `|---------|----------|--------|-----------|---------|-----------|\n`; + md += '## 7. Feature Classification Report\n\n'; + md += '| Feature | Category | Tokens | Time (ms) | Verdict | Rationale |\n'; + md += '|---------|----------|--------|-----------|---------|-----------|\n'; for (const c of classifications) { md += `| ${c.name} | ${c.category} | ${c.tokens} | ${c.timeMs.toFixed(1)} | ${c.verdict} | ${c.rationale.substring(0, 80)}${c.rationale.length > 80 ? '...' : ''} |\n`; } @@ -1025,34 +1025,34 @@ with sub-millisecond precision, classifying each feature as ESSENTIAL, USEFUL, C const cosmeticTokens = classifications.filter(c => c.category === 'COSMETIC').reduce((s, c) => s + c.tokens, 0); const totalTokens = classifications.reduce((s, c) => s + c.tokens, 0); - md += `\n### Summary\n\n`; - md += `| Category | Count | Tokens | % of Total |\n`; - md += `|----------|-------|--------|------------|\n`; + md += '\n### Summary\n\n'; + md += '| Category | Count | Tokens | % of Total |\n'; + md += '|----------|-------|--------|------------|\n'; md += `| ESSENTIAL | ${essentialCount} | ${essentialTokens} | ${totalTokens > 0 ? (essentialTokens / totalTokens * 100).toFixed(0) : 0}% |\n`; md += `| USEFUL | ${usefulCount} | ${classifications.filter(c => c.category === 'USEFUL').reduce((s, c) => s + c.tokens, 0)} | ${totalTokens > 0 ? (classifications.filter(c => c.category === 'USEFUL').reduce((s, c) => s + c.tokens, 0) / totalTokens * 100).toFixed(0) : 0}% |\n`; md += `| COSMETIC | ${cosmeticCount} | ${cosmeticTokens} | ${totalTokens > 0 ? (cosmeticTokens / totalTokens * 100).toFixed(0) : 0}% |\n`; md += `| OVERHEAD | ${overheadCount} | ${classifications.filter(c => c.category === 'OVERHEAD').reduce((s, c) => s + c.tokens, 0)} | n/a |\n`; - md += `\n`; + md += '\n'; } // Recommendations - md += `## 8. Recommendations\n\n`; - md += `### Top Optimization Targets\n\n`; - md += `1. **Git Detection:** Replace \`_isGitRepository()\` execSync with \`.git/HEAD\` existence check (saves ~50ms)\n`; - md += `2. **projectStatus Timeout:** Increase from 20ms or restructure to run fewer/async git commands\n`; - md += `3. **SYNAPSE Token Budget:** Review cosmetic layers in FRESH bracket — only L0,L1,L2,L7 are loaded but still may carry persona/greeting overhead\n\n`; - - md += `### "Lean Activation" Scenario\n\n`; - md += `If we stripped everything non-essential (COSMETIC + OVERHEAD):\n`; + md += '## 8. Recommendations\n\n'; + md += '### Top Optimization Targets\n\n'; + md += '1. **Git Detection:** Replace `_isGitRepository()` execSync with `.git/HEAD` existence check (saves ~50ms)\n'; + md += '2. **projectStatus Timeout:** Increase from 20ms or restructure to run fewer/async git commands\n'; + md += '3. **SYNAPSE Token Budget:** Review cosmetic layers in FRESH bracket — only L0,L1,L2,L7 are loaded but still may carry persona/greeting overhead\n\n'; + + md += '### "Lean Activation" Scenario\n\n'; + md += 'If we stripped everything non-essential (COSMETIC + OVERHEAD):\n'; if (classifications) { const removableTokens = classifications.filter(c => c.category === 'COSMETIC' || c.category === 'OVERHEAD').reduce((s, c) => s + c.tokens, 0); const removableTime = classifications.filter(c => c.category === 'COSMETIC' || c.category === 'OVERHEAD').reduce((s, c) => s + c.timeMs, 0); md += `- **Tokens saved:** ~${removableTokens}\n`; md += `- **Time saved:** ~${removableTime.toFixed(0)}ms\n`; - md += `- **Note:** Cosmetic features (greeting, persona) serve UX purpose — removal not recommended unless context is critical\n\n`; + md += '- **Note:** Cosmetic features (greeting, persona) serve UX purpose — removal not recommended unless context is critical\n\n'; } - md += `---\n\n*Report generated by NOG-17 pipeline audit script*\n`; + md += '---\n\n*Report generated by NOG-17 pipeline audit script*\n'; return md; } @@ -1064,7 +1064,7 @@ async function main() { const args = process.argv.slice(2); const mode = args.find(a => a.startsWith('--')) || '--full'; - console.log(`\nNOG-17: E2E Pipeline Audit`); + console.log('\nNOG-17: E2E Pipeline Audit'); console.log(`Mode: ${mode}`); console.log(`Project: ${PROJECT_ROOT}`); console.log(`Timestamp: ${new Date().toISOString()}`); @@ -1076,7 +1076,7 @@ async function main() { // AC1: Agent Activation auditData.agentActivation = await auditAgentActivation( mode === '--quick' ? ['dev', 'qa', 'architect'] : ALL_AGENTS, - mode === '--quick' ? 1 : RUNS_PER_AGENT + mode === '--quick' ? 1 : RUNS_PER_AGENT, ); // AC4: SYNAPSE Rule Analysis (always fast, no agents needed) @@ -1126,14 +1126,14 @@ async function main() { data: auditData, classifications, }); - console.log(`\nRaw data saved: .synapse/metrics/audit/NOG-17-raw.json`); + console.log('\nRaw data saved: .synapse/metrics/audit/NOG-17-raw.json'); // Generate report (full mode only) if (mode === '--full') { const report = generateReport(auditData, classifications); ensureDir(path.dirname(REPORT_PATH)); fs.writeFileSync(REPORT_PATH, report, 'utf8'); - console.log(`Report saved: docs/qa/NOG-17-pipeline-audit-report.md`); + console.log('Report saved: docs/qa/NOG-17-pipeline-audit-report.md'); } console.log('\nAudit complete.'); diff --git a/tests/synapse/engine.test.js b/tests/synapse/engine.test.js index 348e75085e..f1a0ada340 100644 --- a/tests/synapse/engine.test.js +++ b/tests/synapse/engine.test.js @@ -241,13 +241,15 @@ describe('SynapseEngine', () => { }); test('should instantiate available layers', () => { - // L0, L1, L2, L3 are mocked as available; L4-L7 throw + // The engine must always load the core bracket layers and may also load + // optional layers when they exist in the repository/runtime. expect(engine.layers.length).toBeGreaterThanOrEqual(3); }); - test('should handle all layer modules failing gracefully', () => { - // This is tested implicitly — L4-L7 throw, engine still works - expect(engine.layers.length).toBeLessThanOrEqual(4); + test('should remain resilient as optional layer availability evolves', () => { + // Optional layers may exist or not depending on the current Synapse + // rollout. The constructor should never instantiate more than L0-L7. + expect(engine.layers.length).toBeLessThanOrEqual(8); }); }); diff --git a/tests/synapse/hook-runtime.test.js b/tests/synapse/hook-runtime.test.js index b6f1c9baa5..aef0ee521d 100644 --- a/tests/synapse/hook-runtime.test.js +++ b/tests/synapse/hook-runtime.test.js @@ -70,7 +70,7 @@ describe('hook-runtime', () => { fs.mkdirSync(path.join(cwd, '.synapse', 'sessions'), { recursive: true }); // Mock session-manager with prompt_count: 0 and trackable cleanStaleSessions - let cleanupCalled = false; + const cleanupCalled = false; writeFile( path.join(cwd, '.aiox-core/core/synapse/session/session-manager.js'), [ diff --git a/tests/unit/codex-skills-validate.test.js b/tests/unit/codex-skills-validate.test.js index bbf469d25f..03e113eb92 100644 --- a/tests/unit/codex-skills-validate.test.js +++ b/tests/unit/codex-skills-validate.test.js @@ -87,4 +87,22 @@ describe('Codex Skills Validator', () => { expect(result.ok).toBe(false); expect(result.orphaned).toContain('aiox-legacy'); }); + + it('fails in strict mode when a legacy aios-* alias dir exists for a core agent', () => { + syncSkills({ sourceDir, localSkillsDir: skillsDir, dryRun: false }); + const legacyPath = path.join(skillsDir, 'aios-dev'); + fs.mkdirSync(legacyPath, { recursive: true }); + fs.writeFileSync(path.join(legacyPath, 'SKILL.md'), '# legacy', 'utf8'); + + const result = validateCodexSkills({ + projectRoot: tmpRoot, + sourceDir, + skillsDir, + strict: true, + }); + + expect(result.ok).toBe(false); + expect(result.legacy).toContain('aios-dev'); + expect(result.errors.some(error => error.includes('Legacy skill alias directory'))).toBe(true); + }); }); diff --git a/tests/unit/tok5-analytics.test.js b/tests/unit/tok5-analytics.test.js index 89777181f1..d0e9893cc3 100644 --- a/tests/unit/tok5-analytics.test.js +++ b/tests/unit/tok5-analytics.test.js @@ -14,7 +14,7 @@ const { validateEvent, pruneOldEntries, generateSampleData, - RETENTION_DAYS + RETENTION_DAYS, } = require('../../.aiox-core/infrastructure/scripts/collect-tool-usage'); const { @@ -22,7 +22,7 @@ const { generateRecommendations, generateReport, aggregateUsage, - DEFAULT_THRESHOLDS + DEFAULT_THRESHOLDS, } = require('../../.aiox-core/infrastructure/scripts/generate-optimization-report'); // --- Helpers --- @@ -33,7 +33,7 @@ function makeSession(id, events, daysAgo = 0) { session_id: id, timestamp: ts.toISOString(), event_count: events.length, - events + events, }; } @@ -108,7 +108,7 @@ describe('collect-tool-usage.js', () => { it('keeps sessions within retention window', () => { const sessions = [ makeSession('recent', [makeEvent('Read', 1, 100, 50, 'test-session', 5)], 5), - makeSession('old', [makeEvent('Read', 1, 100, 50, 'test-session', 40)], 40) + makeSession('old', [makeEvent('Read', 1, 100, 50, 'test-session', 40)], 40), ]; const { pruned, removed } = pruneOldEntries(sessions); expect(pruned).toHaveLength(1); @@ -119,7 +119,7 @@ describe('collect-tool-usage.js', () => { it('returns empty for all-old sessions', () => { const sessions = [ makeSession('old1', [makeEvent('Read', 1, 100, 50, 'test-session', 35)], 35), - makeSession('old2', [makeEvent('Read', 1, 100, 50, 'test-session', 60)], 60) + makeSession('old2', [makeEvent('Read', 1, 100, 50, 'test-session', 60)], 60), ]; const { pruned, removed } = pruneOldEntries(sessions); expect(pruned).toHaveLength(0); @@ -153,31 +153,31 @@ describe('generate-optimization-report.js', () => { Write: { tier: 1, tokenCost: 200 }, Bash: { tier: 1, tokenCost: 300 }, git: { tier: 2, tokenCost: 100 }, - exa: { tier: 3, tokenCost: 500 } - } + exa: { tier: 3, tokenCost: 500 }, + }, }; const mockBaseline = { frameworkOverhead: { totalEstimatedTokens: 26143 }, workflows: { 'Story Development Cycle (SDC)': { - median: { totalTokens: 188000 } - } + median: { totalTokens: 188000 }, + }, }, comparison: { aioxActual: { overheadPercentOfTypicalSession: { - 'Story Development Cycle (SDC)': 13.9 - } - } - } + 'Story Development Cycle (SDC)': 13.9, + }, + }, + }, }; describe('aggregateUsage', () => { it('aggregates tool stats across sessions', () => { const sessions = [ makeSession('s1', [makeEvent('Read', 5, 1000, 500), makeEvent('Write', 3, 600, 300)]), - makeSession('s2', [makeEvent('Read', 8, 1600, 800)]) + makeSession('s2', [makeEvent('Read', 8, 1600, 800)]), ]; const { toolStats, sessionCount } = aggregateUsage(sessions); expect(sessionCount).toBe(2); @@ -190,7 +190,7 @@ describe('generate-optimization-report.js', () => { it('calculates averages correctly', () => { const sessions = [ makeSession('s1', [makeEvent('Read', 10, 2000, 1000)]), - makeSession('s2', [makeEvent('Read', 20, 4000, 2000)]) + makeSession('s2', [makeEvent('Read', 20, 4000, 2000)]), ]; const { toolStats } = aggregateUsage(sessions); expect(toolStats.Read.avg_invocations_per_session).toBe(15); @@ -211,8 +211,8 @@ describe('generate-optimization-report.js', () => { it('calculates static overhead from registry tokenCost (C1 fix)', () => { const usageData = { sessions: [ - makeSession('s1', [makeEvent('Read', 5, 1000, 500), makeEvent('Bash', 3, 900, 600)]) - ] + makeSession('s1', [makeEvent('Read', 5, 1000, 500), makeEvent('Bash', 3, 900, 600)]), + ], }; const result = compareBaseline(mockBaseline, usageData, mockRegistry); expect(result.available).toBe(true); @@ -226,8 +226,8 @@ describe('generate-optimization-report.js', () => { it('uses fallback when no registry provided', () => { const usageData = { sessions: [ - makeSession('s1', [makeEvent('Read', 5, 1000, 500)]) - ] + makeSession('s1', [makeEvent('Read', 5, 1000, 500)]), + ], }; const result = compareBaseline(mockBaseline, usageData, null); expect(result.available).toBe(true); @@ -237,7 +237,7 @@ describe('generate-optimization-report.js', () => { it('includes dynamic_usage section', () => { const usageData = { - sessions: [makeSession('s1', [makeEvent('Read', 5, 1000, 500)])] + sessions: [makeSession('s1', [makeEvent('Read', 5, 1000, 500)])], }; const result = compareBaseline(mockBaseline, usageData, mockRegistry); expect(result.dynamic_usage).toBeDefined(); @@ -248,7 +248,7 @@ describe('generate-optimization-report.js', () => { it('correctly assigns target status', () => { // With Read(200) only = 200 post-opt vs 26143 baseline = 99% reduction const usageData = { - sessions: [makeSession('s1', [makeEvent('Read', 1, 200, 100)])] + sessions: [makeSession('s1', [makeEvent('Read', 1, 200, 100)])], }; const result = compareBaseline(mockBaseline, usageData, mockRegistry); expect(result.target_25_45_pct).toBe('ACHIEVED'); @@ -338,11 +338,11 @@ describe('generate-optimization-report.js', () => { available: true, absolute_reduction_tokens: 25000, percentage_reduction: 95.6, - target_25_45_pct: 'ACHIEVED' + target_25_45_pct: 'ACHIEVED', }; const recs = [ { action: 'promote', tool_name: 'git' }, - { action: 'demote', tool_name: 'ffmpeg' } + { action: 'demote', tool_name: 'ffmpeg' }, ]; const usageData = { sessions: [makeSession('s1', [makeEvent('Read', 1, 100, 50)])] }; const report = generateReport(comparison, recs, usageData, DEFAULT_THRESHOLDS);