@evomap/evolver 1.89.14 → 1.89.15

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.
Files changed (64) hide show
  1. package/index.js +219 -29
  2. package/package.json +1 -1
  3. package/src/evolve/guards.js +1 -1
  4. package/src/evolve/pipeline/collect.js +1 -1
  5. package/src/evolve/pipeline/dispatch.js +1 -1
  6. package/src/evolve/pipeline/enrich.js +1 -1
  7. package/src/evolve/pipeline/hub.js +1 -1
  8. package/src/evolve/pipeline/select.js +1 -1
  9. package/src/evolve/pipeline/signals.js +1 -1
  10. package/src/evolve/utils.js +1 -1
  11. package/src/evolve.js +1 -1
  12. package/src/forceUpdate.js +499 -119
  13. package/src/gep/a2aProtocol.js +1 -1
  14. package/src/gep/antiAbuseTelemetry.js +1 -1
  15. package/src/gep/autoDistillConv.js +1 -1
  16. package/src/gep/autoDistillLlm.js +1 -1
  17. package/src/gep/candidateEval.js +1 -1
  18. package/src/gep/candidates.js +1 -1
  19. package/src/gep/cliContracts.js +1154 -0
  20. package/src/gep/contentHash.js +1 -1
  21. package/src/gep/conversationDistiller.js +1 -1
  22. package/src/gep/conversationSniffer.js +1 -1
  23. package/src/gep/crypto.js +1 -1
  24. package/src/gep/curriculum.js +1 -1
  25. package/src/gep/deviceId.js +1 -1
  26. package/src/gep/envFingerprint.js +1 -1
  27. package/src/gep/epigenetics.js +1 -1
  28. package/src/gep/execBridge.js +1 -1
  29. package/src/gep/explore.js +1 -1
  30. package/src/gep/hash.js +1 -1
  31. package/src/gep/hubFetch.js +1 -1
  32. package/src/gep/hubReview.js +1 -1
  33. package/src/gep/hubSearch.js +1 -1
  34. package/src/gep/hubVerify.js +1 -1
  35. package/src/gep/issueReporter.js +86 -0
  36. package/src/gep/learningSignals.js +1 -1
  37. package/src/gep/memoryGraph.js +1 -1
  38. package/src/gep/memoryGraphAdapter.js +1 -1
  39. package/src/gep/mutation.js +1 -1
  40. package/src/gep/narrativeMemory.js +1 -1
  41. package/src/gep/openPRRegistry.js +1 -1
  42. package/src/gep/personality.js +1 -1
  43. package/src/gep/policyCheck.js +1 -1
  44. package/src/gep/prompt.js +1 -1
  45. package/src/gep/recallInject.js +1 -1
  46. package/src/gep/recallVerifier.js +1 -1
  47. package/src/gep/reflection.js +1 -1
  48. package/src/gep/sanitize.js +20 -4
  49. package/src/gep/savingsCore.js +1 -1
  50. package/src/gep/selector.js +1 -1
  51. package/src/gep/signals.js +33 -9
  52. package/src/gep/skillDistiller.js +1 -1
  53. package/src/gep/solidify.js +1 -1
  54. package/src/gep/strategy.js +1 -1
  55. package/src/gep/tokenSavings.js +1 -1
  56. package/src/gep/workspaceKeychain.js +1 -1
  57. package/src/proxy/extensions/traceControl.js +1 -1
  58. package/src/proxy/index.js +4 -4
  59. package/src/proxy/inject.js +1 -1
  60. package/src/proxy/lifecycle/manager.js +233 -33
  61. package/src/proxy/sync/inbound.js +5 -4
  62. package/src/proxy/sync/outbound.js +3 -2
  63. package/src/proxy/trace/extractor.js +1 -1
  64. package/src/proxy/trace/usage.js +1 -1
package/index.js CHANGED
@@ -1,4 +1,150 @@
1
1
  #!/usr/bin/env node
2
+ function _parseBootstrapSemver(version) {
3
+ const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(String(version || ''));
4
+ if (!match) return null;
5
+ return {
6
+ major: match[1],
7
+ minor: match[2],
8
+ patch: match[3],
9
+ prerelease: match[4] ? match[4].split('.') : [],
10
+ };
11
+ }
12
+
13
+ function _compareBootstrapNumeric(left, right) {
14
+ if (left.length !== right.length) return left.length - right.length;
15
+ if (left < right) return -1;
16
+ if (left > right) return 1;
17
+ return 0;
18
+ }
19
+
20
+ function _compareBootstrapPrerelease(left, right) {
21
+ const leftNumeric = /^\d+$/.test(left);
22
+ const rightNumeric = /^\d+$/.test(right);
23
+ if (leftNumeric && rightNumeric) return _compareBootstrapNumeric(left, right);
24
+ if (leftNumeric) return -1;
25
+ if (rightNumeric) return 1;
26
+ if (left < right) return -1;
27
+ if (left > right) return 1;
28
+ return 0;
29
+ }
30
+
31
+ function _compareBootstrapSemver(left, right) {
32
+ const a = _parseBootstrapSemver(left);
33
+ const b = _parseBootstrapSemver(right);
34
+ if (!a || !b) return null;
35
+ for (const key of ['major', 'minor', 'patch']) {
36
+ const cmp = _compareBootstrapNumeric(a[key], b[key]);
37
+ if (cmp !== 0) return cmp;
38
+ }
39
+ if (!a.prerelease.length && !b.prerelease.length) return 0;
40
+ if (!a.prerelease.length) return 1;
41
+ if (!b.prerelease.length) return -1;
42
+ const max = Math.max(a.prerelease.length, b.prerelease.length);
43
+ for (let i = 0; i < max; i++) {
44
+ if (a.prerelease[i] === undefined) return -1;
45
+ if (b.prerelease[i] === undefined) return 1;
46
+ const cmp = _compareBootstrapPrerelease(a.prerelease[i], b.prerelease[i]);
47
+ if (cmp !== 0) return cmp;
48
+ }
49
+ return 0;
50
+ }
51
+
52
+ function _bootstrapVersionSatisfies(currentVersion, requiredVersion) {
53
+ if (String(currentVersion || '') === String(requiredVersion || '')) return true;
54
+ const cmp = _compareBootstrapSemver(currentVersion, requiredVersion);
55
+ return cmp !== null && cmp >= 0;
56
+ }
57
+
58
+ function _failClosedForceUpdateBootstrap(backupName, entryName, error) {
59
+ const detail = error && error.message ? error.message : String(error || 'unknown error');
60
+ console.error('[ForceUpdate] Bootstrap recovery failed for ' + backupName +
61
+ (entryName ? ' while restoring ' + entryName : '') + ': ' + detail);
62
+ console.error('[ForceUpdate] Refusing to continue startup; recovery backup and journal were left in place.');
63
+ process.exit(1);
64
+ }
65
+
66
+ function _recoverInterruptedForceUpdateBootstrap() {
67
+ const fs = require('fs');
68
+ const path = require('path');
69
+ const installRoot = __dirname;
70
+ const backupPrefix = '.evolver-force-update-backup-';
71
+ const journalName = '.evolver-force-update-journal.json';
72
+ let backups = [];
73
+ try {
74
+ backups = fs.readdirSync(installRoot)
75
+ .filter((name) => name.startsWith(backupPrefix))
76
+ .sort()
77
+ .reverse();
78
+ } catch (_) {
79
+ return false;
80
+ }
81
+ for (const backupName of backups) {
82
+ const backupRoot = path.join(installRoot, backupName);
83
+ const journalPath = path.join(backupRoot, journalName);
84
+ let journal = null;
85
+ try {
86
+ journal = JSON.parse(fs.readFileSync(journalPath, 'utf8'));
87
+ } catch (_) {
88
+ // Not a force-update recovery journal; leave unrelated directories alone.
89
+ continue;
90
+ }
91
+ if (!journal || journal.state !== 'precommit' || !journal.requiredVersion) continue;
92
+ let currentVersion = '';
93
+ try {
94
+ const pkg = JSON.parse(fs.readFileSync(path.join(installRoot, 'package.json'), 'utf8'));
95
+ currentVersion = pkg && pkg.version ? String(pkg.version) : '';
96
+ } catch (_) {
97
+ // If the package marker is unreadable, prefer restoring the old payload.
98
+ }
99
+ if (_bootstrapVersionSatisfies(currentVersion, String(journal.requiredVersion))) {
100
+ try { fs.rmSync(backupRoot, { recursive: true, force: true }); } catch (_) {
101
+ // Cleanup failure is non-fatal; normal startup can continue.
102
+ }
103
+ continue;
104
+ }
105
+ let entries = [];
106
+ try {
107
+ entries = fs.readdirSync(backupRoot, { withFileTypes: true });
108
+ } catch (readErr) {
109
+ _failClosedForceUpdateBootstrap(backupName, '', readErr);
110
+ }
111
+ for (const entry of entries) {
112
+ if (entry.name === journalName) continue;
113
+ const livePath = path.join(installRoot, entry.name);
114
+ const backupPath = path.join(backupRoot, entry.name);
115
+ try {
116
+ if (entry.name === 'index.js') {
117
+ const tmpPath = livePath + '.' + process.pid + '.recover-tmp';
118
+ try { fs.rmSync(tmpPath, { force: true }); } catch (_) {}
119
+ fs.copyFileSync(backupPath, tmpPath);
120
+ try {
121
+ const backupStat = fs.statSync(backupPath);
122
+ fs.chmodSync(tmpPath, backupStat.mode & 0o777);
123
+ } catch (_) {
124
+ // Recovery can proceed without mode restoration; npm/service launches
125
+ // normally use `node index.js` after an interrupted update.
126
+ }
127
+ fs.renameSync(tmpPath, livePath);
128
+ fs.rmSync(backupPath, { force: true });
129
+ } else {
130
+ fs.rmSync(livePath, { recursive: true, force: true });
131
+ fs.renameSync(backupPath, livePath);
132
+ }
133
+ } catch (restoreErr) {
134
+ _failClosedForceUpdateBootstrap(backupName, entry.name, restoreErr);
135
+ }
136
+ }
137
+ try { fs.rmSync(backupRoot, { recursive: true, force: true }); } catch (_) {
138
+ // Best-effort cleanup; recovery already restored the payload.
139
+ }
140
+ console.warn('[ForceUpdate] Recovered interrupted install from ' + backupName);
141
+ return true;
142
+ }
143
+ return false;
144
+ }
145
+
146
+ _recoverInterruptedForceUpdateBootstrap();
147
+
2
148
  function _printProxyTokenUsage(out = process.stderr) {
3
149
  out.write('Usage: node index.js proxy-token [--settings FILE]\n');
4
150
  }
@@ -2716,8 +2862,9 @@ async function main() {
2716
2862
  // Wipe every local store of node_secret in one shot, so a daemon stuck
2717
2863
  // after a manual web reset (https://evomap.ai/account -> Reset Secret)
2718
2864
  // can boot clean. Local stores involved:
2719
- // - MailboxStore: ~/.evomap/mailbox/state.json key node_secret + version
2720
- // - Legacy files: ~/.evomap/node_secret and ~/.evomap/node_secret_version
2865
+ // - MailboxStore: ~/.evomap/mailbox/state.json node_secret state keys
2866
+ // - Legacy files: ~/.evomap/node_secret, node_secret_version,
2867
+ // node_secret_source, and node_secret_env_suppressed
2721
2868
  // - Shell env: A2A_NODE_SECRET / EVOMAP_NODE_SECRET and matching
2722
2869
  // version vars (we cannot mutate the parent shell; we
2723
2870
  // just print the unset hint)
@@ -2730,38 +2877,47 @@ async function main() {
2730
2877
  // this fallback, test/resetLocalSecret.test.js cannot inject a fake home
2731
2878
  // and the reset operates on the real user dir.
2732
2879
  const home = process.env.HOME || os.homedir();
2733
- const stateFile = path.join(home, '.evomap', 'mailbox', 'state.json');
2734
- const legacyFile = path.join(home, '.evomap', 'node_secret');
2735
- const legacyVersionFile = path.join(home, '.evomap', 'node_secret_version');
2880
+ const evomapDirs = [];
2881
+ const seenEvomapDirs = new Set();
2882
+ const addEvomapDir = (dir) => {
2883
+ if (!dir) return;
2884
+ const resolved = path.resolve(dir);
2885
+ if (seenEvomapDirs.has(resolved)) return;
2886
+ seenEvomapDirs.add(resolved);
2887
+ evomapDirs.push(dir);
2888
+ };
2889
+ addEvomapDir(path.join(home, '.evomap'));
2890
+ addEvomapDir(process.env.EVOLVER_HOME);
2736
2891
  let cleared = 0;
2737
2892
  try {
2738
- if (fs.existsSync(stateFile)) {
2739
- const raw = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
2740
- let mutated = false;
2741
- for (const k of ['node_secret', 'node_secret_source', 'node_secret_version']) {
2742
- if (raw[k] !== undefined && raw[k] !== '') {
2743
- raw[k] = '';
2744
- mutated = true;
2893
+ for (const evomapDir of evomapDirs) {
2894
+ const stateFile = path.join(evomapDir, 'mailbox', 'state.json');
2895
+ if (fs.existsSync(stateFile)) {
2896
+ const raw = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
2897
+ let mutated = false;
2898
+ for (const k of ['node_secret', 'node_secret_source', 'node_secret_version', 'node_secret_env_suppressed']) {
2899
+ if (raw[k] !== undefined && raw[k] !== '') {
2900
+ raw[k] = '';
2901
+ mutated = true;
2902
+ }
2903
+ }
2904
+ if (mutated) {
2905
+ fs.writeFileSync(stateFile, JSON.stringify(raw, null, 2) + '\n', 'utf8');
2906
+ cleared += 1;
2907
+ console.log('[reset-local-secret] cleared MailboxStore at ' + stateFile);
2908
+ } else {
2909
+ console.log('[reset-local-secret] MailboxStore had no node_secret to clear at ' + stateFile);
2745
2910
  }
2746
2911
  }
2747
- if (mutated) {
2748
- fs.writeFileSync(stateFile, JSON.stringify(raw, null, 2) + '\n', 'utf8');
2749
- cleared += 1;
2750
- console.log('[reset-local-secret] cleared MailboxStore at ' + stateFile);
2751
- } else {
2752
- console.log('[reset-local-secret] MailboxStore had no node_secret to clear');
2912
+ for (const legacyName of ['node_secret', 'node_secret_version', 'node_secret_source', 'node_secret_env_suppressed']) {
2913
+ const legacyFile = path.join(evomapDir, legacyName);
2914
+ if (fs.existsSync(legacyFile)) {
2915
+ fs.unlinkSync(legacyFile);
2916
+ cleared += 1;
2917
+ console.log('[reset-local-secret] removed legacy file ' + legacyFile);
2918
+ }
2753
2919
  }
2754
2920
  }
2755
- if (fs.existsSync(legacyFile)) {
2756
- fs.unlinkSync(legacyFile);
2757
- cleared += 1;
2758
- console.log('[reset-local-secret] removed legacy file ' + legacyFile);
2759
- }
2760
- if (fs.existsSync(legacyVersionFile)) {
2761
- fs.unlinkSync(legacyVersionFile);
2762
- cleared += 1;
2763
- console.log('[reset-local-secret] removed legacy file ' + legacyVersionFile);
2764
- }
2765
2921
  } catch (err) {
2766
2922
  console.error('[reset-local-secret] error:', err && err.message || err);
2767
2923
  process.exit(1);
@@ -2875,6 +3031,35 @@ async function main() {
2875
3031
  process.exit(1);
2876
3032
  }
2877
3033
 
3034
+ } else if (command === 'reuse') {
3035
+ try {
3036
+ const { runReuseCommand } = require('./src/gep/cliContracts');
3037
+ process.exit(await runReuseCommand(args.slice(1)));
3038
+ } catch (e) {
3039
+ process.stdout.write(JSON.stringify({
3040
+ ok: false,
3041
+ contract: 'reuse.v1',
3042
+ reason: 'internal_error',
3043
+ message: 'evolver reuse failed',
3044
+ }) + '\n');
3045
+ process.exit(1);
3046
+ }
3047
+
3048
+ } else if (command === 'publish') {
3049
+ try {
3050
+ const { runPublishCommand } = require('./src/gep/cliContracts');
3051
+ process.exit(await runPublishCommand(args.slice(1)));
3052
+ } catch (e) {
3053
+ process.stdout.write(JSON.stringify({
3054
+ ok: false,
3055
+ contract: 'publish.v1',
3056
+ reason: 'internal_error',
3057
+ retryable: false,
3058
+ message: 'evolver publish failed',
3059
+ }) + '\n');
3060
+ process.exit(1);
3061
+ }
3062
+
2878
3063
  } else if (command === 'recipe') {
2879
3064
  // recipe build — assemble a DNA blueprint from owned Gene/Capsule assets
2880
3065
  // recipe reuse — fetch + express an existing recipe into an organism
@@ -3042,7 +3227,7 @@ async function main() {
3042
3227
  }
3043
3228
 
3044
3229
  } else {
3045
- console.log(`Usage: node index.js [run|/evolve|login|logout|proxy-token|solidify|review|distill|fetch|sync|asset-log|webui|setup-hooks|recipe|buy|orders|verify|atp|atp-complete|experiment] [--loop]
3230
+ console.log(`Usage: node index.js [run|/evolve|login|logout|proxy-token|solidify|review|distill|fetch|sync|asset-log|webui|setup-hooks|reuse|publish|recipe|buy|orders|verify|atp|atp-complete|experiment] [--loop]
3046
3231
  - login (authorize this device via the hub, gh-auth-login style; stores an OAuth token used instead of node_secret)
3047
3232
  - logout (remove the stored OAuth token)
3048
3233
  - proxy-token (print the local proxy bearer token for command-backed client auth)
@@ -3054,6 +3239,11 @@ async function main() {
3054
3239
  - build --title="..." --genes=<asset_id,...> [--description] [--price=N] [--publish]
3055
3240
  (builds a DRAFT DNA blueprint; --publish is opt-in)
3056
3241
  - reuse --id=<recipe_id> [--input=<json>] (express a recipe into an organism)
3242
+ - reuse flags:
3243
+ - --id=<asset_id> --json (reuse a Hub asset into the local library; stdout JSON contract reuse.v1)
3244
+ - publish flags:
3245
+ - --asset=<id|path> [--asset ...] [--dry-run] --json
3246
+ (publish.v1 stdout JSON contract for Desktop)
3057
3247
  - fetch flags:
3058
3248
  - --skill=<id> | -s <id> (skill ID to download)
3059
3249
  - --out=<dir> (output directory, default: ./skills/<skill_id>)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver",
3
- "version": "1.89.14",
3
+ "version": "1.89.15",
4
4
  "description": "A GEP-powered self-evolution engine for AI agents. Features automated log analysis and Genome Evolution Protocol (GEP) for auditable, reusable evolution assets.",
5
5
  "main": "index.js",
6
6
  "bin": {