@nerviq/cli 1.17.3 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -23
- package/README.md +4 -4
- package/bin/cli.js +61 -274
- package/package.json +60 -60
- package/src/activity.js +1039 -1039
- package/src/adoption-advisor.js +299 -299
- package/src/aider/config-parser.js +166 -166
- package/src/aider/context.js +158 -158
- package/src/aider/deep-review.js +316 -316
- package/src/aider/domain-packs.js +303 -303
- package/src/aider/freshness.js +93 -93
- package/src/aider/governance.js +253 -253
- package/src/aider/interactive.js +334 -334
- package/src/aider/mcp-packs.js +329 -329
- package/src/aider/patch.js +214 -214
- package/src/aider/plans.js +186 -186
- package/src/aider/premium.js +360 -360
- package/src/aider/setup.js +404 -404
- package/src/aider/techniques.js +16 -16
- package/src/analyze.js +951 -951
- package/src/anti-patterns.js +485 -485
- package/src/audit/instruction-files.js +180 -180
- package/src/audit/recommendations.js +577 -577
- package/src/auto-suggest.js +154 -154
- package/src/badge.js +13 -13
- package/src/behavioral-drift.js +801 -801
- package/src/benchmark.js +67 -67
- package/src/catalog.js +103 -103
- package/src/certification.js +128 -128
- package/src/codex/config-parser.js +183 -183
- package/src/codex/context.js +223 -223
- package/src/codex/deep-review.js +493 -493
- package/src/codex/domain-packs.js +394 -394
- package/src/codex/freshness.js +84 -84
- package/src/codex/governance.js +192 -192
- package/src/codex/interactive.js +618 -618
- package/src/codex/mcp-packs.js +914 -914
- package/src/codex/patch.js +209 -209
- package/src/codex/plans.js +251 -251
- package/src/codex/premium.js +614 -614
- package/src/codex/setup.js +591 -591
- package/src/context.js +320 -320
- package/src/continuous-ops.js +681 -681
- package/src/copilot/activity.js +309 -309
- package/src/copilot/config-parser.js +280 -226
- package/src/copilot/context.js +218 -197
- package/src/copilot/deep-review.js +346 -346
- package/src/copilot/domain-packs.js +372 -372
- package/src/copilot/freshness.js +57 -57
- package/src/copilot/governance.js +222 -222
- package/src/copilot/interactive.js +406 -406
- package/src/copilot/mcp-packs.js +826 -826
- package/src/copilot/plans.js +253 -253
- package/src/copilot/premium.js +451 -451
- package/src/copilot/setup.js +488 -488
- package/src/copilot/techniques.js +219 -78
- package/src/cost-tracking.js +61 -61
- package/src/cursor/activity.js +301 -301
- package/src/cursor/config-parser.js +265 -265
- package/src/cursor/context.js +256 -256
- package/src/cursor/deep-review.js +334 -334
- package/src/cursor/domain-packs.js +368 -368
- package/src/cursor/freshness.js +65 -65
- package/src/cursor/governance.js +229 -229
- package/src/cursor/interactive.js +391 -391
- package/src/cursor/mcp-packs.js +828 -828
- package/src/cursor/plans.js +254 -254
- package/src/cursor/premium.js +469 -469
- package/src/cursor/setup.js +488 -488
- package/src/dashboard.js +493 -493
- package/src/deep-review.js +428 -428
- package/src/deprecation.js +98 -98
- package/src/diff-only.js +280 -280
- package/src/doctor.js +119 -119
- package/src/domain-pack-expansion.js +1033 -1033
- package/src/domain-packs.js +387 -387
- package/src/feedback.js +178 -178
- package/src/fix-engine.js +783 -0
- package/src/fix-prompts.js +122 -122
- package/src/formatters/sarif.js +115 -115
- package/src/freshness.js +74 -74
- package/src/gemini/config-parser.js +275 -275
- package/src/gemini/context.js +221 -221
- package/src/gemini/deep-review.js +559 -559
- package/src/gemini/domain-packs.js +393 -393
- package/src/gemini/freshness.js +66 -66
- package/src/gemini/governance.js +201 -201
- package/src/gemini/interactive.js +860 -860
- package/src/gemini/mcp-packs.js +915 -915
- package/src/gemini/plans.js +269 -269
- package/src/gemini/premium.js +760 -760
- package/src/gemini/setup.js +692 -692
- package/src/gemini/techniques.js +14 -14
- package/src/governance.js +72 -72
- package/src/harmony/add.js +68 -68
- package/src/harmony/advisor.js +333 -333
- package/src/harmony/canon.js +565 -565
- package/src/harmony/cli.js +591 -591
- package/src/harmony/drift.js +401 -401
- package/src/harmony/governance.js +313 -313
- package/src/harmony/memory.js +239 -239
- package/src/harmony/sync.js +475 -475
- package/src/harmony/watch.js +370 -370
- package/src/hook-validation.js +342 -342
- package/src/index.js +271 -271
- package/src/init.js +184 -184
- package/src/instruction-surfaces.js +185 -185
- package/src/integrations.js +144 -144
- package/src/interactive.js +118 -118
- package/src/locales/en.json +1 -1
- package/src/locales/es.json +1 -1
- package/src/mcp-packs.js +830 -830
- package/src/mcp-server.js +726 -726
- package/src/mcp-validation.js +337 -337
- package/src/nerviq-sync.json +7 -7
- package/src/opencode/config-parser.js +109 -109
- package/src/opencode/context.js +247 -247
- package/src/opencode/deep-review.js +313 -313
- package/src/opencode/domain-packs.js +262 -262
- package/src/opencode/freshness.js +66 -66
- package/src/opencode/governance.js +159 -159
- package/src/opencode/interactive.js +392 -392
- package/src/opencode/mcp-packs.js +705 -705
- package/src/opencode/patch.js +184 -184
- package/src/opencode/plans.js +231 -231
- package/src/opencode/premium.js +413 -413
- package/src/opencode/setup.js +449 -449
- package/src/opencode/techniques.js +27 -27
- package/src/operating-profile.js +574 -574
- package/src/org.js +152 -152
- package/src/permission-rules.js +218 -218
- package/src/plans.js +839 -839
- package/src/platform-change-manifest.js +86 -86
- package/src/plugins.js +110 -110
- package/src/policy-layers.js +210 -210
- package/src/profiles.js +124 -124
- package/src/prompt-injection.js +74 -74
- package/src/public-api.js +173 -173
- package/src/recommendation-rules.js +84 -84
- package/src/repo-archetype.js +386 -386
- package/src/secret-patterns.js +39 -39
- package/src/server.js +527 -527
- package/src/setup/analysis.js +607 -607
- package/src/setup/runtime.js +172 -172
- package/src/setup.js +677 -677
- package/src/shared/capabilities.js +194 -194
- package/src/source-urls.js +132 -132
- package/src/stack-checks.js +565 -565
- package/src/supplemental-checks.js +13 -13
- package/src/synergy/adaptive.js +261 -261
- package/src/synergy/compensation.js +137 -137
- package/src/synergy/evidence.js +193 -193
- package/src/synergy/learning.js +199 -199
- package/src/synergy/patterns.js +227 -227
- package/src/synergy/ranking.js +83 -83
- package/src/synergy/report.js +165 -165
- package/src/synergy/routing.js +146 -146
- package/src/techniques/api.js +407 -407
- package/src/techniques/automation.js +316 -316
- package/src/techniques/compliance.js +257 -257
- package/src/techniques/hygiene.js +294 -294
- package/src/techniques/instructions.js +243 -243
- package/src/techniques/observability.js +226 -226
- package/src/techniques/optimization.js +142 -142
- package/src/techniques/quality.js +318 -318
- package/src/techniques/security.js +237 -237
- package/src/techniques/shared.js +443 -443
- package/src/techniques/stacks.js +2294 -2294
- package/src/techniques/tools.js +106 -106
- package/src/techniques/workflow.js +413 -413
- package/src/techniques.js +81 -81
- package/src/terminology.js +73 -73
- package/src/token-estimate.js +35 -35
- package/src/usage-patterns.js +99 -99
- package/src/verification-metadata.js +145 -145
- package/src/watch.js +247 -247
- package/src/windsurf/activity.js +302 -302
- package/src/windsurf/config-parser.js +267 -267
- package/src/windsurf/context.js +249 -249
- package/src/windsurf/deep-review.js +337 -337
- package/src/windsurf/domain-packs.js +370 -370
- package/src/windsurf/freshness.js +36 -36
- package/src/windsurf/governance.js +231 -231
- package/src/windsurf/interactive.js +388 -388
- package/src/windsurf/mcp-packs.js +792 -792
- package/src/windsurf/plans.js +247 -247
- package/src/windsurf/premium.js +468 -468
- package/src/windsurf/setup.js +471 -471
- package/src/windsurf/techniques.js +17 -17
- package/src/workspace.js +375 -375
package/src/synergy/report.js
CHANGED
|
@@ -1,165 +1,165 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S7. Synergy Dashboard / Report
|
|
3
|
-
*
|
|
4
|
-
* Formats synergy analysis as CLI output showing amplification,
|
|
5
|
-
* per-platform contribution, active and untapped synergies, and trends.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { compoundAudit, calculateAmplification } = require('./evidence');
|
|
9
|
-
const { analyzeCompensation } = require('./compensation');
|
|
10
|
-
const { discoverPatterns } = require('./patterns');
|
|
11
|
-
const { rankRecommendations } = require('./ranking');
|
|
12
|
-
|
|
13
|
-
const COLORS = {
|
|
14
|
-
reset: '\x1b[0m',
|
|
15
|
-
bold: '\x1b[1m',
|
|
16
|
-
dim: '\x1b[2m',
|
|
17
|
-
red: '\x1b[31m',
|
|
18
|
-
green: '\x1b[32m',
|
|
19
|
-
yellow: '\x1b[33m',
|
|
20
|
-
blue: '\x1b[36m',
|
|
21
|
-
magenta: '\x1b[35m',
|
|
22
|
-
white: '\x1b[37m',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function c(text, color) {
|
|
26
|
-
return `${COLORS[color] || ''}${text}${COLORS.reset}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function progressBar(score, max = 100, width = 20) {
|
|
30
|
-
const clamped = Math.min(max, Math.max(0, score));
|
|
31
|
-
const filled = Math.round((clamped / max) * width);
|
|
32
|
-
const empty = width - filled;
|
|
33
|
-
const color = score >= 70 ? 'green' : score >= 40 ? 'yellow' : 'red';
|
|
34
|
-
return c('\u2588'.repeat(filled), color) + c('\u2591'.repeat(empty), 'dim');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Format the synergy report for CLI output.
|
|
39
|
-
*
|
|
40
|
-
* @param {Object} options
|
|
41
|
-
* @param {Object} options.platformAudits - Audit results per platform
|
|
42
|
-
* @param {string[]} options.activePlatforms - Active platform names
|
|
43
|
-
* @param {Object[]} [options.harmonyHistory] - Historical harmony data
|
|
44
|
-
* @param {Object[]} [options.recommendations] - Aggregated recommendations
|
|
45
|
-
* @returns {string} Formatted CLI report
|
|
46
|
-
*/
|
|
47
|
-
function formatSynergyReport(options) {
|
|
48
|
-
const { platformAudits, activePlatforms, harmonyHistory, recommendations } = options;
|
|
49
|
-
const lines = [];
|
|
50
|
-
|
|
51
|
-
// Header
|
|
52
|
-
lines.push('');
|
|
53
|
-
lines.push(c(' ╔══════════════════════════════════════════════════╗', 'blue'));
|
|
54
|
-
lines.push(c(' ║ SYNERGY DASHBOARD [EXPERIMENTAL] ║', 'blue'));
|
|
55
|
-
lines.push(c(' ╚══════════════════════════════════════════════════╝', 'blue'));
|
|
56
|
-
lines.push(c(' Static routing rules. Learned routing planned for v2.0.', 'dim'));
|
|
57
|
-
lines.push(c(' Harmony is the GA cross-platform surface. Treat Synergy as advisory research output.', 'dim'));
|
|
58
|
-
lines.push('');
|
|
59
|
-
|
|
60
|
-
// Compound audit
|
|
61
|
-
const compound = compoundAudit(platformAudits || {});
|
|
62
|
-
const amplification = calculateAmplification(platformAudits || {});
|
|
63
|
-
|
|
64
|
-
const ampColor = compound.amplification > 10 ? 'green'
|
|
65
|
-
: compound.amplification > 0 ? 'yellow' : 'red';
|
|
66
|
-
|
|
67
|
-
lines.push(c(' Synergy Score', 'bold'));
|
|
68
|
-
lines.push(` ${progressBar(compound.compoundScore, 150, 30)} ${c(compound.compoundScore + '/100', 'bold')}` +
|
|
69
|
-
(compound.amplification > 0
|
|
70
|
-
? ` ${c(`(+${compound.amplification} amplification)`, ampColor)}`
|
|
71
|
-
: ''));
|
|
72
|
-
lines.push(` Best single platform: ${compound.bestSingleScore}/100`);
|
|
73
|
-
lines.push(` Cross-validated findings: ${compound.crossValidated.length}`);
|
|
74
|
-
lines.push(` Total unique findings: ${compound.totalFindings}`);
|
|
75
|
-
lines.push('');
|
|
76
|
-
|
|
77
|
-
// Per-platform contribution
|
|
78
|
-
lines.push(c(' Per-Platform Contribution', 'bold'));
|
|
79
|
-
for (const platform of (activePlatforms || [])) {
|
|
80
|
-
const audit = (platformAudits || {})[platform];
|
|
81
|
-
const score = audit ? audit.score : 0;
|
|
82
|
-
const coverage = compound.coverageMap[platform] || { found: 0, unique: 0, shared: 0 };
|
|
83
|
-
lines.push(` ${c(platform.padEnd(10), 'blue')} ${progressBar(score, 100, 15)} ${score}/100 ` +
|
|
84
|
-
`${c(`unique: ${coverage.unique}`, 'dim')} ${c(`shared: ${coverage.shared}`, 'dim')}`);
|
|
85
|
-
}
|
|
86
|
-
lines.push('');
|
|
87
|
-
|
|
88
|
-
// Active synergies (compensations)
|
|
89
|
-
const compensation = analyzeCompensation(activePlatforms || [], platformAudits);
|
|
90
|
-
if (compensation.compensations.length > 0) {
|
|
91
|
-
lines.push(c(' Active Synergies', 'bold'));
|
|
92
|
-
const shown = compensation.compensations.slice(0, 5);
|
|
93
|
-
for (const comp of shown) {
|
|
94
|
-
lines.push(` ${c('\u2713', 'green')} ${comp.compensatedBy.platform} covers ${comp.weakness.platform}'s weakness in ${comp.weakness.label} ` +
|
|
95
|
-
`${c(`(+${comp.netBenefit} net benefit)`, 'green')}`);
|
|
96
|
-
}
|
|
97
|
-
if (compensation.compensations.length > 5) {
|
|
98
|
-
lines.push(c(` ... and ${compensation.compensations.length - 5} more`, 'dim'));
|
|
99
|
-
}
|
|
100
|
-
lines.push('');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Untapped synergies
|
|
104
|
-
if (compensation.uncoveredGaps.length > 0 || compensation.recommendedAdditions.length > 0) {
|
|
105
|
-
lines.push(c(' Untapped Synergies', 'bold'));
|
|
106
|
-
|
|
107
|
-
for (const gap of compensation.uncoveredGaps.slice(0, 3)) {
|
|
108
|
-
lines.push(` ${c('\u26A0', 'yellow')} No platform covers: ${gap.label}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
for (const rec of compensation.recommendedAdditions.slice(0, 2)) {
|
|
112
|
-
const areas = rec.wouldCover.map(w => w.label).join(', ');
|
|
113
|
-
lines.push(` ${c('\u2192', 'blue')} Add ${c(rec.platform, 'bold')} to cover: ${areas}`);
|
|
114
|
-
}
|
|
115
|
-
lines.push('');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Patterns (if history available)
|
|
119
|
-
if (Array.isArray(harmonyHistory) && harmonyHistory.length > 0) {
|
|
120
|
-
const { patterns } = discoverPatterns(harmonyHistory);
|
|
121
|
-
if (patterns.length > 0) {
|
|
122
|
-
lines.push(c(' Discovered Patterns', 'bold'));
|
|
123
|
-
for (const pattern of patterns.slice(0, 4)) {
|
|
124
|
-
const icon = pattern.type === 'recurring-failure' ? c('\u2717', 'red')
|
|
125
|
-
: pattern.type === 'sequence-effect' ? c('\u2194', 'blue')
|
|
126
|
-
: pattern.type === 'diminishing-returns' ? c('\u2193', 'yellow')
|
|
127
|
-
: c('\u2022', 'dim');
|
|
128
|
-
lines.push(` ${icon} ${pattern.description}`);
|
|
129
|
-
}
|
|
130
|
-
lines.push('');
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Top ranked recommendations
|
|
135
|
-
if (Array.isArray(recommendations) && recommendations.length > 0) {
|
|
136
|
-
const ranked = rankRecommendations(recommendations, activePlatforms || []);
|
|
137
|
-
if (ranked.length > 0) {
|
|
138
|
-
lines.push(c(' Top Synergy Recommendations', 'bold'));
|
|
139
|
-
for (const rec of ranked.slice(0, 5)) {
|
|
140
|
-
const platforms = (rec.applicablePlatforms || []).join(', ') || rec.platform || '?';
|
|
141
|
-
lines.push(` ${c(rec.synergyScore.toFixed(1).padStart(5), 'green')} ${rec.name || rec.description || rec.key} ${c(`[${platforms}]`, 'dim')}`);
|
|
142
|
-
}
|
|
143
|
-
lines.push('');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Verdict
|
|
148
|
-
lines.push(c(` Verdict: ${amplification.verdict.replace(/-/g, ' ')}`, 'bold'));
|
|
149
|
-
lines.push('');
|
|
150
|
-
|
|
151
|
-
return lines.join('\n');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Generate a full synergy report for a project directory.
|
|
156
|
-
* High-level entry point that runs compound audit + compensation + patterns.
|
|
157
|
-
*
|
|
158
|
-
* @param {Object} options - Same as formatSynergyReport options
|
|
159
|
-
* @returns {string} Formatted CLI report string
|
|
160
|
-
*/
|
|
161
|
-
function generateSynergyReport(options) {
|
|
162
|
-
return formatSynergyReport(options);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
module.exports = { generateSynergyReport, formatSynergyReport };
|
|
1
|
+
/**
|
|
2
|
+
* S7. Synergy Dashboard / Report
|
|
3
|
+
*
|
|
4
|
+
* Formats synergy analysis as CLI output showing amplification,
|
|
5
|
+
* per-platform contribution, active and untapped synergies, and trends.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { compoundAudit, calculateAmplification } = require('./evidence');
|
|
9
|
+
const { analyzeCompensation } = require('./compensation');
|
|
10
|
+
const { discoverPatterns } = require('./patterns');
|
|
11
|
+
const { rankRecommendations } = require('./ranking');
|
|
12
|
+
|
|
13
|
+
const COLORS = {
|
|
14
|
+
reset: '\x1b[0m',
|
|
15
|
+
bold: '\x1b[1m',
|
|
16
|
+
dim: '\x1b[2m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[36m',
|
|
21
|
+
magenta: '\x1b[35m',
|
|
22
|
+
white: '\x1b[37m',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function c(text, color) {
|
|
26
|
+
return `${COLORS[color] || ''}${text}${COLORS.reset}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function progressBar(score, max = 100, width = 20) {
|
|
30
|
+
const clamped = Math.min(max, Math.max(0, score));
|
|
31
|
+
const filled = Math.round((clamped / max) * width);
|
|
32
|
+
const empty = width - filled;
|
|
33
|
+
const color = score >= 70 ? 'green' : score >= 40 ? 'yellow' : 'red';
|
|
34
|
+
return c('\u2588'.repeat(filled), color) + c('\u2591'.repeat(empty), 'dim');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Format the synergy report for CLI output.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} options
|
|
41
|
+
* @param {Object} options.platformAudits - Audit results per platform
|
|
42
|
+
* @param {string[]} options.activePlatforms - Active platform names
|
|
43
|
+
* @param {Object[]} [options.harmonyHistory] - Historical harmony data
|
|
44
|
+
* @param {Object[]} [options.recommendations] - Aggregated recommendations
|
|
45
|
+
* @returns {string} Formatted CLI report
|
|
46
|
+
*/
|
|
47
|
+
function formatSynergyReport(options) {
|
|
48
|
+
const { platformAudits, activePlatforms, harmonyHistory, recommendations } = options;
|
|
49
|
+
const lines = [];
|
|
50
|
+
|
|
51
|
+
// Header
|
|
52
|
+
lines.push('');
|
|
53
|
+
lines.push(c(' ╔══════════════════════════════════════════════════╗', 'blue'));
|
|
54
|
+
lines.push(c(' ║ SYNERGY DASHBOARD [EXPERIMENTAL] ║', 'blue'));
|
|
55
|
+
lines.push(c(' ╚══════════════════════════════════════════════════╝', 'blue'));
|
|
56
|
+
lines.push(c(' Static routing rules. Learned routing planned for v2.0.', 'dim'));
|
|
57
|
+
lines.push(c(' Harmony is the GA cross-platform surface. Treat Synergy as advisory research output.', 'dim'));
|
|
58
|
+
lines.push('');
|
|
59
|
+
|
|
60
|
+
// Compound audit
|
|
61
|
+
const compound = compoundAudit(platformAudits || {});
|
|
62
|
+
const amplification = calculateAmplification(platformAudits || {});
|
|
63
|
+
|
|
64
|
+
const ampColor = compound.amplification > 10 ? 'green'
|
|
65
|
+
: compound.amplification > 0 ? 'yellow' : 'red';
|
|
66
|
+
|
|
67
|
+
lines.push(c(' Synergy Score', 'bold'));
|
|
68
|
+
lines.push(` ${progressBar(compound.compoundScore, 150, 30)} ${c(compound.compoundScore + '/100', 'bold')}` +
|
|
69
|
+
(compound.amplification > 0
|
|
70
|
+
? ` ${c(`(+${compound.amplification} amplification)`, ampColor)}`
|
|
71
|
+
: ''));
|
|
72
|
+
lines.push(` Best single platform: ${compound.bestSingleScore}/100`);
|
|
73
|
+
lines.push(` Cross-validated findings: ${compound.crossValidated.length}`);
|
|
74
|
+
lines.push(` Total unique findings: ${compound.totalFindings}`);
|
|
75
|
+
lines.push('');
|
|
76
|
+
|
|
77
|
+
// Per-platform contribution
|
|
78
|
+
lines.push(c(' Per-Platform Contribution', 'bold'));
|
|
79
|
+
for (const platform of (activePlatforms || [])) {
|
|
80
|
+
const audit = (platformAudits || {})[platform];
|
|
81
|
+
const score = audit ? audit.score : 0;
|
|
82
|
+
const coverage = compound.coverageMap[platform] || { found: 0, unique: 0, shared: 0 };
|
|
83
|
+
lines.push(` ${c(platform.padEnd(10), 'blue')} ${progressBar(score, 100, 15)} ${score}/100 ` +
|
|
84
|
+
`${c(`unique: ${coverage.unique}`, 'dim')} ${c(`shared: ${coverage.shared}`, 'dim')}`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('');
|
|
87
|
+
|
|
88
|
+
// Active synergies (compensations)
|
|
89
|
+
const compensation = analyzeCompensation(activePlatforms || [], platformAudits);
|
|
90
|
+
if (compensation.compensations.length > 0) {
|
|
91
|
+
lines.push(c(' Active Synergies', 'bold'));
|
|
92
|
+
const shown = compensation.compensations.slice(0, 5);
|
|
93
|
+
for (const comp of shown) {
|
|
94
|
+
lines.push(` ${c('\u2713', 'green')} ${comp.compensatedBy.platform} covers ${comp.weakness.platform}'s weakness in ${comp.weakness.label} ` +
|
|
95
|
+
`${c(`(+${comp.netBenefit} net benefit)`, 'green')}`);
|
|
96
|
+
}
|
|
97
|
+
if (compensation.compensations.length > 5) {
|
|
98
|
+
lines.push(c(` ... and ${compensation.compensations.length - 5} more`, 'dim'));
|
|
99
|
+
}
|
|
100
|
+
lines.push('');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Untapped synergies
|
|
104
|
+
if (compensation.uncoveredGaps.length > 0 || compensation.recommendedAdditions.length > 0) {
|
|
105
|
+
lines.push(c(' Untapped Synergies', 'bold'));
|
|
106
|
+
|
|
107
|
+
for (const gap of compensation.uncoveredGaps.slice(0, 3)) {
|
|
108
|
+
lines.push(` ${c('\u26A0', 'yellow')} No platform covers: ${gap.label}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const rec of compensation.recommendedAdditions.slice(0, 2)) {
|
|
112
|
+
const areas = rec.wouldCover.map(w => w.label).join(', ');
|
|
113
|
+
lines.push(` ${c('\u2192', 'blue')} Add ${c(rec.platform, 'bold')} to cover: ${areas}`);
|
|
114
|
+
}
|
|
115
|
+
lines.push('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Patterns (if history available)
|
|
119
|
+
if (Array.isArray(harmonyHistory) && harmonyHistory.length > 0) {
|
|
120
|
+
const { patterns } = discoverPatterns(harmonyHistory);
|
|
121
|
+
if (patterns.length > 0) {
|
|
122
|
+
lines.push(c(' Discovered Patterns', 'bold'));
|
|
123
|
+
for (const pattern of patterns.slice(0, 4)) {
|
|
124
|
+
const icon = pattern.type === 'recurring-failure' ? c('\u2717', 'red')
|
|
125
|
+
: pattern.type === 'sequence-effect' ? c('\u2194', 'blue')
|
|
126
|
+
: pattern.type === 'diminishing-returns' ? c('\u2193', 'yellow')
|
|
127
|
+
: c('\u2022', 'dim');
|
|
128
|
+
lines.push(` ${icon} ${pattern.description}`);
|
|
129
|
+
}
|
|
130
|
+
lines.push('');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Top ranked recommendations
|
|
135
|
+
if (Array.isArray(recommendations) && recommendations.length > 0) {
|
|
136
|
+
const ranked = rankRecommendations(recommendations, activePlatforms || []);
|
|
137
|
+
if (ranked.length > 0) {
|
|
138
|
+
lines.push(c(' Top Synergy Recommendations', 'bold'));
|
|
139
|
+
for (const rec of ranked.slice(0, 5)) {
|
|
140
|
+
const platforms = (rec.applicablePlatforms || []).join(', ') || rec.platform || '?';
|
|
141
|
+
lines.push(` ${c(rec.synergyScore.toFixed(1).padStart(5), 'green')} ${rec.name || rec.description || rec.key} ${c(`[${platforms}]`, 'dim')}`);
|
|
142
|
+
}
|
|
143
|
+
lines.push('');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Verdict
|
|
148
|
+
lines.push(c(` Verdict: ${amplification.verdict.replace(/-/g, ' ')}`, 'bold'));
|
|
149
|
+
lines.push('');
|
|
150
|
+
|
|
151
|
+
return lines.join('\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate a full synergy report for a project directory.
|
|
156
|
+
* High-level entry point that runs compound audit + compensation + patterns.
|
|
157
|
+
*
|
|
158
|
+
* @param {Object} options - Same as formatSynergyReport options
|
|
159
|
+
* @returns {string} Formatted CLI report string
|
|
160
|
+
*/
|
|
161
|
+
function generateSynergyReport(options) {
|
|
162
|
+
return formatSynergyReport(options);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { generateSynergyReport, formatSynergyReport };
|
package/src/synergy/routing.js
CHANGED
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S2. Intelligent Task Routing
|
|
3
|
-
*
|
|
4
|
-
* Routes tasks to the best platform based on capabilities,
|
|
5
|
-
* project history, and active platform availability.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { PLATFORM_CAPABILITIES } = require('../shared/capabilities');
|
|
9
|
-
|
|
10
|
-
const TASK_TYPE_PATTERNS = [
|
|
11
|
-
{ type: 'bugfix', patterns: ['bug', 'fix', 'error', 'crash', 'broken', 'issue', 'regression', 'failing'] },
|
|
12
|
-
{ type: 'refactor', patterns: ['refactor', 'clean', 'restructure', 'reorganize', 'simplify', 'extract', 'dedup'] },
|
|
13
|
-
{ type: 'review', patterns: ['review', 'audit', 'check', 'inspect', 'evaluate', 'assess', 'analyze'] },
|
|
14
|
-
{ type: 'UI', patterns: ['ui', 'frontend', 'css', 'layout', 'design', 'component', 'style', 'responsive'] },
|
|
15
|
-
{ type: 'CI', patterns: ['ci', 'pipeline', 'deploy', 'workflow', 'github actions', 'build', 'release'] },
|
|
16
|
-
{ type: 'infrastructure', patterns: ['infra', 'terraform', 'docker', 'k8s', 'kubernetes', 'aws', 'cloud'] },
|
|
17
|
-
{ type: 'testing', patterns: ['test', 'spec', 'coverage', 'e2e', 'unit test', 'integration test'] },
|
|
18
|
-
{ type: 'architecture', patterns: ['architect', 'design', 'plan', 'structure', 'module', 'system design'] },
|
|
19
|
-
{ type: 'documentation', patterns: ['doc', 'readme', 'comment', 'explain', 'document', 'jsdoc'] },
|
|
20
|
-
{ type: 'feature', patterns: ['feature', 'implement', 'add', 'create', 'new', 'build', 'develop'] },
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
const TASK_CAPABILITY_MAP = {
|
|
24
|
-
bugfix: ['debugging', 'reasoning', 'ide'],
|
|
25
|
-
refactor: ['refactoring', 'reasoning', 'ide'],
|
|
26
|
-
review: ['review', 'reasoning', 'context'],
|
|
27
|
-
UI: ['ui', 'ide', 'inline'],
|
|
28
|
-
CI: ['ci', 'cloudTasks', 'async'],
|
|
29
|
-
infrastructure: ['ci', 'cloudTasks', 'sandbox'],
|
|
30
|
-
testing: ['debugging', 'ci', 'sandbox'],
|
|
31
|
-
architecture: ['architecture', 'reasoning', 'context'],
|
|
32
|
-
documentation: ['reasoning', 'context', 'inline'],
|
|
33
|
-
feature: ['reasoning', 'ide', 'refactoring'],
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Classify a task description into a task type.
|
|
38
|
-
*
|
|
39
|
-
* @param {string} taskDescription - Free-text task description
|
|
40
|
-
* @returns {string} Task type
|
|
41
|
-
*/
|
|
42
|
-
function classifyTaskType(taskDescription) {
|
|
43
|
-
const lower = taskDescription.toLowerCase();
|
|
44
|
-
let bestMatch = { type: 'feature', score: 0 };
|
|
45
|
-
|
|
46
|
-
for (const { type, patterns } of TASK_TYPE_PATTERNS) {
|
|
47
|
-
const score = patterns.reduce((sum, pattern) => {
|
|
48
|
-
return sum + (lower.includes(pattern) ? 1 : 0);
|
|
49
|
-
}, 0);
|
|
50
|
-
if (score > bestMatch.score) {
|
|
51
|
-
bestMatch = { type, score };
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return bestMatch.type;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Score a platform for a given task type.
|
|
60
|
-
*/
|
|
61
|
-
function scorePlatform(platform, taskType, projectHistory) {
|
|
62
|
-
const capabilities = PLATFORM_CAPABILITIES[platform];
|
|
63
|
-
if (!capabilities) return 0;
|
|
64
|
-
|
|
65
|
-
const relevantCapabilities = TASK_CAPABILITY_MAP[taskType] || ['reasoning'];
|
|
66
|
-
let score = 0;
|
|
67
|
-
let count = 0;
|
|
68
|
-
|
|
69
|
-
for (const cap of relevantCapabilities) {
|
|
70
|
-
if (capabilities[cap] !== undefined) {
|
|
71
|
-
score += capabilities[cap];
|
|
72
|
-
count++;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const baseScore = count > 0 ? score / count : 0;
|
|
77
|
-
|
|
78
|
-
// Boost from project history
|
|
79
|
-
let historyBoost = 0;
|
|
80
|
-
if (projectHistory && projectHistory[platform]) {
|
|
81
|
-
const history = projectHistory[platform];
|
|
82
|
-
const taskHistory = history[taskType];
|
|
83
|
-
if (taskHistory) {
|
|
84
|
-
// Success rate boost: up to +1.0
|
|
85
|
-
const successRate = taskHistory.successes / Math.max(1, taskHistory.total);
|
|
86
|
-
historyBoost = successRate * 1.0;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return Math.round((baseScore + historyBoost) * 100) / 100;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Route a task to the best available platform.
|
|
95
|
-
*
|
|
96
|
-
* @param {string} taskDescription - Free-text task description
|
|
97
|
-
* @param {string[]} activePlatforms - Currently available platforms
|
|
98
|
-
* @param {Object} [projectHistory] - Historical task success data per platform
|
|
99
|
-
* @returns {Object} Routing recommendation
|
|
100
|
-
*/
|
|
101
|
-
function routeTask(taskDescription, activePlatforms, projectHistory) {
|
|
102
|
-
const taskType = classifyTaskType(taskDescription);
|
|
103
|
-
const platforms = (activePlatforms || []).filter(p => PLATFORM_CAPABILITIES[p]);
|
|
104
|
-
|
|
105
|
-
if (platforms.length === 0) {
|
|
106
|
-
return {
|
|
107
|
-
recommended: null,
|
|
108
|
-
alternatives: [],
|
|
109
|
-
taskType,
|
|
110
|
-
reasoning: 'No active platforms with known capabilities',
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const scored = platforms.map(platform => ({
|
|
115
|
-
platform,
|
|
116
|
-
score: scorePlatform(platform, taskType, projectHistory),
|
|
117
|
-
})).sort((a, b) => b.score - a.score);
|
|
118
|
-
|
|
119
|
-
const best = scored[0];
|
|
120
|
-
const alternatives = scored.slice(1);
|
|
121
|
-
|
|
122
|
-
// Build reasoning
|
|
123
|
-
const relevantCaps = TASK_CAPABILITY_MAP[taskType] || ['reasoning'];
|
|
124
|
-
const bestCaps = PLATFORM_CAPABILITIES[best.platform];
|
|
125
|
-
const topStrengths = relevantCaps
|
|
126
|
-
.filter(cap => (bestCaps[cap] || 0) >= 4)
|
|
127
|
-
.join(', ');
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
recommended: {
|
|
131
|
-
platform: best.platform,
|
|
132
|
-
confidence: Math.min(1, best.score / 5),
|
|
133
|
-
reasoning: topStrengths
|
|
134
|
-
? `${best.platform} excels at ${topStrengths} (needed for ${taskType})`
|
|
135
|
-
: `${best.platform} is the best available option for ${taskType}`,
|
|
136
|
-
},
|
|
137
|
-
alternatives: alternatives.map(a => ({
|
|
138
|
-
platform: a.platform,
|
|
139
|
-
confidence: Math.min(1, a.score / 5),
|
|
140
|
-
reasoning: `Score: ${a.score}/5 for ${taskType}`,
|
|
141
|
-
})),
|
|
142
|
-
taskType,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
module.exports = { routeTask, classifyTaskType, PLATFORM_CAPABILITIES };
|
|
1
|
+
/**
|
|
2
|
+
* S2. Intelligent Task Routing
|
|
3
|
+
*
|
|
4
|
+
* Routes tasks to the best platform based on capabilities,
|
|
5
|
+
* project history, and active platform availability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { PLATFORM_CAPABILITIES } = require('../shared/capabilities');
|
|
9
|
+
|
|
10
|
+
const TASK_TYPE_PATTERNS = [
|
|
11
|
+
{ type: 'bugfix', patterns: ['bug', 'fix', 'error', 'crash', 'broken', 'issue', 'regression', 'failing'] },
|
|
12
|
+
{ type: 'refactor', patterns: ['refactor', 'clean', 'restructure', 'reorganize', 'simplify', 'extract', 'dedup'] },
|
|
13
|
+
{ type: 'review', patterns: ['review', 'audit', 'check', 'inspect', 'evaluate', 'assess', 'analyze'] },
|
|
14
|
+
{ type: 'UI', patterns: ['ui', 'frontend', 'css', 'layout', 'design', 'component', 'style', 'responsive'] },
|
|
15
|
+
{ type: 'CI', patterns: ['ci', 'pipeline', 'deploy', 'workflow', 'github actions', 'build', 'release'] },
|
|
16
|
+
{ type: 'infrastructure', patterns: ['infra', 'terraform', 'docker', 'k8s', 'kubernetes', 'aws', 'cloud'] },
|
|
17
|
+
{ type: 'testing', patterns: ['test', 'spec', 'coverage', 'e2e', 'unit test', 'integration test'] },
|
|
18
|
+
{ type: 'architecture', patterns: ['architect', 'design', 'plan', 'structure', 'module', 'system design'] },
|
|
19
|
+
{ type: 'documentation', patterns: ['doc', 'readme', 'comment', 'explain', 'document', 'jsdoc'] },
|
|
20
|
+
{ type: 'feature', patterns: ['feature', 'implement', 'add', 'create', 'new', 'build', 'develop'] },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const TASK_CAPABILITY_MAP = {
|
|
24
|
+
bugfix: ['debugging', 'reasoning', 'ide'],
|
|
25
|
+
refactor: ['refactoring', 'reasoning', 'ide'],
|
|
26
|
+
review: ['review', 'reasoning', 'context'],
|
|
27
|
+
UI: ['ui', 'ide', 'inline'],
|
|
28
|
+
CI: ['ci', 'cloudTasks', 'async'],
|
|
29
|
+
infrastructure: ['ci', 'cloudTasks', 'sandbox'],
|
|
30
|
+
testing: ['debugging', 'ci', 'sandbox'],
|
|
31
|
+
architecture: ['architecture', 'reasoning', 'context'],
|
|
32
|
+
documentation: ['reasoning', 'context', 'inline'],
|
|
33
|
+
feature: ['reasoning', 'ide', 'refactoring'],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Classify a task description into a task type.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} taskDescription - Free-text task description
|
|
40
|
+
* @returns {string} Task type
|
|
41
|
+
*/
|
|
42
|
+
function classifyTaskType(taskDescription) {
|
|
43
|
+
const lower = taskDescription.toLowerCase();
|
|
44
|
+
let bestMatch = { type: 'feature', score: 0 };
|
|
45
|
+
|
|
46
|
+
for (const { type, patterns } of TASK_TYPE_PATTERNS) {
|
|
47
|
+
const score = patterns.reduce((sum, pattern) => {
|
|
48
|
+
return sum + (lower.includes(pattern) ? 1 : 0);
|
|
49
|
+
}, 0);
|
|
50
|
+
if (score > bestMatch.score) {
|
|
51
|
+
bestMatch = { type, score };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return bestMatch.type;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Score a platform for a given task type.
|
|
60
|
+
*/
|
|
61
|
+
function scorePlatform(platform, taskType, projectHistory) {
|
|
62
|
+
const capabilities = PLATFORM_CAPABILITIES[platform];
|
|
63
|
+
if (!capabilities) return 0;
|
|
64
|
+
|
|
65
|
+
const relevantCapabilities = TASK_CAPABILITY_MAP[taskType] || ['reasoning'];
|
|
66
|
+
let score = 0;
|
|
67
|
+
let count = 0;
|
|
68
|
+
|
|
69
|
+
for (const cap of relevantCapabilities) {
|
|
70
|
+
if (capabilities[cap] !== undefined) {
|
|
71
|
+
score += capabilities[cap];
|
|
72
|
+
count++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const baseScore = count > 0 ? score / count : 0;
|
|
77
|
+
|
|
78
|
+
// Boost from project history
|
|
79
|
+
let historyBoost = 0;
|
|
80
|
+
if (projectHistory && projectHistory[platform]) {
|
|
81
|
+
const history = projectHistory[platform];
|
|
82
|
+
const taskHistory = history[taskType];
|
|
83
|
+
if (taskHistory) {
|
|
84
|
+
// Success rate boost: up to +1.0
|
|
85
|
+
const successRate = taskHistory.successes / Math.max(1, taskHistory.total);
|
|
86
|
+
historyBoost = successRate * 1.0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return Math.round((baseScore + historyBoost) * 100) / 100;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Route a task to the best available platform.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} taskDescription - Free-text task description
|
|
97
|
+
* @param {string[]} activePlatforms - Currently available platforms
|
|
98
|
+
* @param {Object} [projectHistory] - Historical task success data per platform
|
|
99
|
+
* @returns {Object} Routing recommendation
|
|
100
|
+
*/
|
|
101
|
+
function routeTask(taskDescription, activePlatforms, projectHistory) {
|
|
102
|
+
const taskType = classifyTaskType(taskDescription);
|
|
103
|
+
const platforms = (activePlatforms || []).filter(p => PLATFORM_CAPABILITIES[p]);
|
|
104
|
+
|
|
105
|
+
if (platforms.length === 0) {
|
|
106
|
+
return {
|
|
107
|
+
recommended: null,
|
|
108
|
+
alternatives: [],
|
|
109
|
+
taskType,
|
|
110
|
+
reasoning: 'No active platforms with known capabilities',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const scored = platforms.map(platform => ({
|
|
115
|
+
platform,
|
|
116
|
+
score: scorePlatform(platform, taskType, projectHistory),
|
|
117
|
+
})).sort((a, b) => b.score - a.score);
|
|
118
|
+
|
|
119
|
+
const best = scored[0];
|
|
120
|
+
const alternatives = scored.slice(1);
|
|
121
|
+
|
|
122
|
+
// Build reasoning
|
|
123
|
+
const relevantCaps = TASK_CAPABILITY_MAP[taskType] || ['reasoning'];
|
|
124
|
+
const bestCaps = PLATFORM_CAPABILITIES[best.platform];
|
|
125
|
+
const topStrengths = relevantCaps
|
|
126
|
+
.filter(cap => (bestCaps[cap] || 0) >= 4)
|
|
127
|
+
.join(', ');
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
recommended: {
|
|
131
|
+
platform: best.platform,
|
|
132
|
+
confidence: Math.min(1, best.score / 5),
|
|
133
|
+
reasoning: topStrengths
|
|
134
|
+
? `${best.platform} excels at ${topStrengths} (needed for ${taskType})`
|
|
135
|
+
: `${best.platform} is the best available option for ${taskType}`,
|
|
136
|
+
},
|
|
137
|
+
alternatives: alternatives.map(a => ({
|
|
138
|
+
platform: a.platform,
|
|
139
|
+
confidence: Math.min(1, a.score / 5),
|
|
140
|
+
reasoning: `Score: ${a.score}/5 for ${taskType}`,
|
|
141
|
+
})),
|
|
142
|
+
taskType,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = { routeTask, classifyTaskType, PLATFORM_CAPABILITIES };
|