@1presence/bridge 0.40.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.js CHANGED
@@ -1,9 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureModelChoice = ensureModelChoice;
4
- exports.getBridgeModel = getBridgeModel;
5
- const readline_1 = require("readline");
6
- const child_process_1 = require("child_process");
1
+ import { emitKeypressEvents } from 'readline';
2
+ import { spawn } from 'child_process';
7
3
  // ─── In-memory model choice ───────────────────────────────────────────────────
8
4
  //
9
5
  // The bridge prompts for a model on every interactive startup. The choice is
@@ -27,7 +23,7 @@ function detectClaudeDefaultModel() {
27
23
  } };
28
24
  let proc;
29
25
  try {
30
- proc = (0, child_process_1.spawn)('claude', [
26
+ proc = spawn('claude', [
31
27
  '-p',
32
28
  '--input-format', 'stream-json',
33
29
  '--output-format', 'stream-json',
@@ -111,7 +107,7 @@ function promptForModel(defaultModel) {
111
107
  }
112
108
  };
113
109
  render();
114
- (0, readline_1.emitKeypressEvents)(process.stdin);
110
+ emitKeypressEvents(process.stdin);
115
111
  const wasRaw = process.stdin.isRaw;
116
112
  if (process.stdin.isTTY)
117
113
  process.stdin.setRawMode(true);
@@ -172,7 +168,7 @@ function promptForModel(defaultModel) {
172
168
  * in memory only — every startup re-prompts. In a non-TTY environment the
173
169
  * prompt is skipped and Claude Code's own default is used.
174
170
  */
175
- async function ensureModelChoice() {
171
+ export async function ensureModelChoice() {
176
172
  if (!process.stdin.isTTY) {
177
173
  selectedModel = null;
178
174
  return;
@@ -187,6 +183,6 @@ async function ensureModelChoice() {
187
183
  }
188
184
  }
189
185
  /** Returns the model id chosen for this session, or null to defer to Claude Code's own default. */
190
- function getBridgeModel() {
186
+ export function getBridgeModel() {
191
187
  return selectedModel;
192
188
  }
package/dist/index.js CHANGED
@@ -1,29 +1,29 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const ws_1 = __importDefault(require("ws"));
8
- const fs_1 = require("fs");
9
- const os_1 = require("os");
10
- const path_1 = require("path");
11
- const auth_1 = require("./auth");
12
- const claude_1 = require("./claude");
13
- const config_1 = require("./config");
14
- const update_1 = require("./update");
15
- const accumulator_1 = require("./accumulator");
16
- const outbox_1 = require("./outbox");
17
- const timer_1 = require("./timer");
18
- const package_json_1 = require("../package.json");
2
+ import WebSocket from 'ws';
3
+ import { writeFileSync, chmodSync, existsSync, statSync, readdirSync } from 'fs';
4
+ import { tmpdir } from 'os';
5
+ import { join, dirname } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { createRequire } from 'module';
8
+ import { getValidAuth, ensureFreshToken, isTokenValid, AuthCancelledError } from './auth.js';
9
+ import { spawnClaude, killAll, cancelConversation, setVerbose, setDebug, paint, SECTION_COLORS } from './claude.js';
10
+ import { ensureModelChoice } from './config.js';
11
+ import { checkAndUpdate } from './update.js';
12
+ import { makeBridgeAccumulator, postSaveTurn } from './accumulator.js';
13
+ import { writeSpool, deleteSpool, listSpool } from './outbox.js';
14
+ import { startTurnTimer, stopTurnTimer, formatElapsed } from './timer.js';
15
+ // ESM has no __dirname; derive it. JSON version is read via createRequire to
16
+ // avoid version-sensitive import assertions on a published CLI bin.
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const { version } = createRequire(import.meta.url)('../package.json');
19
19
  // Published tarballs don't ship src/, so this fires only when running the
20
20
  // dist build from a live workspace checkout. Catches the trap where editing
21
21
  // src/ without re-running tsc leaves you executing stale dist code — banner
22
22
  // version matches package.json but behavior doesn't match the source.
23
23
  if (__dirname.endsWith('dist')) {
24
- const srcDir = (0, path_1.join)(__dirname, '..', 'src');
25
- if ((0, fs_1.existsSync)(srcDir)) {
26
- const newest = (dir) => Math.max(...(0, fs_1.readdirSync)(dir).map(f => (0, fs_1.statSync)((0, path_1.join)(dir, f)).mtimeMs));
24
+ const srcDir = join(__dirname, '..', 'src');
25
+ if (existsSync(srcDir)) {
26
+ const newest = (dir) => Math.max(...readdirSync(dir).map(f => statSync(join(dir, f)).mtimeMs));
27
27
  if (newest(srcDir) > newest(__dirname)) {
28
28
  console.error('Bridge dist is stale (src/ has been edited since last build). Run: npm run build');
29
29
  process.exit(1);
@@ -157,7 +157,7 @@ async function fetchSystemPrompt(token, agentSlug) {
157
157
  }
158
158
  // ─── Setup files ──────────────────────────────────────────────────────────────
159
159
  function tmpFile(name) {
160
- return (0, path_1.join)((0, os_1.tmpdir)(), name);
160
+ return join(tmpdir(), name);
161
161
  }
162
162
  // Fetch the system prompt and write it to /tmp/agent-${uid}.md. The hosted
163
163
  // runtime rebuilds buildSystemBlocks() per turn (dynamic context: vault state,
@@ -169,9 +169,9 @@ async function writeSystemPrompt(auth, agentSlug) {
169
169
  const systemPrompt = await fetchSystemPrompt(token, agentSlug);
170
170
  writeRestricted(tmpFile(`agent-${uid}.md`), systemPrompt);
171
171
  if (VERBOSE) {
172
- console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, '\n[bridge:verbose] ─── system prompt ───────────────────────'));
173
- console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, systemPrompt));
174
- console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, '[bridge:verbose] ─── end system prompt ───────────────────\n'));
172
+ console.log(paint(SECTION_COLORS.system, '\n[bridge:verbose] ─── system prompt ───────────────────────'));
173
+ console.log(paint(SECTION_COLORS.system, systemPrompt));
174
+ console.log(paint(SECTION_COLORS.system, '[bridge:verbose] ─── end system prompt ───────────────────\n'));
175
175
  }
176
176
  }
177
177
  function writeMcpConfig(auth) {
@@ -182,6 +182,12 @@ function writeMcpConfig(auth) {
182
182
  type: 'sse',
183
183
  url: `${GATEWAY_HTTP}/mcp`,
184
184
  headers: { Authorization: `Bearer ${token}` },
185
+ // Force every 1Presence tool into the prompt from turn 1. Without this the
186
+ // SDK defers MCP tools behind tool-search, so the model sees tool *names*
187
+ // (from the system prompt) but has nothing callable and confabulates the
188
+ // call + result as text. Also blocks the turn until the MCP server connects
189
+ // (5s cap) — a loud failure beats a silent tool-less run. See vault/Bugs.md.
190
+ alwaysLoad: true,
185
191
  },
186
192
  },
187
193
  };
@@ -195,8 +201,8 @@ async function writeSetupFiles(auth, agentSlug) {
195
201
  // state. writeFileSync's mode only takes effect on file creation — chmodSync
196
202
  // covers the overwrite case so a legacy 0644 file gets tightened on next run.
197
203
  function writeRestricted(path, data) {
198
- (0, fs_1.writeFileSync)(path, data, { mode: 0o600 });
199
- (0, fs_1.chmodSync)(path, 0o600);
204
+ writeFileSync(path, data, { mode: 0o600 });
205
+ chmodSync(path, 0o600);
200
206
  }
201
207
  // ─── Helpers ──────────────────────────────────────────────────────────────────
202
208
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -208,7 +214,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
208
214
  // Refresh JWT if <10 min remaining before spawning Claude
209
215
  let activeAuth = auth;
210
216
  try {
211
- const freshAuth = await (0, auth_1.ensureFreshToken)(auth);
217
+ const freshAuth = await ensureFreshToken(auth);
212
218
  if (freshAuth.token !== auth.token) {
213
219
  currentAuth = freshAuth;
214
220
  activeAuth = freshAuth;
@@ -218,11 +224,11 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
218
224
  catch (err) {
219
225
  // If the cached token still has time, proceed — refresh was preemptive.
220
226
  // If it's already invalid, MCP calls will 401 mid-turn — fail fast instead.
221
- if (!(0, auth_1.isTokenValid)(auth.token)) {
227
+ if (!isTokenValid(auth.token)) {
222
228
  const message = 'Authentication expired and refresh failed — please restart the bridge to sign in again.';
223
- (0, timer_1.stopTurnTimer)();
229
+ stopTurnTimer();
224
230
  console.error(`[bridge] ${message} (${err.message})`);
225
- if (currentWs?.readyState === ws_1.default.OPEN) {
231
+ if (currentWs?.readyState === WebSocket.OPEN) {
226
232
  currentWs.send(JSON.stringify({ type: 'error', conversationId, message }));
227
233
  }
228
234
  return;
@@ -241,15 +247,15 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
241
247
  }
242
248
  catch (err) {
243
249
  const message = `System prompt refresh failed: ${err.message}`;
244
- (0, timer_1.stopTurnTimer)();
250
+ stopTurnTimer();
245
251
  console.error(`[${new Date().toLocaleTimeString()}] ✗ ${message}`);
246
- if (currentWs?.readyState === ws_1.default.OPEN) {
252
+ if (currentWs?.readyState === WebSocket.OPEN) {
247
253
  currentWs.send(JSON.stringify({ type: 'error', conversationId, message }));
248
254
  }
249
255
  return;
250
256
  }
251
257
  let responding = false;
252
- const accumulator = (0, accumulator_1.makeBridgeAccumulator)();
258
+ const accumulator = makeBridgeAccumulator();
253
259
  const startedAt = Date.now();
254
260
  const turnSessionId = sessionId ?? conversationId; // gateway always supplies one; defensive fallback
255
261
  // The CLI's `--session-id` is treated as a "claim this new session ID"
@@ -283,14 +289,14 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
283
289
  // ack is recoverable by drain-on-startup. The gateway dedupes on
284
290
  // conversationId, so a replay is idempotent.
285
291
  try {
286
- (0, outbox_1.writeSpool)(record);
292
+ writeSpool(record);
287
293
  }
288
294
  catch (err) {
289
295
  console.warn(`[bridge] spool write failed: ${err.message}`);
290
296
  }
291
- const result = await (0, accumulator_1.postSaveTurn)(GATEWAY_HTTP, activeAuth.token, record);
297
+ const result = await postSaveTurn(GATEWAY_HTTP, activeAuth.token, record);
292
298
  if (result.ok) {
293
- (0, outbox_1.deleteSpool)(record.conversationId);
299
+ deleteSpool(record.conversationId);
294
300
  }
295
301
  else {
296
302
  // Leave the spool file in place — next startup or next successful
@@ -298,7 +304,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
298
304
  console.warn(`[bridge] save-turn POST failed (${result.status}): ${result.error ?? 'unknown'} — kept on disk for retry`);
299
305
  }
300
306
  }
301
- (0, claude_1.spawnClaude)({
307
+ spawnClaude({
302
308
  conversationId,
303
309
  presenceSessionId: claudePinnedSessionId,
304
310
  text,
@@ -313,7 +319,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
313
319
  responding = true;
314
320
  console.log(`[${new Date().toLocaleTimeString()}] ◐ responding…`);
315
321
  }
316
- if (currentWs?.readyState === ws_1.default.OPEN) {
322
+ if (currentWs?.readyState === WebSocket.OPEN) {
317
323
  currentWs.send(JSON.stringify({ type: 'stream', conversationId, event }));
318
324
  }
319
325
  },
@@ -321,13 +327,13 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
321
327
  // Ephemeral, non-persisted thread notice (admin-only Local Mode). Relayed
322
328
  // by the gateway to the PWA SSE stream as a `notice` AgentEvent; it does
323
329
  // NOT go through the turn accumulator, so it never lands in history.
324
- if (currentWs?.readyState === ws_1.default.OPEN) {
330
+ if (currentWs?.readyState === WebSocket.OPEN) {
325
331
  currentWs.send(JSON.stringify({ type: 'notice', conversationId, message }));
326
332
  }
327
333
  },
328
334
  onDone: (messageCount, costUsd, usage, model, contextTokens) => {
329
- const elapsed = (0, timer_1.stopTurnTimer)();
330
- const parts = [(0, timer_1.formatElapsed)(elapsed)];
335
+ const elapsed = stopTurnTimer();
336
+ const parts = [formatElapsed(elapsed)];
331
337
  if (usage)
332
338
  parts.push(`in:${usage.input_tokens} out:${usage.output_tokens}`);
333
339
  const costStr = costUsd === 0 ? '$0.0000 (plan usage)' : `$${costUsd.toFixed(4)}`;
@@ -341,9 +347,9 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
341
347
  sessionCostUsd += costUsd;
342
348
  const ctxPct = Math.max(0, Math.min(100, Math.round((contextTokens / contextWindowFor(model)) * 100)));
343
349
  const costSeg = sessionCostUsd > 0 ? `$${sessionCostUsd.toFixed(2)} session` : 'plan usage';
344
- console.log((0, claude_1.paint)('90', ` 🤖 ${friendlyModelName(model)} · 🧠 ${ctxPct}% · 💰 ${costSeg}`));
350
+ console.log(paint('90', ` 🤖 ${friendlyModelName(model)} · 🧠 ${ctxPct}% · 💰 ${costSeg}`));
345
351
  const mapped = toBridgeUsage(usage);
346
- if (currentWs?.readyState === ws_1.default.OPEN) {
352
+ if (currentWs?.readyState === WebSocket.OPEN) {
347
353
  currentWs.send(JSON.stringify({
348
354
  type: 'done',
349
355
  conversationId,
@@ -357,10 +363,10 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
357
363
  void finalizeAndPost(buildSpoolRecord(mapped, model));
358
364
  },
359
365
  onError: (message, usage, model) => {
360
- const elapsed = (0, timer_1.stopTurnTimer)();
361
- console.error(`[${new Date().toLocaleTimeString()}] ✗ ${message} (${(0, timer_1.formatElapsed)(elapsed)})`);
366
+ const elapsed = stopTurnTimer();
367
+ console.error(`[${new Date().toLocaleTimeString()}] ✗ ${message} (${formatElapsed(elapsed)})`);
362
368
  const mapped = toBridgeUsage(usage);
363
- if (currentWs?.readyState === ws_1.default.OPEN) {
369
+ if (currentWs?.readyState === WebSocket.OPEN) {
364
370
  currentWs.send(JSON.stringify({
365
371
  type: 'error',
366
372
  conversationId,
@@ -391,14 +397,14 @@ function toBridgeUsage(usage) {
391
397
  // dedupes on conversationId — if it already saved via the WS path, the
392
398
  // reply is finalized=false and we still delete the spool.
393
399
  async function drainOutbox(auth) {
394
- const records = (0, outbox_1.listSpool)();
400
+ const records = listSpool();
395
401
  if (records.length === 0)
396
402
  return;
397
403
  console.log(`[bridge] draining ${records.length} pending save record${records.length === 1 ? '' : 's'}…`);
398
404
  for (const record of records) {
399
- const result = await (0, accumulator_1.postSaveTurn)(GATEWAY_HTTP, auth.token, record);
405
+ const result = await postSaveTurn(GATEWAY_HTTP, auth.token, record);
400
406
  if (result.ok) {
401
- (0, outbox_1.deleteSpool)(record.conversationId);
407
+ deleteSpool(record.conversationId);
402
408
  }
403
409
  else {
404
410
  console.warn(`[bridge] drain POST failed (${result.status}): ${result.error ?? 'unknown'} — leaving on disk`);
@@ -411,14 +417,14 @@ async function drainOutbox(auth) {
411
417
  const PING_INTERVAL_MS = 30_000;
412
418
  const PONG_TIMEOUT_MS = 10_000;
413
419
  function connect(auth, retryDelay = 1000) {
414
- const ws = new ws_1.default(GATEWAY_WS, {
420
+ const ws = new WebSocket(GATEWAY_WS, {
415
421
  headers: { Authorization: `Bearer ${auth.token}` },
416
422
  });
417
423
  let pingTimer = null;
418
424
  let pongTimer = null;
419
425
  function startPing() {
420
426
  pingTimer = setInterval(() => {
421
- if (ws.readyState !== ws_1.default.OPEN)
427
+ if (ws.readyState !== WebSocket.OPEN)
422
428
  return;
423
429
  ws.send(JSON.stringify({ type: 'ping', ts: Date.now() }));
424
430
  pongTimer = setTimeout(() => {
@@ -473,7 +479,7 @@ function connect(auth, retryDelay = 1000) {
473
479
  // (PWA→gateway connection dropped). Kill the local Claude Code process for
474
480
  // this conversation so it stops generating instead of running to the end.
475
481
  if (msg.type === 'cancel' && msg.conversationId) {
476
- const cancelled = (0, claude_1.cancelConversation)(msg.conversationId);
482
+ const cancelled = cancelConversation(msg.conversationId);
477
483
  if (cancelled)
478
484
  console.log(`[bridge] ✕ stopped conversation ${msg.conversationId}`);
479
485
  return;
@@ -484,9 +490,9 @@ function connect(auth, retryDelay = 1000) {
484
490
  const ts = new Date().toLocaleTimeString();
485
491
  const hist = Array.isArray(history) ? history : [];
486
492
  console.log(`[${ts}] ▶ ${text}${hist.length ? ` (history: ${hist.length} turn${hist.length === 1 ? '' : 's'})` : ''}`);
487
- (0, timer_1.startTurnTimer)();
493
+ startTurnTimer();
488
494
  handleMessage(conversationId, text, sessionId ?? null, hist, auth, vaultFileOpen, clientCapabilities, syncedFolders, agentSlug).catch((err) => {
489
- (0, timer_1.stopTurnTimer)();
495
+ stopTurnTimer();
490
496
  console.error(`[bridge] handleMessage error: ${err.message}`);
491
497
  });
492
498
  });
@@ -529,24 +535,24 @@ function connect(auth, retryDelay = 1000) {
529
535
  }
530
536
  // ─── Main ─────────────────────────────────────────────────────────────────────
531
537
  async function main() {
532
- console.log(`1Presence Bridge v${package_json_1.version}\n`);
538
+ console.log(`1Presence Bridge v${version}\n`);
533
539
  if (VERBOSE) {
534
- (0, claude_1.setVerbose)(true);
540
+ setVerbose(true);
535
541
  console.log('[bridge:verbose] verbose logging enabled — system prompts (magenta), user prompts (blue), assistant text (green), tool inputs (cyan), and tool outputs (yellow) will be printed, colour-coded by kind.\n');
536
542
  }
537
543
  if (DEBUG) {
538
- (0, claude_1.setDebug)(true);
544
+ setDebug(true);
539
545
  console.log('[bridge:debug] debug transcript enabled — user prompts, assistant text, tool inputs, and tool outputs will be printed (system prompt omitted; use --verbose for that).\n');
540
546
  }
541
- if (await (0, update_1.checkAndUpdate)())
547
+ if (await checkAndUpdate())
542
548
  return;
543
549
  // Auth
544
- const auth = await (0, auth_1.getValidAuth)(GATEWAY_HTTP, PWA_URL);
550
+ const auth = await getValidAuth(GATEWAY_HTTP, PWA_URL);
545
551
  currentAuth = auth;
546
552
  // One-time interactive model choice (only prompts on first run; saved to
547
553
  // ~/.1presence/config.json). In a non-TTY environment this is a no-op and
548
554
  // Claude Code's own default is used.
549
- await (0, config_1.ensureModelChoice)();
555
+ await ensureModelChoice();
550
556
  // Write system prompt + MCP config. If this fails the bridge is dead in the
551
557
  // water — surface the underlying error rather than letting it bubble up as
552
558
  // a generic "Fatal:" with no context.
@@ -566,7 +572,7 @@ async function main() {
566
572
  // Graceful shutdown
567
573
  const shutdown = () => {
568
574
  console.log('\nShutting down…');
569
- (0, claude_1.killAll)();
575
+ killAll();
570
576
  process.exit(0);
571
577
  };
572
578
  process.on('SIGINT', shutdown);
@@ -588,7 +594,7 @@ async function main() {
588
594
  });
589
595
  }
590
596
  main().catch((err) => {
591
- if (err instanceof auth_1.AuthCancelledError) {
597
+ if (err instanceof AuthCancelledError) {
592
598
  console.error(`\n${err.message}`);
593
599
  console.error('Run `npx @1presence/bridge` again when you are ready to sign in.');
594
600
  process.exit(0);
package/dist/outbox.js CHANGED
@@ -1,11 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.writeSpool = writeSpool;
4
- exports.deleteSpool = deleteSpool;
5
- exports.listSpool = listSpool;
6
- const fs_1 = require("fs");
7
- const os_1 = require("os");
8
- const path_1 = require("path");
1
+ import { mkdirSync, writeFileSync, readdirSync, readFileSync, unlinkSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
9
4
  // ─── On-disk turn spool ───────────────────────────────────────────────────────
10
5
  //
11
6
  // Each in-flight bridge turn writes a record to ~/.1presence/outbox/. The file
@@ -20,31 +15,31 @@ const path_1 = require("path");
20
15
  //
21
16
  // Payload mode 0600 — the file contains the user's assistant transcript and
22
17
  // tool inputs. Tightened on every write to handle legacy world-readable files.
23
- const OUTBOX_DIR = (0, path_1.join)((0, os_1.homedir)(), '.1presence', 'outbox');
18
+ const OUTBOX_DIR = join(homedir(), '.1presence', 'outbox');
24
19
  function ensureDir() {
25
- (0, fs_1.mkdirSync)(OUTBOX_DIR, { recursive: true });
20
+ mkdirSync(OUTBOX_DIR, { recursive: true });
26
21
  }
27
22
  function pathFor(conversationId) {
28
- return (0, path_1.join)(OUTBOX_DIR, `${conversationId}.json`);
23
+ return join(OUTBOX_DIR, `${conversationId}.json`);
29
24
  }
30
- function writeSpool(record) {
25
+ export function writeSpool(record) {
31
26
  ensureDir();
32
- (0, fs_1.writeFileSync)(pathFor(record.conversationId), JSON.stringify(record), { mode: 0o600 });
27
+ writeFileSync(pathFor(record.conversationId), JSON.stringify(record), { mode: 0o600 });
33
28
  }
34
- function deleteSpool(conversationId) {
29
+ export function deleteSpool(conversationId) {
35
30
  try {
36
- (0, fs_1.unlinkSync)(pathFor(conversationId));
31
+ unlinkSync(pathFor(conversationId));
37
32
  }
38
33
  catch { /* already gone — fine */ }
39
34
  }
40
- function listSpool() {
35
+ export function listSpool() {
41
36
  ensureDir();
42
37
  const out = [];
43
- for (const file of (0, fs_1.readdirSync)(OUTBOX_DIR)) {
38
+ for (const file of readdirSync(OUTBOX_DIR)) {
44
39
  if (!file.endsWith('.json'))
45
40
  continue;
46
41
  try {
47
- const raw = (0, fs_1.readFileSync)((0, path_1.join)(OUTBOX_DIR, file), 'utf-8');
42
+ const raw = readFileSync(join(OUTBOX_DIR, file), 'utf-8');
48
43
  out.push(JSON.parse(raw));
49
44
  }
50
45
  catch {
package/dist/timer.js CHANGED
@@ -1,12 +1,7 @@
1
- "use strict";
2
1
  // Live elapsed-time indicator for the active turn. Writes `\r\x1b[K⏱ Xs`
3
2
  // once per second; wraps console.log/error/warn so that any other output
4
3
  // clears the timer line before printing, then redraws the timer on the new
5
4
  // bottom line. Idempotent — stop is safe to call multiple times.
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.formatElapsed = formatElapsed;
8
- exports.startTurnTimer = startTurnTimer;
9
- exports.stopTurnTimer = stopTurnTimer;
10
5
  let intervalId = null;
11
6
  let startedAt = 0;
12
7
  let originalLog = null;
@@ -19,14 +14,14 @@ function draw() {
19
14
  const elapsedSec = Math.floor((Date.now() - startedAt) / 1000);
20
15
  process.stdout.write(`\r\x1b[K⏱ ${formatElapsed(elapsedSec)}`);
21
16
  }
22
- function formatElapsed(seconds) {
17
+ export function formatElapsed(seconds) {
23
18
  if (seconds < 60)
24
19
  return `${seconds}s`;
25
20
  const m = Math.floor(seconds / 60);
26
21
  const s = seconds % 60;
27
22
  return `${m}m ${s.toString().padStart(2, '0')}s`;
28
23
  }
29
- function startTurnTimer() {
24
+ export function startTurnTimer() {
30
25
  if (intervalId !== null)
31
26
  return;
32
27
  startedAt = Date.now();
@@ -39,7 +34,7 @@ function startTurnTimer() {
39
34
  draw();
40
35
  intervalId = setInterval(draw, 1000);
41
36
  }
42
- function stopTurnTimer() {
37
+ export function stopTurnTimer() {
43
38
  if (intervalId === null)
44
39
  return 0;
45
40
  clearInterval(intervalId);
package/dist/update.js CHANGED
@@ -1,8 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkAndUpdate = checkAndUpdate;
4
- const child_process_1 = require("child_process");
5
- const package_json_1 = require("../package.json");
1
+ import { spawn } from 'child_process';
2
+ import { createRequire } from 'module';
3
+ // ESM JSON imports need version-sensitive import assertions; createRequire reads
4
+ // the manifest synchronously on every Node 18+ without that fragility.
5
+ const { version } = createRequire(import.meta.url)('../package.json');
6
6
  function isNewer(a, b) {
7
7
  const pa = a.split('.').map(Number);
8
8
  const pb = b.split('.').map(Number);
@@ -14,7 +14,7 @@ function isNewer(a, b) {
14
14
  }
15
15
  return false;
16
16
  }
17
- async function checkAndUpdate() {
17
+ export async function checkAndUpdate() {
18
18
  try {
19
19
  const res = await fetch('https://registry.npmjs.org/@1presence/bridge/latest', {
20
20
  signal: AbortSignal.timeout(3000),
@@ -23,10 +23,10 @@ async function checkAndUpdate() {
23
23
  return false;
24
24
  const data = await res.json();
25
25
  const latest = data.version;
26
- if (!isNewer(latest, package_json_1.version))
26
+ if (!isNewer(latest, version))
27
27
  return false;
28
28
  console.log(`Updating to v${latest}…\n`);
29
- const child = (0, child_process_1.spawn)('npx', ['--yes', `@1presence/bridge@${latest}`], {
29
+ const child = spawn('npx', ['--yes', `@1presence/bridge@${latest}`], {
30
30
  stdio: 'inherit',
31
31
  env: process.env,
32
32
  });
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.40.0",
3
+ "version": "0.43.0",
4
4
  "description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
5
+ "type": "module",
5
6
  "bin": {
6
7
  "1presence-bridge": "dist/index.js"
7
8
  },
@@ -18,6 +19,7 @@
18
19
  "start": "node dist/index.js"
19
20
  },
20
21
  "dependencies": {
22
+ "@anthropic-ai/claude-agent-sdk": "^0.3.153",
21
23
  "ws": "^8.20.0"
22
24
  },
23
25
  "devDependencies": {