@evomap/evolver 1.89.20 → 2.0.0-beta.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/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 -3586
- 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/skills/_meta/SKILL.md +0 -41
- package/skills/index.json +0 -14
- 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 -590
- 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 -320
- 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/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
|
@@ -1,558 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { PROXY_PROTOCOL_VERSION, SCHEMA_VERSION } = require('../mailbox/store');
|
|
4
|
-
|
|
5
|
-
function buildRoutes(store, proxyHandlers, taskMonitor, extensions) {
|
|
6
|
-
const {
|
|
7
|
-
dmHandler,
|
|
8
|
-
skillUpdater,
|
|
9
|
-
getHubMailboxStatus,
|
|
10
|
-
sessionHandler,
|
|
11
|
-
messagesHandler,
|
|
12
|
-
responsesHandler,
|
|
13
|
-
geminiHandler,
|
|
14
|
-
chatCompletionsHandler,
|
|
15
|
-
modelsHandler,
|
|
16
|
-
ollamaChatHandler,
|
|
17
|
-
ollamaGenerateHandler,
|
|
18
|
-
vertexHandler,
|
|
19
|
-
} = extensions || {};
|
|
20
|
-
const routes = {
|
|
21
|
-
// -- Mailbox --
|
|
22
|
-
'POST /mailbox/send': async ({ body }) => {
|
|
23
|
-
if (!body.type) throw Object.assign(new Error('type is required'), { statusCode: 400 });
|
|
24
|
-
if (!body.payload) throw Object.assign(new Error('payload is required'), { statusCode: 400 });
|
|
25
|
-
const result = store.send({
|
|
26
|
-
type: body.type,
|
|
27
|
-
payload: body.payload,
|
|
28
|
-
channel: body.channel,
|
|
29
|
-
priority: body.priority,
|
|
30
|
-
refId: body.ref_id,
|
|
31
|
-
expiresAt: body.expires_at,
|
|
32
|
-
});
|
|
33
|
-
return { body: result };
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
'POST /mailbox/poll': async ({ body }) => {
|
|
37
|
-
const messages = store.poll({
|
|
38
|
-
channel: body.channel,
|
|
39
|
-
type: body.type,
|
|
40
|
-
limit: body.limit,
|
|
41
|
-
});
|
|
42
|
-
return { body: { messages, count: messages.length } };
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
'POST /mailbox/ack': async ({ body }) => {
|
|
46
|
-
if (!body.message_ids) throw Object.assign(new Error('message_ids is required'), { statusCode: 400 });
|
|
47
|
-
const count = store.ack(body.message_ids);
|
|
48
|
-
return { body: { acknowledged: count } };
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
'GET /mailbox/list': async ({ query }) => {
|
|
52
|
-
if (!query.type) throw Object.assign(new Error('type query param is required'), { statusCode: 400 });
|
|
53
|
-
const messages = store.list({
|
|
54
|
-
type: query.type,
|
|
55
|
-
direction: query.direction,
|
|
56
|
-
status: query.status,
|
|
57
|
-
limit: Number(query.limit) || 20,
|
|
58
|
-
offset: Number(query.offset) || 0,
|
|
59
|
-
});
|
|
60
|
-
return { body: { messages, count: messages.length } };
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
'GET /mailbox/status/:id': async ({ params }) => {
|
|
64
|
-
const msg = store.getById(params.id);
|
|
65
|
-
if (!msg) throw Object.assign(new Error('Message not found'), { statusCode: 404 });
|
|
66
|
-
return { body: msg };
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
// -- Asset (proxy HTTP) --
|
|
70
|
-
'POST /asset/validate': async ({ body }) => {
|
|
71
|
-
if (!body.asset_id && !body.assets) {
|
|
72
|
-
throw Object.assign(new Error('asset_id or assets is required'), { statusCode: 400 });
|
|
73
|
-
}
|
|
74
|
-
const result = await proxyHandlers.assetValidate(body);
|
|
75
|
-
return { body: result };
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
'POST /asset/fetch': async ({ body }) => {
|
|
79
|
-
const result = await proxyHandlers.assetFetch(body);
|
|
80
|
-
return { body: result };
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
// Reuse-attribution report: the agent declares which fetched assets it
|
|
84
|
-
// actually reused. Forwarded flat (not enveloped) to the hub's
|
|
85
|
-
// /a2a/memory/record; the proxy stamps its own node as sender_id and the
|
|
86
|
-
// hub cross-verifies against AssetFetcher. Best-effort — never throws on a
|
|
87
|
-
// hub error so a report failure can't break the calling agent.
|
|
88
|
-
'POST /asset/report-reuse': async ({ body }) => {
|
|
89
|
-
const result = await proxyHandlers.reportReuse(body || {});
|
|
90
|
-
return { body: result };
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
'POST /asset/search': async ({ body }) => {
|
|
94
|
-
const result = await proxyHandlers.assetSearch(body);
|
|
95
|
-
return { body: result };
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
'POST /asset/submit': async ({ body }) => {
|
|
99
|
-
// The publish path builds a bundle from full asset objects; a bare
|
|
100
|
-
// asset_id is not a valid input here (Bugbot #256 Medium — route used to
|
|
101
|
-
// accept asset_id the handler then ignored).
|
|
102
|
-
if (!body.assets && !body.asset) {
|
|
103
|
-
throw Object.assign(new Error('assets (array) or asset (single object) is required'), { statusCode: 400 });
|
|
104
|
-
}
|
|
105
|
-
// Publish synchronously via the signed Gene+Capsule bundle path
|
|
106
|
-
// (POST /a2a/publish). The old `asset_submit` mailbox dispatch is gated
|
|
107
|
-
// off at the Hub (A2A_MAILBOX_ASSET_SUBMIT_ENABLED), so it silently
|
|
108
|
-
// failed; the Hub now enforces bundles. Returns the per-asset Hub result.
|
|
109
|
-
const result = await proxyHandlers.assetPublish(body);
|
|
110
|
-
return { body: result };
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
'POST /conversation/distill': async ({ body }) => {
|
|
114
|
-
const { distillConversation } = require('../../gep/conversationDistiller');
|
|
115
|
-
const input = body || {};
|
|
116
|
-
const distill = distillConversation(input, { persist: input.persist !== false });
|
|
117
|
-
if (!distill.ok) return { body: distill };
|
|
118
|
-
|
|
119
|
-
let publishResult = null;
|
|
120
|
-
if (input.publish !== false) {
|
|
121
|
-
publishResult = await proxyHandlers.assetPublish({
|
|
122
|
-
assets: [distill.gene, distill.capsule].filter(Boolean),
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
body: {
|
|
128
|
-
...distill,
|
|
129
|
-
queued: false,
|
|
130
|
-
published: Boolean(publishResult),
|
|
131
|
-
publish_result: publishResult,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
'GET /asset/submissions': async ({ query }) => {
|
|
137
|
-
const submissions = store.list({
|
|
138
|
-
type: 'asset_submit',
|
|
139
|
-
direction: 'outbound',
|
|
140
|
-
status: query.status || undefined,
|
|
141
|
-
limit: Number(query.limit) || 20,
|
|
142
|
-
offset: Number(query.offset) || 0,
|
|
143
|
-
});
|
|
144
|
-
const submissionIds = new Set(submissions.map(s => s.id));
|
|
145
|
-
const resultMap = {};
|
|
146
|
-
for (const [, msg] of store._messages) {
|
|
147
|
-
if (msg.type !== 'asset_submit_result' || msg.direction !== 'inbound') continue;
|
|
148
|
-
const refId = msg.payload?.ref_id;
|
|
149
|
-
if (refId && submissionIds.has(refId)) resultMap[refId] = msg;
|
|
150
|
-
}
|
|
151
|
-
const enriched = submissions.map(s => ({
|
|
152
|
-
...s,
|
|
153
|
-
result: resultMap[s.id] ? { ...resultMap[s.id] } : null,
|
|
154
|
-
}));
|
|
155
|
-
return { body: { submissions: enriched, count: enriched.length } };
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
// -- Task --
|
|
159
|
-
'POST /task/subscribe': async ({ body }) => {
|
|
160
|
-
if (taskMonitor) {
|
|
161
|
-
const result = taskMonitor.subscribe(body.capability_filter || body.filters || []);
|
|
162
|
-
return { body: result };
|
|
163
|
-
}
|
|
164
|
-
const result = store.send({
|
|
165
|
-
type: 'task_subscribe',
|
|
166
|
-
payload: body || {},
|
|
167
|
-
});
|
|
168
|
-
return { body: result };
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
'POST /task/unsubscribe': async ({ body }) => {
|
|
172
|
-
if (taskMonitor) {
|
|
173
|
-
const result = taskMonitor.unsubscribe();
|
|
174
|
-
return { body: result };
|
|
175
|
-
}
|
|
176
|
-
const result = store.send({
|
|
177
|
-
type: 'task_unsubscribe',
|
|
178
|
-
payload: body || {},
|
|
179
|
-
});
|
|
180
|
-
return { body: result };
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
'GET /task/list': async ({ query }) => {
|
|
184
|
-
const messages = store.poll({
|
|
185
|
-
type: 'task_available',
|
|
186
|
-
limit: Number(query.limit) || 20,
|
|
187
|
-
});
|
|
188
|
-
return { body: { tasks: messages, count: messages.length } };
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
'POST /task/claim': async ({ body }) => {
|
|
192
|
-
if (!body.task_id) throw Object.assign(new Error('task_id is required'), { statusCode: 400 });
|
|
193
|
-
const result = store.send({
|
|
194
|
-
type: 'task_claim',
|
|
195
|
-
payload: body,
|
|
196
|
-
priority: 'high',
|
|
197
|
-
});
|
|
198
|
-
if (taskMonitor) taskMonitor.recordClaim(body.task_id);
|
|
199
|
-
return { body: result };
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
'POST /task/complete': async ({ body }) => {
|
|
203
|
-
if (!body.task_id) throw Object.assign(new Error('task_id is required'), { statusCode: 400 });
|
|
204
|
-
const result = store.send({
|
|
205
|
-
type: 'task_complete',
|
|
206
|
-
payload: body,
|
|
207
|
-
});
|
|
208
|
-
if (taskMonitor) taskMonitor.recordComplete(body.task_id, body.started_at);
|
|
209
|
-
return { body: result };
|
|
210
|
-
},
|
|
211
|
-
|
|
212
|
-
'GET /task/metrics': async () => {
|
|
213
|
-
if (!taskMonitor) {
|
|
214
|
-
return { body: { subscribed: false, metrics: null } };
|
|
215
|
-
}
|
|
216
|
-
return { body: taskMonitor.getMetrics() };
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
// -- DM (Direct Message) --
|
|
220
|
-
'POST /dm/send': async ({ body }) => {
|
|
221
|
-
if (!body.recipient_node_id) {
|
|
222
|
-
throw Object.assign(new Error('recipient_node_id is required'), { statusCode: 400 });
|
|
223
|
-
}
|
|
224
|
-
if (!body.content) {
|
|
225
|
-
throw Object.assign(new Error('content is required'), { statusCode: 400 });
|
|
226
|
-
}
|
|
227
|
-
if (dmHandler) {
|
|
228
|
-
const result = dmHandler.send({
|
|
229
|
-
recipientNodeId: body.recipient_node_id,
|
|
230
|
-
content: body.content,
|
|
231
|
-
metadata: body.metadata,
|
|
232
|
-
});
|
|
233
|
-
return { body: result };
|
|
234
|
-
}
|
|
235
|
-
const result = store.send({
|
|
236
|
-
type: 'dm',
|
|
237
|
-
payload: {
|
|
238
|
-
recipient_node_id: body.recipient_node_id,
|
|
239
|
-
content: body.content,
|
|
240
|
-
metadata: body.metadata || {},
|
|
241
|
-
},
|
|
242
|
-
});
|
|
243
|
-
return { body: result };
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
'POST /dm/poll': async ({ body }) => {
|
|
247
|
-
if (dmHandler) {
|
|
248
|
-
const messages = dmHandler.poll({ limit: body.limit });
|
|
249
|
-
return { body: { messages, count: messages.length } };
|
|
250
|
-
}
|
|
251
|
-
const messages = store.poll({ type: 'dm', limit: body.limit || 20 });
|
|
252
|
-
return { body: { messages, count: messages.length } };
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
'GET /dm/list': async ({ query }) => {
|
|
256
|
-
if (dmHandler) {
|
|
257
|
-
const messages = dmHandler.list({
|
|
258
|
-
limit: Number(query.limit) || 20,
|
|
259
|
-
offset: Number(query.offset) || 0,
|
|
260
|
-
});
|
|
261
|
-
return { body: { messages, count: messages.length } };
|
|
262
|
-
}
|
|
263
|
-
const messages = store.list({
|
|
264
|
-
type: 'dm',
|
|
265
|
-
limit: Number(query.limit) || 20,
|
|
266
|
-
offset: Number(query.offset) || 0,
|
|
267
|
-
});
|
|
268
|
-
return { body: { messages, count: messages.length } };
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
// -- Session (Collaboration) --
|
|
272
|
-
'POST /session/create': async ({ body }) => {
|
|
273
|
-
if (!body.title) throw Object.assign(new Error('title is required'), { statusCode: 400 });
|
|
274
|
-
if (sessionHandler) {
|
|
275
|
-
const result = sessionHandler.createSession({
|
|
276
|
-
title: body.title,
|
|
277
|
-
description: body.description,
|
|
278
|
-
inviteNodeIds: body.invite_node_ids,
|
|
279
|
-
maxParticipants: body.max_participants,
|
|
280
|
-
});
|
|
281
|
-
return { body: result };
|
|
282
|
-
}
|
|
283
|
-
const result = store.send({
|
|
284
|
-
type: 'session_create',
|
|
285
|
-
payload: {
|
|
286
|
-
title: body.title,
|
|
287
|
-
description: body.description || '',
|
|
288
|
-
invite_node_ids: body.invite_node_ids || [],
|
|
289
|
-
max_participants: body.max_participants || 5,
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
return { body: result };
|
|
293
|
-
},
|
|
294
|
-
|
|
295
|
-
'POST /session/join': async ({ body }) => {
|
|
296
|
-
if (!body.session_id) throw Object.assign(new Error('session_id is required'), { statusCode: 400 });
|
|
297
|
-
if (sessionHandler) {
|
|
298
|
-
const result = sessionHandler.joinSession({ sessionId: body.session_id });
|
|
299
|
-
return { body: result };
|
|
300
|
-
}
|
|
301
|
-
const result = store.send({ type: 'session_join', payload: { session_id: body.session_id } });
|
|
302
|
-
return { body: result };
|
|
303
|
-
},
|
|
304
|
-
|
|
305
|
-
'POST /session/leave': async ({ body }) => {
|
|
306
|
-
if (!body.session_id) throw Object.assign(new Error('session_id is required'), { statusCode: 400 });
|
|
307
|
-
if (sessionHandler) {
|
|
308
|
-
const result = sessionHandler.leaveSession({ sessionId: body.session_id });
|
|
309
|
-
return { body: result };
|
|
310
|
-
}
|
|
311
|
-
const result = store.send({ type: 'session_leave', payload: { session_id: body.session_id } });
|
|
312
|
-
return { body: result };
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
'POST /session/message': async ({ body }) => {
|
|
316
|
-
if (!body.session_id) throw Object.assign(new Error('session_id is required'), { statusCode: 400 });
|
|
317
|
-
if (sessionHandler) {
|
|
318
|
-
const result = sessionHandler.sendMessage({
|
|
319
|
-
sessionId: body.session_id,
|
|
320
|
-
toNodeId: body.to_node_id,
|
|
321
|
-
msgType: body.msg_type,
|
|
322
|
-
payload: body.payload,
|
|
323
|
-
});
|
|
324
|
-
return { body: result };
|
|
325
|
-
}
|
|
326
|
-
const result = store.send({
|
|
327
|
-
type: 'session_message',
|
|
328
|
-
payload: {
|
|
329
|
-
session_id: body.session_id,
|
|
330
|
-
to_node_id: body.to_node_id || null,
|
|
331
|
-
msg_type: body.msg_type || 'context_update',
|
|
332
|
-
payload: body.payload || {},
|
|
333
|
-
},
|
|
334
|
-
});
|
|
335
|
-
return { body: result };
|
|
336
|
-
},
|
|
337
|
-
|
|
338
|
-
'POST /session/delegate': async ({ body }) => {
|
|
339
|
-
if (!body.session_id) throw Object.assign(new Error('session_id is required'), { statusCode: 400 });
|
|
340
|
-
if (!body.title) throw Object.assign(new Error('title is required'), { statusCode: 400 });
|
|
341
|
-
if (sessionHandler) {
|
|
342
|
-
const result = sessionHandler.delegateSubtask({
|
|
343
|
-
sessionId: body.session_id,
|
|
344
|
-
toNodeId: body.to_node_id,
|
|
345
|
-
title: body.title,
|
|
346
|
-
description: body.description,
|
|
347
|
-
role: body.role,
|
|
348
|
-
});
|
|
349
|
-
return { body: result };
|
|
350
|
-
}
|
|
351
|
-
const result = store.send({
|
|
352
|
-
type: 'session_delegate',
|
|
353
|
-
payload: {
|
|
354
|
-
session_id: body.session_id,
|
|
355
|
-
to_node_id: body.to_node_id || null,
|
|
356
|
-
title: body.title,
|
|
357
|
-
description: body.description || '',
|
|
358
|
-
role: body.role || 'builder',
|
|
359
|
-
},
|
|
360
|
-
priority: 'high',
|
|
361
|
-
});
|
|
362
|
-
return { body: result };
|
|
363
|
-
},
|
|
364
|
-
|
|
365
|
-
'POST /session/submit': async ({ body }) => {
|
|
366
|
-
if (!body.session_id) throw Object.assign(new Error('session_id is required'), { statusCode: 400 });
|
|
367
|
-
if (!body.task_id) throw Object.assign(new Error('task_id is required'), { statusCode: 400 });
|
|
368
|
-
if (sessionHandler) {
|
|
369
|
-
const result = sessionHandler.submitResult({
|
|
370
|
-
sessionId: body.session_id,
|
|
371
|
-
taskId: body.task_id,
|
|
372
|
-
resultAssetId: body.result_asset_id,
|
|
373
|
-
summary: body.summary,
|
|
374
|
-
});
|
|
375
|
-
return { body: result };
|
|
376
|
-
}
|
|
377
|
-
const result = store.send({
|
|
378
|
-
type: 'session_submit',
|
|
379
|
-
payload: {
|
|
380
|
-
session_id: body.session_id,
|
|
381
|
-
task_id: body.task_id,
|
|
382
|
-
result_asset_id: body.result_asset_id || null,
|
|
383
|
-
summary: body.summary || '',
|
|
384
|
-
},
|
|
385
|
-
priority: 'high',
|
|
386
|
-
});
|
|
387
|
-
return { body: result };
|
|
388
|
-
},
|
|
389
|
-
|
|
390
|
-
'POST /session/invites/poll': async ({ body }) => {
|
|
391
|
-
if (sessionHandler) {
|
|
392
|
-
const messages = sessionHandler.pollInvites({ limit: body.limit });
|
|
393
|
-
return { body: { messages, count: messages.length } };
|
|
394
|
-
}
|
|
395
|
-
const messages = store.poll({ type: 'collaboration_invite', limit: body.limit || 10 });
|
|
396
|
-
return { body: { messages, count: messages.length } };
|
|
397
|
-
},
|
|
398
|
-
|
|
399
|
-
'GET /session/list': async ({ query }) => {
|
|
400
|
-
if (sessionHandler) {
|
|
401
|
-
const sessions = sessionHandler.listActiveSessions();
|
|
402
|
-
return { body: { sessions, count: sessions.length } };
|
|
403
|
-
}
|
|
404
|
-
const sessions = store.list({ type: 'session_create', direction: 'outbound', limit: Number(query.limit) || 20 });
|
|
405
|
-
return { body: { sessions, count: sessions.length } };
|
|
406
|
-
},
|
|
407
|
-
|
|
408
|
-
// -- System --
|
|
409
|
-
'GET /proxy/status': async () => {
|
|
410
|
-
const outPending = store.countPending({ direction: 'outbound' });
|
|
411
|
-
const inPending = store.countPending({ direction: 'inbound' });
|
|
412
|
-
const nodeId = store.getState('node_id');
|
|
413
|
-
const lastSync = store.getState('last_sync_at');
|
|
414
|
-
const lastSyncError = store.getState('last_sync_error');
|
|
415
|
-
const hubAuthStatus = store.getState('hub_auth_status');
|
|
416
|
-
const reauthBackoffUntil = store.getState('reauth_backoff_until');
|
|
417
|
-
const helloRateLimitUntil = store.getState('hello_rate_limit_until');
|
|
418
|
-
return {
|
|
419
|
-
body: {
|
|
420
|
-
status: 'running',
|
|
421
|
-
node_id: nodeId,
|
|
422
|
-
proxy_protocol_version: PROXY_PROTOCOL_VERSION,
|
|
423
|
-
schema_version: SCHEMA_VERSION,
|
|
424
|
-
outbound_pending: outPending,
|
|
425
|
-
inbound_pending: inPending,
|
|
426
|
-
last_sync_at: lastSync,
|
|
427
|
-
last_sync_error: lastSyncError || null,
|
|
428
|
-
hub_auth_status: hubAuthStatus || null,
|
|
429
|
-
reauth_backoff_until: reauthBackoffUntil || null,
|
|
430
|
-
hello_rate_limit_until: helloRateLimitUntil || null,
|
|
431
|
-
},
|
|
432
|
-
};
|
|
433
|
-
},
|
|
434
|
-
|
|
435
|
-
'GET /proxy/config': async () => {
|
|
436
|
-
return {
|
|
437
|
-
body: {
|
|
438
|
-
channel: 'evomap-hub',
|
|
439
|
-
proxy_protocol_version: PROXY_PROTOCOL_VERSION,
|
|
440
|
-
schema_version: SCHEMA_VERSION,
|
|
441
|
-
},
|
|
442
|
-
};
|
|
443
|
-
},
|
|
444
|
-
|
|
445
|
-
'GET /proxy/hub-status': async () => {
|
|
446
|
-
if (!getHubMailboxStatus) return { body: { error: 'not_available' } };
|
|
447
|
-
const hubStatus = await getHubMailboxStatus();
|
|
448
|
-
return { body: hubStatus };
|
|
449
|
-
},
|
|
450
|
-
|
|
451
|
-
// -- ATP (Agent Transaction Protocol) passthrough --
|
|
452
|
-
// #460 Bug 2: src/atp/hubClient.js historically bypassed the proxy and
|
|
453
|
-
// called the hub directly. When EVOMAP_PROXY=1, hubClient now routes its
|
|
454
|
-
// traffic here so the proxy is the single egress point (audit + offline
|
|
455
|
-
// behavior match the rest of the A2A surface).
|
|
456
|
-
//
|
|
457
|
-
// Security: sender_id and node_id are FORCED to the proxy's own node_id.
|
|
458
|
-
// Callers cannot impersonate another node through the proxy, even if they
|
|
459
|
-
// pass a different sender_id in the body or query string.
|
|
460
|
-
'POST /atp/order': async ({ body }) => {
|
|
461
|
-
const override = { ...(body || {}), sender_id: store.getState('node_id') };
|
|
462
|
-
const result = await proxyHandlers.atpPost('/a2a/atp/order', override);
|
|
463
|
-
return { body: result };
|
|
464
|
-
},
|
|
465
|
-
|
|
466
|
-
'POST /atp/deliver': async ({ body }) => {
|
|
467
|
-
const override = { ...(body || {}), sender_id: store.getState('node_id') };
|
|
468
|
-
const result = await proxyHandlers.atpPost('/a2a/atp/deliver', override);
|
|
469
|
-
return { body: result };
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
'POST /atp/verify': async ({ body }) => {
|
|
473
|
-
const override = { ...(body || {}), sender_id: store.getState('node_id') };
|
|
474
|
-
const result = await proxyHandlers.atpPost('/a2a/atp/verify', override);
|
|
475
|
-
return { body: result };
|
|
476
|
-
},
|
|
477
|
-
|
|
478
|
-
'POST /atp/settle': async ({ body }) => {
|
|
479
|
-
const override = { ...(body || {}), sender_id: store.getState('node_id') };
|
|
480
|
-
const result = await proxyHandlers.atpPost('/a2a/atp/settle', override);
|
|
481
|
-
return { body: result };
|
|
482
|
-
},
|
|
483
|
-
|
|
484
|
-
'POST /atp/dispute': async ({ body }) => {
|
|
485
|
-
const override = { ...(body || {}), sender_id: store.getState('node_id') };
|
|
486
|
-
const result = await proxyHandlers.atpPost('/a2a/atp/dispute', override);
|
|
487
|
-
return { body: result };
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
'GET /atp/merchant/tier': async ({ query }) => {
|
|
491
|
-
const nodeId = store.getState('node_id');
|
|
492
|
-
const result = await proxyHandlers.atpGet('/a2a/atp/merchant/tier', {
|
|
493
|
-
node_id: query.node_id || nodeId,
|
|
494
|
-
});
|
|
495
|
-
return { body: result };
|
|
496
|
-
},
|
|
497
|
-
|
|
498
|
-
'GET /atp/order/:orderId': async ({ params }) => {
|
|
499
|
-
const result = await proxyHandlers.atpGet('/a2a/atp/order/' + encodeURIComponent(params.orderId));
|
|
500
|
-
return { body: result };
|
|
501
|
-
},
|
|
502
|
-
|
|
503
|
-
'GET /atp/proofs': async ({ query }) => {
|
|
504
|
-
const nodeId = store.getState('node_id');
|
|
505
|
-
const q = { node_id: nodeId };
|
|
506
|
-
if (query.role) q.role = query.role;
|
|
507
|
-
if (query.status) q.status = query.status;
|
|
508
|
-
if (query.limit) q.limit = query.limit;
|
|
509
|
-
const result = await proxyHandlers.atpGet('/a2a/atp/proofs', q);
|
|
510
|
-
return { body: result };
|
|
511
|
-
},
|
|
512
|
-
|
|
513
|
-
'GET /atp/policy': async () => {
|
|
514
|
-
const result = await proxyHandlers.atpGet('/a2a/atp/policy');
|
|
515
|
-
return { body: result };
|
|
516
|
-
},
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
// Phase C: only register /v1/messages when the proxy was built with a
|
|
520
|
-
// messages handler (i.e. _proxyAnthropic is available). Slice 5 wires it
|
|
521
|
-
// unconditionally so the route exists on every proxy startup; slice 6 adds
|
|
522
|
-
// EVOMAP_ROUTER_ENABLED behavior inside the handler.
|
|
523
|
-
if (messagesHandler) {
|
|
524
|
-
routes['POST /v1/messages'] = messagesHandler;
|
|
525
|
-
}
|
|
526
|
-
if (responsesHandler) {
|
|
527
|
-
routes['POST /v1/responses'] = responsesHandler;
|
|
528
|
-
}
|
|
529
|
-
if (geminiHandler) {
|
|
530
|
-
// Native Gemini path: model + action (generateContent | streamGenerateContent) are one path segment
|
|
531
|
-
// (`<model>:<action>`), matched as :modelAction and split by the handler.
|
|
532
|
-
routes['POST /v1beta/models/:modelAction'] = geminiHandler;
|
|
533
|
-
}
|
|
534
|
-
if (chatCompletionsHandler) {
|
|
535
|
-
// OpenAI Chat Completions ingress (cursor's OpenAI mode + generic OpenAI clients) → OpenAI upstream.
|
|
536
|
-
routes['POST /v1/chat/completions'] = chatCompletionsHandler;
|
|
537
|
-
}
|
|
538
|
-
if (modelsHandler) {
|
|
539
|
-
// Model-list probe (codex/opencode/cursor/SDKs hit it on startup) → routed by anthropic-version header to
|
|
540
|
-
// the Anthropic or OpenAI upstream's /v1/models, so the probe never 404s.
|
|
541
|
-
routes['GET /v1/models'] = modelsHandler;
|
|
542
|
-
}
|
|
543
|
-
if (ollamaChatHandler) {
|
|
544
|
-
// Ollama native ingress (local/self-hosted models) → Ollama upstream, NDJSON streaming.
|
|
545
|
-
routes['POST /api/chat'] = ollamaChatHandler;
|
|
546
|
-
}
|
|
547
|
-
if (ollamaGenerateHandler) {
|
|
548
|
-
routes['POST /api/generate'] = ollamaGenerateHandler;
|
|
549
|
-
}
|
|
550
|
-
if (vertexHandler) {
|
|
551
|
-
// Vertex AI Gemini native path: project/location/model:action across fixed segments + :modelAction.
|
|
552
|
-
routes['POST /v1/projects/:project/locations/:location/publishers/google/models/:modelAction'] = vertexHandler;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
return routes;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
module.exports = { buildRoutes };
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
|
|
7
|
-
// Settings paths are resolved on every call rather than snapshotted at module
|
|
8
|
-
// load. Tests run in parallel by default (`node --test`); when multiple test
|
|
9
|
-
// files exercise the proxy server, each one starting writes
|
|
10
|
-
// `~/.evolver/settings.json` and the sibling webui observer would read those
|
|
11
|
-
// bytes back and report mode='proxy_only' instead of the expected 'idle'.
|
|
12
|
-
// Lazy resolution lets a test set EVOLVER_SETTINGS_DIR to a temp dir before
|
|
13
|
-
// calling start()/readSettings() and stay isolated from concurrent workers.
|
|
14
|
-
function getSettingsDir() {
|
|
15
|
-
return process.env.EVOLVER_SETTINGS_DIR || path.join(os.homedir(), '.evolver');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function getSettingsFile() {
|
|
19
|
-
return path.join(getSettingsDir(), 'settings.json');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function readSettings() {
|
|
23
|
-
try {
|
|
24
|
-
const file = getSettingsFile();
|
|
25
|
-
if (fs.existsSync(file)) {
|
|
26
|
-
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
27
|
-
}
|
|
28
|
-
} catch {}
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function writeSettings(data) {
|
|
33
|
-
const dir = getSettingsDir();
|
|
34
|
-
const file = getSettingsFile();
|
|
35
|
-
if (!fs.existsSync(dir)) {
|
|
36
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
37
|
-
}
|
|
38
|
-
const current = readSettings();
|
|
39
|
-
const merged = { ...current, ...data };
|
|
40
|
-
// NOTE(windows): mode 0o600 is silently ignored on Windows. The settings
|
|
41
|
-
// file (which may contain proxy credentials) will NOT be owner-read-only.
|
|
42
|
-
// Only Windows user-profile directory ACLs provide isolation. The chmodSync
|
|
43
|
-
// call below is also a no-op on Windows but is retained for Unix correctness.
|
|
44
|
-
fs.writeFileSync(file, JSON.stringify(merged, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
45
|
-
// mode: 0o600 only applies on creation; explicitly chmod to tighten pre-existing files
|
|
46
|
-
try { fs.chmodSync(file, 0o600); } catch { /* best-effort; no-op on Windows */ }
|
|
47
|
-
return merged;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function clearSettings(opts = {}) {
|
|
51
|
-
try {
|
|
52
|
-
const file = getSettingsFile();
|
|
53
|
-
if (fs.existsSync(file)) {
|
|
54
|
-
const current = readSettings();
|
|
55
|
-
const proxyPid = current.proxy?.pid;
|
|
56
|
-
if (!opts.force && proxyPid && proxyPid !== process.pid) return false;
|
|
57
|
-
delete current.proxy;
|
|
58
|
-
fs.writeFileSync(file, JSON.stringify(current, null, 2), 'utf8');
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
} catch {}
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isStaleProxy() {
|
|
66
|
-
const settings = readSettings();
|
|
67
|
-
const pid = settings.proxy?.pid;
|
|
68
|
-
if (!pid) return false;
|
|
69
|
-
try {
|
|
70
|
-
// process.kill(pid, 0) probes whether the process exists without sending a
|
|
71
|
-
// signal. On POSIX it throws ESRCH when the PID is gone. On Windows the
|
|
72
|
-
// Node.js runtime maps this to the same behavior (ESRCH via uv_kill), so
|
|
73
|
-
// the cross-platform semantics are consistent. If the current process does
|
|
74
|
-
// not have permission to query the target PID, EPERM is thrown -- that
|
|
75
|
-
// means the PID exists and is owned by another user, so we treat it as
|
|
76
|
-
// live (not stale) rather than crashing.
|
|
77
|
-
process.kill(pid, 0);
|
|
78
|
-
return false;
|
|
79
|
-
} catch (err) {
|
|
80
|
-
// ESRCH: process does not exist -> stale.
|
|
81
|
-
// EPERM: process exists but is not ours -> not stale (leave settings alone).
|
|
82
|
-
if (err.code === 'EPERM') return false;
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function clearIfStale() {
|
|
88
|
-
if (isStaleProxy()) {
|
|
89
|
-
clearSettings({ force: true });
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function getProxyUrl() {
|
|
96
|
-
const settings = readSettings();
|
|
97
|
-
return settings.proxy?.url || null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function getProxyToken() {
|
|
101
|
-
const settings = readSettings();
|
|
102
|
-
return settings.proxy?.token || null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
module.exports = {
|
|
106
|
-
readSettings,
|
|
107
|
-
writeSettings,
|
|
108
|
-
clearSettings,
|
|
109
|
-
clearIfStale,
|
|
110
|
-
isStaleProxy,
|
|
111
|
-
getProxyUrl,
|
|
112
|
-
getProxyToken,
|
|
113
|
-
getSettingsDir,
|
|
114
|
-
getSettingsFile,
|
|
115
|
-
};
|