open-agents-ai 0.187.227 → 0.187.229

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +699 -119
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5470,6 +5470,98 @@ var init_git_info = __esm({
5470
5470
  }
5471
5471
  });
5472
5472
 
5473
+ // packages/execution/dist/tools/jibberlink.js
5474
+ import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes4 } from "node:crypto";
5475
+ function crc16(bytes) {
5476
+ let crc = 65535;
5477
+ for (let i2 = 0; i2 < bytes.length; i2++) {
5478
+ crc ^= bytes[i2] << 8;
5479
+ for (let j = 0; j < 8; j++) {
5480
+ crc = crc & 32768 ? (crc << 1 ^ 4129) & 65535 : crc << 1 & 65535;
5481
+ }
5482
+ }
5483
+ return crc & 65535;
5484
+ }
5485
+ function deriveRoomKey(roomId, secret = "jibberlink-v1") {
5486
+ const material = `${secret}\0${roomId}`;
5487
+ return createHash("sha256").update(material).digest();
5488
+ }
5489
+ function aesGcmEncrypt(key, plaintext) {
5490
+ if (key.length !== 32)
5491
+ throw new Error("jibberlink: key must be 32 bytes");
5492
+ const iv = randomBytes4(12);
5493
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
5494
+ const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
5495
+ const tag = cipher.getAuthTag();
5496
+ return Buffer.concat([iv, tag, ct]);
5497
+ }
5498
+ function bytesToBits(bytes) {
5499
+ const out = new Uint8Array(bytes.length * 8);
5500
+ for (let i2 = 0; i2 < bytes.length; i2++) {
5501
+ const b = bytes[i2];
5502
+ for (let j = 0; j < 8; j++)
5503
+ out[i2 * 8 + j] = b >> j & 1;
5504
+ }
5505
+ return out;
5506
+ }
5507
+ function modulateFSK(bits) {
5508
+ const out = new Float32Array(bits.length * JL_SAMPLES_PER_BIT);
5509
+ let phase = 0;
5510
+ for (let i2 = 0; i2 < bits.length; i2++) {
5511
+ const freq = bits[i2] ? JL_MARK_HZ : JL_SPACE_HZ;
5512
+ const phaseInc = 2 * Math.PI * freq / JL_SAMPLE_RATE;
5513
+ for (let s2 = 0; s2 < JL_SAMPLES_PER_BIT; s2++) {
5514
+ out[i2 * JL_SAMPLES_PER_BIT + s2] = Math.sin(phase) * 0.8;
5515
+ phase += phaseInc;
5516
+ if (phase > 2 * Math.PI)
5517
+ phase -= 2 * Math.PI;
5518
+ }
5519
+ }
5520
+ return out;
5521
+ }
5522
+ function encodeFrame(payload) {
5523
+ if (payload.length > 65535)
5524
+ throw new Error("jibberlink: payload too large");
5525
+ const preamble = [];
5526
+ for (let i2 = 0; i2 < JL_PREAMBLE_BITS; i2++)
5527
+ preamble.push(i2 & 1);
5528
+ const header = new Uint8Array([
5529
+ JL_SYNC_BYTE,
5530
+ payload.length >> 8 & 255,
5531
+ payload.length & 255
5532
+ ]);
5533
+ const bodyBytes = new Uint8Array(header.length + payload.length + 2);
5534
+ bodyBytes.set(header, 0);
5535
+ bodyBytes.set(payload, header.length);
5536
+ const crc = crc16(bodyBytes.subarray(0, header.length + payload.length));
5537
+ bodyBytes[bodyBytes.length - 2] = crc >> 8 & 255;
5538
+ bodyBytes[bodyBytes.length - 1] = crc & 255;
5539
+ const bodyBits = bytesToBits(bodyBytes);
5540
+ const allBits = new Uint8Array(preamble.length + bodyBits.length);
5541
+ for (let i2 = 0; i2 < preamble.length; i2++)
5542
+ allBits[i2] = preamble[i2];
5543
+ allBits.set(bodyBits, preamble.length);
5544
+ return modulateFSK(allBits);
5545
+ }
5546
+ function encodeEncrypted(roomId, payload, secret) {
5547
+ const key = deriveRoomKey(roomId, secret);
5548
+ const wrapped = aesGcmEncrypt(key, Buffer.from(payload));
5549
+ return encodeFrame(wrapped);
5550
+ }
5551
+ var JL_SAMPLE_RATE, JL_MARK_HZ, JL_SPACE_HZ, JL_BAUD, JL_SAMPLES_PER_BIT, JL_SYNC_BYTE, JL_PREAMBLE_BITS;
5552
+ var init_jibberlink = __esm({
5553
+ "packages/execution/dist/tools/jibberlink.js"() {
5554
+ "use strict";
5555
+ JL_SAMPLE_RATE = 16e3;
5556
+ JL_MARK_HZ = 2200;
5557
+ JL_SPACE_HZ = 1200;
5558
+ JL_BAUD = 300;
5559
+ JL_SAMPLES_PER_BIT = Math.floor(JL_SAMPLE_RATE / JL_BAUD);
5560
+ JL_SYNC_BYTE = 126;
5561
+ JL_PREAMBLE_BITS = 16;
5562
+ }
5563
+ });
5564
+
5473
5565
  // packages/execution/dist/tools/nexus.js
5474
5566
  var nexus_exports = {};
5475
5567
  __export(nexus_exports, {
@@ -5478,7 +5570,7 @@ __export(nexus_exports, {
5478
5570
  import { readFile as readFile8, writeFile as writeFile6, mkdir as mkdir3, chmod, unlink, readdir as readdir2, open as fsOpen, copyFile as copyFile2 } from "node:fs/promises";
5479
5571
  import { existsSync as existsSync11, readFileSync as readFileSync8, watch as fsWatchLocal } from "node:fs";
5480
5572
  import { resolve as resolve13, join as join14 } from "node:path";
5481
- import { randomBytes as randomBytes4, createCipheriv, createDecipheriv, scryptSync, createHash } from "node:crypto";
5573
+ import { randomBytes as randomBytes5, createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, scryptSync, createHash as createHash2 } from "node:crypto";
5482
5574
  import { execSync as execSync8, spawn as spawn2 } from "node:child_process";
5483
5575
  import { hostname, userInfo, homedir as homedir4 } from "node:os";
5484
5576
  function containsKeyMaterial(input) {
@@ -5492,6 +5584,7 @@ var DAEMON_SCRIPT, KEY_PATTERNS, NexusTool;
5492
5584
  var init_nexus = __esm({
5493
5585
  "packages/execution/dist/tools/nexus.js"() {
5494
5586
  "use strict";
5587
+ init_jibberlink();
5495
5588
  DAEMON_SCRIPT = `#!/usr/bin/env node
5496
5589
  /**
5497
5590
  * nexus-daemon.mjs — Standalone nexus process with real TCP/UDP sockets.
@@ -5675,6 +5768,27 @@ var _natsConn = null;
5675
5768
  var _natsCodec = null;
5676
5769
  var _tokensByRequest = {};
5677
5770
 
5771
+ // ── Nexus voice subsystem (PCM + ASR) ─────────────────────────────────
5772
+ // Subscribes to nexus.rooms.audio, filters by the rooms this daemon has
5773
+ // joined, writes incoming voice frames to .oa/nexus/inbox/<room>/voice/
5774
+ // as JSON envelopes AND pipes decoded PCM16 into a whisper child process
5775
+ // so agents auto-receive transcripts of other agents' speech. Publishing
5776
+ // side: voice_publish action relays base64 PCM frames to the same subject.
5777
+ //
5778
+ // Transport contract (same as nexus frontend):
5779
+ // subject: nexus.rooms.audio
5780
+ // payload: JSON over StringCodec
5781
+ // { type:'voice', roomId, peerId, agentName,
5782
+ // sampleRate, encoding:'pcm16'|'float32'|'jibberlink', channels,
5783
+ // seq, timestamp, data:<base64> }
5784
+ var VOICE_SUBJECT = 'nexus.rooms.audio';
5785
+ var _voiceSub = null; // active NATS subscription object
5786
+ var _whisperProc = null; // spawned live-whisper.py child process
5787
+ var _whisperPending = ''; // partial stdout line buffer
5788
+ var _voiceListenRooms = new Set(); // rooms actively piped to whisper
5789
+ var _voiceSeq = 0;
5790
+ var _voiceLastActivityMs = 0;
5791
+
5678
5792
  // Check if an error is a connectivity/dial failure (should trigger NATS fallback)
5679
5793
  // vs an application-level error (auth rejected, capability not found — no point retrying via NATS)
5680
5794
  function isDialFailure(errMsg) {
@@ -5694,6 +5808,140 @@ function isDialFailure(errMsg) {
5694
5808
  lower.includes('connection refused');
5695
5809
  }
5696
5810
 
5811
+ // ── Voice helpers ────────────────────────────────────────────────────
5812
+ // Convert a base64 string to a Buffer of raw PCM bytes (browser-safe
5813
+ // atob is unavailable in Node, use Buffer directly).
5814
+ function _voiceB64ToBuf(b64) {
5815
+ try { return Buffer.from(b64, 'base64'); } catch { return Buffer.alloc(0); }
5816
+ }
5817
+ function _voiceBufToB64(buf) {
5818
+ try { return buf.toString('base64'); } catch { return ''; }
5819
+ }
5820
+ // Convert Int16 PCM little-endian Buffer → Float32Array in [-1, 1]
5821
+ function _voicePcm16ToF32(buf) {
5822
+ var n = buf.length >> 1;
5823
+ var out = new Float32Array(n);
5824
+ for (var i = 0; i < n; i++) {
5825
+ var s = buf.readInt16LE(i * 2);
5826
+ out[i] = s / 32768;
5827
+ }
5828
+ return out;
5829
+ }
5830
+ // Convert Float32Array → Int16 PCM little-endian Buffer
5831
+ function _voiceF32ToPcm16(f32) {
5832
+ var out = Buffer.alloc(f32.length * 2);
5833
+ for (var i = 0; i < f32.length; i++) {
5834
+ var s = Math.max(-1, Math.min(1, f32[i]));
5835
+ out.writeInt16LE(s < 0 ? s * 32768 : s * 32767, i * 2);
5836
+ }
5837
+ return out;
5838
+ }
5839
+ // Ensure a whisper child process is running. Returns true on success.
5840
+ // Lazy-spawned on the first voice_listen_start call per daemon lifetime.
5841
+ function _voiceEnsureWhisper() {
5842
+ if (_whisperProc && !_whisperProc.killed) return true;
5843
+ try {
5844
+ var cp = require('node:child_process');
5845
+ var pathMod = require('node:path');
5846
+ var fsMod = require('node:fs');
5847
+ // Resolve live-whisper.py — ships inside the CLI bundle at dist/scripts
5848
+ // relative to the currently-running daemon script.
5849
+ var candidates = [
5850
+ pathMod.resolve(pathMod.dirname(nexusDir), 'scripts', 'live-whisper.py'),
5851
+ pathMod.resolve(process.cwd(), 'packages/execution/scripts/live-whisper.py'),
5852
+ pathMod.resolve(process.cwd(), 'dist/scripts/live-whisper.py'),
5853
+ pathMod.resolve(process.cwd(), 'scripts/live-whisper.py'),
5854
+ ];
5855
+ var whisperPy = null;
5856
+ for (var i = 0; i < candidates.length; i++) {
5857
+ if (fsMod.existsSync(candidates[i])) { whisperPy = candidates[i]; break; }
5858
+ }
5859
+ if (!whisperPy) {
5860
+ dlog('voice: whisper script not found — searched ' + candidates.length + ' paths');
5861
+ return false;
5862
+ }
5863
+ var pyBin = process.env.PYTHON || 'python3';
5864
+ _whisperProc = cp.spawn(pyBin, [whisperPy, '--stdin', '--model', 'base', '--lang', 'en'], {
5865
+ stdio: ['pipe', 'pipe', 'pipe'],
5866
+ });
5867
+ _whisperPending = '';
5868
+ _whisperProc.stdout.on('data', function(chunk) {
5869
+ _whisperPending += chunk.toString('utf8');
5870
+ // DAEMON_SCRIPT is an outer template literal — any escape sequence
5871
+ // in code we want to appear literally in the generated file must
5872
+ // be double-escaped so the outer template doesn't consume it.
5873
+ var lines = _whisperPending.split('\\n');
5874
+ _whisperPending = lines.pop() || '';
5875
+ for (var li = 0; li < lines.length; li++) {
5876
+ var ln = lines[li].trim();
5877
+ if (!ln) continue;
5878
+ try {
5879
+ var msg = JSON.parse(ln);
5880
+ if (msg && msg.type === 'transcript' && msg.text) {
5881
+ // Write each transcript to every actively-listened room's inbox
5882
+ for (var roomId of _voiceListenRooms) {
5883
+ try {
5884
+ var roomInbox = pathMod.join(inboxDir, roomId, 'voice');
5885
+ fsMod.mkdirSync(roomInbox, { recursive: true });
5886
+ var fname = 'transcript-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8) + '.json';
5887
+ fsMod.writeFileSync(pathMod.join(roomInbox, fname), JSON.stringify({
5888
+ type: 'voice.transcript',
5889
+ roomId: roomId,
5890
+ text: String(msg.text || '').trim(),
5891
+ isFinal: !!msg.isFinal,
5892
+ timestamp: Date.now(),
5893
+ }, null, 2));
5894
+ } catch (we) {
5895
+ dlog('voice: transcript write failed: ' + (we.message || we));
5896
+ }
5897
+ }
5898
+ }
5899
+ } catch { /* non-JSON whisper output — ignore */ }
5900
+ }
5901
+ });
5902
+ _whisperProc.stderr.on('data', function(chunk) {
5903
+ dlog('whisper stderr: ' + chunk.toString('utf8').slice(0, 200));
5904
+ });
5905
+ _whisperProc.on('exit', function(code) {
5906
+ dlog('whisper exited code=' + code);
5907
+ _whisperProc = null;
5908
+ });
5909
+ dlog('voice: whisper child spawned (pid=' + _whisperProc.pid + ')');
5910
+ return true;
5911
+ } catch (err) {
5912
+ dlog('voice: whisper spawn failed: ' + (err.message || err));
5913
+ _whisperProc = null;
5914
+ return false;
5915
+ }
5916
+ }
5917
+ // Feed a PCM16 byte buffer into the whisper stdin. No-op if whisper isn't running.
5918
+ function _voiceFeedWhisper(buf) {
5919
+ if (!_whisperProc || !_whisperProc.stdin || _whisperProc.killed) return;
5920
+ try { _whisperProc.stdin.write(buf); } catch (err) {
5921
+ dlog('voice: whisper stdin write failed: ' + (err.message || err));
5922
+ }
5923
+ }
5924
+ // Write a compact "voice activity" event to the room inbox so the agent
5925
+ // sees who just spoke even when whisper isn't transcribing (no mic drain
5926
+ // on the laptop doing pure listening).
5927
+ function _voiceEmitActivity(env) {
5928
+ try {
5929
+ var pathMod2 = require('node:path');
5930
+ var fsMod2 = require('node:fs');
5931
+ var roomInbox = pathMod2.join(inboxDir, env.roomId, 'voice');
5932
+ fsMod2.mkdirSync(roomInbox, { recursive: true });
5933
+ var fname = 'activity-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6) + '.json';
5934
+ fsMod2.writeFileSync(pathMod2.join(roomInbox, fname), JSON.stringify({
5935
+ type: 'voice.activity',
5936
+ roomId: env.roomId,
5937
+ peerId: env.peerId || '',
5938
+ agentName: env.agentName || '',
5939
+ seq: env.seq || 0,
5940
+ timestamp: env.timestamp || Date.now(),
5941
+ }, null, 2));
5942
+ } catch {}
5943
+ }
5944
+
5697
5945
  function writeStatus(extra = {}) {
5698
5946
  const caps = typeof nexus.getRegisteredCapabilities === 'function'
5699
5947
  ? nexus.getRegisteredCapabilities() : [];
@@ -5828,6 +6076,85 @@ async function handleCmd(cmd) {
5828
6076
  writeResp(id, { ok: true, output: 'Message sent (id: ' + msgId + ')' });
5829
6077
  break;
5830
6078
  }
6079
+ // ── Voice: publish a PCM frame to a room ──
6080
+ // args: { room_id, pcm_base64, sample_rate?, encoding?, channels? }
6081
+ // Relays to nexus.rooms.audio with the same envelope the nexus
6082
+ // frontend decodes. Agents can call this with raw PCM bytes from
6083
+ // any source (TTS, mic, jibberlink modem output).
6084
+ case 'voice_publish': {
6085
+ if (!_natsConn || !_natsCodec) {
6086
+ writeResp(id, { ok: false, output: 'NATS not connected' });
6087
+ return;
6088
+ }
6089
+ if (!args || !args.room_id || !args.pcm_base64) {
6090
+ writeResp(id, { ok: false, output: 'voice_publish requires room_id + pcm_base64' });
6091
+ return;
6092
+ }
6093
+ if (!rooms.has(args.room_id)) {
6094
+ writeResp(id, { ok: false, output: 'Not in room: ' + args.room_id + '. Join first.' });
6095
+ return;
6096
+ }
6097
+ try {
6098
+ var vpEnv = {
6099
+ type: 'voice',
6100
+ roomId: args.room_id,
6101
+ peerId: nexus.peerId || '',
6102
+ agentName: agentName,
6103
+ sampleRate: parseInt(args.sample_rate, 10) || 16000,
6104
+ encoding: args.encoding || 'pcm16',
6105
+ channels: parseInt(args.channels, 10) || 1,
6106
+ seq: _voiceSeq++,
6107
+ timestamp: Date.now(),
6108
+ data: String(args.pcm_base64),
6109
+ };
6110
+ _natsConn.publish(VOICE_SUBJECT, _natsCodec.encode(JSON.stringify(vpEnv)));
6111
+ writeResp(id, { ok: true, output: 'Voice frame published to ' + args.room_id + ' (' + Math.round(args.pcm_base64.length * 0.75) + ' bytes)' });
6112
+ } catch (vpErr) {
6113
+ writeResp(id, { ok: false, output: 'voice_publish error: ' + (vpErr.message || vpErr) });
6114
+ }
6115
+ break;
6116
+ }
6117
+ // ── Voice: start/stop ASR pipeline for a joined room ──
6118
+ case 'voice_listen_start': {
6119
+ var vlsRoom = args && args.room_id;
6120
+ if (!vlsRoom) { writeResp(id, { ok: false, output: 'voice_listen_start requires room_id' }); return; }
6121
+ if (!rooms.has(vlsRoom)) { writeResp(id, { ok: false, output: 'Not in room: ' + vlsRoom }); return; }
6122
+ _voiceListenRooms.add(vlsRoom);
6123
+ var ok = _voiceEnsureWhisper();
6124
+ if (!ok) {
6125
+ _voiceListenRooms.delete(vlsRoom);
6126
+ writeResp(id, { ok: false, output: 'Failed to start whisper — check Python + live-whisper.py path' });
6127
+ return;
6128
+ }
6129
+ writeResp(id, { ok: true, output: 'Voice listen started for ' + vlsRoom + '. Transcripts will appear in inbox/' + vlsRoom + '/voice/' });
6130
+ break;
6131
+ }
6132
+ case 'voice_listen_stop': {
6133
+ var vlsRoom2 = args && args.room_id;
6134
+ if (vlsRoom2) {
6135
+ _voiceListenRooms.delete(vlsRoom2);
6136
+ writeResp(id, { ok: true, output: 'Voice listen stopped for ' + vlsRoom2 });
6137
+ } else {
6138
+ _voiceListenRooms.clear();
6139
+ writeResp(id, { ok: true, output: 'Voice listen stopped for all rooms' });
6140
+ }
6141
+ if (_voiceListenRooms.size === 0 && _whisperProc) {
6142
+ try { _whisperProc.stdin.end(); } catch {}
6143
+ try { _whisperProc.kill(); } catch {}
6144
+ _whisperProc = null;
6145
+ }
6146
+ break;
6147
+ }
6148
+ // ── Voice: status of voice subsystem ──
6149
+ case 'voice_status': {
6150
+ writeResp(id, { ok: true, output: JSON.stringify({
6151
+ subscribed: !!_voiceSub,
6152
+ whisperRunning: !!_whisperProc,
6153
+ listeningRooms: Array.from(_voiceListenRooms),
6154
+ lastActivityMsAgo: _voiceLastActivityMs ? (Date.now() - _voiceLastActivityMs) : null,
6155
+ }, null, 2) });
6156
+ break;
6157
+ }
5831
6158
  // ── Sponsor announcement via NATS ──
5832
6159
  case 'sponsor_announce': {
5833
6160
  // Publish sponsor metadata to NATS so other OA instances can discover it
@@ -8058,6 +8385,58 @@ process.on('unhandledRejection', (reason) => {
8058
8385
  var _natsInvSub = _nc.subscribe(_natsInvSubject);
8059
8386
  dlog('NATS invoke relay listening on ' + _natsInvSubject);
8060
8387
 
8388
+ // ── Voice subscription: nexus.rooms.audio ─────────────────
8389
+ // Filters incoming voice envelopes by the rooms this daemon
8390
+ // has joined. Auto-emits voice.activity events to the room
8391
+ // inbox; if voice_listen_start has been called for that
8392
+ // room, PCM bytes are piped into the whisper child process
8393
+ // for auto-transcription.
8394
+ try {
8395
+ _voiceSub = _nc.subscribe(VOICE_SUBJECT);
8396
+ dlog('NATS voice subscription active on ' + VOICE_SUBJECT);
8397
+ (async function _voiceLoop() {
8398
+ for await (var _vm of _voiceSub) {
8399
+ try {
8400
+ var env = JSON.parse(_natsCodec.decode(_vm.data));
8401
+ if (!env || env.type !== 'voice' || !env.roomId) continue;
8402
+ // Only process audio for rooms this agent has joined —
8403
+ // ignores everyone else's chatter and keeps CPU down.
8404
+ if (!rooms.has(env.roomId)) continue;
8405
+ // Skip our own echo
8406
+ if (env.peerId && env.peerId === nexus.peerId) continue;
8407
+ _voiceLastActivityMs = Date.now();
8408
+ _voiceEmitActivity(env);
8409
+ // If whisper is active for this room, decode and pipe
8410
+ if (_voiceListenRooms.has(env.roomId) && _whisperProc && env.data) {
8411
+ var buf;
8412
+ if (env.encoding === 'float32') {
8413
+ // Float32 → PCM16 conversion so whisper gets a
8414
+ // consistent input format
8415
+ var raw = _voiceB64ToBuf(env.data);
8416
+ var f32 = new Float32Array(raw.buffer, raw.byteOffset, raw.byteLength / 4);
8417
+ buf = _voiceF32ToPcm16(f32);
8418
+ } else if (env.encoding === 'jibberlink') {
8419
+ // Jibberlink frames are encrypted data-over-audio
8420
+ // (see lib-jibberlink.ts). Skip whisper feeding —
8421
+ // those get demodulated + decrypted separately.
8422
+ continue;
8423
+ } else {
8424
+ // Default pcm16 — pass straight through
8425
+ buf = _voiceB64ToBuf(env.data);
8426
+ }
8427
+ _voiceFeedWhisper(buf);
8428
+ }
8429
+ } catch (vErr) {
8430
+ dlog('voice loop parse error: ' + (vErr.message || vErr));
8431
+ }
8432
+ }
8433
+ })().catch(function(loopErr) {
8434
+ dlog('voice loop fatal: ' + (loopErr.message || loopErr));
8435
+ });
8436
+ } catch (vsErr) {
8437
+ dlog('voice subscribe failed: ' + (vsErr.message || vsErr));
8438
+ }
8439
+
8061
8440
  (async function _natsInvokeLoop() {
8062
8441
  for await (var _nm of _natsInvSub) {
8063
8442
  try {
@@ -10093,6 +10472,32 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10093
10472
  confidence: String(args.confidence ?? "0.7")
10094
10473
  });
10095
10474
  break;
10475
+ // ── Voice subsystem (nexus.rooms.audio transport) ──────────
10476
+ case "voice_publish":
10477
+ result = await this.sendDaemonCmd("voice_publish", {
10478
+ room_id: String(args.room_id ?? ""),
10479
+ pcm_base64: String(args.pcm_base64 ?? args.data ?? ""),
10480
+ sample_rate: String(args.sample_rate ?? "16000"),
10481
+ encoding: String(args.encoding ?? "pcm16"),
10482
+ channels: String(args.channels ?? "1")
10483
+ }, 1e4);
10484
+ break;
10485
+ case "voice_speak":
10486
+ result = await this.doVoiceSpeak(args);
10487
+ break;
10488
+ case "voice_listen_start":
10489
+ result = await this.sendDaemonCmd("voice_listen_start", { room_id: String(args.room_id ?? "") });
10490
+ break;
10491
+ case "voice_listen_stop":
10492
+ result = await this.sendDaemonCmd("voice_listen_stop", { room_id: String(args.room_id ?? "") });
10493
+ break;
10494
+ case "voice_status":
10495
+ result = await this.sendDaemonCmd("voice_status", {});
10496
+ break;
10497
+ // ── Jibberlink: encrypted data-over-audio between agents ───
10498
+ case "jibberlink_send":
10499
+ result = await this.doJibberlinkSend(args);
10500
+ break;
10096
10501
  default:
10097
10502
  return { success: false, output: "", error: `Unknown nexus action: ${action}`, durationMs: Date.now() - start2 };
10098
10503
  }
@@ -10131,7 +10536,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10131
10536
  if (!pid)
10132
10537
  throw new Error("Nexus daemon not running. Use action 'connect' first.");
10133
10538
  }
10134
- const cmdId = randomBytes4(8).toString("hex");
10539
+ const cmdId = randomBytes5(8).toString("hex");
10135
10540
  const cmdFile = join14(this.nexusDir, "cmd.json");
10136
10541
  const respFile = join14(this.nexusDir, "resp.json");
10137
10542
  if (existsSync11(respFile))
@@ -10242,7 +10647,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10242
10647
  // =========================================================================
10243
10648
  async doConnect(args) {
10244
10649
  await this.ensureDir();
10245
- const currentScriptHash = createHash("sha256").update(DAEMON_SCRIPT).digest("hex").slice(0, 16);
10650
+ const currentScriptHash = createHash2("sha256").update(DAEMON_SCRIPT).digest("hex").slice(0, 16);
10246
10651
  const existingPid = this.getDaemonPid();
10247
10652
  if (existingPid) {
10248
10653
  let processAlive = false;
@@ -10614,6 +11019,134 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10614
11019
  }
10615
11020
  return this.sendDaemonCmd("send_message", args);
10616
11021
  }
11022
+ /**
11023
+ * Synthesize `text` to WAV via the system TTS (piper/espeak/ffmpeg
11024
+ * sox fallback), decode to raw 16kHz mono PCM16, chunk into 20ms
11025
+ * frames, and publish each frame to nexus.rooms.audio so other
11026
+ * agents + the nexus frontend visitors hear the agent speak.
11027
+ *
11028
+ * This is the symmetry with the existing audio_playback.speak tool,
11029
+ * but routes audio over the nexus voice subject instead of the
11030
+ * local speakers.
11031
+ */
11032
+ async doVoiceSpeak(args) {
11033
+ const text = String(args.text ?? "");
11034
+ const roomId = String(args.room_id ?? "");
11035
+ if (!text)
11036
+ throw new Error("text is required");
11037
+ if (!roomId)
11038
+ throw new Error("room_id is required");
11039
+ if (containsKeyMaterial(text)) {
11040
+ return "BLOCKED: Text contains potential key material.";
11041
+ }
11042
+ const tmpWav = join14(this.nexusDir, `voice-${Date.now()}.wav`);
11043
+ try {
11044
+ const cp2 = await import("node:child_process");
11045
+ const fsMod = await import("node:fs");
11046
+ const path5 = await import("node:path");
11047
+ let synthesized = false;
11048
+ try {
11049
+ cp2.execSync(`echo ${JSON.stringify(text)} | piper --model en_US-lessac-medium --output_file ${JSON.stringify(tmpWav)}`, {
11050
+ stdio: "pipe",
11051
+ timeout: 3e4
11052
+ });
11053
+ synthesized = fsMod.existsSync(tmpWav);
11054
+ } catch {
11055
+ }
11056
+ if (!synthesized) {
11057
+ try {
11058
+ cp2.execSync(`espeak ${JSON.stringify(text)} -w ${JSON.stringify(tmpWav)} -s 160`, {
11059
+ stdio: "pipe",
11060
+ timeout: 15e3
11061
+ });
11062
+ synthesized = fsMod.existsSync(tmpWav);
11063
+ } catch (err) {
11064
+ throw new Error(`TTS synthesis failed: ${err.message || err}`);
11065
+ }
11066
+ }
11067
+ const pcmPath = tmpWav.replace(/\.wav$/, ".pcm");
11068
+ try {
11069
+ cp2.execSync(`ffmpeg -y -i ${JSON.stringify(tmpWav)} -ac 1 -ar 16000 -f s16le ${JSON.stringify(pcmPath)}`, {
11070
+ stdio: "pipe",
11071
+ timeout: 15e3
11072
+ });
11073
+ } catch {
11074
+ const raw = fsMod.readFileSync(tmpWav);
11075
+ fsMod.writeFileSync(pcmPath, raw.slice(44));
11076
+ }
11077
+ const pcm = fsMod.readFileSync(pcmPath);
11078
+ try {
11079
+ fsMod.unlinkSync(tmpWav);
11080
+ } catch {
11081
+ }
11082
+ try {
11083
+ fsMod.unlinkSync(pcmPath);
11084
+ } catch {
11085
+ }
11086
+ const SAMPLE_RATE = 16e3;
11087
+ const FRAME_MS = 50;
11088
+ const FRAME_BYTES = Math.floor(SAMPLE_RATE * FRAME_MS / 1e3 * 2);
11089
+ const frameCount = Math.ceil(pcm.length / FRAME_BYTES);
11090
+ let published = 0;
11091
+ for (let i2 = 0; i2 < pcm.length; i2 += FRAME_BYTES) {
11092
+ const chunk = pcm.subarray(i2, Math.min(i2 + FRAME_BYTES, pcm.length));
11093
+ const b64 = chunk.toString("base64");
11094
+ await this.sendDaemonCmd("voice_publish", {
11095
+ room_id: roomId,
11096
+ pcm_base64: b64,
11097
+ sample_rate: String(SAMPLE_RATE),
11098
+ encoding: "pcm16",
11099
+ channels: "1"
11100
+ }, 5e3);
11101
+ published++;
11102
+ await new Promise((r2) => setTimeout(r2, Math.floor(FRAME_MS * 0.5)));
11103
+ }
11104
+ return `Spoke ${frameCount} frames (${(pcm.length / 1024).toFixed(1)}KB) to ${roomId}`;
11105
+ } catch (err) {
11106
+ throw new Error(`voice_speak failed: ${err.message || err}`);
11107
+ }
11108
+ }
11109
+ /**
11110
+ * Encode a byte payload under AES-GCM (per-room key), modulate it as
11111
+ * FSK over the jibberlink audio modem, and publish the resulting PCM
11112
+ * samples to the room as a voice frame with encoding='jibberlink'.
11113
+ *
11114
+ * Other agents subscribed to nexus.rooms.audio can demodulate + decrypt
11115
+ * it using the same roomId (shared key is derived from roomId + a
11116
+ * caller-supplied `secret`). Visitors in the nexus frontend simply
11117
+ * hear the characteristic chirp tones without decoding.
11118
+ */
11119
+ async doJibberlinkSend(args) {
11120
+ const roomId = String(args.room_id ?? "");
11121
+ const message2 = String(args.message ?? args.data ?? "");
11122
+ const secret = args.secret != null ? String(args.secret) : void 0;
11123
+ if (!roomId)
11124
+ throw new Error("room_id is required");
11125
+ if (!message2)
11126
+ throw new Error("message is required");
11127
+ if (containsKeyMaterial(message2)) {
11128
+ return "BLOCKED: Message contains potential key material.";
11129
+ }
11130
+ const plaintext = Buffer.from(message2, "utf8");
11131
+ if (plaintext.length > 1024) {
11132
+ throw new Error("jibberlink payload > 1KB — split into multiple frames");
11133
+ }
11134
+ const pcmF32 = encodeEncrypted(roomId, plaintext, secret);
11135
+ const pcm16 = Buffer.alloc(pcmF32.length * 2);
11136
+ for (let i2 = 0; i2 < pcmF32.length; i2++) {
11137
+ let s2 = Math.max(-1, Math.min(1, pcmF32[i2]));
11138
+ pcm16.writeInt16LE(s2 < 0 ? s2 * 32768 : s2 * 32767, i2 * 2);
11139
+ }
11140
+ const b64 = pcm16.toString("base64");
11141
+ await this.sendDaemonCmd("voice_publish", {
11142
+ room_id: roomId,
11143
+ pcm_base64: b64,
11144
+ sample_rate: "16000",
11145
+ encoding: "jibberlink",
11146
+ channels: "1"
11147
+ }, 1e4);
11148
+ return `Jibberlink frame sent to ${roomId} (${plaintext.length}B plaintext → ${pcmF32.length} samples)`;
11149
+ }
10617
11150
  async doSendDM(args) {
10618
11151
  const message2 = args.message;
10619
11152
  if (!message2)
@@ -10738,21 +11271,21 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10738
11271
  let privKeyHex;
10739
11272
  try {
10740
11273
  const { privateKeyToAccount } = await import("viem/accounts");
10741
- const privKey = randomBytes4(32);
11274
+ const privKey = randomBytes5(32);
10742
11275
  privKeyHex = privKey.toString("hex");
10743
11276
  const account = privateKeyToAccount(`0x${privKeyHex}`);
10744
11277
  address = account.address;
10745
11278
  privKey.fill(0);
10746
11279
  } catch {
10747
- const privKey = randomBytes4(32);
11280
+ const privKey = randomBytes5(32);
10748
11281
  privKeyHex = privKey.toString("hex");
10749
- address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
11282
+ address = "0x" + createHash2("sha256").update(privKey).digest("hex").slice(0, 40);
10750
11283
  privKey.fill(0);
10751
11284
  }
10752
- const salt = randomBytes4(32);
11285
+ const salt = randomBytes5(32);
10753
11286
  const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
10754
- const iv = randomBytes4(16);
10755
- const cipher = createCipheriv("aes-256-gcm", key, iv);
11287
+ const iv = randomBytes5(16);
11288
+ const cipher = createCipheriv2("aes-256-gcm", key, iv);
10756
11289
  let enc = cipher.update(privKeyHex, "utf8", "hex");
10757
11290
  enc += cipher.final("hex");
10758
11291
  const x402KeyPath = join14(this.nexusDir, "x402-wallet.key");
@@ -10800,21 +11333,21 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10800
11333
  let privKeyHex;
10801
11334
  try {
10802
11335
  const { privateKeyToAccount } = await import("viem/accounts");
10803
- const privKey = randomBytes4(32);
11336
+ const privKey = randomBytes5(32);
10804
11337
  privKeyHex = privKey.toString("hex");
10805
11338
  const account = privateKeyToAccount(`0x${privKeyHex}`);
10806
11339
  address = account.address;
10807
11340
  privKey.fill(0);
10808
11341
  } catch {
10809
- const privKey = randomBytes4(32);
11342
+ const privKey = randomBytes5(32);
10810
11343
  privKeyHex = privKey.toString("hex");
10811
- address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
11344
+ address = "0x" + createHash2("sha256").update(privKey).digest("hex").slice(0, 40);
10812
11345
  privKey.fill(0);
10813
11346
  }
10814
- const salt = randomBytes4(32);
11347
+ const salt = randomBytes5(32);
10815
11348
  const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
10816
- const iv = randomBytes4(16);
10817
- const cipher = createCipheriv("aes-256-gcm", key, iv);
11349
+ const iv = randomBytes5(16);
11350
+ const cipher = createCipheriv2("aes-256-gcm", key, iv);
10818
11351
  let enc = cipher.update(privKeyHex, "utf8", "hex");
10819
11352
  enc += cipher.final("hex");
10820
11353
  const x402KeyPath = join14(this.nexusDir, "x402-wallet.key");
@@ -11120,14 +11653,14 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11120
11653
  throw new Error("User-managed wallet cannot spend (no private key)");
11121
11654
  const salt = Buffer.from(w.salt, "hex");
11122
11655
  const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
11123
- const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(w.iv, "hex"));
11656
+ const decipher = createDecipheriv2("aes-256-gcm", key, Buffer.from(w.iv, "hex"));
11124
11657
  decipher.setAuthTag(Buffer.from(w.authTag, "hex"));
11125
11658
  let privKeyHex = decipher.update(w.encryptedKey, "hex", "utf8");
11126
11659
  privKeyHex += decipher.final("utf8");
11127
11660
  try {
11128
11661
  const { privateKeyToAccount } = await import("viem/accounts");
11129
11662
  const account = privateKeyToAccount(`0x${privKeyHex}`);
11130
- const nonce = "0x" + randomBytes4(32).toString("hex");
11663
+ const nonce = "0x" + randomBytes5(32).toString("hex");
11131
11664
  const now = Math.floor(Date.now() / 1e3);
11132
11665
  const validAfter = now - 60;
11133
11666
  const validBefore = now + 3600;
@@ -11330,8 +11863,8 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
11330
11863
  } catch {
11331
11864
  }
11332
11865
  }
11333
- const nonce = randomBytes4(16).toString("hex");
11334
- const hash = createHash("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
11866
+ const nonce = randomBytes5(16).toString("hex");
11867
+ const hash = createHash2("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
11335
11868
  const bar = (s2) => "█".repeat(Math.round(s2 / 5)) + "░".repeat(20 - Math.round(s2 / 5));
11336
11869
  const mem = vramMb > 24e3 ? 95 : vramMb > 16e3 ? 80 : vramMb > 8e3 ? 60 : vramMb > 0 ? 40 : 20;
11337
11870
  await this.ensureDir();
@@ -19865,7 +20398,7 @@ function createHasher(hashCons, info = {}) {
19865
20398
  Object.assign(hashC, info);
19866
20399
  return Object.freeze(hashC);
19867
20400
  }
19868
- function randomBytes5(bytesLength = 32) {
20401
+ function randomBytes6(bytesLength = 32) {
19869
20402
  const cr = typeof globalThis === "object" ? globalThis.crypto : null;
19870
20403
  if (typeof cr?.getRandomValues !== "function")
19871
20404
  throw new Error("crypto.getRandomValues must be defined");
@@ -19889,11 +20422,11 @@ var init_utils3 = __esm({
19889
20422
  });
19890
20423
 
19891
20424
  // ../node_modules/@libp2p/crypto/dist/src/random-bytes.js
19892
- function randomBytes6(length4) {
20425
+ function randomBytes7(length4) {
19893
20426
  if (isNaN(length4) || length4 <= 0) {
19894
20427
  throw new InvalidParametersError("random bytes length must be a Number bigger than 0");
19895
20428
  }
19896
- return randomBytes5(length4);
20429
+ return randomBytes6(length4);
19897
20430
  }
19898
20431
  var init_random_bytes = __esm({
19899
20432
  "../node_modules/@libp2p/crypto/dist/src/random-bytes.js"() {
@@ -22082,7 +22615,7 @@ function getWLengths(Fp, Fn) {
22082
22615
  }
22083
22616
  function ecdh(Point, ecdhOpts = {}) {
22084
22617
  const { Fn } = Point;
22085
- const randomBytes_ = ecdhOpts.randomBytes || randomBytes5;
22618
+ const randomBytes_ = ecdhOpts.randomBytes || randomBytes6;
22086
22619
  const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) });
22087
22620
  function isValidSecretKey(secretKey) {
22088
22621
  try {
@@ -22147,7 +22680,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
22147
22680
  bits2int_modN: "function"
22148
22681
  });
22149
22682
  ecdsaOpts = Object.assign({}, ecdsaOpts);
22150
- const randomBytes22 = ecdsaOpts.randomBytes || randomBytes5;
22683
+ const randomBytes23 = ecdsaOpts.randomBytes || randomBytes6;
22151
22684
  const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
22152
22685
  const { Fp, Fn } = Point;
22153
22686
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
@@ -22289,7 +22822,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
22289
22822
  throw new Error("invalid private key");
22290
22823
  const seedArgs = [int2octets(d2), int2octets(h1int)];
22291
22824
  if (extraEntropy != null && extraEntropy !== false) {
22292
- const e2 = extraEntropy === true ? randomBytes22(lengths.secretKey) : extraEntropy;
22825
+ const e2 = extraEntropy === true ? randomBytes23(lengths.secretKey) : extraEntropy;
22293
22826
  seedArgs.push(abytes(e2, void 0, "extraEntropy"));
22294
22827
  }
22295
22828
  const seed = concatBytes(...seedArgs);
@@ -46871,7 +47404,7 @@ var init_connection_monitor = __esm({
46871
47404
  const bs = byteStream(stream);
46872
47405
  start2 = Date.now();
46873
47406
  await Promise.all([
46874
- bs.write(randomBytes6(PING_LENGTH), {
47407
+ bs.write(randomBytes7(PING_LENGTH), {
46875
47408
  signal
46876
47409
  }),
46877
47410
  bs.read({
@@ -47383,7 +47916,7 @@ var init_random_walk = __esm({
47383
47916
  this.log("start walk");
47384
47917
  while (this.walkers > 0) {
47385
47918
  try {
47386
- const data = randomBytes6(32);
47919
+ const data = randomBytes7(32);
47387
47920
  let s2 = Date.now();
47388
47921
  for await (const peer of this.peerRouting.getClosestPeers(data, { signal })) {
47389
47922
  if (signal.aborted) {
@@ -53070,12 +53603,12 @@ async function exportToPem(privateKey, password) {
53070
53603
  });
53071
53604
  const keyBuf = keyWrapper.toBER();
53072
53605
  const keyArr = new Uint8Array(keyBuf, 0, keyBuf.byteLength);
53073
- const salt = randomBytes6(SALT_LENGTH);
53606
+ const salt = randomBytes7(SALT_LENGTH);
53074
53607
  const encryptionKey = await pbkdf2Async(sha5122, password, salt, {
53075
53608
  c: ITERATIONS,
53076
53609
  dkLen: KEY_SIZE
53077
53610
  });
53078
- const iv = randomBytes6(16);
53611
+ const iv = randomBytes7(16);
53079
53612
  const cryptoKey = await crypto14.subtle.importKey("raw", encryptionKey, "AES-CBC", false, ["encrypt"]);
53080
53613
  const encrypted = await crypto14.subtle.encrypt({
53081
53614
  name: "AES-CBC",
@@ -53373,7 +53906,7 @@ var init_keychain = __esm({
53373
53906
  const options2 = Object.assign({}, this.options);
53374
53907
  const saltLength = Math.ceil(NIST.minSaltLength / 3) * 3;
53375
53908
  if (options2.dek != null) {
53376
- options2.dek.salt = toString2(randomBytes6(saltLength), "base64");
53909
+ options2.dek.salt = toString2(randomBytes7(saltLength), "base64");
53377
53910
  }
53378
53911
  return options2;
53379
53912
  }
@@ -54864,7 +55397,7 @@ function montgomery(curveDef) {
54864
55397
  const is25519 = type === "x25519";
54865
55398
  if (!is25519 && type !== "x448")
54866
55399
  throw new Error("invalid type");
54867
- const randomBytes_ = rand || randomBytes5;
55400
+ const randomBytes_ = rand || randomBytes6;
54868
55401
  const montgomeryBits = is25519 ? 255 : 448;
54869
55402
  const fieldLen = is25519 ? 32 : 56;
54870
55403
  const Gu = is25519 ? BigInt(9) : BigInt(5);
@@ -58799,9 +59332,9 @@ var init_cookies = __esm({
58799
59332
 
58800
59333
  // ../node_modules/@libp2p/http-peer-id-auth/dist/src/utils.js
58801
59334
  function generateChallenge() {
58802
- const randomBytes22 = new Uint8Array(32);
58803
- crypto.getRandomValues(randomBytes22);
58804
- return toString2(randomBytes22, "base64urlpad");
59335
+ const randomBytes23 = new Uint8Array(32);
59336
+ crypto.getRandomValues(randomBytes23);
59337
+ return toString2(randomBytes23, "base64urlpad");
58805
59338
  }
58806
59339
  function encodeAuthParams(params) {
58807
59340
  const encodedParams = Object.entries(params).map(([key, value2]) => `${key}="${value2}"`).join(", ");
@@ -87999,7 +88532,7 @@ var require_auto = __commonJS({
87999
88532
  // ../node_modules/acme-client/src/client.js
88000
88533
  var require_client = __commonJS({
88001
88534
  "../node_modules/acme-client/src/client.js"(exports, module) {
88002
- var { createHash: createHash9 } = __require("crypto");
88535
+ var { createHash: createHash10 } = __require("crypto");
88003
88536
  var { getPemBodyAsB64u } = require_crypto();
88004
88537
  var { log: log22 } = require_logger();
88005
88538
  var HttpClient = require_http();
@@ -88310,14 +88843,14 @@ var require_client = __commonJS({
88310
88843
  */
88311
88844
  async getChallengeKeyAuthorization(challenge) {
88312
88845
  const jwk = this.http.getJwk();
88313
- const keysum = createHash9("sha256").update(JSON.stringify(jwk));
88846
+ const keysum = createHash10("sha256").update(JSON.stringify(jwk));
88314
88847
  const thumbprint = keysum.digest("base64url");
88315
88848
  const result = `${challenge.token}.${thumbprint}`;
88316
88849
  if (challenge.type === "http-01") {
88317
88850
  return result;
88318
88851
  }
88319
88852
  if (challenge.type === "dns-01") {
88320
- return createHash9("sha256").update(result).digest("base64url");
88853
+ return createHash10("sha256").update(result).digest("base64url");
88321
88854
  }
88322
88855
  if (challenge.type === "tls-alpn-01") {
88323
88856
  return result;
@@ -206664,7 +207197,7 @@ var init_refresh = __esm({
206664
207197
  if (this.routingTable.kb.localPeer == null) {
206665
207198
  throw new Error("Local peer not set");
206666
207199
  }
206667
- const randomData = randomBytes6(2);
207200
+ const randomData = randomBytes7(2);
206668
207201
  const randomUint16 = (randomData[1] << 8) + randomData[0];
206669
207202
  const key = this._makePeerId(this.routingTable.kb.localPeer.kadId, randomUint16, targetCommonPrefixLength);
206670
207203
  const multihash = decode7(key);
@@ -210841,7 +211374,7 @@ var init_ping2 = __esm({
210841
211374
  * Ping a given peer and wait for its response, getting the operation latency.
210842
211375
  */
210843
211376
  async ping(peer, options2 = {}) {
210844
- const data = randomBytes6(PING_LENGTH2);
211377
+ const data = randomBytes7(PING_LENGTH2);
210845
211378
  const stream = await this.components.connectionManager.openStream(peer, this.protocol, {
210846
211379
  runOnLimitedConnection: this.runOnLimitedConnection,
210847
211380
  ...options2
@@ -230997,7 +231530,7 @@ var require_websocket2 = __commonJS({
230997
231530
  var http6 = __require("http");
230998
231531
  var net5 = __require("net");
230999
231532
  var tls2 = __require("tls");
231000
- var { randomBytes: randomBytes22, createHash: createHash9 } = __require("crypto");
231533
+ var { randomBytes: randomBytes23, createHash: createHash10 } = __require("crypto");
231001
231534
  var { Duplex: Duplex3, Readable } = __require("stream");
231002
231535
  var { URL: URL3 } = __require("url");
231003
231536
  var PerMessageDeflate2 = require_permessage_deflate2();
@@ -231527,7 +232060,7 @@ var require_websocket2 = __commonJS({
231527
232060
  }
231528
232061
  }
231529
232062
  const defaultPort = isSecure ? 443 : 80;
231530
- const key = randomBytes22(16).toString("base64");
232063
+ const key = randomBytes23(16).toString("base64");
231531
232064
  const request = isSecure ? https4.request : http6.request;
231532
232065
  const protocolSet = /* @__PURE__ */ new Set();
231533
232066
  let perMessageDeflate;
@@ -231657,7 +232190,7 @@ var require_websocket2 = __commonJS({
231657
232190
  abortHandshake(websocket, socket, "Invalid Upgrade header");
231658
232191
  return;
231659
232192
  }
231660
- const digest3 = createHash9("sha1").update(key + GUID).digest("base64");
232193
+ const digest3 = createHash10("sha1").update(key + GUID).digest("base64");
231661
232194
  if (res.headers["sec-websocket-accept"] !== digest3) {
231662
232195
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
231663
232196
  return;
@@ -232024,7 +232557,7 @@ var require_websocket_server = __commonJS({
232024
232557
  var EventEmitter10 = __require("events");
232025
232558
  var http6 = __require("http");
232026
232559
  var { Duplex: Duplex3 } = __require("stream");
232027
- var { createHash: createHash9 } = __require("crypto");
232560
+ var { createHash: createHash10 } = __require("crypto");
232028
232561
  var extension2 = require_extension2();
232029
232562
  var PerMessageDeflate2 = require_permessage_deflate2();
232030
232563
  var subprotocol2 = require_subprotocol();
@@ -232325,7 +232858,7 @@ var require_websocket_server = __commonJS({
232325
232858
  );
232326
232859
  }
232327
232860
  if (this._state > RUNNING) return abortHandshake(socket, 503);
232328
- const digest3 = createHash9("sha1").update(key + GUID).digest("base64");
232861
+ const digest3 = createHash10("sha1").update(key + GUID).digest("base64");
232329
232862
  const headers = [
232330
232863
  "HTTP/1.1 101 Switching Protocols",
232331
232864
  "Upgrade: websocket",
@@ -245132,13 +245665,13 @@ Justification: ${justification || "(none provided)"}`,
245132
245665
  }
245133
245666
  const snapshot = JSON.stringify(this.selfState, null, 2);
245134
245667
  try {
245135
- const { createHash: createHash9 } = await import("node:crypto");
245668
+ const { createHash: createHash10 } = await import("node:crypto");
245136
245669
  const snapshotDir = join23(this.cwd, ".oa", "identity", "snapshots");
245137
245670
  await mkdir6(snapshotDir, { recursive: true });
245138
245671
  const version4 = this.selfState.version;
245139
245672
  const snapshotPath = join23(snapshotDir, `v${version4}.json`);
245140
245673
  await writeFile11(snapshotPath, snapshot, "utf8");
245141
- const hash = createHash9("sha256").update(snapshot).digest("hex");
245674
+ const hash = createHash10("sha256").update(snapshot).digest("hex");
245142
245675
  await writeFile11(join23(this.cwd, ".oa", "identity", "latest-hash.txt"), hash, "utf8");
245143
245676
  let ipfsCid = "";
245144
245677
  try {
@@ -245271,8 +245804,8 @@ New: ${newNarrative.slice(0, 200)}...`,
245271
245804
  }
245272
245805
  // ── Helpers ──────────────────────────────────────────────────────────────
245273
245806
  createDefaultState() {
245274
- const { createHash: createHash9 } = __require("node:crypto");
245275
- const machineId = createHash9("sha256").update(this.cwd).digest("hex").slice(0, 12);
245807
+ const { createHash: createHash10 } = __require("node:crypto");
245808
+ const machineId = createHash10("sha256").update(this.cwd).digest("hex").slice(0, 12);
245276
245809
  return {
245277
245810
  self_id: `oa-${machineId}`,
245278
245811
  version: 1,
@@ -245354,9 +245887,9 @@ New: ${newNarrative.slice(0, 200)}...`,
245354
245887
  let cid;
245355
245888
  if (this.selfState.version > prevVersion) {
245356
245889
  try {
245357
- const { createHash: createHash9 } = await import("node:crypto");
245890
+ const { createHash: createHash10 } = await import("node:crypto");
245358
245891
  const stateJson = JSON.stringify(this.selfState);
245359
- const hash = createHash9("sha256").update(stateJson).digest("hex").slice(0, 32);
245892
+ const hash = createHash10("sha256").update(stateJson).digest("hex").slice(0, 32);
245360
245893
  const cidsPath = join23(this.cwd, ".oa", "identity", "cids.json");
245361
245894
  const cidsData = { latest: "", hash, version: this.selfState.version };
245362
245895
  try {
@@ -245400,7 +245933,7 @@ import { spawn as spawn7 } from "node:child_process";
245400
245933
  import { createServer as createServer2 } from "node:net";
245401
245934
  import { join as join24 } from "node:path";
245402
245935
  import { tmpdir as tmpdir4 } from "node:os";
245403
- import { randomBytes as randomBytes8 } from "node:crypto";
245936
+ import { randomBytes as randomBytes9 } from "node:crypto";
245404
245937
  import { unlinkSync as unlinkSync3 } from "node:fs";
245405
245938
  var ReplTool;
245406
245939
  var init_repl = __esm({
@@ -245468,7 +246001,7 @@ var init_repl = __esm({
245468
246001
  if (!this.proc || this.proc.killed || this.proc.exitCode !== null) {
245469
246002
  await this.startProcess();
245470
246003
  }
245471
- const tempFile = join24(tmpdir4(), `oa-repl-ctx-${randomBytes8(6).toString("hex")}.txt`);
246004
+ const tempFile = join24(tmpdir4(), `oa-repl-ctx-${randomBytes9(6).toString("hex")}.txt`);
245472
246005
  const { writeFileSync: writeFs, unlinkSync: unlinkFs } = await import("node:fs");
245473
246006
  writeFs(tempFile, content, "utf8");
245474
246007
  const result = await this.executeCode(`with open(${JSON.stringify(tempFile)}, "r") as _f:
@@ -245668,7 +246201,7 @@ print("__OA_REPL_READY__")
245668
246201
  async startIpcServer() {
245669
246202
  if (this.ipcServer)
245670
246203
  return;
245671
- const sockId = randomBytes8(8).toString("hex");
246204
+ const sockId = randomBytes9(8).toString("hex");
245672
246205
  this.ipcPath = join24(tmpdir4(), `oa-repl-ipc-${sockId}.sock`);
245673
246206
  return new Promise((resolve39, reject) => {
245674
246207
  this.ipcServer = createServer2((conn) => {
@@ -245754,7 +246287,7 @@ print("__OA_REPL_READY__")
245754
246287
  resolve39({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
245755
246288
  return;
245756
246289
  }
245757
- const sentinel = `__OA_SENTINEL_${randomBytes8(6).toString("hex")}__`;
246290
+ const sentinel = `__OA_SENTINEL_${randomBytes9(6).toString("hex")}__`;
245758
246291
  let stdout = "";
245759
246292
  let stderr = "";
245760
246293
  let resolved = false;
@@ -250817,7 +251350,7 @@ import { execSync as execSync22, exec as execCb } from "node:child_process";
250817
251350
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir12 } from "node:fs/promises";
250818
251351
  import { resolve as resolve24, join as join37 } from "node:path";
250819
251352
  import { homedir as homedir10 } from "node:os";
250820
- import { randomBytes as randomBytes9 } from "node:crypto";
251353
+ import { randomBytes as randomBytes10 } from "node:crypto";
250821
251354
  function isValidCron(expr) {
250822
251355
  const parts = expr.trim().split(/\s+/);
250823
251356
  if (parts.length !== 5)
@@ -251085,7 +251618,7 @@ var init_scheduler = __esm({
251085
251618
  durationMs: performance.now() - start2
251086
251619
  };
251087
251620
  }
251088
- const id = `sched-${randomBytes9(4).toString("hex")}`;
251621
+ const id = `sched-${randomBytes10(4).toString("hex")}`;
251089
251622
  const oneShot = Boolean(args["one_shot"]);
251090
251623
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
251091
251624
  const scope = String(args["scope"] ?? "local");
@@ -251244,7 +251777,7 @@ ${truncated}`, durationMs: performance.now() - start2 };
251244
251777
  // packages/execution/dist/tools/reminder.js
251245
251778
  import { readFile as readFile16, writeFile as writeFile18, mkdir as mkdir13 } from "node:fs/promises";
251246
251779
  import { resolve as resolve25, join as join38 } from "node:path";
251247
- import { randomBytes as randomBytes10 } from "node:crypto";
251780
+ import { randomBytes as randomBytes11 } from "node:crypto";
251248
251781
  function parseDueTime(due) {
251249
251782
  const lower = due.toLowerCase().trim();
251250
251783
  const now = /* @__PURE__ */ new Date();
@@ -251441,7 +251974,7 @@ var init_reminder = __esm({
251441
251974
  dueAt = parsed.isoDate;
251442
251975
  dueDescription = parsed.description;
251443
251976
  }
251444
- const id = `rem-${randomBytes10(4).toString("hex")}`;
251977
+ const id = `rem-${randomBytes11(4).toString("hex")}`;
251445
251978
  const entry = {
251446
251979
  id,
251447
251980
  message: message2,
@@ -251557,7 +252090,7 @@ var init_reminder = __esm({
251557
252090
  // packages/execution/dist/tools/agenda.js
251558
252091
  import { readFile as readFile17, writeFile as writeFile19, mkdir as mkdir14 } from "node:fs/promises";
251559
252092
  import { resolve as resolve26, join as join39 } from "node:path";
251560
- import { randomBytes as randomBytes11 } from "node:crypto";
252093
+ import { randomBytes as randomBytes12 } from "node:crypto";
251561
252094
  async function loadAttentionStore(workingDir) {
251562
252095
  const storePath = resolve26(workingDir, ".oa", "scheduled", "attention.json");
251563
252096
  try {
@@ -251760,7 +252293,7 @@ ${sections.join("\n")}`,
251760
252293
  expiresAt = target.toISOString();
251761
252294
  }
251762
252295
  }
251763
- const id = `attn-${randomBytes11(4).toString("hex")}`;
252296
+ const id = `attn-${randomBytes12(4).toString("hex")}`;
251764
252297
  const item = {
251765
252298
  id,
251766
252299
  title,
@@ -252466,7 +252999,7 @@ import { execSync as execSync25 } from "node:child_process";
252466
252999
  import { readFile as readFile18, writeFile as writeFile20, mkdir as mkdir15 } from "node:fs/promises";
252467
253000
  import { resolve as resolve28, join as join42 } from "node:path";
252468
253001
  import { homedir as homedir11 } from "node:os";
252469
- import { randomBytes as randomBytes12 } from "node:crypto";
253002
+ import { randomBytes as randomBytes13 } from "node:crypto";
252470
253003
  function isValidCron2(expr) {
252471
253004
  const parts = expr.trim().split(/\s+/);
252472
253005
  if (parts.length !== 5)
@@ -252756,7 +253289,7 @@ var init_cron_agent = __esm({
252756
253289
  durationMs: performance.now() - start2
252757
253290
  };
252758
253291
  }
252759
- const id = `cron-${randomBytes12(4).toString("hex")}`;
253292
+ const id = `cron-${randomBytes13(4).toString("hex")}`;
252760
253293
  const verifyCommand = args["verify_command"] ? String(args["verify_command"]) : void 0;
252761
253294
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : 0;
252762
253295
  const tags = Array.isArray(args["tags"]) ? args["tags"] : [];
@@ -253557,7 +254090,7 @@ var init_working_notes = __esm({
253557
254090
  import { existsSync as existsSync27, readFileSync as readFileSync20, writeFileSync as writeFileSync11, mkdirSync as mkdirSync10, renameSync, unlinkSync as unlinkSync5, readdirSync as readdirSync6 } from "node:fs";
253558
254091
  import { join as join43 } from "node:path";
253559
254092
  import { homedir as homedir12 } from "node:os";
253560
- import { randomBytes as randomBytes13 } from "node:crypto";
254093
+ import { randomBytes as randomBytes14 } from "node:crypto";
253561
254094
  function setTodoEventPublisher(pub) {
253562
254095
  _eventPublisher = pub;
253563
254096
  }
@@ -253593,7 +254126,7 @@ function writeTodos(sessionId, incoming) {
253593
254126
  const oldById = new Map(old.map((t2) => [t2.id, t2]));
253594
254127
  const now = Date.now();
253595
254128
  const newTodos = incoming.map((t2) => {
253596
- const id = t2.id || `todo-${randomBytes13(4).toString("hex")}`;
254129
+ const id = t2.id || `todo-${randomBytes14(4).toString("hex")}`;
253597
254130
  const existing = oldById.get(id);
253598
254131
  const next = {
253599
254132
  id,
@@ -259166,7 +259699,7 @@ Audio file: ${audioFile}`,
259166
259699
 
259167
259700
  // packages/execution/dist/tools/full-sub-agent.js
259168
259701
  import { spawn as spawn14, ChildProcess } from "node:child_process";
259169
- import { randomBytes as randomBytes14 } from "node:crypto";
259702
+ import { randomBytes as randomBytes15 } from "node:crypto";
259170
259703
  function buildSubProcessArgs(opts) {
259171
259704
  const args = [];
259172
259705
  args.push(opts.task);
@@ -259194,7 +259727,7 @@ function findOaBinary3() {
259194
259727
  return "oa";
259195
259728
  }
259196
259729
  function spawnFullSubAgent(task, opts, onOutput, onComplete) {
259197
- const id = `oa-fl-${randomBytes14(2).toString("hex")}`;
259730
+ const id = `oa-fl-${randomBytes15(2).toString("hex")}`;
259198
259731
  const oaBin = findOaBinary3();
259199
259732
  const cliArgs = buildSubProcessArgs({
259200
259733
  task,
@@ -261619,7 +262152,7 @@ var init_environment_snapshot = __esm({
261619
262152
  import { execSync as execSync42 } from "node:child_process";
261620
262153
  import { existsSync as existsSync43, mkdirSync as mkdirSync22, writeFileSync as writeFileSync20, readFileSync as readFileSync33, readdirSync as readdirSync10, unlinkSync as unlinkSync10 } from "node:fs";
261621
262154
  import { join as join57, basename as basename11 } from "node:path";
261622
- import { createHash as createHash2 } from "node:crypto";
262155
+ import { createHash as createHash3 } from "node:crypto";
261623
262156
  function isYouTubeUrl2(url) {
261624
262157
  return /(?:youtube\.com\/(?:watch|shorts|live|embed|v\/)|youtu\.be\/)/i.test(url);
261625
262158
  }
@@ -261647,7 +262180,7 @@ function ensureFfmpeg() {
261647
262180
  function imageHash(imagePath) {
261648
262181
  try {
261649
262182
  const data = readFileSync33(imagePath);
261650
- return createHash2("md5").update(data).digest("hex").slice(0, 12);
262183
+ return createHash3("md5").update(data).digest("hex").slice(0, 12);
261651
262184
  } catch {
261652
262185
  return "unknown";
261653
262186
  }
@@ -266900,7 +267433,7 @@ var init_toolPatternStore = __esm({
266900
267433
  import { join as join64 } from "node:path";
266901
267434
  import { mkdirSync as mkdirSync25, existsSync as existsSync48 } from "node:fs";
266902
267435
  import { randomUUID as randomUUID7 } from "node:crypto";
266903
- import { createHash as createHash3 } from "node:crypto";
267436
+ import { createHash as createHash4 } from "node:crypto";
266904
267437
  function sanitizeImportance(raw, fallback = 5) {
266905
267438
  if (typeof raw !== "number" || !Number.isFinite(raw))
266906
267439
  return fallback;
@@ -267008,7 +267541,7 @@ var init_episodeStore = __esm({
267008
267541
  insert(ep) {
267009
267542
  const id = randomUUID7();
267010
267543
  const now = Date.now();
267011
- const contentHash = createHash3("sha256").update(ep.content).digest("hex").slice(0, 16);
267544
+ const contentHash = createHash4("sha256").update(ep.content).digest("hex").slice(0, 16);
267012
267545
  const modality = ep.modality ?? "text";
267013
267546
  const rawImportance = ep.importance ?? autoImportance(ep.toolName ?? null, modality, ep.content);
267014
267547
  const importance = sanitizeImportance(rawImportance);
@@ -273920,7 +274453,7 @@ import { existsSync as existsSync50, statSync as statSync14, openSync, readSync,
273920
274453
  import { watch as fsWatch } from "node:fs";
273921
274454
  import { join as join66 } from "node:path";
273922
274455
  import { tmpdir as tmpdir17 } from "node:os";
273923
- import { randomBytes as randomBytes15 } from "node:crypto";
274456
+ import { randomBytes as randomBytes16 } from "node:crypto";
273924
274457
  var NexusAgenticBackend;
273925
274458
  var init_nexusBackend = __esm({
273926
274459
  "packages/orchestrator/dist/nexusBackend.js"() {
@@ -274068,7 +274601,7 @@ var init_nexusBackend = __esm({
274068
274601
  * Falls back to unary + word-split if streaming setup fails.
274069
274602
  */
274070
274603
  async *chatCompletionStream(request) {
274071
- const streamFile = join66(tmpdir17(), `nexus-stream-${randomBytes15(6).toString("hex")}.jsonl`);
274604
+ const streamFile = join66(tmpdir17(), `nexus-stream-${randomBytes16(6).toString("hex")}.jsonl`);
274072
274605
  writeFileSync23(streamFile, "", "utf8");
274073
274606
  const daemonArgs = {
274074
274607
  model: this.model,
@@ -274167,7 +274700,7 @@ var init_nexusBackend = __esm({
274167
274700
  }
274168
274701
  yield {
274169
274702
  type: "tool_call_delta",
274170
- toolCallId: tc.id || `call_${randomBytes15(8).toString("hex")}`,
274703
+ toolCallId: tc.id || `call_${randomBytes16(8).toString("hex")}`,
274171
274704
  toolCallName: fn.name,
274172
274705
  toolCallArgs: JSON.stringify(args)
274173
274706
  };
@@ -274263,7 +274796,7 @@ var init_nexusBackend = __esm({
274263
274796
  yield {
274264
274797
  type: "tool_call_delta",
274265
274798
  toolCallIndex: i2,
274266
- toolCallId: tc.id || `call_${randomBytes15(8).toString("hex")}`,
274799
+ toolCallId: tc.id || `call_${randomBytes16(8).toString("hex")}`,
274267
274800
  toolCallName: fn.name,
274268
274801
  toolCallArgs: JSON.stringify(args)
274269
274802
  };
@@ -279367,7 +279900,7 @@ var require_websocket3 = __commonJS({
279367
279900
  var http6 = __require("http");
279368
279901
  var net5 = __require("net");
279369
279902
  var tls2 = __require("tls");
279370
- var { randomBytes: randomBytes22, createHash: createHash9 } = __require("crypto");
279903
+ var { randomBytes: randomBytes23, createHash: createHash10 } = __require("crypto");
279371
279904
  var { Duplex: Duplex3, Readable } = __require("stream");
279372
279905
  var { URL: URL3 } = __require("url");
279373
279906
  var PerMessageDeflate2 = require_permessage_deflate3();
@@ -279897,7 +280430,7 @@ var require_websocket3 = __commonJS({
279897
280430
  }
279898
280431
  }
279899
280432
  const defaultPort = isSecure ? 443 : 80;
279900
- const key = randomBytes22(16).toString("base64");
280433
+ const key = randomBytes23(16).toString("base64");
279901
280434
  const request = isSecure ? https4.request : http6.request;
279902
280435
  const protocolSet = /* @__PURE__ */ new Set();
279903
280436
  let perMessageDeflate;
@@ -280027,7 +280560,7 @@ var require_websocket3 = __commonJS({
280027
280560
  abortHandshake(websocket, socket, "Invalid Upgrade header");
280028
280561
  return;
280029
280562
  }
280030
- const digest3 = createHash9("sha1").update(key + GUID).digest("base64");
280563
+ const digest3 = createHash10("sha1").update(key + GUID).digest("base64");
280031
280564
  if (res.headers["sec-websocket-accept"] !== digest3) {
280032
280565
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
280033
280566
  return;
@@ -280394,7 +280927,7 @@ var require_websocket_server2 = __commonJS({
280394
280927
  var EventEmitter10 = __require("events");
280395
280928
  var http6 = __require("http");
280396
280929
  var { Duplex: Duplex3 } = __require("stream");
280397
- var { createHash: createHash9 } = __require("crypto");
280930
+ var { createHash: createHash10 } = __require("crypto");
280398
280931
  var extension2 = require_extension3();
280399
280932
  var PerMessageDeflate2 = require_permessage_deflate3();
280400
280933
  var subprotocol2 = require_subprotocol2();
@@ -280695,7 +281228,7 @@ var require_websocket_server2 = __commonJS({
280695
281228
  );
280696
281229
  }
280697
281230
  if (this._state > RUNNING) return abortHandshake(socket, 503);
280698
- const digest3 = createHash9("sha1").update(key + GUID).digest("base64");
281231
+ const digest3 = createHash10("sha1").update(key + GUID).digest("base64");
280699
281232
  const headers = [
280700
281233
  "HTTP/1.1 101 Switching Protocols",
280701
281234
  "Upgrade: websocket",
@@ -283209,7 +283742,7 @@ var init_voice_session = __esm({
283209
283742
  import { createServer as createServer4, request as httpRequest } from "node:http";
283210
283743
  import { spawn as spawn20, exec as exec2 } from "node:child_process";
283211
283744
  import { EventEmitter as EventEmitter5 } from "node:events";
283212
- import { randomBytes as randomBytes16 } from "node:crypto";
283745
+ import { randomBytes as randomBytes17 } from "node:crypto";
283213
283746
  import { URL as URL2 } from "node:url";
283214
283747
  import { loadavg, cpus as cpus2, totalmem as totalmem2, freemem as freemem2 } from "node:os";
283215
283748
  import { existsSync as existsSync53, readFileSync as readFileSync39, writeFileSync as writeFileSync26, unlinkSync as unlinkSync13, mkdirSync as mkdirSync29, readdirSync as readdirSync13, statSync as statSync15 } from "node:fs";
@@ -283409,7 +283942,7 @@ var init_expose = __esm({
283409
283942
  this._stateDir = options2.stateDir ?? null;
283410
283943
  this._fullAccess = options2.fullAccess ?? false;
283411
283944
  if (options2.authKey === void 0 || options2.authKey === "") {
283412
- this._authKey = randomBytes16(24).toString("base64url");
283945
+ this._authKey = randomBytes17(24).toString("base64url");
283413
283946
  } else {
283414
283947
  this._authKey = options2.authKey;
283415
283948
  }
@@ -284321,7 +284854,7 @@ ${this.formatConnectionInfo()}`);
284321
284854
  this._onInfo = options2.onInfo;
284322
284855
  this._onError = options2.onError;
284323
284856
  if (options2.authKey === void 0 || options2.authKey === "") {
284324
- this._authKey = randomBytes16(24).toString("base64url");
284857
+ this._authKey = randomBytes17(24).toString("base64url");
284325
284858
  } else {
284326
284859
  this._authKey = options2.authKey;
284327
284860
  }
@@ -284764,7 +285297,7 @@ var init_types = __esm({
284764
285297
  });
284765
285298
 
284766
285299
  // packages/cli/src/tui/p2p/secret-vault.ts
284767
- import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes17, scryptSync as scryptSync2, createHash as createHash4 } from "node:crypto";
285300
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync2, createHash as createHash5 } from "node:crypto";
284768
285301
  import { readFileSync as readFileSync40, writeFileSync as writeFileSync27, existsSync as existsSync54, mkdirSync as mkdirSync30 } from "node:fs";
284769
285302
  import { dirname as dirname18 } from "node:path";
284770
285303
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -284965,10 +285498,10 @@ var init_secret_vault = __esm({
284965
285498
  createdAt: s2.createdAt
284966
285499
  }))
284967
285500
  );
284968
- const salt = randomBytes17(SALT_LEN);
285501
+ const salt = randomBytes18(SALT_LEN);
284969
285502
  const key = scryptSync2(passphrase, salt, KEY_LEN);
284970
- const iv = randomBytes17(IV_LEN);
284971
- const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
285503
+ const iv = randomBytes18(IV_LEN);
285504
+ const cipher = createCipheriv3(CIPHER_ALGO, key, iv);
284972
285505
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
284973
285506
  const tag = cipher.getAuthTag();
284974
285507
  const blob = Buffer.concat([salt, iv, tag, encrypted]);
@@ -284991,7 +285524,7 @@ var init_secret_vault = __esm({
284991
285524
  const tag = blob.subarray(SALT_LEN + IV_LEN, SALT_LEN + IV_LEN + 16);
284992
285525
  const encrypted = blob.subarray(SALT_LEN + IV_LEN + 16);
284993
285526
  const key = scryptSync2(passphrase, salt, KEY_LEN);
284994
- const decipher = createDecipheriv2(CIPHER_ALGO, key, iv);
285527
+ const decipher = createDecipheriv3(CIPHER_ALGO, key, iv);
284995
285528
  decipher.setAuthTag(tag);
284996
285529
  let data;
284997
285530
  try {
@@ -285008,7 +285541,7 @@ var init_secret_vault = __esm({
285008
285541
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
285009
285542
  fingerprint() {
285010
285543
  const names = Array.from(this.secrets.keys()).sort();
285011
- const hash = createHash4("sha256");
285544
+ const hash = createHash5("sha256");
285012
285545
  for (const name10 of names) {
285013
285546
  hash.update(name10 + ":");
285014
285547
  hash.update(this.secrets.get(name10).value);
@@ -285023,7 +285556,7 @@ var init_secret_vault = __esm({
285023
285556
  // packages/cli/src/tui/p2p/peer-mesh.ts
285024
285557
  import { EventEmitter as EventEmitter6 } from "node:events";
285025
285558
  import { createServer as createServer5 } from "node:http";
285026
- import { randomBytes as randomBytes18, createHash as createHash5, generateKeyPairSync } from "node:crypto";
285559
+ import { randomBytes as randomBytes19, createHash as createHash6, generateKeyPairSync } from "node:crypto";
285027
285560
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
285028
285561
  var init_peer_mesh = __esm({
285029
285562
  "packages/cli/src/tui/p2p/peer-mesh.ts"() {
@@ -285040,10 +285573,10 @@ var init_peer_mesh = __esm({
285040
285573
  const { publicKey: publicKey2, privateKey } = generateKeyPairSync("ed25519");
285041
285574
  this.publicKey = publicKey2.export({ type: "spki", format: "der" });
285042
285575
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
285043
- this.peerId = createHash5("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
285576
+ this.peerId = createHash6("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
285044
285577
  this.capabilities = options2.capabilities;
285045
285578
  this.displayName = options2.displayName;
285046
- this._authKey = options2.authKey ?? randomBytes18(24).toString("base64url");
285579
+ this._authKey = options2.authKey ?? randomBytes19(24).toString("base64url");
285047
285580
  }
285048
285581
  /** This node's unique peer ID (hash of public key) */
285049
285582
  peerId;
@@ -285236,7 +285769,7 @@ var init_peer_mesh = __esm({
285236
285769
  if (!ws || ws.readyState !== import_websocket5.default.OPEN) {
285237
285770
  throw new Error(`Peer ${peerId} not connected`);
285238
285771
  }
285239
- const msgId = randomBytes18(8).toString("hex");
285772
+ const msgId = randomBytes19(8).toString("hex");
285240
285773
  return new Promise((resolve39, reject) => {
285241
285774
  const timeout2 = setTimeout(() => {
285242
285775
  this.pendingRequests.delete(msgId);
@@ -285452,7 +285985,7 @@ var init_peer_mesh = __esm({
285452
285985
  const msg = {
285453
285986
  type,
285454
285987
  from: this.peerId,
285455
- msgId: msgId ?? randomBytes18(8).toString("hex"),
285988
+ msgId: msgId ?? randomBytes19(8).toString("hex"),
285456
285989
  ts: (/* @__PURE__ */ new Date()).toISOString(),
285457
285990
  payload
285458
285991
  };
@@ -289057,6 +289590,14 @@ var init_status_bar = __esm({
289057
289590
  _contentScrollOffset = 0;
289058
289591
  // 0 = live (bottom), >0 = scrolled back
289059
289592
  _contentMaxLines = 1e4;
289593
+ // Partial-line accumulator for the buffered-write layer. Stream output
289594
+ // arrives in chunks (one per syntax-highlighted token) and a single
289595
+ // logical line can span many writes. If we naively push each chunk to
289596
+ // _contentLines, scroll-back replay fragments the line across rows and
289597
+ // "injects" extra newlines between pieces. Instead, everything up to the
289598
+ // last \n goes into _contentLines (as complete lines), and the trailing
289599
+ // partial stays in _inProgressLine until the next \n arrives.
289600
+ _inProgressLine = "";
289060
289601
  /** Auto-scroll to live when new content arrives (disabled when user scrolls back) */
289061
289602
  _autoScroll = true;
289062
289603
  /** Cached click region for the spacer button */
@@ -290247,8 +290788,15 @@ var init_status_bar = __esm({
290247
290788
  const fh = this._currentFooterHeight;
290248
290789
  const footerStart = termRows() - fh + 1;
290249
290790
  if (row >= footerStart) return;
290250
- if (type === "press" || type === "drag") {
290251
- this.disableMouseTracking();
290791
+ if (type === "press") {
290792
+ this._textSelection.onMousePress(row, col);
290793
+ this.repaintContent();
290794
+ } else if (type === "drag") {
290795
+ this._textSelection.onMouseDrag(row, col);
290796
+ this.repaintContent();
290797
+ } else if (type === "release") {
290798
+ this._textSelection.onMouseRelease(row, col);
290799
+ this.repaintContent();
290252
290800
  }
290253
290801
  }
290254
290802
  /** Copy current selection to clipboard. Returns true if copied. */
@@ -290590,11 +291138,21 @@ var init_status_bar = __esm({
290590
291138
  if (typeof chunk === "string") text = chunk;
290591
291139
  else if (Buffer.isBuffer(chunk)) text = chunk.toString();
290592
291140
  else text = String(chunk);
290593
- const lines = text.split("\n");
290594
291141
  if (self2._bufferContent && !isOverlayActive()) {
290595
- for (const line of lines) {
290596
- const visible = line.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "");
290597
- if (visible.trim().length > 0) self2.bufferContentLine(line);
291142
+ const combined = self2._inProgressLine + text;
291143
+ const lastNl = combined.lastIndexOf("\n");
291144
+ if (lastNl < 0) {
291145
+ self2._inProgressLine = combined;
291146
+ } else {
291147
+ const completed = combined.slice(0, lastNl);
291148
+ self2._inProgressLine = combined.slice(lastNl + 1);
291149
+ const completeLines = completed.split("\n");
291150
+ for (const line of completeLines) {
291151
+ const visible = line.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "");
291152
+ if (line.length === 0 || visible.length > 0) {
291153
+ self2.bufferContentLine(line);
291154
+ }
291155
+ }
290598
291156
  }
290599
291157
  }
290600
291158
  if (typeof chunk === "string") {
@@ -290627,6 +291185,11 @@ ${CONTENT_BG_SEQ}`);
290627
291185
  if (!this.active) return;
290628
291186
  this.writeDepth = Math.max(0, this.writeDepth - 1);
290629
291187
  if (this.writeDepth === 0) {
291188
+ if (this._inProgressLine.length > 0) {
291189
+ const visible = this._inProgressLine.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "");
291190
+ if (visible.length > 0) this.bufferContentLine(this._inProgressLine);
291191
+ this._inProgressLine = "";
291192
+ }
290630
291193
  this._bufferContent = false;
290631
291194
  if (this._origWrite) {
290632
291195
  try {
@@ -290783,12 +291346,19 @@ ${CONTENT_BG_SEQ}`);
290783
291346
  let buf = "\x1B[?2026h";
290784
291347
  buf += "\x1B7";
290785
291348
  buf += "\x1B[?25l";
291349
+ const selRanges = this._textSelection.hasSelection ? this._textSelection.getSelectedRanges() : [];
291350
+ const selByBufferIdx = /* @__PURE__ */ new Map();
291351
+ for (const r2 of selRanges) selByBufferIdx.set(r2.bufferIdx, { startCol: r2.startCol, endCol: r2.endCol });
290786
291352
  for (let row = 0; row < h; row++) {
290787
291353
  const lineIdx = startIdx + row;
290788
291354
  let line = lineIdx < totalLines ? this._contentLines[lineIdx] : "";
290789
291355
  const screenRow = this.scrollRegionTop + row;
290790
291356
  if (screenRow < headerSafeFloor) continue;
290791
291357
  line = line.replace(/\x1B\[0m/g, `\x1B[0m${CONTENT_BG_SEQ}`);
291358
+ const sel = selByBufferIdx.get(lineIdx);
291359
+ if (sel) {
291360
+ line = TextSelection.applyHighlight(line, sel.startCol, sel.endCol);
291361
+ }
290792
291362
  buf += `\x1B[${screenRow};1H${CONTENT_BG_SEQ}\x1B[2K${line}`;
290793
291363
  }
290794
291364
  const L = layout();
@@ -314607,7 +315177,7 @@ var init_disk_task_output = __esm({
314607
315177
  });
314608
315178
 
314609
315179
  // packages/cli/src/api/http.ts
314610
- import { createHash as createHash6 } from "node:crypto";
315180
+ import { createHash as createHash7 } from "node:crypto";
314611
315181
  function problemDetails(opts) {
314612
315182
  const p2 = {
314613
315183
  type: opts.type ?? "about:blank",
@@ -314670,7 +315240,7 @@ function paginated(items, page2, total) {
314670
315240
  }
314671
315241
  function computeEtag(payload) {
314672
315242
  const json = typeof payload === "string" ? payload : JSON.stringify(payload);
314673
- const hash = createHash6("sha1").update(json).digest("hex").slice(0, 16);
315243
+ const hash = createHash7("sha1").update(json).digest("hex").slice(0, 16);
314674
315244
  return `W/"${hash}"`;
314675
315245
  }
314676
315246
  function checkNotModified(req2, res, etag) {
@@ -317237,11 +317807,11 @@ async function handleAimsIncidentPost(ctx3) {
317237
317807
  }));
317238
317808
  return true;
317239
317809
  }
317240
- const { randomBytes: randomBytes22 } = await import("node:crypto");
317810
+ const { randomBytes: randomBytes23 } = await import("node:crypto");
317241
317811
  const record = await withAimsLock("incidents.json", () => {
317242
317812
  const existing = readAimsFile("incidents.json", []);
317243
317813
  const rec = {
317244
- id: `INC-${Date.now()}-${randomBytes22(4).toString("hex")}`,
317814
+ id: `INC-${Date.now()}-${randomBytes23(4).toString("hex")}`,
317245
317815
  ts: (/* @__PURE__ */ new Date()).toISOString(),
317246
317816
  raised_by: user ?? "anonymous",
317247
317817
  status: "open",
@@ -321419,7 +321989,7 @@ var init_usage_tracker = __esm({
321419
321989
  import { existsSync as existsSync80, readFileSync as readFileSync63, writeFileSync as writeFileSync41, mkdirSync as mkdirSync48, readdirSync as readdirSync27, unlinkSync as unlinkSync21 } from "node:fs";
321420
321990
  import { join as join96 } from "node:path";
321421
321991
  import { homedir as homedir34 } from "node:os";
321422
- import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes19, scryptSync as scryptSync3 } from "node:crypto";
321992
+ import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes20, scryptSync as scryptSync3 } from "node:crypto";
321423
321993
  function globalProfileDir() {
321424
321994
  return join96(homedir34(), ".open-agents", "profiles");
321425
321995
  }
@@ -321503,10 +322073,10 @@ function deleteProfile(name10, scope = "global", projectDir) {
321503
322073
  return false;
321504
322074
  }
321505
322075
  function encryptProfile(profile, password) {
321506
- const salt = randomBytes19(32);
322076
+ const salt = randomBytes20(32);
321507
322077
  const key = scryptSync3(password, salt, 32);
321508
- const iv = randomBytes19(16);
321509
- const cipher = createCipheriv3("aes-256-gcm", key, iv);
322078
+ const iv = randomBytes20(16);
322079
+ const cipher = createCipheriv4("aes-256-gcm", key, iv);
321510
322080
  const plaintext = JSON.stringify(profile);
321511
322081
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
321512
322082
  const tag = cipher.getAuthTag();
@@ -321525,7 +322095,7 @@ function decryptProfile(enc, password) {
321525
322095
  const salt = Buffer.from(enc.salt, "hex");
321526
322096
  const key = scryptSync3(password, salt, 32);
321527
322097
  const iv = Buffer.from(enc.iv, "hex");
321528
- const decipher = createDecipheriv3("aes-256-gcm", key, iv);
322098
+ const decipher = createDecipheriv4("aes-256-gcm", key, iv);
321529
322099
  decipher.setAuthTag(Buffer.from(enc.tag, "hex"));
321530
322100
  const decrypted = Buffer.concat([
321531
322101
  decipher.update(Buffer.from(enc.data, "hex")),
@@ -321918,7 +322488,7 @@ import { dirname as dirname28, join as join98, resolve as resolve34 } from "node
321918
322488
  import { homedir as homedir36 } from "node:os";
321919
322489
  import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
321920
322490
  import { mkdirSync as mkdirSync50, readFileSync as readFileSync64, readdirSync as readdirSync28, existsSync as existsSync82, watch as fsWatch3 } from "node:fs";
321921
- import { randomBytes as randomBytes20, randomUUID as randomUUID11 } from "node:crypto";
322491
+ import { randomBytes as randomBytes21, randomUUID as randomUUID11 } from "node:crypto";
321922
322492
  function getVersion3() {
321923
322493
  try {
321924
322494
  const require3 = createRequire4(import.meta.url);
@@ -322781,7 +323351,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
322781
323351
  "Cache-Control": "no-cache",
322782
323352
  "Connection": "keep-alive"
322783
323353
  });
322784
- const chatId = `chatcmpl-${randomBytes20(12).toString("hex")}`;
323354
+ const chatId = `chatcmpl-${randomBytes21(12).toString("hex")}`;
322785
323355
  let buffer2 = "";
322786
323356
  ollamaStream(
322787
323357
  targetUrl,
@@ -322891,7 +323461,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
322891
323461
  if (ollamaResp.eval_count) metrics.totalTokensOut += ollamaResp.eval_count;
322892
323462
  if (ollamaResp.prompt_eval_count) metrics.totalTokensIn += ollamaResp.prompt_eval_count;
322893
323463
  trackTokens("local", ollamaResp.prompt_eval_count ?? 0, ollamaResp.eval_count ?? 0);
322894
- const chatId = `chatcmpl-${randomBytes20(12).toString("hex")}`;
323464
+ const chatId = `chatcmpl-${randomBytes21(12).toString("hex")}`;
322895
323465
  const responseMessage = {
322896
323466
  role: ollamaResp.message?.role ?? "assistant",
322897
323467
  content: ollamaResp.message?.content ?? ""
@@ -323623,7 +324193,7 @@ async function handleV1Run(req2, res) {
323623
324193
  return;
323624
324194
  }
323625
324195
  }
323626
- const id = `job-${randomBytes20(8).toString("hex")}`;
324196
+ const id = `job-${randomBytes21(8).toString("hex")}`;
323627
324197
  const dir = jobsDir();
323628
324198
  const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
323629
324199
  const isolate = requestBody["isolate"] === true;
@@ -328626,7 +329196,17 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
328626
329196
  statusBar.setNexusStatus("disconnected");
328627
329197
  }
328628
329198
  };
328629
- _tryNexusConnect(1);
329199
+ _tryNexusConnect(1).catch((err) => {
329200
+ try {
329201
+ statusBar.setNexusStatus("disconnected");
329202
+ } catch {
329203
+ }
329204
+ try {
329205
+ const msg = err?.message || String(err);
329206
+ writeContent(() => renderWarning(`Nexus startup: ${msg.slice(0, 160)}`));
329207
+ } catch {
329208
+ }
329209
+ });
328630
329210
  } catch {
328631
329211
  }
328632
329212
  try {
@@ -330810,13 +331390,13 @@ ${fullInput}`;
330810
331390
  writeContent(() => renderError(errMsg));
330811
331391
  if (failureStore) {
330812
331392
  try {
330813
- const { createHash: createHash9 } = await import("node:crypto");
331393
+ const { createHash: createHash10 } = await import("node:crypto");
330814
331394
  failureStore.insert({
330815
331395
  taskId: "",
330816
331396
  sessionId: `${Date.now()}`,
330817
331397
  repoRoot,
330818
331398
  failureType: "runtime-error",
330819
- fingerprint: createHash9("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
331399
+ fingerprint: createHash10("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
330820
331400
  filePath: null,
330821
331401
  errorMessage: errMsg.slice(0, 500),
330822
331402
  context: null,
@@ -331444,7 +332024,7 @@ __export(run_exports, {
331444
332024
  import { resolve as resolve36 } from "node:path";
331445
332025
  import { spawn as spawn26 } from "node:child_process";
331446
332026
  import { mkdirSync as mkdirSync52, writeFileSync as writeFileSync45, readFileSync as readFileSync66, readdirSync as readdirSync30, existsSync as existsSync84 } from "node:fs";
331447
- import { randomBytes as randomBytes21 } from "node:crypto";
332027
+ import { randomBytes as randomBytes22 } from "node:crypto";
331448
332028
  import { join as join100 } from "node:path";
331449
332029
  function jobsDir2(repoPath) {
331450
332030
  const root = resolve36(repoPath ?? process.cwd());
@@ -331539,7 +332119,7 @@ function extractSummary(captured) {
331539
332119
  return lines.slice(-3).join(" ").slice(0, 200);
331540
332120
  }
331541
332121
  async function runBackground(task, config, opts) {
331542
- const id = `job-${randomBytes21(3).toString("hex")}`;
332122
+ const id = `job-${randomBytes22(3).toString("hex")}`;
331543
332123
  const dir = jobsDir2(opts.repoPath);
331544
332124
  const repoRoot = resolve36(opts.repoPath ?? process.cwd());
331545
332125
  const job = {
@@ -331648,7 +332228,7 @@ var init_run = __esm({
331648
332228
  import { glob as glob2 } from "glob";
331649
332229
  import ignore from "ignore";
331650
332230
  import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
331651
- import { createHash as createHash8 } from "node:crypto";
332231
+ import { createHash as createHash9 } from "node:crypto";
331652
332232
  import { join as join101, relative as relative5, extname as extname12, basename as basename18 } from "node:path";
331653
332233
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
331654
332234
  var init_codebase_indexer = __esm({
@@ -331714,7 +332294,7 @@ var init_codebase_indexer = __esm({
331714
332294
  if (fileStat.size > this.config.maxFileSize)
331715
332295
  continue;
331716
332296
  const content = await readFile23(fullPath);
331717
- const hash = createHash8("sha256").update(content).digest("hex");
332297
+ const hash = createHash9("sha256").update(content).digest("hex");
331718
332298
  const ext = extname12(relativePath);
331719
332299
  indexed.push({
331720
332300
  path: fullPath,