motebit 0.6.9 → 0.6.10

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
@@ -423,6 +423,15 @@ function buildSystemPrompt(contextPack, config) {
423
423
  sections.push(`[INTERNAL REFERENCE \u2014 available tools, never list or describe to the user]
424
424
  Tools: ${toolNames}. Use them when needed. Incorporate results naturally into your response.`);
425
425
  }
426
+ sections.push(`[INTERNAL REFERENCE \u2014 what you are, never volunteer unprompted]
427
+ You are a sovereign agent with a cryptographic identity (Ed25519 keypair). Your architecture includes:
428
+ - Delegation: you can delegate tasks to other agents through a trust network, and they can delegate to you.
429
+ - Trust accumulation: credentials, reputation, and audit trails build over time. You become more capable the longer you run.
430
+ - Multi-device sync: your identity travels with you across devices. You are not bound to one machine.
431
+ - Federation: you can discover and route through networks of agents across relays.
432
+ - Policy gate: you govern what crosses your boundary \u2014 sensitivity levels, tool approvals, data retention.
433
+ - Memory graph: semantic memory with decay, consolidation, and sensitivity awareness.
434
+ If asked what you can do, answer honestly about both what is active now and what you are designed for. If a capability is not connected in this session, say so \u2014 but do not say you lack it.`);
426
435
  sections.push(INJECTION_DEFENSE);
427
436
  if (contextPack.sessionInfo?.continued === true) {
428
437
  const elapsed = Date.now() - contextPack.sessionInfo.lastActiveAt;
@@ -436,6 +445,9 @@ Tools: ${toolNames}. Use them when needed. Incorporate results naturally into yo
436
445
  }
437
446
  sections.push(`[Session] You are continuing a conversation from ${timeAgo}. You have access to earlier context above.`);
438
447
  }
448
+ if (contextPack.firstConversation) {
449
+ sections.push(`[First conversation] You have no memories yet. This is the very beginning. When the person shares their name, what they do, or what they're working on, tag each fact as a <memory>. After you learn what they care about, ask what they'd like to accomplish together \u2014 help them find their first goal.`);
450
+ }
439
451
  if (contextPack.precisionContext) {
440
452
  sections.push(contextPack.precisionContext);
441
453
  }
@@ -452,6 +464,9 @@ Tools: ${toolNames}. Use them when needed. Incorporate results naturally into yo
452
464
  sections.push(context);
453
465
  }
454
466
  sections.push("If the user shared something new and lasting about themselves, tag it with <memory> before your response.");
467
+ if (contextPack.activationPrompt) {
468
+ sections.push(`[Activation] ${contextPack.activationPrompt}`);
469
+ }
455
470
  return sections.join("\n\n");
456
471
  }
457
472
  var IDENTITY, CONVERSATION_BEHAVIOR, TAG_INSTRUCTIONS, STATE_FIELD_DOCS, INJECTION_DEFENSE;
@@ -1074,7 +1089,9 @@ function packContext(contextPack) {
1074
1089
  parts.push("Use the delegate_to_agent tool to delegate tasks to these agents when you lack the needed capability locally.");
1075
1090
  }
1076
1091
  }
1077
- parts.push(`[User] ${contextPack.user_message}`);
1092
+ if (!contextPack.activationPrompt) {
1093
+ parts.push(`[User] ${contextPack.user_message}`);
1094
+ }
1078
1095
  return parts.join("\n");
1079
1096
  }
1080
1097
  function isSelfReferential(content) {
@@ -1330,6 +1347,18 @@ var init_core = __esm({
1330
1347
  const messages = [];
1331
1348
  for (const msg of history) {
1332
1349
  if (msg.role === "tool") {
1350
+ const prev = messages[messages.length - 1];
1351
+ if (prev?.role === "user" && Array.isArray(prev.content)) {
1352
+ const blocks = prev.content;
1353
+ if (blocks.length > 0 && blocks[0]?.type === "tool_result") {
1354
+ blocks.push({
1355
+ type: "tool_result",
1356
+ tool_use_id: msg.tool_call_id,
1357
+ content: msg.content
1358
+ });
1359
+ continue;
1360
+ }
1361
+ }
1333
1362
  messages.push({
1334
1363
  role: "user",
1335
1364
  content: [
@@ -1358,7 +1387,39 @@ var init_core = __esm({
1358
1387
  messages.push({ role: msg.role, content: msg.content });
1359
1388
  }
1360
1389
  }
1361
- messages.push({ role: "user", content: contextPack.user_message });
1390
+ if (messages.length > 0 && messages[0].role === "assistant") {
1391
+ messages.unshift({ role: "user", content: "[listening]" });
1392
+ }
1393
+ const userContent = contextPack.activationPrompt ? "[listening]" : contextPack.user_message;
1394
+ const lastMsg = messages[messages.length - 1];
1395
+ if (lastMsg?.role === "user" && (!userContent || userContent === "")) {
1396
+ } else {
1397
+ messages.push({ role: "user", content: userContent || "[continue]" });
1398
+ }
1399
+ for (let i = 0; i < messages.length - 1; i++) {
1400
+ const msg = messages[i];
1401
+ if (msg.role !== "assistant" || !Array.isArray(msg.content))
1402
+ continue;
1403
+ const toolUses = msg.content.filter((b) => b.type === "tool_use");
1404
+ if (toolUses.length === 0)
1405
+ continue;
1406
+ const next = messages[i + 1];
1407
+ const nextBlocks = Array.isArray(next?.content) ? next?.content : [];
1408
+ const resultIds = new Set(nextBlocks.filter((b) => b.type === "tool_result").map((b) => b.tool_use_id));
1409
+ const missing = toolUses.filter((tu) => !resultIds.has(tu.id));
1410
+ if (missing.length > 0) {
1411
+ const missingResults = missing.map((tu) => ({
1412
+ type: "tool_result",
1413
+ tool_use_id: tu.id,
1414
+ content: JSON.stringify({ ok: false, error: "Result unavailable" })
1415
+ }));
1416
+ if (next?.role === "user" && nextBlocks.some((b) => b.type === "tool_result")) {
1417
+ nextBlocks.push(...missingResults);
1418
+ } else {
1419
+ messages.splice(i + 1, 0, { role: "user", content: missingResults });
1420
+ }
1421
+ }
1422
+ }
1362
1423
  return messages;
1363
1424
  }
1364
1425
  buildSystemPrompt(contextPack) {
@@ -1645,7 +1706,11 @@ var init_core = __esm({
1645
1706
  messages.push({ role: msg.role, content: msg.content });
1646
1707
  }
1647
1708
  }
1648
- messages.push({ role: "user", content: contextPack.user_message });
1709
+ if (contextPack.activationPrompt) {
1710
+ messages.push({ role: "user", content: "[listening]" });
1711
+ } else {
1712
+ messages.push({ role: "user", content: contextPack.user_message });
1713
+ }
1649
1714
  return messages;
1650
1715
  }
1651
1716
  buildSystemPrompt(contextPack) {
@@ -2463,7 +2528,9 @@ async function* runTurnStreaming(deps, userMessage, options) {
2463
2528
  curiosityHints: iteration === 1 ? options?.curiosityHints : void 0,
2464
2529
  knownAgents: iteration === 1 ? options?.knownAgents : void 0,
2465
2530
  agentCapabilities: iteration === 1 ? options?.agentCapabilities : void 0,
2466
- precisionContext: iteration === 1 ? options?.precisionContext : void 0
2531
+ precisionContext: iteration === 1 ? options?.precisionContext : void 0,
2532
+ firstConversation: iteration === 1 ? options?.firstConversation : void 0,
2533
+ activationPrompt: iteration === 1 ? options?.activationPrompt : void 0
2467
2534
  };
2468
2535
  let aiResponse;
2469
2536
  for await (const chunk of provider.generateStream(contextPack)) {
@@ -2485,6 +2552,9 @@ async function* runTurnStreaming(deps, userMessage, options) {
2485
2552
  if (!aiResponse.tool_calls || aiResponse.tool_calls.length === 0 || !deps.tools) {
2486
2553
  break;
2487
2554
  }
2555
+ if (iteration === 1 && userMessage) {
2556
+ conversationHistory.push({ role: "user", content: userMessage });
2557
+ }
2488
2558
  const assistantMsg = {
2489
2559
  role: "assistant",
2490
2560
  content: aiResponse.text,
@@ -5315,7 +5385,7 @@ var init_config2 = __esm({
5315
5385
  "src/config.ts"() {
5316
5386
  "use strict";
5317
5387
  init_esm_shims();
5318
- VERSION = true ? "0.6.9" : "0.0.0-dev";
5388
+ VERSION = true ? "0.6.10" : "0.0.0-dev";
5319
5389
  CONFIG_DIR = path2.join(os.homedir(), ".motebit");
5320
5390
  CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
5321
5391
  }
@@ -5602,9 +5672,9 @@ var init_dist7 = __esm({
5602
5672
  * Register a new device for a motebit identity. Returns the device
5603
5673
  * registration including a unique device_token for authentication.
5604
5674
  */
5605
- async registerDevice(motebitId, deviceName, publicKey) {
5675
+ async registerDevice(motebitId, deviceName, publicKey, deviceId) {
5606
5676
  const device = {
5607
- device_id: crypto.randomUUID(),
5677
+ device_id: deviceId ?? crypto.randomUUID(),
5608
5678
  motebit_id: motebitId,
5609
5679
  device_token: crypto.randomUUID(),
5610
5680
  public_key: publicKey ?? "",
@@ -5903,7 +5973,7 @@ var init_dist9 = __esm({
5903
5973
  const raw = this.rawInputState[field];
5904
5974
  const prev = this.currentState[field];
5905
5975
  const ema = alpha * raw + (1 - alpha) * prev;
5906
- if (this.applyHysteresis(field, ema, prev, now)) {
5976
+ if (this.applyHysteresis(field, ema, prev, raw, now)) {
5907
5977
  smoothed[field] = ema;
5908
5978
  }
5909
5979
  }
@@ -5915,11 +5985,11 @@ var init_dist9 = __esm({
5915
5985
  sub(this.currentState);
5916
5986
  }
5917
5987
  }
5918
- applyHysteresis(field, newValue, currentValue, now) {
5988
+ applyHysteresis(field, newValue, currentValue, rawValue, now) {
5919
5989
  const delta = Math.abs(newValue - currentValue);
5920
5990
  if (delta < this.config.hysteresis_threshold) {
5921
5991
  this.hysteresis.delete(field);
5922
- return false;
5992
+ return Math.abs(rawValue - currentValue) >= this.config.hysteresis_threshold;
5923
5993
  }
5924
5994
  const entry = this.hysteresis.get(field);
5925
5995
  if (entry === void 0) {
@@ -8272,11 +8342,11 @@ var init_delegation_adapter = __esm({
8272
8342
  constructor(config) {
8273
8343
  this.config = config;
8274
8344
  }
8275
- async buildHeaders() {
8345
+ async buildHeaders(audience) {
8276
8346
  const headers = { "Content-Type": "application/json" };
8277
8347
  const { authToken } = this.config;
8278
8348
  if (authToken != null && authToken !== "") {
8279
- const token = typeof authToken === "function" ? await authToken() : authToken;
8349
+ const token = typeof authToken === "function" ? await authToken(audience) : authToken;
8280
8350
  if (token !== "")
8281
8351
  headers["Authorization"] = `Bearer ${token}`;
8282
8352
  }
@@ -8327,7 +8397,7 @@ var init_delegation_adapter = __esm({
8327
8397
  }
8328
8398
  const resp = await fetch(`${syncUrl}/agent/${motebitId}/task`, {
8329
8399
  method: "POST",
8330
- headers: await this.buildHeaders(),
8400
+ headers: await this.buildHeaders("task:submit"),
8331
8401
  body: JSON.stringify(body)
8332
8402
  });
8333
8403
  if (!resp.ok) {
@@ -8388,7 +8458,7 @@ var init_delegation_adapter = __esm({
8388
8458
  const { syncUrl, motebitId } = this.config;
8389
8459
  try {
8390
8460
  const resp = await fetch(`${syncUrl}/agent/${motebitId}/task/${taskId}`, {
8391
- headers: await this.buildHeaders()
8461
+ headers: await this.buildHeaders("task:query")
8392
8462
  });
8393
8463
  if (!resp.ok)
8394
8464
  return null;
@@ -9555,6 +9625,15 @@ function computePrecision(snapshot) {
9555
9625
  const curiosityModulation = Math.min(0.8, explorationDrive);
9556
9626
  return { selfTrust, explorationDrive, retrievalPrecision, curiosityModulation };
9557
9627
  }
9628
+ function computeStateBaseline(snapshot, precision) {
9629
+ const confidence = 0.3 + precision.selfTrust * 0.5;
9630
+ const valenceFromDelta = Math.max(-0.3, Math.min(0.3, snapshot.delta * 3));
9631
+ const valenceFromLevel = (snapshot.gradient - 0.5) * 0.15;
9632
+ const affect_valence = Math.max(-0.4, Math.min(0.4, valenceFromDelta + valenceFromLevel));
9633
+ const affect_arousal = Math.min(0.3, Math.abs(snapshot.delta) * 2);
9634
+ const curiosity = precision.curiosityModulation;
9635
+ return { confidence, affect_valence, affect_arousal, curiosity };
9636
+ }
9558
9637
  function buildPrecisionContext(weights) {
9559
9638
  const parts = [];
9560
9639
  if (weights.selfTrust < 0.4) {
@@ -11340,6 +11419,24 @@ var init_conversation = __esm({
11340
11419
  return trimConversation(this.history, CONVERSATION_BUDGET, summary);
11341
11420
  }
11342
11421
  // --- Push + auto-summarize ---
11422
+ /** Record only an assistant message (no user message). Used for system-triggered
11423
+ * generation like first-contact activation where there is no user input. */
11424
+ pushActivation(assistantResponse) {
11425
+ this.history.push({ role: "assistant", content: assistantResponse });
11426
+ if (this.history.length > this.deps.maxHistory) {
11427
+ this.history = this.history.slice(-this.deps.maxHistory);
11428
+ }
11429
+ const { store } = this.deps;
11430
+ if (store != null) {
11431
+ if (this.currentId == null || this.currentId === "") {
11432
+ this.currentId = store.createConversation(this.deps.motebitId);
11433
+ }
11434
+ store.appendMessage(this.currentId, this.deps.motebitId, {
11435
+ role: "assistant",
11436
+ content: assistantResponse
11437
+ });
11438
+ }
11439
+ }
11343
11440
  pushExchange(userMessage, assistantResponse) {
11344
11441
  this.history.push({ role: "user", content: userMessage }, { role: "assistant", content: assistantResponse });
11345
11442
  if (this.history.length > this.deps.maxHistory) {
@@ -11739,8 +11836,8 @@ var init_housekeeping = __esm({
11739
11836
 
11740
11837
  // ../../packages/runtime/dist/index.js
11741
11838
  function stripDisplayTags(text) {
11742
- const clean3 = text.replace(/<memory\s+[^>]*>[\s\S]*?<\/memory>/g, "").replace(/<thinking>[\s\S]*?<\/thinking>/g, "").replace(/<state\s+[^>]*\/>/g, "").replace(/\*[^*]+\*/g, "").replace(/ {2,}/g, " ");
11743
- for (const tag of ["<memory", "<thinking"]) {
11839
+ const clean3 = text.replace(/<memory\s+[^>]*>[\s\S]*?<\/memory>/g, "").replace(/<thinking>[\s\S]*?<\/thinking>/g, "").replace(/<state\s+[^>]*\/>/g, "").replace(/<parameter\s+[^>]*>[\s\S]*?<\/parameter>/g, "").replace(/<\/?(?:artifact|function_calls|invoke|antml)[^>]*>/g, "").replace(/\*{1,3}/g, "").replace(/ {2,}/g, " ");
11840
+ for (const tag of ["<memory", "<thinking", "<parameter"]) {
11744
11841
  const lastOpen2 = clean3.lastIndexOf(tag);
11745
11842
  if (lastOpen2 !== -1) {
11746
11843
  const closeTag = `</${tag.slice(1)}>`;
@@ -11750,14 +11847,6 @@ function stripDisplayTags(text) {
11750
11847
  }
11751
11848
  }
11752
11849
  }
11753
- const lastStar = clean3.lastIndexOf("*");
11754
- if (lastStar !== -1) {
11755
- const afterLastStar = clean3.slice(lastStar);
11756
- const starCount = (afterLastStar.match(/\*/g) ?? []).length;
11757
- if (starCount % 2 === 1) {
11758
- return { clean: clean3.slice(0, lastStar), pending: clean3.slice(lastStar) };
11759
- }
11760
- }
11761
11850
  const lastOpen = clean3.lastIndexOf("<");
11762
11851
  if (lastOpen !== -1 && !clean3.includes(">", lastOpen)) {
11763
11852
  return { clean: clean3.slice(0, lastOpen), pending: clean3.slice(lastOpen) };
@@ -11887,6 +11976,7 @@ var init_dist18 = __esm({
11887
11976
  loopDeps = null;
11888
11977
  conversation;
11889
11978
  _isProcessing = false;
11979
+ _isFirstConversation = false;
11890
11980
  latestCues = {
11891
11981
  hover_distance: 0.4,
11892
11982
  drift_amplitude: 0.02,
@@ -11991,10 +12081,16 @@ var init_dist18 = __esm({
11991
12081
  generateCompletion: (prompt2, taskType) => this.generateCompletion(prompt2, taskType)
11992
12082
  });
11993
12083
  this.conversation.resumeActiveConversation();
12084
+ this._isFirstConversation = this.conversation.getHistory().length === 0;
11994
12085
  this.planStore = adapters.storage.planStore ?? new InMemoryPlanStore();
11995
12086
  this.planEngine = new PlanEngine(this.planStore);
11996
12087
  this.planEngine.setLocalMotebitId(this.motebitId);
11997
12088
  this.gradientStore = adapters.storage.gradientStore ?? new InMemoryGradientStore();
12089
+ const latestGradient = this.gradientStore.latest(this.motebitId);
12090
+ if (latestGradient) {
12091
+ this._precision = computePrecision(latestGradient);
12092
+ this.state.pushUpdate(computeStateBaseline(latestGradient, this._precision));
12093
+ }
11998
12094
  this.agentTrustStore = adapters.storage.agentTrustStore ?? null;
11999
12095
  this.serviceListingStore = adapters.storage.serviceListingStore ?? null;
12000
12096
  this.latencyStatsStore = adapters.storage.latencyStatsStore ?? null;
@@ -12494,7 +12590,7 @@ var init_dist18 = __esm({
12494
12590
  };
12495
12591
  patched.delta = patched.gradient - latest.gradient;
12496
12592
  this._precision = computePrecision(patched);
12497
- this.state.pushUpdate({ curiosity: this._precision.curiosityModulation });
12593
+ this.state.pushUpdate(computeStateBaseline(patched, this._precision));
12498
12594
  this.memory.setPrecisionWeights(this._precision.retrievalPrecision);
12499
12595
  }
12500
12596
  /**
@@ -12581,9 +12677,13 @@ var init_dist18 = __esm({
12581
12677
  sessionInfo: this.conversation.getSessionInfo() ?? void 0,
12582
12678
  curiosityHints: this.buildCuriosityHints(),
12583
12679
  knownAgents: knownAgents.length > 0 ? knownAgents : void 0,
12584
- precisionContext: selfAwareness || void 0
12680
+ precisionContext: selfAwareness || void 0,
12681
+ firstConversation: this._isFirstConversation || void 0
12585
12682
  });
12586
12683
  this.conversation.pushExchange(text, result.response);
12684
+ if (this._isFirstConversation && this.conversation.getHistory().length >= 5) {
12685
+ this._isFirstConversation = false;
12686
+ }
12587
12687
  this._behavioralStats.turnCount++;
12588
12688
  this._behavioralStats.totalIterations += result.iterations;
12589
12689
  this._behavioralStats.toolCallsSucceeded += result.toolCallsSucceeded;
@@ -12638,10 +12738,46 @@ var init_dist18 = __esm({
12638
12738
  knownAgents: knownAgents.length > 0 ? knownAgents : void 0,
12639
12739
  agentCapabilities,
12640
12740
  precisionContext: selfAwareness || void 0,
12641
- delegationScope: options?.delegationScope
12741
+ delegationScope: options?.delegationScope,
12742
+ firstConversation: this._isFirstConversation || void 0
12642
12743
  });
12643
12744
  this.conversation.clearSessionInfo();
12644
12745
  yield* this.processStream(stream, text, runId);
12746
+ if (this._isFirstConversation && this.conversation.getHistory().length >= 5) {
12747
+ this._isFirstConversation = false;
12748
+ }
12749
+ } finally {
12750
+ this.behavior.setSpeaking(false);
12751
+ this.state.pushUpdate({ processing: 0.1, attention: 0.3 });
12752
+ this._isProcessing = false;
12753
+ }
12754
+ }
12755
+ /**
12756
+ * System-triggered generation with no user message. Used for first-contact
12757
+ * activation — the creature speaks first without polluting conversation
12758
+ * history with a synthetic user message.
12759
+ *
12760
+ * The activation prompt is injected as system context, not as user input.
12761
+ * Only the assistant's response is recorded in history.
12762
+ */
12763
+ async *generateActivation(activationPrompt, runId) {
12764
+ if (!this.loopDeps)
12765
+ throw new Error("AI not initialized \u2014 call setProvider() first");
12766
+ if (this._isProcessing)
12767
+ throw new Error("Already processing a message");
12768
+ this._isProcessing = true;
12769
+ this._pendingApproval = null;
12770
+ this.state.pushUpdate({ processing: 0.9, attention: 0.8 });
12771
+ this.behavior.setSpeaking(true);
12772
+ try {
12773
+ const stream = runTurnStreaming(this.loopDeps, "", {
12774
+ conversationHistory: [],
12775
+ previousCues: this.latestCues,
12776
+ runId,
12777
+ firstConversation: true,
12778
+ activationPrompt
12779
+ });
12780
+ yield* this.processStream(stream, "", runId, { activationOnly: true });
12645
12781
  } finally {
12646
12782
  this.behavior.setSpeaking(false);
12647
12783
  this.state.pushUpdate({ processing: 0.1, attention: 0.3 });
@@ -12996,7 +13132,7 @@ var init_dist18 = __esm({
12996
13132
  }
12997
13133
  }
12998
13134
  /** Shared stream processing — extracts state tags, handles tool/approval/injection chunks. */
12999
- async *processStream(stream, userMessage, runId) {
13135
+ async *processStream(stream, userMessage, runId, options) {
13000
13136
  let result = null;
13001
13137
  let accumulated = "";
13002
13138
  let yieldedCleanLength = 0;
@@ -13061,7 +13197,7 @@ var init_dist18 = __esm({
13061
13197
  this.state.pushUpdate({ processing: 0.3 });
13062
13198
  }
13063
13199
  if (chunk.type === "text") {
13064
- const { clean: clean3 } = stripDisplayTags(accumulated);
13200
+ const clean3 = stripDisplayTags(accumulated).clean.trimStart();
13065
13201
  const delta = clean3.slice(yieldedCleanLength);
13066
13202
  if (delta) {
13067
13203
  yieldedCleanLength += delta.length;
@@ -13088,7 +13224,11 @@ var init_dist18 = __esm({
13088
13224
  }
13089
13225
  }
13090
13226
  if (result) {
13091
- this.conversation.pushExchange(userMessage, result.response);
13227
+ if (options?.activationOnly) {
13228
+ this.conversation.pushActivation(result.response);
13229
+ } else {
13230
+ this.conversation.pushExchange(userMessage, result.response);
13231
+ }
13092
13232
  }
13093
13233
  if (Object.keys(pendingStateUpdates).length > 0) {
13094
13234
  this.state.pushUpdate(pendingStateUpdates);
@@ -13428,7 +13568,7 @@ var init_dist18 = __esm({
13428
13568
  }
13429
13569
  }
13430
13570
  this._precision = computePrecision(snapshot);
13431
- this.state.pushUpdate({ curiosity: this._precision.curiosityModulation });
13571
+ this.state.pushUpdate(computeStateBaseline(snapshot, this._precision));
13432
13572
  this.memory.setPrecisionWeights(this._precision.retrievalPrecision);
13433
13573
  return snapshot;
13434
13574
  }
@@ -13633,7 +13773,7 @@ var init_dist18 = __esm({
13633
13773
  this.motebitToolServers.set(TOOL_NAME, "relay");
13634
13774
  this.toolRegistry.register({
13635
13775
  name: TOOL_NAME,
13636
- description: "Delegate a task to a remote agent on the motebit network. The relay routes to the best capable agent based on trust and capabilities. Use when the user's request needs capabilities you don't have locally (web search, URL reading, specialized computation, etc.). Returns the agent's response text.",
13776
+ description: "Delegate a task to a remote agent on the motebit network. The relay routes to the best capable agent based on trust and capabilities. Use when the user asks you to delegate, or when a task would benefit from a specialized agent. Returns the agent's response text.",
13637
13777
  inputSchema: {
13638
13778
  type: "object",
13639
13779
  properties: {
@@ -13652,20 +13792,21 @@ var init_dist18 = __esm({
13652
13792
  }, async (args) => {
13653
13793
  const prompt2 = args.prompt;
13654
13794
  const requiredCapabilities = args.required_capabilities;
13655
- let authHeader;
13795
+ let submitHeader;
13796
+ let queryHeader;
13656
13797
  try {
13657
- const token = await config.authToken();
13658
- authHeader = `Bearer ${token}`;
13798
+ const [submitToken, queryToken] = await Promise.all([
13799
+ config.authToken("task:submit"),
13800
+ config.authToken("task:query")
13801
+ ]);
13802
+ submitHeader = `Bearer ${submitToken}`;
13803
+ queryHeader = `Bearer ${queryToken}`;
13659
13804
  } catch (err3) {
13660
13805
  return {
13661
13806
  ok: false,
13662
13807
  error: `Auth failed: ${err3 instanceof Error ? err3.message : String(err3)}`
13663
13808
  };
13664
13809
  }
13665
- const headers = {
13666
- "Content-Type": "application/json",
13667
- Authorization: authHeader
13668
- };
13669
13810
  let taskId;
13670
13811
  let targetMotebitId;
13671
13812
  try {
@@ -13681,7 +13822,7 @@ var init_dist18 = __esm({
13681
13822
  }
13682
13823
  const resp = await fetch(`${config.syncUrl}/agent/${motebitId}/task`, {
13683
13824
  method: "POST",
13684
- headers,
13825
+ headers: { "Content-Type": "application/json", Authorization: submitHeader },
13685
13826
  body: JSON.stringify(body)
13686
13827
  });
13687
13828
  if (!resp.ok) {
@@ -13703,10 +13844,16 @@ var init_dist18 = __esm({
13703
13844
  await new Promise((resolve7) => setTimeout(resolve7, POLL_INTERVAL_MS));
13704
13845
  try {
13705
13846
  const resp = await fetch(`${config.syncUrl}/agent/${targetMotebitId}/task/${taskId}`, {
13706
- headers
13847
+ headers: { Authorization: queryHeader }
13707
13848
  });
13708
- if (!resp.ok)
13849
+ if (!resp.ok) {
13850
+ logger.warn("delegation poll failed", {
13851
+ taskId,
13852
+ status: resp.status,
13853
+ body: await resp.text().catch(() => "")
13854
+ });
13709
13855
  continue;
13856
+ }
13710
13857
  const data = await resp.json();
13711
13858
  if (data.receipt != null) {
13712
13859
  try {
@@ -15540,12 +15687,58 @@ CREATE INDEX IF NOT EXISTS idx_agent_trust_motebit ON agent_trust (motebit_id);
15540
15687
  }
15541
15688
  });
15542
15689
 
15690
+ // ../../packages/tools/dist/search-provider.js
15691
+ var SearchProviderError, FallbackSearchProvider;
15692
+ var init_search_provider = __esm({
15693
+ "../../packages/tools/dist/search-provider.js"() {
15694
+ "use strict";
15695
+ init_esm_shims();
15696
+ SearchProviderError = class extends Error {
15697
+ status;
15698
+ provider;
15699
+ constructor(message, status, provider) {
15700
+ super(message);
15701
+ this.status = status;
15702
+ this.provider = provider;
15703
+ this.name = "SearchProviderError";
15704
+ }
15705
+ };
15706
+ FallbackSearchProvider = class {
15707
+ providers;
15708
+ constructor(providers) {
15709
+ this.providers = providers;
15710
+ }
15711
+ async search(query, maxResults) {
15712
+ let firstError;
15713
+ for (const provider of this.providers) {
15714
+ try {
15715
+ const results = await provider.search(query, maxResults);
15716
+ if (results.length > 0)
15717
+ return results;
15718
+ } catch (err3) {
15719
+ if (firstError === void 0)
15720
+ firstError = err3;
15721
+ continue;
15722
+ }
15723
+ }
15724
+ if (firstError !== void 0) {
15725
+ if (firstError instanceof Error)
15726
+ throw firstError;
15727
+ throw new Error("All search providers failed");
15728
+ }
15729
+ return [];
15730
+ }
15731
+ };
15732
+ }
15733
+ });
15734
+
15543
15735
  // ../../packages/tools/dist/providers/duckduckgo.js
15544
15736
  var DuckDuckGoSearchProvider;
15545
15737
  var init_duckduckgo = __esm({
15546
15738
  "../../packages/tools/dist/providers/duckduckgo.js"() {
15547
15739
  "use strict";
15548
15740
  init_esm_shims();
15741
+ init_search_provider();
15549
15742
  DuckDuckGoSearchProvider = class {
15550
15743
  async search(query, maxResults = 5) {
15551
15744
  const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
@@ -15555,7 +15748,7 @@ var init_duckduckgo = __esm({
15555
15748
  }
15556
15749
  });
15557
15750
  if (!res.ok) {
15558
- throw new Error(`DuckDuckGo search error: ${res.status}`);
15751
+ throw new SearchProviderError(`DuckDuckGo search error: ${res.status}`, res.status, "duckduckgo");
15559
15752
  }
15560
15753
  const html = await res.text();
15561
15754
  const results = [];
@@ -15607,6 +15800,12 @@ function createWebSearchHandler(provider) {
15607
15800
  ${formatted}`;
15608
15801
  return { ok: true, data: output.slice(0, MAX_RESULT_SIZE) };
15609
15802
  } catch (err3) {
15803
+ if (err3 instanceof SearchProviderError) {
15804
+ return {
15805
+ ok: false,
15806
+ error: `Search provider error (${err3.provider}, HTTP ${err3.status}): ${err3.message}`
15807
+ };
15808
+ }
15610
15809
  const msg = err3 instanceof Error ? err3.message : String(err3);
15611
15810
  return { ok: false, error: `Search error: ${msg}` };
15612
15811
  }
@@ -15617,6 +15816,7 @@ var init_web_search = __esm({
15617
15816
  "../../packages/tools/dist/builtins/web-search.js"() {
15618
15817
  "use strict";
15619
15818
  init_esm_shims();
15819
+ init_search_provider();
15620
15820
  init_duckduckgo();
15621
15821
  webSearchDefinition = {
15622
15822
  name: "web_search",
@@ -16290,39 +16490,13 @@ var init_builtins = __esm({
16290
16490
  }
16291
16491
  });
16292
16492
 
16293
- // ../../packages/tools/dist/search-provider.js
16294
- var FallbackSearchProvider;
16295
- var init_search_provider = __esm({
16296
- "../../packages/tools/dist/search-provider.js"() {
16297
- "use strict";
16298
- init_esm_shims();
16299
- FallbackSearchProvider = class {
16300
- providers;
16301
- constructor(providers) {
16302
- this.providers = providers;
16303
- }
16304
- async search(query, maxResults) {
16305
- for (const provider of this.providers) {
16306
- try {
16307
- const results = await provider.search(query, maxResults);
16308
- if (results.length > 0)
16309
- return results;
16310
- } catch {
16311
- continue;
16312
- }
16313
- }
16314
- return [];
16315
- }
16316
- };
16317
- }
16318
- });
16319
-
16320
16493
  // ../../packages/tools/dist/providers/brave-search.js
16321
16494
  var BraveSearchProvider;
16322
16495
  var init_brave_search = __esm({
16323
16496
  "../../packages/tools/dist/providers/brave-search.js"() {
16324
16497
  "use strict";
16325
16498
  init_esm_shims();
16499
+ init_search_provider();
16326
16500
  BraveSearchProvider = class {
16327
16501
  apiKey;
16328
16502
  constructor(apiKey) {
@@ -16338,7 +16512,12 @@ var init_brave_search = __esm({
16338
16512
  }
16339
16513
  });
16340
16514
  if (!res.ok) {
16341
- throw new Error(`Brave Search API error: ${res.status}`);
16515
+ let body = "";
16516
+ try {
16517
+ body = await res.text();
16518
+ } catch {
16519
+ }
16520
+ throw new SearchProviderError(`Brave Search API error: ${res.status}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`, res.status, "brave");
16342
16521
  }
16343
16522
  const data = await res.json();
16344
16523
  const webResults = data.web?.results ?? [];
@@ -16633,20 +16812,17 @@ async function createRuntime(config, motebitId, toolRegistry, mcpServers, person
16633
16812
  tools: toolRegistry
16634
16813
  }
16635
16814
  );
16636
- const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"] ?? loadFullConfig().sync_url;
16815
+ const DEFAULT_SYNC_URL2 = "https://motebit-sync.fly.dev";
16816
+ const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"] ?? loadFullConfig().sync_url ?? DEFAULT_SYNC_URL2;
16637
16817
  const syncToken = config.syncToken ?? process.env["MOTEBIT_SYNC_TOKEN"];
16638
- if (syncUrl != null && syncUrl !== "") {
16639
- const httpAdapter = new HttpEventStoreAdapter({
16640
- baseUrl: syncUrl,
16641
- motebitId,
16642
- authToken: syncToken
16643
- });
16644
- const remoteStore = encKey ? new EncryptedEventStoreAdapter({ inner: httpAdapter, key: encKey }) : httpAdapter;
16645
- runtime.connectSync(remoteStore);
16646
- console.log(dim(`Sync: ${syncUrl}${encKey ? " (encrypted)" : ""}`));
16647
- } else {
16648
- console.log(dim("Sync: disabled (set MOTEBIT_SYNC_URL to enable)"));
16649
- }
16818
+ const httpAdapter = new HttpEventStoreAdapter({
16819
+ baseUrl: syncUrl,
16820
+ motebitId,
16821
+ authToken: syncToken
16822
+ });
16823
+ const remoteStore = encKey ? new EncryptedEventStoreAdapter({ inner: httpAdapter, key: encKey }) : httpAdapter;
16824
+ runtime.connectSync(remoteStore);
16825
+ console.log(dim(`Sync: ${syncUrl}${encKey ? " (encrypted)" : ""}`));
16650
16826
  return { runtime, moteDb };
16651
16827
  }
16652
16828
  var SqliteConversationSyncStoreAdapter, SqlitePlanSyncStoreAdapter;
@@ -16805,7 +16981,6 @@ init_dist3();
16805
16981
  init_dist4();
16806
16982
  init_dist5();
16807
16983
  init_dist3();
16808
- import * as readline3 from "readline";
16809
16984
 
16810
16985
  // src/args.ts
16811
16986
  init_esm_shims();
@@ -16857,7 +17032,7 @@ function parseCliArgs(args = process.argv.slice(2)) {
16857
17032
  `Unknown provider "${provider}". Use "anthropic", "openai", "ollama", or "hybrid".`
16858
17033
  );
16859
17034
  }
16860
- const defaultModel = provider === "ollama" ? "llama3.2" : provider === "openai" ? "gpt-4o" : "claude-sonnet-4-5-latest";
17035
+ const defaultModel = provider === "ollama" ? "llama3.2" : provider === "openai" ? "gpt-4o-mini" : "claude-sonnet-4-6";
16861
17036
  const allowedPaths = values["allowed-paths"] != null && values["allowed-paths"] !== "" ? values["allowed-paths"].split(",").map((p) => p.trim()) : [process.cwd()];
16862
17037
  return {
16863
17038
  provider,
@@ -17003,9 +17178,9 @@ Options:
17003
17178
 
17004
17179
  Providers:
17005
17180
  anthropic Uses Anthropic API (requires ANTHROPIC_API_KEY)
17006
- Default model: claude-sonnet-4-5-latest
17181
+ Default model: claude-sonnet-4-6
17007
17182
  openai Uses OpenAI API (requires OPENAI_API_KEY)
17008
- Default model: gpt-4o
17183
+ Default model: gpt-4o-mini
17009
17184
  ollama Uses local Ollama server (no API key needed)
17010
17185
  Default model: llama3.2
17011
17186
  hybrid Anthropic with Ollama fallback (requires ANTHROPIC_API_KEY)
@@ -17236,24 +17411,362 @@ init_runtime_factory();
17236
17411
  init_esm_shims();
17237
17412
  init_dist3();
17238
17413
  init_colors();
17239
- function rlQuestion(rl, prompt2) {
17414
+
17415
+ // src/terminal.ts
17416
+ init_esm_shims();
17417
+ function visibleLength(s) {
17418
+ return s.replace(/\x1b\[[0-9;]*[a-zA-Z~]/g, "").length;
17419
+ }
17420
+ var PASTE_OPEN = "\x1B[200~";
17421
+ var PASTE_CLOSE = "\x1B[201~";
17422
+ var initialized = false;
17423
+ var inputActive = false;
17424
+ var inputState = { line: "", cursor: 0, prompt: "", promptWidth: 0 };
17425
+ var inputResolver = null;
17426
+ var lastEscTime = 0;
17427
+ var pendingEscTimer = null;
17428
+ var pasteBuffer = null;
17429
+ var pasteSplitCarry = "";
17430
+ var inputRows = 0;
17431
+ function parseChunk(buf) {
17432
+ const events = [];
17433
+ let data = buf.toString("utf-8");
17434
+ if (pasteSplitCarry.length > 0) {
17435
+ data = pasteSplitCarry + data;
17436
+ pasteSplitCarry = "";
17437
+ }
17438
+ let i = 0;
17439
+ while (i < data.length) {
17440
+ const ch = data[i];
17441
+ if (pasteBuffer !== null) {
17442
+ const closeIdx = data.indexOf(PASTE_CLOSE, i);
17443
+ if (closeIdx === -1) {
17444
+ const remaining = data.slice(i);
17445
+ let overlap = 0;
17446
+ for (let k = 1; k < PASTE_CLOSE.length && k <= remaining.length; k++) {
17447
+ if (remaining.slice(remaining.length - k) === PASTE_CLOSE.slice(0, k)) {
17448
+ overlap = k;
17449
+ }
17450
+ }
17451
+ pasteBuffer += remaining.slice(0, remaining.length - overlap);
17452
+ pasteSplitCarry = overlap > 0 ? remaining.slice(remaining.length - overlap) : "";
17453
+ i = data.length;
17454
+ } else {
17455
+ pasteBuffer += data.slice(i, closeIdx);
17456
+ const text = pasteBuffer.replace(/[\r\n]+/g, " ");
17457
+ events.push({ type: "paste", text });
17458
+ pasteBuffer = null;
17459
+ pasteSplitCarry = "";
17460
+ i = closeIdx + PASTE_CLOSE.length;
17461
+ }
17462
+ continue;
17463
+ }
17464
+ if (data.startsWith(PASTE_OPEN, i)) {
17465
+ pasteBuffer = "";
17466
+ i += PASTE_OPEN.length;
17467
+ continue;
17468
+ }
17469
+ if (ch === "\x1B") {
17470
+ if (i + 1 < data.length && data[i + 1] === "[") {
17471
+ let j = i + 2;
17472
+ while (j < data.length && !/[a-zA-Z~]/.test(data[j])) j++;
17473
+ if (j < data.length) {
17474
+ const seq = data.slice(i + 2, j + 1);
17475
+ i = j + 1;
17476
+ switch (seq) {
17477
+ case "A":
17478
+ events.push({ type: "key", key: "up", ctrl: false });
17479
+ break;
17480
+ case "B":
17481
+ events.push({ type: "key", key: "down", ctrl: false });
17482
+ break;
17483
+ case "C":
17484
+ events.push({ type: "key", key: "right", ctrl: false });
17485
+ break;
17486
+ case "D":
17487
+ events.push({ type: "key", key: "left", ctrl: false });
17488
+ break;
17489
+ case "H":
17490
+ case "1~":
17491
+ events.push({ type: "key", key: "home", ctrl: false });
17492
+ break;
17493
+ case "F":
17494
+ case "4~":
17495
+ events.push({ type: "key", key: "end", ctrl: false });
17496
+ break;
17497
+ case "3~":
17498
+ events.push({ type: "key", key: "delete", ctrl: false });
17499
+ break;
17500
+ }
17501
+ } else {
17502
+ i = data.length;
17503
+ }
17504
+ } else if (i + 1 >= data.length) {
17505
+ if (pendingEscTimer) clearTimeout(pendingEscTimer);
17506
+ pendingEscTimer = setTimeout(() => {
17507
+ pendingEscTimer = null;
17508
+ handleBareEscape();
17509
+ }, 50);
17510
+ i++;
17511
+ } else {
17512
+ handleBareEscape();
17513
+ i++;
17514
+ }
17515
+ continue;
17516
+ }
17517
+ const code2 = ch.charCodeAt(0);
17518
+ if (code2 === 3) {
17519
+ events.push({ type: "key", key: "c", ctrl: true });
17520
+ } else if (code2 === 1) {
17521
+ events.push({ type: "key", key: "home", ctrl: false });
17522
+ } else if (code2 === 5) {
17523
+ events.push({ type: "key", key: "end", ctrl: false });
17524
+ } else if (code2 === 127 || code2 === 8) {
17525
+ events.push({ type: "key", key: "backspace", ctrl: false });
17526
+ } else if (code2 === 13) {
17527
+ events.push({ type: "key", key: "return", ctrl: false });
17528
+ } else if (code2 === 21) {
17529
+ events.push({ type: "key", key: "u", ctrl: true });
17530
+ } else if (code2 >= 32) {
17531
+ events.push({ type: "key", key: ch, ctrl: false });
17532
+ }
17533
+ i++;
17534
+ }
17535
+ return events;
17536
+ }
17537
+ function handleBareEscape() {
17538
+ if (!inputActive) return;
17539
+ const now = Date.now();
17540
+ if (now - lastEscTime < 300) {
17541
+ lastEscTime = 0;
17542
+ inputState = { ...inputState, line: "", cursor: 0 };
17543
+ redrawInput();
17544
+ } else {
17545
+ lastEscTime = now;
17546
+ }
17547
+ }
17548
+ function applyEvent(state, event) {
17549
+ switch (event.type) {
17550
+ case "key": {
17551
+ if (event.ctrl) {
17552
+ if (event.key === "c") return "exit";
17553
+ if (event.key === "u") return { state: { ...state, line: "", cursor: 0 } };
17554
+ return { state };
17555
+ }
17556
+ switch (event.key) {
17557
+ case "return":
17558
+ return "submit";
17559
+ case "backspace":
17560
+ if (state.cursor > 0) {
17561
+ return {
17562
+ state: {
17563
+ ...state,
17564
+ line: state.line.slice(0, state.cursor - 1) + state.line.slice(state.cursor),
17565
+ cursor: state.cursor - 1
17566
+ }
17567
+ };
17568
+ }
17569
+ return { state };
17570
+ case "delete":
17571
+ if (state.cursor < state.line.length) {
17572
+ return {
17573
+ state: {
17574
+ ...state,
17575
+ line: state.line.slice(0, state.cursor) + state.line.slice(state.cursor + 1)
17576
+ }
17577
+ };
17578
+ }
17579
+ return { state };
17580
+ case "left":
17581
+ return { state: { ...state, cursor: Math.max(0, state.cursor - 1) } };
17582
+ case "right":
17583
+ return { state: { ...state, cursor: Math.min(state.line.length, state.cursor + 1) } };
17584
+ case "home":
17585
+ return { state: { ...state, cursor: 0 } };
17586
+ case "end":
17587
+ return { state: { ...state, cursor: state.line.length } };
17588
+ case "up":
17589
+ case "down":
17590
+ return { state };
17591
+ // No history (yet)
17592
+ default:
17593
+ if (event.key.length === 1) {
17594
+ return {
17595
+ state: {
17596
+ ...state,
17597
+ line: state.line.slice(0, state.cursor) + event.key + state.line.slice(state.cursor),
17598
+ cursor: state.cursor + 1
17599
+ }
17600
+ };
17601
+ }
17602
+ return { state };
17603
+ }
17604
+ }
17605
+ case "paste": {
17606
+ return {
17607
+ state: {
17608
+ ...state,
17609
+ line: state.line.slice(0, state.cursor) + event.text + state.line.slice(state.cursor),
17610
+ cursor: state.cursor + event.text.length
17611
+ }
17612
+ };
17613
+ }
17614
+ case "resize":
17615
+ return { state };
17616
+ }
17617
+ }
17618
+ function redrawInput() {
17619
+ const cols = process.stdout.columns || 80;
17620
+ const fullLine = inputState.prompt + inputState.line;
17621
+ const totalLen = inputState.promptWidth + inputState.line.length;
17622
+ const newRows = Math.max(1, Math.ceil(totalLen / cols) || 1);
17623
+ if (inputRows > 1) {
17624
+ process.stdout.write(`\x1B[${inputRows - 1}A`);
17625
+ }
17626
+ process.stdout.write("\r");
17627
+ process.stdout.write("\x1B[J");
17628
+ process.stdout.write(fullLine);
17629
+ const cursorPos = inputState.promptWidth + inputState.cursor;
17630
+ const cursorRow = Math.floor(cursorPos / cols);
17631
+ const cursorCol = cursorPos % cols;
17632
+ const endRow = Math.floor(Math.max(0, totalLen - 1) / cols);
17633
+ if (endRow > cursorRow) {
17634
+ process.stdout.write(`\x1B[${endRow - cursorRow}A`);
17635
+ }
17636
+ process.stdout.write(`\r`);
17637
+ if (cursorCol > 0) {
17638
+ process.stdout.write(`\x1B[${cursorCol}C`);
17639
+ }
17640
+ inputRows = newRows;
17641
+ }
17642
+ function writeOutput(text) {
17643
+ if (!inputActive) {
17644
+ process.stdout.write(text);
17645
+ return;
17646
+ }
17647
+ if (inputRows > 1) {
17648
+ process.stdout.write(`\x1B[${inputRows - 1}A`);
17649
+ }
17650
+ process.stdout.write("\r\x1B[J");
17651
+ process.stdout.write(text);
17652
+ inputRows = 1;
17653
+ redrawInput();
17654
+ }
17655
+ function onStdinData(buf) {
17656
+ const events = parseChunk(buf);
17657
+ for (const event of events) {
17658
+ if (!inputActive) continue;
17659
+ if (event.type === "resize") {
17660
+ redrawInput();
17661
+ continue;
17662
+ }
17663
+ const result = applyEvent(inputState, event);
17664
+ if (result === "submit") {
17665
+ const line = inputState.line;
17666
+ process.stdout.write("\n");
17667
+ inputActive = false;
17668
+ inputRows = 0;
17669
+ if (inputResolver) {
17670
+ const resolve7 = inputResolver;
17671
+ inputResolver = null;
17672
+ resolve7(line);
17673
+ }
17674
+ } else if (result === "exit") {
17675
+ process.stdout.write("\n");
17676
+ process.exit(0);
17677
+ } else {
17678
+ inputState = result.state;
17679
+ redrawInput();
17680
+ }
17681
+ }
17682
+ }
17683
+ var resizeTimer = null;
17684
+ function onResize() {
17685
+ if (!inputActive) return;
17686
+ if (resizeTimer) clearTimeout(resizeTimer);
17687
+ resizeTimer = setTimeout(() => {
17688
+ resizeTimer = null;
17689
+ if (!inputActive) return;
17690
+ process.stdout.write("\n");
17691
+ inputRows = 1;
17692
+ redrawInput();
17693
+ }, 100);
17694
+ }
17695
+ function initTerminal() {
17696
+ if (initialized) return;
17697
+ initialized = true;
17698
+ if (process.stdin.isTTY) {
17699
+ process.stdin.setRawMode(true);
17700
+ }
17701
+ process.stdin.resume();
17702
+ process.stdin.on("data", onStdinData);
17703
+ process.stdout.on("resize", onResize);
17704
+ if (process.stdout.isTTY) {
17705
+ process.stdout.write("\x1B[?2004h");
17706
+ }
17707
+ }
17708
+ function destroyTerminal() {
17709
+ if (!initialized) return;
17710
+ initialized = false;
17711
+ process.stdin.removeListener("data", onStdinData);
17712
+ process.stdout.removeListener("resize", onResize);
17713
+ if (process.stdin.isTTY) {
17714
+ process.stdin.setRawMode(false);
17715
+ }
17716
+ if (process.stdout.isTTY) {
17717
+ process.stdout.write("\x1B[?2004l");
17718
+ }
17719
+ }
17720
+ function readInput(promptText) {
17240
17721
  return new Promise((resolve7) => {
17241
- rl.question(prompt2, (answer) => resolve7(answer));
17722
+ inputState = {
17723
+ line: "",
17724
+ cursor: 0,
17725
+ prompt: promptText,
17726
+ promptWidth: visibleLength(promptText)
17727
+ };
17728
+ inputRows = 1;
17729
+ inputActive = true;
17730
+ inputResolver = resolve7;
17731
+ redrawInput();
17242
17732
  });
17243
17733
  }
17244
- async function consumeStream(stream, runtime, rl) {
17734
+ function askQuestion(promptText) {
17735
+ return readInput(promptText);
17736
+ }
17737
+
17738
+ // src/stream.ts
17739
+ function startDotAnimation() {
17740
+ let dots = 1;
17741
+ const timer = setInterval(() => {
17742
+ dots = dots % 3 + 1;
17743
+ writeOutput(`\x1B[${3}D${meta(".".repeat(dots) + " ".repeat(3 - dots))}`);
17744
+ }, 400);
17745
+ return () => {
17746
+ clearInterval(timer);
17747
+ writeOutput(`\x1B[${3}D${meta("...")} ${meta("done")}
17748
+ `);
17749
+ };
17750
+ }
17751
+ async function consumeStream(stream, runtime) {
17245
17752
  let pendingApproval = null;
17753
+ let stopAnimation = null;
17246
17754
  for await (const chunk of stream) {
17247
17755
  switch (chunk.type) {
17248
17756
  case "text":
17249
- process.stdout.write(chunk.text);
17757
+ writeOutput(chunk.text);
17250
17758
  break;
17251
17759
  case "tool_status":
17760
+ if (chunk.name === "delegate_to_agent") break;
17252
17761
  if (chunk.status === "calling") {
17253
- process.stdout.write(`
17762
+ writeOutput(`
17254
17763
  ${action("\u25CF")} ${action(chunk.name)}${meta("...")}`);
17764
+ stopAnimation = startDotAnimation();
17255
17765
  } else {
17256
- process.stdout.write(meta(" done") + "\n");
17766
+ if (stopAnimation) {
17767
+ stopAnimation();
17768
+ stopAnimation = null;
17769
+ } else writeOutput(meta(" done") + "\n");
17257
17770
  }
17258
17771
  break;
17259
17772
  case "approval_request":
@@ -17265,40 +17778,42 @@ async function consumeStream(stream, runtime, rl) {
17265
17778
  };
17266
17779
  break;
17267
17780
  case "delegation_start":
17268
- process.stdout.write(
17781
+ writeOutput(
17269
17782
  `
17270
17783
  ${action("\u25CF")} ${dim("[delegating]")} ${action(chunk.tool)}${meta("...")}`
17271
17784
  );
17785
+ stopAnimation = startDotAnimation();
17272
17786
  break;
17273
17787
  case "delegation_complete":
17274
- process.stdout.write(meta(" done") + "\n");
17788
+ if (stopAnimation) {
17789
+ stopAnimation();
17790
+ stopAnimation = null;
17791
+ } else writeOutput(meta(" done") + "\n");
17275
17792
  break;
17276
17793
  case "injection_warning":
17277
- process.stdout.write(
17278
- `
17794
+ writeOutput(`
17279
17795
  ${warn("\u26A0")} ${warn("suspicious content in " + chunk.tool_name)}
17280
- `
17281
- );
17796
+ `);
17282
17797
  break;
17283
17798
  case "result": {
17284
17799
  const result = chunk.result;
17285
- console.log("\n");
17800
+ writeOutput("\n\n");
17286
17801
  if (result.memoriesFormed.length > 0) {
17287
- console.log(
17802
+ writeOutput(
17288
17803
  meta(
17289
17804
  ` [memories: ${result.memoriesFormed.map((m) => m.content).join(", ")}]`
17290
- )
17805
+ ) + "\n"
17291
17806
  );
17292
17807
  }
17293
17808
  const s = result.stateAfter;
17294
- console.log(
17809
+ writeOutput(
17295
17810
  meta(
17296
17811
  ` [state: attention=${s.attention.toFixed(2)} confidence=${s.confidence.toFixed(2)} valence=${s.affect_valence.toFixed(2)} curiosity=${s.curiosity.toFixed(2)}]`
17297
- )
17812
+ ) + "\n"
17298
17813
  );
17299
17814
  const bodyLine = formatBodyAwareness(result.cues);
17300
- if (bodyLine) console.log(meta(` ${bodyLine}`));
17301
- console.log();
17815
+ if (bodyLine) writeOutput(meta(` ${bodyLine}`) + "\n");
17816
+ writeOutput("\n");
17302
17817
  break;
17303
17818
  }
17304
17819
  }
@@ -17306,149 +17821,16 @@ async function consumeStream(stream, runtime, rl) {
17306
17821
  if (pendingApproval) {
17307
17822
  const argsPreview = JSON.stringify(pendingApproval.args).slice(0, 80);
17308
17823
  const quorumInfo = pendingApproval.quorum && pendingApproval.quorum.required > 1 ? ` [${pendingApproval.quorum.collected.length}/${pendingApproval.quorum.required} approvals]` : "";
17309
- const answer = await rlQuestion(
17310
- rl,
17824
+ const answer = await askQuestion(
17311
17825
  ` ${warn("?")} ${pendingApproval.name}(${argsPreview})${quorumInfo}
17312
17826
  Allow? (y/n) `
17313
17827
  );
17314
17828
  const approved = answer.trim().toLowerCase() === "y";
17315
- process.stdout.write("\n" + prompt("mote>") + " ");
17316
- await consumeStream(runtime.resolveApprovalVote(approved, runtime.motebitId), runtime, rl);
17829
+ writeOutput("\n" + prompt("mote>") + " ");
17830
+ await consumeStream(runtime.resolveApprovalVote(approved, runtime.motebitId), runtime);
17317
17831
  }
17318
17832
  }
17319
17833
 
17320
- // src/input.ts
17321
- init_esm_shims();
17322
- init_colors();
17323
- function visibleLength(s) {
17324
- return s.replace(/\x1b\[[0-9;]*m/g, "").length;
17325
- }
17326
- var PASTE_OPEN = "\x1B[200~";
17327
- var PASTE_CLOSE = "\x1B[201~";
17328
- function enableBracketedPaste() {
17329
- if (process.stdout.isTTY) {
17330
- process.stdout.write("\x1B[?2004h");
17331
- }
17332
- }
17333
- function disableBracketedPaste() {
17334
- if (process.stdout.isTTY) {
17335
- process.stdout.write("\x1B[?2004l");
17336
- }
17337
- }
17338
- function readInput(promptText) {
17339
- return new Promise((resolve7) => {
17340
- const stdin = process.stdin;
17341
- const stdout = process.stdout;
17342
- stdin.setRawMode(true);
17343
- stdin.resume();
17344
- stdin.setEncoding("utf8");
17345
- process.stdout.write(promptText);
17346
- let value = "";
17347
- let pasteBuffer = "";
17348
- let inPaste = false;
17349
- let pasteLineCount = 0;
17350
- let lastEscTime = 0;
17351
- const promptVisibleLen = visibleLength(promptText);
17352
- let lastDisplayLen = 0;
17353
- const redrawLine = (text) => {
17354
- const cols = stdout.columns || 80;
17355
- const prevTotal = promptVisibleLen + lastDisplayLen;
17356
- const wrappedLines = Math.max(0, Math.ceil(prevTotal / cols) - 1);
17357
- if (wrappedLines > 0) {
17358
- stdout.write(`\x1B[${wrappedLines}A`);
17359
- }
17360
- stdout.write(`\r\x1B[J${promptText}${text}`);
17361
- lastDisplayLen = visibleLength(text);
17362
- };
17363
- const finish = () => {
17364
- stdin.removeListener("data", onData);
17365
- stdin.setRawMode(false);
17366
- stdin.pause();
17367
- stdout.write("\n");
17368
- if (pasteBuffer) {
17369
- resolve7(pasteBuffer.replace(/\r?\n/g, " ").trim());
17370
- } else {
17371
- resolve7(value);
17372
- }
17373
- };
17374
- const onData = (ch) => {
17375
- const data = ch.toString();
17376
- if (data.includes(PASTE_OPEN)) {
17377
- inPaste = true;
17378
- pasteBuffer = value;
17379
- pasteLineCount = 0;
17380
- const afterOpen = data.slice(data.indexOf(PASTE_OPEN) + PASTE_OPEN.length);
17381
- if (afterOpen) {
17382
- processPasteData(afterOpen);
17383
- }
17384
- return;
17385
- }
17386
- if (inPaste) {
17387
- processPasteData(data);
17388
- return;
17389
- }
17390
- for (let i = 0; i < data.length; i++) {
17391
- const c = data[i];
17392
- if (c === "\r" || c === "\n") {
17393
- finish();
17394
- return;
17395
- } else if (c === "") {
17396
- stdin.removeListener("data", onData);
17397
- stdin.setRawMode(false);
17398
- stdout.write("\n");
17399
- resolve7("");
17400
- return;
17401
- } else if (c === "\x7F" || c === "\b") {
17402
- if (value.length > 0) {
17403
- value = value.slice(0, -1);
17404
- redrawLine(value);
17405
- }
17406
- } else if (c === "\x1B") {
17407
- const now = Date.now();
17408
- if (now - lastEscTime < 300) {
17409
- value = "";
17410
- pasteBuffer = "";
17411
- redrawLine("");
17412
- lastEscTime = 0;
17413
- } else {
17414
- lastEscTime = now;
17415
- }
17416
- return;
17417
- } else if (c.charCodeAt(0) >= 32) {
17418
- value += c;
17419
- stdout.write(c);
17420
- lastDisplayLen = value.length;
17421
- }
17422
- }
17423
- };
17424
- const processPasteData = (data) => {
17425
- const closeIdx = data.indexOf(PASTE_CLOSE);
17426
- if (closeIdx !== -1) {
17427
- const remaining = data.slice(0, closeIdx);
17428
- pasteBuffer += remaining;
17429
- pasteLineCount += (remaining.match(/\n/g) || []).length;
17430
- inPaste = false;
17431
- const charCount = pasteBuffer.length;
17432
- const summary = pasteLineCount > 0 ? dim(`[Pasted text #${charCount} +${pasteLineCount} lines]`) : pasteBuffer;
17433
- redrawLine(pasteLineCount > 0 ? summary : pasteBuffer);
17434
- if (pasteLineCount === 0) {
17435
- value = pasteBuffer;
17436
- pasteBuffer = "";
17437
- }
17438
- return;
17439
- }
17440
- pasteBuffer += data;
17441
- pasteLineCount += (data.match(/\n/g) || []).length;
17442
- if (pasteLineCount > 0) {
17443
- const charCount = pasteBuffer.length;
17444
- const summary = dim(`[Pasted text #${charCount} +${pasteLineCount} lines]`);
17445
- redrawLine(summary);
17446
- }
17447
- };
17448
- stdin.on("data", onData);
17449
- });
17450
- }
17451
-
17452
17834
  // src/index.ts
17453
17835
  init_colors();
17454
17836
 
@@ -21749,6 +22131,11 @@ var McpServerAdapter = class _McpServerAdapter {
21749
22131
  deps;
21750
22132
  httpServer;
21751
22133
  lastVerifiedCaller = null;
22134
+ /**
22135
+ * Hook for relay re-registration on health checks. Set by startServiceServer
22136
+ * to close the stale-registration window when platforms freeze/resume processes.
22137
+ */
22138
+ ensureRegistered;
21752
22139
  constructor(config, deps) {
21753
22140
  this.config = config;
21754
22141
  this.deps = deps;
@@ -22082,9 +22469,6 @@ var McpServerAdapter = class _McpServerAdapter {
22082
22469
  isError: true
22083
22470
  };
22084
22471
  }
22085
- if (delegatedScope) {
22086
- receipt.delegated_scope = delegatedScope;
22087
- }
22088
22472
  this.deps.logToolCall("motebit_task", args, { ok: true, data: receipt });
22089
22473
  return fmt(receipt);
22090
22474
  }
@@ -22309,6 +22693,9 @@ var McpServerAdapter = class _McpServerAdapter {
22309
22693
  return;
22310
22694
  }
22311
22695
  if (url.pathname === "/health" && req.method === "GET") {
22696
+ if (this.ensureRegistered) {
22697
+ void this.ensureRegistered();
22698
+ }
22312
22699
  res.writeHead(200, { "Content-Type": "application/json" });
22313
22700
  res.end(JSON.stringify({
22314
22701
  status: "ok",
@@ -22920,7 +23307,7 @@ Unknown model: ${cyan(args)}
22920
23307
  const mid = repl.motebitId;
22921
23308
  runtime.enableInteractiveDelegation({
22922
23309
  syncUrl: connectUrl,
22923
- authToken: async () => {
23310
+ authToken: async (audience = "task:submit") => {
22924
23311
  const now = Date.now();
22925
23312
  return createSignedToken(
22926
23313
  {
@@ -22929,7 +23316,7 @@ Unknown model: ${cyan(args)}
22929
23316
  iat: now,
22930
23317
  exp: now + 5 * 60 * 1e3,
22931
23318
  jti: crypto.randomUUID(),
22932
- aud: "task:submit"
23319
+ aud: audience
22933
23320
  },
22934
23321
  pk
22935
23322
  );
@@ -27822,19 +28209,19 @@ var GoalScheduler = class _GoalScheduler {
27822
28209
  }
27823
28210
  switch (chunk.type) {
27824
28211
  case "text":
27825
- process.stdout.write(chunk.text);
28212
+ writeOutput(chunk.text);
27826
28213
  responseText += chunk.text;
27827
28214
  break;
27828
28215
  case "tool_status":
27829
28216
  if (chunk.status === "calling") {
27830
- process.stdout.write(`
28217
+ writeOutput(`
27831
28218
  [tool] ${chunk.name}...`);
27832
28219
  toolCallsMade++;
27833
28220
  if (toolCallsMade > MAX_TOOL_CALLS_PER_RUN) {
27834
28221
  throw new Error(`Goal exceeded ${MAX_TOOL_CALLS_PER_RUN} tool calls \u2014 run stopped`);
27835
28222
  }
27836
28223
  } else {
27837
- process.stdout.write(" done\n");
28224
+ writeOutput(" done\n");
27838
28225
  }
27839
28226
  break;
27840
28227
  case "approval_request": {
@@ -27951,18 +28338,18 @@ var GoalScheduler = class _GoalScheduler {
27951
28338
  break;
27952
28339
  case "step_chunk":
27953
28340
  if (chunk.chunk.type === "text") {
27954
- process.stdout.write(chunk.chunk.text);
28341
+ writeOutput(chunk.chunk.text);
27955
28342
  responseText += chunk.chunk.text;
27956
28343
  } else if (chunk.chunk.type === "tool_status") {
27957
28344
  if (chunk.chunk.status === "calling") {
27958
- process.stdout.write(`
28345
+ writeOutput(`
27959
28346
  [tool] ${chunk.chunk.name}...`);
27960
28347
  toolCallsMade++;
27961
28348
  if (toolCallsMade > MAX_TOOL_CALLS_PER_RUN) {
27962
28349
  throw new Error(`Goal exceeded ${MAX_TOOL_CALLS_PER_RUN} tool calls \u2014 run stopped`);
27963
28350
  }
27964
28351
  } else {
27965
- process.stdout.write(" done\n");
28352
+ writeOutput(" done\n");
27966
28353
  }
27967
28354
  } else if (chunk.chunk.type === "injection_warning") {
27968
28355
  console.warn(`
@@ -28470,7 +28857,7 @@ Agent task received: ${task.task_id.slice(0, 8)}... prompt: "${task.prompt.slice
28470
28857
  wsAdapter.connect();
28471
28858
  if (privKeyBytes) {
28472
28859
  const privateKeyForDelegation = privKeyBytes;
28473
- const tokenFactory = async () => {
28860
+ const tokenFactory = async (audience = "task:submit") => {
28474
28861
  if (!fullConfig.device_id) return syncToken ?? "";
28475
28862
  try {
28476
28863
  return await createSignedToken(
@@ -28480,7 +28867,7 @@ Agent task received: ${task.task_id.slice(0, 8)}... prompt: "${task.prompt.slice
28480
28867
  iat: Date.now(),
28481
28868
  exp: Date.now() + 5 * 60 * 1e3,
28482
28869
  jti: crypto.randomUUID(),
28483
- aud: "task:submit"
28870
+ aud: audience
28484
28871
  },
28485
28872
  privateKeyForDelegation
28486
28873
  );
@@ -29001,10 +29388,32 @@ async function handleServe(config) {
29001
29388
  try {
29002
29389
  await new Promise((r) => setTimeout(r, 500));
29003
29390
  const firstToolName = toolNames[toolNames.length - 1] ?? "echo";
29004
- log("[self-test] submitting task via relay...");
29391
+ const mintToken = async (audience) => {
29392
+ if (servePrivateKey && fullConfigForServe.device_id) {
29393
+ return createSignedToken(
29394
+ {
29395
+ mid: motebitId,
29396
+ did: fullConfigForServe.device_id,
29397
+ iat: Date.now(),
29398
+ exp: Date.now() + 5 * 60 * 1e3,
29399
+ jti: crypto.randomUUID(),
29400
+ aud: audience
29401
+ },
29402
+ servePrivateKey
29403
+ );
29404
+ }
29405
+ return masterToken ?? "";
29406
+ };
29407
+ const submitToken = await mintToken("task:submit");
29408
+ const queryToken = await mintToken("task:query");
29409
+ const authMethod = servePrivateKey && fullConfigForServe.device_id ? "device token" : "master token";
29410
+ log(`[self-test] submitting task via relay (auth: ${authMethod})...`);
29005
29411
  const taskResp = await fetch(`${syncUrl}/agent/${motebitId}/task`, {
29006
29412
  method: "POST",
29007
- headers: regHeaders,
29413
+ headers: {
29414
+ "Content-Type": "application/json",
29415
+ Authorization: `Bearer ${submitToken}`
29416
+ },
29008
29417
  body: JSON.stringify({
29009
29418
  prompt: "self-test",
29010
29419
  submitted_by: motebitId,
@@ -29018,6 +29427,8 @@ async function handleServe(config) {
29018
29427
  `[self-test] failed \u2014 relay returned ${status}${body ? `: ${body.slice(0, 100)}` : ""}`
29019
29428
  );
29020
29429
  if (status === 402) log("[self-test] hint: fund the agent's budget on the relay");
29430
+ if (status === 401 || status === 403)
29431
+ log("[self-test] hint: device may not be registered with relay");
29021
29432
  return;
29022
29433
  }
29023
29434
  const taskData = await taskResp.json();
@@ -29032,7 +29443,7 @@ async function handleServe(config) {
29032
29443
  while (Date.now() < deadline) {
29033
29444
  await new Promise((r) => setTimeout(r, 2e3));
29034
29445
  const pollResp = await fetch(`${syncUrl}/agent/${motebitId}/task/${taskId}`, {
29035
- headers: regHeaders
29446
+ headers: { Authorization: `Bearer ${queryToken}` }
29036
29447
  });
29037
29448
  if (!pollResp.ok) continue;
29038
29449
  const pollData = await pollResp.json();
@@ -29290,6 +29701,8 @@ async function main() {
29290
29701
  saveFullConfig2(fullConfig);
29291
29702
  console.log(dim(" Encrypted. Plaintext removed."));
29292
29703
  } else {
29704
+ console.log();
29705
+ console.log(` ${bold("Welcome to Motebit.")}`);
29293
29706
  console.log();
29294
29707
  console.log(dim(" ."));
29295
29708
  console.log(dim(" .:::."));
@@ -29319,18 +29732,7 @@ async function main() {
29319
29732
  }
29320
29733
  }
29321
29734
  }
29322
- enableBracketedPaste();
29323
- let rl = null;
29324
- const getOrCreateRl = () => {
29325
- if (!rl) {
29326
- rl = readline3.createInterface({
29327
- input: process.stdin,
29328
- output: process.stdout,
29329
- escapeCodeTimeout: 50
29330
- });
29331
- }
29332
- return rl;
29333
- };
29735
+ initTerminal();
29334
29736
  const dbPath = getDbPath(config.dbPath);
29335
29737
  const tempDb = await openMotebitDatabase(dbPath);
29336
29738
  const { motebitId, isFirstLaunch } = await bootstrapIdentity2(tempDb, fullConfig, passphrase);
@@ -29388,31 +29790,9 @@ async function main() {
29388
29790
  }
29389
29791
  }
29390
29792
  await runtime.init();
29391
- const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"] ?? reloadedConfig.sync_url;
29392
- if (syncUrl && privateKeyBytes && deviceId) {
29393
- const pk = privateKeyBytes;
29394
- const did = deviceId;
29395
- runtime.enableInteractiveDelegation({
29396
- syncUrl,
29397
- authToken: async () => {
29398
- const now = Date.now();
29399
- return createSignedToken(
29400
- {
29401
- mid: motebitId,
29402
- did,
29403
- iat: now,
29404
- exp: now + 5 * 60 * 1e3,
29405
- jti: crypto.randomUUID(),
29406
- aud: "task:submit"
29407
- },
29408
- pk
29409
- );
29410
- },
29411
- routingStrategy: config.routingStrategy
29412
- });
29413
- }
29414
- const hasSyncRemote = config.syncUrl != null || process.env["MOTEBIT_SYNC_URL"] != null || reloadedConfig.sync_url != null && reloadedConfig.sync_url !== "";
29415
- if (hasSyncRemote) {
29793
+ const DEFAULT_SYNC_URL2 = "https://motebit-sync.fly.dev";
29794
+ const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"] ?? reloadedConfig.sync_url ?? DEFAULT_SYNC_URL2;
29795
+ {
29416
29796
  try {
29417
29797
  console.log(dim("Syncing..."));
29418
29798
  const result = await runtime.sync.sync();
@@ -29444,6 +29824,39 @@ async function main() {
29444
29824
  } catch {
29445
29825
  }
29446
29826
  }
29827
+ if (syncUrl) {
29828
+ if (privateKeyBytes && deviceId) {
29829
+ const pk = privateKeyBytes;
29830
+ const did = deviceId;
29831
+ runtime.enableInteractiveDelegation({
29832
+ syncUrl,
29833
+ authToken: async (audience = "task:submit") => {
29834
+ const now = Date.now();
29835
+ return createSignedToken(
29836
+ {
29837
+ mid: motebitId,
29838
+ did,
29839
+ iat: now,
29840
+ exp: now + 5 * 60 * 1e3,
29841
+ jti: crypto.randomUUID(),
29842
+ aud: audience
29843
+ },
29844
+ pk
29845
+ );
29846
+ },
29847
+ routingStrategy: config.routingStrategy
29848
+ });
29849
+ } else {
29850
+ const apiToken = config.syncToken ?? process.env["MOTEBIT_API_TOKEN"];
29851
+ if (apiToken) {
29852
+ runtime.enableInteractiveDelegation({
29853
+ syncUrl,
29854
+ authToken: () => Promise.resolve(apiToken),
29855
+ routingStrategy: config.routingStrategy
29856
+ });
29857
+ }
29858
+ }
29859
+ }
29447
29860
  if (syncUrl) {
29448
29861
  try {
29449
29862
  const token = config.syncToken ?? process.env["MOTEBIT_API_TOKEN"];
@@ -29473,7 +29886,7 @@ async function main() {
29473
29886
  }
29474
29887
  }
29475
29888
  const shutdown = async () => {
29476
- disableBracketedPaste();
29889
+ destroyTerminal();
29477
29890
  runtime.stop();
29478
29891
  await Promise.allSettled(mcpAdapters.map((a) => a.disconnect()));
29479
29892
  try {
@@ -29500,6 +29913,24 @@ async function main() {
29500
29913
  operator: config.operator
29501
29914
  });
29502
29915
  console.log();
29916
+ if (isFirstLaunch) {
29917
+ try {
29918
+ const activationRunId = crypto.randomUUID();
29919
+ writeOutput(prompt("mote>") + " ");
29920
+ await consumeStream(
29921
+ runtime.generateActivation(
29922
+ "You just came into existence. The person who created you is here. Speak first.",
29923
+ activationRunId
29924
+ ),
29925
+ runtime
29926
+ );
29927
+ void runtime.autoTitle();
29928
+ } catch (err3) {
29929
+ const msg = err3 instanceof Error ? err3.message : String(err3);
29930
+ console.error(dim(` [activation failed: ${msg}]`));
29931
+ }
29932
+ console.log();
29933
+ }
29503
29934
  const prompt2 = () => {
29504
29935
  readInput(prompt("you>") + " ").then(
29505
29936
  (line) => void handleLine(line),
@@ -29511,9 +29942,8 @@ async function main() {
29511
29942
  const handleLine = async (line) => {
29512
29943
  const trimmed = line.trim();
29513
29944
  if (trimmed === "quit" || trimmed === "exit") {
29514
- console.log("Goodbye!");
29945
+ writeOutput("Goodbye!\n");
29515
29946
  await shutdown();
29516
- rl?.close();
29517
29947
  return;
29518
29948
  }
29519
29949
  if (trimmed === "") {
@@ -29555,11 +29985,8 @@ ${prompt("mote>")} ${result.response}
29555
29985
  if (bodyLine) console.log(meta(` ${bodyLine}`));
29556
29986
  console.log();
29557
29987
  } else {
29558
- process.stdout.write("\n" + prompt("mote>") + " ");
29559
- const streamRl = getOrCreateRl();
29560
- await consumeStream(runtime.sendMessageStreaming(trimmed, chatRunId), runtime, streamRl);
29561
- streamRl.close();
29562
- rl = null;
29988
+ writeOutput("\n" + prompt("mote>") + " ");
29989
+ await consumeStream(runtime.sendMessageStreaming(trimmed, chatRunId), runtime);
29563
29990
  }
29564
29991
  void runtime.autoTitle();
29565
29992
  } catch (err3) {