@nerviq/cli 1.18.0 → 1.20.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 +2 -2
- package/bin/cli.js +131 -130
- package/package.json +2 -1
- 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/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/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 -783
- 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 +290 -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 +105 -33
- 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/learning.js
CHANGED
|
@@ -1,199 +1,199 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1. Cross-Platform Learning Engine
|
|
3
|
-
*
|
|
4
|
-
* When a recommendation succeeds on one platform, propagate to others.
|
|
5
|
-
* Translates recommendations into each platform's native semantics
|
|
6
|
-
* rather than blindly copying.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
const PLATFORM_SEMANTICS = {
|
|
13
|
-
claude: { configFile: 'CLAUDE.md', format: 'markdown', instructionStyle: 'prose' },
|
|
14
|
-
codex: { configFile: 'AGENTS.md', format: 'markdown', instructionStyle: 'directive' },
|
|
15
|
-
gemini: { configFile: 'GEMINI.md', format: 'markdown', instructionStyle: 'structured' },
|
|
16
|
-
copilot: { configFile: '.github/copilot-instructions.md', format: 'markdown', instructionStyle: 'concise' },
|
|
17
|
-
cursor: { configFile: '.cursor/rules', format: 'mdc', instructionStyle: 'rule-based' },
|
|
18
|
-
windsurf: { configFile: '.windsurf/rules', format: 'markdown', instructionStyle: 'rule-based' },
|
|
19
|
-
aider: { configFile: '.aider.conf.yml', format: 'yaml', instructionStyle: 'convention-based' },
|
|
20
|
-
opencode: { configFile: 'opencode.json', format: 'jsonc', instructionStyle: 'directive' },
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const TRANSLATION_MAP = {
|
|
24
|
-
'verification-command': {
|
|
25
|
-
claude: (rec) => `Add to CLAUDE.md: \`## Verification\` section with \`${rec.command}\``,
|
|
26
|
-
codex: (rec) => `Add to AGENTS.md verification block: \`${rec.command}\``,
|
|
27
|
-
gemini: (rec) => `Add to GEMINI.md: verification command \`${rec.command}\``,
|
|
28
|
-
copilot: (rec) => `Document in copilot-instructions.md: always run \`${rec.command}\` before completing`,
|
|
29
|
-
cursor: (rec) => `Add rule: "Always run \`${rec.command}\` before completing tasks"`,
|
|
30
|
-
windsurf: (rec) => `Add a .windsurf/rules verification rule that runs \`${rec.command}\` before task completion`,
|
|
31
|
-
aider: (rec) => `Document in CONVENTIONS.md or .aider.conf.yml workflow notes: run \`${rec.command}\` before final response`,
|
|
32
|
-
opencode: (rec) => `Add to AGENTS.md or opencode.json workflow guidance: run \`${rec.command}\` before completing`,
|
|
33
|
-
},
|
|
34
|
-
'architecture-doc': {
|
|
35
|
-
claude: () => `Add Mermaid architecture diagram to CLAUDE.md`,
|
|
36
|
-
codex: () => `Add architecture overview to AGENTS.md`,
|
|
37
|
-
gemini: () => `Add architecture context to GEMINI.md`,
|
|
38
|
-
copilot: () => `Add architecture reference in copilot-instructions.md`,
|
|
39
|
-
cursor: () => `Add architecture context rule in .cursor/rules`,
|
|
40
|
-
windsurf: () => `Add architecture guidance to a .windsurf/rules/*.md file or shared workflow`,
|
|
41
|
-
aider: () => `Add architecture overview to CONVENTIONS.md for Aider sessions`,
|
|
42
|
-
opencode: () => `Add architecture context to AGENTS.md and reference it from opencode.json`,
|
|
43
|
-
},
|
|
44
|
-
'permission-rule': {
|
|
45
|
-
claude: (rec) => `Configure in settings.json permissions: ${rec.description}`,
|
|
46
|
-
codex: (rec) => `Set sandbox policy in codex config: ${rec.description}`,
|
|
47
|
-
gemini: (rec) => `Configure Gemini sandbox settings: ${rec.description}`,
|
|
48
|
-
copilot: (rec) => `Note in instructions: ${rec.description}`,
|
|
49
|
-
cursor: (rec) => `Add safety rule: ${rec.description}`,
|
|
50
|
-
windsurf: (rec) => `Translate into .cascadeignore, MCP whitelist, or rule guidance: ${rec.description}`,
|
|
51
|
-
aider: (rec) => `Translate into git workflow guardrails or config defaults: ${rec.description}`,
|
|
52
|
-
opencode: (rec) => `Encode in opencode.json permissions: ${rec.description}`,
|
|
53
|
-
},
|
|
54
|
-
'hook': {
|
|
55
|
-
claude: (rec) => `Add hook in settings.json: ${rec.description}`,
|
|
56
|
-
codex: (rec) => `Add pre/post task check: ${rec.description}`,
|
|
57
|
-
gemini: (rec) => `Add automated check: ${rec.description}`,
|
|
58
|
-
copilot: (rec) => `Add workflow step: ${rec.description}`,
|
|
59
|
-
cursor: (rec) => `Add background task rule: ${rec.description}`,
|
|
60
|
-
windsurf: (rec) => `Implement as a workflow, Steps sequence, or auto rule: ${rec.description}`,
|
|
61
|
-
aider: (rec) => `Implement via git hooks, auto-test, or documented Aider workflow: ${rec.description}`,
|
|
62
|
-
opencode: (rec) => `Implement via plugin, workflow, or task automation: ${rec.description}`,
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Adapt a recommendation from one platform's semantics to another.
|
|
68
|
-
*/
|
|
69
|
-
function adaptRecommendation(recommendation, sourcePlatform, targetPlatform) {
|
|
70
|
-
const translator = TRANSLATION_MAP[recommendation.type];
|
|
71
|
-
if (translator && translator[targetPlatform]) {
|
|
72
|
-
return translator[targetPlatform](recommendation);
|
|
73
|
-
}
|
|
74
|
-
// Generic fallback: describe the recommendation in platform-neutral terms
|
|
75
|
-
const semantics = PLATFORM_SEMANTICS[targetPlatform];
|
|
76
|
-
if (!semantics) return recommendation.description || recommendation.recommendation;
|
|
77
|
-
return `[${semantics.configFile}] ${recommendation.description || recommendation.recommendation}`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Calculate confidence for a propagated insight based on similarity
|
|
82
|
-
* between source and target platforms.
|
|
83
|
-
*/
|
|
84
|
-
function calculatePropagationConfidence(insight, sourcePlatform, targetPlatform) {
|
|
85
|
-
// Base confidence from the original outcome
|
|
86
|
-
let confidence = Math.min(1, Math.max(0, (insight.score_delta || 0) / 20));
|
|
87
|
-
|
|
88
|
-
// Same instruction style = higher confidence
|
|
89
|
-
const sourceStyle = (PLATFORM_SEMANTICS[sourcePlatform] || {}).instructionStyle;
|
|
90
|
-
const targetStyle = (PLATFORM_SEMANTICS[targetPlatform] || {}).instructionStyle;
|
|
91
|
-
if (sourceStyle === targetStyle) confidence *= 1.2;
|
|
92
|
-
|
|
93
|
-
// Same format = slightly higher confidence
|
|
94
|
-
const sourceFormat = (PLATFORM_SEMANTICS[sourcePlatform] || {}).format;
|
|
95
|
-
const targetFormat = (PLATFORM_SEMANTICS[targetPlatform] || {}).format;
|
|
96
|
-
if (sourceFormat === targetFormat) confidence *= 1.1;
|
|
97
|
-
|
|
98
|
-
return Math.min(1, Math.round(confidence * 100) / 100);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Propagate an insight from one platform to others.
|
|
103
|
-
*
|
|
104
|
-
* @param {Object} insight - { type, recommendation, outcome, score_delta }
|
|
105
|
-
* @param {string} sourcePlatform - Platform where the insight originated
|
|
106
|
-
* @param {string[]} targetPlatforms - Platforms to propagate to
|
|
107
|
-
* @returns {Object[]} Adapted recommendations per target platform
|
|
108
|
-
*/
|
|
109
|
-
function propagateInsight(insight, sourcePlatform, targetPlatforms) {
|
|
110
|
-
return targetPlatforms
|
|
111
|
-
.filter(p => p !== sourcePlatform)
|
|
112
|
-
.map(platform => ({
|
|
113
|
-
platform,
|
|
114
|
-
adaptedRecommendation: adaptRecommendation(insight, sourcePlatform, platform),
|
|
115
|
-
confidence: calculatePropagationConfidence(insight, sourcePlatform, platform),
|
|
116
|
-
sourceEvidence: {
|
|
117
|
-
platform: sourcePlatform,
|
|
118
|
-
outcome: insight.outcome,
|
|
119
|
-
score_delta: insight.score_delta,
|
|
120
|
-
},
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Read recommendation outcomes from all platforms and find cross-learning opportunities.
|
|
126
|
-
*
|
|
127
|
-
* @param {string} dir - Project directory
|
|
128
|
-
* @returns {Object[]} Cross-learning opportunities
|
|
129
|
-
*/
|
|
130
|
-
function getCrossLearnings(dir) {
|
|
131
|
-
const learningsFile = path.join(dir, '.claude', 'synergy-learnings.json');
|
|
132
|
-
let learnings = [];
|
|
133
|
-
try {
|
|
134
|
-
learnings = JSON.parse(fs.readFileSync(learningsFile, 'utf8'));
|
|
135
|
-
} catch {
|
|
136
|
-
// No learnings file yet
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Group by recommendation type
|
|
140
|
-
const byType = {};
|
|
141
|
-
for (const learning of learnings) {
|
|
142
|
-
if (!byType[learning.type]) byType[learning.type] = [];
|
|
143
|
-
byType[learning.type].push(learning);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const opportunities = [];
|
|
147
|
-
for (const [type, items] of Object.entries(byType)) {
|
|
148
|
-
// Find successful outcomes
|
|
149
|
-
const successes = items.filter(i => i.outcome === 'applied' || i.outcome === 'helpful');
|
|
150
|
-
if (successes.length === 0) continue;
|
|
151
|
-
|
|
152
|
-
// Find platforms that haven't tried this yet
|
|
153
|
-
const triedPlatforms = new Set(items.map(i => i.platform));
|
|
154
|
-
const allPlatforms = Object.keys(PLATFORM_SEMANTICS);
|
|
155
|
-
const untried = allPlatforms.filter(p => !triedPlatforms.has(p));
|
|
156
|
-
|
|
157
|
-
if (untried.length > 0) {
|
|
158
|
-
const bestSuccess = successes.reduce((a, b) =>
|
|
159
|
-
(b.score_delta || 0) > (a.score_delta || 0) ? b : a
|
|
160
|
-
);
|
|
161
|
-
opportunities.push({
|
|
162
|
-
type,
|
|
163
|
-
successfulOn: successes.map(s => s.platform),
|
|
164
|
-
untestedOn: untried,
|
|
165
|
-
bestEvidence: bestSuccess,
|
|
166
|
-
propagations: propagateInsight(bestSuccess, bestSuccess.platform, untried),
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return opportunities;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Record a learning outcome for later cross-platform propagation.
|
|
176
|
-
*
|
|
177
|
-
* @param {string} dir - Project directory
|
|
178
|
-
* @param {Object} outcome - { platform, type, recommendation, outcome, score_delta }
|
|
179
|
-
*/
|
|
180
|
-
function recordLearningOutcome(dir, outcome) {
|
|
181
|
-
const learningsFile = path.join(dir, '.claude', 'synergy-learnings.json');
|
|
182
|
-
let learnings = [];
|
|
183
|
-
try {
|
|
184
|
-
learnings = JSON.parse(fs.readFileSync(learningsFile, 'utf8'));
|
|
185
|
-
} catch {
|
|
186
|
-
// Start fresh
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
learnings.push({
|
|
190
|
-
...outcome,
|
|
191
|
-
timestamp: new Date().toISOString(),
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
const claudeDir = path.join(dir, '.claude');
|
|
195
|
-
if (!fs.existsSync(claudeDir)) fs.mkdirSync(claudeDir, { recursive: true });
|
|
196
|
-
fs.writeFileSync(learningsFile, JSON.stringify(learnings, null, 2));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
module.exports = { propagateInsight, getCrossLearnings, recordLearningOutcome };
|
|
1
|
+
/**
|
|
2
|
+
* S1. Cross-Platform Learning Engine
|
|
3
|
+
*
|
|
4
|
+
* When a recommendation succeeds on one platform, propagate to others.
|
|
5
|
+
* Translates recommendations into each platform's native semantics
|
|
6
|
+
* rather than blindly copying.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const PLATFORM_SEMANTICS = {
|
|
13
|
+
claude: { configFile: 'CLAUDE.md', format: 'markdown', instructionStyle: 'prose' },
|
|
14
|
+
codex: { configFile: 'AGENTS.md', format: 'markdown', instructionStyle: 'directive' },
|
|
15
|
+
gemini: { configFile: 'GEMINI.md', format: 'markdown', instructionStyle: 'structured' },
|
|
16
|
+
copilot: { configFile: '.github/copilot-instructions.md', format: 'markdown', instructionStyle: 'concise' },
|
|
17
|
+
cursor: { configFile: '.cursor/rules', format: 'mdc', instructionStyle: 'rule-based' },
|
|
18
|
+
windsurf: { configFile: '.windsurf/rules', format: 'markdown', instructionStyle: 'rule-based' },
|
|
19
|
+
aider: { configFile: '.aider.conf.yml', format: 'yaml', instructionStyle: 'convention-based' },
|
|
20
|
+
opencode: { configFile: 'opencode.json', format: 'jsonc', instructionStyle: 'directive' },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const TRANSLATION_MAP = {
|
|
24
|
+
'verification-command': {
|
|
25
|
+
claude: (rec) => `Add to CLAUDE.md: \`## Verification\` section with \`${rec.command}\``,
|
|
26
|
+
codex: (rec) => `Add to AGENTS.md verification block: \`${rec.command}\``,
|
|
27
|
+
gemini: (rec) => `Add to GEMINI.md: verification command \`${rec.command}\``,
|
|
28
|
+
copilot: (rec) => `Document in copilot-instructions.md: always run \`${rec.command}\` before completing`,
|
|
29
|
+
cursor: (rec) => `Add rule: "Always run \`${rec.command}\` before completing tasks"`,
|
|
30
|
+
windsurf: (rec) => `Add a .windsurf/rules verification rule that runs \`${rec.command}\` before task completion`,
|
|
31
|
+
aider: (rec) => `Document in CONVENTIONS.md or .aider.conf.yml workflow notes: run \`${rec.command}\` before final response`,
|
|
32
|
+
opencode: (rec) => `Add to AGENTS.md or opencode.json workflow guidance: run \`${rec.command}\` before completing`,
|
|
33
|
+
},
|
|
34
|
+
'architecture-doc': {
|
|
35
|
+
claude: () => `Add Mermaid architecture diagram to CLAUDE.md`,
|
|
36
|
+
codex: () => `Add architecture overview to AGENTS.md`,
|
|
37
|
+
gemini: () => `Add architecture context to GEMINI.md`,
|
|
38
|
+
copilot: () => `Add architecture reference in copilot-instructions.md`,
|
|
39
|
+
cursor: () => `Add architecture context rule in .cursor/rules`,
|
|
40
|
+
windsurf: () => `Add architecture guidance to a .windsurf/rules/*.md file or shared workflow`,
|
|
41
|
+
aider: () => `Add architecture overview to CONVENTIONS.md for Aider sessions`,
|
|
42
|
+
opencode: () => `Add architecture context to AGENTS.md and reference it from opencode.json`,
|
|
43
|
+
},
|
|
44
|
+
'permission-rule': {
|
|
45
|
+
claude: (rec) => `Configure in settings.json permissions: ${rec.description}`,
|
|
46
|
+
codex: (rec) => `Set sandbox policy in codex config: ${rec.description}`,
|
|
47
|
+
gemini: (rec) => `Configure Gemini sandbox settings: ${rec.description}`,
|
|
48
|
+
copilot: (rec) => `Note in instructions: ${rec.description}`,
|
|
49
|
+
cursor: (rec) => `Add safety rule: ${rec.description}`,
|
|
50
|
+
windsurf: (rec) => `Translate into .cascadeignore, MCP whitelist, or rule guidance: ${rec.description}`,
|
|
51
|
+
aider: (rec) => `Translate into git workflow guardrails or config defaults: ${rec.description}`,
|
|
52
|
+
opencode: (rec) => `Encode in opencode.json permissions: ${rec.description}`,
|
|
53
|
+
},
|
|
54
|
+
'hook': {
|
|
55
|
+
claude: (rec) => `Add hook in settings.json: ${rec.description}`,
|
|
56
|
+
codex: (rec) => `Add pre/post task check: ${rec.description}`,
|
|
57
|
+
gemini: (rec) => `Add automated check: ${rec.description}`,
|
|
58
|
+
copilot: (rec) => `Add workflow step: ${rec.description}`,
|
|
59
|
+
cursor: (rec) => `Add background task rule: ${rec.description}`,
|
|
60
|
+
windsurf: (rec) => `Implement as a workflow, Steps sequence, or auto rule: ${rec.description}`,
|
|
61
|
+
aider: (rec) => `Implement via git hooks, auto-test, or documented Aider workflow: ${rec.description}`,
|
|
62
|
+
opencode: (rec) => `Implement via plugin, workflow, or task automation: ${rec.description}`,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Adapt a recommendation from one platform's semantics to another.
|
|
68
|
+
*/
|
|
69
|
+
function adaptRecommendation(recommendation, sourcePlatform, targetPlatform) {
|
|
70
|
+
const translator = TRANSLATION_MAP[recommendation.type];
|
|
71
|
+
if (translator && translator[targetPlatform]) {
|
|
72
|
+
return translator[targetPlatform](recommendation);
|
|
73
|
+
}
|
|
74
|
+
// Generic fallback: describe the recommendation in platform-neutral terms
|
|
75
|
+
const semantics = PLATFORM_SEMANTICS[targetPlatform];
|
|
76
|
+
if (!semantics) return recommendation.description || recommendation.recommendation;
|
|
77
|
+
return `[${semantics.configFile}] ${recommendation.description || recommendation.recommendation}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Calculate confidence for a propagated insight based on similarity
|
|
82
|
+
* between source and target platforms.
|
|
83
|
+
*/
|
|
84
|
+
function calculatePropagationConfidence(insight, sourcePlatform, targetPlatform) {
|
|
85
|
+
// Base confidence from the original outcome
|
|
86
|
+
let confidence = Math.min(1, Math.max(0, (insight.score_delta || 0) / 20));
|
|
87
|
+
|
|
88
|
+
// Same instruction style = higher confidence
|
|
89
|
+
const sourceStyle = (PLATFORM_SEMANTICS[sourcePlatform] || {}).instructionStyle;
|
|
90
|
+
const targetStyle = (PLATFORM_SEMANTICS[targetPlatform] || {}).instructionStyle;
|
|
91
|
+
if (sourceStyle === targetStyle) confidence *= 1.2;
|
|
92
|
+
|
|
93
|
+
// Same format = slightly higher confidence
|
|
94
|
+
const sourceFormat = (PLATFORM_SEMANTICS[sourcePlatform] || {}).format;
|
|
95
|
+
const targetFormat = (PLATFORM_SEMANTICS[targetPlatform] || {}).format;
|
|
96
|
+
if (sourceFormat === targetFormat) confidence *= 1.1;
|
|
97
|
+
|
|
98
|
+
return Math.min(1, Math.round(confidence * 100) / 100);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Propagate an insight from one platform to others.
|
|
103
|
+
*
|
|
104
|
+
* @param {Object} insight - { type, recommendation, outcome, score_delta }
|
|
105
|
+
* @param {string} sourcePlatform - Platform where the insight originated
|
|
106
|
+
* @param {string[]} targetPlatforms - Platforms to propagate to
|
|
107
|
+
* @returns {Object[]} Adapted recommendations per target platform
|
|
108
|
+
*/
|
|
109
|
+
function propagateInsight(insight, sourcePlatform, targetPlatforms) {
|
|
110
|
+
return targetPlatforms
|
|
111
|
+
.filter(p => p !== sourcePlatform)
|
|
112
|
+
.map(platform => ({
|
|
113
|
+
platform,
|
|
114
|
+
adaptedRecommendation: adaptRecommendation(insight, sourcePlatform, platform),
|
|
115
|
+
confidence: calculatePropagationConfidence(insight, sourcePlatform, platform),
|
|
116
|
+
sourceEvidence: {
|
|
117
|
+
platform: sourcePlatform,
|
|
118
|
+
outcome: insight.outcome,
|
|
119
|
+
score_delta: insight.score_delta,
|
|
120
|
+
},
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Read recommendation outcomes from all platforms and find cross-learning opportunities.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} dir - Project directory
|
|
128
|
+
* @returns {Object[]} Cross-learning opportunities
|
|
129
|
+
*/
|
|
130
|
+
function getCrossLearnings(dir) {
|
|
131
|
+
const learningsFile = path.join(dir, '.claude', 'synergy-learnings.json');
|
|
132
|
+
let learnings = [];
|
|
133
|
+
try {
|
|
134
|
+
learnings = JSON.parse(fs.readFileSync(learningsFile, 'utf8'));
|
|
135
|
+
} catch {
|
|
136
|
+
// No learnings file yet
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Group by recommendation type
|
|
140
|
+
const byType = {};
|
|
141
|
+
for (const learning of learnings) {
|
|
142
|
+
if (!byType[learning.type]) byType[learning.type] = [];
|
|
143
|
+
byType[learning.type].push(learning);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const opportunities = [];
|
|
147
|
+
for (const [type, items] of Object.entries(byType)) {
|
|
148
|
+
// Find successful outcomes
|
|
149
|
+
const successes = items.filter(i => i.outcome === 'applied' || i.outcome === 'helpful');
|
|
150
|
+
if (successes.length === 0) continue;
|
|
151
|
+
|
|
152
|
+
// Find platforms that haven't tried this yet
|
|
153
|
+
const triedPlatforms = new Set(items.map(i => i.platform));
|
|
154
|
+
const allPlatforms = Object.keys(PLATFORM_SEMANTICS);
|
|
155
|
+
const untried = allPlatforms.filter(p => !triedPlatforms.has(p));
|
|
156
|
+
|
|
157
|
+
if (untried.length > 0) {
|
|
158
|
+
const bestSuccess = successes.reduce((a, b) =>
|
|
159
|
+
(b.score_delta || 0) > (a.score_delta || 0) ? b : a
|
|
160
|
+
);
|
|
161
|
+
opportunities.push({
|
|
162
|
+
type,
|
|
163
|
+
successfulOn: successes.map(s => s.platform),
|
|
164
|
+
untestedOn: untried,
|
|
165
|
+
bestEvidence: bestSuccess,
|
|
166
|
+
propagations: propagateInsight(bestSuccess, bestSuccess.platform, untried),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return opportunities;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Record a learning outcome for later cross-platform propagation.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} dir - Project directory
|
|
178
|
+
* @param {Object} outcome - { platform, type, recommendation, outcome, score_delta }
|
|
179
|
+
*/
|
|
180
|
+
function recordLearningOutcome(dir, outcome) {
|
|
181
|
+
const learningsFile = path.join(dir, '.claude', 'synergy-learnings.json');
|
|
182
|
+
let learnings = [];
|
|
183
|
+
try {
|
|
184
|
+
learnings = JSON.parse(fs.readFileSync(learningsFile, 'utf8'));
|
|
185
|
+
} catch {
|
|
186
|
+
// Start fresh
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
learnings.push({
|
|
190
|
+
...outcome,
|
|
191
|
+
timestamp: new Date().toISOString(),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const claudeDir = path.join(dir, '.claude');
|
|
195
|
+
if (!fs.existsSync(claudeDir)) fs.mkdirSync(claudeDir, { recursive: true });
|
|
196
|
+
fs.writeFileSync(learningsFile, JSON.stringify(learnings, null, 2));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = { propagateInsight, getCrossLearnings, recordLearningOutcome };
|