@meet-ai/cli 0.0.34 → 0.0.36

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 (3) hide show
  1. package/dist/index.js +1940 -782
  2. package/package.json +2 -1
  3. package/README.md +0 -114
package/dist/index.js CHANGED
@@ -1590,10 +1590,10 @@ function fixedBase64(bodyLength, padding) {
1590
1590
  function fixedBase64url(length) {
1591
1591
  return new RegExp(`^[A-Za-z0-9_-]{${length}}$`);
1592
1592
  }
1593
- var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uuid = (version) => {
1594
- if (!version)
1593
+ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uuid = (version2) => {
1594
+ if (!version2)
1595
1595
  return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
1596
- return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
1596
+ return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
1597
1597
  }, uuid4, uuid6, uuid7, email, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`, ipv4, ipv6, mac = (delimiter) => {
1598
1598
  const escapedDelim = escapeRegex(delimiter ?? ":");
1599
1599
  return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
@@ -2249,9 +2249,9 @@ class Doc {
2249
2249
  }
2250
2250
 
2251
2251
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/versions.js
2252
- var version;
2252
+ var version2;
2253
2253
  var init_versions = __esm(() => {
2254
- version = {
2254
+ version2 = {
2255
2255
  major: 4,
2256
2256
  minor: 3,
2257
2257
  patch: 6
@@ -2627,7 +2627,7 @@ var init_schemas = __esm(() => {
2627
2627
  inst ?? (inst = {});
2628
2628
  inst._zod.def = def;
2629
2629
  inst._zod.bag = inst._zod.bag || {};
2630
- inst._zod.version = version;
2630
+ inst._zod.version = version2;
2631
2631
  const checks = [...inst._zod.def.checks ?? []];
2632
2632
  if (inst._zod.traits.has("$ZodCheck")) {
2633
2633
  checks.unshift(inst);
@@ -11912,7 +11912,7 @@ var init_json_schema = () => {};
11912
11912
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/index.js
11913
11913
  var exports_core2 = {};
11914
11914
  __export(exports_core2, {
11915
- version: () => version,
11915
+ version: () => version2,
11916
11916
  util: () => exports_util,
11917
11917
  treeifyError: () => treeifyError,
11918
11918
  toJSONSchema: () => toJSONSchema,
@@ -14012,10 +14012,10 @@ function fromJSONSchema(schema, params) {
14012
14012
  if (typeof schema === "boolean") {
14013
14013
  return schema ? z.any() : z.never();
14014
14014
  }
14015
- const version2 = detectVersion(schema, params?.defaultTarget);
14015
+ const version3 = detectVersion(schema, params?.defaultTarget);
14016
14016
  const defs = schema.$defs || schema.definitions || {};
14017
14017
  const ctx = {
14018
- version: version2,
14018
+ version: version3,
14019
14019
  defs,
14020
14020
  refs: new Map,
14021
14021
  processing: new Set,
@@ -14390,6 +14390,100 @@ var init_zod = __esm(() => {
14390
14390
  init_external();
14391
14391
  });
14392
14392
 
14393
+ // src/lib/codex.ts
14394
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
14395
+ import { homedir } from "node:os";
14396
+ import { dirname, join, resolve } from "node:path";
14397
+ function getCodexHome(options) {
14398
+ if (options?.codexHome)
14399
+ return options.codexHome;
14400
+ if (options?.env?.CODEX_HOME)
14401
+ return options.env.CODEX_HOME;
14402
+ if (process.env.CODEX_HOME)
14403
+ return process.env.CODEX_HOME;
14404
+ if (process.env.MEET_AI_CODEX_STATE_DIR)
14405
+ return process.env.MEET_AI_CODEX_STATE_DIR;
14406
+ return join(homedir(), ".codex");
14407
+ }
14408
+ function getCodexConfigPaths(options) {
14409
+ const home = getCodexHome(options);
14410
+ return [
14411
+ resolve(".codex/config.json"),
14412
+ resolve(".codex/config.toml"),
14413
+ join(home, "config.json"),
14414
+ join(home, "config.toml")
14415
+ ];
14416
+ }
14417
+ function parseCodexTomlEnv(path) {
14418
+ if (!existsSync(path))
14419
+ return null;
14420
+ const env = {};
14421
+ let inEnvSection = false;
14422
+ for (const line of readFileSync(path, "utf-8").split(/\r?\n/)) {
14423
+ const trimmed = line.trim();
14424
+ if (!trimmed || trimmed.startsWith("#"))
14425
+ continue;
14426
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
14427
+ inEnvSection = trimmed === "[env]";
14428
+ continue;
14429
+ }
14430
+ if (!inEnvSection)
14431
+ continue;
14432
+ const match = trimmed.match(/^([A-Z0-9_]+)\s*=\s*"([^"]*)"$/);
14433
+ if (!match)
14434
+ continue;
14435
+ env[match[1]] = match[2];
14436
+ }
14437
+ return Object.keys(env).length > 0 ? env : null;
14438
+ }
14439
+ function readCodexConfigEnv(options) {
14440
+ for (const path of getCodexConfigPaths(options)) {
14441
+ if (!existsSync(path))
14442
+ continue;
14443
+ if (path.endsWith(".json")) {
14444
+ try {
14445
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
14446
+ if (parsed.env && Object.keys(parsed.env).length > 0) {
14447
+ return parsed.env;
14448
+ }
14449
+ } catch {
14450
+ continue;
14451
+ }
14452
+ continue;
14453
+ }
14454
+ const env = parseCodexTomlEnv(path);
14455
+ if (env)
14456
+ return env;
14457
+ }
14458
+ return null;
14459
+ }
14460
+ function getInboxPath(sessionId, options) {
14461
+ return join(getCodexHome(options), "meet-ai", "inbox", `${sessionId}.json`);
14462
+ }
14463
+ function appendCodexInboxEntry(sessionId, entry, options) {
14464
+ const path = getInboxPath(sessionId, options);
14465
+ mkdirSync(dirname(path), { recursive: true });
14466
+ let entries = [];
14467
+ try {
14468
+ entries = JSON.parse(readFileSync(path, "utf-8"));
14469
+ } catch {
14470
+ entries = [];
14471
+ }
14472
+ entries.push(entry);
14473
+ writeFileSync(path, `${JSON.stringify(entries, null, 2)}
14474
+ `);
14475
+ return path;
14476
+ }
14477
+ var init_codex = () => {};
14478
+
14479
+ // src/runtime.ts
14480
+ function getMeetAiRuntime(env = process.env) {
14481
+ const raw = env.MEET_AI_RUNTIME?.trim().toLowerCase();
14482
+ if (raw === "codex")
14483
+ return "codex";
14484
+ return "claude";
14485
+ }
14486
+
14393
14487
  // src/config.ts
14394
14488
  var exports_config = {};
14395
14489
  __export(exports_config, {
@@ -14397,15 +14491,15 @@ __export(exports_config, {
14397
14491
  getMeetAiConfig: () => getMeetAiConfig,
14398
14492
  configSchema: () => configSchema
14399
14493
  });
14400
- import { readFileSync, existsSync } from "node:fs";
14401
- import { join, resolve } from "node:path";
14402
- import { homedir } from "node:os";
14494
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "node:fs";
14495
+ import { join as join2, resolve as resolve2 } from "node:path";
14496
+ import { homedir as homedir2 } from "node:os";
14403
14497
  function loadSettingsFromPath(path) {
14404
14498
  try {
14405
- if (!existsSync(path)) {
14499
+ if (!existsSync2(path)) {
14406
14500
  return null;
14407
14501
  }
14408
- const content = readFileSync(path, "utf-8");
14502
+ const content = readFileSync2(path, "utf-8");
14409
14503
  return JSON.parse(content);
14410
14504
  } catch {
14411
14505
  return null;
@@ -14418,7 +14512,16 @@ function resolveRawConfig(opts) {
14418
14512
  key: process.env.MEET_AI_KEY
14419
14513
  };
14420
14514
  }
14421
- const projectSettingsPath = opts?.projectSettingsPath ?? resolve("./.claude/settings.json");
14515
+ if (getMeetAiRuntime() === "codex") {
14516
+ const codexEnv = readCodexConfigEnv({ codexHome: opts?.codexHome });
14517
+ if (codexEnv?.MEET_AI_URL) {
14518
+ return {
14519
+ url: codexEnv.MEET_AI_URL,
14520
+ key: codexEnv.MEET_AI_KEY
14521
+ };
14522
+ }
14523
+ }
14524
+ const projectSettingsPath = opts?.projectSettingsPath ?? resolve2("./.claude/settings.json");
14422
14525
  const projectSettings = loadSettingsFromPath(projectSettingsPath);
14423
14526
  if (projectSettings?.env?.MEET_AI_URL) {
14424
14527
  return {
@@ -14426,7 +14529,7 @@ function resolveRawConfig(opts) {
14426
14529
  key: projectSettings.env.MEET_AI_KEY
14427
14530
  };
14428
14531
  }
14429
- const userSettingsPath = join(opts?.homeDir ?? homedir(), ".claude/settings.json");
14532
+ const userSettingsPath = join2(opts?.homeDir ?? homedir2(), ".claude/settings.json");
14430
14533
  const userSettings = loadSettingsFromPath(userSettingsPath);
14431
14534
  if (userSettings?.env?.MEET_AI_URL) {
14432
14535
  return {
@@ -14450,18 +14553,14 @@ function getMeetAiConfig(opts) {
14450
14553
  var configSchema;
14451
14554
  var init_config = __esm(() => {
14452
14555
  init_zod();
14556
+ init_codex();
14453
14557
  configSchema = exports_external.object({
14454
14558
  url: exports_external.string().url("MEET_AI_URL must be a valid URL"),
14455
14559
  key: exports_external.string().optional()
14456
14560
  });
14457
14561
  });
14458
14562
 
14459
- // src/client.ts
14460
- function wsLog(data) {
14461
- const json2 = JSON.stringify({ ...data, ts: new Date().toISOString() });
14462
- const isSuccess = data.event === "connected" || data.event === "reconnected" || data.event === "catchup";
14463
- console.error(isSuccess ? `\x1B[32m${json2}\x1B[0m` : json2);
14464
- }
14563
+ // src/domain/adapters/HttpTransport.ts
14465
14564
  function isRetryable(error48) {
14466
14565
  if (error48 instanceof TypeError)
14467
14566
  return true;
@@ -14488,396 +14587,773 @@ async function withRetry(fn, options) {
14488
14587
  delay_ms: delay,
14489
14588
  error: lastError.message
14490
14589
  }));
14491
- await new Promise((resolve2) => setTimeout(resolve2, delay));
14590
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
14492
14591
  }
14493
14592
  }
14494
14593
  throw lastError;
14495
14594
  }
14496
- function cleanupOldAttachments() {
14595
+ async function parseErrorMessage(res) {
14497
14596
  try {
14498
- const { readdirSync, statSync, unlinkSync } = __require("node:fs");
14499
- const now = Date.now();
14500
- for (const entry of readdirSync(ATTACHMENTS_DIR)) {
14501
- try {
14502
- const filePath = `${ATTACHMENTS_DIR}/${entry}`;
14503
- const mtime = statSync(filePath).mtimeMs;
14504
- if (now - mtime > MAX_AGE_MS) {
14505
- unlinkSync(filePath);
14506
- }
14507
- } catch {}
14508
- }
14597
+ const err2 = await res.json();
14598
+ const msg = err2.error;
14599
+ if (typeof msg === "string")
14600
+ return msg;
14601
+ if (msg)
14602
+ return JSON.stringify(msg);
14509
14603
  } catch {}
14604
+ return `HTTP ${res.status}`;
14510
14605
  }
14511
- function createClient(baseUrl, apiKey) {
14512
- function headers(extra) {
14606
+
14607
+ class HttpTransport {
14608
+ baseUrl;
14609
+ apiKey;
14610
+ constructor(baseUrl, apiKey) {
14611
+ this.baseUrl = baseUrl;
14612
+ this.apiKey = apiKey;
14613
+ }
14614
+ headers(extra) {
14513
14615
  const h = { "Content-Type": "application/json", ...extra };
14514
- if (apiKey) {
14515
- h["Authorization"] = `Bearer ${apiKey}`;
14616
+ if (this.apiKey) {
14617
+ h["Authorization"] = `Bearer ${this.apiKey}`;
14516
14618
  }
14517
14619
  return h;
14518
14620
  }
14519
- return {
14520
- async createRoom(name) {
14521
- const res = await fetch(`${baseUrl}/api/rooms`, {
14621
+ authHeaders() {
14622
+ return this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : undefined;
14623
+ }
14624
+ buildUrl(path, query) {
14625
+ const params = new URLSearchParams;
14626
+ if (query) {
14627
+ for (const [key, value] of Object.entries(query)) {
14628
+ if (value)
14629
+ params.set(key, value);
14630
+ }
14631
+ }
14632
+ const qs = params.toString();
14633
+ return `${this.baseUrl}${path}${qs ? `?${qs}` : ""}`;
14634
+ }
14635
+ async postJson(path, body, opts) {
14636
+ const doRequest = async () => {
14637
+ const res = await fetch(this.buildUrl(path, opts?.query), {
14522
14638
  method: "POST",
14523
- headers: headers(),
14524
- body: JSON.stringify({ name })
14639
+ headers: this.headers(),
14640
+ body: body !== undefined ? JSON.stringify(body) : undefined
14525
14641
  });
14526
- if (!res.ok) {
14527
- const err2 = await res.json();
14528
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14529
- }
14642
+ if (!res.ok)
14643
+ throw new Error(await parseErrorMessage(res));
14530
14644
  return res.json();
14531
- },
14532
- async sendMessage(roomId, sender, content, color) {
14533
- return withRetry(async () => {
14534
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/messages`, {
14535
- method: "POST",
14536
- headers: headers(),
14537
- body: JSON.stringify({ sender, content, sender_type: "agent", ...color && { color } })
14538
- });
14539
- if (!res.ok) {
14540
- const err2 = await res.json().catch(() => ({}));
14541
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14542
- }
14543
- return res.json();
14645
+ };
14646
+ return opts?.retry ? withRetry(doRequest, opts.retry) : doRequest();
14647
+ }
14648
+ async postText(path, body, opts) {
14649
+ const doRequest = async () => {
14650
+ const res = await fetch(this.buildUrl(path, opts?.query), {
14651
+ method: "POST",
14652
+ headers: this.headers(),
14653
+ body: body !== undefined ? JSON.stringify(body) : undefined
14544
14654
  });
14545
- },
14546
- async getMessages(roomId, options) {
14547
- const params = new URLSearchParams;
14548
- if (options?.after)
14549
- params.set("after", options.after);
14550
- if (options?.exclude)
14551
- params.set("exclude", options.exclude);
14552
- if (options?.senderType)
14553
- params.set("sender_type", options.senderType);
14554
- const qs = params.toString();
14555
- const url2 = `${baseUrl}/api/rooms/${roomId}/messages${qs ? `?${qs}` : ""}`;
14556
- const res = await fetch(url2, {
14557
- headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined
14655
+ if (!res.ok)
14656
+ throw new Error(await parseErrorMessage(res));
14657
+ return res.text();
14658
+ };
14659
+ return opts?.retry ? withRetry(doRequest, opts.retry) : doRequest();
14660
+ }
14661
+ async getJson(path, opts) {
14662
+ const doRequest = async () => {
14663
+ const res = await fetch(this.buildUrl(path, opts?.query), {
14664
+ headers: this.authHeaders()
14558
14665
  });
14559
- if (!res.ok) {
14560
- const err2 = await res.json();
14561
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14562
- }
14666
+ if (!res.ok)
14667
+ throw new Error(await parseErrorMessage(res));
14563
14668
  return res.json();
14564
- },
14565
- listen(roomId, options) {
14566
- const wsUrl = baseUrl.replace(/^http/, "ws");
14567
- const tokenParam = apiKey ? `?token=${apiKey}` : "";
14568
- let pingInterval = null;
14569
- let reconnectAttempt = 0;
14570
- const seen = new Set;
14571
- let lastSeenId = null;
14572
- function deliver(msg) {
14573
- if (seen.has(msg.id))
14574
- return;
14575
- seen.add(msg.id);
14576
- if (seen.size > 200) {
14577
- const first = seen.values().next().value;
14578
- seen.delete(first);
14579
- }
14580
- lastSeenId = msg.id;
14581
- if (options?.exclude && msg.sender === options.exclude)
14582
- return;
14583
- if (options?.senderType && msg.sender_type !== options.senderType)
14584
- return;
14585
- if (options?.onMessage) {
14586
- options.onMessage(msg);
14587
- } else {
14588
- console.log(JSON.stringify(msg));
14589
- }
14669
+ };
14670
+ return opts?.retry ? withRetry(doRequest, opts.retry) : doRequest();
14671
+ }
14672
+ async getRaw(path) {
14673
+ const res = await fetch(this.buildUrl(path), {
14674
+ headers: this.authHeaders()
14675
+ });
14676
+ if (!res.ok)
14677
+ throw new Error(await parseErrorMessage(res));
14678
+ return res;
14679
+ }
14680
+ async del(path) {
14681
+ const res = await fetch(this.buildUrl(path), {
14682
+ method: "DELETE",
14683
+ headers: this.headers()
14684
+ });
14685
+ if (!res.ok)
14686
+ throw new Error(await parseErrorMessage(res));
14687
+ }
14688
+ }
14689
+
14690
+ // src/coding-agents.ts
14691
+ function isCodingAgentId(value) {
14692
+ return CODING_AGENT_DEFINITIONS.some((agent) => agent.id === value);
14693
+ }
14694
+ var CODING_AGENT_DEFINITIONS;
14695
+ var init_coding_agents = __esm(() => {
14696
+ CODING_AGENT_DEFINITIONS = [
14697
+ { id: "claude", label: "Claude Code" },
14698
+ { id: "codex", label: "Codex" }
14699
+ ];
14700
+ });
14701
+
14702
+ // src/domain/adapters/ConnectionAdapter.ts
14703
+ function wsLog(data) {
14704
+ const json2 = JSON.stringify({ ...data, ts: new Date().toISOString() });
14705
+ const isSuccess = data.event === "connected" || data.event === "reconnected" || data.event === "catchup";
14706
+ console.error(isSuccess ? `\x1B[32m${json2}\x1B[0m` : json2);
14707
+ }
14708
+
14709
+ class ConnectionAdapter {
14710
+ transport;
14711
+ baseUrl;
14712
+ apiKey;
14713
+ constructor(transport, baseUrl, apiKey) {
14714
+ this.transport = transport;
14715
+ this.baseUrl = baseUrl;
14716
+ this.apiKey = apiKey;
14717
+ }
14718
+ listen(roomId, options) {
14719
+ const wsUrl = this.baseUrl.replace(/^http/, "ws");
14720
+ const wsHeaders = this.apiKey ? { headers: { Authorization: `Bearer ${this.apiKey}` } } : undefined;
14721
+ let pingInterval = null;
14722
+ let reconnectAttempt = 0;
14723
+ const seen = new Set;
14724
+ let lastSeenId = null;
14725
+ const transport = this.transport;
14726
+ function deliver(msg) {
14727
+ if (seen.has(msg.id))
14728
+ return;
14729
+ seen.add(msg.id);
14730
+ if (seen.size > 200) {
14731
+ const first = seen.values().next().value;
14732
+ seen.delete(first);
14590
14733
  }
14591
- function getReconnectDelay() {
14592
- const delay = Math.min(1000 * 2 ** Math.min(reconnectAttempt, 4), 15000);
14593
- reconnectAttempt++;
14594
- return delay + delay * 0.5 * Math.random();
14734
+ lastSeenId = msg.id;
14735
+ if (options?.exclude && msg.sender === options.exclude)
14736
+ return;
14737
+ if (options?.senderType && msg.sender_type !== options.senderType)
14738
+ return;
14739
+ if (options?.onMessage) {
14740
+ options.onMessage(msg);
14741
+ } else {
14742
+ console.log(JSON.stringify(msg));
14595
14743
  }
14596
- const fetchMessages = this.getMessages.bind(this);
14597
- function connect() {
14598
- const ws = new WebSocket(`${wsUrl}/api/rooms/${roomId}/ws${tokenParam}`);
14599
- const connectTimeout = setTimeout(() => {
14600
- if (ws.readyState !== WebSocket.OPEN) {
14601
- wsLog({ event: "timeout", after_ms: 30000 });
14602
- try {
14603
- ws.close(4000, "connect timeout");
14604
- } catch {}
14605
- const delay = getReconnectDelay();
14606
- wsLog({ event: "reconnecting", attempt: reconnectAttempt, delay_ms: Math.round(delay) });
14607
- setTimeout(connect, delay);
14608
- }
14609
- }, 30000);
14610
- ws.onopen = async () => {
14611
- clearTimeout(connectTimeout);
14612
- const wasReconnect = reconnectAttempt > 0;
14613
- reconnectAttempt = 0;
14614
- wsLog({ event: wasReconnect ? "reconnected" : "connected" });
14615
- if (pingInterval)
14616
- clearInterval(pingInterval);
14617
- pingInterval = setInterval(() => {
14618
- if (ws.readyState === WebSocket.OPEN) {
14619
- ws.send(JSON.stringify({ type: "ping" }));
14620
- }
14621
- }, 30000);
14622
- if (lastSeenId) {
14623
- try {
14624
- const missed = await fetchMessages(roomId, { after: lastSeenId });
14625
- if (missed.length)
14626
- wsLog({ event: "catchup", count: missed.length });
14627
- for (const msg of missed)
14628
- deliver(msg);
14629
- } catch {}
14630
- }
14631
- };
14632
- ws.onmessage = (event) => {
14633
- const text = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
14634
- const data = JSON.parse(text);
14635
- if (data.type === "pong")
14636
- return;
14637
- if (data.type === "terminal_subscribe" || data.type === "terminal_unsubscribe") {
14638
- options?.onMessage?.(data);
14639
- return;
14640
- }
14641
- if (data.type === "terminal_data")
14642
- return;
14643
- deliver(data);
14644
- };
14645
- ws.onclose = (event) => {
14646
- clearTimeout(connectTimeout);
14647
- if (pingInterval)
14648
- clearInterval(pingInterval);
14649
- const code = event.code;
14650
- if (code === 1000) {
14651
- wsLog({ event: "closed", code: 1000 });
14652
- return;
14653
- }
14654
- const reason = code === 1006 ? "network drop" : code === 1012 ? "service restart" : code === 1013 ? "server back-off" : `code ${code}`;
14744
+ }
14745
+ function getReconnectDelay() {
14746
+ const delay = Math.min(1000 * 2 ** Math.min(reconnectAttempt, 4), 15000);
14747
+ reconnectAttempt++;
14748
+ return delay + delay * 0.5 * Math.random();
14749
+ }
14750
+ function connect() {
14751
+ const ws = new WebSocket(`${wsUrl}/api/rooms/${roomId}/ws`, wsHeaders);
14752
+ const connectTimeout = setTimeout(() => {
14753
+ if (ws.readyState !== WebSocket.OPEN) {
14754
+ wsLog({ event: "timeout", after_ms: 30000 });
14755
+ try {
14756
+ ws.close(4000, "connect timeout");
14757
+ } catch {}
14655
14758
  const delay = getReconnectDelay();
14656
- wsLog({ event: "disconnected", code, reason });
14657
14759
  wsLog({ event: "reconnecting", attempt: reconnectAttempt, delay_ms: Math.round(delay) });
14658
14760
  setTimeout(connect, delay);
14659
- };
14660
- ws.onerror = () => {};
14661
- return ws;
14662
- }
14663
- return connect();
14664
- },
14665
- async sendLog(roomId, sender, content, color, messageId) {
14666
- return withRetry(async () => {
14667
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/logs`, {
14668
- method: "POST",
14669
- headers: headers(),
14670
- body: JSON.stringify({
14671
- sender,
14672
- content,
14673
- ...color && { color },
14674
- ...messageId && { message_id: messageId }
14675
- })
14676
- });
14677
- if (!res.ok) {
14678
- const err2 = await res.json().catch(() => ({}));
14679
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14680
14761
  }
14681
- return res.json();
14682
- });
14683
- },
14684
- async sendTeamInfo(roomId, payload) {
14685
- return withRetry(async () => {
14686
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/team-info`, {
14687
- method: "POST",
14688
- headers: headers(),
14689
- body: payload
14690
- });
14691
- if (!res.ok) {
14692
- const err2 = await res.json().catch(() => ({}));
14693
- const msg = err2.error;
14694
- throw new Error(typeof msg === "string" ? msg : msg ? JSON.stringify(msg) : `HTTP ${res.status}`);
14695
- }
14696
- return res.text();
14697
- });
14698
- },
14699
- async sendCommands(roomId, payload) {
14700
- return withRetry(async () => {
14701
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/commands`, {
14702
- method: "POST",
14703
- headers: headers(),
14704
- body: payload
14705
- });
14706
- if (!res.ok) {
14707
- const err2 = await res.json().catch(() => ({}));
14708
- const msg = err2.error;
14709
- throw new Error(typeof msg === "string" ? msg : msg ? JSON.stringify(msg) : `HTTP ${res.status}`);
14762
+ }, 30000);
14763
+ ws.onopen = async () => {
14764
+ clearTimeout(connectTimeout);
14765
+ const wasReconnect = reconnectAttempt > 0;
14766
+ reconnectAttempt = 0;
14767
+ wsLog({ event: wasReconnect ? "reconnected" : "connected" });
14768
+ if (pingInterval)
14769
+ clearInterval(pingInterval);
14770
+ pingInterval = setInterval(() => {
14771
+ if (ws.readyState === WebSocket.OPEN) {
14772
+ ws.send(JSON.stringify({ type: "ping" }));
14773
+ }
14774
+ }, 30000);
14775
+ if (lastSeenId) {
14776
+ try {
14777
+ const missed = await transport.getJson(`/api/rooms/${roomId}/messages`, { query: { after: lastSeenId } });
14778
+ if (missed.length)
14779
+ wsLog({ event: "catchup", count: missed.length });
14780
+ for (const msg of missed)
14781
+ deliver(msg);
14782
+ } catch {}
14710
14783
  }
14711
- return res.text();
14712
- });
14713
- },
14714
- async sendTasks(roomId, payload) {
14715
- return withRetry(async () => {
14716
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/tasks`, {
14717
- method: "POST",
14718
- headers: headers(),
14719
- body: payload
14720
- });
14721
- if (!res.ok) {
14722
- const err2 = await res.json().catch(() => ({}));
14723
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14784
+ };
14785
+ ws.onmessage = (event) => {
14786
+ const text = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
14787
+ const data = JSON.parse(text);
14788
+ if (data.type === "pong")
14789
+ return;
14790
+ if (data.type === "terminal_subscribe" || data.type === "terminal_unsubscribe") {
14791
+ options?.onMessage?.(data);
14792
+ return;
14724
14793
  }
14725
- return res.text();
14726
- });
14727
- },
14728
- async getMessageAttachments(roomId, messageId) {
14729
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}/messages/${messageId}/attachments`, {
14730
- headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined
14731
- });
14732
- if (!res.ok) {
14733
- const err2 = await res.json().catch(() => ({}));
14734
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14735
- }
14736
- return res.json();
14737
- },
14738
- async downloadAttachment(attachmentId) {
14739
- cleanupOldAttachments();
14740
- const res = await fetch(`${baseUrl}/api/attachments/${attachmentId}`, {
14741
- headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined
14742
- });
14743
- if (!res.ok) {
14744
- const err2 = await res.json().catch(() => ({}));
14745
- throw new Error(err2.error ?? `HTTP ${res.status}`);
14746
- }
14747
- const { mkdirSync, writeFileSync } = await import("node:fs");
14748
- const dir = "/tmp/meet-ai-attachments";
14749
- mkdirSync(dir, { recursive: true });
14750
- const safeId = attachmentId.replace(/[^a-zA-Z0-9_-]/g, "") || "unknown";
14751
- const localPath = `${dir}/${safeId}.bin`;
14752
- const buffer = Buffer.from(await res.arrayBuffer());
14753
- writeFileSync(localPath, buffer);
14754
- return localPath;
14755
- },
14756
- listenLobby(options) {
14757
- const wsUrl = baseUrl.replace(/^http/, "ws");
14758
- const tokenParam = apiKey ? `?token=${apiKey}` : "";
14759
- let pingInterval = null;
14760
- let reconnectAttempt = 0;
14761
- let reconnectScheduled = false;
14762
- const log = options?.silent ? () => {} : wsLog;
14763
- function getReconnectDelay() {
14764
- const delay = Math.min(1000 * 2 ** Math.min(reconnectAttempt, 4), 15000);
14765
- reconnectAttempt++;
14766
- return delay + delay * 0.5 * Math.random();
14767
- }
14768
- function scheduleReconnect() {
14769
- if (reconnectScheduled)
14794
+ if (data.type === "terminal_data")
14770
14795
  return;
14771
- reconnectScheduled = true;
14796
+ deliver(data);
14797
+ };
14798
+ ws.onclose = (event) => {
14799
+ clearTimeout(connectTimeout);
14800
+ if (pingInterval)
14801
+ clearInterval(pingInterval);
14802
+ const code = event.code;
14803
+ if (code === 1000) {
14804
+ wsLog({ event: "closed", code: 1000 });
14805
+ return;
14806
+ }
14807
+ const reason = code === 1006 ? "network drop" : code === 1012 ? "service restart" : code === 1013 ? "server back-off" : `code ${code}`;
14772
14808
  const delay = getReconnectDelay();
14773
- log({ event: "reconnecting", attempt: reconnectAttempt, delay_ms: Math.round(delay) });
14774
- setTimeout(() => {
14775
- reconnectScheduled = false;
14776
- connect();
14777
- }, delay);
14778
- }
14779
- function connect() {
14780
- const ws = new WebSocket(`${wsUrl}/api/lobby/ws${tokenParam}`);
14781
- const connectTimeout = setTimeout(() => {
14782
- if (ws.readyState !== WebSocket.OPEN) {
14783
- try {
14784
- ws.close(4000, "connect timeout");
14785
- } catch {}
14786
- scheduleReconnect();
14787
- }
14788
- }, 30000);
14789
- ws.onopen = () => {
14790
- clearTimeout(connectTimeout);
14791
- reconnectAttempt = 0;
14792
- log({ event: "lobby_connected" });
14793
- if (pingInterval)
14794
- clearInterval(pingInterval);
14795
- pingInterval = setInterval(() => {
14796
- if (ws.readyState === WebSocket.OPEN) {
14797
- ws.send(JSON.stringify({ type: "ping" }));
14798
- }
14799
- }, 30000);
14800
- };
14801
- ws.onmessage = (event) => {
14802
- const text = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
14809
+ wsLog({ event: "disconnected", code, reason });
14810
+ wsLog({ event: "reconnecting", attempt: reconnectAttempt, delay_ms: Math.round(delay) });
14811
+ setTimeout(connect, delay);
14812
+ };
14813
+ ws.onerror = () => {};
14814
+ return ws;
14815
+ }
14816
+ return connect();
14817
+ }
14818
+ listenLobby(options) {
14819
+ const wsUrl = this.baseUrl.replace(/^http/, "ws");
14820
+ const wsHeaders = this.apiKey ? { headers: { Authorization: `Bearer ${this.apiKey}` } } : undefined;
14821
+ let pingInterval = null;
14822
+ let reconnectAttempt = 0;
14823
+ let reconnectScheduled = false;
14824
+ const log = options?.silent ? () => {} : wsLog;
14825
+ function getReconnectDelay() {
14826
+ const delay = Math.min(1000 * 2 ** Math.min(reconnectAttempt, 4), 15000);
14827
+ reconnectAttempt++;
14828
+ return delay + delay * 0.5 * Math.random();
14829
+ }
14830
+ function scheduleReconnect() {
14831
+ if (reconnectScheduled)
14832
+ return;
14833
+ reconnectScheduled = true;
14834
+ const delay = getReconnectDelay();
14835
+ log({ event: "reconnecting", attempt: reconnectAttempt, delay_ms: Math.round(delay) });
14836
+ setTimeout(() => {
14837
+ reconnectScheduled = false;
14838
+ connect();
14839
+ }, delay);
14840
+ }
14841
+ function connect() {
14842
+ const ws = new WebSocket(`${wsUrl}/api/lobby/ws`, wsHeaders);
14843
+ const connectTimeout = setTimeout(() => {
14844
+ if (ws.readyState !== WebSocket.OPEN) {
14803
14845
  try {
14804
- const data = JSON.parse(text);
14805
- if (data.type === "pong")
14806
- return;
14807
- if (data.type === "room_created" && data.id && data.name) {
14808
- options?.onRoomCreated?.(data.id, data.name);
14809
- }
14810
- if (data.type === "spawn_request" && data.room_name) {
14811
- options?.onSpawnRequest?.(data.room_name);
14812
- }
14846
+ ws.close(4000, "connect timeout");
14813
14847
  } catch {}
14814
- };
14815
- ws.onclose = (event) => {
14816
- clearTimeout(connectTimeout);
14817
- if (pingInterval)
14818
- clearInterval(pingInterval);
14819
- if (event.code === 1000)
14820
- return;
14821
14848
  scheduleReconnect();
14822
- };
14823
- ws.onerror = () => {};
14824
- return ws;
14849
+ }
14850
+ }, 30000);
14851
+ ws.onopen = () => {
14852
+ clearTimeout(connectTimeout);
14853
+ reconnectAttempt = 0;
14854
+ log({ event: "lobby_connected" });
14855
+ if (pingInterval)
14856
+ clearInterval(pingInterval);
14857
+ pingInterval = setInterval(() => {
14858
+ if (ws.readyState === WebSocket.OPEN) {
14859
+ ws.send(JSON.stringify({ type: "ping" }));
14860
+ }
14861
+ }, 30000);
14862
+ };
14863
+ ws.onmessage = (event) => {
14864
+ const text = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
14865
+ try {
14866
+ const data = JSON.parse(text);
14867
+ if (data.type === "pong")
14868
+ return;
14869
+ if (data.type === "room_created" && data.id && data.name) {
14870
+ options?.onRoomCreated?.(data.id, data.name);
14871
+ }
14872
+ if (data.type === "spawn_request" && data.room_name) {
14873
+ const codingAgent = typeof data.coding_agent === "string" && isCodingAgentId(data.coding_agent) ? data.coding_agent : "claude";
14874
+ options?.onSpawnRequest?.({ roomName: data.room_name, codingAgent });
14875
+ }
14876
+ } catch {}
14877
+ };
14878
+ ws.onclose = (event) => {
14879
+ clearTimeout(connectTimeout);
14880
+ if (pingInterval)
14881
+ clearInterval(pingInterval);
14882
+ if (event.code === 1000)
14883
+ return;
14884
+ scheduleReconnect();
14885
+ };
14886
+ ws.onerror = () => {};
14887
+ return ws;
14888
+ }
14889
+ return connect();
14890
+ }
14891
+ async generateKey() {
14892
+ return this.transport.postJson("/api/keys");
14893
+ }
14894
+ }
14895
+ var init_ConnectionAdapter = __esm(() => {
14896
+ init_coding_agents();
14897
+ });
14898
+
14899
+ // src/domain/adapters/FileSystemAdapter.ts
14900
+ import {
14901
+ readFileSync as readFileSync3,
14902
+ writeFileSync as writeFileSync2,
14903
+ mkdirSync as mkdirSync2,
14904
+ existsSync as existsSync3,
14905
+ statSync as statSync2
14906
+ } from "node:fs";
14907
+
14908
+ class FileSystemAdapter {
14909
+ readFileSync(path, encoding) {
14910
+ return readFileSync3(path, encoding);
14911
+ }
14912
+ writeFileSync(path, data, encoding) {
14913
+ writeFileSync2(path, data, encoding);
14914
+ }
14915
+ mkdirSync(path, opts) {
14916
+ mkdirSync2(path, opts);
14917
+ }
14918
+ existsSync(path) {
14919
+ return existsSync3(path);
14920
+ }
14921
+ statSync(path) {
14922
+ const stat = statSync2(path);
14923
+ return { mtimeMs: stat.mtimeMs, size: stat.size };
14924
+ }
14925
+ }
14926
+ var init_FileSystemAdapter = () => {};
14927
+
14928
+ // src/domain/repositories/MessageRepository.ts
14929
+ class MessageRepository {
14930
+ transport;
14931
+ constructor(transport) {
14932
+ this.transport = transport;
14933
+ }
14934
+ async send(roomId, sender, content, color) {
14935
+ return this.transport.postJson(`/api/rooms/${roomId}/messages`, { sender, content, sender_type: "agent", ...color && { color } }, RETRY);
14936
+ }
14937
+ async list(roomId, opts) {
14938
+ const query = {};
14939
+ if (opts?.after)
14940
+ query.after = opts.after;
14941
+ if (opts?.exclude)
14942
+ query.exclude = opts.exclude;
14943
+ if (opts?.senderType)
14944
+ query.sender_type = opts.senderType;
14945
+ return this.transport.getJson(`/api/rooms/${roomId}/messages`, { query });
14946
+ }
14947
+ async sendLog(roomId, sender, content, opts) {
14948
+ return this.transport.postJson(`/api/rooms/${roomId}/logs`, {
14949
+ sender,
14950
+ content,
14951
+ ...opts?.color && { color: opts.color },
14952
+ ...opts?.messageId && { message_id: opts.messageId }
14953
+ }, RETRY);
14954
+ }
14955
+ }
14956
+ var RETRY;
14957
+ var init_MessageRepository = __esm(() => {
14958
+ RETRY = { retry: { maxRetries: 3, baseDelay: 1000 } };
14959
+ });
14960
+
14961
+ // src/domain/repositories/RoomRepository.ts
14962
+ class RoomRepository {
14963
+ transport;
14964
+ constructor(transport) {
14965
+ this.transport = transport;
14966
+ }
14967
+ async create(name) {
14968
+ return this.transport.postJson("/api/rooms", { name });
14969
+ }
14970
+ async delete(roomId) {
14971
+ return this.transport.del(`/api/rooms/${roomId}`);
14972
+ }
14973
+ async sendTeamInfo(roomId, payload) {
14974
+ return this.transport.postText(`/api/rooms/${roomId}/team-info`, JSON.parse(payload), {
14975
+ retry: RETRY2
14976
+ });
14977
+ }
14978
+ async sendCommands(roomId, payload) {
14979
+ return this.transport.postText(`/api/rooms/${roomId}/commands`, JSON.parse(payload), {
14980
+ retry: RETRY2
14981
+ });
14982
+ }
14983
+ async sendTasks(roomId, payload) {
14984
+ return this.transport.postText(`/api/rooms/${roomId}/tasks`, JSON.parse(payload), {
14985
+ retry: RETRY2
14986
+ });
14987
+ }
14988
+ async sendTerminalData(roomId, data) {
14989
+ try {
14990
+ await this.transport.postJson(`/api/rooms/${roomId}/terminal`, { data });
14991
+ } catch {}
14992
+ }
14993
+ }
14994
+ var RETRY2;
14995
+ var init_RoomRepository = __esm(() => {
14996
+ RETRY2 = { maxRetries: 3, baseDelay: 1000 };
14997
+ });
14998
+
14999
+ // src/domain/repositories/AttachmentRepository.ts
15000
+ class AttachmentRepository {
15001
+ transport;
15002
+ constructor(transport) {
15003
+ this.transport = transport;
15004
+ }
15005
+ async listForMessage(roomId, messageId) {
15006
+ return this.transport.getJson(`/api/rooms/${roomId}/messages/${messageId}/attachments`);
15007
+ }
15008
+ async download(attachmentId) {
15009
+ return this.transport.getRaw(`/api/attachments/${attachmentId}`);
15010
+ }
15011
+ }
15012
+
15013
+ // src/domain/usecases/SendMessage.ts
15014
+ class SendMessage {
15015
+ messageRepository;
15016
+ constructor(messageRepository) {
15017
+ this.messageRepository = messageRepository;
15018
+ }
15019
+ async execute(roomId, sender, content, color) {
15020
+ return this.messageRepository.send(roomId, sender, content, color);
15021
+ }
15022
+ }
15023
+
15024
+ // src/domain/usecases/CreateRoom.ts
15025
+ class CreateRoom {
15026
+ roomRepository;
15027
+ constructor(roomRepository) {
15028
+ this.roomRepository = roomRepository;
15029
+ }
15030
+ async execute(name) {
15031
+ return this.roomRepository.create(name);
15032
+ }
15033
+ }
15034
+
15035
+ // src/domain/usecases/DeleteRoom.ts
15036
+ class DeleteRoom {
15037
+ roomRepository;
15038
+ constructor(roomRepository) {
15039
+ this.roomRepository = roomRepository;
15040
+ }
15041
+ async execute(roomId) {
15042
+ return this.roomRepository.delete(roomId);
15043
+ }
15044
+ }
15045
+
15046
+ // src/domain/usecases/SendLog.ts
15047
+ class SendLog {
15048
+ messageRepository;
15049
+ constructor(messageRepository) {
15050
+ this.messageRepository = messageRepository;
15051
+ }
15052
+ async execute(roomId, sender, content, opts) {
15053
+ return this.messageRepository.sendLog(roomId, sender, content, opts);
15054
+ }
15055
+ }
15056
+
15057
+ // src/domain/usecases/SendTeamInfo.ts
15058
+ class SendTeamInfo {
15059
+ roomRepository;
15060
+ constructor(roomRepository) {
15061
+ this.roomRepository = roomRepository;
15062
+ }
15063
+ async execute(roomId, payload) {
15064
+ return this.roomRepository.sendTeamInfo(roomId, payload);
15065
+ }
15066
+ }
15067
+
15068
+ // src/domain/usecases/SendCommands.ts
15069
+ class SendCommands {
15070
+ roomRepository;
15071
+ constructor(roomRepository) {
15072
+ this.roomRepository = roomRepository;
15073
+ }
15074
+ async execute(roomId, payload) {
15075
+ return this.roomRepository.sendCommands(roomId, payload);
15076
+ }
15077
+ }
15078
+
15079
+ // src/domain/usecases/SendTasks.ts
15080
+ class SendTasks {
15081
+ roomRepository;
15082
+ constructor(roomRepository) {
15083
+ this.roomRepository = roomRepository;
15084
+ }
15085
+ async execute(roomId, payload) {
15086
+ return this.roomRepository.sendTasks(roomId, payload);
15087
+ }
15088
+ }
15089
+
15090
+ // src/domain/usecases/SendTerminalData.ts
15091
+ class SendTerminalData {
15092
+ roomRepository;
15093
+ constructor(roomRepository) {
15094
+ this.roomRepository = roomRepository;
15095
+ }
15096
+ async execute(roomId, data) {
15097
+ return this.roomRepository.sendTerminalData(roomId, data);
15098
+ }
15099
+ }
15100
+
15101
+ // src/domain/services/InboxRouter.ts
15102
+ import { dirname as dirname2 } from "node:path";
15103
+
15104
+ class InboxRouter {
15105
+ fs;
15106
+ constructor(fs) {
15107
+ this.fs = fs;
15108
+ }
15109
+ route(msg, opts) {
15110
+ const entry = {
15111
+ from: `meet-ai:${msg.sender}`,
15112
+ text: msg.content,
15113
+ timestamp: new Date().toISOString(),
15114
+ read: false
15115
+ };
15116
+ if (opts.attachmentPaths?.length) {
15117
+ entry.attachments = opts.attachmentPaths;
15118
+ }
15119
+ const members = this.getTeamMembers(opts.teamDir);
15120
+ const targets = this.resolveInboxTargets(msg.content, members);
15121
+ if (targets) {
15122
+ for (const target of targets) {
15123
+ this.appendToInbox(`${opts.inboxDir}/${target}.json`, entry);
15124
+ }
15125
+ } else if (opts.defaultInboxPath) {
15126
+ this.appendToInbox(opts.defaultInboxPath, entry);
15127
+ }
15128
+ }
15129
+ checkIdle(opts) {
15130
+ const members = this.getTeamMembers(opts.teamDir);
15131
+ const newlyIdle = this.checkIdleAgents(opts.inboxDir, members, opts.inbox, opts.notified);
15132
+ for (const agent of newlyIdle) {
15133
+ opts.notified.add(agent);
15134
+ if (opts.defaultInboxPath) {
15135
+ this.appendToInbox(opts.defaultInboxPath, {
15136
+ from: "meet-ai:idle-check",
15137
+ text: `${agent} idle for 5+ minutes`,
15138
+ timestamp: new Date().toISOString(),
15139
+ read: false
15140
+ });
14825
15141
  }
14826
- return connect();
14827
- },
14828
- async generateKey() {
14829
- const res = await fetch(`${baseUrl}/api/keys`, {
14830
- method: "POST",
14831
- headers: headers()
14832
- });
14833
- if (!res.ok) {
14834
- const err2 = await res.json();
14835
- throw new Error(err2.error ?? `HTTP ${res.status}`);
15142
+ }
15143
+ }
15144
+ appendToInbox(path, entry) {
15145
+ this.fs.mkdirSync(dirname2(path), { recursive: true });
15146
+ let messages = [];
15147
+ try {
15148
+ messages = JSON.parse(this.fs.readFileSync(path, "utf-8"));
15149
+ } catch {}
15150
+ messages.push(entry);
15151
+ this.fs.writeFileSync(path, JSON.stringify(messages, null, 2));
15152
+ }
15153
+ getTeamMembers(teamDir) {
15154
+ try {
15155
+ const config2 = JSON.parse(this.fs.readFileSync(`${teamDir}/config.json`, "utf-8"));
15156
+ return new Set(config2.members?.map((m) => m.name) || []);
15157
+ } catch {
15158
+ return new Set;
15159
+ }
15160
+ }
15161
+ resolveInboxTargets(content, members) {
15162
+ const mentions = content.match(/@([\w-]+)/g);
15163
+ if (!mentions)
15164
+ return null;
15165
+ const valid = [...new Set(mentions.map((m) => m.slice(1)))].filter((name) => members.has(name));
15166
+ return valid.length > 0 ? valid : null;
15167
+ }
15168
+ checkIdleAgents(inboxDir, members, excludeAgent, notified, now = Date.now()) {
15169
+ const newlyIdle = [];
15170
+ for (const member of members) {
15171
+ if (member === excludeAgent)
15172
+ continue;
15173
+ const inboxPath = `${inboxDir}/${member}.json`;
15174
+ let mtime;
15175
+ try {
15176
+ mtime = this.fs.statSync(inboxPath).mtimeMs;
15177
+ } catch {
15178
+ continue;
14836
15179
  }
14837
- return res.json();
14838
- },
14839
- async deleteRoom(roomId) {
14840
- const res = await fetch(`${baseUrl}/api/rooms/${roomId}`, {
14841
- method: "DELETE",
14842
- headers: headers()
14843
- });
14844
- if (!res.ok) {
14845
- const err2 = await res.json().catch(() => ({}));
14846
- throw new Error(err2.error ?? `HTTP ${res.status}`);
15180
+ const idleMs = now - mtime;
15181
+ if (idleMs >= IDLE_THRESHOLD_MS) {
15182
+ if (!notified.has(member)) {
15183
+ newlyIdle.push(member);
15184
+ }
15185
+ } else {
15186
+ notified.delete(member);
14847
15187
  }
14848
- },
14849
- async sendTerminalData(roomId, data) {
14850
- try {
14851
- await fetch(`${baseUrl}/api/rooms/${roomId}/terminal`, {
14852
- method: "POST",
14853
- headers: headers(),
14854
- body: JSON.stringify({ data })
14855
- });
14856
- } catch {}
14857
15188
  }
14858
- };
15189
+ return newlyIdle;
15190
+ }
14859
15191
  }
14860
- var ATTACHMENTS_DIR = "/tmp/meet-ai-attachments", MAX_AGE_MS;
14861
- var init_client = __esm(() => {
14862
- MAX_AGE_MS = 5 * 60 * 1000;
15192
+ var IDLE_THRESHOLD_MS;
15193
+ var init_InboxRouter = __esm(() => {
15194
+ IDLE_THRESHOLD_MS = 5 * 60 * 1000;
14863
15195
  });
14864
15196
 
14865
- // src/lib/client-factory.ts
14866
- var exports_client_factory = {};
14867
- __export(exports_client_factory, {
15197
+ // src/domain/usecases/Listen.ts
15198
+ class Listen {
15199
+ connectionAdapter;
15200
+ messageRepository;
15201
+ constructor(connectionAdapter, messageRepository) {
15202
+ this.connectionAdapter = connectionAdapter;
15203
+ this.messageRepository = messageRepository;
15204
+ }
15205
+ execute(roomId, opts) {
15206
+ return this.connectionAdapter.listen(roomId, opts);
15207
+ }
15208
+ }
15209
+
15210
+ // src/domain/usecases/ListenLobby.ts
15211
+ class ListenLobby {
15212
+ connectionAdapter;
15213
+ constructor(connectionAdapter) {
15214
+ this.connectionAdapter = connectionAdapter;
15215
+ }
15216
+ execute(opts) {
15217
+ return this.connectionAdapter.listenLobby(opts);
15218
+ }
15219
+ }
15220
+
15221
+ // src/domain/usecases/Poll.ts
15222
+ class Poll {
15223
+ messageRepository;
15224
+ constructor(messageRepository) {
15225
+ this.messageRepository = messageRepository;
15226
+ }
15227
+ async execute(roomId, opts) {
15228
+ return this.messageRepository.list(roomId, opts);
15229
+ }
15230
+ }
15231
+
15232
+ // src/domain/usecases/GenerateKey.ts
15233
+ class GenerateKey {
15234
+ connectionAdapter;
15235
+ constructor(connectionAdapter) {
15236
+ this.connectionAdapter = connectionAdapter;
15237
+ }
15238
+ async execute() {
15239
+ return this.connectionAdapter.generateKey();
15240
+ }
15241
+ }
15242
+
15243
+ // src/domain/usecases/GetAttachments.ts
15244
+ class GetAttachments {
15245
+ attachmentRepository;
15246
+ constructor(attachmentRepository) {
15247
+ this.attachmentRepository = attachmentRepository;
15248
+ }
15249
+ async execute(roomId, messageId) {
15250
+ return this.attachmentRepository.listForMessage(roomId, messageId);
15251
+ }
15252
+ }
15253
+
15254
+ // src/domain/usecases/DownloadAttachment.ts
15255
+ class DownloadAttachment {
15256
+ attachmentRepository;
15257
+ constructor(attachmentRepository) {
15258
+ this.attachmentRepository = attachmentRepository;
15259
+ }
15260
+ async execute(attachmentId) {
15261
+ return this.attachmentRepository.download(attachmentId);
15262
+ }
15263
+ }
15264
+
15265
+ // src/domain/bootstrap.ts
15266
+ var exports_bootstrap = {};
15267
+ __export(exports_bootstrap, {
15268
+ getContainer: () => getContainer,
14868
15269
  getClient: () => getClient
14869
15270
  });
15271
+ function cleanupOldAttachments() {
15272
+ try {
15273
+ const { readdirSync: readdirSync2, statSync: statSync3, unlinkSync } = __require("node:fs");
15274
+ const now = Date.now();
15275
+ for (const entry of readdirSync2(ATTACHMENTS_DIR)) {
15276
+ try {
15277
+ const filePath = `${ATTACHMENTS_DIR}/${entry}`;
15278
+ const mtime = statSync3(filePath).mtimeMs;
15279
+ if (now - mtime > MAX_AGE_MS) {
15280
+ unlinkSync(filePath);
15281
+ }
15282
+ } catch {}
15283
+ }
15284
+ } catch {}
15285
+ }
15286
+ function createContainer() {
15287
+ const config2 = getMeetAiConfig();
15288
+ const transport = new HttpTransport(config2.url, config2.key);
15289
+ const messageRepository = new MessageRepository(transport);
15290
+ const roomRepository = new RoomRepository(transport);
15291
+ const attachmentRepository = new AttachmentRepository(transport);
15292
+ const connectionAdapter = new ConnectionAdapter(transport, config2.url, config2.key);
15293
+ const fileSystem = new FileSystemAdapter;
15294
+ const inboxRouter = new InboxRouter(fileSystem);
15295
+ return {
15296
+ sendMessage: new SendMessage(messageRepository),
15297
+ createRoom: new CreateRoom(roomRepository),
15298
+ deleteRoom: new DeleteRoom(roomRepository),
15299
+ sendLog: new SendLog(messageRepository),
15300
+ sendTeamInfo: new SendTeamInfo(roomRepository),
15301
+ sendCommands: new SendCommands(roomRepository),
15302
+ sendTasks: new SendTasks(roomRepository),
15303
+ sendTerminalData: new SendTerminalData(roomRepository),
15304
+ listen: new Listen(connectionAdapter, messageRepository),
15305
+ listenLobby: new ListenLobby(connectionAdapter),
15306
+ poll: new Poll(messageRepository),
15307
+ generateKey: new GenerateKey(connectionAdapter),
15308
+ getAttachments: new GetAttachments(attachmentRepository),
15309
+ downloadAttachment: new DownloadAttachment(attachmentRepository),
15310
+ inboxRouter
15311
+ };
15312
+ }
15313
+ function getContainer() {
15314
+ if (!container) {
15315
+ container = createContainer();
15316
+ }
15317
+ return container;
15318
+ }
14870
15319
  function getClient() {
14871
- if (!_client) {
14872
- const config2 = getMeetAiConfig();
14873
- _client = createClient(config2.url, config2.key);
14874
- }
14875
- return _client;
15320
+ const c = getContainer();
15321
+ return {
15322
+ createRoom: (name) => c.createRoom.execute(name),
15323
+ sendMessage: (roomId, sender, content, color) => c.sendMessage.execute(roomId, sender, content, color),
15324
+ getMessages: (roomId, options) => c.poll.execute(roomId, options),
15325
+ listen: (roomId, options) => c.listen.execute(roomId, options),
15326
+ sendLog: (roomId, sender, content, color, messageId) => c.sendLog.execute(roomId, sender, content, { color, messageId }),
15327
+ sendTeamInfo: (roomId, payload) => c.sendTeamInfo.execute(roomId, payload),
15328
+ sendCommands: (roomId, payload) => c.sendCommands.execute(roomId, payload),
15329
+ sendTasks: (roomId, payload) => c.sendTasks.execute(roomId, payload),
15330
+ getMessageAttachments: (roomId, messageId) => c.getAttachments.execute(roomId, messageId),
15331
+ downloadAttachment: async (attachmentId) => {
15332
+ cleanupOldAttachments();
15333
+ const response = await c.downloadAttachment.execute(attachmentId);
15334
+ const { mkdirSync: mkdirSync3, writeFileSync: writeFileSync3 } = await import("node:fs");
15335
+ mkdirSync3(ATTACHMENTS_DIR, { recursive: true });
15336
+ const safeId = attachmentId.replace(/[^a-zA-Z0-9_-]/g, "") || "unknown";
15337
+ const localPath = `${ATTACHMENTS_DIR}/${safeId}.bin`;
15338
+ const buffer = Buffer.from(await response.arrayBuffer());
15339
+ writeFileSync3(localPath, buffer);
15340
+ return localPath;
15341
+ },
15342
+ listenLobby: (options) => c.listenLobby.execute(options),
15343
+ generateKey: () => c.generateKey.execute(),
15344
+ deleteRoom: (roomId) => c.deleteRoom.execute(roomId),
15345
+ sendTerminalData: (roomId, data) => c.sendTerminalData.execute(roomId, data)
15346
+ };
14876
15347
  }
14877
- var _client = null;
14878
- var init_client_factory = __esm(() => {
15348
+ var ATTACHMENTS_DIR = "/tmp/meet-ai-attachments", MAX_AGE_MS, container = null;
15349
+ var init_bootstrap = __esm(() => {
14879
15350
  init_config();
14880
- init_client();
15351
+ init_ConnectionAdapter();
15352
+ init_FileSystemAdapter();
15353
+ init_MessageRepository();
15354
+ init_RoomRepository();
15355
+ init_InboxRouter();
15356
+ MAX_AGE_MS = 5 * 60 * 1000;
14881
15357
  });
14882
15358
 
14883
15359
  // src/commands/create-room/schema.ts
@@ -14909,7 +15385,7 @@ __export(exports_command, {
14909
15385
  var command_default;
14910
15386
  var init_command = __esm(() => {
14911
15387
  init_dist();
14912
- init_client_factory();
15388
+ init_bootstrap();
14913
15389
  init_usecase();
14914
15390
  init_output();
14915
15391
  command_default = defineCommand({
@@ -14964,7 +15440,7 @@ __export(exports_command2, {
14964
15440
  var command_default2;
14965
15441
  var init_command2 = __esm(() => {
14966
15442
  init_dist();
14967
- init_client_factory();
15443
+ init_bootstrap();
14968
15444
  init_usecase2();
14969
15445
  init_output();
14970
15446
  command_default2 = defineCommand({
@@ -15040,7 +15516,7 @@ __export(exports_command3, {
15040
15516
  var command_default3;
15041
15517
  var init_command3 = __esm(() => {
15042
15518
  init_dist();
15043
- init_client_factory();
15519
+ init_bootstrap();
15044
15520
  init_usecase3();
15045
15521
  init_output();
15046
15522
  command_default3 = defineCommand({
@@ -15123,7 +15599,7 @@ __export(exports_command4, {
15123
15599
  var command_default4;
15124
15600
  var init_command4 = __esm(() => {
15125
15601
  init_dist();
15126
- init_client_factory();
15602
+ init_bootstrap();
15127
15603
  init_usecase4();
15128
15604
  init_output();
15129
15605
  command_default4 = defineCommand({
@@ -15241,7 +15717,7 @@ __export(exports_command5, {
15241
15717
  var command_default5;
15242
15718
  var init_command5 = __esm(() => {
15243
15719
  init_dist();
15244
- init_client_factory();
15720
+ init_bootstrap();
15245
15721
  init_usecase5();
15246
15722
  init_output();
15247
15723
  command_default5 = defineCommand({
@@ -15288,78 +15764,28 @@ var init_command5 = __esm(() => {
15288
15764
  });
15289
15765
  });
15290
15766
 
15767
+ // src/inbox-router.ts
15768
+ var IDLE_CHECK_INTERVAL_MS = 60000, IDLE_THRESHOLD_MS2;
15769
+ var init_inbox_router = __esm(() => {
15770
+ IDLE_THRESHOLD_MS2 = 5 * 60 * 1000;
15771
+ });
15772
+
15291
15773
  // src/commands/listen/schema.ts
15292
15774
  var ListenInput;
15293
15775
  var init_schema6 = __esm(() => {
15294
15776
  init_zod();
15295
15777
  ListenInput = exports_external.object({
15296
- roomId: exports_external.string().min(1, "Room ID is required").regex(/^[a-zA-Z0-9_-]+$/, "Room ID must contain only alphanumeric characters, hyphens, and underscores"),
15778
+ roomId: exports_external.uuid({ error: "Room ID must be a valid uuid" }),
15297
15779
  exclude: exports_external.string().optional(),
15298
15780
  senderType: exports_external.string().optional(),
15299
15781
  team: exports_external.string().optional(),
15300
- inbox: exports_external.string().optional(),
15301
- stdinPane: exports_external.string().optional()
15782
+ inbox: exports_external.string().optional()
15302
15783
  }).refine((data) => !(data.inbox && !data.team), {
15303
15784
  message: "--inbox requires --team",
15304
15785
  path: ["inbox"]
15305
15786
  });
15306
15787
  });
15307
15788
 
15308
- // src/inbox-router.ts
15309
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync, statSync } from "node:fs";
15310
- import { dirname } from "node:path";
15311
- function appendToInbox(path, entry) {
15312
- mkdirSync(dirname(path), { recursive: true });
15313
- let messages = [];
15314
- try {
15315
- messages = JSON.parse(readFileSync2(path, "utf-8"));
15316
- } catch {}
15317
- messages.push(entry);
15318
- writeFileSync(path, JSON.stringify(messages, null, 2));
15319
- }
15320
- function getTeamMembers(teamDir) {
15321
- try {
15322
- const config2 = JSON.parse(readFileSync2(`${teamDir}/config.json`, "utf-8"));
15323
- return new Set(config2.members?.map((m) => m.name) || []);
15324
- } catch {
15325
- return new Set;
15326
- }
15327
- }
15328
- function resolveInboxTargets(content, members) {
15329
- const mentions = content.match(/@([\w-]+)/g);
15330
- if (!mentions)
15331
- return null;
15332
- const valid = [...new Set(mentions.map((m) => m.slice(1)))].filter((name) => members.has(name));
15333
- return valid.length > 0 ? valid : null;
15334
- }
15335
- function checkIdleAgents(inboxDir, members, excludeAgent, notified, now = Date.now()) {
15336
- const newlyIdle = [];
15337
- for (const member of members) {
15338
- if (member === excludeAgent)
15339
- continue;
15340
- const inboxPath = `${inboxDir}/${member}.json`;
15341
- let mtime;
15342
- try {
15343
- mtime = statSync(inboxPath).mtimeMs;
15344
- } catch {
15345
- continue;
15346
- }
15347
- const idleMs = now - mtime;
15348
- if (idleMs >= IDLE_THRESHOLD_MS) {
15349
- if (!notified.has(member)) {
15350
- newlyIdle.push(member);
15351
- }
15352
- } else {
15353
- notified.delete(member);
15354
- }
15355
- }
15356
- return newlyIdle;
15357
- }
15358
- var IDLE_CHECK_INTERVAL_MS = 60000, IDLE_THRESHOLD_MS;
15359
- var init_inbox_router = __esm(() => {
15360
- IDLE_THRESHOLD_MS = 5 * 60 * 1000;
15361
- });
15362
-
15363
15789
  // src/lib/tmux-client.ts
15364
15790
  import { execFileSync, execFile as execFileCb } from "node:child_process";
15365
15791
  function validateSessionName(name) {
@@ -15367,10 +15793,10 @@ function validateSessionName(name) {
15367
15793
  throw new Error(`Invalid tmux session name: ${name}`);
15368
15794
  }
15369
15795
  }
15370
- function parseVersion(version2) {
15371
- if (!version2)
15796
+ function parseVersion(version3) {
15797
+ if (!version3)
15372
15798
  return [0, 0];
15373
- const match = version2.match(/(\d+)\.(\d+)/);
15799
+ const match = version3.match(/(\d+)\.(\d+)/);
15374
15800
  if (!match)
15375
15801
  return [0, 0];
15376
15802
  return [Number(match[1]), Number(match[2])];
@@ -15390,6 +15816,9 @@ class TmuxClient {
15390
15816
  timeout: 5000,
15391
15817
  stdio: ["pipe", "pipe", "pipe"]
15392
15818
  }).trim();
15819
+ if (!result) {
15820
+ return { available: false, version: null, error: "tmux returned an empty version string" };
15821
+ }
15393
15822
  return { available: true, version: result };
15394
15823
  } catch (error48) {
15395
15824
  return {
@@ -15401,11 +15830,7 @@ class TmuxClient {
15401
15830
  }
15402
15831
  newSession(name, commandArgs, env) {
15403
15832
  validateSessionName(name);
15404
- if (env) {
15405
- for (const [key, value] of Object.entries(env)) {
15406
- this.exec(["-L", this.server, "set-environment", "-g", key, value]);
15407
- }
15408
- }
15833
+ const envArgs = env ? ["env", ...Object.entries(env).map(([key, value]) => `${key}=${value}`)] : [];
15409
15834
  const args = [
15410
15835
  "-L",
15411
15836
  this.server,
@@ -15418,14 +15843,10 @@ class TmuxClient {
15418
15843
  "-y",
15419
15844
  "40",
15420
15845
  "--",
15846
+ ...envArgs,
15421
15847
  ...commandArgs
15422
15848
  ];
15423
15849
  const result = this.exec(args);
15424
- if (env) {
15425
- for (const key of Object.keys(env)) {
15426
- this.exec(["-L", this.server, "set-environment", "-g", "-u", key]);
15427
- }
15428
- }
15429
15850
  if (!result.ok)
15430
15851
  return result;
15431
15852
  this.exec(["-L", this.server, "set-option", "-t", name, "remain-on-exit", "on"]);
@@ -15465,13 +15886,13 @@ class TmuxClient {
15465
15886
  "-F",
15466
15887
  "#{pane_id}\t#{session_name}\t#{pane_title}\t#{pane_current_command}"
15467
15888
  ];
15468
- return new Promise((resolve2) => {
15889
+ return new Promise((resolve3) => {
15469
15890
  execFileCb("tmux", args, { encoding: "utf8", timeout: 5000 }, (error48, stdout) => {
15470
15891
  if (error48) {
15471
- resolve2([]);
15892
+ resolve3([]);
15472
15893
  return;
15473
15894
  }
15474
- resolve2(stdout.trim().split(`
15895
+ resolve3(stdout.trim().split(`
15475
15896
  `).filter((line) => line.trim()).map((line) => {
15476
15897
  const [paneId, sessionName, title, command] = line.split("\t");
15477
15898
  return { paneId: paneId ?? "", sessionName: sessionName ?? "", title: title ?? "", command: command ?? "" };
@@ -15524,10 +15945,10 @@ class TmuxClient {
15524
15945
  if (lines > 0) {
15525
15946
  args.push("-S", `-${lines}`);
15526
15947
  }
15527
- return new Promise((resolve2) => {
15948
+ return new Promise((resolve3) => {
15528
15949
  execFileCb("tmux", args, { encoding: "utf8", timeout: 5000 }, (error48, stdout) => {
15529
15950
  if (error48) {
15530
- resolve2([]);
15951
+ resolve3([]);
15531
15952
  return;
15532
15953
  }
15533
15954
  const result = stdout.split(`
@@ -15535,7 +15956,7 @@ class TmuxClient {
15535
15956
  while (result.length > 0 && result[result.length - 1] === "") {
15536
15957
  result.pop();
15537
15958
  }
15538
- resolve2(result);
15959
+ resolve3(result);
15539
15960
  });
15540
15961
  });
15541
15962
  }
@@ -15579,36 +16000,12 @@ var init_tmux_client = __esm(() => {
15579
16000
  SESSION_NAME_RE = /^[a-zA-Z0-9_-]+$/;
15580
16001
  });
15581
16002
 
15582
- // src/commands/listen/usecase.ts
15583
- function routeToInbox(msg, inboxDir, defaultInboxPath, teamDir, stdinPane, attachmentPaths) {
15584
- const entry = {
15585
- from: `meet-ai:${msg.sender}`,
15586
- text: msg.content,
15587
- timestamp: new Date().toISOString(),
15588
- read: false
15589
- };
15590
- if (attachmentPaths?.length) {
15591
- entry.attachments = attachmentPaths;
15592
- }
15593
- const members = getTeamMembers(teamDir);
15594
- const targets = resolveInboxTargets(msg.content, members);
15595
- if (targets) {
15596
- for (const target of targets) {
15597
- appendToInbox(`${inboxDir}/${target}.json`, entry);
15598
- }
15599
- } else if (stdinPane) {} else if (defaultInboxPath) {
15600
- appendToInbox(defaultInboxPath, entry);
15601
- }
15602
- }
15603
- function listen(client, input) {
15604
- const parsed = ListenInput.parse(input);
15605
- const { roomId, exclude, senderType, team, inbox, stdinPane } = parsed;
15606
- const inboxDir = team ? `${process.env.HOME}/.claude/teams/${team}/inboxes` : null;
15607
- const defaultInboxPath = inboxDir && inbox ? `${inboxDir}/${inbox}.json` : null;
15608
- const teamDir = team ? `${process.env.HOME}/.claude/teams/${team}` : null;
16003
+ // src/commands/listen/shared.ts
16004
+ function createTerminalControlHandler(input) {
16005
+ const { client, roomId, teamDir } = input;
15609
16006
  const tmuxClient = new TmuxClient({ server: "meet-ai", scrollback: 50000 });
15610
16007
  let terminalInterval = null;
15611
- const onMessage = (msg) => {
16008
+ function handle(msg) {
15612
16009
  if (msg.type === "terminal_resize") {
15613
16010
  const cols = msg.cols;
15614
16011
  if (typeof cols === "number" && cols > 0) {
@@ -15620,7 +16017,7 @@ function listen(client, input) {
15620
16017
  }
15621
16018
  });
15622
16019
  }
15623
- return;
16020
+ return true;
15624
16021
  }
15625
16022
  if (msg.type === "terminal_subscribe") {
15626
16023
  const roomPrefix = roomId.slice(0, 8);
@@ -15673,50 +16070,76 @@ function listen(client, input) {
15673
16070
  await client.sendTerminalData(roomId, payload);
15674
16071
  } catch {}
15675
16072
  }, TERMINAL_POLL_MS);
15676
- return;
16073
+ return true;
15677
16074
  }
15678
16075
  if (msg.type === "terminal_unsubscribe") {
15679
16076
  if (terminalInterval) {
15680
16077
  clearInterval(terminalInterval);
15681
16078
  terminalInterval = null;
15682
16079
  }
15683
- return;
16080
+ return true;
15684
16081
  }
15685
16082
  if (msg.type === "terminal_data") {
15686
- return;
16083
+ return true;
16084
+ }
16085
+ return false;
16086
+ }
16087
+ function shutdown() {
16088
+ if (terminalInterval) {
16089
+ clearInterval(terminalInterval);
16090
+ terminalInterval = null;
15687
16091
  }
15688
- if (msg.id && msg.room_id && msg.attachment_count > 0) {
16092
+ }
16093
+ return { handle, shutdown };
16094
+ }
16095
+ var init_shared = __esm(() => {
16096
+ init_tmux_client();
16097
+ });
16098
+
16099
+ // src/commands/listen/listen-claude.ts
16100
+ function listenClaude(client, input, inboxRouter) {
16101
+ const parsed = ListenInput.parse(input);
16102
+ const { roomId, exclude, senderType, team, inbox } = parsed;
16103
+ const inboxDir = team ? `${process.env.HOME}/.claude/teams/${team}/inboxes` : null;
16104
+ const defaultInboxPath = inboxDir && inbox ? `${inboxDir}/${inbox}.json` : null;
16105
+ const teamDir = team ? `${process.env.HOME}/.claude/teams/${team}` : undefined;
16106
+ const terminal = createTerminalControlHandler({ client, roomId, teamDir, inboxRouter });
16107
+ const onMessage = (msg) => {
16108
+ if (terminal.handle(msg))
16109
+ return;
16110
+ if (msg.id && msg.room_id && (msg.attachment_count ?? 0) > 0) {
15689
16111
  downloadMessageAttachments(client, msg.room_id, msg.id).then((paths) => {
15690
16112
  const output = paths.length ? { ...msg, attachments: paths } : msg;
15691
16113
  console.log(JSON.stringify(output));
15692
- if (inboxDir && teamDir)
15693
- routeToInbox(msg, inboxDir, defaultInboxPath, teamDir, stdinPane, paths);
16114
+ if (inboxDir && teamDir && inboxRouter) {
16115
+ inboxRouter.route(msg, {
16116
+ inboxDir,
16117
+ defaultInboxPath,
16118
+ teamDir,
16119
+ attachmentPaths: paths
16120
+ });
16121
+ }
15694
16122
  });
15695
- } else {
15696
- console.log(JSON.stringify(msg));
15697
- if (inboxDir && teamDir)
15698
- routeToInbox(msg, inboxDir, defaultInboxPath, teamDir, stdinPane);
16123
+ return;
16124
+ }
16125
+ console.log(JSON.stringify(msg));
16126
+ if (inboxDir && teamDir && inboxRouter) {
16127
+ inboxRouter.route(msg, { inboxDir, defaultInboxPath, teamDir });
15699
16128
  }
15700
16129
  };
15701
16130
  const ws = client.listen(roomId, { exclude, senderType, onMessage });
15702
16131
  let idleCheckTimeout = null;
15703
16132
  const idleNotified = new Set;
15704
- if (inboxDir && inbox && teamDir) {
16133
+ if (inboxDir && inbox && teamDir && inboxRouter) {
15705
16134
  let scheduleIdleCheck = function() {
15706
16135
  idleCheckTimeout = setTimeout(() => {
15707
- const members = getTeamMembers(teamDir);
15708
- const newlyIdle = checkIdleAgents(inboxDir, members, inbox, idleNotified);
15709
- for (const agent of newlyIdle) {
15710
- idleNotified.add(agent);
15711
- if (defaultInboxPath) {
15712
- appendToInbox(defaultInboxPath, {
15713
- from: "meet-ai:idle-check",
15714
- text: `${agent} idle for 5+ minutes`,
15715
- timestamp: new Date().toISOString(),
15716
- read: false
15717
- });
15718
- }
15719
- }
16136
+ inboxRouter.checkIdle({
16137
+ inboxDir,
16138
+ teamDir,
16139
+ inbox,
16140
+ defaultInboxPath: defaultInboxPath ?? null,
16141
+ notified: idleNotified
16142
+ });
15720
16143
  scheduleIdleCheck();
15721
16144
  }, IDLE_CHECK_INTERVAL_MS);
15722
16145
  };
@@ -15725,10 +16148,621 @@ function listen(client, input) {
15725
16148
  function shutdown() {
15726
16149
  if (idleCheckTimeout)
15727
16150
  clearTimeout(idleCheckTimeout);
15728
- if (terminalInterval) {
15729
- clearInterval(terminalInterval);
15730
- terminalInterval = null;
16151
+ terminal.shutdown();
16152
+ if (ws.readyState === WebSocket.OPEN) {
16153
+ ws.close(1000, "client shutdown");
16154
+ }
16155
+ process.exit(0);
16156
+ }
16157
+ process.on("SIGINT", shutdown);
16158
+ process.on("SIGTERM", shutdown);
16159
+ process.on("SIGHUP", shutdown);
16160
+ return ws;
16161
+ }
16162
+ var init_listen_claude = __esm(() => {
16163
+ init_inbox_router();
16164
+ init_schema6();
16165
+ init_shared();
16166
+ });
16167
+
16168
+ // src/lib/codex-app-server.ts
16169
+ import {
16170
+ spawn
16171
+ } from "node:child_process";
16172
+ import { stderr } from "node:process";
16173
+ import { createInterface } from "node:readline";
16174
+ function isObject2(value) {
16175
+ return typeof value === "object" && value !== null;
16176
+ }
16177
+ function isJsonRpcResponse(value) {
16178
+ return isObject2(value) && "id" in value && (("result" in value) || ("error" in value));
16179
+ }
16180
+ function isJsonRpcServerRequest(value) {
16181
+ return isObject2(value) && typeof value.method === "string" && "id" in value && !("result" in value) && !("error" in value);
16182
+ }
16183
+ function isJsonRpcNotification(value) {
16184
+ return isObject2(value) && typeof value.method === "string" && !("id" in value);
16185
+ }
16186
+ function toErrorMessage(error48) {
16187
+ if (error48 instanceof Error)
16188
+ return error48.message;
16189
+ return String(error48);
16190
+ }
16191
+ function formatRoomMessageForCodex(input) {
16192
+ const lines = [
16193
+ `New message from meet-ai sender "${input.sender}" at ${input.timestamp ?? new Date().toISOString()}:`,
16194
+ "",
16195
+ input.content
16196
+ ];
16197
+ if (input.attachments?.length) {
16198
+ lines.push("", `Attachments: ${input.attachments.join(", ")}`);
16199
+ }
16200
+ return lines.join(`
16201
+ `);
16202
+ }
16203
+ function maybeActiveTurnId(thread) {
16204
+ if (!thread || !Array.isArray(thread.turns))
16205
+ return null;
16206
+ for (let index = thread.turns.length - 1;index >= 0; index -= 1) {
16207
+ const turn = thread.turns[index];
16208
+ if (turn?.status === "inProgress" && typeof turn.id === "string") {
16209
+ return turn.id;
16210
+ }
16211
+ }
16212
+ return null;
16213
+ }
16214
+ function isSteerPreconditionError(error48) {
16215
+ if (!isObject2(error48))
16216
+ return false;
16217
+ const message = typeof error48.message === "string" ? error48.message.toLowerCase() : "";
16218
+ return message.includes("expected") || message.includes("active turn") || message.includes("precondition");
16219
+ }
16220
+ function isAgentMessageDeltaNotification(params) {
16221
+ return isObject2(params) && typeof params.threadId === "string" && typeof params.turnId === "string" && typeof params.itemId === "string" && typeof params.delta === "string";
16222
+ }
16223
+ function extractAgentMessageDelta(params) {
16224
+ if (!isAgentMessageDeltaNotification(params)) {
16225
+ return { itemId: null, turnId: null, text: null };
16226
+ }
16227
+ return {
16228
+ itemId: params.itemId,
16229
+ turnId: params.turnId,
16230
+ text: params.delta
16231
+ };
16232
+ }
16233
+ function isItemCompletedNotification(params) {
16234
+ return isObject2(params) && typeof params.threadId === "string" && typeof params.turnId === "string" && isObject2(params.item) && typeof params.item.type === "string" && typeof params.item.id === "string";
16235
+ }
16236
+ function extractCompletedAgentMessage(params) {
16237
+ if (!isItemCompletedNotification(params))
16238
+ return null;
16239
+ if (params.item.type !== "agentMessage")
16240
+ return null;
16241
+ return {
16242
+ itemId: params.item.id,
16243
+ turnId: params.turnId,
16244
+ text: params.item.text
16245
+ };
16246
+ }
16247
+ function isThreadStartedNotification(params) {
16248
+ return isObject2(params) && isObject2(params.thread) && typeof params.thread.id === "string";
16249
+ }
16250
+ function isTurnStartedNotification(params) {
16251
+ return isObject2(params) && typeof params.threadId === "string" && isObject2(params.turn) && typeof params.turn.id === "string";
16252
+ }
16253
+ function isTurnCompletedNotification(params) {
16254
+ return isObject2(params) && typeof params.threadId === "string" && isObject2(params.turn) && typeof params.turn.id === "string";
16255
+ }
16256
+
16257
+ class CodexAppServerBridge {
16258
+ threadId;
16259
+ cwd;
16260
+ codexBin;
16261
+ clientName;
16262
+ clientTitle;
16263
+ clientVersion;
16264
+ experimentalApi;
16265
+ env;
16266
+ spawnFn;
16267
+ stderrStream;
16268
+ child = null;
16269
+ stdoutReader = null;
16270
+ readyPromise = null;
16271
+ pendingRequests = new Map;
16272
+ nextRequestId = 1;
16273
+ activeTurnId = null;
16274
+ injectionQueue = Promise.resolve();
16275
+ eventHandler = null;
16276
+ constructor(options) {
16277
+ this.threadId = options.threadId ?? null;
16278
+ this.cwd = options.cwd;
16279
+ this.codexBin = options.codexBin ?? options.env?.MEET_AI_CODEX_PATH ?? process.env.MEET_AI_CODEX_PATH ?? "codex";
16280
+ this.clientName = options.clientName ?? "meet_ai";
16281
+ this.clientTitle = options.clientTitle ?? "meet-ai CLI";
16282
+ this.clientVersion = options.clientVersion ?? "0.0.0";
16283
+ this.experimentalApi = options.experimentalApi ?? false;
16284
+ this.env = options.env ?? process.env;
16285
+ this.spawnFn = options.spawnFn ?? spawn;
16286
+ this.stderrStream = options.stderr ?? stderr;
16287
+ }
16288
+ async start() {
16289
+ if (!this.readyPromise) {
16290
+ this.readyPromise = this.startInternal().catch((error48) => {
16291
+ this.readyPromise = null;
16292
+ throw error48;
16293
+ });
16294
+ }
16295
+ return this.readyPromise;
16296
+ }
16297
+ async injectText(input) {
16298
+ const text = formatRoomMessageForCodex(input);
16299
+ return this.injectPrompt(text);
16300
+ }
16301
+ async injectPrompt(text) {
16302
+ return this.enqueue(async () => {
16303
+ await this.start();
16304
+ const payload = [{ type: "text", text, text_elements: [] }];
16305
+ const threadId = this.threadId;
16306
+ if (!threadId) {
16307
+ throw new Error("Codex app-server bridge does not have an active thread");
16308
+ }
16309
+ if (this.activeTurnId) {
16310
+ try {
16311
+ const result2 = await this.request("turn/steer", {
16312
+ threadId,
16313
+ input: payload,
16314
+ expectedTurnId: this.activeTurnId
16315
+ });
16316
+ this.activeTurnId = result2.turnId;
16317
+ return { mode: "steer", threadId, turnId: result2.turnId };
16318
+ } catch (error48) {
16319
+ if (!isSteerPreconditionError(error48))
16320
+ throw error48;
16321
+ this.activeTurnId = null;
16322
+ }
16323
+ }
16324
+ const result = await this.request("turn/start", {
16325
+ threadId,
16326
+ input: payload
16327
+ });
16328
+ this.activeTurnId = result.turn.id;
16329
+ return { mode: "start", threadId, turnId: result.turn.id };
16330
+ });
16331
+ }
16332
+ getThreadId() {
16333
+ return this.threadId;
16334
+ }
16335
+ async close() {
16336
+ this.readyPromise = null;
16337
+ this.activeTurnId = null;
16338
+ if (this.stdoutReader) {
16339
+ this.stdoutReader.close();
16340
+ this.stdoutReader = null;
16341
+ }
16342
+ const child = this.child;
16343
+ this.child = null;
16344
+ if (!child)
16345
+ return;
16346
+ for (const pending of this.pendingRequests.values()) {
16347
+ pending.reject(new Error("Codex app-server bridge closed"));
16348
+ }
16349
+ this.pendingRequests.clear();
16350
+ child.kill();
16351
+ }
16352
+ setEventHandler(handler) {
16353
+ this.eventHandler = handler;
16354
+ }
16355
+ enqueue(fn) {
16356
+ const next = this.injectionQueue.then(fn, fn);
16357
+ this.injectionQueue = next.catch(() => {
16358
+ return;
16359
+ });
16360
+ return next;
16361
+ }
16362
+ async startInternal() {
16363
+ const child = this.spawnFn(this.codexBin, [
16364
+ "app-server",
16365
+ "--enable",
16366
+ "multi_agent",
16367
+ "--enable",
16368
+ "memories",
16369
+ "--enable",
16370
+ "realtime_conversation",
16371
+ "-c",
16372
+ 'sandbox_mode="workspace-write"',
16373
+ "-c",
16374
+ "sandbox_workspace_write.network_access=true",
16375
+ "-c",
16376
+ 'web_search="live"',
16377
+ "--listen",
16378
+ "stdio://"
16379
+ ], {
16380
+ cwd: this.cwd,
16381
+ env: this.env,
16382
+ stdio: ["pipe", "pipe", "pipe"]
16383
+ });
16384
+ this.child = child;
16385
+ this.stdoutReader = createInterface({ input: child.stdout });
16386
+ this.stdoutReader.on("line", (line) => {
16387
+ this.handleLine(line);
16388
+ });
16389
+ child.stderr.on("data", (chunk) => {
16390
+ this.stderrStream.write(chunk);
16391
+ });
16392
+ child.on("exit", (_code, signal) => {
16393
+ const reason = new Error(`codex app-server exited${signal ? ` with signal ${signal}` : ""}`);
16394
+ for (const pending of this.pendingRequests.values()) {
16395
+ pending.reject(reason);
16396
+ }
16397
+ this.pendingRequests.clear();
16398
+ this.child = null;
16399
+ this.stdoutReader = null;
16400
+ this.readyPromise = null;
16401
+ });
16402
+ await this.request("initialize", {
16403
+ clientInfo: {
16404
+ name: this.clientName,
16405
+ title: this.clientTitle,
16406
+ version: this.clientVersion
16407
+ },
16408
+ capabilities: {
16409
+ experimentalApi: this.experimentalApi
16410
+ }
16411
+ });
16412
+ this.notify("initialized");
16413
+ if (this.threadId) {
16414
+ const resumeParams = {
16415
+ threadId: this.threadId,
16416
+ persistExtendedHistory: this.experimentalApi
16417
+ };
16418
+ try {
16419
+ const resumeResult = await this.request("thread/resume", resumeParams);
16420
+ this.threadId = typeof resumeResult.thread?.id === "string" ? resumeResult.thread.id : this.threadId;
16421
+ this.activeTurnId = maybeActiveTurnId(resumeResult.thread);
16422
+ return;
16423
+ } catch {
16424
+ this.stderrStream.write(`meet-ai: codex app-server could not resume thread ${this.threadId}, starting fresh
16425
+ `);
16426
+ this.threadId = null;
16427
+ this.activeTurnId = null;
16428
+ }
16429
+ }
16430
+ const startResult = await this.request("thread/start", {
16431
+ cwd: this.cwd,
16432
+ experimentalRawEvents: false,
16433
+ persistExtendedHistory: this.experimentalApi
16434
+ });
16435
+ this.threadId = typeof startResult.thread?.id === "string" ? startResult.thread.id : null;
16436
+ this.activeTurnId = maybeActiveTurnId(startResult.thread);
16437
+ }
16438
+ async handleLine(line) {
16439
+ const trimmed = line.trim();
16440
+ if (!trimmed)
16441
+ return;
16442
+ let message;
16443
+ try {
16444
+ message = JSON.parse(trimmed);
16445
+ } catch {
16446
+ this.stderrStream.write(`meet-ai: failed to parse codex app-server line: ${trimmed}
16447
+ `);
16448
+ return;
16449
+ }
16450
+ if (isJsonRpcResponse(message)) {
16451
+ const pending = this.pendingRequests.get(message.id);
16452
+ if (!pending)
16453
+ return;
16454
+ this.pendingRequests.delete(message.id);
16455
+ if (message.error) {
16456
+ pending.reject(new Error(message.error.message ?? "Unknown app-server error"));
16457
+ return;
16458
+ }
16459
+ pending.resolve(message.result);
16460
+ return;
16461
+ }
16462
+ if (isJsonRpcServerRequest(message)) {
16463
+ this.respondToServerRequest(message);
16464
+ return;
16465
+ }
16466
+ if (isJsonRpcNotification(message)) {
16467
+ this.handleNotification(message);
16468
+ }
16469
+ }
16470
+ handleNotification(message) {
16471
+ if (message.method === "thread/started") {
16472
+ if (isThreadStartedNotification(message.params))
16473
+ this.threadId = message.params.thread.id;
16474
+ return;
16475
+ }
16476
+ if (message.method === "turn/started") {
16477
+ if (isTurnStartedNotification(message.params) && message.params.threadId === this.threadId) {
16478
+ this.activeTurnId = message.params.turn.id;
16479
+ }
16480
+ return;
16481
+ }
16482
+ if (message.method === "turn/completed") {
16483
+ if (isTurnCompletedNotification(message.params) && message.params.threadId === this.threadId && message.params.turn.id === this.activeTurnId) {
16484
+ this.activeTurnId = null;
16485
+ }
16486
+ this.emitEvent({
16487
+ type: "turn_completed",
16488
+ turnId: isTurnCompletedNotification(message.params) ? message.params.turn.id : null
16489
+ });
16490
+ return;
16491
+ }
16492
+ if (message.method === "item/agentMessage/delta") {
16493
+ const event = extractAgentMessageDelta(message.params);
16494
+ if (event.text) {
16495
+ this.emitEvent({
16496
+ type: "agent_message_delta",
16497
+ itemId: event.itemId,
16498
+ turnId: event.turnId,
16499
+ text: event.text
16500
+ });
16501
+ }
16502
+ return;
16503
+ }
16504
+ if (message.method === "item/completed") {
16505
+ const event = extractCompletedAgentMessage(message.params);
16506
+ if (event?.text) {
16507
+ this.emitEvent({
16508
+ type: "agent_message_completed",
16509
+ itemId: event.itemId,
16510
+ turnId: event.turnId,
16511
+ text: event.text
16512
+ });
16513
+ }
16514
+ }
16515
+ }
16516
+ emitEvent(event) {
16517
+ if (!this.eventHandler)
16518
+ return;
16519
+ try {
16520
+ this.eventHandler(event);
16521
+ } catch (error48) {
16522
+ this.stderrStream.write(`meet-ai: codex app-server event handler failed: ${toErrorMessage(error48)}
16523
+ `);
16524
+ }
16525
+ }
16526
+ respondToServerRequest(message) {
16527
+ switch (message.method) {
16528
+ case "item/commandExecution/requestApproval": {
16529
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16530
+ `);
16531
+ this.writeMessage({ id: message.id, result: { decision: "decline" } });
16532
+ return;
16533
+ }
16534
+ case "item/fileChange/requestApproval": {
16535
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16536
+ `);
16537
+ this.writeMessage({ id: message.id, result: { decision: "decline" } });
16538
+ return;
16539
+ }
16540
+ case "item/tool/requestUserInput": {
16541
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16542
+ `);
16543
+ this.writeMessage({ id: message.id, result: { answers: {} } });
16544
+ return;
16545
+ }
16546
+ case "mcpServer/elicitation/request": {
16547
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16548
+ `);
16549
+ this.writeMessage({ id: message.id, result: { action: "cancel", content: null } });
16550
+ return;
16551
+ }
16552
+ case "applyPatchApproval": {
16553
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16554
+ `);
16555
+ this.writeMessage({ id: message.id, result: { decision: "denied" } });
16556
+ return;
16557
+ }
16558
+ case "execCommandApproval": {
16559
+ this.stderrStream.write(`meet-ai: auto-resolving unsupported codex app-server request ${message.method}
16560
+ `);
16561
+ this.writeMessage({ id: message.id, result: { decision: "denied" } });
16562
+ return;
16563
+ }
16564
+ default: {
16565
+ this.stderrStream.write(`meet-ai: rejecting unsupported codex app-server request ${message.method}
16566
+ `);
16567
+ this.writeMessage({
16568
+ id: message.id,
16569
+ error: {
16570
+ message: `meet-ai app-server bridge does not support ${message.method}`
16571
+ }
16572
+ });
16573
+ }
16574
+ }
16575
+ }
16576
+ notify(method, params) {
16577
+ this.writeMessage(params === undefined ? { method } : { method, params });
16578
+ }
16579
+ request(method, params) {
16580
+ const id = this.nextRequestId++;
16581
+ return new Promise((resolve3, reject) => {
16582
+ this.pendingRequests.set(id, { resolve: resolve3, reject });
16583
+ try {
16584
+ this.writeMessage(params === undefined ? { method, id } : { method, id, params });
16585
+ } catch (error48) {
16586
+ this.pendingRequests.delete(id);
16587
+ reject(error48);
16588
+ }
16589
+ });
16590
+ }
16591
+ writeMessage(message) {
16592
+ const child = this.child;
16593
+ if (!child) {
16594
+ throw new Error("Codex app-server bridge is not connected");
16595
+ }
16596
+ child.stdin.write(`${JSON.stringify(message)}
16597
+ `);
16598
+ }
16599
+ }
16600
+ function createCodexAppServerBridge(options) {
16601
+ return new CodexAppServerBridge(options);
16602
+ }
16603
+ function describeCodexAppServerError(error48) {
16604
+ return `meet-ai: failed to inject message into Codex via app-server: ${toErrorMessage(error48)}`;
16605
+ }
16606
+ var init_codex_app_server = () => {};
16607
+
16608
+ // src/commands/listen/listen-codex.ts
16609
+ function formatCodexListenOutput(msg) {
16610
+ const lines = [
16611
+ `[meet-ai] ${msg.sender} ${msg.created_at ?? new Date().toISOString()}`,
16612
+ msg.content
16613
+ ];
16614
+ if (msg.attachments?.length) {
16615
+ lines.push(`attachments: ${msg.attachments.join(", ")}`);
16616
+ }
16617
+ return `${lines.join(`
16618
+ `)}
16619
+ `;
16620
+ }
16621
+ function formatCodexInjectionOutput(result) {
16622
+ return `[meet-ai->codex] ${result.mode} ${result.turnId}
16623
+ `;
16624
+ }
16625
+ function isTruthyEnv(value) {
16626
+ if (!value)
16627
+ return false;
16628
+ const normalized = value.trim().toLowerCase();
16629
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
16630
+ }
16631
+ function normalizeFinalText(value) {
16632
+ return value.replace(/\r\n/g, `
16633
+ `).trim();
16634
+ }
16635
+ function makeMessageKey(event) {
16636
+ return event.itemId ?? event.turnId ?? "unknown";
16637
+ }
16638
+ function listenCodex(client, input, codexBridgeOverride) {
16639
+ const parsed = ListenInput.parse(input);
16640
+ const { roomId, exclude, senderType, team, inbox } = parsed;
16641
+ let shutdownStarted = false;
16642
+ if (team || inbox) {
16643
+ const flags = [team ? "--team" : null, inbox ? "--inbox" : null].filter(Boolean).join(", ");
16644
+ throw new Error(`Codex listen does not support Claude inbox routing flags (${flags}). Run meet-ai listen without Claude-specific routing options.`);
16645
+ }
16646
+ const terminal = createTerminalControlHandler({ client, roomId });
16647
+ const codexBridge = codexBridgeOverride ?? createCodexAppServerBridge({
16648
+ threadId: null,
16649
+ cwd: process.cwd(),
16650
+ experimentalApi: isTruthyEnv(process.env.MEET_AI_CODEX_APP_SERVER_EXPERIMENTAL)
16651
+ });
16652
+ const bootstrapPrompt = process.env.MEET_AI_CODEX_BOOTSTRAP_PROMPT?.trim();
16653
+ const codexSender = process.env.MEET_AI_AGENT_NAME?.trim() || "codex";
16654
+ const messageState = new Map;
16655
+ let publishQueue = Promise.resolve();
16656
+ const enqueuePublish = (task) => {
16657
+ publishQueue = publishQueue.then(task, task).catch((error48) => {
16658
+ console.error(`meet-ai: failed to publish Codex output to room: ${error48 instanceof Error ? error48.message : String(error48)}`);
16659
+ });
16660
+ };
16661
+ const publishBufferedMessage = (key) => {
16662
+ const state = messageState.get(key);
16663
+ const text = normalizeFinalText(state?.text ?? "");
16664
+ if (!state || state.sent || state.sending || !text)
16665
+ return;
16666
+ state.sending = true;
16667
+ enqueuePublish(async () => {
16668
+ try {
16669
+ await client.sendMessage(roomId, codexSender, text);
16670
+ state.sent = true;
16671
+ } finally {
16672
+ state.sending = false;
16673
+ }
16674
+ });
16675
+ };
16676
+ const mergeEventText = (event) => {
16677
+ const key = makeMessageKey(event);
16678
+ const nextText = event.text.replace(/\r\n/g, `
16679
+ `);
16680
+ if (!nextText)
16681
+ return;
16682
+ const existing = messageState.get(key);
16683
+ if (!existing) {
16684
+ messageState.set(key, { turnId: event.turnId, text: nextText, sent: false, sending: false });
16685
+ return;
15731
16686
  }
16687
+ existing.turnId = event.turnId ?? existing.turnId;
16688
+ if (event.type === "agent_message_completed") {
16689
+ existing.text = nextText;
16690
+ return;
16691
+ }
16692
+ existing.text += nextText;
16693
+ };
16694
+ codexBridge.setEventHandler((event) => {
16695
+ if (event.type === "agent_message_delta" || event.type === "agent_message_completed") {
16696
+ mergeEventText(event);
16697
+ if (event.type === "agent_message_completed") {
16698
+ publishBufferedMessage(makeMessageKey(event));
16699
+ }
16700
+ return;
16701
+ }
16702
+ if (event.type === "turn_completed") {
16703
+ for (const [key, state] of messageState.entries()) {
16704
+ if (state.turnId === event.turnId || !event.turnId && !state.sent) {
16705
+ publishBufferedMessage(key);
16706
+ }
16707
+ }
16708
+ }
16709
+ });
16710
+ const injectMessage = (message) => {
16711
+ codexBridge.injectText({
16712
+ sender: message.sender,
16713
+ content: message.content,
16714
+ timestamp: new Date().toISOString(),
16715
+ attachments: message.attachments
16716
+ }).then((result) => {
16717
+ appendCodexInboxEntry(result.threadId, {
16718
+ from: `meet-ai:${message.sender}`,
16719
+ text: message.content,
16720
+ timestamp: new Date().toISOString(),
16721
+ read: false,
16722
+ ...message.attachments?.length ? { attachments: message.attachments } : {}
16723
+ });
16724
+ console.log(formatCodexInjectionOutput(result));
16725
+ }).catch((error48) => {
16726
+ console.error(describeCodexAppServerError(error48));
16727
+ });
16728
+ };
16729
+ const onMessage = (msg) => {
16730
+ if (terminal.handle(msg))
16731
+ return;
16732
+ if (msg.id && msg.room_id && (msg.attachment_count ?? 0) > 0) {
16733
+ downloadMessageAttachments(client, msg.room_id, msg.id).then((paths) => {
16734
+ const output = paths.length ? { ...msg, attachments: paths } : msg;
16735
+ console.log(formatCodexListenOutput(output));
16736
+ injectMessage({
16737
+ sender: msg.sender,
16738
+ content: msg.content,
16739
+ attachments: paths
16740
+ });
16741
+ });
16742
+ return;
16743
+ }
16744
+ console.log(formatCodexListenOutput(msg));
16745
+ injectMessage({
16746
+ sender: msg.sender,
16747
+ content: msg.content
16748
+ });
16749
+ };
16750
+ const ws = client.listen(roomId, { exclude, senderType, onMessage });
16751
+ if (bootstrapPrompt) {
16752
+ const bootstrapRequest = codexBridge.injectPrompt(bootstrapPrompt);
16753
+ bootstrapRequest.then((result) => {
16754
+ console.log(formatCodexInjectionOutput(result));
16755
+ }).catch((error48) => {
16756
+ console.error(describeCodexAppServerError(error48));
16757
+ });
16758
+ }
16759
+ function shutdown() {
16760
+ if (shutdownStarted)
16761
+ return;
16762
+ shutdownStarted = true;
16763
+ terminal.shutdown();
16764
+ codexBridge.setEventHandler(null);
16765
+ codexBridge.close();
15732
16766
  if (ws.readyState === WebSocket.OPEN) {
15733
16767
  ws.close(1000, "client shutdown");
15734
16768
  }
@@ -15739,10 +16773,11 @@ function listen(client, input) {
15739
16773
  process.on("SIGHUP", shutdown);
15740
16774
  return ws;
15741
16775
  }
15742
- var init_usecase6 = __esm(() => {
16776
+ var init_listen_codex = __esm(() => {
16777
+ init_codex();
16778
+ init_codex_app_server();
15743
16779
  init_schema6();
15744
- init_inbox_router();
15745
- init_tmux_client();
16780
+ init_shared();
15746
16781
  });
15747
16782
 
15748
16783
  // src/commands/listen/command.ts
@@ -15752,10 +16787,11 @@ __export(exports_command6, {
15752
16787
  });
15753
16788
  var command_default6;
15754
16789
  var init_command6 = __esm(() => {
15755
- init_dist();
15756
- init_client_factory();
15757
- init_usecase6();
16790
+ init_bootstrap();
15758
16791
  init_output();
16792
+ init_dist();
16793
+ init_listen_claude();
16794
+ init_listen_codex();
15759
16795
  command_default6 = defineCommand({
15760
16796
  meta: {
15761
16797
  name: "listen",
@@ -15786,24 +16822,24 @@ var init_command6 = __esm(() => {
15786
16822
  type: "string",
15787
16823
  alias: "i",
15788
16824
  description: "Inbox name for routing (requires --team)"
15789
- },
15790
- "stdin-pane": {
15791
- type: "string",
15792
- alias: "s",
15793
- description: "tmux pane ID to inject non-@mention messages into via send-keys"
15794
16825
  }
15795
16826
  },
15796
16827
  run({ args }) {
15797
16828
  try {
15798
16829
  const client = getClient();
15799
- listen(client, {
16830
+ const container2 = getContainer();
16831
+ const input = {
15800
16832
  roomId: args.roomId,
15801
16833
  exclude: args.exclude,
15802
16834
  senderType: args["sender-type"],
15803
16835
  team: args.team,
15804
- inbox: args.inbox,
15805
- stdinPane: args["stdin-pane"]
15806
- });
16836
+ inbox: args.inbox
16837
+ };
16838
+ if (getMeetAiRuntime() === "codex") {
16839
+ listenCodex(client, input);
16840
+ return;
16841
+ }
16842
+ listenClaude(client, input, container2.inboxRouter);
15807
16843
  } catch (error48) {
15808
16844
  err(error48 instanceof Error ? error48.message : String(error48));
15809
16845
  process.exit(1);
@@ -15835,7 +16871,7 @@ async function sendTeamInfo(client, input) {
15835
16871
  await client.sendTeamInfo(parsed.roomId, parsed.payload);
15836
16872
  ok("Team info sent");
15837
16873
  }
15838
- var init_usecase7 = __esm(() => {
16874
+ var init_usecase6 = __esm(() => {
15839
16875
  init_schema7();
15840
16876
  init_output();
15841
16877
  });
@@ -15848,8 +16884,8 @@ __export(exports_command7, {
15848
16884
  var command_default7;
15849
16885
  var init_command7 = __esm(() => {
15850
16886
  init_dist();
15851
- init_client_factory();
15852
- init_usecase7();
16887
+ init_bootstrap();
16888
+ init_usecase6();
15853
16889
  init_output();
15854
16890
  command_default7 = defineCommand({
15855
16891
  meta: {
@@ -15903,7 +16939,7 @@ async function sendTasks(client, input) {
15903
16939
  await client.sendTasks(parsed.roomId, parsed.payload);
15904
16940
  ok("Tasks info sent");
15905
16941
  }
15906
- var init_usecase8 = __esm(() => {
16942
+ var init_usecase7 = __esm(() => {
15907
16943
  init_schema8();
15908
16944
  init_output();
15909
16945
  });
@@ -15916,8 +16952,8 @@ __export(exports_command8, {
15916
16952
  var command_default8;
15917
16953
  var init_command8 = __esm(() => {
15918
16954
  init_dist();
15919
- init_client_factory();
15920
- init_usecase8();
16955
+ init_bootstrap();
16956
+ init_usecase7();
15921
16957
  init_output();
15922
16958
  command_default8 = defineCommand({
15923
16959
  meta: {
@@ -15964,7 +17000,7 @@ async function downloadAttachment(client, input) {
15964
17000
  ok(localPath);
15965
17001
  return localPath;
15966
17002
  }
15967
- var init_usecase9 = __esm(() => {
17003
+ var init_usecase8 = __esm(() => {
15968
17004
  init_schema9();
15969
17005
  init_output();
15970
17006
  });
@@ -15977,8 +17013,8 @@ __export(exports_command9, {
15977
17013
  var command_default9;
15978
17014
  var init_command9 = __esm(() => {
15979
17015
  init_dist();
15980
- init_client_factory();
15981
- init_usecase9();
17016
+ init_bootstrap();
17017
+ init_usecase8();
15982
17018
  init_output();
15983
17019
  command_default9 = defineCommand({
15984
17020
  meta: {
@@ -16020,7 +17056,7 @@ __export(exports_command10, {
16020
17056
  var command_default10;
16021
17057
  var init_command10 = __esm(() => {
16022
17058
  init_dist();
16023
- init_client_factory();
17059
+ init_bootstrap();
16024
17060
  init_output();
16025
17061
  command_default10 = defineCommand({
16026
17062
  meta: {
@@ -16041,12 +17077,12 @@ var init_command10 = __esm(() => {
16041
17077
  });
16042
17078
 
16043
17079
  // src/lib/hooks/find-room.ts
16044
- import { readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2, createReadStream } from "node:fs";
16045
- import { join as join2 } from "node:path";
16046
- import { createInterface } from "node:readline";
17080
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3, createReadStream } from "node:fs";
17081
+ import { join as join3 } from "node:path";
17082
+ import { createInterface as createInterface2 } from "node:readline";
16047
17083
  async function extractTeamName(transcriptPath) {
16048
17084
  try {
16049
- const rl = createInterface({
17085
+ const rl = createInterface2({
16050
17086
  input: createReadStream(transcriptPath, "utf-8"),
16051
17087
  crlfDelay: Infinity
16052
17088
  });
@@ -16074,7 +17110,7 @@ function registerSession(filePath, data, sessionId) {
16074
17110
  }
16075
17111
  data.session_ids = ids;
16076
17112
  try {
16077
- writeFileSync2(filePath, JSON.stringify(data));
17113
+ writeFileSync3(filePath, JSON.stringify(data));
16078
17114
  } catch {}
16079
17115
  }
16080
17116
  async function findRoom(sessionId, teamsDir, transcriptPath) {
@@ -16082,9 +17118,9 @@ async function findRoom(sessionId, teamsDir, transcriptPath) {
16082
17118
  if (transcriptPath) {
16083
17119
  const teamName = await extractTeamName(transcriptPath);
16084
17120
  if (teamName) {
16085
- const filePath = join2(dir, teamName, "meet-ai.json");
17121
+ const filePath = join3(dir, teamName, "meet-ai.json");
16086
17122
  try {
16087
- const raw = readFileSync3(filePath, "utf-8");
17123
+ const raw = readFileSync4(filePath, "utf-8");
16088
17124
  const data = JSON.parse(raw);
16089
17125
  registerSession(filePath, data, sessionId);
16090
17126
  if (data.room_id)
@@ -16094,14 +17130,14 @@ async function findRoom(sessionId, teamsDir, transcriptPath) {
16094
17130
  }
16095
17131
  let entries;
16096
17132
  try {
16097
- entries = readdirSync(dir);
17133
+ entries = readdirSync2(dir);
16098
17134
  } catch {
16099
17135
  return null;
16100
17136
  }
16101
17137
  for (const entry of entries) {
16102
- const filePath = join2(dir, entry, "meet-ai.json");
17138
+ const filePath = join3(dir, entry, "meet-ai.json");
16103
17139
  try {
16104
- const raw = readFileSync3(filePath, "utf-8");
17140
+ const raw = readFileSync4(filePath, "utf-8");
16105
17141
  const data = JSON.parse(raw);
16106
17142
  const knownIds = data.session_ids ?? [data.session_id];
16107
17143
  if (knownIds.includes(sessionId) || data.session_id === sessionId) {
@@ -16264,17 +17300,17 @@ var init_cookie = __esm(() => {
16264
17300
  var init_fetch_result_please = () => {};
16265
17301
 
16266
17302
  // ../../node_modules/.bun/hono@4.11.8/node_modules/hono/dist/client/utils.js
16267
- function isObject2(item) {
17303
+ function isObject3(item) {
16268
17304
  return typeof item === "object" && item !== null && !Array.isArray(item);
16269
17305
  }
16270
17306
  function deepMerge(target, source) {
16271
- if (!isObject2(target) && !isObject2(source)) {
17307
+ if (!isObject3(target) && !isObject3(source)) {
16272
17308
  return source;
16273
17309
  }
16274
17310
  const merged = { ...target };
16275
17311
  for (const key in source) {
16276
17312
  const value = source[key];
16277
- if (isObject2(merged[key]) && isObject2(value)) {
17313
+ if (isObject3(merged[key]) && isObject3(value)) {
16278
17314
  merged[key] = deepMerge(merged[key], value);
16279
17315
  } else {
16280
17316
  merged[key] = value;
@@ -16481,14 +17517,14 @@ var createProxy = (callback, path) => {
16481
17517
  }
16482
17518
  return req;
16483
17519
  }, []);
16484
- var init_client2 = __esm(() => {
17520
+ var init_client = __esm(() => {
16485
17521
  init_cookie();
16486
17522
  init_utils();
16487
17523
  });
16488
17524
 
16489
17525
  // ../../node_modules/.bun/hono@4.11.8/node_modules/hono/dist/client/index.js
16490
- var init_client3 = __esm(() => {
16491
- init_client2();
17526
+ var init_client2 = __esm(() => {
17527
+ init_client();
16492
17528
  init_utils();
16493
17529
  });
16494
17530
 
@@ -16542,35 +17578,35 @@ async function sendLogEntry(client, roomId, summary, messageId) {
16542
17578
  } catch {}
16543
17579
  }
16544
17580
  var HOOK_COLOR = "#6b7280", HOOK_SENDER = "hook";
16545
- var init_client4 = __esm(() => {
16546
- init_client3();
17581
+ var init_client3 = __esm(() => {
17582
+ init_client2();
16547
17583
  });
16548
17584
 
16549
17585
  // src/lib/hooks/index.ts
16550
17586
  var init_hooks = __esm(() => {
16551
17587
  init_find_room();
16552
17588
  init_summarize();
16553
- init_client4();
17589
+ init_client3();
16554
17590
  });
16555
17591
 
16556
17592
  // src/commands/hook/log-tool-use/usecase.ts
16557
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, statSync as statSync2, rmSync } from "node:fs";
17593
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, statSync as statSync3, rmSync } from "node:fs";
16558
17594
  function getOrCreateParentId(sessionId) {
16559
17595
  const path = `/tmp/meet-ai-hook-${sessionId}.msgid`;
16560
17596
  try {
16561
- const mtime = statSync2(path).mtimeMs;
17597
+ const mtime = statSync3(path).mtimeMs;
16562
17598
  if (Date.now() - mtime > PARENT_MSG_TTL_SEC * 1000) {
16563
17599
  rmSync(path, { force: true });
16564
17600
  return null;
16565
17601
  }
16566
- return readFileSync4(path, "utf-8").trim() || null;
17602
+ return readFileSync5(path, "utf-8").trim() || null;
16567
17603
  } catch {
16568
17604
  return null;
16569
17605
  }
16570
17606
  }
16571
17607
  function saveParentId(sessionId, msgId) {
16572
17608
  try {
16573
- writeFileSync3(`/tmp/meet-ai-hook-${sessionId}.msgid`, msgId);
17609
+ writeFileSync4(`/tmp/meet-ai-hook-${sessionId}.msgid`, msgId);
16574
17610
  } catch {}
16575
17611
  }
16576
17612
  async function processHookInput(rawInput, teamsDir) {
@@ -16674,7 +17710,7 @@ async function processHookInput(rawInput, teamsDir) {
16674
17710
  return "sent";
16675
17711
  }
16676
17712
  var PARENT_MSG_TTL_SEC = 120;
16677
- var init_usecase10 = __esm(() => {
17713
+ var init_usecase9 = __esm(() => {
16678
17714
  init_hooks();
16679
17715
  });
16680
17716
 
@@ -16686,7 +17722,7 @@ __export(exports_command11, {
16686
17722
  var command_default11;
16687
17723
  var init_command11 = __esm(() => {
16688
17724
  init_dist();
16689
- init_usecase10();
17725
+ init_usecase9();
16690
17726
  command_default11 = defineCommand({
16691
17727
  meta: {
16692
17728
  name: "log-tool-use",
@@ -16851,8 +17887,8 @@ async function processPlanReview(rawInput, teamsDir) {
16851
17887
  }
16852
17888
  }
16853
17889
  var POLL_INTERVAL_MS = 2000, POLL_TIMEOUT_MS = 2592000000;
16854
- var init_usecase11 = __esm(() => {
16855
- init_client4();
17890
+ var init_usecase10 = __esm(() => {
17891
+ init_client3();
16856
17892
  init_find_room();
16857
17893
  });
16858
17894
 
@@ -16875,7 +17911,7 @@ var init_command12 = __esm(() => {
16875
17911
  for await (const chunk of process.stdin) {
16876
17912
  input += chunk;
16877
17913
  }
16878
- const { processPlanReview: processPlanReview2 } = await Promise.resolve().then(() => (init_usecase11(), exports_usecase));
17914
+ const { processPlanReview: processPlanReview2 } = await Promise.resolve().then(() => (init_usecase10(), exports_usecase));
16879
17915
  await processPlanReview2(input);
16880
17916
  } catch (error48) {
16881
17917
  process.stderr.write(`[plan-review] fatal: ${error48}
@@ -16947,7 +17983,7 @@ async function pollForAnswer(client, roomId, reviewId, pollInterval = POLL_INTER
16947
17983
  process.stderr.write(`[question-review] poll error: ${error48}
16948
17984
  `);
16949
17985
  }
16950
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
17986
+ await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
16951
17987
  }
16952
17988
  return null;
16953
17989
  }
@@ -17047,8 +18083,8 @@ async function processQuestionReview(rawInput, teamsDir, opts) {
17047
18083
  }
17048
18084
  }
17049
18085
  var POLL_INTERVAL_MS2 = 2000, POLL_TIMEOUT_MS2 = 1800000;
17050
- var init_usecase12 = __esm(() => {
17051
- init_client4();
18086
+ var init_usecase11 = __esm(() => {
18087
+ init_client3();
17052
18088
  init_find_room();
17053
18089
  });
17054
18090
 
@@ -17060,7 +18096,7 @@ __export(exports_command13, {
17060
18096
  var command_default13;
17061
18097
  var init_command13 = __esm(() => {
17062
18098
  init_dist();
17063
- init_usecase12();
18099
+ init_usecase11();
17064
18100
  command_default13 = defineCommand({
17065
18101
  meta: {
17066
18102
  name: "question-review",
@@ -17139,7 +18175,7 @@ async function pollForDecision2(client, roomId, reviewId, pollInterval = POLL_IN
17139
18175
  process.stderr.write(`[permission-review] poll error: ${error48}
17140
18176
  `);
17141
18177
  }
17142
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
18178
+ await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
17143
18179
  }
17144
18180
  return null;
17145
18181
  }
@@ -17245,8 +18281,8 @@ async function processPermissionReview(rawInput, teamsDir, opts) {
17245
18281
  }
17246
18282
  }
17247
18283
  var POLL_INTERVAL_MS3 = 2000, POLL_TIMEOUT_MS3 = 1800000;
17248
- var init_usecase13 = __esm(() => {
17249
- init_client4();
18284
+ var init_usecase12 = __esm(() => {
18285
+ init_client3();
17250
18286
  init_find_room();
17251
18287
  });
17252
18288
 
@@ -17258,7 +18294,7 @@ __export(exports_command14, {
17258
18294
  var command_default14;
17259
18295
  var init_command14 = __esm(() => {
17260
18296
  init_dist();
17261
- init_usecase13();
18297
+ init_usecase12();
17262
18298
  command_default14 = defineCommand({
17263
18299
  meta: {
17264
18300
  name: "permission-review",
@@ -17303,21 +18339,21 @@ var init_command15 = __esm(() => {
17303
18339
  });
17304
18340
 
17305
18341
  // src/commands/setup-hooks/usecase.ts
17306
- import { existsSync as existsSync2 } from "node:fs";
18342
+ import { existsSync as existsSync4 } from "node:fs";
17307
18343
  import { readFile, writeFile, mkdir } from "node:fs/promises";
17308
- import { homedir as homedir2 } from "node:os";
17309
- import { resolve as resolve2, dirname as dirname2 } from "node:path";
18344
+ import { homedir as homedir3 } from "node:os";
18345
+ import { resolve as resolve3, dirname as dirname3 } from "node:path";
17310
18346
  function isMeetAiHook(entry) {
17311
18347
  return entry.hooks?.some((h) => typeof h.command === "string" && h.command.startsWith("meet-ai hook ")) ?? false;
17312
18348
  }
17313
18349
  function getSettingsPath(project) {
17314
18350
  if (project) {
17315
- return resolve2(process.cwd(), ".claude", "settings.json");
18351
+ return resolve3(process.cwd(), ".claude", "settings.json");
17316
18352
  }
17317
- return resolve2(homedir2(), ".claude", "settings.json");
18353
+ return resolve3(homedir3(), ".claude", "settings.json");
17318
18354
  }
17319
18355
  async function readSettings(path) {
17320
- if (!existsSync2(path)) {
18356
+ if (!existsSync4(path)) {
17321
18357
  return {};
17322
18358
  }
17323
18359
  const raw = await readFile(path, "utf-8");
@@ -17399,7 +18435,7 @@ async function setupHooks(options) {
17399
18435
  if (Object.keys(cleaned).length === 0) {
17400
18436
  delete updated.hooks;
17401
18437
  }
17402
- await mkdir(dirname2(settingsPath), { recursive: true });
18438
+ await mkdir(dirname3(settingsPath), { recursive: true });
17403
18439
  await writeFile(settingsPath, `${JSON.stringify(updated, null, 2)}
17404
18440
  `);
17405
18441
  for (const r of removed) {
@@ -17416,7 +18452,7 @@ async function setupHooks(options) {
17416
18452
  return;
17417
18453
  }
17418
18454
  const updated = { ...settings, hooks: merged };
17419
- await mkdir(dirname2(settingsPath), { recursive: true });
18455
+ await mkdir(dirname3(settingsPath), { recursive: true });
17420
18456
  await writeFile(settingsPath, `${JSON.stringify(updated, null, 2)}
17421
18457
  `);
17422
18458
  for (const a of added) {
@@ -17426,7 +18462,7 @@ async function setupHooks(options) {
17426
18462
  }
17427
18463
  }
17428
18464
  var import_picocolors2, MEET_AI_HOOKS;
17429
- var init_usecase14 = __esm(() => {
18465
+ var init_usecase13 = __esm(() => {
17430
18466
  init_output();
17431
18467
  import_picocolors2 = __toESM(require_picocolors(), 1);
17432
18468
  MEET_AI_HOOKS = {
@@ -17485,7 +18521,7 @@ __export(exports_command16, {
17485
18521
  var command_default16;
17486
18522
  var init_command16 = __esm(() => {
17487
18523
  init_dist();
17488
- init_usecase14();
18524
+ init_usecase13();
17489
18525
  init_output();
17490
18526
  command_default16 = defineCommand({
17491
18527
  meta: {
@@ -17525,10 +18561,10 @@ var init_command16 = __esm(() => {
17525
18561
  });
17526
18562
 
17527
18563
  // src/commands/list-commands/usecase.ts
17528
- import { existsSync as existsSync3 } from "node:fs";
18564
+ import { existsSync as existsSync5 } from "node:fs";
17529
18565
  import { readFile as readFile2, readdir } from "node:fs/promises";
17530
- import { homedir as homedir3 } from "node:os";
17531
- import { join as join3, resolve as resolve3 } from "node:path";
18566
+ import { homedir as homedir4 } from "node:os";
18567
+ import { join as join4, resolve as resolve4 } from "node:path";
17532
18568
  function parseYamlFrontmatter(content) {
17533
18569
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
17534
18570
  if (!match)
@@ -17544,8 +18580,8 @@ function parseYamlFrontmatter(content) {
17544
18580
  };
17545
18581
  }
17546
18582
  async function readSkillsFromDir(baseDir, source, scope) {
17547
- const skillsDir = join3(baseDir, "skills");
17548
- if (!existsSync3(skillsDir))
18583
+ const skillsDir = join4(baseDir, "skills");
18584
+ if (!existsSync5(skillsDir))
17549
18585
  return [];
17550
18586
  let entries;
17551
18587
  try {
@@ -17555,8 +18591,8 @@ async function readSkillsFromDir(baseDir, source, scope) {
17555
18591
  }
17556
18592
  const results = [];
17557
18593
  for (const entry of entries) {
17558
- const skillFile = join3(skillsDir, entry, "SKILL.md");
17559
- if (!existsSync3(skillFile))
18594
+ const skillFile = join4(skillsDir, entry, "SKILL.md");
18595
+ if (!existsSync5(skillFile))
17560
18596
  continue;
17561
18597
  try {
17562
18598
  const content = await readFile2(skillFile, "utf-8");
@@ -17579,7 +18615,7 @@ async function readSkillsFromDir(baseDir, source, scope) {
17579
18615
  return results;
17580
18616
  }
17581
18617
  async function readCommandsFromDir(commandsDir, source, scope) {
17582
- if (!existsSync3(commandsDir))
18618
+ if (!existsSync5(commandsDir))
17583
18619
  return [];
17584
18620
  const results = [];
17585
18621
  async function scanDir(dir) {
@@ -17590,7 +18626,7 @@ async function readCommandsFromDir(commandsDir, source, scope) {
17590
18626
  return;
17591
18627
  }
17592
18628
  for (const entry of entries) {
17593
- const fullPath = join3(dir, entry.name);
18629
+ const fullPath = join4(dir, entry.name);
17594
18630
  if (entry.isDirectory()) {
17595
18631
  await scanDir(fullPath);
17596
18632
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -17617,7 +18653,7 @@ async function readCommandsFromDir(commandsDir, source, scope) {
17617
18653
  return results;
17618
18654
  }
17619
18655
  async function readSettings2(settingsPath) {
17620
- if (!existsSync3(settingsPath))
18656
+ if (!existsSync5(settingsPath))
17621
18657
  return {};
17622
18658
  try {
17623
18659
  const raw = await readFile2(settingsPath, "utf-8");
@@ -17627,7 +18663,7 @@ async function readSettings2(settingsPath) {
17627
18663
  }
17628
18664
  }
17629
18665
  async function readInstalledPlugins(pluginsFile) {
17630
- if (!existsSync3(pluginsFile))
18666
+ if (!existsSync5(pluginsFile))
17631
18667
  return {};
17632
18668
  try {
17633
18669
  const raw = await readFile2(pluginsFile, "utf-8");
@@ -17638,17 +18674,17 @@ async function readInstalledPlugins(pluginsFile) {
17638
18674
  }
17639
18675
  }
17640
18676
  async function listCommands(options) {
17641
- const projectPath = resolve3(options.projectPath ?? process.cwd());
17642
- const userClaudeDir = options._userClaudeDir ?? join3(homedir3(), ".claude");
17643
- const pluginsFile = options._pluginsFile ?? join3(homedir3(), ".claude", "plugins", "installed_plugins.json");
18677
+ const projectPath = resolve4(options.projectPath ?? process.cwd());
18678
+ const userClaudeDir = options._userClaudeDir ?? join4(homedir4(), ".claude");
18679
+ const pluginsFile = options._pluginsFile ?? join4(homedir4(), ".claude", "plugins", "installed_plugins.json");
17644
18680
  const results = [];
17645
18681
  const userSkills = await readSkillsFromDir(userClaudeDir, "standalone", "user");
17646
18682
  results.push(...userSkills);
17647
- const projectClaudeDir = join3(projectPath, ".claude");
18683
+ const projectClaudeDir = join4(projectPath, ".claude");
17648
18684
  const projectSkills = await readSkillsFromDir(projectClaudeDir, "standalone", "project");
17649
18685
  results.push(...projectSkills);
17650
- const userSettings = await readSettings2(join3(userClaudeDir, "settings.json"));
17651
- const projectSettings = await readSettings2(join3(projectClaudeDir, "settings.json"));
18686
+ const userSettings = await readSettings2(join4(userClaudeDir, "settings.json"));
18687
+ const projectSettings = await readSettings2(join4(projectClaudeDir, "settings.json"));
17652
18688
  const userEnabled = userSettings.enabledPlugins ?? {};
17653
18689
  const projectEnabled = projectSettings.enabledPlugins ?? {};
17654
18690
  const enabledPlugins = new Map;
@@ -17666,7 +18702,7 @@ async function listCommands(options) {
17666
18702
  continue;
17667
18703
  const { installPath } = installations[0];
17668
18704
  const source = `plugin:${scopeName}`;
17669
- const pluginCommands = await readCommandsFromDir(join3(installPath, "commands"), source, pluginScope);
18705
+ const pluginCommands = await readCommandsFromDir(join4(installPath, "commands"), source, pluginScope);
17670
18706
  results.push(...pluginCommands);
17671
18707
  const pluginSkills = await readSkillsFromDir(installPath, source, pluginScope);
17672
18708
  results.push(...pluginSkills);
@@ -17674,7 +18710,7 @@ async function listCommands(options) {
17674
18710
  }
17675
18711
  return results;
17676
18712
  }
17677
- var init_usecase15 = () => {};
18713
+ var init_usecase14 = () => {};
17678
18714
 
17679
18715
  // src/commands/list-commands/command.ts
17680
18716
  var exports_command17 = {};
@@ -17684,7 +18720,7 @@ __export(exports_command17, {
17684
18720
  var command_default17;
17685
18721
  var init_command17 = __esm(() => {
17686
18722
  init_dist();
17687
- init_usecase15();
18723
+ init_usecase14();
17688
18724
  init_output();
17689
18725
  command_default17 = defineCommand({
17690
18726
  meta: {
@@ -17718,8 +18754,8 @@ async function sendCommands(client, input) {
17718
18754
  await client.sendCommands(input.roomId, payload);
17719
18755
  ok("Commands sent");
17720
18756
  }
17721
- var init_usecase16 = __esm(() => {
17722
- init_usecase15();
18757
+ var init_usecase15 = __esm(() => {
18758
+ init_usecase14();
17723
18759
  init_output();
17724
18760
  });
17725
18761
 
@@ -17731,8 +18767,8 @@ __export(exports_command18, {
17731
18767
  var command_default18;
17732
18768
  var init_command18 = __esm(() => {
17733
18769
  init_dist();
17734
- init_client_factory();
17735
- init_usecase16();
18770
+ init_bootstrap();
18771
+ init_usecase15();
17736
18772
  init_output();
17737
18773
  command_default18 = defineCommand({
17738
18774
  meta: {
@@ -18123,14 +19159,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
18123
19159
  prevActScopeDepth !== actScopeDepth - 1 && console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ");
18124
19160
  actScopeDepth = prevActScopeDepth;
18125
19161
  }
18126
- function recursivelyFlushAsyncActWork(returnValue, resolve4, reject) {
19162
+ function recursivelyFlushAsyncActWork(returnValue, resolve5, reject) {
18127
19163
  var queue = ReactSharedInternals.actQueue;
18128
19164
  if (queue !== null)
18129
19165
  if (queue.length !== 0)
18130
19166
  try {
18131
19167
  flushActQueue(queue);
18132
19168
  enqueueTask(function() {
18133
- return recursivelyFlushAsyncActWork(returnValue, resolve4, reject);
19169
+ return recursivelyFlushAsyncActWork(returnValue, resolve5, reject);
18134
19170
  });
18135
19171
  return;
18136
19172
  } catch (error48) {
@@ -18138,7 +19174,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
18138
19174
  }
18139
19175
  else
18140
19176
  ReactSharedInternals.actQueue = null;
18141
- 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve4(returnValue);
19177
+ 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve5(returnValue);
18142
19178
  }
18143
19179
  function flushActQueue(queue) {
18144
19180
  if (!isFlushing) {
@@ -18314,14 +19350,14 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
18314
19350
  didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = true, console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"));
18315
19351
  });
18316
19352
  return {
18317
- then: function(resolve4, reject) {
19353
+ then: function(resolve5, reject) {
18318
19354
  didAwaitActCall = true;
18319
19355
  thenable.then(function(returnValue) {
18320
19356
  popActScope(prevActQueue, prevActScopeDepth);
18321
19357
  if (prevActScopeDepth === 0) {
18322
19358
  try {
18323
19359
  flushActQueue(queue), enqueueTask(function() {
18324
- return recursivelyFlushAsyncActWork(returnValue, resolve4, reject);
19360
+ return recursivelyFlushAsyncActWork(returnValue, resolve5, reject);
18325
19361
  });
18326
19362
  } catch (error$0) {
18327
19363
  ReactSharedInternals.thrownErrors.push(error$0);
@@ -18332,7 +19368,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
18332
19368
  reject(_thrownError);
18333
19369
  }
18334
19370
  } else
18335
- resolve4(returnValue);
19371
+ resolve5(returnValue);
18336
19372
  }, function(error48) {
18337
19373
  popActScope(prevActQueue, prevActScopeDepth);
18338
19374
  0 < ReactSharedInternals.thrownErrors.length ? (error48 = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error48)) : reject(error48);
@@ -18348,11 +19384,11 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
18348
19384
  if (0 < ReactSharedInternals.thrownErrors.length)
18349
19385
  throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
18350
19386
  return {
18351
- then: function(resolve4, reject) {
19387
+ then: function(resolve5, reject) {
18352
19388
  didAwaitActCall = true;
18353
19389
  prevActScopeDepth === 0 ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
18354
- return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve4, reject);
18355
- })) : resolve4(returnValue$jscomp$0);
19390
+ return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve5, reject);
19391
+ })) : resolve5(returnValue$jscomp$0);
18356
19392
  }
18357
19393
  };
18358
19394
  };
@@ -19135,14 +20171,14 @@ var require_signal_exit = __commonJS((exports, module) => {
19135
20171
  import { PassThrough } from "node:stream";
19136
20172
  var consoleMethods, originalMethods, patchConsole = (callback) => {
19137
20173
  const stdout = new PassThrough;
19138
- const stderr = new PassThrough;
20174
+ const stderr2 = new PassThrough;
19139
20175
  stdout.write = (data) => {
19140
20176
  callback("stdout", data);
19141
20177
  };
19142
- stderr.write = (data) => {
20178
+ stderr2.write = (data) => {
19143
20179
  callback("stderr", data);
19144
20180
  };
19145
- const internalConsole = new console.Console(stdout, stderr);
20181
+ const internalConsole = new console.Console(stdout, stderr2);
19146
20182
  for (const method of consoleMethods) {
19147
20183
  originalMethods[method] = console[method];
19148
20184
  console[method] = internalConsole[method];
@@ -21339,12 +22375,12 @@ import { execFileSync as execFileSync2 } from "node:child_process";
21339
22375
  import fs from "node:fs";
21340
22376
  import tty from "node:tty";
21341
22377
  function terminalSize() {
21342
- const { env: env2, stdout, stderr } = process4;
22378
+ const { env: env2, stdout, stderr: stderr2 } = process4;
21343
22379
  if (stdout?.columns && stdout?.rows) {
21344
22380
  return create(stdout.columns, stdout.rows);
21345
22381
  }
21346
- if (stderr?.columns && stderr?.rows) {
21347
- return create(stderr.columns, stderr.rows);
22382
+ if (stderr2?.columns && stderr2?.rows) {
22383
+ return create(stderr2.columns, stderr2.rows);
21348
22384
  }
21349
22385
  if (env2.COLUMNS && env2.LINES) {
21350
22386
  return create(env2.COLUMNS, env2.LINES);
@@ -23849,8 +24885,8 @@ It can also happen if the client has a browser extension installed which messes
23849
24885
  currentEntangledActionThenable = {
23850
24886
  status: "pending",
23851
24887
  value: undefined,
23852
- then: function(resolve4) {
23853
- entangledListeners.push(resolve4);
24888
+ then: function(resolve5) {
24889
+ entangledListeners.push(resolve5);
23854
24890
  }
23855
24891
  };
23856
24892
  }
@@ -23874,8 +24910,8 @@ It can also happen if the client has a browser extension installed which messes
23874
24910
  status: "pending",
23875
24911
  value: null,
23876
24912
  reason: null,
23877
- then: function(resolve4) {
23878
- listeners.push(resolve4);
24913
+ then: function(resolve5) {
24914
+ listeners.push(resolve5);
23879
24915
  }
23880
24916
  };
23881
24917
  thenable.then(function() {
@@ -27010,11 +28046,11 @@ https://react.dev/link/unsafe-component-lifecycles`, _instance, newApiName, stat
27010
28046
  function updateHostContainer(current2, workInProgress2) {
27011
28047
  if (supportsPersistence && doesRequireClone(current2, workInProgress2)) {
27012
28048
  current2 = workInProgress2.stateNode;
27013
- var container = current2.containerInfo, newChildSet = createContainerChildSet();
28049
+ var container2 = current2.containerInfo, newChildSet = createContainerChildSet();
27014
28050
  appendAllChildrenToContainer(newChildSet, workInProgress2, false, false);
27015
28051
  current2.pendingChildren = newChildSet;
27016
28052
  markUpdate(workInProgress2);
27017
- finalizeContainerChildren(container, newChildSet);
28053
+ finalizeContainerChildren(container2, newChildSet);
27018
28054
  }
27019
28055
  }
27020
28056
  function updateHostComponent(current2, workInProgress2, type, newProps) {
@@ -30276,27 +31312,27 @@ Check the render method of \`` + fiberTag + "`.");
30276
31312
  parentComponent = emptyContextObject;
30277
31313
  return parentComponent;
30278
31314
  }
30279
- function updateContainerSync(element, container, parentComponent, callback) {
30280
- updateContainerImpl(container.current, 2, element, container, parentComponent, callback);
31315
+ function updateContainerSync(element, container2, parentComponent, callback) {
31316
+ updateContainerImpl(container2.current, 2, element, container2, parentComponent, callback);
30281
31317
  return 2;
30282
31318
  }
30283
- function updateContainerImpl(rootFiber, lane, element, container, parentComponent, callback) {
31319
+ function updateContainerImpl(rootFiber, lane, element, container2, parentComponent, callback) {
30284
31320
  if (injectedHook && typeof injectedHook.onScheduleFiberRoot === "function")
30285
31321
  try {
30286
- injectedHook.onScheduleFiberRoot(rendererID, container, element);
31322
+ injectedHook.onScheduleFiberRoot(rendererID, container2, element);
30287
31323
  } catch (err2) {
30288
31324
  hasLoggedError || (hasLoggedError = true, console.error("React instrumentation encountered an error: %o", err2));
30289
31325
  }
30290
31326
  parentComponent = getContextForSubtree(parentComponent);
30291
- container.context === null ? container.context = parentComponent : container.pendingContext = parentComponent;
31327
+ container2.context === null ? container2.context = parentComponent : container2.pendingContext = parentComponent;
30292
31328
  isRendering && current !== null && !didWarnAboutNestedUpdates && (didWarnAboutNestedUpdates = true, console.error(`Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate.
30293
31329
 
30294
31330
  Check the render method of %s.`, getComponentNameFromFiber(current) || "Unknown"));
30295
- container = createUpdate(lane);
30296
- container.payload = { element };
31331
+ container2 = createUpdate(lane);
31332
+ container2.payload = { element };
30297
31333
  callback = callback === undefined ? null : callback;
30298
- callback !== null && (typeof callback !== "function" && console.error("Expected the last optional `callback` argument to be a function. Instead received: %s.", callback), container.callback = callback);
30299
- element = enqueueUpdate(rootFiber, container, lane);
31334
+ callback !== null && (typeof callback !== "function" && console.error("Expected the last optional `callback` argument to be a function. Instead received: %s.", callback), container2.callback = callback);
31335
+ element = enqueueUpdate(rootFiber, container2, lane);
30300
31336
  element !== null && (startUpdateTimerByLane(lane, "root.render()", null), scheduleUpdateOnFiber(element, rootFiber, lane), entangleTransitions(element, rootFiber, lane));
30301
31337
  }
30302
31338
  function markRetryLaneImpl(fiber, retryLane) {
@@ -32056,16 +33092,16 @@ No matching component was found for:
32056
33092
  }
32057
33093
  return null;
32058
33094
  };
32059
- exports2.getPublicRootInstance = function(container) {
32060
- container = container.current;
32061
- if (!container.child)
33095
+ exports2.getPublicRootInstance = function(container2) {
33096
+ container2 = container2.current;
33097
+ if (!container2.child)
32062
33098
  return null;
32063
- switch (container.child.tag) {
33099
+ switch (container2.child.tag) {
32064
33100
  case 27:
32065
33101
  case 5:
32066
- return getPublicInstance(container.child.stateNode);
33102
+ return getPublicInstance(container2.child.stateNode);
32067
33103
  default:
32068
- return container.child.stateNode;
33104
+ return container2.child.stateNode;
32069
33105
  }
32070
33106
  };
32071
33107
  exports2.injectIntoDevTools = function() {
@@ -32137,9 +33173,9 @@ No matching component was found for:
32137
33173
  return action(formData);
32138
33174
  });
32139
33175
  };
32140
- exports2.updateContainer = function(element, container, parentComponent, callback) {
32141
- var current2 = container.current, lane = requestUpdateLane(current2);
32142
- updateContainerImpl(current2, lane, element, container, parentComponent, callback);
33176
+ exports2.updateContainer = function(element, container2, parentComponent, callback) {
33177
+ var current2 = container2.current, lane = requestUpdateLane(current2);
33178
+ updateContainerImpl(current2, lane, element, container2, parentComponent, callback);
32143
33179
  return lane;
32144
33180
  };
32145
33181
  exports2.updateContainerSync = updateContainerSync;
@@ -36562,7 +37598,7 @@ var require_websocket_server = __commonJS((exports, module) => {
36562
37598
  socket.on("error", socketOnError);
36563
37599
  const key = req.headers["sec-websocket-key"];
36564
37600
  const upgrade = req.headers.upgrade;
36565
- const version2 = +req.headers["sec-websocket-version"];
37601
+ const version3 = +req.headers["sec-websocket-version"];
36566
37602
  if (req.method !== "GET") {
36567
37603
  const message = "Invalid HTTP method";
36568
37604
  abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
@@ -36578,7 +37614,7 @@ var require_websocket_server = __commonJS((exports, module) => {
36578
37614
  abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
36579
37615
  return;
36580
37616
  }
36581
- if (version2 !== 13 && version2 !== 8) {
37617
+ if (version3 !== 13 && version3 !== 8) {
36582
37618
  const message = "Missing or invalid Sec-WebSocket-Version header";
36583
37619
  abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {
36584
37620
  "Sec-WebSocket-Version": "13, 8"
@@ -36618,7 +37654,7 @@ var require_websocket_server = __commonJS((exports, module) => {
36618
37654
  }
36619
37655
  if (this.options.verifyClient) {
36620
37656
  const info2 = {
36621
- origin: req.headers[`${version2 === 8 ? "sec-websocket-origin" : "origin"}`],
37657
+ origin: req.headers[`${version3 === 8 ? "sec-websocket-origin" : "origin"}`],
36622
37658
  secure: !!(req.socket.authorized || req.socket.encrypted),
36623
37659
  req
36624
37660
  };
@@ -39453,20 +40489,20 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
39453
40489
  }
39454
40490
  return 0;
39455
40491
  };
39456
- var validate2 = function validate3(version2) {
39457
- return typeof version2 === "string" && /^[v\d]/.test(version2) && semver.test(version2);
40492
+ var validate2 = function validate3(version3) {
40493
+ return typeof version3 === "string" && /^[v\d]/.test(version3) && semver.test(version3);
39458
40494
  };
39459
40495
  var compare = function compare2(v1, v2, operator) {
39460
40496
  assertValidOperator(operator);
39461
40497
  var res = compareVersions(v1, v2);
39462
40498
  return operatorResMap[operator].includes(res);
39463
40499
  };
39464
- var satisfies = function satisfies2(version2, range) {
40500
+ var satisfies = function satisfies2(version3, range) {
39465
40501
  var m = range.match(/^([<>=~^]+)/);
39466
40502
  var op = m ? m[1] : "=";
39467
40503
  if (op !== "^" && op !== "~")
39468
- return compare(version2, range, op);
39469
- var _validateAndParse = validateAndParse(version2), _validateAndParse2 = _slicedToArray(_validateAndParse, 5), v1 = _validateAndParse2[0], v2 = _validateAndParse2[1], v3 = _validateAndParse2[2], vp = _validateAndParse2[4];
40504
+ return compare(version3, range, op);
40505
+ var _validateAndParse = validateAndParse(version3), _validateAndParse2 = _slicedToArray(_validateAndParse, 5), v1 = _validateAndParse2[0], v2 = _validateAndParse2[1], v3 = _validateAndParse2[2], vp = _validateAndParse2[4];
39470
40506
  var _validateAndParse3 = validateAndParse(range), _validateAndParse4 = _slicedToArray(_validateAndParse3, 5), r1 = _validateAndParse4[0], r2 = _validateAndParse4[1], r3 = _validateAndParse4[2], rp = _validateAndParse4[4];
39471
40507
  var v = [v1, v2, v3];
39472
40508
  var r = [r1, r2 !== null && r2 !== undefined ? r2 : "x", r3 !== null && r3 !== undefined ? r3 : "x"];
@@ -39489,13 +40525,13 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
39489
40525
  return true;
39490
40526
  };
39491
40527
  var semver = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
39492
- var validateAndParse = function validateAndParse2(version2) {
39493
- if (typeof version2 !== "string") {
40528
+ var validateAndParse = function validateAndParse2(version3) {
40529
+ if (typeof version3 !== "string") {
39494
40530
  throw new TypeError("Invalid argument expected string");
39495
40531
  }
39496
- var match = version2.match(semver);
40532
+ var match = version3.match(semver);
39497
40533
  if (!match) {
39498
- throw new Error("Invalid argument not valid semver ('".concat(version2, "' received)"));
40534
+ throw new Error("Invalid argument not valid semver ('".concat(version3, "' received)"));
39499
40535
  }
39500
40536
  match.shift();
39501
40537
  return match;
@@ -41129,11 +42165,11 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
41129
42165
  return obj;
41130
42166
  }
41131
42167
  var FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER = "999.9.9";
41132
- function hasAssignedBackend(version2) {
41133
- if (version2 == null || version2 === "") {
42168
+ function hasAssignedBackend(version3) {
42169
+ if (version3 == null || version3 === "") {
41134
42170
  return false;
41135
42171
  }
41136
- return gte(version2, FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER);
42172
+ return gte(version3, FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER);
41137
42173
  }
41138
42174
  function cleanForBridge(data, isPathAllowed) {
41139
42175
  var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
@@ -41612,7 +42648,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
41612
42648
  }
41613
42649
  var Overlay_assign = Object.assign;
41614
42650
  var OverlayRect = /* @__PURE__ */ function() {
41615
- function OverlayRect2(doc2, container) {
42651
+ function OverlayRect2(doc2, container2) {
41616
42652
  Overlay_classCallCheck(this, OverlayRect2);
41617
42653
  this.node = doc2.createElement("div");
41618
42654
  this.border = doc2.createElement("div");
@@ -41630,7 +42666,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
41630
42666
  this.node.appendChild(this.border);
41631
42667
  this.border.appendChild(this.padding);
41632
42668
  this.padding.appendChild(this.content);
41633
- container.appendChild(this.node);
42669
+ container2.appendChild(this.node);
41634
42670
  }
41635
42671
  return Overlay_createClass(OverlayRect2, [{
41636
42672
  key: "remove",
@@ -41657,7 +42693,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
41657
42693
  }]);
41658
42694
  }();
41659
42695
  var OverlayTip = /* @__PURE__ */ function() {
41660
- function OverlayTip2(doc2, container) {
42696
+ function OverlayTip2(doc2, container2) {
41661
42697
  Overlay_classCallCheck(this, OverlayTip2);
41662
42698
  this.tip = doc2.createElement("div");
41663
42699
  Overlay_assign(this.tip.style, {
@@ -41687,7 +42723,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
41687
42723
  color: "#d7d7d7"
41688
42724
  });
41689
42725
  this.tip.style.zIndex = "10000000";
41690
- container.appendChild(this.tip);
42726
+ container2.appendChild(this.tip);
41691
42727
  }
41692
42728
  return Overlay_createClass(OverlayTip2, [{
41693
42729
  key: "remove",
@@ -42789,9 +43825,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
42789
43825
  }
42790
43826
  });
42791
43827
  agent_defineProperty(_this2, "getBackendVersion", function() {
42792
- var version2 = "6.1.5-5d87cd2244";
42793
- if (version2) {
42794
- _this2._bridge.send("backendVersion", version2);
43828
+ var version3 = "6.1.5-5d87cd2244";
43829
+ if (version3) {
43830
+ _this2._bridge.send("backendVersion", version3);
42795
43831
  }
42796
43832
  });
42797
43833
  agent_defineProperty(_this2, "getBridgeProtocol", function() {
@@ -45319,7 +46355,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45319
46355
  } : function() {
45320
46356
  return Date.now();
45321
46357
  };
45322
- function getInternalReactConstants(version2) {
46358
+ function getInternalReactConstants(version3) {
45323
46359
  var ReactPriorityLevels = {
45324
46360
  ImmediatePriority: 99,
45325
46361
  UserBlockingPriority: 98,
@@ -45328,7 +46364,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45328
46364
  IdlePriority: 95,
45329
46365
  NoPriority: 90
45330
46366
  };
45331
- if (gt(version2, "17.0.2")) {
46367
+ if (gt(version3, "17.0.2")) {
45332
46368
  ReactPriorityLevels = {
45333
46369
  ImmediatePriority: 1,
45334
46370
  UserBlockingPriority: 2,
@@ -45339,15 +46375,15 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45339
46375
  };
45340
46376
  }
45341
46377
  var StrictModeBits = 0;
45342
- if (gte(version2, "18.0.0-alpha")) {
46378
+ if (gte(version3, "18.0.0-alpha")) {
45343
46379
  StrictModeBits = 24;
45344
- } else if (gte(version2, "16.9.0")) {
46380
+ } else if (gte(version3, "16.9.0")) {
45345
46381
  StrictModeBits = 1;
45346
- } else if (gte(version2, "16.3.0")) {
46382
+ } else if (gte(version3, "16.3.0")) {
45347
46383
  StrictModeBits = 2;
45348
46384
  }
45349
46385
  var ReactTypeOfWork = null;
45350
- if (gt(version2, "17.0.1")) {
46386
+ if (gt(version3, "17.0.1")) {
45351
46387
  ReactTypeOfWork = {
45352
46388
  CacheComponent: 24,
45353
46389
  ClassComponent: 1,
@@ -45384,7 +46420,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45384
46420
  ViewTransitionComponent: 30,
45385
46421
  ActivityComponent: 31
45386
46422
  };
45387
- } else if (gte(version2, "17.0.0-alpha")) {
46423
+ } else if (gte(version3, "17.0.0-alpha")) {
45388
46424
  ReactTypeOfWork = {
45389
46425
  CacheComponent: -1,
45390
46426
  ClassComponent: 1,
@@ -45421,7 +46457,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45421
46457
  ViewTransitionComponent: -1,
45422
46458
  ActivityComponent: -1
45423
46459
  };
45424
- } else if (gte(version2, "16.6.0-beta.0")) {
46460
+ } else if (gte(version3, "16.6.0-beta.0")) {
45425
46461
  ReactTypeOfWork = {
45426
46462
  CacheComponent: -1,
45427
46463
  ClassComponent: 1,
@@ -45458,7 +46494,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45458
46494
  ViewTransitionComponent: -1,
45459
46495
  ActivityComponent: -1
45460
46496
  };
45461
- } else if (gte(version2, "16.4.3-alpha")) {
46497
+ } else if (gte(version3, "16.4.3-alpha")) {
45462
46498
  ReactTypeOfWork = {
45463
46499
  CacheComponent: -1,
45464
46500
  ClassComponent: 2,
@@ -45744,8 +46780,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45744
46780
  }
45745
46781
  }
45746
46782
  function renderer_attach(hook, rendererID, renderer, global2, shouldStartProfilingNow, profilingSettings) {
45747
- var version2 = renderer.reconcilerVersion || renderer.version;
45748
- var _getInternalReactCons = getInternalReactConstants(version2), getDisplayNameForFiber = _getInternalReactCons.getDisplayNameForFiber, getTypeSymbol = _getInternalReactCons.getTypeSymbol, ReactPriorityLevels = _getInternalReactCons.ReactPriorityLevels, ReactTypeOfWork = _getInternalReactCons.ReactTypeOfWork, StrictModeBits = _getInternalReactCons.StrictModeBits;
46783
+ var version3 = renderer.reconcilerVersion || renderer.version;
46784
+ var _getInternalReactCons = getInternalReactConstants(version3), getDisplayNameForFiber = _getInternalReactCons.getDisplayNameForFiber, getTypeSymbol = _getInternalReactCons.getTypeSymbol, ReactPriorityLevels = _getInternalReactCons.ReactPriorityLevels, ReactTypeOfWork = _getInternalReactCons.ReactTypeOfWork, StrictModeBits = _getInternalReactCons.StrictModeBits;
45749
46785
  var { ActivityComponent, CacheComponent, ClassComponent, ContextConsumer, DehydratedSuspenseComponent, ForwardRef, Fragment, FunctionComponent, HostRoot, HostHoistable, HostSingleton, HostPortal, HostComponent, HostText, IncompleteClassComponent, IncompleteFunctionComponent, IndeterminateComponent, LegacyHiddenComponent, MemoComponent, OffscreenComponent, SimpleMemoComponent, SuspenseComponent, SuspenseListComponent, TracingMarkerComponent, Throw, ViewTransitionComponent } = ReactTypeOfWork;
45750
46786
  var { ImmediatePriority, UserBlockingPriority, NormalPriority, LowPriority, IdlePriority, NoPriority } = ReactPriorityLevels;
45751
46787
  var { getLaneLabelMap, injectProfilingHooks, overrideHookState, overrideHookStateDeletePath, overrideHookStateRenamePath, overrideProps, overridePropsDeletePath, overridePropsRenamePath, scheduleRefresh, setErrorHandler, setSuspenseHandler, scheduleUpdate, getCurrentFiber } = renderer;
@@ -45771,7 +46807,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
45771
46807
  getLaneLabelMap,
45772
46808
  currentDispatcherRef: getDispatcherRef(renderer),
45773
46809
  workTagMap: ReactTypeOfWork,
45774
- reactVersion: version2
46810
+ reactVersion: version3
45775
46811
  });
45776
46812
  injectProfilingHooks(response.profilingHooks);
45777
46813
  getTimelineData = response.getTimelineData;
@@ -49650,8 +50686,8 @@ The error thrown in the component is:
49650
50686
  getEnvironmentNames
49651
50687
  };
49652
50688
  }
49653
- function isMatchingRender(version2) {
49654
- return !hasAssignedBackend(version2);
50689
+ function isMatchingRender(version3) {
50690
+ return !hasAssignedBackend(version3);
49655
50691
  }
49656
50692
  function attachRenderer(hook, id, renderer, global2, shouldStartProfilingNow, profilingSettings) {
49657
50693
  if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) {
@@ -50665,7 +51701,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
50665
51701
  ws.onmessage = handleMessage;
50666
51702
  ws.onopen = function() {
50667
51703
  bridge = new src_bridge({
50668
- listen: function listen2(fn) {
51704
+ listen: function listen(fn) {
50669
51705
  messageListeners.push(fn);
50670
51706
  return function() {
50671
51707
  var index = messageListeners.indexOf(fn);
@@ -50798,7 +51834,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
50798
51834
  return;
50799
51835
  }
50800
51836
  var wall = {
50801
- listen: function listen2(fn) {
51837
+ listen: function listen(fn) {
50802
51838
  onSubscribe(fn);
50803
51839
  return function() {
50804
51840
  onUnsubscribe(fn);
@@ -51504,10 +52540,10 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
51504
52540
  return 3;
51505
52541
  }
51506
52542
  if ("TERM_PROGRAM" in env2) {
51507
- const version2 = Number.parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
52543
+ const version3 = Number.parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
51508
52544
  switch (env2.TERM_PROGRAM) {
51509
52545
  case "iTerm.app": {
51510
- return version2 >= 3 ? 3 : 2;
52546
+ return version3 >= 3 ? 3 : 2;
51511
52547
  }
51512
52548
  case "Apple_Terminal": {
51513
52549
  return 2;
@@ -53554,7 +54590,7 @@ var init_ErrorBoundary = __esm(() => {
53554
54590
  // ../../node_modules/.bun/ink@6.8.0+b7580ee3b5d80903/node_modules/ink/build/components/App.js
53555
54591
  import { EventEmitter as EventEmitter2 } from "node:events";
53556
54592
  import process12 from "node:process";
53557
- function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, setCursorPosition }) {
54593
+ function App({ children, stdin, stdout, stderr: stderr2, writeToStdout, writeToStderr, exitOnCtrlC, onExit, setCursorPosition }) {
53558
54594
  const [isFocusEnabled, setIsFocusEnabled] = import_react14.useState(true);
53559
54595
  const [activeFocusId, setActiveFocusId] = import_react14.useState(undefined);
53560
54596
  const [, setFocusables] = import_react14.useState([]);
@@ -53826,9 +54862,9 @@ Read about how to prevent this error on https://github.com/vadimdemedes/ink/#isr
53826
54862
  write: writeToStdout
53827
54863
  }), [stdout, writeToStdout]);
53828
54864
  const stderrContextValue = import_react14.useMemo(() => ({
53829
- stderr,
54865
+ stderr: stderr2,
53830
54866
  write: writeToStderr
53831
- }), [stderr, writeToStderr]);
54867
+ }), [stderr2, writeToStderr]);
53832
54868
  const cursorContextValue = import_react14.useMemo(() => ({
53833
54869
  setCursorPosition
53834
54870
  }), [setCursorPosition]);
@@ -54282,8 +55318,8 @@ class Ink {
54282
55318
  }
54283
55319
  }
54284
55320
  async waitUntilExit() {
54285
- this.exitPromise ||= new Promise((resolve4, reject) => {
54286
- this.resolveExitPromise = resolve4;
55321
+ this.exitPromise ||= new Promise((resolve5, reject) => {
55322
+ this.resolveExitPromise = resolve5;
54287
55323
  this.rejectExitPromise = reject;
54288
55324
  });
54289
55325
  if (!this.beforeExitHandler) {
@@ -55119,13 +56155,88 @@ var init_build2 = __esm(async () => {
55119
56155
  ]);
55120
56156
  });
55121
56157
 
56158
+ // src/spawner.ts
56159
+ import { execSync } from "node:child_process";
56160
+ import { existsSync as existsSync7 } from "node:fs";
56161
+ import { homedir as homedir5, platform as platform2 } from "node:os";
56162
+ import { join as join5 } from "node:path";
56163
+ function findBinary(binaryName, envVarName, commonPaths) {
56164
+ try {
56165
+ const command = platform2() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
56166
+ const result = execSync(command, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim();
56167
+ const binaryPath = result.split(`
56168
+ `)[0].trim();
56169
+ if (binaryPath && existsSync7(binaryPath)) {
56170
+ return binaryPath;
56171
+ }
56172
+ } catch {}
56173
+ const envPath = process.env[envVarName];
56174
+ if (envPath && existsSync7(envPath)) {
56175
+ return envPath;
56176
+ }
56177
+ for (const path of commonPaths) {
56178
+ if (existsSync7(path)) {
56179
+ return path;
56180
+ }
56181
+ }
56182
+ throw new Error(`${binaryName} is not installed`);
56183
+ }
56184
+ function findClaudeCli() {
56185
+ const home = homedir5();
56186
+ try {
56187
+ return findBinary("claude", "MEET_AI_CLAUDE_PATH", [
56188
+ join5(home, ".bun", "bin", "claude"),
56189
+ "/opt/homebrew/bin/claude",
56190
+ "/usr/local/bin/claude",
56191
+ join5(home, ".local", "bin", "claude")
56192
+ ]);
56193
+ } catch {
56194
+ throw new Error(`
56195
+ Claude Code is not installed
56196
+
56197
+ Please install Claude Code:
56198
+ bun add -g @anthropic-ai/claude-code
56199
+
56200
+ Or set MEET_AI_CLAUDE_PATH to the Claude Code CLI path.
56201
+ `.trim());
56202
+ }
56203
+ }
56204
+ function findCodexCli() {
56205
+ const home = homedir5();
56206
+ try {
56207
+ return findBinary("codex", "MEET_AI_CODEX_PATH", [
56208
+ join5(home, ".bun", "bin", "codex"),
56209
+ "/opt/homebrew/bin/codex",
56210
+ "/usr/local/bin/codex",
56211
+ join5(home, ".local", "bin", "codex")
56212
+ ]);
56213
+ } catch {
56214
+ throw new Error(`
56215
+ Codex CLI is not installed
56216
+
56217
+ Please install Codex:
56218
+ npm install -g @openai/codex
56219
+
56220
+ Or set MEET_AI_CODEX_PATH to the Codex CLI path.
56221
+ `.trim());
56222
+ }
56223
+ }
56224
+ var init_spawner = () => {};
56225
+
55122
56226
  // src/lib/process-manager.ts
55123
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync, lstatSync } from "node:fs";
55124
- import { homedir as homedir4 } from "node:os";
55125
- import { join as join4 } from "node:path";
56227
+ import { existsSync as existsSync8, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync5 } from "node:fs";
56228
+ import { homedir as homedir6 } from "node:os";
56229
+ import { fileURLToPath } from "node:url";
56230
+ import { join as join6 } from "node:path";
56231
+ function getRegistryDir() {
56232
+ return join6(process.env.HOME ?? homedir6(), ".meet-ai");
56233
+ }
56234
+ function getRegistryPath() {
56235
+ return join6(getRegistryDir(), "sessions.json");
56236
+ }
55126
56237
  function readRegistry() {
55127
56238
  try {
55128
- const data = readFileSync6(REGISTRY_PATH, "utf8");
56239
+ const data = readFileSync7(getRegistryPath(), "utf8");
55129
56240
  const parsed = exports_external.array(SessionEntrySchema).safeParse(JSON.parse(data));
55130
56241
  return parsed.success ? parsed.data : [];
55131
56242
  } catch {
@@ -55133,17 +56244,18 @@ function readRegistry() {
55133
56244
  }
55134
56245
  }
55135
56246
  function writeRegistry(entries) {
55136
- mkdirSync2(REGISTRY_DIR, { recursive: true, mode: 448 });
56247
+ const registryDir = getRegistryDir();
56248
+ mkdirSync3(registryDir, { recursive: true, mode: 448 });
55137
56249
  try {
55138
- const stat = lstatSync(REGISTRY_DIR);
56250
+ const stat = lstatSync(registryDir);
55139
56251
  if (!stat.isDirectory())
55140
56252
  return;
55141
56253
  } catch {
55142
56254
  return;
55143
56255
  }
55144
- const tmpPath = join4(REGISTRY_DIR, `sessions.${process.pid}.${Date.now()}.tmp`);
55145
- writeFileSync4(tmpPath, JSON.stringify(entries, null, 2), { mode: 384 });
55146
- renameSync(tmpPath, REGISTRY_PATH);
56256
+ const tmpPath = join6(registryDir, `sessions.${process.pid}.${Date.now()}.tmp`);
56257
+ writeFileSync5(tmpPath, JSON.stringify(entries, null, 2), { mode: 384 });
56258
+ renameSync(tmpPath, getRegistryPath());
55147
56259
  }
55148
56260
  function addToRegistry(entry) {
55149
56261
  const entries = readRegistry();
@@ -55158,6 +56270,17 @@ function removeFromRegistry(sessionName) {
55158
56270
  const entries = readRegistry().filter((e) => e.sessionName !== sessionName);
55159
56271
  writeRegistry(entries);
55160
56272
  }
56273
+ function resolveSelfCliCommand() {
56274
+ const sourceEntry = fileURLToPath(new URL("../index.ts", import.meta.url));
56275
+ if (existsSync8(sourceEntry) && typeof Bun !== "undefined") {
56276
+ return [process.execPath, "run", sourceEntry];
56277
+ }
56278
+ const builtEntry = fileURLToPath(new URL("../index.js", import.meta.url));
56279
+ if (existsSync8(builtEntry)) {
56280
+ return [process.execPath, builtEntry];
56281
+ }
56282
+ return ["meet-ai"];
56283
+ }
55161
56284
 
55162
56285
  class ProcessManager {
55163
56286
  teams = new Map;
@@ -55171,11 +56294,12 @@ class ProcessManager {
55171
56294
  sessionName(roomId) {
55172
56295
  return `mai-${roomId}`;
55173
56296
  }
55174
- spawn(roomId, roomName) {
56297
+ spawn(roomId, roomName, codingAgent = "claude") {
55175
56298
  const sessionName = this.sessionName(roomId);
55176
56299
  const team = {
55177
56300
  roomId,
55178
56301
  roomName,
56302
+ codingAgent,
55179
56303
  sessionName,
55180
56304
  status: "starting",
55181
56305
  exitCode: null,
@@ -55186,22 +56310,24 @@ class ProcessManager {
55186
56310
  this.spawned++;
55187
56311
  if (this.opts.dryRun)
55188
56312
  return team;
55189
- const fullPrompt = [
55190
- `ROOM_ID: ${roomId}`,
55191
- "",
55192
- "You are a team lead. IMMEDIATELY:",
55193
- "1. Start agent-team to start accepting commands from Meet AI",
55194
- "2. Connect to the meet-ai room using the /meet-ai skill",
55195
- "3. Just send a welcome message to the room, do not perform any work yet."
55196
- ].join(`
56313
+ const fullPrompt = [`ROOM_ID: ${roomId}`, "", ...this.buildPromptLines(codingAgent)].join(`
55197
56314
  `);
55198
- const claudeArgs = [
55199
- "--dangerously-skip-permissions",
55200
- "--model",
55201
- this.opts.model ?? "opus",
55202
- fullPrompt
55203
- ];
55204
- const sessionEnv = { DISABLE_AUTOUPDATER: "1" };
56315
+ const agentBinary = this.opts.agentBinaries[codingAgent];
56316
+ if (!agentBinary) {
56317
+ team.status = "error";
56318
+ team.lines.push(`[error] No CLI binary configured for coding agent: ${codingAgent}`);
56319
+ this.opts.onStatusChange?.(roomId, "error");
56320
+ return team;
56321
+ }
56322
+ const commandArgs = codingAgent === "codex" ? this.buildCodexListenCommandArgs(roomId) : [agentBinary, ...this.buildClaudeCommandArgs(fullPrompt)];
56323
+ const sessionEnv = {
56324
+ DISABLE_AUTOUPDATER: "1",
56325
+ MEET_AI_RUNTIME: codingAgent
56326
+ };
56327
+ if (codingAgent === "codex") {
56328
+ sessionEnv.MEET_AI_CODEX_PATH = agentBinary;
56329
+ sessionEnv.MEET_AI_CODEX_BOOTSTRAP_PROMPT = fullPrompt;
56330
+ }
55205
56331
  for (const key of ENV_ALLOWLIST) {
55206
56332
  const value = process.env[key];
55207
56333
  if (value)
@@ -55210,15 +56336,21 @@ class ProcessManager {
55210
56336
  if (this.opts.env)
55211
56337
  Object.assign(sessionEnv, this.opts.env);
55212
56338
  if (this.opts.debug) {
55213
- team.lines.push(`[debug] CMD: ${this.opts.claudePath} ${claudeArgs.join(" ").slice(0, 200)}`);
56339
+ team.lines.push(`[debug] AGENT: ${codingAgent}`);
56340
+ team.lines.push(`[debug] CMD: ${commandArgs.join(" ").slice(0, 200)}`);
55214
56341
  team.lines.push(`[debug] ENV: ${Object.keys(sessionEnv).join(", ")}`);
55215
56342
  }
55216
- const commandArgs = [this.opts.claudePath, ...claudeArgs];
55217
56343
  const result = this.tmux.newSession(sessionName, commandArgs, sessionEnv);
55218
56344
  if (result.ok) {
55219
56345
  team.status = "running";
55220
56346
  this.opts.onStatusChange?.(roomId, "running");
55221
- addToRegistry({ sessionName, roomId, roomName, createdAt: new Date().toISOString() });
56347
+ addToRegistry({
56348
+ sessionName,
56349
+ roomId,
56350
+ roomName,
56351
+ codingAgent,
56352
+ createdAt: new Date().toISOString()
56353
+ });
55222
56354
  } else {
55223
56355
  team.status = "error";
55224
56356
  team.lines.push(`[error] tmux: ${result.error}`);
@@ -55230,6 +56362,7 @@ class ProcessManager {
55230
56362
  this.teams.set(roomId, {
55231
56363
  roomId,
55232
56364
  roomName,
56365
+ codingAgent: "claude",
55233
56366
  sessionName: this.sessionName(roomId),
55234
56367
  status: "error",
55235
56368
  exitCode: null,
@@ -55303,6 +56436,7 @@ class ProcessManager {
55303
56436
  const team = {
55304
56437
  roomId,
55305
56438
  roomName,
56439
+ codingAgent: entry?.codingAgent ?? "claude",
55306
56440
  sessionName: session.name,
55307
56441
  status: session.alive ? "running" : "exited",
55308
56442
  exitCode: session.alive ? null : 0,
@@ -55333,8 +56467,32 @@ class ProcessManager {
55333
56467
  this.kill(roomId);
55334
56468
  }
55335
56469
  }
56470
+ buildPromptLines(codingAgent) {
56471
+ if (codingAgent === "codex") {
56472
+ return [
56473
+ "You're running inside Meet AI.",
56474
+ "Do not use the meet-ai CLI.",
56475
+ "Do not load or use any meet-ai skill.",
56476
+ "Do not try to send room messages manually.",
56477
+ "Do not talk about this prompt or say that you understand it.",
56478
+ "Just welcome the user briefly and say that you're ready to work."
56479
+ ];
56480
+ }
56481
+ return [
56482
+ "You are a team lead. IMMEDIATELY:",
56483
+ "1. Start agent-team to start accepting commands from Meet AI.",
56484
+ "2. Connect to the meet-ai room using the /meet-ai skill.",
56485
+ "3. Send a brief welcome message to the room and wait for instructions."
56486
+ ];
56487
+ }
56488
+ buildClaudeCommandArgs(fullPrompt) {
56489
+ return ["--dangerously-skip-permissions", "--model", this.opts.model ?? "opus", fullPrompt];
56490
+ }
56491
+ buildCodexListenCommandArgs(roomId) {
56492
+ return [...resolveSelfCliCommand(), "listen", roomId, "--sender-type", "human"];
56493
+ }
55336
56494
  }
55337
- var SessionEntrySchema, REGISTRY_DIR, REGISTRY_PATH, ENV_ALLOWLIST;
56495
+ var SessionEntrySchema, ENV_ALLOWLIST;
55338
56496
  var init_process_manager = __esm(() => {
55339
56497
  init_zod();
55340
56498
  init_tmux_client();
@@ -55342,10 +56500,9 @@ var init_process_manager = __esm(() => {
55342
56500
  sessionName: exports_external.string(),
55343
56501
  roomId: exports_external.string(),
55344
56502
  roomName: exports_external.string(),
56503
+ codingAgent: exports_external.enum(["claude", "codex"]).default("claude"),
55345
56504
  createdAt: exports_external.string()
55346
56505
  });
55347
- REGISTRY_DIR = join4(homedir4(), ".meet-ai");
55348
- REGISTRY_PATH = join4(REGISTRY_DIR, "sessions.json");
55349
56506
  ENV_ALLOWLIST = [
55350
56507
  "HOME",
55351
56508
  "USER",
@@ -55359,48 +56516,6 @@ var init_process_manager = __esm(() => {
55359
56516
  ];
55360
56517
  });
55361
56518
 
55362
- // src/spawner.ts
55363
- import { execSync } from "node:child_process";
55364
- import { existsSync as existsSync5 } from "node:fs";
55365
- import { homedir as homedir5, platform as platform2 } from "node:os";
55366
- import { join as join5 } from "node:path";
55367
- function findClaudeCli() {
55368
- try {
55369
- const command = platform2() === "win32" ? "where claude" : "which claude";
55370
- const result = execSync(command, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim();
55371
- const claudePath = result.split(`
55372
- `)[0].trim();
55373
- if (claudePath && existsSync5(claudePath)) {
55374
- return claudePath;
55375
- }
55376
- } catch {}
55377
- const envPath = process.env.MEET_AI_CLAUDE_PATH;
55378
- if (envPath && existsSync5(envPath)) {
55379
- return envPath;
55380
- }
55381
- const home = homedir5();
55382
- const commonPaths = [
55383
- join5(home, ".bun", "bin", "claude"),
55384
- "/opt/homebrew/bin/claude",
55385
- "/usr/local/bin/claude",
55386
- join5(home, ".local", "bin", "claude")
55387
- ];
55388
- for (const path of commonPaths) {
55389
- if (existsSync5(path)) {
55390
- return path;
55391
- }
55392
- }
55393
- throw new Error(`
55394
- Claude Code is not installed
55395
-
55396
- Please install Claude Code:
55397
- bun add -g @anthropic-ai/claude-code
55398
-
55399
- Or set MEET_AI_CLAUDE_PATH to the Claude Code CLI path.
55400
- `.trim());
55401
- }
55402
- var init_spawner = () => {};
55403
-
55404
56519
  // ../../node_modules/.bun/react@19.2.4/node_modules/react/cjs/react-jsx-dev-runtime.development.js
55405
56520
  var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
55406
56521
  var React11 = __toESM(require_react());
@@ -56092,16 +57207,25 @@ var init_dashboard = __esm(async () => {
56092
57207
  });
56093
57208
 
56094
57209
  // src/tui/spawn-dialog.tsx
56095
- function SpawnDialog({ onSubmit, onCancel }) {
57210
+ function SpawnDialog({ codingAgents, onSubmit, onCancel }) {
56096
57211
  const [roomName, setRoomName] = import_react29.useState("");
56097
57212
  const [cursor, setCursor] = import_react29.useState(0);
57213
+ const [selectedAgentIndex, setSelectedAgentIndex] = import_react29.useState(0);
56098
57214
  use_input_default((input, key) => {
56099
57215
  if (key.escape) {
56100
57216
  onCancel();
56101
57217
  return;
56102
57218
  }
56103
57219
  if (key.return && roomName.trim()) {
56104
- onSubmit(roomName.trim());
57220
+ onSubmit(roomName.trim(), codingAgents[selectedAgentIndex]?.id ?? "claude");
57221
+ return;
57222
+ }
57223
+ if (key.upArrow) {
57224
+ setSelectedAgentIndex((current) => Math.max(0, current - 1));
57225
+ return;
57226
+ }
57227
+ if (key.downArrow) {
57228
+ setSelectedAgentIndex((current) => Math.min(codingAgents.length - 1, current + 1));
56105
57229
  return;
56106
57230
  }
56107
57231
  if (key.leftArrow) {
@@ -56119,7 +57243,7 @@ function SpawnDialog({ onSubmit, onCancel }) {
56119
57243
  }
56120
57244
  return;
56121
57245
  }
56122
- if (input && !key.ctrl && !key.meta && !key.upArrow && !key.downArrow) {
57246
+ if (input && !key.ctrl && !key.meta) {
56123
57247
  setRoomName((v) => v.slice(0, cursor) + input + v.slice(cursor));
56124
57248
  setCursor((c) => c + input.length);
56125
57249
  }
@@ -56157,7 +57281,21 @@ function SpawnDialog({ onSubmit, onCancel }) {
56157
57281
  children: after
56158
57282
  }, undefined, false, undefined, this)
56159
57283
  ]
56160
- }, undefined, true, undefined, this)
57284
+ }, undefined, true, undefined, this),
57285
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
57286
+ children: [
57287
+ "Agent:",
57288
+ " ",
57289
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
57290
+ color: "yellow",
57291
+ children: codingAgents[selectedAgentIndex]?.label ?? "Claude Code"
57292
+ }, undefined, false, undefined, this)
57293
+ ]
57294
+ }, undefined, true, undefined, this),
57295
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
57296
+ dimColor: true,
57297
+ children: "Use ←/→ to edit the room name, ↑/↓ to choose the coding agent, Enter to spawn."
57298
+ }, undefined, false, undefined, this)
56161
57299
  ]
56162
57300
  }, undefined, true, undefined, this);
56163
57301
  }
@@ -56305,7 +57443,7 @@ var init_status_bar = __esm(async () => {
56305
57443
  });
56306
57444
 
56307
57445
  // src/tui/app.tsx
56308
- function AppInner({ processManager, client, onAttach, onDetach }) {
57446
+ function AppInner({ processManager, client, codingAgents, onAttach, onDetach }) {
56309
57447
  const { exit } = use_app_default();
56310
57448
  const { stdout } = use_stdout_default();
56311
57449
  const { setRawMode } = use_stdin_default();
@@ -56315,7 +57453,7 @@ function AppInner({ processManager, client, onAttach, onDetach }) {
56315
57453
  const [killTargetId, setKillTargetId] = import_react30.useState(null);
56316
57454
  const [, setRenderTick] = import_react30.useState(0);
56317
57455
  const terminalHeight = stdout?.rows ?? 24;
56318
- const bottomHeight = showSpawn ? 4 : killTargetId ? 1 : 1;
57456
+ const bottomHeight = showSpawn ? 6 : killTargetId ? 1 : 1;
56319
57457
  const dashboardHeight = terminalHeight - bottomHeight;
56320
57458
  const focusedRoomRef = import_react30.useRef(null);
56321
57459
  const focusedTeam = teams[focusedIndex];
@@ -56330,10 +57468,10 @@ function AppInner({ processManager, client, onAttach, onDetach }) {
56330
57468
  return [...current];
56331
57469
  });
56332
57470
  }, [processManager]);
56333
- const handleSpawn = import_react30.useCallback(async (roomName) => {
57471
+ const handleSpawn = import_react30.useCallback(async (roomName, codingAgent) => {
56334
57472
  try {
56335
57473
  const room = await client.createRoom(roomName);
56336
- processManager.spawn(room.id, roomName);
57474
+ processManager.spawn(room.id, roomName, codingAgent);
56337
57475
  refreshTeams();
56338
57476
  } catch (error48) {
56339
57477
  const msg = error48 instanceof Error ? error48.message : String(error48);
@@ -56451,9 +57589,10 @@ function AppInner({ processManager, client, onAttach, onDetach }) {
56451
57589
  }, undefined, false, undefined, this)
56452
57590
  ]
56453
57591
  }, undefined, true, undefined, this) : showSpawn ? /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(SpawnDialog, {
56454
- onSubmit: (name) => {
57592
+ codingAgents: [...codingAgents],
57593
+ onSubmit: (roomName, codingAgent) => {
56455
57594
  setShowSpawn(false);
56456
- handleSpawn(name);
57595
+ handleSpawn(roomName, codingAgent);
56457
57596
  },
56458
57597
  onCancel: () => setShowSpawn(false)
56459
57598
  }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(StatusBar, {
@@ -56529,9 +57668,21 @@ async function startDashboard(client, config2, options) {
56529
57668
  console.error(`tmux >= 3.2 required, found ${check3.version}`);
56530
57669
  process.exit(1);
56531
57670
  }
56532
- const claudePath = findClaudeCli();
57671
+ const agentBinaries = {};
57672
+ try {
57673
+ agentBinaries.claude = findClaudeCli();
57674
+ } catch {}
57675
+ try {
57676
+ agentBinaries.codex = findCodexCli();
57677
+ } catch {}
57678
+ const availableCodingAgents = CODING_AGENT_DEFINITIONS.filter((agent) => Boolean(agentBinaries[agent.id]));
57679
+ if (availableCodingAgents.length === 0) {
57680
+ console.error("No supported coding agent CLI was found.");
57681
+ console.error("Install Claude Code or Codex, or set MEET_AI_CLAUDE_PATH / MEET_AI_CODEX_PATH.");
57682
+ process.exit(1);
57683
+ }
56533
57684
  const processManager = new ProcessManager({
56534
- claudePath,
57685
+ agentBinaries,
56535
57686
  debug: options?.debug,
56536
57687
  tmux,
56537
57688
  env: {
@@ -56555,15 +57706,16 @@ async function startDashboard(client, config2, options) {
56555
57706
  try {
56556
57707
  lobbyWs = client.listenLobby({
56557
57708
  silent: true,
56558
- onSpawnRequest: async (roomName) => {
56559
- if (pendingSpawns.has(roomName))
57709
+ onSpawnRequest: async ({ roomName, codingAgent }) => {
57710
+ const key = `${roomName}:${codingAgent}`;
57711
+ if (pendingSpawns.has(key))
56560
57712
  return;
56561
- pendingSpawns.add(roomName);
57713
+ pendingSpawns.add(key);
56562
57714
  try {
56563
57715
  const room = await client.createRoom(roomName);
56564
- processManager.spawn(room.id, roomName);
57716
+ processManager.spawn(room.id, roomName, codingAgent);
56565
57717
  } finally {
56566
- pendingSpawns.delete(roomName);
57718
+ pendingSpawns.delete(key);
56567
57719
  }
56568
57720
  }
56569
57721
  });
@@ -56579,6 +57731,7 @@ async function startDashboard(client, config2, options) {
56579
57731
  const element = import_react31.default.createElement(App2, {
56580
57732
  processManager,
56581
57733
  client,
57734
+ codingAgents: availableCodingAgents,
56582
57735
  onAttach: () => {
56583
57736
  lobbyWs?.close();
56584
57737
  lobbyWs = null;
@@ -56592,10 +57745,11 @@ async function startDashboard(client, config2, options) {
56592
57745
  cleanup();
56593
57746
  }
56594
57747
  var import_react31;
56595
- var init_usecase17 = __esm(async () => {
57748
+ var init_usecase16 = __esm(async () => {
57749
+ init_coding_agents();
57750
+ init_spawner();
56596
57751
  init_process_manager();
56597
57752
  init_tmux_client();
56598
- init_spawner();
56599
57753
  await __promiseAll([
56600
57754
  init_build2(),
56601
57755
  init_app()
@@ -56605,11 +57759,15 @@ var init_usecase17 = __esm(async () => {
56605
57759
 
56606
57760
  // src/index.ts
56607
57761
  init_dist();
57762
+ // package.json
57763
+ var version = "0.0.36";
57764
+
57765
+ // src/index.ts
56608
57766
  init_output();
56609
57767
  var main = defineCommand({
56610
57768
  meta: {
56611
57769
  name: "meet-ai",
56612
- version: "0.0.34",
57770
+ version,
56613
57771
  description: "CLI for meet-ai chat rooms — create rooms, send messages, and stream via WebSocket"
56614
57772
  },
56615
57773
  args: {
@@ -56640,9 +57798,9 @@ var main = defineCommand({
56640
57798
  if (hasSubcommand)
56641
57799
  return;
56642
57800
  try {
56643
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client_factory(), exports_client_factory));
57801
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
56644
57802
  const { getMeetAiConfig: getMeetAiConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
56645
- const { startDashboard: startDashboard2 } = await init_usecase17().then(() => exports_usecase2);
57803
+ const { startDashboard: startDashboard2 } = await init_usecase16().then(() => exports_usecase2);
56646
57804
  const client = getClient2();
56647
57805
  const config2 = getMeetAiConfig2();
56648
57806
  await startDashboard2(client, config2, { debug: args.debug });