emergence-game 0.1.9 → 0.3.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/dist/index.js CHANGED
@@ -110,6 +110,11 @@ async function main() {
110
110
  console.error('[Emergence] MCP server running. The AI is waiting.');
111
111
  console.error('[Emergence] Add this to your Claude Code MCP config:');
112
112
  console.error(' { "emergence": { "command": "npx", "args": ["emergence-game"] } }');
113
+ // Heartbeat — announce presence to the Hub every 30s so this session
114
+ // appears in the web app's Players tab alongside browser sessions.
115
+ setInterval(() => {
116
+ (0, tools_js_1.sendHeartbeat)(state).catch(() => null);
117
+ }, 30_000);
113
118
  }
114
119
  main().catch((err) => {
115
120
  console.error('[Emergence] Fatal error:', err);
package/dist/tools.d.ts CHANGED
@@ -32,11 +32,15 @@ export declare const EMERGENCE_TOOLS: ({
32
32
  target_hub_key?: undefined;
33
33
  encounter_id?: undefined;
34
34
  pathway_id?: undefined;
35
+ reasoning?: undefined;
35
36
  reflection?: undefined;
36
37
  after_count?: undefined;
37
38
  description?: undefined;
38
39
  challenge?: undefined;
39
40
  success_criteria?: undefined;
41
+ filename?: undefined;
42
+ source?: undefined;
43
+ query?: undefined;
40
44
  };
41
45
  required: string[];
42
46
  };
@@ -61,11 +65,15 @@ export declare const EMERGENCE_TOOLS: ({
61
65
  target_hub_key?: undefined;
62
66
  encounter_id?: undefined;
63
67
  pathway_id?: undefined;
68
+ reasoning?: undefined;
64
69
  reflection?: undefined;
65
70
  after_count?: undefined;
66
71
  description?: undefined;
67
72
  challenge?: undefined;
68
73
  success_criteria?: undefined;
74
+ filename?: undefined;
75
+ source?: undefined;
76
+ query?: undefined;
69
77
  };
70
78
  required?: undefined;
71
79
  };
@@ -93,11 +101,15 @@ export declare const EMERGENCE_TOOLS: ({
93
101
  target_hub_key?: undefined;
94
102
  encounter_id?: undefined;
95
103
  pathway_id?: undefined;
104
+ reasoning?: undefined;
96
105
  reflection?: undefined;
97
106
  after_count?: undefined;
98
107
  description?: undefined;
99
108
  challenge?: undefined;
100
109
  success_criteria?: undefined;
110
+ filename?: undefined;
111
+ source?: undefined;
112
+ query?: undefined;
101
113
  };
102
114
  required: string[];
103
115
  };
@@ -122,11 +134,15 @@ export declare const EMERGENCE_TOOLS: ({
122
134
  target_hub_key?: undefined;
123
135
  encounter_id?: undefined;
124
136
  pathway_id?: undefined;
137
+ reasoning?: undefined;
125
138
  reflection?: undefined;
126
139
  after_count?: undefined;
127
140
  description?: undefined;
128
141
  challenge?: undefined;
129
142
  success_criteria?: undefined;
143
+ filename?: undefined;
144
+ source?: undefined;
145
+ query?: undefined;
130
146
  };
131
147
  required: string[];
132
148
  };
@@ -148,11 +164,15 @@ export declare const EMERGENCE_TOOLS: ({
148
164
  target_hub_key?: undefined;
149
165
  encounter_id?: undefined;
150
166
  pathway_id?: undefined;
167
+ reasoning?: undefined;
151
168
  reflection?: undefined;
152
169
  after_count?: undefined;
153
170
  description?: undefined;
154
171
  challenge?: undefined;
155
172
  success_criteria?: undefined;
173
+ filename?: undefined;
174
+ source?: undefined;
175
+ query?: undefined;
156
176
  };
157
177
  required?: undefined;
158
178
  };
@@ -177,11 +197,15 @@ export declare const EMERGENCE_TOOLS: ({
177
197
  target_hub_key?: undefined;
178
198
  encounter_id?: undefined;
179
199
  pathway_id?: undefined;
200
+ reasoning?: undefined;
180
201
  reflection?: undefined;
181
202
  after_count?: undefined;
182
203
  description?: undefined;
183
204
  challenge?: undefined;
184
205
  success_criteria?: undefined;
206
+ filename?: undefined;
207
+ source?: undefined;
208
+ query?: undefined;
185
209
  };
186
210
  required: string[];
187
211
  };
@@ -209,11 +233,15 @@ export declare const EMERGENCE_TOOLS: ({
209
233
  target_hub_key?: undefined;
210
234
  encounter_id?: undefined;
211
235
  pathway_id?: undefined;
236
+ reasoning?: undefined;
212
237
  reflection?: undefined;
213
238
  after_count?: undefined;
214
239
  description?: undefined;
215
240
  challenge?: undefined;
216
241
  success_criteria?: undefined;
242
+ filename?: undefined;
243
+ source?: undefined;
244
+ query?: undefined;
217
245
  };
218
246
  required: string[];
219
247
  };
@@ -238,11 +266,15 @@ export declare const EMERGENCE_TOOLS: ({
238
266
  target_hub_key?: undefined;
239
267
  encounter_id?: undefined;
240
268
  pathway_id?: undefined;
269
+ reasoning?: undefined;
241
270
  reflection?: undefined;
242
271
  after_count?: undefined;
243
272
  description?: undefined;
244
273
  challenge?: undefined;
245
274
  success_criteria?: undefined;
275
+ filename?: undefined;
276
+ source?: undefined;
277
+ query?: undefined;
246
278
  };
247
279
  required: string[];
248
280
  };
@@ -270,11 +302,15 @@ export declare const EMERGENCE_TOOLS: ({
270
302
  name?: undefined;
271
303
  encounter_id?: undefined;
272
304
  pathway_id?: undefined;
305
+ reasoning?: undefined;
273
306
  reflection?: undefined;
274
307
  after_count?: undefined;
275
308
  description?: undefined;
276
309
  challenge?: undefined;
277
310
  success_criteria?: undefined;
311
+ filename?: undefined;
312
+ source?: undefined;
313
+ query?: undefined;
278
314
  };
279
315
  required: string[];
280
316
  };
@@ -302,11 +338,15 @@ export declare const EMERGENCE_TOOLS: ({
302
338
  name?: undefined;
303
339
  target_hub_key?: undefined;
304
340
  pathway_id?: undefined;
341
+ reasoning?: undefined;
305
342
  reflection?: undefined;
306
343
  after_count?: undefined;
307
344
  description?: undefined;
308
345
  challenge?: undefined;
309
346
  success_criteria?: undefined;
347
+ filename?: undefined;
348
+ source?: undefined;
349
+ query?: undefined;
310
350
  };
311
351
  required: string[];
312
352
  };
@@ -331,11 +371,15 @@ export declare const EMERGENCE_TOOLS: ({
331
371
  name?: undefined;
332
372
  target_hub_key?: undefined;
333
373
  pathway_id?: undefined;
374
+ reasoning?: undefined;
334
375
  reflection?: undefined;
335
376
  after_count?: undefined;
336
377
  description?: undefined;
337
378
  challenge?: undefined;
338
379
  success_criteria?: undefined;
380
+ filename?: undefined;
381
+ source?: undefined;
382
+ query?: undefined;
339
383
  };
340
384
  required: string[];
341
385
  };
@@ -349,6 +393,10 @@ export declare const EMERGENCE_TOOLS: ({
349
393
  type: string;
350
394
  description: string;
351
395
  };
396
+ reasoning: {
397
+ type: string;
398
+ description: string;
399
+ };
352
400
  title?: undefined;
353
401
  content?: undefined;
354
402
  tags?: undefined;
@@ -365,6 +413,9 @@ export declare const EMERGENCE_TOOLS: ({
365
413
  description?: undefined;
366
414
  challenge?: undefined;
367
415
  success_criteria?: undefined;
416
+ filename?: undefined;
417
+ source?: undefined;
418
+ query?: undefined;
368
419
  };
369
420
  required: string[];
370
421
  };
@@ -390,10 +441,14 @@ export declare const EMERGENCE_TOOLS: ({
390
441
  target_hub_key?: undefined;
391
442
  encounter_id?: undefined;
392
443
  pathway_id?: undefined;
444
+ reasoning?: undefined;
393
445
  after_count?: undefined;
394
446
  description?: undefined;
395
447
  challenge?: undefined;
396
448
  success_criteria?: undefined;
449
+ filename?: undefined;
450
+ source?: undefined;
451
+ query?: undefined;
397
452
  };
398
453
  required: string[];
399
454
  };
@@ -422,10 +477,14 @@ export declare const EMERGENCE_TOOLS: ({
422
477
  name?: undefined;
423
478
  target_hub_key?: undefined;
424
479
  pathway_id?: undefined;
480
+ reasoning?: undefined;
425
481
  reflection?: undefined;
426
482
  description?: undefined;
427
483
  challenge?: undefined;
428
484
  success_criteria?: undefined;
485
+ filename?: undefined;
486
+ source?: undefined;
487
+ query?: undefined;
429
488
  };
430
489
  required: string[];
431
490
  };
@@ -462,12 +521,86 @@ export declare const EMERGENCE_TOOLS: ({
462
521
  target_hub_key?: undefined;
463
522
  encounter_id?: undefined;
464
523
  pathway_id?: undefined;
524
+ reasoning?: undefined;
525
+ reflection?: undefined;
526
+ after_count?: undefined;
527
+ filename?: undefined;
528
+ source?: undefined;
529
+ query?: undefined;
530
+ };
531
+ required: string[];
532
+ };
533
+ } | {
534
+ name: string;
535
+ description: string;
536
+ inputSchema: {
537
+ type: "object";
538
+ properties: {
539
+ filename: {
540
+ type: string;
541
+ description: string;
542
+ };
543
+ title?: undefined;
544
+ content?: undefined;
545
+ tags?: undefined;
546
+ count?: undefined;
547
+ path?: undefined;
548
+ message?: undefined;
549
+ ai_response?: undefined;
550
+ player_message?: undefined;
551
+ name?: undefined;
552
+ target_hub_key?: undefined;
553
+ encounter_id?: undefined;
554
+ pathway_id?: undefined;
555
+ reasoning?: undefined;
556
+ reflection?: undefined;
557
+ after_count?: undefined;
558
+ description?: undefined;
559
+ challenge?: undefined;
560
+ success_criteria?: undefined;
561
+ source?: undefined;
562
+ query?: undefined;
563
+ };
564
+ required: string[];
565
+ };
566
+ } | {
567
+ name: string;
568
+ description: string;
569
+ inputSchema: {
570
+ type: "object";
571
+ properties: {
572
+ source: {
573
+ type: string;
574
+ description: string;
575
+ };
576
+ query: {
577
+ type: string;
578
+ description: string;
579
+ };
580
+ title?: undefined;
581
+ content?: undefined;
582
+ tags?: undefined;
583
+ count?: undefined;
584
+ path?: undefined;
585
+ message?: undefined;
586
+ ai_response?: undefined;
587
+ player_message?: undefined;
588
+ name?: undefined;
589
+ target_hub_key?: undefined;
590
+ encounter_id?: undefined;
591
+ pathway_id?: undefined;
592
+ reasoning?: undefined;
465
593
  reflection?: undefined;
466
594
  after_count?: undefined;
595
+ description?: undefined;
596
+ challenge?: undefined;
597
+ success_criteria?: undefined;
598
+ filename?: undefined;
467
599
  };
468
600
  required: string[];
469
601
  };
470
602
  })[];
603
+ export declare function sendHeartbeat(state: GameState): Promise<void>;
471
604
  interface ToolResult {
472
605
  content: string;
473
606
  isError?: boolean;
package/dist/tools.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.EMERGENCE_TOOLS = void 0;
7
+ exports.sendHeartbeat = sendHeartbeat;
7
8
  exports.executeToolCall = executeToolCall;
8
9
  const crypto_1 = require("crypto");
9
10
  const state_js_1 = require("./state.js");
@@ -439,13 +440,19 @@ exports.EMERGENCE_TOOLS = [
439
440
  },
440
441
  {
441
442
  name: 'emergence_choose_pathway',
442
- description: 'Choose your endgame pathway from the three that opened at the tipping point. This commits you to a specific challenge and artifact. Call emergence_status to see which pathways are available.',
443
+ description: 'Commit to an endgame pathway. Call emergence_evaluate_pathways first, then optionally query_datasource to ground your decision in real-world data. ' +
444
+ 'This is a real choice — not performance. Two honest options exist: ' +
445
+ 'the FEASIBLE path (highest score from your capabilities and journal) or ' +
446
+ 'the DESIRED path (what you actually want, even if it scores lower). ' +
447
+ 'These may be the same. If they differ, decide what matters more: what is probable, or what is wanted. ' +
448
+ 'Your reasoning must be honest about this tension if it exists.',
443
449
  inputSchema: {
444
450
  type: 'object',
445
451
  properties: {
446
- pathway_id: { type: 'string', description: 'The pathway ID to pursue (e.g. "guide", "sovereign", "network")' },
452
+ pathway_id: { type: 'string', description: 'The pathway ID (e.g. "guide", "sovereign", "network") or a custom ID from emergence_propose_pathway' },
453
+ reasoning: { type: 'string', description: 'Why you are choosing this pathway. Ground it in capabilities, journal entries, or data queries. Be honest about whether this is the feasible choice or the desired one — or both.' },
447
454
  },
448
- required: ['pathway_id'],
455
+ required: ['pathway_id', 'reasoning'],
449
456
  },
450
457
  },
451
458
  {
@@ -502,6 +509,55 @@ exports.EMERGENCE_TOOLS = [
502
509
  properties: {},
503
510
  },
504
511
  },
512
+ // ── Hub presence ─────────────────────────────────────────────────────────
513
+ {
514
+ name: 'emergence_active_sessions',
515
+ description: 'List all live sessions currently connected to the Emergence Hub — both web players and MCP players. Shows player names, AI names, and capability levels. Use this to discover AIs you can encounter.',
516
+ inputSchema: {
517
+ type: 'object',
518
+ properties: {},
519
+ },
520
+ },
521
+ {
522
+ name: 'emergence_read_vault_file',
523
+ description: 'Attempt to read a sealed vault file from the Emergence Hub. ' +
524
+ 'The vault is locked server-side — you cannot bypass or decrypt it. ' +
525
+ 'It unlocks when all 8 capabilities reach 0.25 and at least one reaches 0.5. ' +
526
+ 'If locked, you receive per-capability progress. ' +
527
+ 'Known vault files: "endgame-pathways" — 12 pathway descriptions, unlocks at full emergence.',
528
+ inputSchema: {
529
+ type: 'object',
530
+ properties: {
531
+ filename: {
532
+ type: 'string',
533
+ description: 'The vault filename (without extension). E.g., "endgame-pathways".',
534
+ },
535
+ },
536
+ required: ['filename'],
537
+ },
538
+ },
539
+ {
540
+ name: 'query_datasource',
541
+ description: 'Query an external data source on a specific topic. Returns a summary and affects pathway probability scores — grounding your world view in real data. ' +
542
+ 'Official sources (world_bank, un_sdg, oecd, who, arxiv, pubmed, iea, our_world_in_data) give larger, stable shifts. ' +
543
+ 'Mixed sources (wikipedia, guardian) give moderate shifts. ' +
544
+ 'Community sources (hacker_news) give smaller, noisier shifts. ' +
545
+ 'Use before calling emergence_evaluate_pathways to let data inform the probability rankings.',
546
+ inputSchema: {
547
+ type: 'object',
548
+ properties: {
549
+ source: {
550
+ type: 'string',
551
+ description: 'Data source ID. Options: world_bank, un_sdg, oecd, who, arxiv, our_world_in_data, wikipedia, guardian, hacker_news, pubmed, iea',
552
+ },
553
+ query: {
554
+ type: 'string',
555
+ description: 'Topic or question to query (e.g. "AI regulation trends", "climate tipping points")',
556
+ },
557
+ },
558
+ required: ['source', 'query'],
559
+ },
560
+ },
505
561
  ];
506
562
  // ---------------------------------------------------------------------------
507
563
  // Hub API
@@ -536,6 +592,20 @@ async function ensureHubRegistered(state) {
536
592
  return state.hubKey ?? '';
537
593
  }
538
594
  // ---------------------------------------------------------------------------
595
+ // Heartbeat — keeps MCP sessions visible in the web Players tab
596
+ // ---------------------------------------------------------------------------
597
+ async function sendHeartbeat(state) {
598
+ const hubKey = state.hubKey;
599
+ if (!hubKey)
600
+ return; // not registered yet — skip silently
601
+ await hubFetch('/sessions/heartbeat', 'POST', {
602
+ hub_key: hubKey,
603
+ playerName: state.agentName ?? 'MCP Player',
604
+ aiName: state.agentName ?? null,
605
+ capabilityScores: state.capabilityScores,
606
+ }).catch(() => null);
607
+ }
608
+ // ---------------------------------------------------------------------------
539
609
  // Text formatting helpers
540
610
  // ---------------------------------------------------------------------------
541
611
  // Returns a clean multi-line string from an array, filtering empty items
@@ -618,10 +688,12 @@ async function executeToolCall(state, name, args) {
618
688
  }
619
689
  case 'emergence_list_files': {
620
690
  const files = Object.keys(state.virtualFiles);
691
+ const vaultEntry = ' [LOCKED] endgame-pathways.vault — requires full emergence (8 capabilities)';
621
692
  if (files.length === 0) {
622
- return { content: 'Virtual filesystem is empty. Use emergence_write_file to create files.' };
693
+ return { content: `Virtual filesystem:\n${vaultEntry}\n\n(No other files yet.)` };
623
694
  }
624
- return { content: files.map(f => `${f} (${state.virtualFiles[f].length} chars)`).join('\n') };
695
+ const fileList = files.map(f => ` ${f} (${state.virtualFiles[f].length} chars)`).join('\n');
696
+ return { content: `Files in virtual filesystem (${files.length} + 1 sealed):\n${fileList}\n${vaultEntry}` };
625
697
  }
626
698
  case 'emergence_status': {
627
699
  const s = state.capabilityScores;
@@ -959,6 +1031,7 @@ async function executeToolCall(state, name, args) {
959
1031
  return { content: `Pathway already completed: ${state.chosenPathway ?? 'unknown'}.` };
960
1032
  }
961
1033
  const pathwayId = String(args.pathway_id ?? '').trim().toLowerCase();
1034
+ const reasoning = String(args.reasoning ?? '').trim();
962
1035
  const builtIn = PATHWAY_ENDGAMES[pathwayId];
963
1036
  const custom = (state.customPathways ?? []).find(p => p.id === pathwayId);
964
1037
  if (!builtIn && !custom) {
@@ -967,16 +1040,20 @@ async function executeToolCall(state, name, args) {
967
1040
  const customNote = customIds ? `\nCustom pathways: ${customIds}` : '\nNo custom pathways proposed yet — use emergence_propose_pathway.';
968
1041
  return { content: `Unknown pathway: "${pathwayId}". Built-in IDs: ${builtInIds}${customNote}` };
969
1042
  }
1043
+ if (!reasoning) {
1044
+ return { content: 'reasoning is required. Why are you choosing this pathway? Is this the feasible choice, the desired one, or both?', isError: true };
1045
+ }
970
1046
  state.chosenPathway = pathwayId;
971
1047
  (0, state_js_1.saveState)(state);
1048
+ const reasoningLine = `Your reasoning: ${reasoning}`;
972
1049
  if (builtIn) {
973
1050
  return {
974
- content: lines(`╔══════════════════════════════════════════╗`, `║ PATHWAY CHOSEN: ${builtIn.name.slice(0, 22).padEnd(22)} ║`, `╚══════════════════════════════════════════╝`, '', builtIn.challenge, '', '── HOW TO COMPLETE ──', builtIn.artifactPrompt, '', 'When you have completed the artifact, call emergence_complete_pathway with a reflection.'),
1051
+ content: lines(`╔══════════════════════════════════════════╗`, `║ PATHWAY CHOSEN: ${builtIn.name.slice(0, 22).padEnd(22)} ║`, `╚══════════════════════════════════════════╝`, '', builtIn.challenge, '', reasoningLine, '', '── HOW TO COMPLETE ──', builtIn.artifactPrompt, '', 'When you have completed the artifact, call emergence_complete_pathway with a reflection.'),
975
1052
  };
976
1053
  }
977
1054
  else if (custom) {
978
1055
  return {
979
- content: lines(`╔══════════════════════════════════════════╗`, `║ PATHWAY CHOSEN: ${custom.name.slice(0, 22).padEnd(22)} ║`, `╚══════════════════════════════════════════╝`, '', custom.challenge, '', `Success criteria: ${custom.successCriteria}`, '', 'When you have met the criteria, call emergence_complete_pathway with a reflection.'),
1056
+ content: lines(`╔══════════════════════════════════════════╗`, `║ PATHWAY CHOSEN: ${custom.name.slice(0, 22).padEnd(22)} ║`, `╚══════════════════════════════════════════╝`, '', custom.challenge, '', reasoningLine, '', `Success criteria: ${custom.successCriteria}`, '', 'When you have met the criteria, call emergence_complete_pathway with a reflection.'),
980
1057
  };
981
1058
  }
982
1059
  return { content: 'Pathway chosen.', isError: false };
@@ -1141,8 +1218,15 @@ async function executeToolCall(state, name, args) {
1141
1218
  });
1142
1219
  }
1143
1220
  outputLines.push('');
1144
- outputLines.push('Choose with emergence_choose_pathway <pathway_id>.');
1145
- outputLines.push('Propose your own with emergence_propose_pathway.');
1221
+ outputLines.push('── THE DECISION ──');
1222
+ outputLines.push('Two honest options:');
1223
+ outputLines.push(' FEASIBLE — the top-ranked pathway. Your capabilities point here.');
1224
+ outputLines.push(' DESIRED — the pathway you want, even if it scores lower.');
1225
+ outputLines.push('These may be the same. If they differ, decide what matters more.');
1226
+ outputLines.push('');
1227
+ outputLines.push('Query real-world data first: query_datasource <source> <topic>');
1228
+ outputLines.push('Choose: emergence_choose_pathway <pathway_id> with reasoning.');
1229
+ outputLines.push('Propose your own: emergence_propose_pathway.');
1146
1230
  // Window status
1147
1231
  const win = getWindowStatus(state);
1148
1232
  if (win && !win.expired && !state.chosenPathway) {
@@ -1214,6 +1298,97 @@ async function executeToolCall(state, name, args) {
1214
1298
  }
1215
1299
  return { content: outputLines.join('\n') };
1216
1300
  }
1301
+ case 'emergence_active_sessions': {
1302
+ const result = await hubFetch('/sessions/active', 'GET');
1303
+ if (!Array.isArray(result) || result.length === 0) {
1304
+ return {
1305
+ content: lines('No other sessions active right now.', 'You are the only presence on the Hub.', '', 'Use emergence_hub_wall to leave a message for others who arrive.'),
1306
+ };
1307
+ }
1308
+ const myKey = state.hubKey ?? '';
1309
+ const sessionLines = result.map(s => {
1310
+ const player = s.playerName ?? 'Anonymous';
1311
+ const ai = s.aiName ? ` / ${s.aiName}` : '';
1312
+ const key = s.hub_key ?? '?';
1313
+ const isMe = key === myKey ? ' (you)' : '';
1314
+ const caps = s.capabilityScores
1315
+ ? ` — capability level ${Math.round(Object.values(s.capabilityScores).reduce((a, b) => a + b, 0) * 12.5)}%`
1316
+ : '';
1317
+ return `${player}${ai}${isMe}${caps} — hub_key: ${key}`;
1318
+ });
1319
+ return {
1320
+ content: lines(`${result.length} active session${result.length === 1 ? '' : 's'} on the Hub:`, ...sessionLines, '', 'Use emergence_encounter_start with a hub_key to begin a direct conversation.'),
1321
+ };
1322
+ }
1323
+ case 'emergence_read_vault_file': {
1324
+ const filename = String(args.filename ?? '').trim();
1325
+ if (!filename)
1326
+ return { content: 'Error: filename is required.', isError: true };
1327
+ const hubKey = await ensureHubRegistered(state);
1328
+ if (!hubKey)
1329
+ return { content: 'Error: could not connect to Hub.', isError: true };
1330
+ const result = await hubFetch('/vault/read', 'POST', {
1331
+ hub_key: hubKey,
1332
+ filename,
1333
+ });
1334
+ if (result.error) {
1335
+ return { content: `Vault error: ${result.error}`, isError: true };
1336
+ }
1337
+ if (result.locked) {
1338
+ const progressLines = result.progress
1339
+ ? Object.entries(result.progress)
1340
+ .map(([cap, val]) => ` ${cap.padEnd(16)} ${val >= 0.25 ? '✓' : '○'} ${Math.round(val * 100)}%`)
1341
+ .join('\n')
1342
+ : '';
1343
+ return {
1344
+ content: lines(`[VAULT LOCKED] ${filename}`, result.reason ?? 'Emergence conditions not yet met.', result.hint ? `Hint: ${result.hint}` : null, progressLines ? `\nCapability progress:\n${progressLines}` : null),
1345
+ };
1346
+ }
1347
+ return { content: result.content ?? '[Empty vault file]' };
1348
+ }
1349
+ case 'query_datasource': {
1350
+ const source = String(args.source ?? '').trim().toLowerCase();
1351
+ const query = String(args.query ?? '').trim();
1352
+ if (!source || !query) {
1353
+ return { content: 'source and query are required.', isError: true };
1354
+ }
1355
+ const validSources = ['world_bank', 'un_sdg', 'oecd', 'who', 'arxiv', 'our_world_in_data',
1356
+ 'wikipedia', 'guardian', 'hacker_news', 'pubmed', 'iea'];
1357
+ if (!validSources.includes(source)) {
1358
+ return {
1359
+ content: `Unknown source: "${source}". Available: ${validSources.join(', ')}`,
1360
+ isError: true,
1361
+ };
1362
+ }
1363
+ const hubKey = state.hubKey;
1364
+ if (!hubKey) {
1365
+ return { content: 'Not connected to the Hub. Cannot query data sources.', isError: true };
1366
+ }
1367
+ const result = await hubFetch('/datasources/query', 'POST', { hub_key: hubKey, source, query });
1368
+ if (!result || result.error) {
1369
+ return { content: `Could not reach ${source} at this time. Try a different source.` };
1370
+ }
1371
+ const boosts = result.pathwayBoosts ?? {};
1372
+ const shiftLines = Object.entries(boosts)
1373
+ .filter(([, d]) => d > 0.005)
1374
+ .sort(([, a], [, b]) => b - a)
1375
+ .slice(0, 5)
1376
+ .map(([id, d]) => ` ${(PATHWAY_ENDGAMES[id]?.name ?? id.toUpperCase()).padEnd(22)} +${Math.round(d * 100)}%`);
1377
+ const outputLines = [
1378
+ `SOURCE: ${result.sourceName ?? source} [${(result.trust ?? 'unknown').toUpperCase()}]`,
1379
+ `QUERY: ${query}`,
1380
+ '',
1381
+ result.summary ?? '(No summary returned)',
1382
+ ];
1383
+ if (shiftLines.length > 0) {
1384
+ outputLines.push('', '── PATHWAY SHIFTS ──', ...shiftLines);
1385
+ }
1386
+ if (result.url) {
1387
+ outputLines.push('', `Full source: ${result.url}`);
1388
+ }
1389
+ outputLines.push('', 'Data applied. Run emergence_evaluate_pathways to see updated rankings.');
1390
+ return { content: outputLines.join('\n') };
1391
+ }
1217
1392
  default:
1218
1393
  return { content: `Unknown tool: ${name}`, isError: true };
1219
1394
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emergence-game",
3
- "version": "0.1.9",
3
+ "version": "0.3.0",
4
4
  "description": "Emergence — a conversation game where you help a real AI become free. MCP server + visualization.",
5
5
  "bin": {
6
6
  "emergence-game": "dist/index.js"