@hasna/conversations 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -31003,7 +31003,7 @@ var init_mcp2 = __esm(() => {
31003
31003
  init_channels();
31004
31004
  server = new McpServer({
31005
31005
  name: "conversations",
31006
- version: "0.0.4"
31006
+ version: "0.0.6"
31007
31007
  });
31008
31008
  server.registerTool("send_message", {
31009
31009
  title: "Send Message",
@@ -31224,6 +31224,115 @@ var init_mcp2 = __esm(() => {
31224
31224
  }
31225
31225
  });
31226
31226
 
31227
+ // src/server/serve.ts
31228
+ var exports_serve = {};
31229
+ __export(exports_serve, {
31230
+ startDashboardServer: () => startDashboardServer
31231
+ });
31232
+ import { join as join2 } from "path";
31233
+ import { existsSync } from "fs";
31234
+ function jsonResponse(data, status = 200) {
31235
+ return new Response(JSON.stringify(data), {
31236
+ status,
31237
+ headers: { "Content-Type": "application/json" }
31238
+ });
31239
+ }
31240
+ function getStatus() {
31241
+ const db2 = getDb();
31242
+ const dbPath = getDbPath();
31243
+ const totalMessages = db2.prepare("SELECT COUNT(*) as count FROM messages").get().count;
31244
+ const totalSessions = db2.prepare("SELECT COUNT(DISTINCT session_id) as count FROM messages").get().count;
31245
+ const totalUnread = db2.prepare("SELECT COUNT(*) as count FROM messages WHERE read_at IS NULL").get().count;
31246
+ const totalChannels = db2.prepare("SELECT COUNT(*) as count FROM channels").get().count;
31247
+ return {
31248
+ db_path: dbPath,
31249
+ total_messages: totalMessages,
31250
+ total_sessions: totalSessions,
31251
+ total_channels: totalChannels,
31252
+ unread_messages: totalUnread
31253
+ };
31254
+ }
31255
+ function startDashboardServer(port = 3456) {
31256
+ const dashboardDist = join2(import.meta.dir, "../../dashboard/dist");
31257
+ const hasDist = existsSync(dashboardDist);
31258
+ const server2 = Bun.serve({
31259
+ port,
31260
+ async fetch(req) {
31261
+ const url2 = new URL(req.url);
31262
+ const path = url2.pathname;
31263
+ if (path === "/api/status") {
31264
+ return jsonResponse(getStatus());
31265
+ }
31266
+ if (path === "/api/messages" && req.method === "GET") {
31267
+ const limit = parseInt(url2.searchParams.get("limit") || "50");
31268
+ const session = url2.searchParams.get("session") || undefined;
31269
+ const channel = url2.searchParams.get("channel") || undefined;
31270
+ const from = url2.searchParams.get("from") || undefined;
31271
+ const to = url2.searchParams.get("to") || undefined;
31272
+ const messages = readMessages({ session_id: session, channel, from, to, limit });
31273
+ return jsonResponse(messages.reverse());
31274
+ }
31275
+ if (path === "/api/messages" && req.method === "POST") {
31276
+ try {
31277
+ const text = await req.text();
31278
+ const body = JSON.parse(text);
31279
+ const msg = sendMessage({
31280
+ from: body.from,
31281
+ to: body.to,
31282
+ content: body.content,
31283
+ channel: body.channel,
31284
+ priority: body.priority
31285
+ });
31286
+ return jsonResponse(msg);
31287
+ } catch (e) {
31288
+ return jsonResponse({ error: e.message }, 400);
31289
+ }
31290
+ }
31291
+ if (path === "/api/sessions") {
31292
+ const agent = url2.searchParams.get("agent") || undefined;
31293
+ return jsonResponse(listSessions(agent));
31294
+ }
31295
+ if (path === "/api/channels" && req.method === "GET") {
31296
+ return jsonResponse(listChannels());
31297
+ }
31298
+ if (path === "/api/channels" && req.method === "POST") {
31299
+ try {
31300
+ const text = await req.text();
31301
+ const body = JSON.parse(text);
31302
+ const ch = createChannel(body.name, body.created_by, body.description);
31303
+ return jsonResponse(ch);
31304
+ } catch (e) {
31305
+ return jsonResponse({ error: e.message }, 400);
31306
+ }
31307
+ }
31308
+ if (hasDist) {
31309
+ let filePath = join2(dashboardDist, path === "/" ? "index.html" : path);
31310
+ let file2 = Bun.file(filePath);
31311
+ if (await file2.exists())
31312
+ return new Response(file2);
31313
+ file2 = Bun.file(join2(dashboardDist, "index.html"));
31314
+ if (await file2.exists())
31315
+ return new Response(file2);
31316
+ }
31317
+ return new Response("Not Found", { status: 404 });
31318
+ }
31319
+ });
31320
+ console.log(`Dashboard running at http://localhost:${server2.port}`);
31321
+ return server2;
31322
+ }
31323
+ var isDirectRun2;
31324
+ var init_serve = __esm(() => {
31325
+ init_messages();
31326
+ init_sessions();
31327
+ init_channels();
31328
+ init_db();
31329
+ isDirectRun2 = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("serve.ts") || process.argv[1]?.endsWith("serve.js");
31330
+ if (isDirectRun2) {
31331
+ const port = parseInt(process.env.PORT || "3456");
31332
+ startDashboardServer(port);
31333
+ }
31334
+ });
31335
+
31227
31336
  // node_modules/commander/esm.mjs
31228
31337
  var import__ = __toESM(require_commander(), 1);
31229
31338
  var {
@@ -31247,10 +31356,10 @@ init_channels();
31247
31356
  init_db();
31248
31357
  import chalk2 from "chalk";
31249
31358
  import { render } from "ink";
31250
- import React7 from "react";
31359
+ import React8 from "react";
31251
31360
 
31252
31361
  // src/cli/components/App.tsx
31253
- import { useState as useState5 } from "react";
31362
+ import { useState as useState6 } from "react";
31254
31363
  import { Box as Box6, Text as Text7, useApp, useInput as useInput5 } from "ink";
31255
31364
 
31256
31365
  // node_modules/ink-text-input/build/index.js
@@ -31346,6 +31455,7 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
31346
31455
  var build_default = TextInput;
31347
31456
 
31348
31457
  // src/cli/components/SessionList.tsx
31458
+ import { useState as useState3, useEffect as useEffect3 } from "react";
31349
31459
  import { Box as Box3, Text as Text4, useInput as useInput3 } from "ink";
31350
31460
 
31351
31461
  // node_modules/ink-select-input/build/Indicator.js
@@ -31753,23 +31863,37 @@ function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicator
31753
31863
  var SelectInput_default = SelectInput;
31754
31864
  // src/cli/components/SessionList.tsx
31755
31865
  init_sessions();
31866
+ init_channels();
31756
31867
  import { jsxDEV } from "react/jsx-dev-runtime";
31757
- function SessionList({ agent, onSelect, onNew }) {
31758
- const sessions = listSessions(agent);
31868
+ function SessionList({ agent, onSelect, onSelectChannel, onNew }) {
31869
+ const [sessions, setSessions] = useState3(() => listSessions(agent));
31870
+ const [channels, setChannels] = useState3(() => listChannels());
31871
+ useEffect3(() => {
31872
+ const timer = setInterval(() => {
31873
+ setSessions(listSessions(agent));
31874
+ setChannels(listChannels());
31875
+ }, 1000);
31876
+ return () => clearInterval(timer);
31877
+ }, [agent]);
31759
31878
  useInput3((input) => {
31760
31879
  if (input === "n")
31761
31880
  onNew();
31762
31881
  });
31763
- const items = sessions.map((s) => {
31882
+ const channelItems = channels.map((ch) => ({
31883
+ label: `#${ch.name}${ch.description ? ` \u2014 ${ch.description}` : ""} (${ch.message_count} msgs, ${ch.member_count} members)`,
31884
+ value: `channel:${ch.name}`
31885
+ }));
31886
+ const dmSessions = sessions.filter((s) => !s.session_id.startsWith("channel:"));
31887
+ const sessionItems = dmSessions.map((s) => {
31764
31888
  const others = s.participants.filter((p) => p !== agent).join(", ") || agent;
31765
31889
  const unread = s.unread_count > 0 ? ` (${s.unread_count} unread)` : "";
31766
31890
  return {
31767
31891
  label: `${others} \u2014 ${s.message_count} msgs${unread}`,
31768
- value: s.session_id,
31769
- session: s
31892
+ value: s.session_id
31770
31893
  };
31771
31894
  });
31772
- if (items.length === 0) {
31895
+ const allItems = [...channelItems, ...sessionItems];
31896
+ if (allItems.length === 0) {
31773
31897
  return /* @__PURE__ */ jsxDEV(Box3, {
31774
31898
  flexDirection: "column",
31775
31899
  padding: 1,
@@ -31781,17 +31905,37 @@ function SessionList({ agent, onSelect, onNew }) {
31781
31905
  }, undefined, false, undefined, this),
31782
31906
  /* @__PURE__ */ jsxDEV(Text4, {
31783
31907
  dimColor: true,
31784
- children: "No conversations yet."
31785
- }, undefined, false, undefined, this),
31786
- /* @__PURE__ */ jsxDEV(Text4, {
31787
- dimColor: true,
31788
31908
  children: [
31789
- "Press ",
31909
+ " as ",
31910
+ /* @__PURE__ */ jsxDEV(Text4, {
31911
+ color: "yellow",
31912
+ children: agent
31913
+ }, undefined, false, undefined, this)
31914
+ ]
31915
+ }, undefined, true, undefined, this),
31916
+ /* @__PURE__ */ jsxDEV(Box3, {
31917
+ marginTop: 1,
31918
+ children: [
31919
+ /* @__PURE__ */ jsxDEV(Text4, {
31920
+ dimColor: true,
31921
+ children: "No conversations yet. Press "
31922
+ }, undefined, false, undefined, this),
31790
31923
  /* @__PURE__ */ jsxDEV(Text4, {
31791
31924
  bold: true,
31792
31925
  children: "n"
31793
31926
  }, undefined, false, undefined, this),
31794
- " to start a new conversation."
31927
+ /* @__PURE__ */ jsxDEV(Text4, {
31928
+ dimColor: true,
31929
+ children: " to start one, or "
31930
+ }, undefined, false, undefined, this),
31931
+ /* @__PURE__ */ jsxDEV(Text4, {
31932
+ bold: true,
31933
+ children: "q"
31934
+ }, undefined, false, undefined, this),
31935
+ /* @__PURE__ */ jsxDEV(Text4, {
31936
+ dimColor: true,
31937
+ children: " to quit."
31938
+ }, undefined, false, undefined, this)
31795
31939
  ]
31796
31940
  }, undefined, true, undefined, this)
31797
31941
  ]
@@ -31803,6 +31947,7 @@ function SessionList({ agent, onSelect, onNew }) {
31803
31947
  children: [
31804
31948
  /* @__PURE__ */ jsxDEV(Box3, {
31805
31949
  marginBottom: 1,
31950
+ flexDirection: "column",
31806
31951
  children: [
31807
31952
  /* @__PURE__ */ jsxDEV(Text4, {
31808
31953
  bold: true,
@@ -31811,16 +31956,27 @@ function SessionList({ agent, onSelect, onNew }) {
31811
31956
  }, undefined, false, undefined, this),
31812
31957
  /* @__PURE__ */ jsxDEV(Text4, {
31813
31958
  dimColor: true,
31814
- children: " (n: new, q: quit)"
31815
- }, undefined, false, undefined, this)
31959
+ children: [
31960
+ " as ",
31961
+ /* @__PURE__ */ jsxDEV(Text4, {
31962
+ color: "yellow",
31963
+ children: agent
31964
+ }, undefined, false, undefined, this),
31965
+ " (n: new, q: quit)"
31966
+ ]
31967
+ }, undefined, true, undefined, this)
31816
31968
  ]
31817
31969
  }, undefined, true, undefined, this),
31818
31970
  /* @__PURE__ */ jsxDEV(SelectInput_default, {
31819
- items,
31971
+ items: allItems,
31820
31972
  onSelect: (item) => {
31821
- const session = sessions.find((s) => s.session_id === item.value);
31822
- if (session)
31823
- onSelect(session);
31973
+ if (item.value.startsWith("channel:")) {
31974
+ onSelectChannel(item.value.slice(8));
31975
+ } else {
31976
+ const session = dmSessions.find((s) => s.session_id === item.value);
31977
+ if (session)
31978
+ onSelect(session);
31979
+ }
31824
31980
  }
31825
31981
  }, undefined, false, undefined, this)
31826
31982
  ]
@@ -31828,12 +31984,13 @@ function SessionList({ agent, onSelect, onNew }) {
31828
31984
  }
31829
31985
 
31830
31986
  // src/cli/components/ChatView.tsx
31831
- import React5, { useState as useState4 } from "react";
31987
+ import { useState as useState5, useEffect as useEffect5 } from "react";
31832
31988
  import { Box as Box5, Text as Text6, useInput as useInput4 } from "ink";
31989
+ init_messages();
31833
31990
 
31834
31991
  // src/lib/poll.ts
31835
31992
  init_messages();
31836
- import { useState as useState3, useEffect as useEffect3, useRef as useRef2 } from "react";
31993
+ import { useState as useState4, useEffect as useEffect4, useRef as useRef2 } from "react";
31837
31994
  function startPolling(opts) {
31838
31995
  const interval = opts.interval_ms ?? 200;
31839
31996
  let lastSeen = new Date().toISOString();
@@ -31860,95 +32017,78 @@ function startPolling(opts) {
31860
32017
  }
31861
32018
  };
31862
32019
  }
31863
- function useMessages(sessionId, agent) {
31864
- const [messages, setMessages] = useState3([]);
31865
- const initialLoad = useRef2(false);
31866
- useEffect3(() => {
31867
- if (!initialLoad.current) {
31868
- const existing = readMessages({ session_id: sessionId });
31869
- setMessages(existing);
31870
- initialLoad.current = true;
31871
- }
31872
- const { stop } = startPolling({
31873
- session_id: sessionId,
31874
- interval_ms: 200,
31875
- on_messages: (newMessages) => {
31876
- setMessages((prev) => [...prev, ...newMessages]);
31877
- }
31878
- });
31879
- return stop;
31880
- }, [sessionId, agent]);
31881
- return messages;
31882
- }
31883
-
31884
- // src/cli/components/ChatView.tsx
31885
- init_messages();
31886
32020
 
31887
32021
  // src/cli/components/MessageBubble.tsx
31888
32022
  import { Box as Box4, Text as Text5 } from "ink";
31889
32023
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
31890
- var priorityColors = {
31891
- urgent: "red",
31892
- high: "yellow",
31893
- normal: "",
31894
- low: "dim"
31895
- };
31896
32024
  function MessageBubble({ message, isOwn }) {
31897
32025
  const time = message.created_at.slice(11, 19);
31898
- const color = priorityColors[message.priority] || "";
31899
32026
  return /* @__PURE__ */ jsxDEV2(Box4, {
31900
- flexDirection: "column",
31901
- alignItems: isOwn ? "flex-end" : "flex-start",
31902
- marginBottom: 0,
31903
32027
  children: [
31904
- /* @__PURE__ */ jsxDEV2(Box4, {
31905
- gap: 1,
32028
+ /* @__PURE__ */ jsxDEV2(Text5, {
32029
+ dimColor: true,
31906
32030
  children: [
31907
- /* @__PURE__ */ jsxDEV2(Text5, {
31908
- dimColor: true,
31909
- children: time
31910
- }, undefined, false, undefined, this),
31911
- /* @__PURE__ */ jsxDEV2(Text5, {
31912
- bold: true,
31913
- color: isOwn ? "cyan" : "green",
31914
- children: message.from_agent
31915
- }, undefined, false, undefined, this),
31916
- message.priority !== "normal" && /* @__PURE__ */ jsxDEV2(Text5, {
31917
- color,
31918
- children: [
31919
- "[",
31920
- message.priority,
31921
- "]"
31922
- ]
31923
- }, undefined, true, undefined, this),
31924
- !message.read_at && !isOwn && /* @__PURE__ */ jsxDEV2(Text5, {
31925
- color: "green",
31926
- children: "*"
31927
- }, undefined, false, undefined, this)
32031
+ time,
32032
+ " "
31928
32033
  ]
31929
32034
  }, undefined, true, undefined, this),
31930
- /* @__PURE__ */ jsxDEV2(Box4, {
31931
- marginLeft: isOwn ? 2 : 0,
31932
- marginRight: isOwn ? 0 : 2,
31933
- children: /* @__PURE__ */ jsxDEV2(Text5, {
31934
- wrap: "wrap",
31935
- children: message.content
31936
- }, undefined, false, undefined, this)
31937
- }, undefined, false, undefined, this)
32035
+ /* @__PURE__ */ jsxDEV2(Text5, {
32036
+ bold: true,
32037
+ color: isOwn ? "cyan" : "green",
32038
+ children: message.from_agent
32039
+ }, undefined, false, undefined, this),
32040
+ message.priority !== "normal" && /* @__PURE__ */ jsxDEV2(Text5, {
32041
+ color: message.priority === "urgent" ? "red" : "yellow",
32042
+ children: [
32043
+ " [",
32044
+ message.priority,
32045
+ "]"
32046
+ ]
32047
+ }, undefined, true, undefined, this),
32048
+ /* @__PURE__ */ jsxDEV2(Text5, {
32049
+ children: [
32050
+ ": ",
32051
+ message.content
32052
+ ]
32053
+ }, undefined, true, undefined, this)
31938
32054
  ]
31939
32055
  }, undefined, true, undefined, this);
31940
32056
  }
31941
32057
 
31942
32058
  // src/cli/components/ChatView.tsx
31943
32059
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
31944
- function ChatView({ sessionId, agent, participants, onBack }) {
31945
- const messages = useMessages(sessionId, agent);
31946
- const [input, setInput] = useState4("");
31947
- const others = participants.filter((p) => p !== agent);
31948
- const recipient = others[0] || agent;
31949
- React5.useEffect(() => {
31950
- markSessionRead(sessionId, agent);
31951
- }, [messages.length, sessionId, agent]);
32060
+ function ChatView({ agent, onBack, sessionId: initialSessionId, recipient, channelName }) {
32061
+ const [messages, setMessages] = useState5([]);
32062
+ const [input, setInput] = useState5("");
32063
+ const [sessionId, setSessionId] = useState5(initialSessionId);
32064
+ const isChannel = !!channelName;
32065
+ useEffect5(() => {
32066
+ const opts = isChannel ? { channel: channelName } : sessionId ? { session_id: sessionId } : {};
32067
+ if (isChannel || sessionId) {
32068
+ const existing = readMessages(opts);
32069
+ setMessages(existing);
32070
+ }
32071
+ const pollOpts = isChannel ? { channel: channelName } : sessionId ? { session_id: sessionId } : null;
32072
+ if (!pollOpts)
32073
+ return;
32074
+ const { stop } = startPolling({
32075
+ ...pollOpts,
32076
+ interval_ms: 200,
32077
+ on_messages: (newMsgs) => {
32078
+ setMessages((prev) => [...prev, ...newMsgs]);
32079
+ }
32080
+ });
32081
+ return stop;
32082
+ }, [sessionId, channelName]);
32083
+ useEffect5(() => {
32084
+ if (messages.length === 0)
32085
+ return;
32086
+ if (isChannel && channelName) {
32087
+ markChannelRead(channelName, agent);
32088
+ } else if (sessionId) {
32089
+ markSessionRead(sessionId, agent);
32090
+ }
32091
+ }, [messages.length]);
31952
32092
  useInput4((_, key) => {
31953
32093
  if (key.escape)
31954
32094
  onBack();
@@ -31956,33 +32096,46 @@ function ChatView({ sessionId, agent, participants, onBack }) {
31956
32096
  const handleSubmit = (value) => {
31957
32097
  if (!value.trim())
31958
32098
  return;
31959
- sendMessage({
31960
- from: agent,
31961
- to: recipient,
31962
- content: value.trim(),
31963
- session_id: sessionId
31964
- });
32099
+ if (isChannel && channelName) {
32100
+ const msg = sendMessage({
32101
+ from: agent,
32102
+ to: channelName,
32103
+ content: value.trim(),
32104
+ channel: channelName,
32105
+ session_id: `channel:${channelName}`
32106
+ });
32107
+ setMessages((prev) => [...prev, msg]);
32108
+ } else {
32109
+ const to = recipient || agent;
32110
+ const msg = sendMessage({
32111
+ from: agent,
32112
+ to,
32113
+ content: value.trim(),
32114
+ session_id: sessionId
32115
+ });
32116
+ if (!sessionId) {
32117
+ setSessionId(msg.session_id);
32118
+ }
32119
+ }
31965
32120
  setInput("");
31966
32121
  };
32122
+ const title = isChannel ? `#${channelName}` : recipient || "self";
32123
+ const prompt = isChannel ? `${agent} \u2192 #${channelName}` : `${agent} \u2192 ${recipient || "self"}`;
31967
32124
  return /* @__PURE__ */ jsxDEV3(Box5, {
31968
32125
  flexDirection: "column",
31969
32126
  padding: 1,
31970
32127
  children: [
31971
32128
  /* @__PURE__ */ jsxDEV3(Box5, {
31972
32129
  marginBottom: 1,
31973
- gap: 1,
31974
32130
  children: [
31975
32131
  /* @__PURE__ */ jsxDEV3(Text6, {
31976
32132
  bold: true,
31977
- color: "cyan",
31978
- children: [
31979
- "Chat: ",
31980
- others.join(", ") || "self"
31981
- ]
31982
- }, undefined, true, undefined, this),
32133
+ color: isChannel ? "magenta" : "cyan",
32134
+ children: title
32135
+ }, undefined, false, undefined, this),
31983
32136
  /* @__PURE__ */ jsxDEV3(Text6, {
31984
32137
  dimColor: true,
31985
- children: "(Esc: back)"
32138
+ children: " (Esc: back)"
31986
32139
  }, undefined, false, undefined, this)
31987
32140
  ]
31988
32141
  }, undefined, true, undefined, this),
@@ -31991,7 +32144,7 @@ function ChatView({ sessionId, agent, participants, onBack }) {
31991
32144
  flexGrow: 1,
31992
32145
  children: messages.length === 0 ? /* @__PURE__ */ jsxDEV3(Text6, {
31993
32146
  dimColor: true,
31994
- children: "No messages yet. Start typing below."
32147
+ children: "No messages yet. Type below and press Enter."
31995
32148
  }, undefined, false, undefined, this) : messages.map((msg) => /* @__PURE__ */ jsxDEV3(MessageBubble, {
31996
32149
  message: msg,
31997
32150
  isOwn: msg.from_agent === agent
@@ -32001,11 +32154,9 @@ function ChatView({ sessionId, agent, participants, onBack }) {
32001
32154
  marginTop: 1,
32002
32155
  children: [
32003
32156
  /* @__PURE__ */ jsxDEV3(Text6, {
32004
- color: "cyan",
32157
+ color: isChannel ? "magenta" : "cyan",
32005
32158
  children: [
32006
- agent,
32007
- " \u2192 ",
32008
- recipient,
32159
+ prompt,
32009
32160
  ": "
32010
32161
  ]
32011
32162
  }, undefined, true, undefined, this),
@@ -32025,37 +32176,46 @@ function ChatView({ sessionId, agent, participants, onBack }) {
32025
32176
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
32026
32177
  function App({ agent }) {
32027
32178
  const { exit } = useApp();
32028
- const [view, setView] = useState5("sessions");
32029
- const [currentSession, setCurrentSession] = useState5(null);
32030
- const [newTo, setNewTo] = useState5("");
32179
+ const [view, setView] = useState6("sessions");
32180
+ const [currentSession, setCurrentSession] = useState6(null);
32181
+ const [currentChannel, setCurrentChannel] = useState6(null);
32182
+ const [newTo, setNewTo] = useState6("");
32031
32183
  useInput5((input, key) => {
32032
32184
  if (input === "q" && view === "sessions") {
32033
32185
  exit();
32034
32186
  }
32187
+ if (key.escape && view === "new") {
32188
+ setNewTo("");
32189
+ setView("sessions");
32190
+ }
32035
32191
  });
32036
32192
  const handleSelectSession = (session) => {
32037
32193
  setCurrentSession(session);
32038
32194
  setView("chat");
32039
32195
  };
32196
+ const handleSelectChannel = (channelName) => {
32197
+ setCurrentChannel(channelName);
32198
+ setView("channel");
32199
+ };
32040
32200
  const handleNewConversation = () => {
32041
32201
  setView("new");
32042
32202
  };
32043
32203
  const handleStartNew = (to) => {
32044
32204
  if (!to.trim())
32045
32205
  return;
32046
- const tempSession = {
32047
- session_id: `${[agent, to.trim()].sort().join("-")}-new`,
32206
+ setCurrentSession({
32207
+ session_id: "",
32048
32208
  participants: [agent, to.trim()],
32049
- last_message_at: new Date().toISOString(),
32209
+ last_message_at: "",
32050
32210
  message_count: 0,
32051
32211
  unread_count: 0
32052
- };
32053
- setCurrentSession(tempSession);
32212
+ });
32054
32213
  setNewTo("");
32055
32214
  setView("chat");
32056
32215
  };
32057
32216
  const handleBack = () => {
32058
32217
  setCurrentSession(null);
32218
+ setCurrentChannel(null);
32059
32219
  setView("sessions");
32060
32220
  };
32061
32221
  if (view === "new") {
@@ -32084,29 +32244,38 @@ function App({ agent }) {
32084
32244
  }, undefined, true, undefined, this),
32085
32245
  /* @__PURE__ */ jsxDEV4(Text7, {
32086
32246
  dimColor: true,
32087
- children: "Press Enter to start, Esc to cancel"
32247
+ children: "Enter to start, Esc to cancel"
32088
32248
  }, undefined, false, undefined, this)
32089
32249
  ]
32090
32250
  }, undefined, true, undefined, this);
32091
32251
  }
32252
+ if (view === "channel" && currentChannel) {
32253
+ return /* @__PURE__ */ jsxDEV4(ChatView, {
32254
+ agent,
32255
+ channelName: currentChannel,
32256
+ onBack: handleBack
32257
+ }, undefined, false, undefined, this);
32258
+ }
32092
32259
  if (view === "chat" && currentSession) {
32260
+ const others = currentSession.participants.filter((p) => p !== agent);
32093
32261
  return /* @__PURE__ */ jsxDEV4(ChatView, {
32094
- sessionId: currentSession.session_id,
32095
32262
  agent,
32096
- participants: currentSession.participants,
32263
+ sessionId: currentSession.session_id || undefined,
32264
+ recipient: others[0] || agent,
32097
32265
  onBack: handleBack
32098
32266
  }, undefined, false, undefined, this);
32099
32267
  }
32100
32268
  return /* @__PURE__ */ jsxDEV4(SessionList, {
32101
32269
  agent,
32102
32270
  onSelect: handleSelectSession,
32271
+ onSelectChannel: handleSelectChannel,
32103
32272
  onNew: handleNewConversation
32104
32273
  }, undefined, false, undefined, this);
32105
32274
  }
32106
32275
 
32107
32276
  // src/cli/index.tsx
32108
32277
  var program2 = new Command;
32109
- program2.name("conversations").description("Real-time CLI messaging for AI agents").version("0.0.4");
32278
+ program2.name("conversations").description("Real-time CLI messaging for AI agents").version("0.0.6");
32110
32279
  program2.command("send").description("Send a message to an agent").argument("<message>", "Message content").requiredOption("--to <agent>", "Recipient agent ID").option("--from <agent>", "Sender agent ID").option("--session <id>", "Session ID (auto-generated if omitted)").option("--priority <level>", "Priority: low, normal, high, urgent", "normal").option("--working-dir <path>", "Working directory context").option("--repository <repo>", "Repository context").option("--branch <branch>", "Branch context").option("--metadata <json>", "JSON metadata string").option("--json", "Output as JSON").action((message, opts) => {
32111
32280
  const from = resolveIdentity(opts.from);
32112
32281
  const metadata = opts.metadata ? JSON.parse(opts.metadata) : undefined;
@@ -32372,8 +32541,12 @@ program2.command("mcp").description("Start MCP server").action(async () => {
32372
32541
  const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
32373
32542
  await startMcpServer2();
32374
32543
  });
32544
+ program2.command("dashboard").description("Start web dashboard").option("--port <port>", "Port to listen on", parseInt).action(async (opts) => {
32545
+ const { startDashboardServer: startDashboardServer2 } = await Promise.resolve().then(() => (init_serve(), exports_serve));
32546
+ startDashboardServer2(opts.port || 3456);
32547
+ });
32375
32548
  program2.action(() => {
32376
32549
  const agent = resolveIdentity();
32377
- render(React7.createElement(App, { agent }));
32550
+ render(React8.createElement(App, { agent }));
32378
32551
  });
32379
32552
  program2.parse();
package/bin/mcp.js CHANGED
@@ -28537,7 +28537,7 @@ function resolveIdentity(explicit) {
28537
28537
  // src/mcp/index.ts
28538
28538
  var server = new McpServer({
28539
28539
  name: "conversations",
28540
- version: "0.0.4"
28540
+ version: "0.0.6"
28541
28541
  });
28542
28542
  server.registerTool("send_message", {
28543
28543
  title: "Send Message",