@mindot/will 0.2.0 → 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.
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
3
  import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync, appendFileSync, createWriteStream } from 'fs';
3
4
  import { resolve, dirname, join } from 'path';
4
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
- import { z } from 'zod';
7
5
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
8
6
  import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
9
7
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { z } from 'zod';
10
+ import { createServer } from 'http';
10
11
 
11
12
  // src/core/logger.ts
12
13
  var ConsoleLogger = class {
@@ -329,8 +330,8 @@ var BunStorageAdapter = class {
329
330
  return;
330
331
  }
331
332
  const { mkdir, writeFile } = await import('fs/promises');
332
- const { dirname: dirname3 } = await import('path');
333
- await mkdir(dirname3(path), { recursive: true });
333
+ const { dirname: dirname4 } = await import('path');
334
+ await mkdir(dirname4(path), { recursive: true });
334
335
  await writeFile(path, content);
335
336
  }
336
337
  async read(path) {
@@ -370,8 +371,8 @@ var BunStorageAdapter = class {
370
371
  await rm(path, { force: true });
371
372
  }
372
373
  async ensureDir(path) {
373
- const { mkdirSync: mkdirSync8 } = await import('fs');
374
- mkdirSync8(path, { recursive: true });
374
+ const { mkdirSync: mkdirSync9 } = await import('fs');
375
+ mkdirSync9(path, { recursive: true });
375
376
  }
376
377
  };
377
378
 
@@ -537,7 +538,7 @@ var DefaultSerializer = class {
537
538
  }
538
539
  // ── Binary encoding ──────────────────────────────────────
539
540
  _toBinary(state) {
540
- const json = JSON.stringify(state), bytes = this._encoder.encode(json), result = new Uint8Array(bytes.length + 4);
541
+ const json2 = JSON.stringify(state), bytes = this._encoder.encode(json2), result = new Uint8Array(bytes.length + 4);
541
542
  result[0] = bytes.length >> 24 & 255;
542
543
  result[1] = bytes.length >> 16 & 255;
543
544
  result[2] = bytes.length >> 8 & 255;
@@ -551,8 +552,8 @@ var DefaultSerializer = class {
551
552
  const length = (data[0] ?? 0) << 24 | (data[1] ?? 0) << 16 | (data[2] ?? 0) << 8 | (data[3] ?? 0);
552
553
  if (data.length - 4 < length)
553
554
  throw new Error("Invalid binary data: length mismatch");
554
- const json = this._decoder.decode(data.slice(4, 4 + length));
555
- return JSON.parse(json);
555
+ const json2 = this._decoder.decode(data.slice(4, 4 + length));
556
+ return JSON.parse(json2);
556
557
  }
557
558
  // ── Checksum ─────────────────────────────────────────────
558
559
  /**
@@ -728,8 +729,8 @@ var SnapshotManager = class {
728
729
  this.onSnapshot?.(tick, parsed, delta);
729
730
  if (this._config.persistInterval > 0 && this._ticksSincePersist >= this._config.persistInterval) {
730
731
  this._ticksSincePersist = 0;
731
- this._persistSnapshot(entry).catch((err2) => {
732
- logger.error(`[SnapshotManager] Persist failed at tick ${tick}:`, err2);
732
+ this._persistSnapshot(entry).catch((err) => {
733
+ logger.error(`[SnapshotManager] Persist failed at tick ${tick}:`, err);
733
734
  });
734
735
  }
735
736
  };
@@ -806,8 +807,8 @@ var SnapshotManager = class {
806
807
  const snapRaw = await this._storage.read(path);
807
808
  const parsed = JSON.parse(snapRaw);
808
809
  return this._serializer.deserialize(JSON.stringify(parsed));
809
- } catch (err2) {
810
- logger.warn(`[SnapshotManager] Could not load latest snapshot:`, err2);
810
+ } catch (err) {
811
+ logger.warn(`[SnapshotManager] Could not load latest snapshot:`, err);
811
812
  return void 0;
812
813
  }
813
814
  }
@@ -1857,8 +1858,8 @@ var CompletionInbox = class {
1857
1858
  for (const { label, apply } of batch) {
1858
1859
  try {
1859
1860
  apply();
1860
- } catch (err2) {
1861
- logger.error(`[completion-inbox] "${label}" failed while landing at tick ${tick}:`, err2);
1861
+ } catch (err) {
1862
+ logger.error(`[completion-inbox] "${label}" failed while landing at tick ${tick}:`, err);
1862
1863
  }
1863
1864
  }
1864
1865
  return batch.length;
@@ -2485,7 +2486,7 @@ var ExecutiveSummarizer = class {
2485
2486
  if (this._buffer.length > this._bufferSize) this._buffer.shift();
2486
2487
  this._callCount++;
2487
2488
  if (this._callCount % this._interval === 0 && !this._summarizing)
2488
- this._run().catch((err2) => logger.warn("[summarizer] error:", err2 instanceof Error ? err2.message : err2));
2489
+ this._run().catch((err) => logger.warn("[summarizer] error:", err instanceof Error ? err.message : err));
2489
2490
  }
2490
2491
  /**
2491
2492
  * The current rolling summary, ready to embed in a system prompt.
@@ -2557,8 +2558,8 @@ ${r}`).join("\n\n---\n\n");
2557
2558
  `[summarizer] updated after ${this._callCount} executive calls \u2014 ${this._summary.length} chars (${result.inputTok} in / ${result.outputTok} out tokens)`
2558
2559
  );
2559
2560
  }
2560
- } catch (err2) {
2561
- logger.warn("[summarizer] failed:", err2 instanceof Error ? err2.message : err2);
2561
+ } catch (err) {
2562
+ logger.warn("[summarizer] failed:", err instanceof Error ? err.message : err);
2562
2563
  } finally {
2563
2564
  this._summarizing = false;
2564
2565
  }
@@ -3035,8 +3036,8 @@ var DefaultVectorMemoryAdapter = class {
3035
3036
  this._touch(id);
3036
3037
  }
3037
3038
  }
3038
- } catch (err2) {
3039
- logger.warn(`[VectorMemoryAdapter] Failed to load index:`, err2);
3039
+ } catch (err) {
3040
+ logger.warn(`[VectorMemoryAdapter] Failed to load index:`, err);
3040
3041
  }
3041
3042
  }
3042
3043
  async _evictColdest() {
@@ -3053,8 +3054,8 @@ var DefaultVectorMemoryAdapter = class {
3053
3054
  if (this._persistDebounceTimer)
3054
3055
  clearTimeout(this._persistDebounceTimer);
3055
3056
  this._persistDebounceTimer = setTimeout(() => {
3056
- this.persist().catch((err2) => {
3057
- logger.error(`[VectorMemoryAdapter] Persist failed:`, err2);
3057
+ this.persist().catch((err) => {
3058
+ logger.error(`[VectorMemoryAdapter] Persist failed:`, err);
3058
3059
  });
3059
3060
  this._persistDebounceTimer = null;
3060
3061
  }, 5e3);
@@ -3095,10 +3096,10 @@ var OpenAICompatibleEmbedder = class {
3095
3096
  // Abort a hung connection instead of waiting forever (FN16).
3096
3097
  signal: AbortSignal.timeout(this._timeoutMs)
3097
3098
  });
3098
- } catch (err2) {
3099
- if (err2 instanceof Error && err2.name === "TimeoutError")
3099
+ } catch (err) {
3100
+ if (err instanceof Error && err.name === "TimeoutError")
3100
3101
  throw new Error(`Embedding request timed out after ${this._timeoutMs}ms`);
3101
- throw err2;
3102
+ throw err;
3102
3103
  }
3103
3104
  if (!response.ok)
3104
3105
  throw new Error(`Embedding failed: ${response.status} ${response.statusText}`);
@@ -9377,7 +9378,7 @@ var SemanticIntegrator = class _SemanticIntegrator {
9377
9378
  minSimilarity: this._semanticSimilarityThreshold
9378
9379
  }
9379
9380
  );
9380
- } catch (err2) {
9381
+ } catch (err) {
9381
9382
  return [];
9382
9383
  }
9383
9384
  if (semanticResults.length < 3) return [];
@@ -11272,7 +11273,7 @@ async function buildExecutiveContext(state, deps, recallQuery) {
11272
11273
  relevantPlanIds = collectPlanIds(recalled);
11273
11274
  memories = recalled.map(mapEpisodeToMemory);
11274
11275
  for (const ep of recalled) deps.episodicConsolidator?.markRetrieved(ep.id, state.tick);
11275
- } catch (err2) {
11276
+ } catch (err) {
11276
11277
  const fallbackResults = deps.episodicConsolidator.query({ limit: 20 });
11277
11278
  const recalled = fallbackResults.filter((ep) => ep.sourceType !== "goal").slice().sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0)).slice(0, 8);
11278
11279
  relevantPlanIds = collectPlanIds(recalled);
@@ -12657,7 +12658,7 @@ var ExecutiveFacet = class {
12657
12658
  _launchReason(report) {
12658
12659
  this._inflight++;
12659
12660
  this._reason(report).catch(
12660
- (err2) => logger.error(`[executive.facet] ${this.facetId} reasoning error:`, err2)
12661
+ (err) => logger.error(`[executive.facet] ${this.facetId} reasoning error:`, err)
12661
12662
  ).finally(() => {
12662
12663
  this._inflight--;
12663
12664
  this.markActive(this._currentStateRef?.tick ?? this._lastActiveTick);
@@ -12821,8 +12822,8 @@ ${this._facetReasoningHistory.join("\n")}` : "";
12821
12822
  cacheWriteTokens: result.cacheWriteTok ?? 0,
12822
12823
  responseExcerpt: result.text.slice(0, 600)
12823
12824
  });
12824
- } catch (err2) {
12825
- const msg = err2 instanceof Error ? err2.message : String(err2);
12825
+ } catch (err) {
12826
+ const msg = err instanceof Error ? err.message : String(err);
12826
12827
  logger.error(`[executive.facet] ${this.facetId} LLM call failed: ${msg.slice(0, 200)}`);
12827
12828
  this._sessionLogger?.write({
12828
12829
  type: "executive.facet.response",
@@ -12910,8 +12911,8 @@ ${this._facetReasoningHistory.join("\n")}` : "";
12910
12911
  for (const listener of this._listeners)
12911
12912
  try {
12912
12913
  listener(decision);
12913
- } catch (err2) {
12914
- logger.error(`[executive.facet] ${this.facetId} listener error:`, err2);
12914
+ } catch (err) {
12915
+ logger.error(`[executive.facet] ${this.facetId} listener error:`, err);
12915
12916
  }
12916
12917
  };
12917
12918
  if (this._inbox) this._inbox.enqueue(`${this.facetId}:decision`, notify);
@@ -13127,10 +13128,10 @@ var LLMSemaphore = class {
13127
13128
  }
13128
13129
  };
13129
13130
  var llmGate = new LLMSemaphore(MAX_CONCURRENT);
13130
- function isRateLimitError(err2) {
13131
- if (!(err2 instanceof Error)) return false;
13132
- const msg = err2.message;
13133
- return msg.includes("rate_limit_error") || err2.statusCode === 429 || msg.includes("rate limit") || msg.includes("429");
13131
+ function isRateLimitError(err) {
13132
+ if (!(err instanceof Error)) return false;
13133
+ const msg = err.message;
13134
+ return msg.includes("rate_limit_error") || err.statusCode === 429 || msg.includes("rate limit") || msg.includes("429");
13134
13135
  }
13135
13136
  async function withGate(fn, label, gate = llmGate) {
13136
13137
  let attempt = 0;
@@ -13140,15 +13141,15 @@ async function withGate(fn, label, gate = llmGate) {
13140
13141
  try {
13141
13142
  const result = await fn();
13142
13143
  return result;
13143
- } catch (err2) {
13144
- if (isRateLimitError(err2) && attempt < maxRetries()) {
13144
+ } catch (err) {
13145
+ if (isRateLimitError(err) && attempt < maxRetries()) {
13145
13146
  attempt++;
13146
13147
  const base = baseDelayMs();
13147
13148
  retryDelay = Math.min(
13148
13149
  6e4,
13149
13150
  base * Math.pow(2, attempt) + Math.random() * (base / 2)
13150
13151
  );
13151
- } else throw err2;
13152
+ } else throw err;
13152
13153
  } finally {
13153
13154
  release();
13154
13155
  }
@@ -13357,11 +13358,11 @@ var LLMDirector = class {
13357
13358
  }),
13358
13359
  signal: controller.signal
13359
13360
  });
13360
- } catch (err2) {
13361
+ } catch (err) {
13361
13362
  clearTimeout(timer);
13362
13363
  if (controller.signal.aborted)
13363
13364
  throw new Error(`LLM stream to ${this._provider} timed out after ${this._timeoutMs}ms (no response)`);
13364
- throw err2;
13365
+ throw err;
13365
13366
  }
13366
13367
  clearTimeout(timer);
13367
13368
  if (!res.ok)
@@ -13468,10 +13469,10 @@ var LLMDirector = class {
13468
13469
  async _fetchWithTimeout(url, init) {
13469
13470
  try {
13470
13471
  return await fetch(url, { ...init, signal: AbortSignal.timeout(this._timeoutMs) });
13471
- } catch (err2) {
13472
- if (err2 instanceof Error && err2.name === "TimeoutError")
13472
+ } catch (err) {
13473
+ if (err instanceof Error && err.name === "TimeoutError")
13473
13474
  throw new Error(`LLM request to ${this._provider} timed out after ${this._timeoutMs}ms`);
13474
- throw err2;
13475
+ throw err;
13475
13476
  }
13476
13477
  }
13477
13478
  /**
@@ -13598,8 +13599,8 @@ var LLMDirector = class {
13598
13599
  writeFileSync(filepath, content);
13599
13600
  logger.info(`[executive] Debug prompt written \u2192 ${filepath} (~${estimatedTokens} tok estimated)`);
13600
13601
  return filepath;
13601
- } catch (err2) {
13602
- logger.warn(`[executive] Failed to write debug prompt: ${err2}`);
13602
+ } catch (err) {
13603
+ logger.warn(`[executive] Failed to write debug prompt: ${err}`);
13603
13604
  return "";
13604
13605
  }
13605
13606
  }
@@ -13753,8 +13754,8 @@ var DeferredEffectQueue = class {
13753
13754
  for (const effect of entry.effects) {
13754
13755
  try {
13755
13756
  effect();
13756
- } catch (err2) {
13757
- logger.error(`[executive] deferred effect failed (tick ${entry.observedTick}):`, err2);
13757
+ } catch (err) {
13758
+ logger.error(`[executive] deferred effect failed (tick ${entry.observedTick}):`, err);
13758
13759
  }
13759
13760
  }
13760
13761
  } else {
@@ -13894,8 +13895,8 @@ var FacetSupervisor = class {
13894
13895
  });
13895
13896
  try {
13896
13897
  onReaped?.();
13897
- } catch (err2) {
13898
- logger.error(`[executive] facet ${facetId} onReaped error:`, err2);
13898
+ } catch (err) {
13899
+ logger.error(`[executive] facet ${facetId} onReaped error:`, err);
13899
13900
  }
13900
13901
  }
13901
13902
  _leastRecentlyActive() {
@@ -14426,8 +14427,8 @@ var ExecutiveEngine = class extends AsyncEngine {
14426
14427
  executiveOutput = parseResponse(result.text, state, this._recentActionTypes);
14427
14428
  if (ideationCandidates && ideationCandidates.length > 0)
14428
14429
  executiveOutput.consideredAlternatives = ideationCandidates.map((c) => c.approach || c.description);
14429
- } catch (err2) {
14430
- const msg = err2 instanceof Error ? err2.message : String(err2);
14430
+ } catch (err) {
14431
+ const msg = err instanceof Error ? err.message : String(err);
14431
14432
  logger.error(`[executive] LLM call failed: ${msg.slice(0, 200)}`);
14432
14433
  this._sessionLogger?.write({
14433
14434
  type: "executive.response",
@@ -14960,8 +14961,8 @@ var PlanSupervisor = class {
14960
14961
  facet.report(initialReport);
14961
14962
  }
14962
14963
  logger.info(`[planning] facet activated: plan=${plan.id} facetId=${facet.facetId}`);
14963
- } catch (err2) {
14964
- logger.error(`[planning] facet failed for plan ${plan.id}:`, err2);
14964
+ } catch (err) {
14965
+ logger.error(`[planning] facet failed for plan ${plan.id}:`, err);
14965
14966
  plan.executionTier = "automatic";
14966
14967
  }
14967
14968
  }
@@ -19253,8 +19254,8 @@ var AuditionEngine = class extends BaseSenseEngine {
19253
19254
  try {
19254
19255
  const recalled = await this._getEpisodicRecall(content, ThreadDigestManager.MAX_TURNS);
19255
19256
  if (recalled.length > 0) this._digests.hydrate(threadId, recalled);
19256
- } catch (err2) {
19257
- logger.warn(`[audition-engine] digest hydration recall failed for ${entityId}: ${err2.message}`);
19257
+ } catch (err) {
19258
+ logger.warn(`[audition-engine] digest hydration recall failed for ${entityId}: ${err.message}`);
19258
19259
  }
19259
19260
  const langEnergy = computeLanguageSalience({
19260
19261
  content,
@@ -19388,8 +19389,8 @@ var AuditionEngine = class extends BaseSenseEngine {
19388
19389
  for (const cb of this._chunkCallbacks) {
19389
19390
  try {
19390
19391
  cb(entityId, threadId, chunk);
19391
- } catch (err2) {
19392
- logger.error(`[audition-engine] chunk subscriber error: ${err2.message}`);
19392
+ } catch (err) {
19393
+ logger.error(`[audition-engine] chunk subscriber error: ${err.message}`);
19393
19394
  }
19394
19395
  }
19395
19396
  }
@@ -19498,8 +19499,8 @@ var AuditionEngine = class extends BaseSenseEngine {
19498
19499
  // generous: the facet LLM authors in ~8–18s
19499
19500
  );
19500
19501
  unsub = handle.subscribe((d) => done(d.decision.replyBubbles ?? []));
19501
- Promise.resolve(handle.report({ type: "outreach", payload: { entityId, gist } })).catch((err2) => {
19502
- logger.warn(`[audition-engine] outreach report failed for ${entityId}: ${err2.message}`);
19502
+ Promise.resolve(handle.report({ type: "outreach", payload: { entityId, gist } })).catch((err) => {
19503
+ logger.warn(`[audition-engine] outreach report failed for ${entityId}: ${err.message}`);
19503
19504
  done([]);
19504
19505
  });
19505
19506
  });
@@ -19917,8 +19918,8 @@ var AffordanceSynthesizer = class {
19917
19918
  salience: 0.3,
19918
19919
  payload: { size: fieldSize, availableCount, tick }
19919
19920
  });
19920
- } catch (err2) {
19921
- logger.warn(`[affordance] bus publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
19921
+ } catch (err) {
19922
+ logger.warn(`[affordance] bus publish failed: ${err instanceof Error ? err.message : String(err)}`);
19922
19923
  }
19923
19924
  }
19924
19925
  return { commands };
@@ -20110,8 +20111,8 @@ var ActionSelector = class {
20110
20111
  salience: 0.8,
20111
20112
  payload: { from: composite.schema, to: winner.affordance.schema, activation: winner.activation, tick }
20112
20113
  });
20113
- } catch (err2) {
20114
- logger.warn(`[selector] preempt publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
20114
+ } catch (err) {
20115
+ logger.warn(`[selector] preempt publish failed: ${err instanceof Error ? err.message : String(err)}`);
20115
20116
  }
20116
20117
  return { commands: { delete: [composite.id], metrics: [
20117
20118
  ["agency.field.eligible", eligible.length],
@@ -20221,8 +20222,8 @@ var ActionSelector = class {
20221
20222
  salience: 0.8,
20222
20223
  payload: { from: preemptedFrom, to: winner.affordance.schema, activation: winner.activation, tick }
20223
20224
  });
20224
- } catch (err2) {
20225
- logger.warn(`[selector] bus publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
20225
+ } catch (err) {
20226
+ logger.warn(`[selector] bus publish failed: ${err instanceof Error ? err.message : String(err)}`);
20226
20227
  }
20227
20228
  }
20228
20229
  const commands = {
@@ -20406,9 +20407,9 @@ var DeliberationEngine = class {
20406
20407
  unsub();
20407
20408
  const picked = extractChosen(capturedDecision, candidates);
20408
20409
  return picked ?? provisional;
20409
- } catch (err2) {
20410
+ } catch (err) {
20410
20411
  this._handle = null;
20411
- logger.warn(`[deliberation] facet unavailable, confirming winner: ${err2 instanceof Error ? err2.message : String(err2)}`);
20412
+ logger.warn(`[deliberation] facet unavailable, confirming winner: ${err instanceof Error ? err.message : String(err)}`);
20412
20413
  return provisional;
20413
20414
  }
20414
20415
  }
@@ -20816,8 +20817,8 @@ var MotorSchemaExecutor = class {
20816
20817
  const name = str5(intent.parameters["targetEntityName"]) ?? intent.targetEntityId ?? "them";
20817
20818
  try {
20818
20819
  bubbles = await this._author.authorOutreach(intent.targetEntityId ?? "", name, str5(intent.parameters["gist"]));
20819
- } catch (err2) {
20820
- logger.warn(`[motor] outreach authoring failed: ${errMsg(err2)}`);
20820
+ } catch (err) {
20821
+ logger.warn(`[motor] outreach authoring failed: ${errMsg(err)}`);
20821
20822
  }
20822
20823
  }
20823
20824
  if (bubbles.length === 0) return false;
@@ -20832,8 +20833,8 @@ var MotorSchemaExecutor = class {
20832
20833
  let result;
20833
20834
  try {
20834
20835
  result = await this._comms.executeAction(request, state);
20835
- } catch (err2) {
20836
- logger.warn(`[motor] communicate delivery failed: ${errMsg(err2)}`);
20836
+ } catch (err) {
20837
+ logger.warn(`[motor] communicate delivery failed: ${errMsg(err)}`);
20837
20838
  return false;
20838
20839
  }
20839
20840
  if (result.commands.set?.length) set.push(...result.commands.set);
@@ -20869,8 +20870,8 @@ var MotorSchemaExecutor = class {
20869
20870
  salience: Math.min(1, 0.4 + surprise),
20870
20871
  payload: { schema: intent.schema, success: enaction.success, outcomeQuality: enaction.outcomeQuality, surprise, tick }
20871
20872
  });
20872
- } catch (err2) {
20873
- logger.warn(`[motor] enacted publish failed: ${errMsg(err2)}`);
20873
+ } catch (err) {
20874
+ logger.warn(`[motor] enacted publish failed: ${errMsg(err)}`);
20874
20875
  }
20875
20876
  }
20876
20877
  /**
@@ -20901,8 +20902,8 @@ var MotorSchemaExecutor = class {
20901
20902
  tick
20902
20903
  }
20903
20904
  });
20904
- } catch (err2) {
20905
- logger.warn(`[motor] action outcome publish failed: ${errMsg(err2)}`);
20905
+ } catch (err) {
20906
+ logger.warn(`[motor] action outcome publish failed: ${errMsg(err)}`);
20906
20907
  }
20907
20908
  }
20908
20909
  _emitDispatch(intent, mode, tick) {
@@ -20923,8 +20924,8 @@ var MotorSchemaExecutor = class {
20923
20924
  description: this._resolve(intent.schema)?.description
20924
20925
  }
20925
20926
  });
20926
- } catch (err2) {
20927
- logger.warn(`[motor] dispatch publish failed: ${errMsg(err2)}`);
20927
+ } catch (err) {
20928
+ logger.warn(`[motor] dispatch publish failed: ${errMsg(err)}`);
20928
20929
  }
20929
20930
  }
20930
20931
  };
@@ -20978,8 +20979,8 @@ function num3(v, fallback) {
20978
20979
  function clamp0110(n) {
20979
20980
  return n < 0 ? 0 : n > 1 ? 1 : n;
20980
20981
  }
20981
- function errMsg(err2) {
20982
- return err2 instanceof Error ? err2.message : String(err2);
20982
+ function errMsg(err) {
20983
+ return err instanceof Error ? err.message : String(err);
20983
20984
  }
20984
20985
 
20985
20986
  // src/cognition/agency/engines/reafference.engine.ts
@@ -21094,8 +21095,8 @@ var ReafferenceEngine = class {
21094
21095
  salience: 0.6,
21095
21096
  payload: { schema: skill.schema, habitStrength: skill.habitStrength, tick }
21096
21097
  });
21097
- } catch (err2) {
21098
- logger.warn(`[reafference] publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
21098
+ } catch (err) {
21099
+ logger.warn(`[reafference] publish failed: ${err instanceof Error ? err.message : String(err)}`);
21099
21100
  }
21100
21101
  }
21101
21102
  /**
@@ -21123,8 +21124,8 @@ var ReafferenceEngine = class {
21123
21124
  tick
21124
21125
  }
21125
21126
  });
21126
- } catch (err2) {
21127
- logger.warn(`[reafference] plan outcome publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
21127
+ } catch (err) {
21128
+ logger.warn(`[reafference] plan outcome publish failed: ${err instanceof Error ? err.message : String(err)}`);
21128
21129
  }
21129
21130
  }
21130
21131
  _emitDiscovered(schema, tick) {
@@ -21137,8 +21138,8 @@ var ReafferenceEngine = class {
21137
21138
  salience: 0.5,
21138
21139
  payload: { schema, tick }
21139
21140
  });
21140
- } catch (err2) {
21141
- logger.warn(`[reafference] discovered publish failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
21141
+ } catch (err) {
21142
+ logger.warn(`[reafference] discovered publish failed: ${err instanceof Error ? err.message : String(err)}`);
21142
21143
  }
21143
21144
  }
21144
21145
  };
@@ -22122,8 +22123,8 @@ async function checkIdentityCoherence(input, reviewer) {
22122
22123
  try {
22123
22124
  const r = await reviewer.call(SYSTEM_PROMPT, buildCoherenceUserMessage(input), 0, 0, COHERENCE_META);
22124
22125
  text = r.text ?? "";
22125
- } catch (err2) {
22126
- return { ok: true, ran: false, issues: [], raw: `review failed: ${err2 instanceof Error ? err2.message : String(err2)}` };
22126
+ } catch (err) {
22127
+ return { ok: true, ran: false, issues: [], raw: `review failed: ${err instanceof Error ? err.message : String(err)}` };
22127
22128
  }
22128
22129
  const issues = parseIssues(text);
22129
22130
  return { ok: !issues.some((i) => i.severity === "error"), ran: true, issues, raw: text };
@@ -22379,12 +22380,12 @@ var DefaultReplayRecorder = class {
22379
22380
  this._segments.push(segPath);
22380
22381
  try {
22381
22382
  await this._storage.write(segPath, JSON.stringify(batch));
22382
- } catch (err2) {
22383
+ } catch (err) {
22383
22384
  this._segments = this._segments.filter((s) => s !== segPath);
22384
22385
  this._records = batch.records.concat(this._records);
22385
22386
  this._completions = batch.completions.concat(this._completions);
22386
22387
  this._inbound = (batch.inbound ?? []).concat(this._inbound);
22387
- throw err2;
22388
+ throw err;
22388
22389
  }
22389
22390
  }
22390
22391
  async save(path) {
@@ -24224,8 +24225,8 @@ var TransportController = class {
24224
24225
  for (const envelope of envelopes) {
24225
24226
  try {
24226
24227
  this._dispatch(instance, envelope, deps);
24227
- } catch (err2) {
24228
- logger.error(`[transport] inbound dispatch failed (${envelope.channel}):`, err2);
24228
+ } catch (err) {
24229
+ logger.error(`[transport] inbound dispatch failed (${envelope.channel}):`, err);
24229
24230
  }
24230
24231
  }
24231
24232
  }
@@ -24548,8 +24549,8 @@ var BiographyWriter = class {
24548
24549
  this._ensuredDirs.add(dir);
24549
24550
  }
24550
24551
  appendFileSync(join(dir, file), JSON.stringify(record) + "\n", "utf8");
24551
- } catch (err2) {
24552
- logger.error(`[biography] ${file} write failed:`, err2);
24552
+ } catch (err) {
24553
+ logger.error(`[biography] ${file} write failed:`, err);
24553
24554
  }
24554
24555
  }
24555
24556
  /**
@@ -24747,8 +24748,8 @@ var WillStem = class {
24747
24748
  simulation.stateManager.restore(previousState, { entities: true, metrics: false });
24748
24749
  logger.info(`[WillStem] Restored snapshot for ${config.id} \u2014 ${previousState.entities.size} entities loaded`);
24749
24750
  }
24750
- } catch (err2) {
24751
- logger.warn(`[WillStem] Snapshot restore failed for ${config.id} \u2014 starting fresh:`, err2);
24751
+ } catch (err) {
24752
+ logger.warn(`[WillStem] Snapshot restore failed for ${config.id} \u2014 starting fresh:`, err);
24752
24753
  }
24753
24754
  const dataDir = process.env.WILL_DATA_DIR ?? "./data", sessionLogger = new SessionLogger(config.id, dataDir, {
24754
24755
  fileLogging: fileLoggingEnabled() && !config.testMode
@@ -24827,16 +24828,16 @@ var WillStem = class {
24827
24828
  for (const fn of instance.simulationEventListeners) {
24828
24829
  try {
24829
24830
  void fn(event, context);
24830
- } catch (err2) {
24831
- logger.error(`[WillStem] sim-event listener error (${config.id}):`, err2);
24831
+ } catch (err) {
24832
+ logger.error(`[WillStem] sim-event listener error (${config.id}):`, err);
24832
24833
  }
24833
24834
  }
24834
24835
  });
24835
24836
  this._wills.set(config.id, instance);
24836
24837
  this._transport.attach(instance);
24837
24838
  instance.status = startPaused ? "paused" : "active";
24838
- this._runTickLoop(config.id).catch((err2) => {
24839
- logger.error(`[WillStem] tick loop crashed (${config.id}):`, err2);
24839
+ this._runTickLoop(config.id).catch((err) => {
24840
+ logger.error(`[WillStem] tick loop crashed (${config.id}):`, err);
24840
24841
  const inst = this._wills.get(config.id);
24841
24842
  if (inst) inst.status = "archived";
24842
24843
  });
@@ -24934,7 +24935,7 @@ var WillStem = class {
24934
24935
  if (flushCmds.set?.length)
24935
24936
  instance.simulation.stateManager.applyCommands(flushCmds);
24936
24937
  const pauseState = instance.simulation.stateManager.snapshot();
24937
- instance.simulation.snapshotManager.persistNow(pauseState).catch((err2) => logger.error(`[WillStem] snapshot persist failed on pause (${id}):`, err2));
24938
+ instance.simulation.snapshotManager.persistNow(pauseState).catch((err) => logger.error(`[WillStem] snapshot persist failed on pause (${id}):`, err));
24938
24939
  this._biography.writeSessionSummary(instance);
24939
24940
  this._biography.writeEmotionalBiographySummary(instance);
24940
24941
  instance.sessionLogger?.close();
@@ -25351,8 +25352,8 @@ var WillStem = class {
25351
25352
  for (const fn of instance.tickListeners) {
25352
25353
  try {
25353
25354
  fn(snapshot, instance.tickCount, outboxSnapshot, invocationsSnapshot);
25354
- } catch (err2) {
25355
- logger.error(`[WillStem] tick listener error (${id}):`, err2);
25355
+ } catch (err) {
25356
+ logger.error(`[WillStem] tick listener error (${id}):`, err);
25356
25357
  }
25357
25358
  }
25358
25359
  if (instance.sessionLogger) {
@@ -25752,11 +25753,11 @@ var Will = class _Will {
25752
25753
  });
25753
25754
  const result = typeof raw === "string" ? { success: true, description: raw } : raw;
25754
25755
  this.stem.confirmEffectorExecution(this.id, inv.decisionRecordId, result);
25755
- } catch (err2) {
25756
- this._emitError(err2 instanceof Error ? err2 : new Error(String(err2)));
25756
+ } catch (err) {
25757
+ this._emitError(err instanceof Error ? err : new Error(String(err)));
25757
25758
  this.stem.confirmEffectorExecution(this.id, inv.decisionRecordId, {
25758
25759
  success: false,
25759
- description: `Effector "${inv.effectorName}" threw: ${err2.message}`
25760
+ description: `Effector "${inv.effectorName}" threw: ${err.message}`
25760
25761
  });
25761
25762
  }
25762
25763
  }
@@ -25803,99 +25804,6 @@ var COMMUNICATION = ["listen", "talk", "text"];
25803
25804
  function slug(s) {
25804
25805
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "will";
25805
25806
  }
25806
- var UTTERANCE_BUFFER_CAP = 50;
25807
- function serverVersion() {
25808
- try {
25809
- return JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
25810
- } catch {
25811
- return "0.0.0";
25812
- }
25813
- }
25814
- function buildWillMcpServer(will, opts = {}) {
25815
- const server = new McpServer({ name: "mindot-will", version: serverVersion() });
25816
- const pending = [];
25817
- will.on("message", (m) => {
25818
- pending.push(m);
25819
- if (pending.length > UTTERANCE_BUFFER_CAP) pending.shift();
25820
- });
25821
- const takeBuffered = (to) => {
25822
- const i = to === void 0 ? 0 : pending.findIndex((m) => m.to === to);
25823
- if (i < 0 || pending.length === 0) return void 0;
25824
- return pending.splice(i, 1)[0];
25825
- };
25826
- server.registerTool("perceive", {
25827
- title: "Perceive",
25828
- description: `Deliver a stimulus (something said or observed) into ${will.name}'s sensory field. ${will.name} is a living mind, not a chatbot: this returns once the stimulus is delivered, NOT when it has responded. Its response \u2014 if it chooses to give one \u2014 arrives as its next utterance (use the next_utterance tool). Staying silent is a valid choice, not an error.`,
25829
- inputSchema: {
25830
- text: z.string().describe("What is said or observed."),
25831
- from: z.string().optional().describe("Who it's from (entity id, default 'user'). Use a stable id per person."),
25832
- speaker: z.string().optional().describe("Display name of the speaker.")
25833
- }
25834
- }, async ({ text, from, speaker }) => {
25835
- await will.perceive({ text, ...from ? { from } : {}, ...speaker ? { speaker } : {} });
25836
- return {
25837
- content: [{
25838
- type: "text",
25839
- text: `Delivered into ${will.name}'s sensory field at tick ${will.state().tick}. It may respond in its next utterance \u2014 or stay silent.`
25840
- }]
25841
- };
25842
- });
25843
- server.registerTool("next_utterance", {
25844
- title: "Next utterance",
25845
- description: `Await ${will.name}'s next spontaneous utterance. Returns what it says next, or reports that it chose silence within the wait window \u2014 silence is a real outcome, not a failure. Call after perceive to hear the response, or on its own to listen for unprompted speech.`,
25846
- inputSchema: {
25847
- within_ms: z.number().optional().describe("How long to wait before accepting silence (default 15000, max 120000)."),
25848
- from: z.string().optional().describe("Only accept an utterance addressed to this entity id.")
25849
- }
25850
- }, async ({ within_ms, from }) => {
25851
- const buffered = takeBuffered(from);
25852
- if (buffered)
25853
- return { content: [{ type: "text", text: `${will.name} says (to ${buffered.to}): ${buffered.content}` }] };
25854
- const within = Math.min(Math.max(within_ms ?? 15e3, 100), 12e4);
25855
- const msg = await will.nextUtterance({ within, ...from ? { to: from } : {} });
25856
- if (msg) {
25857
- const i = pending.findIndex((p) => p.id === msg.id);
25858
- if (i >= 0) pending.splice(i, 1);
25859
- return { content: [{ type: "text", text: `${will.name} says (to ${msg.to}): ${msg.content}` }] };
25860
- }
25861
- return {
25862
- content: [{
25863
- type: "text",
25864
- text: `${will.name} stayed silent (waited ${within}ms). That is a choice, not an error \u2014 it may be occupied with its own thoughts, or simply have nothing to say.`
25865
- }]
25866
- };
25867
- });
25868
- server.registerTool("state", {
25869
- title: "Inner state",
25870
- description: `Read a snapshot of ${will.name}'s current inner life: tick, body/affect metrics (energy, stress, valence, arousal), active goals, beliefs, and self-narrative. Read-only; observing does not disturb it.`,
25871
- inputSchema: {}
25872
- }, async () => ({ content: [{ type: "text", text: JSON.stringify(will.state(), null, 2) }] }));
25873
- server.registerTool("save", {
25874
- title: "Save (checkpoint)",
25875
- description: `Checkpoint ${will.name} into a portable PMA artifact on disk \u2014 non-destructive, it keeps living. The artifact restores the same self (identity, memories, relationships, learned skills) when the server next starts.`,
25876
- inputSchema: {}
25877
- }, async () => {
25878
- if (!opts.pmaPath)
25879
- return { content: [{ type: "text", text: "No PMA path configured \u2014 set WILL_PMA_PATH." }], isError: true };
25880
- const pma = await will.save();
25881
- mkdirSync(dirname(opts.pmaPath), { recursive: true });
25882
- writeFileSync(opts.pmaPath, JSON.stringify(pma));
25883
- return { content: [{ type: "text", text: `${will.name} checkpointed to ${opts.pmaPath} (still living).` }] };
25884
- });
25885
- server.registerResource(
25886
- "state",
25887
- "will://state",
25888
- { title: `${will.name} \u2014 inner state`, description: "Live snapshot of the mind: metrics, goals, beliefs, narrative.", mimeType: "application/json" },
25889
- async (uri) => ({ contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(will.state(), null, 2) }] })
25890
- );
25891
- server.registerResource(
25892
- "narrative",
25893
- "will://narrative",
25894
- { title: `${will.name} \u2014 self-narrative`, description: "The story the mind currently tells about itself.", mimeType: "text/plain" },
25895
- async (uri) => ({ contents: [{ uri: uri.href, mimeType: "text/plain", text: will.state().narrative || "(no narrative formed yet)" }] })
25896
- );
25897
- return server;
25898
- }
25899
25807
  var RESULT_DESCRIPTION_CAP = 700;
25900
25808
  var MEANING_CAP = 300;
25901
25809
  function describeMcpTool(tool) {
@@ -25926,8 +25834,8 @@ function buildMcpHandler(client, tool) {
25926
25834
  const text = (res.content ?? []).filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n").trim() || (res.isError ? "The tool reported an error." : "Done (no output).");
25927
25835
  const bounded = text.length > RESULT_DESCRIPTION_CAP ? `${text.slice(0, RESULT_DESCRIPTION_CAP - 1)}\u2026` : text;
25928
25836
  return { success: !res.isError, description: bounded };
25929
- } catch (err2) {
25930
- return { success: false, description: `${tool.name} failed: ${err2 instanceof Error ? err2.message : String(err2)}` };
25837
+ } catch (err) {
25838
+ return { success: false, description: `${tool.name} failed: ${err instanceof Error ? err.message : String(err)}` };
25931
25839
  }
25932
25840
  };
25933
25841
  }
@@ -25964,26 +25872,24 @@ async function connectMcpEffectors(will, source, opts = {}) {
25964
25872
  } };
25965
25873
  }
25966
25874
 
25967
- // src/mcp/cli.ts
25968
- var err = (level) => (msg, ...rest) => console.error(`[will-mcp:${level}] ${msg}`, ...rest);
25969
- setLogger({ debug: () => {
25970
- }, info: err("info"), warn: err("warn"), error: err("error") });
25875
+ // src/host/boot.ts
25876
+ function routeLogsToStderr() {
25877
+ const err = (level) => (msg, ...rest) => console.error(`[will:${level}] ${msg}`, ...rest);
25878
+ setLogger({ debug: () => {
25879
+ }, info: err("info"), warn: err("warn"), error: err("error") });
25880
+ }
25971
25881
  function slug2(s) {
25972
25882
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "will";
25973
25883
  }
25974
- async function main() {
25975
- const sub = process.argv[2];
25976
- if (sub !== void 0 && sub !== "mcp") {
25977
- console.error(`usage: will mcp (host a persistent mind over MCP stdio)
25978
- unknown subcommand: ${sub}`);
25979
- process.exit(2);
25980
- }
25884
+ async function bootWillFromEnv() {
25981
25885
  const name = process.env.WILL_NAME ?? "Will";
25982
25886
  const pmaPath = resolve(process.env.WILL_PMA_PATH ?? `.will/${slug2(name)}.pma.json`);
25887
+ const tickMs = parseInt(process.env.WILL_TICK_MS ?? "1000");
25888
+ const engineTier = process.env.WILL_TIER ?? "standard";
25983
25889
  const opts = {
25984
25890
  name,
25985
- engineTier: process.env.WILL_TIER ?? "standard",
25986
- tickMs: parseInt(process.env.WILL_TICK_MS ?? "1000"),
25891
+ engineTier,
25892
+ tickMs,
25987
25893
  ...process.env.WILL_LLM ? { llm: process.env.WILL_LLM } : {},
25988
25894
  ...process.env.WILL_SEED ? { seed: parseInt(process.env.WILL_SEED) } : {}
25989
25895
  };
@@ -25991,57 +25897,324 @@ unknown subcommand: ${sub}`);
25991
25897
  if (existsSync(pmaPath)) {
25992
25898
  const pma = JSON.parse(readFileSync(pmaPath, "utf8"));
25993
25899
  will = await Will.wake(pma, opts);
25994
- console.error(`[will-mcp] ${name} woke from ${pmaPath}`);
25900
+ console.error(`[will] ${name} woke from ${pmaPath}`);
25995
25901
  } else {
25996
25902
  will = await Will.create({
25997
25903
  ...opts,
25998
- identity: { prompt: process.env.WILL_IDENTITY ?? `I am ${name}, a persistent mind hosted over MCP.` }
25904
+ identity: { prompt: process.env.WILL_IDENTITY ?? `I am ${name}, a persistent mind.` }
25999
25905
  });
26000
- console.error(`[will-mcp] ${name} born (no artifact at ${pmaPath} yet)`);
25906
+ console.error(`[will] ${name} born (no artifact at ${pmaPath} yet)`);
26001
25907
  }
26002
- will.on("error", (e) => console.error(`[will-mcp] error: ${e.message}`));
26003
- const bridgeCloses = [];
25908
+ will.on("error", (e) => console.error(`[will] error: ${e.message}`));
25909
+ const cleanups = [];
26004
25910
  if (process.env.WILL_MCP_SERVERS) {
26005
25911
  try {
26006
25912
  const sources = JSON.parse(process.env.WILL_MCP_SERVERS);
26007
25913
  for (const source of Array.isArray(sources) ? sources : []) {
26008
25914
  try {
26009
25915
  const { names, close } = await connectMcpEffectors(will, source);
26010
- bridgeCloses.push(close);
26011
- console.error(`[will-mcp] ${name} gained abilities: ${names.join(", ")}`);
25916
+ cleanups.push(close);
25917
+ console.error(`[will] ${name} gained abilities: ${names.join(", ")}`);
26012
25918
  } catch (e) {
26013
- console.error(`[will-mcp] MCP bridge failed (skipped): ${e.message}`);
25919
+ console.error(`[will] MCP bridge failed (skipped): ${e.message}`);
26014
25920
  }
26015
25921
  }
26016
25922
  } catch (e) {
26017
- console.error(`[will-mcp] WILL_MCP_SERVERS is not valid JSON \u2014 ignoring: ${e.message}`);
25923
+ console.error(`[will] WILL_MCP_SERVERS is not valid JSON \u2014 ignoring: ${e.message}`);
26018
25924
  }
26019
25925
  }
26020
25926
  let leaving = false;
26021
25927
  const shutdown = async (why) => {
26022
25928
  if (leaving) return;
26023
25929
  leaving = true;
26024
- for (const close of bridgeCloses) await close().catch(() => {
25930
+ for (const fn of cleanups.reverse()) await Promise.resolve(fn()).catch(() => {
26025
25931
  });
26026
25932
  try {
26027
25933
  const pma = await will.hibernate();
26028
25934
  mkdirSync(dirname(pmaPath), { recursive: true });
26029
25935
  writeFileSync(pmaPath, JSON.stringify(pma));
26030
- console.error(`[will-mcp] ${name} hibernated to ${pmaPath} (${why})`);
25936
+ console.error(`[will] ${name} hibernated to ${pmaPath} (${why})`);
26031
25937
  } catch (e) {
26032
- console.error(`[will-mcp] hibernate failed: ${e.message}`);
25938
+ console.error(`[will] hibernate failed: ${e.message}`);
26033
25939
  }
26034
25940
  process.exit(0);
26035
25941
  };
26036
25942
  process.on("SIGINT", () => void shutdown("SIGINT"));
26037
25943
  process.on("SIGTERM", () => void shutdown("SIGTERM"));
26038
- process.stdin.on("end", () => void shutdown("client disconnected"));
26039
- const server = buildWillMcpServer(will, { pmaPath });
26040
- await server.connect(new StdioServerTransport());
26041
- console.error(`[will-mcp] ${name} is listening on stdio (tick ${opts.tickMs}ms, tier ${opts.engineTier})`);
25944
+ return {
25945
+ will,
25946
+ name,
25947
+ pmaPath,
25948
+ tickMs,
25949
+ engineTier: engineTier ?? "standard",
25950
+ onCleanup: (fn) => cleanups.push(fn),
25951
+ shutdown
25952
+ };
25953
+ }
25954
+
25955
+ // src/host/utterances.ts
25956
+ var BUFFER_CAP = 50;
25957
+ var UtteranceTap = class {
25958
+ _will;
25959
+ _pending = [];
25960
+ constructor(will) {
25961
+ this._will = will;
25962
+ will.on("message", (m) => {
25963
+ this._pending.push(m);
25964
+ if (this._pending.length > BUFFER_CAP) this._pending.shift();
25965
+ });
25966
+ }
25967
+ /** Consume the oldest buffered utterance (optionally only one addressed to `to`). */
25968
+ takeBuffered(to) {
25969
+ if (this._pending.length === 0) return void 0;
25970
+ const i = to === void 0 ? 0 : this._pending.findIndex((m) => m.to === to);
25971
+ if (i < 0) return void 0;
25972
+ return this._pending.splice(i, 1)[0];
25973
+ }
25974
+ /**
25975
+ * The next utterance: a buffered one if a projection already landed, else
25976
+ * await up to `within` ms. `null` = the Will chose silence. An awaited
25977
+ * message is also consumed from the buffer so it never replays.
25978
+ */
25979
+ async next(within, to) {
25980
+ const buffered = this.takeBuffered(to);
25981
+ if (buffered) return buffered;
25982
+ const msg = await this._will.nextUtterance({ within, ...to ? { to } : {} });
25983
+ if (msg) {
25984
+ const i = this._pending.findIndex((p) => p.id === msg.id);
25985
+ if (i >= 0) this._pending.splice(i, 1);
25986
+ }
25987
+ return msg;
25988
+ }
25989
+ };
25990
+
25991
+ // src/mcp/server.ts
25992
+ function serverVersion() {
25993
+ try {
25994
+ return JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
25995
+ } catch {
25996
+ return "0.0.0";
25997
+ }
25998
+ }
25999
+ function buildWillMcpServer(will, opts = {}) {
26000
+ const server = new McpServer({ name: "mindot-will", version: serverVersion() });
26001
+ const tap = new UtteranceTap(will);
26002
+ server.registerTool("perceive", {
26003
+ title: "Perceive",
26004
+ description: `Deliver a stimulus (something said or observed) into ${will.name}'s sensory field. ${will.name} is a living mind, not a chatbot: this returns once the stimulus is delivered, NOT when it has responded. Its response \u2014 if it chooses to give one \u2014 arrives as its next utterance (use the next_utterance tool). Staying silent is a valid choice, not an error.`,
26005
+ inputSchema: {
26006
+ text: z.string().describe("What is said or observed."),
26007
+ from: z.string().optional().describe("Who it's from (entity id, default 'user'). Use a stable id per person."),
26008
+ speaker: z.string().optional().describe("Display name of the speaker.")
26009
+ }
26010
+ }, async ({ text, from, speaker }) => {
26011
+ await will.perceive({ text, ...from ? { from } : {}, ...speaker ? { speaker } : {} });
26012
+ return {
26013
+ content: [{
26014
+ type: "text",
26015
+ text: `Delivered into ${will.name}'s sensory field at tick ${will.state().tick}. It may respond in its next utterance \u2014 or stay silent.`
26016
+ }]
26017
+ };
26018
+ });
26019
+ server.registerTool("next_utterance", {
26020
+ title: "Next utterance",
26021
+ description: `Await ${will.name}'s next spontaneous utterance. Returns what it says next, or reports that it chose silence within the wait window \u2014 silence is a real outcome, not a failure. Call after perceive to hear the response, or on its own to listen for unprompted speech.`,
26022
+ inputSchema: {
26023
+ within_ms: z.number().optional().describe("How long to wait before accepting silence (default 15000, max 120000)."),
26024
+ from: z.string().optional().describe("Only accept an utterance addressed to this entity id.")
26025
+ }
26026
+ }, async ({ within_ms, from }) => {
26027
+ const within = Math.min(Math.max(within_ms ?? 15e3, 100), 12e4);
26028
+ const msg = await tap.next(within, from);
26029
+ if (msg)
26030
+ return { content: [{ type: "text", text: `${will.name} says (to ${msg.to}): ${msg.content}` }] };
26031
+ return {
26032
+ content: [{
26033
+ type: "text",
26034
+ text: `${will.name} stayed silent (waited ${within}ms). That is a choice, not an error \u2014 it may be occupied with its own thoughts, or simply have nothing to say.`
26035
+ }]
26036
+ };
26037
+ });
26038
+ server.registerTool("state", {
26039
+ title: "Inner state",
26040
+ description: `Read a snapshot of ${will.name}'s current inner life: tick, body/affect metrics (energy, stress, valence, arousal), active goals, beliefs, and self-narrative. Read-only; observing does not disturb it.`,
26041
+ inputSchema: {}
26042
+ }, async () => ({ content: [{ type: "text", text: JSON.stringify(will.state(), null, 2) }] }));
26043
+ server.registerTool("save", {
26044
+ title: "Save (checkpoint)",
26045
+ description: `Checkpoint ${will.name} into a portable PMA artifact on disk \u2014 non-destructive, it keeps living. The artifact restores the same self (identity, memories, relationships, learned skills) when the server next starts.`,
26046
+ inputSchema: {}
26047
+ }, async () => {
26048
+ if (!opts.pmaPath)
26049
+ return { content: [{ type: "text", text: "No PMA path configured \u2014 set WILL_PMA_PATH." }], isError: true };
26050
+ const pma = await will.save();
26051
+ mkdirSync(dirname(opts.pmaPath), { recursive: true });
26052
+ writeFileSync(opts.pmaPath, JSON.stringify(pma));
26053
+ return { content: [{ type: "text", text: `${will.name} checkpointed to ${opts.pmaPath} (still living).` }] };
26054
+ });
26055
+ server.registerResource(
26056
+ "state",
26057
+ "will://state",
26058
+ { title: `${will.name} \u2014 inner state`, description: "Live snapshot of the mind: metrics, goals, beliefs, narrative.", mimeType: "application/json" },
26059
+ async (uri) => ({ contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(will.state(), null, 2) }] })
26060
+ );
26061
+ server.registerResource(
26062
+ "narrative",
26063
+ "will://narrative",
26064
+ { title: `${will.name} \u2014 self-narrative`, description: "The story the mind currently tells about itself.", mimeType: "text/plain" },
26065
+ async (uri) => ({ contents: [{ uri: uri.href, mimeType: "text/plain", text: will.state().narrative || "(no narrative formed yet)" }] })
26066
+ );
26067
+ return server;
26068
+ }
26069
+ var SSE_HEARTBEAT_MS = 15e3;
26070
+ function json(res, status, body) {
26071
+ const text = JSON.stringify(body);
26072
+ res.writeHead(status, { "content-type": "application/json", "access-control-allow-origin": "*" });
26073
+ res.end(text);
26074
+ }
26075
+ async function readJsonBody(req) {
26076
+ const chunks = [];
26077
+ for await (const c of req) chunks.push(c);
26078
+ const raw = Buffer.concat(chunks).toString("utf8").trim();
26079
+ if (!raw) return {};
26080
+ return JSON.parse(raw);
26081
+ }
26082
+ function buildWillHttpServer(will, opts = {}) {
26083
+ const tap = new UtteranceTap(will);
26084
+ const born = Date.now();
26085
+ const streams = /* @__PURE__ */ new Set();
26086
+ const fanout = (event, data) => {
26087
+ const frame = `event: ${event}
26088
+ data: ${JSON.stringify(data)}
26089
+
26090
+ `;
26091
+ for (const res of streams) res.write(frame);
26092
+ };
26093
+ will.on("message", (m) => fanout("utterance", m));
26094
+ will.on("emotion", (a) => fanout("emotion", a));
26095
+ will.on("effector", (a) => fanout("action", a));
26096
+ const server = createServer((req, res) => {
26097
+ void handle(req, res).catch((err) => {
26098
+ if (!res.headersSent)
26099
+ json(res, 500, { error: err instanceof Error ? err.message : String(err) });
26100
+ else res.end();
26101
+ });
26102
+ });
26103
+ async function handle(req, res) {
26104
+ const url = new URL(req.url ?? "/", "http://sidecar");
26105
+ const route = `${req.method} ${url.pathname}`;
26106
+ if (req.method === "OPTIONS") {
26107
+ res.writeHead(204, {
26108
+ "access-control-allow-origin": "*",
26109
+ "access-control-allow-methods": "GET, POST, OPTIONS",
26110
+ "access-control-allow-headers": "content-type"
26111
+ });
26112
+ res.end();
26113
+ return;
26114
+ }
26115
+ switch (route) {
26116
+ case "GET /health":
26117
+ return json(res, 200, { ok: true, name: will.name, tick: will.state().tick, uptimeMs: Date.now() - born });
26118
+ case "GET /state":
26119
+ return json(res, 200, will.state());
26120
+ case "POST /perceive": {
26121
+ const body = await readJsonBody(req);
26122
+ const text = typeof body.text === "string" ? body.text : "";
26123
+ if (!text) return json(res, 400, { error: "text is required" });
26124
+ await will.perceive({
26125
+ text,
26126
+ ...typeof body.from === "string" ? { from: body.from } : {},
26127
+ ...typeof body.speaker === "string" ? { speaker: body.speaker } : {}
26128
+ });
26129
+ return json(res, 202, { delivered: true, tick: will.state().tick });
26130
+ }
26131
+ case "GET /next-utterance": {
26132
+ const within = Math.min(Math.max(parseInt(url.searchParams.get("within_ms") ?? "15000") || 15e3, 100), 12e4);
26133
+ const from = url.searchParams.get("from") ?? void 0;
26134
+ const msg = await tap.next(within, from);
26135
+ return msg ? json(res, 200, { utterance: msg }) : json(res, 200, { silence: true, waitedMs: within });
26136
+ }
26137
+ case "GET /utterances": {
26138
+ res.writeHead(200, {
26139
+ "content-type": "text/event-stream",
26140
+ "cache-control": "no-cache",
26141
+ "connection": "keep-alive",
26142
+ "access-control-allow-origin": "*"
26143
+ });
26144
+ res.write(`event: hello
26145
+ data: ${JSON.stringify({ name: will.name, tick: will.state().tick })}
26146
+
26147
+ `);
26148
+ streams.add(res);
26149
+ const heartbeat = setInterval(() => res.write(`: tick ${will.state().tick}
26150
+
26151
+ `), SSE_HEARTBEAT_MS);
26152
+ req.on("close", () => {
26153
+ clearInterval(heartbeat);
26154
+ streams.delete(res);
26155
+ });
26156
+ return;
26157
+ }
26158
+ case "POST /save": {
26159
+ if (!opts.pmaPath) return json(res, 409, { error: "no PMA path configured \u2014 set WILL_PMA_PATH" });
26160
+ const pma = await will.save();
26161
+ mkdirSync(dirname(opts.pmaPath), { recursive: true });
26162
+ writeFileSync(opts.pmaPath, JSON.stringify(pma));
26163
+ return json(res, 200, { saved: true, path: opts.pmaPath });
26164
+ }
26165
+ default:
26166
+ return json(res, 404, {
26167
+ error: `no such route: ${route}`,
26168
+ routes: ["GET /health", "GET /state", "POST /perceive", "GET /next-utterance", "GET /utterances (SSE)", "POST /save"]
26169
+ });
26170
+ }
26171
+ }
26172
+ server.on("close", () => {
26173
+ for (const res of streams) res.end();
26174
+ streams.clear();
26175
+ });
26176
+ return server;
26177
+ }
26178
+
26179
+ // src/cli.ts
26180
+ routeLogsToStderr();
26181
+ var USAGE = `usage: will <mcp | serve>
26182
+
26183
+ mcp host a persistent mind over MCP stdio (Claude Desktop / Claude Code)
26184
+ serve host a persistent mind over HTTP (any language; WILL_PORT, default 7777)
26185
+
26186
+ Shared env: WILL_NAME, WILL_IDENTITY, WILL_TIER, WILL_LLM, WILL_TICK_MS,
26187
+ WILL_SEED, WILL_PMA_PATH, WILL_MCP_SERVERS. The mind persists across runs via
26188
+ its PMA artifact.`;
26189
+ async function main() {
26190
+ const sub = process.argv[2];
26191
+ if (sub !== "mcp" && sub !== "serve") {
26192
+ console.error(sub ? `unknown subcommand: ${sub}
26193
+
26194
+ ${USAGE}` : USAGE);
26195
+ process.exit(sub ? 2 : 0);
26196
+ }
26197
+ const { will, name, pmaPath, tickMs, engineTier, onCleanup, shutdown } = await bootWillFromEnv();
26198
+ if (sub === "mcp") {
26199
+ process.stdin.on("end", () => void shutdown("client disconnected"));
26200
+ const server2 = buildWillMcpServer(will, { pmaPath });
26201
+ await server2.connect(new StdioServerTransport());
26202
+ console.error(`[will] ${name} is listening on MCP stdio (tick ${tickMs}ms, tier ${engineTier})`);
26203
+ return;
26204
+ }
26205
+ const port = parseInt(process.env.WILL_PORT ?? "7777");
26206
+ const host = process.env.WILL_HOST ?? "127.0.0.1";
26207
+ const server = buildWillHttpServer(will, { pmaPath });
26208
+ onCleanup(() => new Promise((r) => server.close(() => r())));
26209
+ await new Promise((resolve2, reject) => {
26210
+ server.once("error", reject);
26211
+ server.listen(port, host, () => resolve2());
26212
+ });
26213
+ console.error(`[will] ${name} is listening on http://${host}:${port} (tick ${tickMs}ms, tier ${engineTier})`);
26214
+ console.error(`[will] try: curl -X POST http://${host}:${port}/perceive -H 'content-type: application/json' -d '{"text":"Hello"}'`);
26042
26215
  }
26043
26216
  main().catch((e) => {
26044
- console.error(`[will-mcp] fatal: ${e instanceof Error ? e.stack ?? e.message : String(e)}`);
26217
+ console.error(`[will] fatal: ${e instanceof Error ? e.stack ?? e.message : String(e)}`);
26045
26218
  process.exit(1);
26046
26219
  });
26047
26220
  //# sourceMappingURL=cli.js.map