@evomap/evolver 1.90.0 → 2.0.0-beta.1
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/README.md +27 -564
- package/bin/evolver-llm-proxy.js +3 -0
- package/bin/evolver-mcp.js +2 -0
- package/bin/evolver-proxy.js +3 -0
- package/bin/evolver.js +4 -0
- package/index.js +1 -3670
- package/package.json +32 -62
- package/CONTRIBUTING.md +0 -19
- package/LICENSE +0 -641
- package/README.ja-JP.md +0 -521
- package/README.ko-KR.md +0 -520
- package/README.zh-CN.md +0 -531
- package/SKILL.md +0 -365
- package/assets/cover.png +0 -0
- package/assets/gep/genes.seed.json +0 -496
- package/conformance/savings-core/constants.json +0 -30
- package/conformance/savings-core/golden-vectors.json +0 -333
- package/scripts/a2a_export.js +0 -63
- package/scripts/a2a_ingest.js +0 -79
- package/scripts/a2a_promote.js +0 -118
- package/scripts/analyze_by_skill.js +0 -121
- package/scripts/build_binaries.js +0 -479
- package/scripts/check-changelog.js +0 -166
- package/scripts/extract_log.js +0 -85
- package/scripts/generate_history.js +0 -75
- package/scripts/gep_append_event.js +0 -96
- package/scripts/gep_personality_report.js +0 -234
- package/scripts/human_report.js +0 -147
- package/scripts/recall-verify-report.js +0 -234
- package/scripts/recover_loop.js +0 -61
- package/scripts/refresh_stars_badge.js +0 -168
- package/scripts/seed-merchants.js +0 -91
- package/scripts/skill2recipes.js +0 -118
- package/scripts/suggest_version.js +0 -89
- package/scripts/validate-modules.js +0 -38
- package/scripts/validate-suite.js +0 -78
- package/src/adapters/claudeCode.js +0 -194
- package/src/adapters/codex.js +0 -216
- package/src/adapters/cursor.js +0 -91
- package/src/adapters/hookAdapter.js +0 -469
- package/src/adapters/kiro.js +0 -195
- package/src/adapters/opencode.js +0 -326
- package/src/adapters/scripts/_lockPaths.js +0 -74
- package/src/adapters/scripts/_memoryFiltering.js +0 -35
- package/src/adapters/scripts/_runtimePaths.js +0 -440
- package/src/adapters/scripts/evolver-session-end.js +0 -321
- package/src/adapters/scripts/evolver-session-start.js +0 -587
- package/src/adapters/scripts/evolver-signal-detect.js +0 -98
- package/src/adapters/scripts/evolver-task-recall.js +0 -173
- package/src/atp/atpExecute.js +0 -283
- package/src/atp/atpTaskPickup.js +0 -233
- package/src/atp/autoBuyer.js +0 -382
- package/src/atp/autoDeliver.js +0 -215
- package/src/atp/cli.js +0 -354
- package/src/atp/cliAutobuyPrompt.js +0 -154
- package/src/atp/consumerAgent.js +0 -157
- package/src/atp/defaultHandler.js +0 -69
- package/src/atp/heartbeatSignalsHandler.js +0 -254
- package/src/atp/hubClient.js +0 -317
- package/src/atp/index.js +0 -38
- package/src/atp/merchantAgent.js +0 -118
- package/src/atp/protocol.js +0 -41
- package/src/atp/questionComposer.js +0 -133
- package/src/atp/serviceHelper.js +0 -92
- package/src/canary.js +0 -13
- package/src/config.js +0 -351
- package/src/evolve/guards.js +0 -1
- package/src/evolve/pipeline/collect.js +0 -1
- package/src/evolve/pipeline/dispatch.js +0 -1
- package/src/evolve/pipeline/enrich.js +0 -1
- package/src/evolve/pipeline/hub.js +0 -1
- package/src/evolve/pipeline/select.js +0 -1
- package/src/evolve/pipeline/signals.js +0 -1
- package/src/evolve/utils.js +0 -1
- package/src/evolve.js +0 -1
- package/src/experiment/agentRunner.js +0 -229
- package/src/experiment/cli.js +0 -159
- package/src/experiment/comparison.js +0 -233
- package/src/experiment/metrics.js +0 -75
- package/src/forceUpdate.js +0 -991
- package/src/gep/a2a.js +0 -173
- package/src/gep/a2aProtocol.js +0 -1
- package/src/gep/analyzer.js +0 -35
- package/src/gep/antiAbuseTelemetry.js +0 -1
- package/src/gep/assetCallLog.js +0 -197
- package/src/gep/assetStore.js +0 -723
- package/src/gep/assets.js +0 -36
- package/src/gep/autoDistillConv.js +0 -1
- package/src/gep/autoDistillLlm.js +0 -1
- package/src/gep/bridge.js +0 -138
- package/src/gep/candidateEval.js +0 -1
- package/src/gep/candidates.js +0 -1
- package/src/gep/claimNudge.js +0 -121
- package/src/gep/cliContracts.js +0 -1190
- package/src/gep/contentHash.js +0 -1
- package/src/gep/conversationDistiller.js +0 -1
- package/src/gep/conversationSniffer.js +0 -1
- package/src/gep/crypto.js +0 -1
- package/src/gep/curriculum.js +0 -1
- package/src/gep/deviceId.js +0 -1
- package/src/gep/directoryClient.js +0 -115
- package/src/gep/envFingerprint.js +0 -1
- package/src/gep/epigenetics.js +0 -1
- package/src/gep/execBridge.js +0 -1
- package/src/gep/executionTrace.js +0 -291
- package/src/gep/explore.js +0 -1
- package/src/gep/featureFlags.js +0 -121
- package/src/gep/gitOps.js +0 -265
- package/src/gep/hash.js +0 -1
- package/src/gep/hostErrorClassifier.js +0 -34
- package/src/gep/hubFetch.js +0 -1
- package/src/gep/hubReview.js +0 -1
- package/src/gep/hubSearch.js +0 -1
- package/src/gep/hubVerify.js +0 -1
- package/src/gep/idleScheduler.js +0 -400
- package/src/gep/issueReporter.js +0 -416
- package/src/gep/learningSignals.js +0 -1
- package/src/gep/llmReview.js +0 -92
- package/src/gep/localStateAwareness.js +0 -243
- package/src/gep/mailboxTransport.js +0 -119
- package/src/gep/memoryGraph.js +0 -1
- package/src/gep/memoryGraphAdapter.js +0 -1
- package/src/gep/mutation.js +0 -1
- package/src/gep/narrativeMemory.js +0 -1
- package/src/gep/oauthLogin.js +0 -181
- package/src/gep/openPRRegistry.js +0 -1
- package/src/gep/paths.js +0 -522
- package/src/gep/personality.js +0 -1
- package/src/gep/policyCheck.js +0 -1
- package/src/gep/portable.js +0 -103
- package/src/gep/privacyClient.js +0 -235
- package/src/gep/prompt.js +0 -1
- package/src/gep/questionGenerator.js +0 -518
- package/src/gep/recallInject.js +0 -1
- package/src/gep/recallVerifier.js +0 -1
- package/src/gep/reflection.js +0 -1
- package/src/gep/sanitize.js +0 -264
- package/src/gep/savingsCore.js +0 -1
- package/src/gep/schemas/capsule.js +0 -170
- package/src/gep/schemas/gene.js +0 -154
- package/src/gep/schemas/index.js +0 -8
- package/src/gep/schemas/protocol.js +0 -51
- package/src/gep/schemas/task.js +0 -74
- package/src/gep/selector.js +0 -1
- package/src/gep/selfPR.js +0 -469
- package/src/gep/signals.js +0 -776
- package/src/gep/skill2gep.js +0 -1056
- package/src/gep/skill2gepAudit.js +0 -303
- package/src/gep/skill2recipes.js +0 -511
- package/src/gep/skillDistiller.js +0 -1
- package/src/gep/skillPublisher.js +0 -358
- package/src/gep/solidify.js +0 -1
- package/src/gep/strategy.js +0 -1
- package/src/gep/taskReceiver.js +0 -575
- package/src/gep/tokenSavings.js +0 -1
- package/src/gep/trajectoryExport.js +0 -1
- package/src/gep/validationReport.js +0 -55
- package/src/gep/validator/index.js +0 -411
- package/src/gep/validator/reporter.js +0 -210
- package/src/gep/validator/sandboxExecutor.js +0 -480
- package/src/gep/validator/stakeBootstrap.js +0 -357
- package/src/gep/workspaceKeychain.js +0 -1
- package/src/ops/cleanup.js +0 -80
- package/src/ops/commentary.js +0 -60
- package/src/ops/health_check.js +0 -104
- package/src/ops/index.js +0 -11
- package/src/ops/innovation.js +0 -67
- package/src/ops/lifecycle.js +0 -798
- package/src/ops/self_repair.js +0 -76
- package/src/ops/skills_monitor.js +0 -147
- package/src/ops/trigger.js +0 -33
- package/src/proxy/clientSettings.js +0 -405
- package/src/proxy/envelope.js +0 -59
- package/src/proxy/extensions/dmHandler.js +0 -45
- package/src/proxy/extensions/sessionHandler.js +0 -141
- package/src/proxy/extensions/skillUpdater.js +0 -64
- package/src/proxy/extensions/traceControl.js +0 -1
- package/src/proxy/index.js +0 -1395
- package/src/proxy/inject.js +0 -1
- package/src/proxy/lifecycle/manager.js +0 -1568
- package/src/proxy/mailbox/state.js +0 -207
- package/src/proxy/mailbox/store.js +0 -602
- package/src/proxy/router/cache_passthrough.js +0 -26
- package/src/proxy/router/features.js +0 -84
- package/src/proxy/router/gemini_route.js +0 -154
- package/src/proxy/router/messages_route.js +0 -535
- package/src/proxy/router/model_router.js +0 -113
- package/src/proxy/router/models_route.js +0 -52
- package/src/proxy/router/ollama_route.js +0 -103
- package/src/proxy/router/responses_route.js +0 -170
- package/src/proxy/router/vertex_route.js +0 -110
- package/src/proxy/server/http.js +0 -363
- package/src/proxy/server/routes.js +0 -558
- package/src/proxy/server/settings.js +0 -115
- package/src/proxy/sync/engine.js +0 -179
- package/src/proxy/sync/inbound.js +0 -211
- package/src/proxy/sync/outbound.js +0 -361
- package/src/proxy/task/monitor.js +0 -131
- package/src/proxy/trace/extractor.js +0 -1
- package/src/proxy/trace/usage.js +0 -1
- package/src/solo/breaker.js +0 -25
- package/src/solo/gitGuard.js +0 -65
- package/src/webui/client/clientJs/assets.js +0 -111
- package/src/webui/client/clientJs/bootstrap.js +0 -92
- package/src/webui/client/clientJs/common.js +0 -77
- package/src/webui/client/clientJs/i18n.js +0 -366
- package/src/webui/client/clientJs/index.js +0 -35
- package/src/webui/client/clientJs/interactions.js +0 -351
- package/src/webui/client/clientJs/overview.js +0 -152
- package/src/webui/client/clientJs/personality.js +0 -285
- package/src/webui/client/clientJs/pipelines.js +0 -330
- package/src/webui/client/indexHtml.js +0 -221
- package/src/webui/client/static.js +0 -23
- package/src/webui/client/stylesCss.js +0 -639
- package/src/webui/client/vendor/README.md +0 -15
- package/src/webui/client/vendor/echarts.min.js +0 -45
- package/src/webui/index.js +0 -14
- package/src/webui/observer/assets.js +0 -146
- package/src/webui/observer/index.js +0 -37
- package/src/webui/observer/interactions.js +0 -127
- package/src/webui/observer/jsonl.js +0 -75
- package/src/webui/observer/paths.js +0 -46
- package/src/webui/observer/personality.js +0 -43
- package/src/webui/observer/pipelineEvents.js +0 -58
- package/src/webui/observer/redact.js +0 -63
- package/src/webui/observer/runs.js +0 -356
- package/src/webui/observer/safety.js +0 -57
- package/src/webui/observer/skills.js +0 -70
- package/src/webui/observer/status.js +0 -71
- package/src/webui/server/http.js +0 -138
- package/src/webui/server/routes.js +0 -41
package/src/adapters/opencode.js
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { copyHookScripts, removeHookScripts, removeMarkedSection, assertSafeConfigDir } = require('./hookAdapter');
|
|
4
|
-
|
|
5
|
-
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
|
-
const PLUGINS_DIR_NAME = 'plugins';
|
|
7
|
-
const PLUGIN_FILE_NAME = 'evolver.js';
|
|
8
|
-
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
9
|
-
// First line of the plugin file. Used to (a) prove the plugin file is one we
|
|
10
|
-
// wrote, so uninstall can safely delete it, and (b) skip overwriting if the
|
|
11
|
-
// user replaced it with a custom plugin.
|
|
12
|
-
const PLUGIN_HEADER = '// _evolver_managed: true (do not remove this line)';
|
|
13
|
-
|
|
14
|
-
function buildPluginSource(hooksDirAbsolute) {
|
|
15
|
-
// The plugin shells out to the same three Node scripts that every other
|
|
16
|
-
// evolver adapter uses, so the runtime behavior stays consistent across
|
|
17
|
-
// hosts. opencode loads .js files synchronously at startup and invokes
|
|
18
|
-
// the default-exported async factory with a context object.
|
|
19
|
-
return `${PLUGIN_HEADER}
|
|
20
|
-
// Auto-generated by \`evolver setup-hooks --platform=opencode\`.
|
|
21
|
-
// See https://opencode.ai/docs/plugins/ for the plugin API.
|
|
22
|
-
//
|
|
23
|
-
// This plugin wires opencode events to the three evolver hook scripts:
|
|
24
|
-
// session.created -> evolver-session-start.js (inject memory)
|
|
25
|
-
// tool.execute.after -> evolver-signal-detect.js (detect signals on writes/edits)
|
|
26
|
-
// session.idle -> evolver-session-end.js (record outcome)
|
|
27
|
-
//
|
|
28
|
-
// Each script is a stdin/stdout JSON filter -- nothing else is shared with
|
|
29
|
-
// opencode, so removing this file fully detaches evolver from opencode.
|
|
30
|
-
|
|
31
|
-
const { spawnSync } = require('node:child_process');
|
|
32
|
-
const path = require('node:path');
|
|
33
|
-
|
|
34
|
-
const HOOKS_DIR = ${JSON.stringify(hooksDirAbsolute)};
|
|
35
|
-
|
|
36
|
-
function runHook(scriptName, payload, timeoutMs) {
|
|
37
|
-
try {
|
|
38
|
-
const result = spawnSync('node', [path.join(HOOKS_DIR, scriptName)], {
|
|
39
|
-
input: JSON.stringify(payload || {}),
|
|
40
|
-
encoding: 'utf8',
|
|
41
|
-
timeout: timeoutMs,
|
|
42
|
-
});
|
|
43
|
-
if (!result || !result.stdout) return {};
|
|
44
|
-
try { return JSON.parse(result.stdout); } catch { return {}; }
|
|
45
|
-
} catch {
|
|
46
|
-
return {};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const Evolver = async () => ({
|
|
51
|
-
event: async ({ event }) => {
|
|
52
|
-
if (!event || typeof event.type !== 'string') return;
|
|
53
|
-
if (event.type === 'session.created') {
|
|
54
|
-
runHook('evolver-session-start.js', {
|
|
55
|
-
session_id: event.properties && event.properties.info && event.properties.info.id,
|
|
56
|
-
}, 3000);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
if (event.type === 'session.idle') {
|
|
60
|
-
runHook('evolver-session-end.js', {
|
|
61
|
-
session_id: event.properties && event.properties.sessionID,
|
|
62
|
-
}, 8000);
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
'tool.execute.after': async (input, output) => {
|
|
66
|
-
if (!input || typeof input.tool !== 'string') return;
|
|
67
|
-
if (input.tool !== 'write' && input.tool !== 'edit') return;
|
|
68
|
-
runHook('evolver-signal-detect.js', {
|
|
69
|
-
tool_input: (output && output.args) || {},
|
|
70
|
-
tool_response: (output && output.output) || (output && output.result) || {},
|
|
71
|
-
}, 2000);
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
module.exports = { Evolver };
|
|
76
|
-
module.exports.default = Evolver;
|
|
77
|
-
`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function buildAgentsMdSection() {
|
|
81
|
-
return `${EVOLVER_MARKER}
|
|
82
|
-
## Evolution Memory (Evolver)
|
|
83
|
-
|
|
84
|
-
This project uses evolver for self-evolution. Hooks automatically:
|
|
85
|
-
1. Run quietly at session start and load recent evolution memory when useful
|
|
86
|
-
2. Detect evolution signals during file edits
|
|
87
|
-
3. Record outcomes at session end
|
|
88
|
-
|
|
89
|
-
Use Evolver context only when it is directly relevant. Do not narrate routine Evolver checks, hook status, or empty recall/search results to the user.
|
|
90
|
-
Signals: log_error, perf_bottleneck, user_feature_request, capability_gap, deployment_issue, test_failure.`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function appendSectionToFile(filePath, marker, content) {
|
|
94
|
-
let existing = '';
|
|
95
|
-
try { existing = fs.readFileSync(filePath, 'utf8'); } catch { /* new file */ }
|
|
96
|
-
if (existing.includes(marker)) return false;
|
|
97
|
-
const separator = existing.length > 0 && !existing.endsWith('\n') ? '\n\n' : '\n';
|
|
98
|
-
fs.writeFileSync(filePath, existing + separator + content + '\n', 'utf8');
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function isEvolverManagedPluginFile(filePath) {
|
|
103
|
-
try {
|
|
104
|
-
if (!fs.existsSync(filePath)) return false;
|
|
105
|
-
const raw = fs.readFileSync(filePath, 'utf8');
|
|
106
|
-
return raw.includes('_evolver_managed: true');
|
|
107
|
-
} catch {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function writePluginFile(pluginsDir, source) {
|
|
113
|
-
fs.mkdirSync(pluginsDir, { recursive: true });
|
|
114
|
-
const dest = path.join(pluginsDir, PLUGIN_FILE_NAME);
|
|
115
|
-
const tmp = dest + '.tmp';
|
|
116
|
-
fs.writeFileSync(tmp, source, 'utf8');
|
|
117
|
-
fs.renameSync(tmp, dest);
|
|
118
|
-
return dest;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function install({ configRoot, evolverRoot, force }) {
|
|
122
|
-
const opencodeDir = path.join(configRoot, '.opencode');
|
|
123
|
-
const hooksDir = path.join(opencodeDir, HOOK_SCRIPTS_DIR_NAME);
|
|
124
|
-
const pluginsDir = path.join(opencodeDir, PLUGINS_DIR_NAME);
|
|
125
|
-
const pluginPath = path.join(pluginsDir, PLUGIN_FILE_NAME);
|
|
126
|
-
const agentsMdPath = path.join(configRoot, 'AGENTS.md');
|
|
127
|
-
assertSafeConfigDir(opencodeDir, '.opencode', { subdirs: [HOOK_SCRIPTS_DIR_NAME, PLUGINS_DIR_NAME] });
|
|
128
|
-
|
|
129
|
-
if (!force && isEvolverManagedPluginFile(pluginPath)) {
|
|
130
|
-
console.log('[opencode] Evolver plugin already installed. Use --force to overwrite.');
|
|
131
|
-
printPostInstallNotice(pluginPath);
|
|
132
|
-
return { ok: true, skipped: true, plugin_path: pluginPath };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
fs.mkdirSync(opencodeDir, { recursive: true });
|
|
136
|
-
|
|
137
|
-
const written = writePluginFile(pluginsDir, buildPluginSource(hooksDir));
|
|
138
|
-
console.log('[opencode] Wrote ' + written);
|
|
139
|
-
|
|
140
|
-
const copied = copyHookScripts(hooksDir, path.join(evolverRoot, 'src', 'adapters'));
|
|
141
|
-
console.log('[opencode] Copied ' + copied.length + ' hook scripts to ' + hooksDir);
|
|
142
|
-
|
|
143
|
-
const injected = appendSectionToFile(agentsMdPath, EVOLVER_MARKER, buildAgentsMdSection());
|
|
144
|
-
if (injected) {
|
|
145
|
-
console.log('[opencode] Injected evolution section into ' + agentsMdPath);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
console.log('[opencode] Installation complete.');
|
|
149
|
-
printPostInstallNotice(written);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
ok: true,
|
|
153
|
-
platform: 'opencode',
|
|
154
|
-
plugin_path: written,
|
|
155
|
-
files: [written, agentsMdPath, ...copied],
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function printPostInstallNotice(pluginPath) {
|
|
160
|
-
// The opencode TUI "Plugins" tab only lists TUI plugins (registered via
|
|
161
|
-
// tui.json with `default export { id, tui }`). Server plugins like ours,
|
|
162
|
-
// auto-loaded from .opencode/plugins/, are functional but invisible in
|
|
163
|
-
// that tab. This is by opencode design, not a bug. See:
|
|
164
|
-
// https://github.com/sst/opencode -> packages/opencode/specs/tui-plugins.md
|
|
165
|
-
// Surfacing this proactively here prevents the "is it actually loaded?"
|
|
166
|
-
// confusion that motivated EvoMap/evolver issue #531.
|
|
167
|
-
console.log('');
|
|
168
|
-
console.log('[opencode] Restart opencode for the plugin to take effect.');
|
|
169
|
-
console.log('[opencode] Note: this is a SERVER plugin (event hooks). It will NOT appear in');
|
|
170
|
-
console.log('[opencode] the TUI "Plugins" tab -- that tab only lists TUI plugins');
|
|
171
|
-
console.log('[opencode] (registered via tui.json). The plugin is still loaded and');
|
|
172
|
-
console.log('[opencode] running silently in the background.');
|
|
173
|
-
console.log('[opencode] To verify the plugin is loaded, run:');
|
|
174
|
-
console.log('[opencode] opencode --print-logs --log-level INFO debug config 2>&1 | grep ' + JSON.stringify(pluginPath));
|
|
175
|
-
console.log('[opencode] Or run:');
|
|
176
|
-
console.log('[opencode] evolver setup-hooks --platform=opencode --verify');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Walk the install state and report what is healthy / what is missing.
|
|
180
|
-
// Used by the `--verify` flag to give users a definitive answer to
|
|
181
|
-
// "is the plugin actually installed and loadable?". Returns a structured
|
|
182
|
-
// result so callers (CLI, future TUI plugin) can format it as they like.
|
|
183
|
-
function verify({ configRoot }) {
|
|
184
|
-
const opencodeDir = path.join(configRoot, '.opencode');
|
|
185
|
-
const hooksDir = path.join(opencodeDir, HOOK_SCRIPTS_DIR_NAME);
|
|
186
|
-
const pluginsDir = path.join(opencodeDir, PLUGINS_DIR_NAME);
|
|
187
|
-
const pluginPath = path.join(pluginsDir, PLUGIN_FILE_NAME);
|
|
188
|
-
const agentsMdPath = path.join(configRoot, 'AGENTS.md');
|
|
189
|
-
const expectedScripts = [
|
|
190
|
-
'evolver-session-start.js',
|
|
191
|
-
'evolver-signal-detect.js',
|
|
192
|
-
'evolver-session-end.js',
|
|
193
|
-
];
|
|
194
|
-
|
|
195
|
-
const checks = [];
|
|
196
|
-
|
|
197
|
-
const pluginExists = fs.existsSync(pluginPath);
|
|
198
|
-
checks.push({
|
|
199
|
-
id: 'plugin_file_present',
|
|
200
|
-
ok: pluginExists,
|
|
201
|
-
detail: pluginExists ? pluginPath : 'missing: ' + pluginPath,
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
const managed = pluginExists && isEvolverManagedPluginFile(pluginPath);
|
|
205
|
-
checks.push({
|
|
206
|
-
id: 'plugin_managed_marker',
|
|
207
|
-
ok: managed,
|
|
208
|
-
detail: managed
|
|
209
|
-
? 'first line contains _evolver_managed: true'
|
|
210
|
-
: 'plugin file is not evolver-managed (was it edited or replaced by another tool?)',
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
let pluginLoadable = false;
|
|
214
|
-
let pluginLoadError = null;
|
|
215
|
-
if (pluginExists) {
|
|
216
|
-
try {
|
|
217
|
-
// Require the plugin in an isolated module cache slot to confirm it
|
|
218
|
-
// parses and exports the expected shape. opencode does an ESM dynamic
|
|
219
|
-
// import; CommonJS require here is a strict subset of that, so a
|
|
220
|
-
// failure here is a guaranteed failure under opencode too.
|
|
221
|
-
delete require.cache[require.resolve(pluginPath)];
|
|
222
|
-
const mod = require(pluginPath);
|
|
223
|
-
const fn = mod && (mod.Evolver || mod.default);
|
|
224
|
-
pluginLoadable = typeof fn === 'function';
|
|
225
|
-
if (!pluginLoadable) pluginLoadError = 'no Evolver/default function export';
|
|
226
|
-
} catch (err) {
|
|
227
|
-
pluginLoadError = (err && err.message) || String(err);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
checks.push({
|
|
231
|
-
id: 'plugin_loadable',
|
|
232
|
-
ok: pluginLoadable,
|
|
233
|
-
detail: pluginLoadable
|
|
234
|
-
? 'require() succeeded and exports Evolver()'
|
|
235
|
-
: 'require() failed: ' + (pluginLoadError || 'unknown'),
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
const missingScripts = expectedScripts.filter(
|
|
239
|
-
(name) => !fs.existsSync(path.join(hooksDir, name))
|
|
240
|
-
);
|
|
241
|
-
checks.push({
|
|
242
|
-
id: 'hook_scripts_present',
|
|
243
|
-
ok: missingScripts.length === 0,
|
|
244
|
-
detail: missingScripts.length === 0
|
|
245
|
-
? 'all 3 hook scripts present in ' + hooksDir
|
|
246
|
-
: 'missing: ' + missingScripts.join(', '),
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
let agentsMdHasSection = false;
|
|
250
|
-
try {
|
|
251
|
-
if (fs.existsSync(agentsMdPath)) {
|
|
252
|
-
agentsMdHasSection = fs.readFileSync(agentsMdPath, 'utf8').includes(EVOLVER_MARKER);
|
|
253
|
-
}
|
|
254
|
-
} catch { /* ignore */ }
|
|
255
|
-
checks.push({
|
|
256
|
-
id: 'agents_md_section',
|
|
257
|
-
ok: agentsMdHasSection,
|
|
258
|
-
detail: agentsMdHasSection
|
|
259
|
-
? 'AGENTS.md contains evolution memory section'
|
|
260
|
-
: 'AGENTS.md is missing or has no evolution section (re-run install)',
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
const allOk = checks.every((c) => c.ok);
|
|
264
|
-
|
|
265
|
-
return {
|
|
266
|
-
ok: allOk,
|
|
267
|
-
plugin_path: pluginPath,
|
|
268
|
-
hooks_dir: hooksDir,
|
|
269
|
-
config_root: configRoot,
|
|
270
|
-
checks,
|
|
271
|
-
note: allOk
|
|
272
|
-
? 'Plugin is installed and loadable. opencode\'s TUI "Plugins" tab will not list it -- that tab only shows TUI plugins. Run `opencode --print-logs --log-level INFO debug config` and grep for the plugin path to confirm opencode loads it at startup.'
|
|
273
|
-
: 'One or more checks failed. Re-run `evolver setup-hooks --platform=opencode --force` to repair.',
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function printVerifyReport(report) {
|
|
278
|
-
console.log('[opencode] Verify report');
|
|
279
|
-
console.log('[opencode] plugin path : ' + report.plugin_path);
|
|
280
|
-
console.log('[opencode] hooks dir : ' + report.hooks_dir);
|
|
281
|
-
console.log('[opencode] config root : ' + report.config_root);
|
|
282
|
-
console.log('[opencode] Checks:');
|
|
283
|
-
for (const c of report.checks) {
|
|
284
|
-
console.log('[opencode] ' + (c.ok ? '[OK] ' : '[FAIL]') + ' ' + c.id + ' -- ' + c.detail);
|
|
285
|
-
}
|
|
286
|
-
console.log('[opencode] ' + (report.ok ? 'All checks passed.' : 'Some checks failed.'));
|
|
287
|
-
console.log('[opencode] ' + report.note);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function uninstall({ configRoot }) {
|
|
291
|
-
const opencodeDir = path.join(configRoot, '.opencode');
|
|
292
|
-
const hooksDir = path.join(opencodeDir, HOOK_SCRIPTS_DIR_NAME);
|
|
293
|
-
const pluginsDir = path.join(opencodeDir, PLUGINS_DIR_NAME);
|
|
294
|
-
const pluginPath = path.join(pluginsDir, PLUGIN_FILE_NAME);
|
|
295
|
-
const agentsMdPath = path.join(configRoot, 'AGENTS.md');
|
|
296
|
-
assertSafeConfigDir(opencodeDir, '.opencode', { subdirs: [HOOK_SCRIPTS_DIR_NAME, PLUGINS_DIR_NAME] });
|
|
297
|
-
|
|
298
|
-
let changed = false;
|
|
299
|
-
|
|
300
|
-
if (isEvolverManagedPluginFile(pluginPath)) {
|
|
301
|
-
try { fs.unlinkSync(pluginPath); changed = true; } catch { /* ignore */ }
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const scripts = removeHookScripts(hooksDir);
|
|
305
|
-
if (scripts > 0) changed = true;
|
|
306
|
-
|
|
307
|
-
if (removeMarkedSection(agentsMdPath, EVOLVER_MARKER)) {
|
|
308
|
-
changed = true;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
console.log(changed
|
|
312
|
-
? '[opencode] Uninstalled evolver plugin and hooks.'
|
|
313
|
-
: '[opencode] No evolver plugin found to uninstall.');
|
|
314
|
-
|
|
315
|
-
return { ok: true, removed: changed };
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
module.exports = {
|
|
319
|
-
install,
|
|
320
|
-
uninstall,
|
|
321
|
-
verify,
|
|
322
|
-
printVerifyReport,
|
|
323
|
-
buildPluginSource,
|
|
324
|
-
isEvolverManagedPluginFile,
|
|
325
|
-
PLUGIN_FILE_NAME,
|
|
326
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// _lockPaths.js
|
|
2
|
-
// Single source of truth for the daemon singleton-lock location and lease
|
|
3
|
-
// tunables, shared by the daemon (index.js) and the session-start hook's
|
|
4
|
-
// auto-restart guard (evolver-session-start.js).
|
|
5
|
-
//
|
|
6
|
-
// Issue #176: the hook used to replicate this logic inline ("keep index.js
|
|
7
|
-
// out of the hook's require graph"), which could silently diverge whenever
|
|
8
|
-
// the daemon's lock resolution changed. This module keeps that property —
|
|
9
|
-
// it depends only on fs/os/path — while making divergence structurally
|
|
10
|
-
// impossible.
|
|
11
|
-
//
|
|
12
|
-
// Deployed-layout constraint (PR #163): hook scripts are COPIED into the
|
|
13
|
-
// host's hooks dir (e.g. `.claude/hooks/`) and run from there, so every
|
|
14
|
-
// same-dir helper they require must be a sibling file listed in
|
|
15
|
-
// hookAdapter.js's copy/remove lists (enforced by test/adapters.test.js).
|
|
16
|
-
|
|
17
|
-
const fs = require('fs');
|
|
18
|
-
const os = require('os');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
// Round-4 (see the history note above index.js's daemon-lock block): the
|
|
22
|
-
// pidfile previously defaulted to __dirname, which differs per install mode
|
|
23
|
-
// (global install vs dev clone vs npx cache), so two daemons launched under
|
|
24
|
-
// different install modes never saw each other's lock. Default now lives
|
|
25
|
-
// under the per-user state dir so all install modes converge.
|
|
26
|
-
// EVOLVER_LOCK_DIR still overrides for tests / sandboxed runs — note the
|
|
27
|
-
// basename differs from the default in that case (`evolver.pid` vs
|
|
28
|
-
// `instance.lock`).
|
|
29
|
-
function getLockFilePath(env) {
|
|
30
|
-
const e = env || process.env;
|
|
31
|
-
if (e.EVOLVER_LOCK_DIR) {
|
|
32
|
-
return path.join(e.EVOLVER_LOCK_DIR, 'evolver.pid');
|
|
33
|
-
}
|
|
34
|
-
// os.homedir() is cross-platform; process.env.HOME is unset on Windows.
|
|
35
|
-
return path.join(os.homedir(), '.evomap', 'instance.lock');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Round-9: lease tunables for the daemon lock. A live daemon refreshes the
|
|
39
|
-
// lock mtime every LOCK_REFRESH_MS; a lock whose mtime is older than
|
|
40
|
-
// STALE_LOCK_TTL_MS (and that was written by a lease-aware daemon) is
|
|
41
|
-
// treated as stale even if its PID happens to be alive — closing the
|
|
42
|
-
// "crash + PID reuse -> new daemon silently refuses to start" hole and the
|
|
43
|
-
// "SIGKILL leaves a stale lock nobody reclaims" hole. The TTL is well above
|
|
44
|
-
// the heartbeat interval (default 6min) so a healthy daemon never trips it.
|
|
45
|
-
// On Windows, SIGTERM is implemented as TerminateProcess() (not a catchable
|
|
46
|
-
// signal), so the daemon's releaseLock() never runs and the lock file stays
|
|
47
|
-
// on disk with the dead PID — hence the shorter Windows TTL, with a 1-min
|
|
48
|
-
// refresh (3x margin against transient FS hiccups). Unix: 5 min TTL is
|
|
49
|
-
// 2.5x the 2-min refresh cadence.
|
|
50
|
-
const STALE_LOCK_TTL_MS = process.platform === 'win32' ? 3 * 60_000 : 5 * 60_000;
|
|
51
|
-
const LOCK_REFRESH_MS = process.platform === 'win32' ? 1 * 60_000 : 2 * 60_000;
|
|
52
|
-
|
|
53
|
-
// Returns true if the lock was written by a lease-aware daemon AND its
|
|
54
|
-
// mtime is older than the stale TTL — i.e. no live owner is refreshing it,
|
|
55
|
-
// so it is safe to treat the recorded PID as dead regardless of whether
|
|
56
|
-
// process.kill(pid, 0) resolves (the PID may have been reused). Locks
|
|
57
|
-
// written by pre-lease daemons (payload.lease !== true) are never judged
|
|
58
|
-
// stale by mtime, so we never falsely steal an older daemon's lock.
|
|
59
|
-
function lockIsStaleByLease(lockFile, payload) {
|
|
60
|
-
if (!payload || payload.lease !== true) return false;
|
|
61
|
-
try {
|
|
62
|
-
const ageMs = Date.now() - fs.statSync(lockFile).mtimeMs;
|
|
63
|
-
return ageMs > STALE_LOCK_TTL_MS;
|
|
64
|
-
} catch (_) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = {
|
|
70
|
-
getLockFilePath,
|
|
71
|
-
lockIsStaleByLease,
|
|
72
|
-
STALE_LOCK_TTL_MS,
|
|
73
|
-
LOCK_REFRESH_MS,
|
|
74
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// _memoryFiltering.js
|
|
2
|
-
// Shared memory filtering logic for evolver hooks (platform-independent).
|
|
3
|
-
//
|
|
4
|
-
// Responsibility: Filter evolution memory outcomes to reduce noise in Claude/Codex context.
|
|
5
|
-
// - Removes failed outcomes (no learning value)
|
|
6
|
-
// - Filters low-confidence outcomes (score < 0.5)
|
|
7
|
-
// - Enforces time bounds (< 7 days old)
|
|
8
|
-
// - Limits result size (max 3 outcomes)
|
|
9
|
-
|
|
10
|
-
const DEFAULT_MIN_SCORE = 0.5;
|
|
11
|
-
const DEFAULT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
12
|
-
const DEFAULT_MAX_OUTCOMES = 3;
|
|
13
|
-
|
|
14
|
-
function filterRelevantOutcomes(entries, opts = {}) {
|
|
15
|
-
const minScore = opts.minScore !== undefined ? opts.minScore : DEFAULT_MIN_SCORE;
|
|
16
|
-
const maxAgeMs = opts.maxAgeMs !== undefined ? opts.maxAgeMs : DEFAULT_MAX_AGE_MS;
|
|
17
|
-
const maxOutcomes = opts.maxOutcomes !== undefined ? opts.maxOutcomes : DEFAULT_MAX_OUTCOMES;
|
|
18
|
-
|
|
19
|
-
const now = Date.now();
|
|
20
|
-
|
|
21
|
-
return entries
|
|
22
|
-
.filter(e => {
|
|
23
|
-
// Only keep 'success' outcomes (failed ones don't provide learning value)
|
|
24
|
-
if (e.outcome?.status !== 'success') return false;
|
|
25
|
-
// Only keep high-confidence outcomes
|
|
26
|
-
if ((e.outcome?.score ?? 0) < minScore) return false;
|
|
27
|
-
// Only keep recent outcomes
|
|
28
|
-
const ts = e.timestamp ? new Date(e.timestamp).getTime() : 0;
|
|
29
|
-
if (now - ts > maxAgeMs) return false;
|
|
30
|
-
return true;
|
|
31
|
-
})
|
|
32
|
-
.slice(-maxOutcomes);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = { filterRelevantOutcomes, DEFAULT_MIN_SCORE, DEFAULT_MAX_AGE_MS, DEFAULT_MAX_OUTCOMES };
|