@meet-ai/cli 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +163 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15519,10 +15519,11 @@ class TmuxClient {
15519
15519
  "-t",
15520
15520
  target,
15521
15521
  "-p",
15522
- "-e",
15523
- "-S",
15524
- `-${lines}`
15522
+ "-e"
15525
15523
  ];
15524
+ if (lines > 0) {
15525
+ args.push("-S", `-${lines}`);
15526
+ }
15526
15527
  return new Promise((resolve2) => {
15527
15528
  execFileCb("tmux", args, { encoding: "utf8", timeout: 5000 }, (error48, stdout) => {
15528
15529
  if (error48) {
@@ -15538,6 +15539,15 @@ class TmuxClient {
15538
15539
  });
15539
15540
  });
15540
15541
  }
15542
+ resizePane(paneId, cols, rows) {
15543
+ const result = this.exec(["-L", this.server, "resize-pane", "-t", paneId, "-x", String(cols)]);
15544
+ if (!result.ok)
15545
+ return result;
15546
+ if (rows) {
15547
+ return this.exec(["-L", this.server, "resize-pane", "-t", paneId, "-y", String(rows)]);
15548
+ }
15549
+ return result;
15550
+ }
15541
15551
  attachSession(name) {
15542
15552
  validateSessionName(name);
15543
15553
  try {
@@ -15599,6 +15609,19 @@ function listen(client, input) {
15599
15609
  const tmuxClient = new TmuxClient({ server: "meet-ai", scrollback: 50000 });
15600
15610
  let terminalInterval = null;
15601
15611
  const onMessage = (msg) => {
15612
+ if (msg.type === "terminal_resize") {
15613
+ const cols = msg.cols;
15614
+ if (typeof cols === "number" && cols > 0) {
15615
+ tmuxClient.listAllPanes().then((allPanes) => {
15616
+ const roomPrefix = roomId.slice(0, 8);
15617
+ const roomPanes = allPanes.filter((p) => p.sessionName.includes(roomPrefix));
15618
+ for (const p of roomPanes) {
15619
+ tmuxClient.resizePane(p.paneId, cols);
15620
+ }
15621
+ });
15622
+ }
15623
+ return;
15624
+ }
15602
15625
  if (msg.type === "terminal_subscribe") {
15603
15626
  const roomPrefix = roomId.slice(0, 8);
15604
15627
  let membersByPaneId = {};
@@ -15619,6 +15642,7 @@ function listen(client, input) {
15619
15642
  clearInterval(terminalInterval);
15620
15643
  terminalInterval = null;
15621
15644
  }
15645
+ let lastSentPayload = "";
15622
15646
  const TERMINAL_POLL_MS = 500;
15623
15647
  terminalInterval = setInterval(async () => {
15624
15648
  try {
@@ -15638,11 +15662,15 @@ function listen(client, input) {
15638
15662
  return a.name.localeCompare(b.name);
15639
15663
  });
15640
15664
  const results = await Promise.all(panes.map(async (p) => {
15641
- const lines = await tmuxClient.capturePane(p.paneId, 500);
15665
+ const lines = await tmuxClient.capturePane(p.paneId, 0);
15642
15666
  return { name: p.name, paneId: p.paneId, data: lines.join(`\r
15643
15667
  `) };
15644
15668
  }));
15645
- await client.sendTerminalData(roomId, JSON.stringify({ panes: results }));
15669
+ const payload = JSON.stringify({ panes: results });
15670
+ if (payload === lastSentPayload)
15671
+ return;
15672
+ lastSentPayload = payload;
15673
+ await client.sendTerminalData(roomId, payload);
15646
15674
  } catch {}
15647
15675
  }, TERMINAL_POLL_MS);
15648
15676
  return;
@@ -15654,6 +15682,9 @@ function listen(client, input) {
15654
15682
  }
15655
15683
  return;
15656
15684
  }
15685
+ if (msg.type === "terminal_data") {
15686
+ return;
15687
+ }
15657
15688
  if (msg.id && msg.room_id && msg.attachment_count > 0) {
15658
15689
  downloadMessageAttachments(client, msg.room_id, msg.id).then((paths) => {
15659
15690
  const output = paths.length ? { ...msg, attachments: paths } : msg;
@@ -16009,10 +16040,56 @@ var init_command10 = __esm(() => {
16009
16040
  });
16010
16041
 
16011
16042
  // src/lib/hooks/find-room.ts
16012
- import { readdirSync, readFileSync as readFileSync3 } from "node:fs";
16043
+ import { readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2, createReadStream } from "node:fs";
16013
16044
  import { join as join2 } from "node:path";
16014
- function findRoomId(sessionId, teamsDir) {
16045
+ import { createInterface } from "node:readline";
16046
+ async function extractTeamName(transcriptPath) {
16047
+ try {
16048
+ const rl = createInterface({
16049
+ input: createReadStream(transcriptPath, "utf-8"),
16050
+ crlfDelay: Infinity
16051
+ });
16052
+ for await (const line of rl) {
16053
+ try {
16054
+ const obj = JSON.parse(line);
16055
+ if (obj.teamName) {
16056
+ rl.close();
16057
+ return obj.teamName;
16058
+ }
16059
+ } catch {
16060
+ continue;
16061
+ }
16062
+ }
16063
+ } catch {}
16064
+ return null;
16065
+ }
16066
+ function registerSession(filePath, data, sessionId) {
16067
+ const ids = data.session_ids ?? [data.session_id];
16068
+ if (!ids.includes(sessionId)) {
16069
+ ids.push(sessionId);
16070
+ }
16071
+ if (!ids.includes(data.session_id)) {
16072
+ ids.unshift(data.session_id);
16073
+ }
16074
+ data.session_ids = ids;
16075
+ try {
16076
+ writeFileSync2(filePath, JSON.stringify(data));
16077
+ } catch {}
16078
+ }
16079
+ async function findRoomId(sessionId, teamsDir, transcriptPath) {
16015
16080
  const dir = teamsDir ?? `${process.env.HOME}/.claude/teams`;
16081
+ if (transcriptPath) {
16082
+ const teamName = await extractTeamName(transcriptPath);
16083
+ if (teamName) {
16084
+ const filePath = join2(dir, teamName, "meet-ai.json");
16085
+ try {
16086
+ const raw = readFileSync3(filePath, "utf-8");
16087
+ const data = JSON.parse(raw);
16088
+ registerSession(filePath, data, sessionId);
16089
+ return data.room_id || null;
16090
+ } catch {}
16091
+ }
16092
+ }
16016
16093
  let entries;
16017
16094
  try {
16018
16095
  entries = readdirSync(dir);
@@ -16024,7 +16101,8 @@ function findRoomId(sessionId, teamsDir) {
16024
16101
  try {
16025
16102
  const raw = readFileSync3(filePath, "utf-8");
16026
16103
  const data = JSON.parse(raw);
16027
- if (data.session_id === sessionId) {
16104
+ const knownIds = data.session_ids ?? [data.session_id];
16105
+ if (knownIds.includes(sessionId) || data.session_id === sessionId) {
16028
16106
  return data.room_id || null;
16029
16107
  }
16030
16108
  } catch {
@@ -16076,6 +16154,39 @@ function summarize(toolName, toolInput) {
16076
16154
  var truncate = (s, n) => s.slice(0, n);
16077
16155
  var init_summarize = () => {};
16078
16156
 
16157
+ // src/lib/hooks/format-diff.ts
16158
+ function shortPath(filePath) {
16159
+ const parts = filePath.replace(/\\/g, "/").split("/").filter(Boolean);
16160
+ return parts.slice(-3).join("/");
16161
+ }
16162
+ function formatDiff(filePath, hunks) {
16163
+ const display = shortPath(filePath);
16164
+ const diffLines = hunks.map((hunk) => {
16165
+ const header = `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`;
16166
+ return `${header}
16167
+ ${hunk.lines.join(`
16168
+ `)}`;
16169
+ }).join(`
16170
+ `);
16171
+ return `[diff:${display}]
16172
+ --- a/${display}
16173
+ +++ b/${display}
16174
+ ${diffLines}`;
16175
+ }
16176
+ function formatWriteDiff(filePath, content) {
16177
+ const display = shortPath(filePath);
16178
+ const lines = content.split(`
16179
+ `);
16180
+ const header = `@@ -0,0 +1,${lines.length} @@`;
16181
+ const addedLines = lines.map((line) => `+${line}`).join(`
16182
+ `);
16183
+ return `[diff:${display}]
16184
+ --- /dev/null
16185
+ +++ b/${display}
16186
+ ${header}
16187
+ ${addedLines}`;
16188
+ }
16189
+
16079
16190
  // ../../node_modules/.bun/hono@4.11.8/node_modules/hono/dist/utils/url.js
16080
16191
  var init_url = () => {};
16081
16192
 
@@ -16427,7 +16538,7 @@ var init_hooks = __esm(() => {
16427
16538
  });
16428
16539
 
16429
16540
  // src/commands/hook/log-tool-use/usecase.ts
16430
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, statSync as statSync2, rmSync } from "node:fs";
16541
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, statSync as statSync2, rmSync } from "node:fs";
16431
16542
  function getOrCreateParentId(sessionId) {
16432
16543
  const path = `/tmp/meet-ai-hook-${sessionId}.msgid`;
16433
16544
  try {
@@ -16443,7 +16554,7 @@ function getOrCreateParentId(sessionId) {
16443
16554
  }
16444
16555
  function saveParentId(sessionId, msgId) {
16445
16556
  try {
16446
- writeFileSync2(`/tmp/meet-ai-hook-${sessionId}.msgid`, msgId);
16557
+ writeFileSync3(`/tmp/meet-ai-hook-${sessionId}.msgid`, msgId);
16447
16558
  } catch {}
16448
16559
  }
16449
16560
  async function processHookInput(rawInput, teamsDir) {
@@ -16453,7 +16564,13 @@ async function processHookInput(rawInput, teamsDir) {
16453
16564
  } catch {
16454
16565
  return "skip";
16455
16566
  }
16456
- const { session_id: sessionId, tool_name: toolName, tool_input: toolInput = {} } = input;
16567
+ const {
16568
+ session_id: sessionId,
16569
+ transcript_path: transcriptPath,
16570
+ tool_name: toolName,
16571
+ tool_input: toolInput = {},
16572
+ tool_response: toolResponse
16573
+ } = input;
16457
16574
  if (!sessionId || !toolName)
16458
16575
  return "skip";
16459
16576
  if (toolName === "SendMessage")
@@ -16463,7 +16580,7 @@ async function processHookInput(rawInput, teamsDir) {
16463
16580
  if (cmd.startsWith("cd ") || cmd.startsWith("meet-ai "))
16464
16581
  return "skip";
16465
16582
  }
16466
- const roomId = findRoomId(sessionId, teamsDir);
16583
+ const roomId = await findRoomId(sessionId, teamsDir, transcriptPath);
16467
16584
  if (!roomId)
16468
16585
  return "skip";
16469
16586
  const url2 = process.env.MEET_AI_URL;
@@ -16471,6 +16588,31 @@ async function processHookInput(rawInput, teamsDir) {
16471
16588
  if (!url2 || !key)
16472
16589
  return "skip";
16473
16590
  const client = createHookClient(url2, key);
16591
+ if (toolName === "Edit" && toolResponse?.structuredPatch) {
16592
+ const hunks = toolResponse.structuredPatch;
16593
+ const filePath = typeof toolInput.file_path === "string" ? toolInput.file_path : "?";
16594
+ const diffContent = formatDiff(filePath, hunks);
16595
+ let parentId2 = getOrCreateParentId(sessionId);
16596
+ if (!parentId2) {
16597
+ parentId2 = await sendParentMessage(client, roomId);
16598
+ if (parentId2)
16599
+ saveParentId(sessionId, parentId2);
16600
+ }
16601
+ await sendLogEntry(client, roomId, diffContent, parentId2 ?? undefined);
16602
+ return "sent";
16603
+ }
16604
+ if (toolName === "Write" && typeof toolInput.content === "string") {
16605
+ const filePath = typeof toolInput.file_path === "string" ? toolInput.file_path : "?";
16606
+ const diffContent = formatWriteDiff(filePath, toolInput.content);
16607
+ let parentId2 = getOrCreateParentId(sessionId);
16608
+ if (!parentId2) {
16609
+ parentId2 = await sendParentMessage(client, roomId);
16610
+ if (parentId2)
16611
+ saveParentId(sessionId, parentId2);
16612
+ }
16613
+ await sendLogEntry(client, roomId, diffContent, parentId2 ?? undefined);
16614
+ return "sent";
16615
+ }
16474
16616
  const summary = summarize(toolName, toolInput);
16475
16617
  let parentId = getOrCreateParentId(sessionId);
16476
16618
  if (!parentId) {
@@ -16614,14 +16756,14 @@ async function processPlanReview(rawInput, teamsDir) {
16614
16756
  `);
16615
16757
  return;
16616
16758
  }
16617
- const { session_id: sessionId } = input;
16759
+ const { session_id: sessionId, transcript_path: transcriptPath } = input;
16618
16760
  if (!sessionId) {
16619
16761
  process.stderr.write(`[plan-review] missing session_id
16620
16762
  `);
16621
16763
  return;
16622
16764
  }
16623
16765
  const planContent = input.tool_input?.plan || "_Agent requested to exit plan mode without a plan._";
16624
- const roomId = findRoomId(sessionId, teamsDir);
16766
+ const roomId = await findRoomId(sessionId, teamsDir, transcriptPath);
16625
16767
  if (!roomId) {
16626
16768
  process.stderr.write(`[plan-review] no room found for session
16627
16769
  `);
@@ -16802,7 +16944,7 @@ async function processQuestionReview(rawInput, teamsDir, opts) {
16802
16944
  `);
16803
16945
  return;
16804
16946
  }
16805
- const { session_id: sessionId, hook_event_name: hookEventName, tool_input: toolInput } = input;
16947
+ const { session_id: sessionId, transcript_path: transcriptPath, hook_event_name: hookEventName, tool_input: toolInput } = input;
16806
16948
  if (!sessionId || !toolInput?.questions?.length) {
16807
16949
  process.stderr.write(`[question-review] missing session_id or questions
16808
16950
  `);
@@ -16810,7 +16952,7 @@ async function processQuestionReview(rawInput, teamsDir, opts) {
16810
16952
  }
16811
16953
  process.stderr.write(`[question-review] triggered by ${hookEventName} event
16812
16954
  `);
16813
- const roomId = findRoomId(sessionId, teamsDir);
16955
+ const roomId = await findRoomId(sessionId, teamsDir, transcriptPath);
16814
16956
  if (!roomId) {
16815
16957
  process.stderr.write(`[question-review] no room found for session
16816
16958
  `);
@@ -16999,7 +17141,7 @@ async function processPermissionReview(rawInput, teamsDir, opts) {
16999
17141
  `);
17000
17142
  return;
17001
17143
  }
17002
- const { session_id: sessionId, hook_event_name: hookEventName, tool_name: toolName, tool_input: toolInput } = input;
17144
+ const { session_id: sessionId, transcript_path: transcriptPath, hook_event_name: hookEventName, tool_name: toolName, tool_input: toolInput } = input;
17003
17145
  if (!sessionId || !toolName) {
17004
17146
  process.stderr.write(`[permission-review] missing session_id or tool_name
17005
17147
  `);
@@ -17013,7 +17155,7 @@ async function processPermissionReview(rawInput, teamsDir, opts) {
17013
17155
  }
17014
17156
  process.stderr.write(`[permission-review] triggered by ${hookEventName} for tool ${toolName}
17015
17157
  `);
17016
- const roomId = findRoomId(sessionId, teamsDir);
17158
+ const roomId = await findRoomId(sessionId, teamsDir, transcriptPath);
17017
17159
  if (!roomId) {
17018
17160
  process.stderr.write(`[permission-review] no room found for session
17019
17161
  `);
@@ -54928,7 +55070,7 @@ var init_build2 = __esm(async () => {
54928
55070
  });
54929
55071
 
54930
55072
  // src/lib/process-manager.ts
54931
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync, lstatSync } from "node:fs";
55073
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync, lstatSync } from "node:fs";
54932
55074
  import { homedir as homedir4 } from "node:os";
54933
55075
  import { join as join4 } from "node:path";
54934
55076
  function readRegistry() {
@@ -54950,7 +55092,7 @@ function writeRegistry(entries) {
54950
55092
  return;
54951
55093
  }
54952
55094
  const tmpPath = join4(REGISTRY_DIR, `sessions.${process.pid}.${Date.now()}.tmp`);
54953
- writeFileSync3(tmpPath, JSON.stringify(entries, null, 2), { mode: 384 });
55095
+ writeFileSync4(tmpPath, JSON.stringify(entries, null, 2), { mode: 384 });
54954
55096
  renameSync(tmpPath, REGISTRY_PATH);
54955
55097
  }
54956
55098
  function addToRegistry(entry) {
@@ -56417,7 +56559,7 @@ init_output();
56417
56559
  var main = defineCommand({
56418
56560
  meta: {
56419
56561
  name: "meet-ai",
56420
- version: "0.0.30",
56562
+ version: "0.0.32",
56421
56563
  description: "CLI for meet-ai chat rooms — create rooms, send messages, and stream via WebSocket"
56422
56564
  },
56423
56565
  args: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meet-ai/cli",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "CLI for meet-ai chat rooms — create rooms, send messages, and stream via WebSocket",
5
5
  "keywords": [
6
6
  "chat",