@three333/termbuddy 0.1.2 → 0.1.3

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/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # TermBuddy
2
+
3
+ 一个跑在终端里的“同频搭子”。你敲键盘,它也知道你在努力;你想专注,它就给你上钟;你想互动,它还能帮你把“礼物”从你这边丢到对面。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g @three333/termbuddy
9
+ ```
10
+
11
+ ## 启动
12
+
13
+ ```bash
14
+ termbuddy
15
+ ```
16
+
17
+ 进入后:
18
+
19
+ - 先取个昵称(直接回车用默认也行)
20
+ - `[1]` 建房(Host):会在局域网里广播房间
21
+ - `[2]` 加入(Join):扫描局域网,选择房间加入
22
+
23
+ 常用按键:
24
+
25
+ - `/` 打开/关闭 AI Console
26
+ - `q` 结束本次陪伴(或在菜单里退出)
27
+ - 扫描页 `b` 返回
28
+ - 倒计时进行中按 `x` 取消
29
+
30
+ ## 核心功能
31
+
32
+ - **局域网组队**:Host 用 UDP 广播房间(`UDP 45888`),客户端扫描后用 TCP 连接同步状态(默认 `TCP 45999`)。
33
+ - **敲键盘状态同步**:本地输入会变成 `TYPING/IDLE`,对面会看到你在不在“认真”。
34
+ - 可选:`TERMBUDDY_ACTIVITY_SOURCE=keyboard` 用全局键盘监听统计活跃(适合你不在这个终端里敲字也想计入活跃的场景)。
35
+ - **专注倒计时**:倒计时会显示成一个小钟表 sprite,并在结束/取消后退出舞台。
36
+ - **互动投掷物**:你可以在你和 buddy 之间投掷物品(例如 `ROSE/POOP/HAMMER`),终端里会看到飞行动画。
37
+ - **小猫气泡**:可以在小猫头上弹出一句话(适合“加油”“别摸鱼”等短提示)。
38
+ - **AI Console(可选)**:按 `/` 召唤一个极简 AI 助手,它可以调用工具帮你:
39
+ - `start_countdown` 开始倒计时
40
+ - `throw_projectile` 投掷互动
41
+ - `show_bubble` 显示气泡
42
+
43
+ ### AI Key(DeepSeek)
44
+
45
+ AI Console 会提示你输入 DeepSeek API Key。当前实现会把 key 存到**你运行 `termbuddy` 的当前目录**下的 `./src/assets/key.json`。
46
+
47
+ 你也可以手动创建:
48
+
49
+ ```json
50
+ {
51
+ "apiKey": "YOUR_DEEPSEEK_API_KEY"
52
+ }
53
+ ```
54
+
55
+ ## 例子(直接对 AI 说)
56
+
57
+ - “倒计时 25 分钟”
58
+ - “扔他一个玫瑰”
59
+ - “在我头上显示气泡:专注 10 分钟”
60
+
package/dist/cli.js CHANGED
@@ -1770,16 +1770,8 @@ function Session(props) {
1770
1770
  }, [props.role, props.localName, roomName, tcp.listenPort]);
1771
1771
  useBroadcaster(broadcasterOptions);
1772
1772
  const localActivity = useActivityMonitor();
1773
- const peers = useMemo8(() => {
1774
- return tcp.peerName ? [
1775
- {
1776
- id: "remote",
1777
- name: tcp.peerName,
1778
- state: tcp.remoteState ?? "OFFLINE"
1779
- }
1780
- ] : [];
1781
- }, [tcp.peerName, tcp.remoteState]);
1782
- const firstPeerName = tcp.peerName;
1773
+ const peers = tcp.peers;
1774
+ const firstPeerName = peers.length > 0 ? peers[0].name : void 0;
1783
1775
  const onToggleAi = useCallback4(() => setShowAi((v) => !v), []);
1784
1776
  const onCloseAi = useCallback4(() => setShowAi(false), []);
1785
1777
  const sessionStartAtRef = useRef4(Date.now());
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/page/MainMenu.tsx","../src/page/NicknamePrompt.tsx","../src/hooks/globalKeyboard.ts","../src/hooks/useActivityMonitor.ts","../src/components/tool/createCountdownTool.ts","../src/components/tool/createBubbleTool.ts","../src/components/tool/createInteractionTool.ts","../src/components/tool/createSessionInfoTool.ts","../src/components/tool/index.ts","../src/hooks/useAiAgent.ts","../src/constants.ts","../src/net/broadcast.ts","../src/net/index.ts","../src/hooks/useBroadcaster.ts","../src/hooks/useScanner.ts","../src/hooks/useTcpSync.ts","../src/hooks/index.ts","../src/page/RoomScanner.tsx","../src/page/LeavePage.tsx","../src/storage/apiKey.ts","../src/components/AiConsole.tsx","../src/components/sprite/BubbleSprite.tsx","../src/components/sprite/BuddyAvatar.tsx","../src/components/sprite/CountdownClockSprite.tsx","../src/components/sprite/ProjectileThrowSprite.tsx","../src/components/StatusHeader.tsx","../src/components/index.ts","../src/page/Session.tsx","../src/page/index.ts","../src/app/App.tsx","../src/app/index.ts","../src/cli.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text, useInput } from \"ink\";\n\nexport function MainMenu(props: {\n onHost: () => void;\n onJoin: () => void;\n onExit: () => void;\n}) {\n useInput((input, key) => {\n if (key.escape || input === \"q\") props.onExit();\n if (input === \"1\") props.onHost();\n if (input === \"2\") props.onJoin();\n });\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text>\n {String.raw`\n████████╗███████╗██████╗ ███╗ ███╗██████╗ ██╗ ██╗██████╗ ██████╗ ██╗ ██╗\n╚══██╔══╝██╔════╝██╔══██╗████╗ ████║██╔══██╗██║ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝\n ██║ █████╗ ██████╔╝██╔████╔██║██████╔╝██║ ██║██║ ██║██║ ██║ ╚████╔╝ \n ██║ ██╔══╝ ██╔══██╗██║╚██╔╝██║██╔══██╗██║ ██║██║ ██║██║ ██║ ╚██╔╝ \n ██║ ███████╗██║ ██║██║ ╚═╝ ██║██████╔╝╚██████╔╝██████╔╝██████╔╝ ██║ \n ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ \n`}\n </Text>\n <Box flexDirection=\"column\" marginTop={1}>\n <Text>Terminal Body Doubling — 极简 / 极客 / 私密</Text>\n <Text> </Text>\n <Text>\n <Text color=\"cyan\">[1]</Text> 建房 (Host)\n </Text>\n <Text>\n <Text color=\"cyan\">[2]</Text> 加入 (Join)\n </Text>\n <Text>\n <Text color=\"cyan\">[q]</Text> 退出\n </Text>\n </Box>\n </Box>\n );\n}\n","import React, { useMemo, useState } from \"react\";\nimport os from \"node:os\";\nimport { Box, Text, useInput } from \"ink\";\n\nfunction defaultNick(): string {\n try {\n return os.userInfo().username || os.hostname();\n } catch {\n return os.hostname();\n }\n}\n\nexport function NicknamePrompt(props: {\n onSubmit: (nickname: string) => void;\n onExit: () => void;\n}) {\n const initial = useMemo(() => defaultNick(), []);\n const [nickname, setNickname] = useState(initial);\n const [touched, setTouched] = useState(false);\n\n useInput((input, key) => {\n if (key.escape) props.onExit();\n\n if (key.return) {\n const name = nickname.trim();\n if (!name) return;\n props.onSubmit(name);\n return;\n }\n\n if (key.backspace || key.delete) {\n setTouched(true);\n setNickname((v) => v.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (!input) return;\n if (input === \"\\t\") return;\n\n setTouched(true);\n setNickname((v) => v + input);\n });\n\n const hint = touched ? \"\" : \" (回车确认,可直接用默认值)\";\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"gray\">欢迎来到 TermBuddy</Text>\n <Box marginTop={1}>\n <Text>\n 请输入你的昵称:<Text color=\"cyan\">{nickname || \"\"}</Text>\n <Text color=\"gray\">{hint}</Text>\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\">按 Esc 退出。</Text>\n </Box>\n </Box>\n );\n}\n\n","import { spawn } from \"node:child_process\";\n\nexport type GlobalKeyboardBackend = \"uiohook\" | \"xinput\";\n\ntype Listener = () => void;\n\nlet backend: GlobalKeyboardBackend | null = null;\nlet started = false;\nlet starting: Promise<GlobalKeyboardBackend | null> | null = null;\nlet stopBackend: (() => void) | null = null;\n\nconst listeners = new Set<Listener>();\n\nfunction emitKeydown() {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // ignore\n }\n }\n}\n\nasync function tryStartUiohook(): Promise<GlobalKeyboardBackend | null> {\n try {\n const mod = (await import(\"uiohook-napi\")) as unknown as {\n uIOhook?: {\n on: (event: \"keydown\", listener: () => void) => unknown;\n removeListener?: (event: \"keydown\", listener: () => void) => unknown;\n start: () => void;\n stop: () => void;\n };\n default?: { uIOhook?: unknown };\n };\n\n const uIOhook =\n mod.uIOhook ??\n ((mod.default as { uIOhook?: unknown } | undefined)?.uIOhook as\n | {\n on: (event: \"keydown\", listener: () => void) => unknown;\n removeListener?: (event: \"keydown\", listener: () => void) => unknown;\n start: () => void;\n stop: () => void;\n }\n | undefined);\n if (!uIOhook) return null;\n\n const onKeydown = () => emitKeydown();\n uIOhook.on(\"keydown\", onKeydown);\n uIOhook.start();\n\n stopBackend = () => {\n uIOhook.removeListener?.(\"keydown\", onKeydown);\n uIOhook.stop();\n };\n\n return \"uiohook\";\n } catch {\n return null;\n }\n}\n\nfunction tryStartXinput(): Promise<GlobalKeyboardBackend | null> {\n if (process.platform !== \"linux\") return Promise.resolve(null);\n if (!process.env.DISPLAY) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n let resolved = false;\n const child = spawn(\"xinput\", [\"test-xi2\", \"--root\"], {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n\n const resolveOnce = (value: GlobalKeyboardBackend | null) => {\n if (resolved) return;\n resolved = true;\n resolve(value);\n };\n\n child.once(\"error\", () => {\n resolveOnce(null);\n });\n\n // If we got here, treat it as started; parsing may continue.\n resolveOnce(\"xinput\");\n\n let buf = \"\";\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n if (/KeyPress/.test(line)) emitKeydown();\n }\n });\n\n stopBackend = () => {\n child.stdout?.removeAllListeners();\n child.removeAllListeners();\n child.kill();\n };\n });\n}\n\nexport async function ensureGlobalKeyboard(): Promise<GlobalKeyboardBackend | null> {\n if (started) return backend;\n if (starting) return starting;\n\n starting = (async () => {\n const uiohook = await tryStartUiohook();\n if (uiohook) return uiohook;\n return await tryStartXinput();\n })();\n\n backend = await starting;\n started = backend !== null;\n if (!started) stopBackend = null;\n starting = null;\n\n return backend;\n}\n\nfunction stopIfIdle() {\n if (listeners.size > 0) return;\n if (!started) return;\n started = false;\n backend = null;\n const stop = stopBackend;\n stopBackend = null;\n try {\n stop?.();\n } catch {\n // ignore\n }\n}\n\nexport function subscribeGlobalKeydown(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n stopIfIdle();\n };\n}\n\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useInput } from \"ink\";\nimport type { ActivityState } from \"../protocol.js\";\nimport {\n ensureGlobalKeyboard,\n subscribeGlobalKeydown,\n} from \"./globalKeyboard.js\";\n\nexport function useActivityMonitor(options?: {\n idleAfterMs?: number;\n source?: \"ink\" | \"keyboard\";\n}): {\n state: ActivityState;\n} {\n const idleAfterMs = options?.idleAfterMs ?? 1500;\n const [state, setState] = useState<ActivityState>(\"IDLE\");\n\n const lastActivityRef = useRef<number>(Date.now());\n\n const markActive = useCallback(() => {\n lastActivityRef.current = Date.now();\n setState(\"TYPING\");\n }, []);\n\n useInput(() => {\n markActive();\n });\n\n // Optional global keyboard activity.\n useEffect(() => {\n const rawSource =\n options?.source ?? process.env.TERMBUDDY_ACTIVITY_SOURCE ?? \"ink\";\n\n // Back-compat: previous env value.\n const source = rawSource === \"xinput\" ? \"keyboard\" : rawSource;\n if (source !== \"keyboard\") return;\n\n let cancelled = false;\n let unsub: (() => void) | null = null;\n void (async () => {\n const ok = await ensureGlobalKeyboard();\n if (cancelled) return;\n if (!ok) return;\n unsub = subscribeGlobalKeydown(markActive);\n })();\n\n return () => {\n cancelled = true;\n unsub?.();\n };\n }, [markActive, options?.source]);\n\n useEffect(() => {\n const id = setInterval(() => {\n const delta = Date.now() - lastActivityRef.current;\n if (delta >= idleAfterMs) setState(\"IDLE\");\n }, 200);\n return () => clearInterval(id);\n }, [idleAfterMs]);\n\n return { state };\n}\n","import { tool } from \"langchain\";\n\nexport function createCountdownTool(options: {\n onStartCountdown?: (minutes: number) => void;\n}) {\n return tool(\n async (input: { minutes: number }) => {\n const minutes = Number(input.minutes);\n if (!Number.isFinite(minutes) || minutes <= 0) return \"倒计时分钟数无效。\";\n options.onStartCountdown?.(minutes);\n return `已开始倒计时 ${minutes} 分钟。`;\n },\n {\n name: \"start_countdown\",\n description: \"开始一个专注倒计时(分钟)。\",\n schema: {\n type: \"object\",\n properties: {\n minutes: {\n type: \"integer\",\n minimum: 1,\n maximum: 180,\n description: \"倒计时分钟数\",\n },\n },\n required: [\"minutes\"],\n additionalProperties: false,\n },\n }\n );\n}\n\n","import { tool } from \"langchain\";\n\nexport type BubbleTarget = \"local\" | \"buddy\";\n\nexport function createBubbleTool(options: {\n onShowBubble?: (args: {\n text: string;\n target: BubbleTarget;\n durationMs: number;\n }) => void;\n}) {\n return tool(\n async (input: { text?: string; target?: BubbleTarget; durationMs?: number }) => {\n const text = String(input.text ?? \"\").trim();\n if (!text) return \"气泡内容为空。\";\n\n const target: BubbleTarget =\n input.target === \"buddy\" || input.target === \"local\"\n ? input.target\n : \"local\";\n\n const durationRaw = Number(input.durationMs ?? 2500);\n const durationMs =\n Number.isFinite(durationRaw) && durationRaw > 0\n ? Math.min(15_000, Math.max(300, Math.floor(durationRaw)))\n : 2500;\n\n options.onShowBubble?.({ text, target, durationMs });\n return `已显示气泡:${text}`;\n },\n {\n name: \"show_bubble\",\n description: \"在小猫头像上显示一个气泡(短消息提示)。\",\n schema: {\n type: \"object\",\n properties: {\n text: {\n type: \"string\",\n minLength: 1,\n maxLength: 120,\n description: \"气泡里的文字\",\n },\n target: {\n type: \"string\",\n enum: [\"local\", \"buddy\"],\n description: \"显示在哪一侧的小猫上(local=我,buddy=同桌)\",\n },\n durationMs: {\n type: \"integer\",\n minimum: 300,\n maximum: 15000,\n description: \"显示时长(毫秒,可选)\",\n },\n },\n required: [\"text\"],\n additionalProperties: false,\n },\n }\n );\n}\n\n","import { tool } from \"langchain\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../sprite/ProjectileThrowSprite.js\";\n\nconst KIND_ALIASES: Array<{ kind: ProjectileKind; keys: string[] }> = [\n { kind: \"ROSE\", keys: [\"rose\", \"花\", \"玫瑰\", \"🌹\", \"love\"] },\n { kind: \"POOP\", keys: [\"poop\", \"屎\", \"💩\", \"大便\"] },\n { kind: \"HAMMER\", keys: [\"hammer\", \"锤\", \"🔨\", \"敲\", \"打\"] },\n];\n\nfunction normalizeKind(raw: unknown): ProjectileKind | null {\n if (typeof raw !== \"string\") return null;\n const upper = raw.toUpperCase().trim();\n if (upper === \"ROSE\" || upper === \"POOP\" || upper === \"HAMMER\") return upper;\n\n const lower = raw.toLowerCase();\n for (const item of KIND_ALIASES) {\n if (item.keys.some((k) => lower.includes(k))) return item.kind;\n }\n return null;\n}\n\nfunction normalizeDirection(raw: unknown): ProjectileDirection | null {\n if (typeof raw !== \"string\") return null;\n const upper = raw.toUpperCase().trim();\n if (upper === \"LEFT_TO_RIGHT\" || upper === \"RIGHT_TO_LEFT\") return upper;\n return null;\n}\n\nexport function createInteractionTool(options: {\n onThrow?: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n}) {\n return tool(\n async (input: { kind?: string; direction?: string; message?: string }) => {\n const kind = normalizeKind(input.kind ?? \"\") ?? \"ROSE\";\n const direction = normalizeDirection(input.direction) ?? \"LEFT_TO_RIGHT\";\n options.onThrow?.(kind, direction);\n const msg = (input.message ?? \"\").trim();\n return msg ? `已投掷 ${kind}:${msg}` : `已投掷 ${kind}。`;\n },\n {\n name: \"throw_projectile\",\n description: \"和同桌互动:投掷一个小物品(🌹/💩/🔨)。\",\n schema: {\n type: \"object\",\n properties: {\n kind: {\n type: \"string\",\n description:\n \"投掷物类型(ROSE/POOP/HAMMER,或任意描述如“玫瑰/锤子/💩”)\",\n },\n direction: {\n type: \"string\",\n enum: [\"LEFT_TO_RIGHT\", \"RIGHT_TO_LEFT\"],\n description: \"飞行方向\",\n },\n message: { type: \"string\", description: \"附带一句话(可选)\" },\n },\n required: [],\n additionalProperties: false,\n },\n }\n );\n}\n","import { tool } from \"langchain\";\n\nexport function createSessionInfoTool(options: {\n localName: string;\n peerName: string;\n}) {\n return tool(\n async () => {\n return JSON.stringify(\n {\n localName: options.localName,\n peerName: options.peerName,\n },\n null,\n 2\n );\n },\n {\n name: \"session_info\",\n description: \"获取当前会话上下文(本地昵称、同桌昵称)。\",\n schema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n }\n );\n}\n\n","export { createCountdownTool } from \"./createCountdownTool.js\";\nexport { createBubbleTool } from \"./createBubbleTool.js\";\nexport { createInteractionTool } from \"./createInteractionTool.js\";\nexport { createSessionInfoTool } from \"./createSessionInfoTool.js\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createAgent } from \"langchain\";\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport {\n createBubbleTool,\n createCountdownTool,\n createInteractionTool,\n createSessionInfoTool,\n} from \"../components/tool/index.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../components/sprite/ProjectileThrowSprite.js\";\ntype LineKind = \"user\" | \"ai\" | \"system\";\nexport type AiLine = { kind: LineKind; text: string; at: number };\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!content) return \"\";\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (typeof part === \"string\") return part;\n if (typeof part === \"object\" && part && \"text\" in part)\n return String((part as any).text ?? \"\");\n return \"\";\n })\n .join(\"\");\n }\n if (typeof content === \"object\" && \"text\" in (content as any))\n return String((content as any).text ?? \"\");\n return String(content);\n}\n\nfunction lastAiText(messages: unknown[]): string | null {\n for (let i = messages.length - 1; i >= 0; i--) {\n const m: any = messages[i];\n const type =\n typeof m?.getType === \"function\"\n ? m.getType()\n : typeof m?._getType === \"function\"\n ? m._getType()\n : m?.type;\n if (type === \"ai\") {\n const t = contentToText(m?.content);\n return t || \"\";\n }\n }\n return null;\n}\n\nfunction createSystemPrompt(context: { localName: string; peerName: string }) {\n return [\n \"你是 TermBuddy 里的“壳中幽灵 (Ghost in the Shell)”。\",\n \"默认隐形;被 / 唤醒时出现。风格:极简、干练、少废话。\",\n \"你可以使用工具来操控应用功能(例如倒计时)。\",\n \"如果用户提到“倒计时/专注/计时/countdown”,优先调用 start_countdown。\",\n \"如果用户提到“气泡/泡泡/提示/说一句”,优先调用 show_bubble。\",\n \"如果用户提到“互动/扔/投掷/throw”,优先调用 throw_projectile。\",\n \"当用户明确要求投掷 N 次且 1<=N<=100 时,必须按 N 执行:重复调用 throw_projectile 共 N 次,不要改成“示意/少量几次”。超过 100 则分批多次调用。\",\n `当前上下文:我叫 ${context.localName};同桌叫 ${context.peerName}。`,\n ].join(\"\\n\");\n}\n\nexport function useAiAgent(options: {\n localName: string;\n peerName: string;\n onStartCountdown?: (minutes: number) => void;\n onShowBubble?: (args: {\n text: string;\n target: \"local\" | \"buddy\";\n durationMs: number;\n }) => void;\n onThrowProjectile?: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n apiKey?: string;\n}) {\n const [lines, setLines] = useState<AiLine[]>([]);\n const [busy, setBusy] = useState(false);\n const [apiKeyError, setApiKeyError] = useState(false);\n\n const agentRef = useRef<Awaited<ReturnType<typeof createAgent>> | null>(null);\n const agentInitRef = useRef<Promise<\n Awaited<ReturnType<typeof createAgent>>\n > | null>(null);\n const agentKeyRef = useRef<string | null>(null);\n const stateRef = useRef<{ messages: unknown[] }>({ messages: [] });\n const abortRef = useRef<AbortController | null>(null);\n\n const append = useCallback((line: AiLine) => {\n setLines((prev) => [...prev, line]);\n }, []);\n\n const updateLine = useCallback((at: number, text: string) => {\n setLines((prev) => {\n const idx = prev.findIndex((l) => l.at === at);\n if (idx === -1) return prev;\n const next = [...prev];\n next[idx] = { ...next[idx], text };\n return next;\n });\n }, []);\n\n const ensureAgent = useCallback(async () => {\n const apiKey = (options.apiKey ?? \"\").trim();\n if (!apiKey) throw new Error(\"missing_api_key\");\n\n if (agentRef.current && agentKeyRef.current === apiKey)\n return agentRef.current;\n\n agentRef.current = null;\n agentInitRef.current = null;\n agentKeyRef.current = apiKey;\n stateRef.current.messages = [];\n\n agentInitRef.current ??= (async () => {\n const startCountdown = createCountdownTool({\n onStartCountdown: options.onStartCountdown,\n });\n\n const showBubble = createBubbleTool({\n onShowBubble: options.onShowBubble,\n });\n\n const sessionInfo = createSessionInfoTool({\n localName: options.localName,\n peerName: options.peerName,\n });\n\n const interaction = createInteractionTool({\n onThrow: options.onThrowProjectile,\n });\n\n const llm = new ChatOpenAI({\n model: \"deepseek-chat\",\n configuration: {\n baseURL: \"https://api.deepseek.com\",\n },\n apiKey: apiKey,\n temperature: 0.1,\n maxTokens: 1000,\n timeout: 30000,\n });\n return createAgent({\n model: llm,\n tools: [startCountdown, showBubble, interaction, sessionInfo],\n systemPrompt: createSystemPrompt({\n localName: options.localName,\n peerName: options.peerName,\n }),\n name: \"ghost\",\n });\n })();\n\n agentRef.current = await agentInitRef.current;\n return agentRef.current;\n }, [\n options.apiKey,\n options.localName,\n options.onStartCountdown,\n options.onShowBubble,\n options.onThrowProjectile,\n options.peerName,\n ]);\n\n const ask = useCallback(\n async (text: string) => {\n const userAt = Date.now();\n const aiAt = userAt + 1;\n const toolAt = userAt + 2;\n setLines([\n { kind: \"user\", text: `> ${text}`, at: userAt },\n { kind: \"ai\", text: \"…\", at: aiAt },\n { kind: \"system\", text: \"\", at: toolAt },\n ]);\n\n abortRef.current?.abort();\n abortRef.current = new AbortController();\n\n setBusy(true);\n try {\n const agent = await ensureAgent();\n const stream = await agent.stream(\n {\n messages: [{ role: \"user\", content: text }],\n },\n {\n streamMode: \"values\",\n signal: abortRef.current.signal,\n } as any\n );\n\n for await (const chunk of stream as any) {\n const messages = (chunk?.messages ?? []) as unknown[];\n if (messages.length > 0) stateRef.current.messages = messages;\n\n const latest: any = messages.at(-1);\n if (latest?.tool_calls?.length) {\n const names = latest.tool_calls\n .map((tc: any) => tc?.name)\n .filter(Boolean)\n .join(\", \");\n if (names) updateLine(toolAt, `Calling tools: ${names}`);\n continue;\n }\n\n const t = lastAiText(messages);\n if (t !== null) updateLine(aiAt, t);\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n const isApiKeyError =\n msg === \"missing_api_key\" ||\n msg.includes(\"401\") ||\n msg.includes(\"403\") ||\n msg.includes(\"Unauthorized\") ||\n msg.includes(\"Invalid API\");\n\n if (isApiKeyError) {\n setApiKeyError(true);\n updateLine(aiAt, \"API Key 错误或失效,请重新输入(按 R 键)\");\n } else {\n updateLine(aiAt, `(AI 出错)${msg}`);\n }\n } finally {\n setBusy(false);\n }\n },\n [append, ensureAgent, updateLine]\n );\n\n const resetApiKeyError = useCallback(() => {\n setApiKeyError(false);\n }, []);\n\n useEffect(() => {\n return () => abortRef.current?.abort();\n }, []);\n\n return { lines, ask, busy, apiKeyError, resetApiKeyError };\n}\n","export const UDP_PORT = 45888;\nexport const TCP_DEFAULT_PORT = 45999;\n\nexport const DISCOVERY_VERSION = 1;\nexport const APP_NAME = 'TermBuddy';\n","import os from \"node:os\";\n\nfunction ipv4ToInt(ip: string) {\n return ip\n .split(\".\")\n .map((n) => Number.parseInt(n, 10))\n .reduce((acc, n) => ((acc << 8) | (n & 255)) >>> 0, 0);\n}\n\nfunction intToIpv4(n: number) {\n return [24, 16, 8, 0].map((shift) => String((n >>> shift) & 255)).join(\".\");\n}\n\nexport function getBroadcastTargets(): string[] {\n const out = new Set<string>([\"255.255.255.255\"]);\n\n const ifaces = os.networkInterfaces();\n for (const entries of Object.values(ifaces)) {\n if (!entries) continue;\n for (const e of entries) {\n if (e.family !== \"IPv4\") continue;\n if (e.internal) continue;\n if (!e.address || !e.netmask) continue;\n const ip = ipv4ToInt(e.address);\n const mask = ipv4ToInt(e.netmask);\n const broadcast = (ip | (~mask >>> 0)) >>> 0;\n out.add(intToIpv4(broadcast));\n }\n }\n\n return [...out];\n}\n","export { getBroadcastTargets } from \"./broadcast.js\";\n","import { useEffect } from \"react\";\nimport dgram from \"node:dgram\";\nimport { UDP_PORT, DISCOVERY_VERSION } from \"../constants.js\";\nimport type { DiscoveryPacket } from \"../protocol.js\";\nimport { getBroadcastTargets } from \"../net/index.js\";\n\ntype Options =\n | { enabled: false }\n | {\n enabled: true;\n hostName: string;\n roomName: string;\n tcpPort?: number | null;\n intervalMs?: number;\n };\n\nexport function useBroadcaster(options: Options) {\n const depKey = options.enabled\n ? `${options.hostName}|${options.roomName}|${options.tcpPort ?? \"\"}|${\n options.intervalMs ?? 1000\n }`\n : \"disabled\";\n\n useEffect(() => {\n if (!options.enabled) return;\n if (!options.tcpPort) return;\n\n const socket = dgram.createSocket(\"udp4\");\n socket.on(\"error\", () => {});\n\n socket.bind(() => {\n socket.setBroadcast(true);\n });\n\n const targets = getBroadcastTargets();\n\n const send = () => {\n const packet: DiscoveryPacket = {\n type: \"termbuddy_discovery\",\n version: DISCOVERY_VERSION,\n hostName: options.hostName,\n roomName: options.roomName,\n tcpPort: options.tcpPort!,\n sentAt: Date.now(),\n };\n const msg = Buffer.from(JSON.stringify(packet));\n for (const address of targets) {\n socket.send(msg, UDP_PORT, address);\n }\n };\n\n send();\n const id = setInterval(send, options.intervalMs ?? 1000);\n\n return () => {\n clearInterval(id);\n socket.close();\n };\n }, [depKey]);\n}\n","import { useEffect, useState } from \"react\";\nimport dgram from \"node:dgram\";\nimport { UDP_PORT, DISCOVERY_VERSION } from \"../constants.js\";\nimport type { DiscoveryPacket } from \"../protocol.js\";\nimport type { DiscoveredRoom } from \"../types.js\";\n\nfunction safeParse(msg: Buffer): DiscoveryPacket | null {\n try {\n const parsed = JSON.parse(msg.toString(\"utf8\")) as DiscoveryPacket;\n if (parsed?.type !== \"termbuddy_discovery\") return null;\n if (parsed?.version !== DISCOVERY_VERSION) return null;\n if (!parsed.hostName || !parsed.roomName || !parsed.tcpPort) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function useScanner(options?: {\n staleAfterMs?: number;\n}): DiscoveredRoom[] {\n const staleAfterMs = options?.staleAfterMs ?? 3500;\n const [rooms, setRooms] = useState<DiscoveredRoom[]>([]);\n\n useEffect(() => {\n const socket = dgram.createSocket(\"udp4\");\n socket.on(\"error\", () => {});\n\n socket.on(\"message\", (msg, rinfo) => {\n const packet = safeParse(msg);\n if (!packet) return;\n\n const now = Date.now();\n setRooms((prev) => {\n const key = `${rinfo.address}:${packet.tcpPort}`;\n const next = prev.filter((r) => `${r.ip}:${r.tcpPort}` !== key);\n next.push({\n ip: rinfo.address,\n hostName: packet.hostName,\n roomName: packet.roomName,\n tcpPort: packet.tcpPort,\n lastSeenAt: now,\n });\n return next;\n });\n });\n\n socket.bind(UDP_PORT, () => {});\n\n const prune = setInterval(() => {\n const now = Date.now();\n setRooms((prev) =>\n prev.filter((r) => now - r.lastSeenAt <= staleAfterMs)\n );\n }, 500);\n\n return () => {\n clearInterval(prune);\n socket.close();\n };\n }, [staleAfterMs]);\n\n return rooms;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport net from \"node:net\";\nimport type {\n ActivityState,\n ConnectionStatus,\n TcpPacket,\n ProjectileKind,\n ProjectileDirection,\n Peer,\n} from \"../protocol.js\";\nimport { TCP_DEFAULT_PORT } from \"../constants.js\";\n\ntype HostOptions = { role: \"host\"; localName: string; port?: number };\ntype ClientOptions = {\n role: \"client\";\n localName: string;\n hostIp: string;\n tcpPort: number;\n hostName?: string;\n};\ntype Options = HostOptions | ClientOptions;\n\nfunction writePacket(socket: net.Socket, packet: TcpPacket) {\n socket.write(`${JSON.stringify(packet)}\\n`, \"utf8\");\n}\n\ntype PeerConnection = {\n id: string;\n socket: net.Socket;\n name: string;\n state: ActivityState;\n lastSeen: number;\n heartbeatInterval: NodeJS.Timeout | null;\n};\n\nexport function useTcpSync(options: Options): {\n status: ConnectionStatus;\n listenPort?: number;\n peers: Peer[];\n peerName?: string; // For backward compatibility (first peer name)\n remoteState?: ActivityState; // For backward compatibility (first peer state)\n sendStatus: (state: ActivityState) => void;\n sendProjectile: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n setOnRemoteProjectile: (callback: (kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) => void;\n} {\n const [status, setStatus] = useState<ConnectionStatus>(\n options.role === \"host\" ? \"waiting\" : \"connecting\"\n );\n const [listenPort, setListenPort] = useState<number | undefined>(undefined);\n const [peers, setPeers] = useState<Peer[]>([]);\n\n const onRemoteProjectileRef = useRef<((kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) | undefined>(undefined);\n\n // For host: map of all peer connections\n const peerConnectionsRef = useRef<Map<string, PeerConnection>>(new Map());\n // For client: single socket ref\n const clientSocketRef = useRef<net.Socket | null>(null);\n const clientHeartbeatRef = useRef<NodeJS.Timeout | null>(null);\n const clientLastSeenRef = useRef<number>(Date.now());\n\n // Generate unique peer ID\n const generatePeerId = () => `peer_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n // Broadcast packet to all peers (host only)\n const broadcastPacket = useCallback((packet: TcpPacket, excludeId?: string) => {\n peerConnectionsRef.current.forEach((peer, id) => {\n if (id !== excludeId && !peer.socket.destroyed) {\n writePacket(peer.socket, packet);\n }\n });\n }, []);\n\n // Update peers state from connections map\n const syncPeersState = useCallback(() => {\n const peerList: Peer[] = [];\n peerConnectionsRef.current.forEach((conn) => {\n peerList.push({ id: conn.id, name: conn.name, state: conn.state });\n });\n setPeers(peerList);\n\n // Update status based on peer count\n if (options.role === \"host\") {\n setStatus(peerList.length > 0 ? \"connected\" : \"waiting\");\n }\n }, [options.role]);\n\n // Remove a peer connection (host only)\n const removePeerConnection = useCallback((peerId: string) => {\n const conn = peerConnectionsRef.current.get(peerId);\n if (conn) {\n if (conn.heartbeatInterval) clearInterval(conn.heartbeatInterval);\n if (!conn.socket.destroyed) conn.socket.destroy();\n\n // Notify other peers about the left peer\n broadcastPacket({ type: \"peer_left\", peerName: conn.name, sentAt: Date.now() }, peerId);\n\n peerConnectionsRef.current.delete(peerId);\n syncPeersState();\n }\n }, [broadcastPacket, syncPeersState]);\n\n // Attach a new peer socket (host only)\n const attachPeerSocket = useCallback((socket: net.Socket) => {\n const peerId = generatePeerId();\n let buf = \"\";\n\n socket.setNoDelay(true);\n socket.setEncoding(\"utf8\");\n\n const conn: PeerConnection = {\n id: peerId,\n socket,\n name: \"Connecting...\",\n state: \"IDLE\",\n lastSeen: Date.now(),\n heartbeatInterval: null,\n };\n\n peerConnectionsRef.current.set(peerId, conn);\n\n socket.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n\n try {\n const packet = JSON.parse(line) as TcpPacket;\n conn.lastSeen = Date.now();\n\n if (packet.type === \"hello\") {\n conn.name = packet.clientName;\n syncPeersState();\n\n // Send hello back\n writePacket(socket, {\n type: \"hello\",\n hostName: options.localName,\n clientName: \"Host\",\n sentAt: Date.now(),\n });\n\n // Notify other peers about new peer\n broadcastPacket({ type: \"peer_joined\", peerName: conn.name, sentAt: Date.now() }, peerId);\n\n // Send list of existing peers to new peer\n peerConnectionsRef.current.forEach((existingConn, existingId) => {\n if (existingId !== peerId && existingConn.name !== \"Connecting...\") {\n writePacket(socket, { type: \"peer_joined\", peerName: existingConn.name, sentAt: Date.now() });\n }\n });\n }\n\n if (packet.type === \"status\") {\n conn.state = packet.state;\n syncPeersState();\n // Broadcast status to other peers\n broadcastPacket({ ...packet, senderName: conn.name }, peerId);\n }\n\n if (packet.type === \"ping\") {\n writePacket(socket, { type: \"pong\", sentAt: Date.now() });\n }\n\n if (packet.type === \"projectile\") {\n // Call local handler\n onRemoteProjectileRef.current?.(packet.kind, packet.direction, conn.name);\n // Broadcast to other peers\n broadcastPacket({ ...packet, senderName: conn.name }, peerId);\n }\n } catch {\n // ignore parse errors\n }\n }\n });\n\n socket.on(\"close\", () => {\n removePeerConnection(peerId);\n });\n\n socket.on(\"error\", () => {\n removePeerConnection(peerId);\n });\n\n // Heartbeat for this peer\n conn.heartbeatInterval = setInterval(() => {\n if (socket.destroyed) {\n removePeerConnection(peerId);\n return;\n }\n writePacket(socket, { type: \"ping\", sentAt: Date.now() });\n const age = Date.now() - conn.lastSeen;\n if (age > 6000) {\n removePeerConnection(peerId);\n }\n }, 2000);\n\n syncPeersState();\n }, [options.localName, broadcastPacket, syncPeersState, removePeerConnection]);\n\n // Client socket cleanup\n const cleanupClientSocket = useCallback(() => {\n if (clientHeartbeatRef.current) clearInterval(clientHeartbeatRef.current);\n clientHeartbeatRef.current = null;\n\n const s = clientSocketRef.current;\n clientSocketRef.current = null;\n if (s && !s.destroyed) s.destroy();\n }, []);\n\n // Attach client socket\n const attachClientSocket = useCallback((socket: net.Socket) => {\n cleanupClientSocket();\n clientSocketRef.current = socket;\n clientLastSeenRef.current = Date.now();\n\n setStatus(\"connected\");\n\n let buf = \"\";\n socket.setNoDelay(true);\n socket.setEncoding(\"utf8\");\n\n socket.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n\n try {\n const packet = JSON.parse(line) as TcpPacket;\n clientLastSeenRef.current = Date.now();\n\n if (packet.type === \"hello\") {\n // Host connected - add host as first peer\n setPeers((prev) => {\n const hostExists = prev.some((p) => p.id === \"host\");\n if (hostExists) return prev;\n return [{ id: \"host\", name: packet.hostName, state: \"IDLE\" as ActivityState }, ...prev];\n });\n }\n\n if (packet.type === \"status\") {\n // Update peer's state\n const senderName = packet.senderName;\n if (senderName) {\n setPeers((prev) => prev.map((p) =>\n p.name === senderName ? { ...p, state: packet.state } : p\n ));\n } else {\n // From host\n setPeers((prev) => prev.map((p) =>\n p.id === \"host\" ? { ...p, state: packet.state } : p\n ));\n }\n }\n\n if (packet.type === \"ping\") {\n writePacket(socket, { type: \"pong\", sentAt: Date.now() });\n }\n\n if (packet.type === \"projectile\") {\n onRemoteProjectileRef.current?.(packet.kind, packet.direction, packet.senderName);\n }\n\n if (packet.type === \"peer_joined\") {\n setPeers((prev) => {\n const exists = prev.some((p) => p.name === packet.peerName);\n if (exists) return prev;\n return [...prev, { id: `peer_${Date.now()}`, name: packet.peerName, state: \"IDLE\" as ActivityState }];\n });\n }\n\n if (packet.type === \"peer_left\") {\n setPeers((prev) => prev.filter((p) => p.name !== packet.peerName));\n }\n } catch {\n // ignore\n }\n }\n });\n\n socket.on(\"close\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n cleanupClientSocket();\n });\n\n socket.on(\"error\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n });\n\n // Hello handshake\n writePacket(socket, {\n type: \"hello\",\n hostName: options.role === \"client\" ? options.hostName ?? \"Host\" : options.localName,\n clientName: options.localName,\n sentAt: Date.now(),\n });\n\n // Heartbeat\n clientHeartbeatRef.current = setInterval(() => {\n const sock = clientSocketRef.current;\n if (!sock || sock.destroyed) return;\n writePacket(sock, { type: \"ping\", sentAt: Date.now() });\n const age = Date.now() - clientLastSeenRef.current;\n if (age > 6000) {\n setStatus(\"disconnected\");\n setPeers([]);\n cleanupClientSocket();\n }\n }, 2000);\n }, [cleanupClientSocket, options]);\n\n // Main effect: setup server or client\n useEffect(() => {\n if (options.role === \"host\") {\n const server = net.createServer((socket) => {\n attachPeerSocket(socket);\n });\n\n server.on(\"error\", () => {});\n\n server.listen(options.port ?? TCP_DEFAULT_PORT, () => {\n const address = server.address();\n if (address && typeof address === \"object\") setListenPort(address.port);\n });\n\n return () => {\n // Cleanup all peer connections\n peerConnectionsRef.current.forEach((conn) => {\n if (conn.heartbeatInterval) clearInterval(conn.heartbeatInterval);\n if (!conn.socket.destroyed) conn.socket.destroy();\n });\n peerConnectionsRef.current.clear();\n server.close();\n };\n }\n\n // Client mode\n setStatus(\"connecting\");\n const socket = net.createConnection(\n { host: options.hostIp, port: options.tcpPort },\n () => {\n attachClientSocket(socket);\n }\n );\n socket.on(\"error\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n });\n\n return () => {\n socket.destroy();\n cleanupClientSocket();\n };\n }, [attachPeerSocket, attachClientSocket, cleanupClientSocket, options]);\n\n // Send status to all peers\n const sendStatus = useCallback((state: ActivityState) => {\n if (options.role === \"host\") {\n broadcastPacket({ type: \"status\", state, senderName: options.localName, sentAt: Date.now() });\n } else {\n const socket = clientSocketRef.current;\n if (socket && !socket.destroyed) {\n writePacket(socket, { type: \"status\", state, sentAt: Date.now() });\n }\n }\n }, [options, broadcastPacket]);\n\n // Send projectile to all peers\n const sendProjectile = useCallback((kind: ProjectileKind, direction: ProjectileDirection) => {\n if (options.role === \"host\") {\n broadcastPacket({ type: \"projectile\", kind, direction, senderName: options.localName, sentAt: Date.now() });\n } else {\n const socket = clientSocketRef.current;\n if (socket && !socket.destroyed) {\n writePacket(socket, { type: \"projectile\", kind, direction, sentAt: Date.now() });\n }\n }\n }, [options, broadcastPacket]);\n\n const setOnRemoteProjectile = useCallback((callback: (kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) => {\n onRemoteProjectileRef.current = callback;\n }, []);\n\n // Backward compatibility: first peer\n const firstPeer = peers[0];\n const peerName = firstPeer?.name;\n const remoteState = firstPeer?.state;\n\n return {\n status,\n listenPort,\n peers,\n peerName,\n remoteState,\n sendStatus,\n sendProjectile,\n setOnRemoteProjectile\n };\n}\n","export { useActivityMonitor } from \"./useActivityMonitor.js\";\nexport { useAiAgent } from \"./useAiAgent.js\";\nexport { useBroadcaster } from \"./useBroadcaster.js\";\nexport { useScanner } from \"./useScanner.js\";\nexport { useTcpSync } from \"./useTcpSync.js\";\n","import React, {useMemo} from 'react';\nimport {Box, Text, useInput} from 'ink';\nimport {useScanner} from '../hooks/index.js';\nimport type {DiscoveredRoom} from '../types.js';\n\nexport function RoomScanner(props: {\n\tonSelectRoom: (room: DiscoveredRoom) => void;\n\tonBack: () => void;\n\tonExit: () => void;\n}) {\n\tconst rooms = useScanner();\n\n\tconst sortedRooms = useMemo(() => {\n\t\treturn [...rooms].sort((a, b) => b.lastSeenAt - a.lastSeenAt);\n\t}, [rooms]);\n\n\tuseInput((input, key) => {\n\t\tif (key.escape || input === 'b') props.onBack();\n\t\tif (input === 'q') props.onExit();\n\n\t\tconst index = Number.parseInt(input, 10);\n\t\tif (Number.isNaN(index)) return;\n\t\tconst room = sortedRooms[index - 1];\n\t\tif (!room) return;\n\t\tprops.onSelectRoom(room);\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" padding={1}>\n\t\t\t<Text>\n\t\t\t\t<Text color=\"yellow\">正在扫描局域网...</Text> (按 <Text color=\"cyan\">b</Text> 返回,{' '}\n\t\t\t\t<Text color=\"cyan\">q</Text> 退出)\n\t\t\t</Text>\n\t\t\t<Box flexDirection=\"column\" marginTop={1}>\n\t\t\t\t{sortedRooms.length === 0 ? (\n\t\t\t\t\t<Text color=\"gray\">暂无房间广播。</Text>\n\t\t\t\t) : (\n\t\t\t\t\tsortedRooms.map((room, i) => (\n\t\t\t\t\t\t<Text key={`${room.ip}:${room.tcpPort}`}>\n\t\t\t\t\t\t\t<Text color=\"cyan\">[{i + 1}]</Text> {room.hostName} <Text color=\"gray\">@</Text>{' '}\n\t\t\t\t\t\t\t<Text color=\"gray\">\n\t\t\t\t\t\t\t\t{room.ip}:{room.tcpPort}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t</Box>\n\t);\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { LeaveStats } from \"../types.js\";\n\nfunction formatDuration(ms: number) {\n const totalSeconds = Math.max(0, Math.floor(ms / 1000));\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) return `${hours}小时${minutes}分${seconds}秒`;\n if (minutes > 0) return `${minutes}分${seconds}秒`;\n return `${seconds}秒`;\n}\n\nexport function LeavePage(props: {\n stats: LeaveStats;\n onBack: () => void;\n onExit: () => void;\n}) {\n useInput((input, key) => {\n if (key.escape || input === \"q\") props.onExit();\n if (key.return || input === \" \") props.onBack();\n });\n\n const sessionLabel = useMemo(\n () => formatDuration(props.stats.sessionDurationMs),\n [props.stats.sessionDurationMs]\n );\n const connectedLabel = useMemo(\n () => formatDuration(props.stats.connectedDurationMs),\n [props.stats.connectedDurationMs]\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} alignItems=\"center\">\n {/* <Text color=\"cyan\">\n {String.raw`\n ____ _ _ \n / ___| ___ ___ | | __ _| |_| |\n \\___ \\ / _ \\ _ \\ | | / _' | __| |\n ___) | __/ __/ | |__| (_| | |_|_|\n |____/ \\___|\\___|___|_____\\__,_|\\__(_)\n |_____| \n`}\n </Text> */}\n\n <Box\n flexDirection=\"column\"\n marginTop={1}\n borderStyle=\"round\"\n paddingX={2}\n borderColor=\"gray\"\n >\n <Text color=\"white\" bold>\n {props.stats.peerName\n ? `与 ${props.stats.peerName} 的同频记录`\n : \"本次专注记录\"}\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\" gap={1}>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>⌨️ 键盘敲击</Text>\n <Text color=\"yellow\">{props.stats.keyPresses}</Text>\n </Box>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>⏱️ 总共时长</Text>\n <Text color=\"green\">{sessionLabel}</Text>\n </Box>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>🔗 连线时长</Text>\n <Text color=\"blue\">{connectedLabel}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box marginTop={1}>\n <Text color=\"gray\">\n 按 <Text color=\"white\">Enter</Text> 返回菜单,或{\" \"}\n <Text color=\"red\">q</Text> 退出程序\n </Text>\n </Box>\n </Box>\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\ntype KeyFile = {apiKey?: string};\n\nconst KEY_RELATIVE_PATH = path.join('src', 'assets', 'key.json');\n\nasync function readJsonFile(filePath: string): Promise<KeyFile | null> {\n\ttry {\n\t\tconst raw = await fs.readFile(filePath, 'utf8');\n\t\tconst parsed = JSON.parse(raw) as KeyFile;\n\t\tif (!parsed || typeof parsed !== 'object') return null;\n\t\treturn parsed;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function ensureDirForFile(filePath: string) {\n\tawait fs.mkdir(path.dirname(filePath), {recursive: true});\n}\n\nexport async function loadStoredApiKey(): Promise<string | null> {\n\tconst absolute = path.resolve(process.cwd(), KEY_RELATIVE_PATH);\n\tconst json = await readJsonFile(absolute);\n\tconst key = (json?.apiKey ?? '').trim();\n\treturn key.length > 0 ? key : null;\n}\n\nexport async function saveStoredApiKey(apiKey: string): Promise<void> {\n\tconst trimmed = apiKey.trim();\n\tif (trimmed.length === 0) {\n\t\tthrow new Error('API key cannot be empty');\n\t}\n\tconst absolute = path.resolve(process.cwd(), KEY_RELATIVE_PATH);\n\tawait ensureDirForFile(absolute);\n\tconst payload: KeyFile = {apiKey: trimmed};\n\tawait fs.writeFile(absolute, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n}\n\n","import React, { useEffect, useMemo, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useAiAgent } from \"../hooks/index.js\";\nimport { loadStoredApiKey, saveStoredApiKey } from \"../storage/apiKey.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"./sprite/ProjectileThrowSprite.js\";\n\nexport function AiConsole(props: {\n onClose: () => void;\n onStartCountdown: (minutes: number) => void;\n onShowBubble?: (args: {\n text: string;\n target: \"local\" | \"buddy\";\n durationMs: number;\n }) => void;\n onThrowProjectile: (\n kind: ProjectileKind,\n direction: ProjectileDirection\n ) => void;\n localName: string;\n peerName: string;\n}) {\n const [input, setInput] = useState(\"\");\n const [apiKey, setApiKey] = useState<string | null>(null);\n const [keyDraft, setKeyDraft] = useState(\"\");\n const [cursorOn, setCursorOn] = useState(true);\n const [keyStatus, setKeyStatus] = useState<\n \"loading\" | \"missing\" | \"ready\" | \"saving\"\n >(\"loading\");\n\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n const stored = await loadStoredApiKey();\n if (cancelled) return;\n if (stored) {\n setApiKey(stored);\n setKeyStatus(\"ready\");\n } else {\n setKeyStatus(\"missing\");\n }\n })();\n return () => {\n cancelled = true;\n };\n }, []);\n\n useEffect(() => {\n const handle = setInterval(() => setCursorOn((v) => !v), 500);\n return () => clearInterval(handle);\n }, []);\n\n const agent = useAiAgent({\n localName: props.localName,\n peerName: props.peerName,\n onStartCountdown: props.onStartCountdown,\n onShowBubble: props.onShowBubble,\n onThrowProjectile: props.onThrowProjectile,\n apiKey: apiKey ?? undefined,\n });\n\n const resetApiKey = () => {\n setApiKey(null);\n setKeyDraft(\"\");\n setKeyStatus(\"missing\");\n agent.resetApiKeyError();\n };\n\n const helpLine = useMemo(\n () => \"示例:倒计时20分钟 / 聊会天 / 和别人互动一下\",\n []\n );\n\n useInput(\n (ch, key) => {\n if (key.escape) {\n props.onClose();\n return;\n }\n\n if (agent.apiKeyError && (ch === \"r\" || ch === \"R\")) {\n resetApiKey();\n return;\n }\n\n if (keyStatus !== \"ready\") {\n if (key.return) {\n const draft = keyDraft.trim();\n if (!draft) return;\n setKeyStatus(\"saving\");\n void (async () => {\n await saveStoredApiKey(draft);\n setApiKey(draft);\n setKeyDraft(\"\");\n setKeyStatus(\"ready\");\n })();\n return;\n }\n\n if (key.backspace || key.delete) {\n setKeyDraft((s) => s.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (ch) setKeyDraft((s) => s + ch);\n return;\n }\n\n if (key.return) {\n const line = input.trim();\n setInput(\"\");\n if (!line) return;\n void agent.ask(line);\n return;\n }\n\n if (key.backspace || key.delete) {\n setInput((s) => s.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (ch) setInput((s) => s + ch);\n },\n { isActive: true }\n );\n\n const lines = agent.lines.filter((l) => l.text.trim().length > 0).slice(-6);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" paddingX={1} paddingY={0}>\n <Box justifyContent=\"space-between\" marginBottom={0}>\n <Text color=\"cyan\">AI Console</Text>\n <Text color=\"gray\">\n {keyStatus === \"saving\"\n ? \"Saving…\"\n : agent.apiKeyError\n ? \"Press R to reset API\"\n : agent.busy\n ? \"Thinking…\"\n : \"Esc Close\"}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\">\n {keyStatus === \"loading\" ? (\n <Text color=\"gray\">Checking API Key...</Text>\n ) : keyStatus === \"missing\" || keyStatus === \"saving\" ? (\n <Text color=\"yellow\">\n Setup: Enter DeepSeek API Key (saves to{\" \"}\n <Text color=\"cyan\">src/assets/key.json</Text>)\n </Text>\n ) : lines.length === 0 ? (\n <Text color=\"gray\">{helpLine}</Text>\n ) : null}\n </Box>\n\n <Box flexDirection=\"column\" marginTop={0} minHeight={6}>\n {keyStatus === \"ready\" ? (\n <>\n {lines.map((l, i) => (\n <Text\n key={`${l.kind}:${l.at}:${i}`}\n color={l.kind === \"user\" ? \"yellow\" : \"white\"}\n wrap=\"truncate-end\"\n >\n {l.kind === \"user\" ? \"> \" : \"\"}\n {l.text}\n </Text>\n ))}\n </>\n ) : (\n <Text color=\"gray\">Please enter API Key to proceed.</Text>\n )}\n </Box>\n\n <Box\n marginTop={0}\n borderStyle=\"single\"\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n >\n <Text color=\"green\">{\">\"} </Text>\n {keyStatus === \"ready\" ? (\n <>\n <Text>{input}</Text>\n {cursorOn ? <Text inverse> </Text> : <Text> </Text>}\n </>\n ) : (\n <Text>\n {keyDraft.length === 0\n ? \"\"\n : \"*\".repeat(Math.min(64, keyDraft.length))}\n {cursorOn ? <Text inverse> </Text> : <Text> </Text>}\n </Text>\n )}\n </Box>\n </Box>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\n\nfunction wrapText(text: string, maxWidth: number) {\n const chars = Array.from(text);\n const lines: string[] = [];\n for (let i = 0; i < chars.length; i += maxWidth) {\n lines.push(chars.slice(i, i + maxWidth).join(\"\"));\n }\n return lines.length ? lines : [\"\"];\n}\n\nfunction renderBubbleLines(text: string, maxInnerWidth: number) {\n const contentLines = wrapText(text, maxInnerWidth);\n const innerWidth = Math.min(\n maxInnerWidth,\n Math.max(...contentLines.map((l) => Array.from(l).length), 1)\n );\n\n const top = `╭${\"─\".repeat(innerWidth + 2)}╮`;\n \n // Create a bottom line with a little tail \"v\" in the middle\n const tailPos = Math.floor((innerWidth + 2) / 2);\n const bottomChars = Array.from(`╰${\"─\".repeat(innerWidth + 2)}╯`);\n if (bottomChars[tailPos]) bottomChars[tailPos] = \"v\"; // Simple tail\n const bottom = bottomChars.join(\"\");\n\n const middle = contentLines.map((l) => {\n const pad = innerWidth - Array.from(l).length;\n return `│ ${l}${\" \".repeat(Math.max(0, pad))} │`;\n });\n return [top, ...middle, bottom];\n}\n\nexport function BubbleSprite(props: {\n text: string;\n maxInnerWidth?: number;\n color?: string;\n}) {\n const trimmed = props.text.trim();\n const maxInnerWidth = props.maxInnerWidth ?? 18;\n\n const lines = useMemo(() => {\n if (!trimmed) return null;\n return renderBubbleLines(trimmed, maxInnerWidth);\n }, [maxInnerWidth, trimmed]);\n\n if (!lines) return null;\n\n return (\n <Box flexDirection=\"column\" alignItems=\"center\">\n {lines.map((line, i) => (\n <Text key={`bubble:${i}`} color={props.color ?? \"gray\"}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ActivityState } from \"../../protocol.js\";\nimport { BubbleSprite } from \"./BubbleSprite.js\";\n\nconst SPRITES: Record<\n ActivityState,\n { color?: string; compact: string; frames: string[] }\n> = {\n TYPING: {\n color: \"green\",\n compact: \"( >_<)===3\",\n frames: [\" /\\\\_/\\\\ \", \"( >_<) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n IDLE: {\n color: \"yellow\",\n compact: \"( -.-)Zzz\",\n frames: [\" /\\\\_/\\\\ \", \"( -.-) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n OFFLINE: {\n color: \"gray\",\n compact: \"( x_x)\",\n frames: [\" /\\\\_/\\\\ \", \"( x_x) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n};\n\nexport function BuddyAvatar(props: {\n state: ActivityState;\n variant?: \"frames\" | \"compact\";\n bubbleText?: string | null;\n marginTop?: number;\n}) {\n const sprite = SPRITES[props.state];\n if (props.variant === \"compact\") {\n return (\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n marginTop={props.marginTop ?? 1}\n >\n {props.bubbleText ? <BubbleSprite text={props.bubbleText} /> : null}\n <Text color={sprite.color}>{sprite.compact}</Text>\n </Box>\n );\n }\n\n return (\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n marginTop={props.marginTop ?? 1}\n >\n {props.bubbleText ? <BubbleSprite text={props.bubbleText} /> : null}\n {sprite.frames.map((line, i) => (\n <Text key={`${props.state}:${i}`} color={sprite.color}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport type CountdownClockType = \"SHORT\" | \"MEDIUM\" | \"LONG\";\nexport type CountdownClockVariant = \"FULL\" | \"COMPACT\";\n\nexport function countdownClockTypeFromMinutes(\n minutes: number\n): CountdownClockType {\n if (minutes <= 10) return \"SHORT\";\n if (minutes <= 30) return \"MEDIUM\";\n return \"LONG\";\n}\n\nfunction clamp01(n: number) {\n if (n <= 0) return 0;\n if (n >= 1) return 1;\n return n;\n}\n\nconst TYPE_STYLE: Record<CountdownClockType, { color: string; label: string }> =\n {\n SHORT: { color: \"green\", label: \"Sprint\" },\n MEDIUM: { color: \"cyan\", label: \"Focus\" },\n LONG: { color: \"magenta\", label: \"Deep\" },\n };\n\ntype HandDir = \"N\" | \"NE\" | \"E\" | \"SE\" | \"S\" | \"SW\" | \"W\" | \"NW\";\n\nfunction handFromProgress(progress01: number): HandDir {\n const idx = Math.round(clamp01(progress01) * 7);\n const dirs: HandDir[] = [\"N\", \"NE\", \"E\", \"SE\", \"S\", \"SW\", \"W\", \"NW\"];\n return dirs[idx]!;\n}\n\nfunction renderClockFace(hand: HandDir) {\n const lines = [\n \" .---. \",\n \" / \\\\ \",\n \"| • |\",\n \" \\\\ / \",\n \" '---' \",\n ].map((s) => s.split(\"\"));\n\n const center = { r: 2, c: 4 };\n const handMap: Record<HandDir, { r: number; c: number; ch: string }> = {\n N: { r: 1, c: 4, ch: \"|\" },\n NE: { r: 1, c: 5, ch: \"/\" },\n E: { r: 2, c: 5, ch: \"-\" },\n SE: { r: 3, c: 5, ch: \"\\\\\" },\n S: { r: 3, c: 4, ch: \"|\" },\n SW: { r: 3, c: 3, ch: \"/\" },\n W: { r: 2, c: 3, ch: \"-\" },\n NW: { r: 1, c: 3, ch: \"\\\\\" },\n };\n\n const tip = handMap[hand];\n lines[center.r][center.c] = \"•\";\n lines[tip.r][tip.c] = tip.ch;\n\n return lines.map((row) => row.join(\"\"));\n}\n\nfunction renderCompactClockFace(hand: HandDir) {\n const lines = [\" .---. \", \"| • |\", \" '---' \"].map((s) => s.split(\"\"));\n const center = { r: 1, c: 3 };\n const handMap: Record<HandDir, { r: number; c: number; ch: string }> = {\n N: { r: 0, c: 3, ch: \"|\" },\n NE: { r: 0, c: 4, ch: \"/\" },\n E: { r: 1, c: 5, ch: \"-\" },\n SE: { r: 2, c: 4, ch: \"\\\\\" },\n S: { r: 2, c: 3, ch: \"|\" },\n SW: { r: 2, c: 2, ch: \"/\" },\n W: { r: 1, c: 1, ch: \"-\" },\n NW: { r: 0, c: 2, ch: \"\\\\\" },\n };\n\n const tip = handMap[hand];\n lines[center.r][center.c] = \"•\";\n lines[tip.r][tip.c] = tip.ch;\n\n return lines.map((row) => row.join(\"\"));\n}\n\nexport function CountdownClockSprite(props: {\n type?: CountdownClockType;\n variant?: CountdownClockVariant;\n minutes?: number;\n label?: string | null;\n showLabel?: boolean;\n totalSeconds?: number;\n remainingSeconds?: number | null;\n}) {\n const type =\n props.type ??\n (typeof props.minutes === \"number\"\n ? countdownClockTypeFromMinutes(props.minutes)\n : \"MEDIUM\");\n\n const progress01 = useMemo(() => {\n if (\n typeof props.totalSeconds !== \"number\" ||\n props.totalSeconds <= 0 ||\n props.remainingSeconds === null ||\n typeof props.remainingSeconds !== \"number\"\n ) {\n return null;\n }\n return clamp01(props.remainingSeconds / props.totalSeconds);\n }, [props.remainingSeconds, props.totalSeconds]);\n\n const style = TYPE_STYLE[type];\n const hand = handFromProgress(progress01 ?? 1);\n const caption = props.label ?? style.label;\n\n if (props.variant === \"COMPACT\") {\n const face = renderCompactClockFace(hand);\n return (\n <Box flexDirection=\"column\">\n {face.map((line, i) => (\n <Text key={`clock:compact:${type}:${hand}:${i}`} color={style.color}>\n {line}\n </Text>\n ))}\n {props.showLabel === false ? null : (\n <Text color=\"gray\">{caption ?? \" \"}</Text>\n )}\n </Box>\n );\n }\n\n const face = renderClockFace(hand);\n\n return (\n <Box flexDirection=\"column\">\n {face.map((line, i) => (\n <Text key={`clock:${type}:${hand}:${i}`} color={style.color}>\n {line}\n </Text>\n ))}\n {props.showLabel === false ? null : (\n <Text color=\"gray\">{caption ?? \" \"}</Text>\n )}\n </Box>\n );\n}\n","import React, { useEffect, useMemo, useState } from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport type ProjectileKind = \"ROSE\" | \"POOP\" | \"HAMMER\";\nexport type ProjectileDirection = \"LEFT_TO_RIGHT\" | \"RIGHT_TO_LEFT\";\n\nconst PROJECTILES: Record<ProjectileKind, { glyph: string; color: string }> = {\n ROSE: { glyph: \"🌹\", color: \"magenta\" },\n POOP: { glyph: \"💩\", color: \"yellow\" },\n HAMMER: { glyph: \"🔨\", color: \"cyan\" },\n};\n\nfunction clamp01(n: number) {\n if (n <= 0) return 0;\n if (n >= 1) return 1;\n return n;\n}\n\nfunction renderTrack(width: number, pos: number, glyph: string) {\n const w = Math.max(8, Math.floor(width));\n const innerWidth = w - 2;\n if (pos < 0) return `|${new Array(innerWidth).fill(\"·\").join(\"\")}|`;\n const clampedPos = Math.max(0, Math.min(innerWidth - 1, Math.floor(pos)));\n\n const track = new Array(innerWidth).fill(\"·\");\n track[clampedPos] = glyph;\n return `|${track.join(\"\")}|`;\n}\n\nexport function ProjectileThrowSprite(props: {\n kind: ProjectileKind;\n direction?: ProjectileDirection;\n width?: number;\n progress?: number;\n shotId?: string | number;\n durationMs?: number;\n leftLabel?: string;\n rightLabel?: string;\n onDone?: () => void;\n}) {\n const direction = props.direction ?? \"LEFT_TO_RIGHT\";\n const width = props.width ?? 28;\n const durationMs = props.durationMs ?? 700;\n\n const [autoProgress, setAutoProgress] = useState<number | null>(null);\n const progress = typeof props.progress === \"number\" ? props.progress : autoProgress;\n\n useEffect(() => {\n if (props.shotId === undefined) return;\n const startedAt = Date.now();\n setAutoProgress(0);\n\n const handle = setInterval(() => {\n const elapsed = Date.now() - startedAt;\n const next = clamp01(elapsed / Math.max(1, durationMs));\n setAutoProgress(next);\n if (next >= 1) {\n clearInterval(handle);\n props.onDone?.();\n }\n }, 33);\n\n return () => clearInterval(handle);\n }, [durationMs, props.onDone, props.shotId]);\n\n const projectile = PROJECTILES[props.kind];\n\n const track = useMemo(() => {\n if (progress === null || !Number.isFinite(progress)) {\n return renderTrack(width, -1, \" \");\n }\n const innerWidth = Math.max(8, Math.floor(width)) - 2;\n const rawPos = clamp01(progress) * (innerWidth - 1);\n const pos =\n direction === \"LEFT_TO_RIGHT\" ? rawPos : (innerWidth - 1 - rawPos);\n return renderTrack(width, pos, projectile.glyph);\n }, [direction, progress, projectile.glyph, width]);\n\n return (\n <Box>\n {props.leftLabel ? <Text color=\"gray\">{props.leftLabel} </Text> : null}\n <Text color={projectile.color}>{track}</Text>\n {props.rightLabel ? <Text color=\"gray\"> {props.rightLabel}</Text> : null}\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ConnectionStatus } from \"../protocol.js\";\n\nfunction statusText(status: ConnectionStatus) {\n switch (status) {\n case \"waiting\":\n return { label: \"Waiting\", color: \"yellow\" };\n case \"connecting\":\n return { label: \"Connecting\", color: \"yellow\" };\n case \"connected\":\n return { label: \"Connected via TCP\", color: \"green\" };\n case \"disconnected\":\n return { label: \"Disconnected\", color: \"red\" };\n }\n}\n\nexport function StatusHeader(props: {\n role: \"host\" | \"client\";\n status: ConnectionStatus;\n hostIp?: string;\n tcpPort?: number;\n peerCount?: number;\n}) {\n const st = statusText(props.status);\n return (\n <Box>\n <Box>\n <Text color={st.color}>{st.label}</Text>\n {props.peerCount !== undefined && props.peerCount > 0 && (\n <Text color=\"cyan\"> ({props.peerCount} online)</Text>\n )}\n {props.role === \"host\" ? (\n <Text color=\"gray\">\n {props.tcpPort ? ` — TCP :${props.tcpPort}` : \"\"}\n </Text>\n ) : (\n <Text color=\"gray\">\n {props.hostIp && props.tcpPort\n ? ` — ${props.hostIp}:${props.tcpPort}`\n : \"\"}\n </Text>\n )}\n </Box>\n </Box>\n );\n}\n","export { AiConsole } from \"./AiConsole.js\";\nexport { BuddyAvatar } from \"./sprite/BuddyAvatar.js\";\nexport {\n CountdownClockSprite,\n countdownClockTypeFromMinutes,\n} from \"./sprite/CountdownClockSprite.js\";\nexport { ProjectileThrowSprite } from \"./sprite/ProjectileThrowSprite.js\";\nexport { StatusHeader } from \"./StatusHeader.js\";\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { ActivityState } from \"../protocol.js\";\nimport {\n AiConsole,\n BuddyAvatar,\n CountdownClockSprite,\n ProjectileThrowSprite,\n StatusHeader,\n} from \"../components/index.js\";\nimport type { CountdownClockType } from \"../components/sprite/CountdownClockSprite.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../components/sprite/ProjectileThrowSprite.js\";\nimport {\n useActivityMonitor,\n useBroadcaster,\n useTcpSync,\n} from \"../hooks/index.js\";\nimport { ensureGlobalKeyboard, subscribeGlobalKeydown } from \"../hooks/globalKeyboard.js\";\nimport type { LeaveStats } from \"../types.js\";\n\nfunction formatMMSS(totalSeconds: number) {\n const m = Math.floor(totalSeconds / 60);\n const s = totalSeconds % 60;\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nexport function Session(\n props:\n | { role: \"host\"; localName: string; onLeave: (stats: LeaveStats) => void }\n | {\n role: \"client\";\n localName: string;\n onLeave: (stats: LeaveStats) => void;\n hostIp: string;\n tcpPort: number;\n roomName: string;\n hostName: string;\n }\n) {\n const roomName = useMemo(\n () => `${props.localName}'s Room`,\n [props.localName]\n );\n\n const [showAi, setShowAi] = useState(false);\n const [countdown, setCountdown] = useState<{\n minutes: number;\n totalSeconds: number;\n endsAt: number;\n remainingSeconds: number;\n type: CountdownClockType;\n } | null>(null);\n const [shots, setShots] = useState<\n Array<{\n id: number;\n kind: ProjectileKind;\n direction: ProjectileDirection;\n }>\n >([]);\n const [localBubble, setLocalBubble] = useState<string | null>(null);\n const [buddyBubble, setBuddyBubble] = useState<string | null>(null);\n const bubbleTimersRef = useRef<{\n local: NodeJS.Timeout | null;\n buddy: NodeJS.Timeout | null;\n }>({ local: null, buddy: null });\n\n const tcpOptions = useMemo(() => {\n return props.role === \"host\"\n ? ({ role: \"host\", localName: props.localName } as const)\n : ({\n role: \"client\",\n localName: props.localName,\n hostIp: props.hostIp,\n tcpPort: props.tcpPort,\n hostName: props.hostName,\n } as const);\n }, [\n props.role,\n props.localName,\n props.role === \"client\" ? props.hostIp : \"\",\n props.role === \"client\" ? props.tcpPort : 0,\n props.role === \"client\" ? props.hostName : \"\",\n ]);\n\n const tcp = useTcpSync(tcpOptions);\n\n const broadcasterOptions = useMemo(() => {\n return props.role === \"host\"\n ? ({\n enabled: true,\n hostName: props.localName,\n roomName,\n tcpPort: tcp.listenPort,\n } as const)\n : ({ enabled: false } as const);\n }, [props.role, props.localName, roomName, tcp.listenPort]);\n\n useBroadcaster(broadcasterOptions);\n\n const localActivity = useActivityMonitor();\n\n // Fix: Derive peers from single peerName until multi-peer is supported\n const peers = useMemo(() => {\n return tcp.peerName\n ? [\n {\n id: \"remote\",\n name: tcp.peerName,\n state: tcp.remoteState ?? (\"OFFLINE\" as const),\n },\n ]\n : [];\n }, [tcp.peerName, tcp.remoteState]);\n\n const firstPeerName = tcp.peerName;\n\n const onToggleAi = useCallback(() => setShowAi((v) => !v), []);\n const onCloseAi = useCallback(() => setShowAi(false), []);\n\n const sessionStartAtRef = useRef<number>(Date.now());\n const connectedStartAtRef = useRef<number | null>(null);\n const connectedTotalMsRef = useRef<number>(0);\n const keyPressesRef = useRef<number>(0);\n const useGlobalKeyboardRef = useRef<boolean>(false);\n\n const countKeyPress = useCallback(() => {\n keyPressesRef.current += 1;\n }, []);\n\n // Count terminal key presses unless global keyboard listener is active.\n useInput(\n () => {\n if (!useGlobalKeyboardRef.current) countKeyPress();\n },\n { isActive: true }\n );\n\n // If `TERMBUDDY_ACTIVITY_SOURCE=keyboard`, count global key presses.\n useEffect(() => {\n const raw = process.env.TERMBUDDY_ACTIVITY_SOURCE ?? \"ink\";\n const source = raw === \"xinput\" ? \"keyboard\" : raw;\n if (source !== \"keyboard\") return;\n\n let cancelled = false;\n let unsub: (() => void) | null = null;\n void (async () => {\n const ok = await ensureGlobalKeyboard();\n if (cancelled) return;\n if (!ok) return;\n useGlobalKeyboardRef.current = true;\n unsub = subscribeGlobalKeydown(countKeyPress);\n })();\n\n return () => {\n cancelled = true;\n unsub?.();\n useGlobalKeyboardRef.current = false;\n };\n }, [countKeyPress]);\n\n // Track connected time.\n useEffect(() => {\n if (tcp.status === \"connected\") {\n if (connectedStartAtRef.current === null) {\n connectedStartAtRef.current = Date.now();\n }\n return;\n }\n\n if (connectedStartAtRef.current !== null) {\n connectedTotalMsRef.current += Date.now() - connectedStartAtRef.current;\n connectedStartAtRef.current = null;\n }\n }, [tcp.status]);\n\n const finishAndLeave = useCallback(() => {\n const endedAt = Date.now();\n let connectedDurationMs = connectedTotalMsRef.current;\n if (connectedStartAtRef.current !== null) {\n connectedDurationMs += endedAt - connectedStartAtRef.current;\n }\n\n const stats: LeaveStats = {\n keyPresses: keyPressesRef.current,\n sessionDurationMs: endedAt - sessionStartAtRef.current,\n connectedDurationMs,\n startedAt: sessionStartAtRef.current,\n endedAt,\n peerName: firstPeerName,\n };\n props.onLeave(stats);\n }, [props, firstPeerName]);\n\n const startCountdown = useCallback((minutes: number) => {\n const totalSeconds = Math.max(1, Math.floor(minutes * 60));\n const endsAt = Date.now() + totalSeconds * 1000;\n const type: CountdownClockType =\n minutes <= 10 ? \"SHORT\" : minutes <= 30 ? \"MEDIUM\" : \"LONG\";\n setCountdown({\n minutes,\n totalSeconds,\n endsAt,\n remainingSeconds: totalSeconds,\n type,\n });\n }, []);\n\n const nextShotIdRef = useRef<number>(1);\n const shotQueueRef = useRef<\n Array<{ kind: ProjectileKind; direction: ProjectileDirection }>\n >([]);\n\n const pumpShotQueue = useCallback(() => {\n setShots((prev) => {\n if (prev.length >= 1) return prev;\n const next = shotQueueRef.current.shift();\n if (!next) return prev;\n const id = nextShotIdRef.current++;\n return [...prev, { id, kind: next.kind, direction: next.direction }];\n });\n }, []);\n\n useEffect(() => {\n if (shots.length === 0) pumpShotQueue();\n }, [shots.length, pumpShotQueue]);\n\n const throwProjectile = useCallback(\n (kind: ProjectileKind, direction: ProjectileDirection) => {\n shotQueueRef.current.push({ kind, direction });\n pumpShotQueue();\n if (tcp.status === \"connected\") tcp.sendProjectile(kind, direction);\n },\n [pumpShotQueue, tcp]\n );\n\n const showBubble = useCallback(\n (args: { text: string; target: \"local\" | \"buddy\"; durationMs: number }) => {\n const text = args.text.trim();\n if (!text) return;\n const durationMs = Math.max(300, Math.min(15_000, Math.floor(args.durationMs)));\n\n const setBubble = args.target === \"buddy\" ? setBuddyBubble : setLocalBubble;\n setBubble(text);\n\n const prevTimer =\n args.target === \"buddy\"\n ? bubbleTimersRef.current.buddy\n : bubbleTimersRef.current.local;\n if (prevTimer) clearTimeout(prevTimer);\n\n const handle = setTimeout(() => {\n setBubble(null);\n if (args.target === \"buddy\") bubbleTimersRef.current.buddy = null;\n else bubbleTimersRef.current.local = null;\n }, durationMs);\n\n if (args.target === \"buddy\") bubbleTimersRef.current.buddy = handle;\n else bubbleTimersRef.current.local = handle;\n },\n []\n );\n\n useInput(\n (input, key) => {\n if (input === \"q\") finishAndLeave();\n if (input === \"/\" && !key.ctrl && !key.meta) onToggleAi();\n },\n { isActive: !showAi }\n );\n\n useInput(\n (input) => {\n if (input === \"x\") setCountdown(null);\n },\n { isActive: !showAi && countdown !== null }\n );\n\n const localState = localActivity.state;\n const localLabel =\n props.role === \"host\"\n ? `${props.localName} (Host)`\n : `${props.localName} (Client)`;\n\n // Sync local activity state to peer.\n useEffect(() => {\n if (tcp.status !== \"connected\") return;\n tcp.sendStatus(localState);\n }, [localState, tcp.status, tcp.sendStatus]);\n\n // Handle incoming projectiles from peer (flip direction)\n useEffect(() => {\n const handleRemoteProjectile = (kind: ProjectileKind, direction: ProjectileDirection, _senderName?: string) => {\n const flippedDirection: ProjectileDirection =\n direction === \"LEFT_TO_RIGHT\" ? \"RIGHT_TO_LEFT\" : \"LEFT_TO_RIGHT\";\n shotQueueRef.current.push({ kind, direction: flippedDirection });\n pumpShotQueue();\n };\n\n tcp.setOnRemoteProjectile(handleRemoteProjectile);\n }, [tcp, pumpShotQueue]);\n\n useEffect(() => {\n if (!countdown) return;\n const endsAt = countdown.endsAt;\n const handle = setInterval(() => {\n const remaining = Math.max(0, Math.ceil((endsAt - Date.now()) / 1000));\n setCountdown((prev) => {\n if (!prev) return prev;\n if (prev.endsAt !== endsAt) return prev;\n if (remaining <= 0) return null;\n if (prev.remainingSeconds === remaining) return prev;\n return { ...prev, remainingSeconds: remaining };\n });\n }, 250);\n return () => clearInterval(handle);\n }, [countdown?.endsAt]);\n\n useEffect(() => {\n return () => {\n if (bubbleTimersRef.current.local) clearTimeout(bubbleTimersRef.current.local);\n if (bubbleTimersRef.current.buddy) clearTimeout(bubbleTimersRef.current.buddy);\n };\n }, []);\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <StatusHeader\n role={props.role}\n status={tcp.status}\n hostIp={props.role === \"client\" ? props.hostIp : undefined}\n tcpPort={props.role === \"client\" ? props.tcpPort : tcp.listenPort}\n peerCount={peers.length}\n />\n\n {/* Main Stage: 3 Columns */}\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n marginTop={1}\n gap={2}\n >\n {/* Left: Local User */}\n <Box flexDirection=\"column\" alignItems=\"center\" minWidth={20}>\n {countdown ? (\n <Box flexDirection=\"column\" alignItems=\"center\" marginBottom={0}>\n <Text color=\"gray\">{formatMMSS(countdown.remainingSeconds)}</Text>\n <CountdownClockSprite\n variant=\"COMPACT\"\n type={countdown.type}\n minutes={countdown.minutes}\n totalSeconds={countdown.totalSeconds}\n remainingSeconds={countdown.remainingSeconds}\n showLabel={false}\n />\n </Box>\n ) : (\n <Box height={4} />\n )}\n <BuddyAvatar state={localState} marginTop={0} bubbleText={localBubble} />\n <Text color=\"cyan\">{localLabel}</Text>\n </Box>\n\n {/* Center: Stage (Projectiles only) */}\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n flexGrow={1}\n minWidth={40}\n >\n {/* Projectile Area */}\n <Box flexDirection=\"column\" width=\"100%\" alignItems=\"center\">\n {shots.map((s) => (\n <ProjectileThrowSprite\n key={String(s.id)}\n kind={s.kind}\n direction={s.direction}\n shotId={s.id}\n width={36}\n onDone={() =>\n setShots((prev) => prev.filter((x) => x.id !== s.id))\n }\n />\n ))}\n {/* Spacer to maintain layout stability when shots appear/disappear */}\n {shots.length === 0 ? <Box height={1} /> : null}\n </Box>\n </Box>\n\n {/* Right: Remote Users */}\n <Box flexDirection=\"column\" alignItems=\"center\" minWidth={20}>\n {peers.length === 0 ? (\n <>\n <Box height={4} />\n <BuddyAvatar state=\"OFFLINE\" marginTop={0} bubbleText={buddyBubble} />\n <Text color=\"gray\">Waiting...</Text>\n </>\n ) : (\n <Box flexDirection=\"row\" gap={2} flexWrap=\"wrap\" justifyContent=\"center\">\n {peers.slice(0, 4).map((peer) => (\n <Box key={peer.id} flexDirection=\"column\" alignItems=\"center\">\n <BuddyAvatar state={peer.state} marginTop={0} bubbleText={buddyBubble} />\n <Text color=\"magenta\">{peer.name}</Text>\n </Box>\n ))}\n {peers.length > 4 && (\n <Text color=\"gray\">+{peers.length - 4} more</Text>\n )}\n </Box>\n )}\n </Box>\n </Box>\n\n {/* Footer Instructions (Hide when AI is open to save space) */}\n {!showAi ? (\n <Box marginTop={1} justifyContent=\"center\">\n <Text color=\"gray\">\n 按 <Text color=\"cyan\">/</Text> 召唤 AI Console,按{\" \"}\n <Text color=\"cyan\">q</Text> 结束本次陪伴。\n {countdown ? (\n <>\n {\" \"}\n <Text color=\"gray\">\n (倒计时中:按 <Text color=\"cyan\">x</Text> 取消)\n </Text>\n </>\n ) : null}\n </Text>\n </Box>\n ) : null}\n\n {/* AI Console Overlay */}\n {showAi ? (\n <Box\n marginTop={1}\n width=\"100%\"\n flexDirection=\"row\"\n justifyContent=\"center\"\n >\n <Box width={64}>\n <AiConsole\n onClose={onCloseAi}\n onStartCountdown={startCountdown}\n onShowBubble={showBubble}\n onThrowProjectile={throwProjectile}\n localName={props.localName}\n peerName={\n firstPeerName ??\n (props.role === \"client\" ? props.hostName : undefined) ??\n \"Buddy\"\n }\n />\n </Box>\n </Box>\n ) : null}\n </Box>\n );\n}\n","export { MainMenu } from \"./MainMenu.js\";\nexport { NicknamePrompt } from \"./NicknamePrompt.js\";\nexport { RoomScanner } from \"./RoomScanner.js\";\nexport { LeavePage } from \"./LeavePage.js\";\nexport { Session } from \"./Session.js\";\n","import React, { useCallback, useMemo, useState } from \"react\";\nimport os from \"node:os\";\nimport { useApp } from \"ink\";\nimport {\n LeavePage,\n MainMenu,\n NicknamePrompt,\n RoomScanner,\n Session,\n} from \"../page/index.js\";\nimport type { LeaveStats } from \"../types.js\";\n\ntype View =\n | { name: \"NICKNAME\" }\n | { name: \"MENU\" }\n | { name: \"SCANNING\" }\n | { name: \"LEAVE\"; stats: LeaveStats }\n | { name: \"SESSION\"; role: \"host\" }\n | {\n name: \"SESSION\";\n role: \"client\";\n hostIp: string;\n tcpPort: number;\n roomName: string;\n hostName: string;\n };\n\nexport function App() {\n const { exit } = useApp();\n const [view, setView] = useState<View>({ name: \"NICKNAME\" });\n const [nickname, setNickname] = useState<string | null>(null);\n\n const localName = useMemo(() => nickname ?? os.hostname(), [nickname]);\n\n const goMenu = useCallback(() => setView({ name: \"MENU\" }), []);\n\n if (view.name === \"NICKNAME\") {\n return (\n <NicknamePrompt\n onExit={() => exit()}\n onSubmit={(name) => {\n setNickname(name);\n setView({ name: \"MENU\" });\n }}\n />\n );\n }\n\n if (view.name === \"MENU\") {\n return (\n <MainMenu\n onHost={() => setView({ name: \"SESSION\", role: \"host\" })}\n onJoin={() => setView({ name: \"SCANNING\" })}\n onExit={() => exit()}\n />\n );\n }\n\n if (view.name === \"LEAVE\") {\n return (\n <LeavePage stats={view.stats} onBack={goMenu} onExit={() => exit()} />\n );\n }\n\n if (view.name === \"SCANNING\") {\n return (\n <RoomScanner\n onBack={goMenu}\n onExit={() => exit()}\n onSelectRoom={(room) =>\n setView({\n name: \"SESSION\",\n role: \"client\",\n hostIp: room.ip,\n tcpPort: room.tcpPort,\n roomName: room.roomName,\n hostName: room.hostName,\n })\n }\n />\n );\n }\n\n if (view.name === \"SESSION\" && view.role === \"host\") {\n return (\n <Session\n localName={localName}\n role=\"host\"\n onLeave={(stats) => setView({ name: \"LEAVE\", stats })}\n />\n );\n }\n\n return (\n <Session\n localName={localName}\n role=\"client\"\n onLeave={(stats) => setView({ name: \"LEAVE\", stats })}\n hostIp={view.hostIp}\n tcpPort={view.tcpPort}\n roomName={view.roomName}\n hostName={view.hostName}\n />\n );\n}\n","export { App } from \"./App.js\";\n","process.env.NODE_ENV ??= 'production';\n\nconst React = await import('react');\nconst {render} = await import('ink');\nconst {App} = await import('./app/index.js');\n\nrender(React.createElement(App));\n"],"mappings":"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","names":["Box","Text","useInput","jsx","jsxs","useState","useInput","tool","tool","tool","useCallback","useEffect","useRef","useState","os","useEffect","useEffect","useState","dgram","useCallback","useEffect","useRef","useState","socket","useMemo","Box","Text","useInput","jsx","jsxs","useMemo","Box","Text","useInput","jsx","jsxs","useEffect","useMemo","useState","Box","Text","useInput","jsx","jsxs","useMemo","Box","Text","jsx","Box","Text","jsx","jsxs","useMemo","Box","Text","jsx","jsxs","face","useEffect","useMemo","useState","Box","Text","jsx","jsxs","clamp01","Box","Text","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useState","Box","Text","useInput","Fragment","jsx","jsxs","useCallback","useMemo","useState","os","jsx","React","App"]}
1
+ {"version":3,"sources":["../src/page/MainMenu.tsx","../src/page/NicknamePrompt.tsx","../src/hooks/globalKeyboard.ts","../src/hooks/useActivityMonitor.ts","../src/components/tool/createCountdownTool.ts","../src/components/tool/createBubbleTool.ts","../src/components/tool/createInteractionTool.ts","../src/components/tool/createSessionInfoTool.ts","../src/components/tool/index.ts","../src/hooks/useAiAgent.ts","../src/constants.ts","../src/net/broadcast.ts","../src/net/index.ts","../src/hooks/useBroadcaster.ts","../src/hooks/useScanner.ts","../src/hooks/useTcpSync.ts","../src/hooks/index.ts","../src/page/RoomScanner.tsx","../src/page/LeavePage.tsx","../src/storage/apiKey.ts","../src/components/AiConsole.tsx","../src/components/sprite/BubbleSprite.tsx","../src/components/sprite/BuddyAvatar.tsx","../src/components/sprite/CountdownClockSprite.tsx","../src/components/sprite/ProjectileThrowSprite.tsx","../src/components/StatusHeader.tsx","../src/components/index.ts","../src/page/Session.tsx","../src/page/index.ts","../src/app/App.tsx","../src/app/index.ts","../src/cli.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text, useInput } from \"ink\";\n\nexport function MainMenu(props: {\n onHost: () => void;\n onJoin: () => void;\n onExit: () => void;\n}) {\n useInput((input, key) => {\n if (key.escape || input === \"q\") props.onExit();\n if (input === \"1\") props.onHost();\n if (input === \"2\") props.onJoin();\n });\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text>\n {String.raw`\n████████╗███████╗██████╗ ███╗ ███╗██████╗ ██╗ ██╗██████╗ ██████╗ ██╗ ██╗\n╚══██╔══╝██╔════╝██╔══██╗████╗ ████║██╔══██╗██║ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝\n ██║ █████╗ ██████╔╝██╔████╔██║██████╔╝██║ ██║██║ ██║██║ ██║ ╚████╔╝ \n ██║ ██╔══╝ ██╔══██╗██║╚██╔╝██║██╔══██╗██║ ██║██║ ██║██║ ██║ ╚██╔╝ \n ██║ ███████╗██║ ██║██║ ╚═╝ ██║██████╔╝╚██████╔╝██████╔╝██████╔╝ ██║ \n ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ \n`}\n </Text>\n <Box flexDirection=\"column\" marginTop={1}>\n <Text>Terminal Body Doubling — 极简 / 极客 / 私密</Text>\n <Text> </Text>\n <Text>\n <Text color=\"cyan\">[1]</Text> 建房 (Host)\n </Text>\n <Text>\n <Text color=\"cyan\">[2]</Text> 加入 (Join)\n </Text>\n <Text>\n <Text color=\"cyan\">[q]</Text> 退出\n </Text>\n </Box>\n </Box>\n );\n}\n","import React, { useMemo, useState } from \"react\";\nimport os from \"node:os\";\nimport { Box, Text, useInput } from \"ink\";\n\nfunction defaultNick(): string {\n try {\n return os.userInfo().username || os.hostname();\n } catch {\n return os.hostname();\n }\n}\n\nexport function NicknamePrompt(props: {\n onSubmit: (nickname: string) => void;\n onExit: () => void;\n}) {\n const initial = useMemo(() => defaultNick(), []);\n const [nickname, setNickname] = useState(initial);\n const [touched, setTouched] = useState(false);\n\n useInput((input, key) => {\n if (key.escape) props.onExit();\n\n if (key.return) {\n const name = nickname.trim();\n if (!name) return;\n props.onSubmit(name);\n return;\n }\n\n if (key.backspace || key.delete) {\n setTouched(true);\n setNickname((v) => v.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (!input) return;\n if (input === \"\\t\") return;\n\n setTouched(true);\n setNickname((v) => v + input);\n });\n\n const hint = touched ? \"\" : \" (回车确认,可直接用默认值)\";\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color=\"gray\">欢迎来到 TermBuddy</Text>\n <Box marginTop={1}>\n <Text>\n 请输入你的昵称:<Text color=\"cyan\">{nickname || \"\"}</Text>\n <Text color=\"gray\">{hint}</Text>\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\">按 Esc 退出。</Text>\n </Box>\n </Box>\n );\n}\n\n","import { spawn } from \"node:child_process\";\n\nexport type GlobalKeyboardBackend = \"uiohook\" | \"xinput\";\n\ntype Listener = () => void;\n\nlet backend: GlobalKeyboardBackend | null = null;\nlet started = false;\nlet starting: Promise<GlobalKeyboardBackend | null> | null = null;\nlet stopBackend: (() => void) | null = null;\n\nconst listeners = new Set<Listener>();\n\nfunction emitKeydown() {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // ignore\n }\n }\n}\n\nasync function tryStartUiohook(): Promise<GlobalKeyboardBackend | null> {\n try {\n const mod = (await import(\"uiohook-napi\")) as unknown as {\n uIOhook?: {\n on: (event: \"keydown\", listener: () => void) => unknown;\n removeListener?: (event: \"keydown\", listener: () => void) => unknown;\n start: () => void;\n stop: () => void;\n };\n default?: { uIOhook?: unknown };\n };\n\n const uIOhook =\n mod.uIOhook ??\n ((mod.default as { uIOhook?: unknown } | undefined)?.uIOhook as\n | {\n on: (event: \"keydown\", listener: () => void) => unknown;\n removeListener?: (event: \"keydown\", listener: () => void) => unknown;\n start: () => void;\n stop: () => void;\n }\n | undefined);\n if (!uIOhook) return null;\n\n const onKeydown = () => emitKeydown();\n uIOhook.on(\"keydown\", onKeydown);\n uIOhook.start();\n\n stopBackend = () => {\n uIOhook.removeListener?.(\"keydown\", onKeydown);\n uIOhook.stop();\n };\n\n return \"uiohook\";\n } catch {\n return null;\n }\n}\n\nfunction tryStartXinput(): Promise<GlobalKeyboardBackend | null> {\n if (process.platform !== \"linux\") return Promise.resolve(null);\n if (!process.env.DISPLAY) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n let resolved = false;\n const child = spawn(\"xinput\", [\"test-xi2\", \"--root\"], {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n\n const resolveOnce = (value: GlobalKeyboardBackend | null) => {\n if (resolved) return;\n resolved = true;\n resolve(value);\n };\n\n child.once(\"error\", () => {\n resolveOnce(null);\n });\n\n // If we got here, treat it as started; parsing may continue.\n resolveOnce(\"xinput\");\n\n let buf = \"\";\n child.stdout?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n if (/KeyPress/.test(line)) emitKeydown();\n }\n });\n\n stopBackend = () => {\n child.stdout?.removeAllListeners();\n child.removeAllListeners();\n child.kill();\n };\n });\n}\n\nexport async function ensureGlobalKeyboard(): Promise<GlobalKeyboardBackend | null> {\n if (started) return backend;\n if (starting) return starting;\n\n starting = (async () => {\n const uiohook = await tryStartUiohook();\n if (uiohook) return uiohook;\n return await tryStartXinput();\n })();\n\n backend = await starting;\n started = backend !== null;\n if (!started) stopBackend = null;\n starting = null;\n\n return backend;\n}\n\nfunction stopIfIdle() {\n if (listeners.size > 0) return;\n if (!started) return;\n started = false;\n backend = null;\n const stop = stopBackend;\n stopBackend = null;\n try {\n stop?.();\n } catch {\n // ignore\n }\n}\n\nexport function subscribeGlobalKeydown(listener: Listener): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n stopIfIdle();\n };\n}\n\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useInput } from \"ink\";\nimport type { ActivityState } from \"../protocol.js\";\nimport {\n ensureGlobalKeyboard,\n subscribeGlobalKeydown,\n} from \"./globalKeyboard.js\";\n\nexport function useActivityMonitor(options?: {\n idleAfterMs?: number;\n source?: \"ink\" | \"keyboard\";\n}): {\n state: ActivityState;\n} {\n const idleAfterMs = options?.idleAfterMs ?? 1500;\n const [state, setState] = useState<ActivityState>(\"IDLE\");\n\n const lastActivityRef = useRef<number>(Date.now());\n\n const markActive = useCallback(() => {\n lastActivityRef.current = Date.now();\n setState(\"TYPING\");\n }, []);\n\n useInput(() => {\n markActive();\n });\n\n // Optional global keyboard activity.\n useEffect(() => {\n const rawSource =\n options?.source ?? process.env.TERMBUDDY_ACTIVITY_SOURCE ?? \"ink\";\n\n // Back-compat: previous env value.\n const source = rawSource === \"xinput\" ? \"keyboard\" : rawSource;\n if (source !== \"keyboard\") return;\n\n let cancelled = false;\n let unsub: (() => void) | null = null;\n void (async () => {\n const ok = await ensureGlobalKeyboard();\n if (cancelled) return;\n if (!ok) return;\n unsub = subscribeGlobalKeydown(markActive);\n })();\n\n return () => {\n cancelled = true;\n unsub?.();\n };\n }, [markActive, options?.source]);\n\n useEffect(() => {\n const id = setInterval(() => {\n const delta = Date.now() - lastActivityRef.current;\n if (delta >= idleAfterMs) setState(\"IDLE\");\n }, 200);\n return () => clearInterval(id);\n }, [idleAfterMs]);\n\n return { state };\n}\n","import { tool } from \"langchain\";\n\nexport function createCountdownTool(options: {\n onStartCountdown?: (minutes: number) => void;\n}) {\n return tool(\n async (input: { minutes: number }) => {\n const minutes = Number(input.minutes);\n if (!Number.isFinite(minutes) || minutes <= 0) return \"倒计时分钟数无效。\";\n options.onStartCountdown?.(minutes);\n return `已开始倒计时 ${minutes} 分钟。`;\n },\n {\n name: \"start_countdown\",\n description: \"开始一个专注倒计时(分钟)。\",\n schema: {\n type: \"object\",\n properties: {\n minutes: {\n type: \"integer\",\n minimum: 1,\n maximum: 180,\n description: \"倒计时分钟数\",\n },\n },\n required: [\"minutes\"],\n additionalProperties: false,\n },\n }\n );\n}\n\n","import { tool } from \"langchain\";\n\nexport type BubbleTarget = \"local\" | \"buddy\";\n\nexport function createBubbleTool(options: {\n onShowBubble?: (args: {\n text: string;\n target: BubbleTarget;\n durationMs: number;\n }) => void;\n}) {\n return tool(\n async (input: { text?: string; target?: BubbleTarget; durationMs?: number }) => {\n const text = String(input.text ?? \"\").trim();\n if (!text) return \"气泡内容为空。\";\n\n const target: BubbleTarget =\n input.target === \"buddy\" || input.target === \"local\"\n ? input.target\n : \"local\";\n\n const durationRaw = Number(input.durationMs ?? 2500);\n const durationMs =\n Number.isFinite(durationRaw) && durationRaw > 0\n ? Math.min(15_000, Math.max(300, Math.floor(durationRaw)))\n : 2500;\n\n options.onShowBubble?.({ text, target, durationMs });\n return `已显示气泡:${text}`;\n },\n {\n name: \"show_bubble\",\n description: \"在小猫头像上显示一个气泡(短消息提示)。\",\n schema: {\n type: \"object\",\n properties: {\n text: {\n type: \"string\",\n minLength: 1,\n maxLength: 120,\n description: \"气泡里的文字\",\n },\n target: {\n type: \"string\",\n enum: [\"local\", \"buddy\"],\n description: \"显示在哪一侧的小猫上(local=我,buddy=同桌)\",\n },\n durationMs: {\n type: \"integer\",\n minimum: 300,\n maximum: 15000,\n description: \"显示时长(毫秒,可选)\",\n },\n },\n required: [\"text\"],\n additionalProperties: false,\n },\n }\n );\n}\n\n","import { tool } from \"langchain\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../sprite/ProjectileThrowSprite.js\";\n\nconst KIND_ALIASES: Array<{ kind: ProjectileKind; keys: string[] }> = [\n { kind: \"ROSE\", keys: [\"rose\", \"花\", \"玫瑰\", \"🌹\", \"love\"] },\n { kind: \"POOP\", keys: [\"poop\", \"屎\", \"💩\", \"大便\"] },\n { kind: \"HAMMER\", keys: [\"hammer\", \"锤\", \"🔨\", \"敲\", \"打\"] },\n];\n\nfunction normalizeKind(raw: unknown): ProjectileKind | null {\n if (typeof raw !== \"string\") return null;\n const upper = raw.toUpperCase().trim();\n if (upper === \"ROSE\" || upper === \"POOP\" || upper === \"HAMMER\") return upper;\n\n const lower = raw.toLowerCase();\n for (const item of KIND_ALIASES) {\n if (item.keys.some((k) => lower.includes(k))) return item.kind;\n }\n return null;\n}\n\nfunction normalizeDirection(raw: unknown): ProjectileDirection | null {\n if (typeof raw !== \"string\") return null;\n const upper = raw.toUpperCase().trim();\n if (upper === \"LEFT_TO_RIGHT\" || upper === \"RIGHT_TO_LEFT\") return upper;\n return null;\n}\n\nexport function createInteractionTool(options: {\n onThrow?: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n}) {\n return tool(\n async (input: { kind?: string; direction?: string; message?: string }) => {\n const kind = normalizeKind(input.kind ?? \"\") ?? \"ROSE\";\n const direction = normalizeDirection(input.direction) ?? \"LEFT_TO_RIGHT\";\n options.onThrow?.(kind, direction);\n const msg = (input.message ?? \"\").trim();\n return msg ? `已投掷 ${kind}:${msg}` : `已投掷 ${kind}。`;\n },\n {\n name: \"throw_projectile\",\n description: \"和同桌互动:投掷一个小物品(🌹/💩/🔨)。\",\n schema: {\n type: \"object\",\n properties: {\n kind: {\n type: \"string\",\n description:\n \"投掷物类型(ROSE/POOP/HAMMER,或任意描述如“玫瑰/锤子/💩”)\",\n },\n direction: {\n type: \"string\",\n enum: [\"LEFT_TO_RIGHT\", \"RIGHT_TO_LEFT\"],\n description: \"飞行方向\",\n },\n message: { type: \"string\", description: \"附带一句话(可选)\" },\n },\n required: [],\n additionalProperties: false,\n },\n }\n );\n}\n","import { tool } from \"langchain\";\n\nexport function createSessionInfoTool(options: {\n localName: string;\n peerName: string;\n}) {\n return tool(\n async () => {\n return JSON.stringify(\n {\n localName: options.localName,\n peerName: options.peerName,\n },\n null,\n 2\n );\n },\n {\n name: \"session_info\",\n description: \"获取当前会话上下文(本地昵称、同桌昵称)。\",\n schema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n }\n );\n}\n\n","export { createCountdownTool } from \"./createCountdownTool.js\";\nexport { createBubbleTool } from \"./createBubbleTool.js\";\nexport { createInteractionTool } from \"./createInteractionTool.js\";\nexport { createSessionInfoTool } from \"./createSessionInfoTool.js\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createAgent } from \"langchain\";\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport {\n createBubbleTool,\n createCountdownTool,\n createInteractionTool,\n createSessionInfoTool,\n} from \"../components/tool/index.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../components/sprite/ProjectileThrowSprite.js\";\ntype LineKind = \"user\" | \"ai\" | \"system\";\nexport type AiLine = { kind: LineKind; text: string; at: number };\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!content) return \"\";\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (typeof part === \"string\") return part;\n if (typeof part === \"object\" && part && \"text\" in part)\n return String((part as any).text ?? \"\");\n return \"\";\n })\n .join(\"\");\n }\n if (typeof content === \"object\" && \"text\" in (content as any))\n return String((content as any).text ?? \"\");\n return String(content);\n}\n\nfunction lastAiText(messages: unknown[]): string | null {\n for (let i = messages.length - 1; i >= 0; i--) {\n const m: any = messages[i];\n const type =\n typeof m?.getType === \"function\"\n ? m.getType()\n : typeof m?._getType === \"function\"\n ? m._getType()\n : m?.type;\n if (type === \"ai\") {\n const t = contentToText(m?.content);\n return t || \"\";\n }\n }\n return null;\n}\n\nfunction createSystemPrompt(context: { localName: string; peerName: string }) {\n return [\n \"你是 TermBuddy 里的“壳中幽灵 (Ghost in the Shell)”。\",\n \"默认隐形;被 / 唤醒时出现。风格:极简、干练、少废话。\",\n \"你可以使用工具来操控应用功能(例如倒计时)。\",\n \"如果用户提到“倒计时/专注/计时/countdown”,优先调用 start_countdown。\",\n \"如果用户提到“气泡/泡泡/提示/说一句”,优先调用 show_bubble。\",\n \"如果用户提到“互动/扔/投掷/throw”,优先调用 throw_projectile。\",\n \"当用户明确要求投掷 N 次且 1<=N<=100 时,必须按 N 执行:重复调用 throw_projectile 共 N 次,不要改成“示意/少量几次”。超过 100 则分批多次调用。\",\n `当前上下文:我叫 ${context.localName};同桌叫 ${context.peerName}。`,\n ].join(\"\\n\");\n}\n\nexport function useAiAgent(options: {\n localName: string;\n peerName: string;\n onStartCountdown?: (minutes: number) => void;\n onShowBubble?: (args: {\n text: string;\n target: \"local\" | \"buddy\";\n durationMs: number;\n }) => void;\n onThrowProjectile?: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n apiKey?: string;\n}) {\n const [lines, setLines] = useState<AiLine[]>([]);\n const [busy, setBusy] = useState(false);\n const [apiKeyError, setApiKeyError] = useState(false);\n\n const agentRef = useRef<Awaited<ReturnType<typeof createAgent>> | null>(null);\n const agentInitRef = useRef<Promise<\n Awaited<ReturnType<typeof createAgent>>\n > | null>(null);\n const agentKeyRef = useRef<string | null>(null);\n const stateRef = useRef<{ messages: unknown[] }>({ messages: [] });\n const abortRef = useRef<AbortController | null>(null);\n\n const append = useCallback((line: AiLine) => {\n setLines((prev) => [...prev, line]);\n }, []);\n\n const updateLine = useCallback((at: number, text: string) => {\n setLines((prev) => {\n const idx = prev.findIndex((l) => l.at === at);\n if (idx === -1) return prev;\n const next = [...prev];\n next[idx] = { ...next[idx], text };\n return next;\n });\n }, []);\n\n const ensureAgent = useCallback(async () => {\n const apiKey = (options.apiKey ?? \"\").trim();\n if (!apiKey) throw new Error(\"missing_api_key\");\n\n if (agentRef.current && agentKeyRef.current === apiKey)\n return agentRef.current;\n\n agentRef.current = null;\n agentInitRef.current = null;\n agentKeyRef.current = apiKey;\n stateRef.current.messages = [];\n\n agentInitRef.current ??= (async () => {\n const startCountdown = createCountdownTool({\n onStartCountdown: options.onStartCountdown,\n });\n\n const showBubble = createBubbleTool({\n onShowBubble: options.onShowBubble,\n });\n\n const sessionInfo = createSessionInfoTool({\n localName: options.localName,\n peerName: options.peerName,\n });\n\n const interaction = createInteractionTool({\n onThrow: options.onThrowProjectile,\n });\n\n const llm = new ChatOpenAI({\n model: \"deepseek-chat\",\n configuration: {\n baseURL: \"https://api.deepseek.com\",\n },\n apiKey: apiKey,\n temperature: 0.1,\n maxTokens: 1000,\n timeout: 30000,\n });\n return createAgent({\n model: llm,\n tools: [startCountdown, showBubble, interaction, sessionInfo],\n systemPrompt: createSystemPrompt({\n localName: options.localName,\n peerName: options.peerName,\n }),\n name: \"ghost\",\n });\n })();\n\n agentRef.current = await agentInitRef.current;\n return agentRef.current;\n }, [\n options.apiKey,\n options.localName,\n options.onStartCountdown,\n options.onShowBubble,\n options.onThrowProjectile,\n options.peerName,\n ]);\n\n const ask = useCallback(\n async (text: string) => {\n const userAt = Date.now();\n const aiAt = userAt + 1;\n const toolAt = userAt + 2;\n setLines([\n { kind: \"user\", text: `> ${text}`, at: userAt },\n { kind: \"ai\", text: \"…\", at: aiAt },\n { kind: \"system\", text: \"\", at: toolAt },\n ]);\n\n abortRef.current?.abort();\n abortRef.current = new AbortController();\n\n setBusy(true);\n try {\n const agent = await ensureAgent();\n const stream = await agent.stream(\n {\n messages: [{ role: \"user\", content: text }],\n },\n {\n streamMode: \"values\",\n signal: abortRef.current.signal,\n } as any\n );\n\n for await (const chunk of stream as any) {\n const messages = (chunk?.messages ?? []) as unknown[];\n if (messages.length > 0) stateRef.current.messages = messages;\n\n const latest: any = messages.at(-1);\n if (latest?.tool_calls?.length) {\n const names = latest.tool_calls\n .map((tc: any) => tc?.name)\n .filter(Boolean)\n .join(\", \");\n if (names) updateLine(toolAt, `Calling tools: ${names}`);\n continue;\n }\n\n const t = lastAiText(messages);\n if (t !== null) updateLine(aiAt, t);\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n const isApiKeyError =\n msg === \"missing_api_key\" ||\n msg.includes(\"401\") ||\n msg.includes(\"403\") ||\n msg.includes(\"Unauthorized\") ||\n msg.includes(\"Invalid API\");\n\n if (isApiKeyError) {\n setApiKeyError(true);\n updateLine(aiAt, \"API Key 错误或失效,请重新输入(按 R 键)\");\n } else {\n updateLine(aiAt, `(AI 出错)${msg}`);\n }\n } finally {\n setBusy(false);\n }\n },\n [append, ensureAgent, updateLine]\n );\n\n const resetApiKeyError = useCallback(() => {\n setApiKeyError(false);\n }, []);\n\n useEffect(() => {\n return () => abortRef.current?.abort();\n }, []);\n\n return { lines, ask, busy, apiKeyError, resetApiKeyError };\n}\n","export const UDP_PORT = 45888;\nexport const TCP_DEFAULT_PORT = 45999;\n\nexport const DISCOVERY_VERSION = 1;\nexport const APP_NAME = 'TermBuddy';\n","import os from \"node:os\";\n\nfunction ipv4ToInt(ip: string) {\n return ip\n .split(\".\")\n .map((n) => Number.parseInt(n, 10))\n .reduce((acc, n) => ((acc << 8) | (n & 255)) >>> 0, 0);\n}\n\nfunction intToIpv4(n: number) {\n return [24, 16, 8, 0].map((shift) => String((n >>> shift) & 255)).join(\".\");\n}\n\nexport function getBroadcastTargets(): string[] {\n const out = new Set<string>([\"255.255.255.255\"]);\n\n const ifaces = os.networkInterfaces();\n for (const entries of Object.values(ifaces)) {\n if (!entries) continue;\n for (const e of entries) {\n if (e.family !== \"IPv4\") continue;\n if (e.internal) continue;\n if (!e.address || !e.netmask) continue;\n const ip = ipv4ToInt(e.address);\n const mask = ipv4ToInt(e.netmask);\n const broadcast = (ip | (~mask >>> 0)) >>> 0;\n out.add(intToIpv4(broadcast));\n }\n }\n\n return [...out];\n}\n","export { getBroadcastTargets } from \"./broadcast.js\";\n","import { useEffect } from \"react\";\nimport dgram from \"node:dgram\";\nimport { UDP_PORT, DISCOVERY_VERSION } from \"../constants.js\";\nimport type { DiscoveryPacket } from \"../protocol.js\";\nimport { getBroadcastTargets } from \"../net/index.js\";\n\ntype Options =\n | { enabled: false }\n | {\n enabled: true;\n hostName: string;\n roomName: string;\n tcpPort?: number | null;\n intervalMs?: number;\n };\n\nexport function useBroadcaster(options: Options) {\n const depKey = options.enabled\n ? `${options.hostName}|${options.roomName}|${options.tcpPort ?? \"\"}|${\n options.intervalMs ?? 1000\n }`\n : \"disabled\";\n\n useEffect(() => {\n if (!options.enabled) return;\n if (!options.tcpPort) return;\n\n const socket = dgram.createSocket(\"udp4\");\n socket.on(\"error\", () => {});\n\n socket.bind(() => {\n socket.setBroadcast(true);\n });\n\n const targets = getBroadcastTargets();\n\n const send = () => {\n const packet: DiscoveryPacket = {\n type: \"termbuddy_discovery\",\n version: DISCOVERY_VERSION,\n hostName: options.hostName,\n roomName: options.roomName,\n tcpPort: options.tcpPort!,\n sentAt: Date.now(),\n };\n const msg = Buffer.from(JSON.stringify(packet));\n for (const address of targets) {\n socket.send(msg, UDP_PORT, address);\n }\n };\n\n send();\n const id = setInterval(send, options.intervalMs ?? 1000);\n\n return () => {\n clearInterval(id);\n socket.close();\n };\n }, [depKey]);\n}\n","import { useEffect, useState } from \"react\";\nimport dgram from \"node:dgram\";\nimport { UDP_PORT, DISCOVERY_VERSION } from \"../constants.js\";\nimport type { DiscoveryPacket } from \"../protocol.js\";\nimport type { DiscoveredRoom } from \"../types.js\";\n\nfunction safeParse(msg: Buffer): DiscoveryPacket | null {\n try {\n const parsed = JSON.parse(msg.toString(\"utf8\")) as DiscoveryPacket;\n if (parsed?.type !== \"termbuddy_discovery\") return null;\n if (parsed?.version !== DISCOVERY_VERSION) return null;\n if (!parsed.hostName || !parsed.roomName || !parsed.tcpPort) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function useScanner(options?: {\n staleAfterMs?: number;\n}): DiscoveredRoom[] {\n const staleAfterMs = options?.staleAfterMs ?? 3500;\n const [rooms, setRooms] = useState<DiscoveredRoom[]>([]);\n\n useEffect(() => {\n const socket = dgram.createSocket(\"udp4\");\n socket.on(\"error\", () => {});\n\n socket.on(\"message\", (msg, rinfo) => {\n const packet = safeParse(msg);\n if (!packet) return;\n\n const now = Date.now();\n setRooms((prev) => {\n const key = `${rinfo.address}:${packet.tcpPort}`;\n const next = prev.filter((r) => `${r.ip}:${r.tcpPort}` !== key);\n next.push({\n ip: rinfo.address,\n hostName: packet.hostName,\n roomName: packet.roomName,\n tcpPort: packet.tcpPort,\n lastSeenAt: now,\n });\n return next;\n });\n });\n\n socket.bind(UDP_PORT, () => {});\n\n const prune = setInterval(() => {\n const now = Date.now();\n setRooms((prev) =>\n prev.filter((r) => now - r.lastSeenAt <= staleAfterMs)\n );\n }, 500);\n\n return () => {\n clearInterval(prune);\n socket.close();\n };\n }, [staleAfterMs]);\n\n return rooms;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport net from \"node:net\";\nimport type {\n ActivityState,\n ConnectionStatus,\n TcpPacket,\n ProjectileKind,\n ProjectileDirection,\n Peer,\n} from \"../protocol.js\";\nimport { TCP_DEFAULT_PORT } from \"../constants.js\";\n\ntype HostOptions = { role: \"host\"; localName: string; port?: number };\ntype ClientOptions = {\n role: \"client\";\n localName: string;\n hostIp: string;\n tcpPort: number;\n hostName?: string;\n};\ntype Options = HostOptions | ClientOptions;\n\nfunction writePacket(socket: net.Socket, packet: TcpPacket) {\n socket.write(`${JSON.stringify(packet)}\\n`, \"utf8\");\n}\n\ntype PeerConnection = {\n id: string;\n socket: net.Socket;\n name: string;\n state: ActivityState;\n lastSeen: number;\n heartbeatInterval: NodeJS.Timeout | null;\n};\n\nexport function useTcpSync(options: Options): {\n status: ConnectionStatus;\n listenPort?: number;\n peers: Peer[];\n peerName?: string; // For backward compatibility (first peer name)\n remoteState?: ActivityState; // For backward compatibility (first peer state)\n sendStatus: (state: ActivityState) => void;\n sendProjectile: (kind: ProjectileKind, direction: ProjectileDirection) => void;\n setOnRemoteProjectile: (callback: (kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) => void;\n} {\n const [status, setStatus] = useState<ConnectionStatus>(\n options.role === \"host\" ? \"waiting\" : \"connecting\"\n );\n const [listenPort, setListenPort] = useState<number | undefined>(undefined);\n const [peers, setPeers] = useState<Peer[]>([]);\n\n const onRemoteProjectileRef = useRef<((kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) | undefined>(undefined);\n\n // For host: map of all peer connections\n const peerConnectionsRef = useRef<Map<string, PeerConnection>>(new Map());\n // For client: single socket ref\n const clientSocketRef = useRef<net.Socket | null>(null);\n const clientHeartbeatRef = useRef<NodeJS.Timeout | null>(null);\n const clientLastSeenRef = useRef<number>(Date.now());\n\n // Generate unique peer ID\n const generatePeerId = () => `peer_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n // Broadcast packet to all peers (host only)\n const broadcastPacket = useCallback((packet: TcpPacket, excludeId?: string) => {\n peerConnectionsRef.current.forEach((peer, id) => {\n if (id !== excludeId && !peer.socket.destroyed) {\n writePacket(peer.socket, packet);\n }\n });\n }, []);\n\n // Update peers state from connections map\n const syncPeersState = useCallback(() => {\n const peerList: Peer[] = [];\n peerConnectionsRef.current.forEach((conn) => {\n peerList.push({ id: conn.id, name: conn.name, state: conn.state });\n });\n setPeers(peerList);\n\n // Update status based on peer count\n if (options.role === \"host\") {\n setStatus(peerList.length > 0 ? \"connected\" : \"waiting\");\n }\n }, [options.role]);\n\n // Remove a peer connection (host only)\n const removePeerConnection = useCallback((peerId: string) => {\n const conn = peerConnectionsRef.current.get(peerId);\n if (conn) {\n if (conn.heartbeatInterval) clearInterval(conn.heartbeatInterval);\n if (!conn.socket.destroyed) conn.socket.destroy();\n\n // Notify other peers about the left peer\n broadcastPacket({ type: \"peer_left\", peerName: conn.name, sentAt: Date.now() }, peerId);\n\n peerConnectionsRef.current.delete(peerId);\n syncPeersState();\n }\n }, [broadcastPacket, syncPeersState]);\n\n // Attach a new peer socket (host only)\n const attachPeerSocket = useCallback((socket: net.Socket) => {\n const peerId = generatePeerId();\n let buf = \"\";\n\n socket.setNoDelay(true);\n socket.setEncoding(\"utf8\");\n\n const conn: PeerConnection = {\n id: peerId,\n socket,\n name: \"Connecting...\",\n state: \"IDLE\",\n lastSeen: Date.now(),\n heartbeatInterval: null,\n };\n\n peerConnectionsRef.current.set(peerId, conn);\n\n socket.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n\n try {\n const packet = JSON.parse(line) as TcpPacket;\n conn.lastSeen = Date.now();\n\n if (packet.type === \"hello\") {\n conn.name = packet.clientName;\n syncPeersState();\n\n // Send hello back\n writePacket(socket, {\n type: \"hello\",\n hostName: options.localName,\n clientName: \"Host\",\n sentAt: Date.now(),\n });\n\n // Notify other peers about new peer\n broadcastPacket({ type: \"peer_joined\", peerName: conn.name, sentAt: Date.now() }, peerId);\n\n // Send list of existing peers to new peer\n peerConnectionsRef.current.forEach((existingConn, existingId) => {\n if (existingId !== peerId && existingConn.name !== \"Connecting...\") {\n writePacket(socket, { type: \"peer_joined\", peerName: existingConn.name, sentAt: Date.now() });\n }\n });\n }\n\n if (packet.type === \"status\") {\n conn.state = packet.state;\n syncPeersState();\n // Broadcast status to other peers\n broadcastPacket({ ...packet, senderName: conn.name }, peerId);\n }\n\n if (packet.type === \"ping\") {\n writePacket(socket, { type: \"pong\", sentAt: Date.now() });\n }\n\n if (packet.type === \"projectile\") {\n // Call local handler\n onRemoteProjectileRef.current?.(packet.kind, packet.direction, conn.name);\n // Broadcast to other peers\n broadcastPacket({ ...packet, senderName: conn.name }, peerId);\n }\n } catch {\n // ignore parse errors\n }\n }\n });\n\n socket.on(\"close\", () => {\n removePeerConnection(peerId);\n });\n\n socket.on(\"error\", () => {\n removePeerConnection(peerId);\n });\n\n // Heartbeat for this peer\n conn.heartbeatInterval = setInterval(() => {\n if (socket.destroyed) {\n removePeerConnection(peerId);\n return;\n }\n writePacket(socket, { type: \"ping\", sentAt: Date.now() });\n const age = Date.now() - conn.lastSeen;\n if (age > 6000) {\n removePeerConnection(peerId);\n }\n }, 2000);\n\n syncPeersState();\n }, [options.localName, broadcastPacket, syncPeersState, removePeerConnection]);\n\n // Client socket cleanup\n const cleanupClientSocket = useCallback(() => {\n if (clientHeartbeatRef.current) clearInterval(clientHeartbeatRef.current);\n clientHeartbeatRef.current = null;\n\n const s = clientSocketRef.current;\n clientSocketRef.current = null;\n if (s && !s.destroyed) s.destroy();\n }, []);\n\n // Attach client socket\n const attachClientSocket = useCallback((socket: net.Socket) => {\n cleanupClientSocket();\n clientSocketRef.current = socket;\n clientLastSeenRef.current = Date.now();\n\n setStatus(\"connected\");\n\n let buf = \"\";\n socket.setNoDelay(true);\n socket.setEncoding(\"utf8\");\n\n socket.on(\"data\", (chunk: string) => {\n buf += chunk;\n while (true) {\n const idx = buf.indexOf(\"\\n\");\n if (idx === -1) break;\n const line = buf.slice(0, idx).trim();\n buf = buf.slice(idx + 1);\n if (!line) continue;\n\n try {\n const packet = JSON.parse(line) as TcpPacket;\n clientLastSeenRef.current = Date.now();\n\n if (packet.type === \"hello\") {\n // Host connected - add host as first peer\n setPeers((prev) => {\n const hostExists = prev.some((p) => p.id === \"host\");\n if (hostExists) return prev;\n return [{ id: \"host\", name: packet.hostName, state: \"IDLE\" as ActivityState }, ...prev];\n });\n }\n\n if (packet.type === \"status\") {\n // Update peer's state\n const senderName = packet.senderName;\n if (senderName) {\n setPeers((prev) => prev.map((p) =>\n p.name === senderName ? { ...p, state: packet.state } : p\n ));\n } else {\n // From host\n setPeers((prev) => prev.map((p) =>\n p.id === \"host\" ? { ...p, state: packet.state } : p\n ));\n }\n }\n\n if (packet.type === \"ping\") {\n writePacket(socket, { type: \"pong\", sentAt: Date.now() });\n }\n\n if (packet.type === \"projectile\") {\n onRemoteProjectileRef.current?.(packet.kind, packet.direction, packet.senderName);\n }\n\n if (packet.type === \"peer_joined\") {\n setPeers((prev) => {\n const exists = prev.some((p) => p.name === packet.peerName);\n if (exists) return prev;\n return [...prev, { id: `peer_${Date.now()}`, name: packet.peerName, state: \"IDLE\" as ActivityState }];\n });\n }\n\n if (packet.type === \"peer_left\") {\n setPeers((prev) => prev.filter((p) => p.name !== packet.peerName));\n }\n } catch {\n // ignore\n }\n }\n });\n\n socket.on(\"close\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n cleanupClientSocket();\n });\n\n socket.on(\"error\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n });\n\n // Hello handshake\n writePacket(socket, {\n type: \"hello\",\n hostName: options.role === \"client\" ? options.hostName ?? \"Host\" : options.localName,\n clientName: options.localName,\n sentAt: Date.now(),\n });\n\n // Heartbeat\n clientHeartbeatRef.current = setInterval(() => {\n const sock = clientSocketRef.current;\n if (!sock || sock.destroyed) return;\n writePacket(sock, { type: \"ping\", sentAt: Date.now() });\n const age = Date.now() - clientLastSeenRef.current;\n if (age > 6000) {\n setStatus(\"disconnected\");\n setPeers([]);\n cleanupClientSocket();\n }\n }, 2000);\n }, [cleanupClientSocket, options]);\n\n // Main effect: setup server or client\n useEffect(() => {\n if (options.role === \"host\") {\n const server = net.createServer((socket) => {\n attachPeerSocket(socket);\n });\n\n server.on(\"error\", () => {});\n\n server.listen(options.port ?? TCP_DEFAULT_PORT, () => {\n const address = server.address();\n if (address && typeof address === \"object\") setListenPort(address.port);\n });\n\n return () => {\n // Cleanup all peer connections\n peerConnectionsRef.current.forEach((conn) => {\n if (conn.heartbeatInterval) clearInterval(conn.heartbeatInterval);\n if (!conn.socket.destroyed) conn.socket.destroy();\n });\n peerConnectionsRef.current.clear();\n server.close();\n };\n }\n\n // Client mode\n setStatus(\"connecting\");\n const socket = net.createConnection(\n { host: options.hostIp, port: options.tcpPort },\n () => {\n attachClientSocket(socket);\n }\n );\n socket.on(\"error\", () => {\n setStatus(\"disconnected\");\n setPeers([]);\n });\n\n return () => {\n socket.destroy();\n cleanupClientSocket();\n };\n }, [attachPeerSocket, attachClientSocket, cleanupClientSocket, options]);\n\n // Send status to all peers\n const sendStatus = useCallback((state: ActivityState) => {\n if (options.role === \"host\") {\n broadcastPacket({ type: \"status\", state, senderName: options.localName, sentAt: Date.now() });\n } else {\n const socket = clientSocketRef.current;\n if (socket && !socket.destroyed) {\n writePacket(socket, { type: \"status\", state, sentAt: Date.now() });\n }\n }\n }, [options, broadcastPacket]);\n\n // Send projectile to all peers\n const sendProjectile = useCallback((kind: ProjectileKind, direction: ProjectileDirection) => {\n if (options.role === \"host\") {\n broadcastPacket({ type: \"projectile\", kind, direction, senderName: options.localName, sentAt: Date.now() });\n } else {\n const socket = clientSocketRef.current;\n if (socket && !socket.destroyed) {\n writePacket(socket, { type: \"projectile\", kind, direction, sentAt: Date.now() });\n }\n }\n }, [options, broadcastPacket]);\n\n const setOnRemoteProjectile = useCallback((callback: (kind: ProjectileKind, direction: ProjectileDirection, senderName?: string) => void) => {\n onRemoteProjectileRef.current = callback;\n }, []);\n\n // Backward compatibility: first peer\n const firstPeer = peers[0];\n const peerName = firstPeer?.name;\n const remoteState = firstPeer?.state;\n\n return {\n status,\n listenPort,\n peers,\n peerName,\n remoteState,\n sendStatus,\n sendProjectile,\n setOnRemoteProjectile\n };\n}\n","export { useActivityMonitor } from \"./useActivityMonitor.js\";\nexport { useAiAgent } from \"./useAiAgent.js\";\nexport { useBroadcaster } from \"./useBroadcaster.js\";\nexport { useScanner } from \"./useScanner.js\";\nexport { useTcpSync } from \"./useTcpSync.js\";\n","import React, {useMemo} from 'react';\nimport {Box, Text, useInput} from 'ink';\nimport {useScanner} from '../hooks/index.js';\nimport type {DiscoveredRoom} from '../types.js';\n\nexport function RoomScanner(props: {\n\tonSelectRoom: (room: DiscoveredRoom) => void;\n\tonBack: () => void;\n\tonExit: () => void;\n}) {\n\tconst rooms = useScanner();\n\n\tconst sortedRooms = useMemo(() => {\n\t\treturn [...rooms].sort((a, b) => b.lastSeenAt - a.lastSeenAt);\n\t}, [rooms]);\n\n\tuseInput((input, key) => {\n\t\tif (key.escape || input === 'b') props.onBack();\n\t\tif (input === 'q') props.onExit();\n\n\t\tconst index = Number.parseInt(input, 10);\n\t\tif (Number.isNaN(index)) return;\n\t\tconst room = sortedRooms[index - 1];\n\t\tif (!room) return;\n\t\tprops.onSelectRoom(room);\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" padding={1}>\n\t\t\t<Text>\n\t\t\t\t<Text color=\"yellow\">正在扫描局域网...</Text> (按 <Text color=\"cyan\">b</Text> 返回,{' '}\n\t\t\t\t<Text color=\"cyan\">q</Text> 退出)\n\t\t\t</Text>\n\t\t\t<Box flexDirection=\"column\" marginTop={1}>\n\t\t\t\t{sortedRooms.length === 0 ? (\n\t\t\t\t\t<Text color=\"gray\">暂无房间广播。</Text>\n\t\t\t\t) : (\n\t\t\t\t\tsortedRooms.map((room, i) => (\n\t\t\t\t\t\t<Text key={`${room.ip}:${room.tcpPort}`}>\n\t\t\t\t\t\t\t<Text color=\"cyan\">[{i + 1}]</Text> {room.hostName} <Text color=\"gray\">@</Text>{' '}\n\t\t\t\t\t\t\t<Text color=\"gray\">\n\t\t\t\t\t\t\t\t{room.ip}:{room.tcpPort}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t</Box>\n\t);\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { LeaveStats } from \"../types.js\";\n\nfunction formatDuration(ms: number) {\n const totalSeconds = Math.max(0, Math.floor(ms / 1000));\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) return `${hours}小时${minutes}分${seconds}秒`;\n if (minutes > 0) return `${minutes}分${seconds}秒`;\n return `${seconds}秒`;\n}\n\nexport function LeavePage(props: {\n stats: LeaveStats;\n onBack: () => void;\n onExit: () => void;\n}) {\n useInput((input, key) => {\n if (key.escape || input === \"q\") props.onExit();\n if (key.return || input === \" \") props.onBack();\n });\n\n const sessionLabel = useMemo(\n () => formatDuration(props.stats.sessionDurationMs),\n [props.stats.sessionDurationMs]\n );\n const connectedLabel = useMemo(\n () => formatDuration(props.stats.connectedDurationMs),\n [props.stats.connectedDurationMs]\n );\n\n return (\n <Box flexDirection=\"column\" padding={1} alignItems=\"center\">\n {/* <Text color=\"cyan\">\n {String.raw`\n ____ _ _ \n / ___| ___ ___ | | __ _| |_| |\n \\___ \\ / _ \\ _ \\ | | / _' | __| |\n ___) | __/ __/ | |__| (_| | |_|_|\n |____/ \\___|\\___|___|_____\\__,_|\\__(_)\n |_____| \n`}\n </Text> */}\n\n <Box\n flexDirection=\"column\"\n marginTop={1}\n borderStyle=\"round\"\n paddingX={2}\n borderColor=\"gray\"\n >\n <Text color=\"white\" bold>\n {props.stats.peerName\n ? `与 ${props.stats.peerName} 的同频记录`\n : \"本次专注记录\"}\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\" gap={1}>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>⌨️ 键盘敲击</Text>\n <Text color=\"yellow\">{props.stats.keyPresses}</Text>\n </Box>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>⏱️ 总共时长</Text>\n <Text color=\"green\">{sessionLabel}</Text>\n </Box>\n <Box justifyContent=\"space-between\" width={30}>\n <Text>🔗 连线时长</Text>\n <Text color=\"blue\">{connectedLabel}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box marginTop={1}>\n <Text color=\"gray\">\n 按 <Text color=\"white\">Enter</Text> 返回菜单,或{\" \"}\n <Text color=\"red\">q</Text> 退出程序\n </Text>\n </Box>\n </Box>\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\ntype KeyFile = {apiKey?: string};\n\nconst KEY_RELATIVE_PATH = path.join('src', 'assets', 'key.json');\n\nasync function readJsonFile(filePath: string): Promise<KeyFile | null> {\n\ttry {\n\t\tconst raw = await fs.readFile(filePath, 'utf8');\n\t\tconst parsed = JSON.parse(raw) as KeyFile;\n\t\tif (!parsed || typeof parsed !== 'object') return null;\n\t\treturn parsed;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function ensureDirForFile(filePath: string) {\n\tawait fs.mkdir(path.dirname(filePath), {recursive: true});\n}\n\nexport async function loadStoredApiKey(): Promise<string | null> {\n\tconst absolute = path.resolve(process.cwd(), KEY_RELATIVE_PATH);\n\tconst json = await readJsonFile(absolute);\n\tconst key = (json?.apiKey ?? '').trim();\n\treturn key.length > 0 ? key : null;\n}\n\nexport async function saveStoredApiKey(apiKey: string): Promise<void> {\n\tconst trimmed = apiKey.trim();\n\tif (trimmed.length === 0) {\n\t\tthrow new Error('API key cannot be empty');\n\t}\n\tconst absolute = path.resolve(process.cwd(), KEY_RELATIVE_PATH);\n\tawait ensureDirForFile(absolute);\n\tconst payload: KeyFile = {apiKey: trimmed};\n\tawait fs.writeFile(absolute, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n}\n\n","import React, { useEffect, useMemo, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { useAiAgent } from \"../hooks/index.js\";\nimport { loadStoredApiKey, saveStoredApiKey } from \"../storage/apiKey.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"./sprite/ProjectileThrowSprite.js\";\n\nexport function AiConsole(props: {\n onClose: () => void;\n onStartCountdown: (minutes: number) => void;\n onShowBubble?: (args: {\n text: string;\n target: \"local\" | \"buddy\";\n durationMs: number;\n }) => void;\n onThrowProjectile: (\n kind: ProjectileKind,\n direction: ProjectileDirection\n ) => void;\n localName: string;\n peerName: string;\n}) {\n const [input, setInput] = useState(\"\");\n const [apiKey, setApiKey] = useState<string | null>(null);\n const [keyDraft, setKeyDraft] = useState(\"\");\n const [cursorOn, setCursorOn] = useState(true);\n const [keyStatus, setKeyStatus] = useState<\n \"loading\" | \"missing\" | \"ready\" | \"saving\"\n >(\"loading\");\n\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n const stored = await loadStoredApiKey();\n if (cancelled) return;\n if (stored) {\n setApiKey(stored);\n setKeyStatus(\"ready\");\n } else {\n setKeyStatus(\"missing\");\n }\n })();\n return () => {\n cancelled = true;\n };\n }, []);\n\n useEffect(() => {\n const handle = setInterval(() => setCursorOn((v) => !v), 500);\n return () => clearInterval(handle);\n }, []);\n\n const agent = useAiAgent({\n localName: props.localName,\n peerName: props.peerName,\n onStartCountdown: props.onStartCountdown,\n onShowBubble: props.onShowBubble,\n onThrowProjectile: props.onThrowProjectile,\n apiKey: apiKey ?? undefined,\n });\n\n const resetApiKey = () => {\n setApiKey(null);\n setKeyDraft(\"\");\n setKeyStatus(\"missing\");\n agent.resetApiKeyError();\n };\n\n const helpLine = useMemo(\n () => \"示例:倒计时20分钟 / 聊会天 / 和别人互动一下\",\n []\n );\n\n useInput(\n (ch, key) => {\n if (key.escape) {\n props.onClose();\n return;\n }\n\n if (agent.apiKeyError && (ch === \"r\" || ch === \"R\")) {\n resetApiKey();\n return;\n }\n\n if (keyStatus !== \"ready\") {\n if (key.return) {\n const draft = keyDraft.trim();\n if (!draft) return;\n setKeyStatus(\"saving\");\n void (async () => {\n await saveStoredApiKey(draft);\n setApiKey(draft);\n setKeyDraft(\"\");\n setKeyStatus(\"ready\");\n })();\n return;\n }\n\n if (key.backspace || key.delete) {\n setKeyDraft((s) => s.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (ch) setKeyDraft((s) => s + ch);\n return;\n }\n\n if (key.return) {\n const line = input.trim();\n setInput(\"\");\n if (!line) return;\n void agent.ask(line);\n return;\n }\n\n if (key.backspace || key.delete) {\n setInput((s) => s.slice(0, -1));\n return;\n }\n\n if (key.ctrl || key.meta) return;\n if (ch) setInput((s) => s + ch);\n },\n { isActive: true }\n );\n\n const lines = agent.lines.filter((l) => l.text.trim().length > 0).slice(-6);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" paddingX={1} paddingY={0}>\n <Box justifyContent=\"space-between\" marginBottom={0}>\n <Text color=\"cyan\">AI Console</Text>\n <Text color=\"gray\">\n {keyStatus === \"saving\"\n ? \"Saving…\"\n : agent.apiKeyError\n ? \"Press R to reset API\"\n : agent.busy\n ? \"Thinking…\"\n : \"Esc Close\"}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\">\n {keyStatus === \"loading\" ? (\n <Text color=\"gray\">Checking API Key...</Text>\n ) : keyStatus === \"missing\" || keyStatus === \"saving\" ? (\n <Text color=\"yellow\">\n Setup: Enter DeepSeek API Key (saves to{\" \"}\n <Text color=\"cyan\">src/assets/key.json</Text>)\n </Text>\n ) : lines.length === 0 ? (\n <Text color=\"gray\">{helpLine}</Text>\n ) : null}\n </Box>\n\n <Box flexDirection=\"column\" marginTop={0} minHeight={6}>\n {keyStatus === \"ready\" ? (\n <>\n {lines.map((l, i) => (\n <Text\n key={`${l.kind}:${l.at}:${i}`}\n color={l.kind === \"user\" ? \"yellow\" : \"white\"}\n wrap=\"truncate-end\"\n >\n {l.kind === \"user\" ? \"> \" : \"\"}\n {l.text}\n </Text>\n ))}\n </>\n ) : (\n <Text color=\"gray\">Please enter API Key to proceed.</Text>\n )}\n </Box>\n\n <Box\n marginTop={0}\n borderStyle=\"single\"\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n >\n <Text color=\"green\">{\">\"} </Text>\n {keyStatus === \"ready\" ? (\n <>\n <Text>{input}</Text>\n {cursorOn ? <Text inverse> </Text> : <Text> </Text>}\n </>\n ) : (\n <Text>\n {keyDraft.length === 0\n ? \"\"\n : \"*\".repeat(Math.min(64, keyDraft.length))}\n {cursorOn ? <Text inverse> </Text> : <Text> </Text>}\n </Text>\n )}\n </Box>\n </Box>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\n\nfunction wrapText(text: string, maxWidth: number) {\n const chars = Array.from(text);\n const lines: string[] = [];\n for (let i = 0; i < chars.length; i += maxWidth) {\n lines.push(chars.slice(i, i + maxWidth).join(\"\"));\n }\n return lines.length ? lines : [\"\"];\n}\n\nfunction renderBubbleLines(text: string, maxInnerWidth: number) {\n const contentLines = wrapText(text, maxInnerWidth);\n const innerWidth = Math.min(\n maxInnerWidth,\n Math.max(...contentLines.map((l) => Array.from(l).length), 1)\n );\n\n const top = `╭${\"─\".repeat(innerWidth + 2)}╮`;\n \n // Create a bottom line with a little tail \"v\" in the middle\n const tailPos = Math.floor((innerWidth + 2) / 2);\n const bottomChars = Array.from(`╰${\"─\".repeat(innerWidth + 2)}╯`);\n if (bottomChars[tailPos]) bottomChars[tailPos] = \"v\"; // Simple tail\n const bottom = bottomChars.join(\"\");\n\n const middle = contentLines.map((l) => {\n const pad = innerWidth - Array.from(l).length;\n return `│ ${l}${\" \".repeat(Math.max(0, pad))} │`;\n });\n return [top, ...middle, bottom];\n}\n\nexport function BubbleSprite(props: {\n text: string;\n maxInnerWidth?: number;\n color?: string;\n}) {\n const trimmed = props.text.trim();\n const maxInnerWidth = props.maxInnerWidth ?? 18;\n\n const lines = useMemo(() => {\n if (!trimmed) return null;\n return renderBubbleLines(trimmed, maxInnerWidth);\n }, [maxInnerWidth, trimmed]);\n\n if (!lines) return null;\n\n return (\n <Box flexDirection=\"column\" alignItems=\"center\">\n {lines.map((line, i) => (\n <Text key={`bubble:${i}`} color={props.color ?? \"gray\"}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ActivityState } from \"../../protocol.js\";\nimport { BubbleSprite } from \"./BubbleSprite.js\";\n\nconst SPRITES: Record<\n ActivityState,\n { color?: string; compact: string; frames: string[] }\n> = {\n TYPING: {\n color: \"green\",\n compact: \"( >_<)===3\",\n frames: [\" /\\\\_/\\\\ \", \"( >_<) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n IDLE: {\n color: \"yellow\",\n compact: \"( -.-)Zzz\",\n frames: [\" /\\\\_/\\\\ \", \"( -.-) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n OFFLINE: {\n color: \"gray\",\n compact: \"( x_x)\",\n frames: [\" /\\\\_/\\\\ \", \"( x_x) \", \" /|_|\\\\\\\\ \", \" / \\\\\\\\ \"],\n },\n};\n\nexport function BuddyAvatar(props: {\n state: ActivityState;\n variant?: \"frames\" | \"compact\";\n bubbleText?: string | null;\n marginTop?: number;\n}) {\n const sprite = SPRITES[props.state];\n if (props.variant === \"compact\") {\n return (\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n marginTop={props.marginTop ?? 1}\n >\n {props.bubbleText ? <BubbleSprite text={props.bubbleText} /> : null}\n <Text color={sprite.color}>{sprite.compact}</Text>\n </Box>\n );\n }\n\n return (\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n marginTop={props.marginTop ?? 1}\n >\n {props.bubbleText ? <BubbleSprite text={props.bubbleText} /> : null}\n {sprite.frames.map((line, i) => (\n <Text key={`${props.state}:${i}`} color={sprite.color}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n","import React, { useMemo } from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport type CountdownClockType = \"SHORT\" | \"MEDIUM\" | \"LONG\";\nexport type CountdownClockVariant = \"FULL\" | \"COMPACT\";\n\nexport function countdownClockTypeFromMinutes(\n minutes: number\n): CountdownClockType {\n if (minutes <= 10) return \"SHORT\";\n if (minutes <= 30) return \"MEDIUM\";\n return \"LONG\";\n}\n\nfunction clamp01(n: number) {\n if (n <= 0) return 0;\n if (n >= 1) return 1;\n return n;\n}\n\nconst TYPE_STYLE: Record<CountdownClockType, { color: string; label: string }> =\n {\n SHORT: { color: \"green\", label: \"Sprint\" },\n MEDIUM: { color: \"cyan\", label: \"Focus\" },\n LONG: { color: \"magenta\", label: \"Deep\" },\n };\n\ntype HandDir = \"N\" | \"NE\" | \"E\" | \"SE\" | \"S\" | \"SW\" | \"W\" | \"NW\";\n\nfunction handFromProgress(progress01: number): HandDir {\n const idx = Math.round(clamp01(progress01) * 7);\n const dirs: HandDir[] = [\"N\", \"NE\", \"E\", \"SE\", \"S\", \"SW\", \"W\", \"NW\"];\n return dirs[idx]!;\n}\n\nfunction renderClockFace(hand: HandDir) {\n const lines = [\n \" .---. \",\n \" / \\\\ \",\n \"| • |\",\n \" \\\\ / \",\n \" '---' \",\n ].map((s) => s.split(\"\"));\n\n const center = { r: 2, c: 4 };\n const handMap: Record<HandDir, { r: number; c: number; ch: string }> = {\n N: { r: 1, c: 4, ch: \"|\" },\n NE: { r: 1, c: 5, ch: \"/\" },\n E: { r: 2, c: 5, ch: \"-\" },\n SE: { r: 3, c: 5, ch: \"\\\\\" },\n S: { r: 3, c: 4, ch: \"|\" },\n SW: { r: 3, c: 3, ch: \"/\" },\n W: { r: 2, c: 3, ch: \"-\" },\n NW: { r: 1, c: 3, ch: \"\\\\\" },\n };\n\n const tip = handMap[hand];\n lines[center.r][center.c] = \"•\";\n lines[tip.r][tip.c] = tip.ch;\n\n return lines.map((row) => row.join(\"\"));\n}\n\nfunction renderCompactClockFace(hand: HandDir) {\n const lines = [\" .---. \", \"| • |\", \" '---' \"].map((s) => s.split(\"\"));\n const center = { r: 1, c: 3 };\n const handMap: Record<HandDir, { r: number; c: number; ch: string }> = {\n N: { r: 0, c: 3, ch: \"|\" },\n NE: { r: 0, c: 4, ch: \"/\" },\n E: { r: 1, c: 5, ch: \"-\" },\n SE: { r: 2, c: 4, ch: \"\\\\\" },\n S: { r: 2, c: 3, ch: \"|\" },\n SW: { r: 2, c: 2, ch: \"/\" },\n W: { r: 1, c: 1, ch: \"-\" },\n NW: { r: 0, c: 2, ch: \"\\\\\" },\n };\n\n const tip = handMap[hand];\n lines[center.r][center.c] = \"•\";\n lines[tip.r][tip.c] = tip.ch;\n\n return lines.map((row) => row.join(\"\"));\n}\n\nexport function CountdownClockSprite(props: {\n type?: CountdownClockType;\n variant?: CountdownClockVariant;\n minutes?: number;\n label?: string | null;\n showLabel?: boolean;\n totalSeconds?: number;\n remainingSeconds?: number | null;\n}) {\n const type =\n props.type ??\n (typeof props.minutes === \"number\"\n ? countdownClockTypeFromMinutes(props.minutes)\n : \"MEDIUM\");\n\n const progress01 = useMemo(() => {\n if (\n typeof props.totalSeconds !== \"number\" ||\n props.totalSeconds <= 0 ||\n props.remainingSeconds === null ||\n typeof props.remainingSeconds !== \"number\"\n ) {\n return null;\n }\n return clamp01(props.remainingSeconds / props.totalSeconds);\n }, [props.remainingSeconds, props.totalSeconds]);\n\n const style = TYPE_STYLE[type];\n const hand = handFromProgress(progress01 ?? 1);\n const caption = props.label ?? style.label;\n\n if (props.variant === \"COMPACT\") {\n const face = renderCompactClockFace(hand);\n return (\n <Box flexDirection=\"column\">\n {face.map((line, i) => (\n <Text key={`clock:compact:${type}:${hand}:${i}`} color={style.color}>\n {line}\n </Text>\n ))}\n {props.showLabel === false ? null : (\n <Text color=\"gray\">{caption ?? \" \"}</Text>\n )}\n </Box>\n );\n }\n\n const face = renderClockFace(hand);\n\n return (\n <Box flexDirection=\"column\">\n {face.map((line, i) => (\n <Text key={`clock:${type}:${hand}:${i}`} color={style.color}>\n {line}\n </Text>\n ))}\n {props.showLabel === false ? null : (\n <Text color=\"gray\">{caption ?? \" \"}</Text>\n )}\n </Box>\n );\n}\n","import React, { useEffect, useMemo, useState } from \"react\";\nimport { Box, Text } from \"ink\";\n\nexport type ProjectileKind = \"ROSE\" | \"POOP\" | \"HAMMER\";\nexport type ProjectileDirection = \"LEFT_TO_RIGHT\" | \"RIGHT_TO_LEFT\";\n\nconst PROJECTILES: Record<ProjectileKind, { glyph: string; color: string }> = {\n ROSE: { glyph: \"🌹\", color: \"magenta\" },\n POOP: { glyph: \"💩\", color: \"yellow\" },\n HAMMER: { glyph: \"🔨\", color: \"cyan\" },\n};\n\nfunction clamp01(n: number) {\n if (n <= 0) return 0;\n if (n >= 1) return 1;\n return n;\n}\n\nfunction renderTrack(width: number, pos: number, glyph: string) {\n const w = Math.max(8, Math.floor(width));\n const innerWidth = w - 2;\n if (pos < 0) return `|${new Array(innerWidth).fill(\"·\").join(\"\")}|`;\n const clampedPos = Math.max(0, Math.min(innerWidth - 1, Math.floor(pos)));\n\n const track = new Array(innerWidth).fill(\"·\");\n track[clampedPos] = glyph;\n return `|${track.join(\"\")}|`;\n}\n\nexport function ProjectileThrowSprite(props: {\n kind: ProjectileKind;\n direction?: ProjectileDirection;\n width?: number;\n progress?: number;\n shotId?: string | number;\n durationMs?: number;\n leftLabel?: string;\n rightLabel?: string;\n onDone?: () => void;\n}) {\n const direction = props.direction ?? \"LEFT_TO_RIGHT\";\n const width = props.width ?? 28;\n const durationMs = props.durationMs ?? 700;\n\n const [autoProgress, setAutoProgress] = useState<number | null>(null);\n const progress = typeof props.progress === \"number\" ? props.progress : autoProgress;\n\n useEffect(() => {\n if (props.shotId === undefined) return;\n const startedAt = Date.now();\n setAutoProgress(0);\n\n const handle = setInterval(() => {\n const elapsed = Date.now() - startedAt;\n const next = clamp01(elapsed / Math.max(1, durationMs));\n setAutoProgress(next);\n if (next >= 1) {\n clearInterval(handle);\n props.onDone?.();\n }\n }, 33);\n\n return () => clearInterval(handle);\n }, [durationMs, props.onDone, props.shotId]);\n\n const projectile = PROJECTILES[props.kind];\n\n const track = useMemo(() => {\n if (progress === null || !Number.isFinite(progress)) {\n return renderTrack(width, -1, \" \");\n }\n const innerWidth = Math.max(8, Math.floor(width)) - 2;\n const rawPos = clamp01(progress) * (innerWidth - 1);\n const pos =\n direction === \"LEFT_TO_RIGHT\" ? rawPos : (innerWidth - 1 - rawPos);\n return renderTrack(width, pos, projectile.glyph);\n }, [direction, progress, projectile.glyph, width]);\n\n return (\n <Box>\n {props.leftLabel ? <Text color=\"gray\">{props.leftLabel} </Text> : null}\n <Text color={projectile.color}>{track}</Text>\n {props.rightLabel ? <Text color=\"gray\"> {props.rightLabel}</Text> : null}\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ConnectionStatus } from \"../protocol.js\";\n\nfunction statusText(status: ConnectionStatus) {\n switch (status) {\n case \"waiting\":\n return { label: \"Waiting\", color: \"yellow\" };\n case \"connecting\":\n return { label: \"Connecting\", color: \"yellow\" };\n case \"connected\":\n return { label: \"Connected via TCP\", color: \"green\" };\n case \"disconnected\":\n return { label: \"Disconnected\", color: \"red\" };\n }\n}\n\nexport function StatusHeader(props: {\n role: \"host\" | \"client\";\n status: ConnectionStatus;\n hostIp?: string;\n tcpPort?: number;\n peerCount?: number;\n}) {\n const st = statusText(props.status);\n return (\n <Box>\n <Box>\n <Text color={st.color}>{st.label}</Text>\n {props.peerCount !== undefined && props.peerCount > 0 && (\n <Text color=\"cyan\"> ({props.peerCount} online)</Text>\n )}\n {props.role === \"host\" ? (\n <Text color=\"gray\">\n {props.tcpPort ? ` — TCP :${props.tcpPort}` : \"\"}\n </Text>\n ) : (\n <Text color=\"gray\">\n {props.hostIp && props.tcpPort\n ? ` — ${props.hostIp}:${props.tcpPort}`\n : \"\"}\n </Text>\n )}\n </Box>\n </Box>\n );\n}\n","export { AiConsole } from \"./AiConsole.js\";\nexport { BuddyAvatar } from \"./sprite/BuddyAvatar.js\";\nexport {\n CountdownClockSprite,\n countdownClockTypeFromMinutes,\n} from \"./sprite/CountdownClockSprite.js\";\nexport { ProjectileThrowSprite } from \"./sprite/ProjectileThrowSprite.js\";\nexport { StatusHeader } from \"./StatusHeader.js\";\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { ActivityState } from \"../protocol.js\";\nimport {\n AiConsole,\n BuddyAvatar,\n CountdownClockSprite,\n ProjectileThrowSprite,\n StatusHeader,\n} from \"../components/index.js\";\nimport type { CountdownClockType } from \"../components/sprite/CountdownClockSprite.js\";\nimport type {\n ProjectileDirection,\n ProjectileKind,\n} from \"../components/sprite/ProjectileThrowSprite.js\";\nimport {\n useActivityMonitor,\n useBroadcaster,\n useTcpSync,\n} from \"../hooks/index.js\";\nimport { ensureGlobalKeyboard, subscribeGlobalKeydown } from \"../hooks/globalKeyboard.js\";\nimport type { LeaveStats } from \"../types.js\";\n\nfunction formatMMSS(totalSeconds: number) {\n const m = Math.floor(totalSeconds / 60);\n const s = totalSeconds % 60;\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nexport function Session(\n props:\n | { role: \"host\"; localName: string; onLeave: (stats: LeaveStats) => void }\n | {\n role: \"client\";\n localName: string;\n onLeave: (stats: LeaveStats) => void;\n hostIp: string;\n tcpPort: number;\n roomName: string;\n hostName: string;\n }\n) {\n const roomName = useMemo(\n () => `${props.localName}'s Room`,\n [props.localName]\n );\n\n const [showAi, setShowAi] = useState(false);\n const [countdown, setCountdown] = useState<{\n minutes: number;\n totalSeconds: number;\n endsAt: number;\n remainingSeconds: number;\n type: CountdownClockType;\n } | null>(null);\n const [shots, setShots] = useState<\n Array<{\n id: number;\n kind: ProjectileKind;\n direction: ProjectileDirection;\n }>\n >([]);\n const [localBubble, setLocalBubble] = useState<string | null>(null);\n const [buddyBubble, setBuddyBubble] = useState<string | null>(null);\n const bubbleTimersRef = useRef<{\n local: NodeJS.Timeout | null;\n buddy: NodeJS.Timeout | null;\n }>({ local: null, buddy: null });\n\n const tcpOptions = useMemo(() => {\n return props.role === \"host\"\n ? ({ role: \"host\", localName: props.localName } as const)\n : ({\n role: \"client\",\n localName: props.localName,\n hostIp: props.hostIp,\n tcpPort: props.tcpPort,\n hostName: props.hostName,\n } as const);\n }, [\n props.role,\n props.localName,\n props.role === \"client\" ? props.hostIp : \"\",\n props.role === \"client\" ? props.tcpPort : 0,\n props.role === \"client\" ? props.hostName : \"\",\n ]);\n\n const tcp = useTcpSync(tcpOptions);\n\n const broadcasterOptions = useMemo(() => {\n return props.role === \"host\"\n ? ({\n enabled: true,\n hostName: props.localName,\n roomName,\n tcpPort: tcp.listenPort,\n } as const)\n : ({ enabled: false } as const);\n }, [props.role, props.localName, roomName, tcp.listenPort]);\n\n useBroadcaster(broadcasterOptions);\n\n const localActivity = useActivityMonitor();\n\n // Use peers array from TCP sync for multi-peer support\n const peers = tcp.peers;\n const firstPeerName = peers.length > 0 ? peers[0].name : undefined;\n\n const onToggleAi = useCallback(() => setShowAi((v) => !v), []);\n const onCloseAi = useCallback(() => setShowAi(false), []);\n\n const sessionStartAtRef = useRef<number>(Date.now());\n const connectedStartAtRef = useRef<number | null>(null);\n const connectedTotalMsRef = useRef<number>(0);\n const keyPressesRef = useRef<number>(0);\n const useGlobalKeyboardRef = useRef<boolean>(false);\n\n const countKeyPress = useCallback(() => {\n keyPressesRef.current += 1;\n }, []);\n\n // Count terminal key presses unless global keyboard listener is active.\n useInput(\n () => {\n if (!useGlobalKeyboardRef.current) countKeyPress();\n },\n { isActive: true }\n );\n\n // If `TERMBUDDY_ACTIVITY_SOURCE=keyboard`, count global key presses.\n useEffect(() => {\n const raw = process.env.TERMBUDDY_ACTIVITY_SOURCE ?? \"ink\";\n const source = raw === \"xinput\" ? \"keyboard\" : raw;\n if (source !== \"keyboard\") return;\n\n let cancelled = false;\n let unsub: (() => void) | null = null;\n void (async () => {\n const ok = await ensureGlobalKeyboard();\n if (cancelled) return;\n if (!ok) return;\n useGlobalKeyboardRef.current = true;\n unsub = subscribeGlobalKeydown(countKeyPress);\n })();\n\n return () => {\n cancelled = true;\n unsub?.();\n useGlobalKeyboardRef.current = false;\n };\n }, [countKeyPress]);\n\n // Track connected time.\n useEffect(() => {\n if (tcp.status === \"connected\") {\n if (connectedStartAtRef.current === null) {\n connectedStartAtRef.current = Date.now();\n }\n return;\n }\n\n if (connectedStartAtRef.current !== null) {\n connectedTotalMsRef.current += Date.now() - connectedStartAtRef.current;\n connectedStartAtRef.current = null;\n }\n }, [tcp.status]);\n\n const finishAndLeave = useCallback(() => {\n const endedAt = Date.now();\n let connectedDurationMs = connectedTotalMsRef.current;\n if (connectedStartAtRef.current !== null) {\n connectedDurationMs += endedAt - connectedStartAtRef.current;\n }\n\n const stats: LeaveStats = {\n keyPresses: keyPressesRef.current,\n sessionDurationMs: endedAt - sessionStartAtRef.current,\n connectedDurationMs,\n startedAt: sessionStartAtRef.current,\n endedAt,\n peerName: firstPeerName,\n };\n props.onLeave(stats);\n }, [props, firstPeerName]);\n\n const startCountdown = useCallback((minutes: number) => {\n const totalSeconds = Math.max(1, Math.floor(minutes * 60));\n const endsAt = Date.now() + totalSeconds * 1000;\n const type: CountdownClockType =\n minutes <= 10 ? \"SHORT\" : minutes <= 30 ? \"MEDIUM\" : \"LONG\";\n setCountdown({\n minutes,\n totalSeconds,\n endsAt,\n remainingSeconds: totalSeconds,\n type,\n });\n }, []);\n\n const nextShotIdRef = useRef<number>(1);\n const shotQueueRef = useRef<\n Array<{ kind: ProjectileKind; direction: ProjectileDirection }>\n >([]);\n\n const pumpShotQueue = useCallback(() => {\n setShots((prev) => {\n if (prev.length >= 1) return prev;\n const next = shotQueueRef.current.shift();\n if (!next) return prev;\n const id = nextShotIdRef.current++;\n return [...prev, { id, kind: next.kind, direction: next.direction }];\n });\n }, []);\n\n useEffect(() => {\n if (shots.length === 0) pumpShotQueue();\n }, [shots.length, pumpShotQueue]);\n\n const throwProjectile = useCallback(\n (kind: ProjectileKind, direction: ProjectileDirection) => {\n shotQueueRef.current.push({ kind, direction });\n pumpShotQueue();\n if (tcp.status === \"connected\") tcp.sendProjectile(kind, direction);\n },\n [pumpShotQueue, tcp]\n );\n\n const showBubble = useCallback(\n (args: { text: string; target: \"local\" | \"buddy\"; durationMs: number }) => {\n const text = args.text.trim();\n if (!text) return;\n const durationMs = Math.max(300, Math.min(15_000, Math.floor(args.durationMs)));\n\n const setBubble = args.target === \"buddy\" ? setBuddyBubble : setLocalBubble;\n setBubble(text);\n\n const prevTimer =\n args.target === \"buddy\"\n ? bubbleTimersRef.current.buddy\n : bubbleTimersRef.current.local;\n if (prevTimer) clearTimeout(prevTimer);\n\n const handle = setTimeout(() => {\n setBubble(null);\n if (args.target === \"buddy\") bubbleTimersRef.current.buddy = null;\n else bubbleTimersRef.current.local = null;\n }, durationMs);\n\n if (args.target === \"buddy\") bubbleTimersRef.current.buddy = handle;\n else bubbleTimersRef.current.local = handle;\n },\n []\n );\n\n useInput(\n (input, key) => {\n if (input === \"q\") finishAndLeave();\n if (input === \"/\" && !key.ctrl && !key.meta) onToggleAi();\n },\n { isActive: !showAi }\n );\n\n useInput(\n (input) => {\n if (input === \"x\") setCountdown(null);\n },\n { isActive: !showAi && countdown !== null }\n );\n\n const localState = localActivity.state;\n const localLabel =\n props.role === \"host\"\n ? `${props.localName} (Host)`\n : `${props.localName} (Client)`;\n\n // Sync local activity state to peer.\n useEffect(() => {\n if (tcp.status !== \"connected\") return;\n tcp.sendStatus(localState);\n }, [localState, tcp.status, tcp.sendStatus]);\n\n // Handle incoming projectiles from peer (flip direction)\n useEffect(() => {\n const handleRemoteProjectile = (kind: ProjectileKind, direction: ProjectileDirection, _senderName?: string) => {\n const flippedDirection: ProjectileDirection =\n direction === \"LEFT_TO_RIGHT\" ? \"RIGHT_TO_LEFT\" : \"LEFT_TO_RIGHT\";\n shotQueueRef.current.push({ kind, direction: flippedDirection });\n pumpShotQueue();\n };\n\n tcp.setOnRemoteProjectile(handleRemoteProjectile);\n }, [tcp, pumpShotQueue]);\n\n useEffect(() => {\n if (!countdown) return;\n const endsAt = countdown.endsAt;\n const handle = setInterval(() => {\n const remaining = Math.max(0, Math.ceil((endsAt - Date.now()) / 1000));\n setCountdown((prev) => {\n if (!prev) return prev;\n if (prev.endsAt !== endsAt) return prev;\n if (remaining <= 0) return null;\n if (prev.remainingSeconds === remaining) return prev;\n return { ...prev, remainingSeconds: remaining };\n });\n }, 250);\n return () => clearInterval(handle);\n }, [countdown?.endsAt]);\n\n useEffect(() => {\n return () => {\n if (bubbleTimersRef.current.local) clearTimeout(bubbleTimersRef.current.local);\n if (bubbleTimersRef.current.buddy) clearTimeout(bubbleTimersRef.current.buddy);\n };\n }, []);\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <StatusHeader\n role={props.role}\n status={tcp.status}\n hostIp={props.role === \"client\" ? props.hostIp : undefined}\n tcpPort={props.role === \"client\" ? props.tcpPort : tcp.listenPort}\n peerCount={peers.length}\n />\n\n {/* Main Stage: 3 Columns */}\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n marginTop={1}\n gap={2}\n >\n {/* Left: Local User */}\n <Box flexDirection=\"column\" alignItems=\"center\" minWidth={20}>\n {countdown ? (\n <Box flexDirection=\"column\" alignItems=\"center\" marginBottom={0}>\n <Text color=\"gray\">{formatMMSS(countdown.remainingSeconds)}</Text>\n <CountdownClockSprite\n variant=\"COMPACT\"\n type={countdown.type}\n minutes={countdown.minutes}\n totalSeconds={countdown.totalSeconds}\n remainingSeconds={countdown.remainingSeconds}\n showLabel={false}\n />\n </Box>\n ) : (\n <Box height={4} />\n )}\n <BuddyAvatar state={localState} marginTop={0} bubbleText={localBubble} />\n <Text color=\"cyan\">{localLabel}</Text>\n </Box>\n\n {/* Center: Stage (Projectiles only) */}\n <Box\n flexDirection=\"column\"\n alignItems=\"center\"\n flexGrow={1}\n minWidth={40}\n >\n {/* Projectile Area */}\n <Box flexDirection=\"column\" width=\"100%\" alignItems=\"center\">\n {shots.map((s) => (\n <ProjectileThrowSprite\n key={String(s.id)}\n kind={s.kind}\n direction={s.direction}\n shotId={s.id}\n width={36}\n onDone={() =>\n setShots((prev) => prev.filter((x) => x.id !== s.id))\n }\n />\n ))}\n {/* Spacer to maintain layout stability when shots appear/disappear */}\n {shots.length === 0 ? <Box height={1} /> : null}\n </Box>\n </Box>\n\n {/* Right: Remote Users */}\n <Box flexDirection=\"column\" alignItems=\"center\" minWidth={20}>\n {peers.length === 0 ? (\n <>\n <Box height={4} />\n <BuddyAvatar state=\"OFFLINE\" marginTop={0} bubbleText={buddyBubble} />\n <Text color=\"gray\">Waiting...</Text>\n </>\n ) : (\n <Box flexDirection=\"row\" gap={2} flexWrap=\"wrap\" justifyContent=\"center\">\n {peers.slice(0, 4).map((peer) => (\n <Box key={peer.id} flexDirection=\"column\" alignItems=\"center\">\n <BuddyAvatar state={peer.state} marginTop={0} bubbleText={buddyBubble} />\n <Text color=\"magenta\">{peer.name}</Text>\n </Box>\n ))}\n {peers.length > 4 && (\n <Text color=\"gray\">+{peers.length - 4} more</Text>\n )}\n </Box>\n )}\n </Box>\n </Box>\n\n {/* Footer Instructions (Hide when AI is open to save space) */}\n {!showAi ? (\n <Box marginTop={1} justifyContent=\"center\">\n <Text color=\"gray\">\n 按 <Text color=\"cyan\">/</Text> 召唤 AI Console,按{\" \"}\n <Text color=\"cyan\">q</Text> 结束本次陪伴。\n {countdown ? (\n <>\n {\" \"}\n <Text color=\"gray\">\n (倒计时中:按 <Text color=\"cyan\">x</Text> 取消)\n </Text>\n </>\n ) : null}\n </Text>\n </Box>\n ) : null}\n\n {/* AI Console Overlay */}\n {showAi ? (\n <Box\n marginTop={1}\n width=\"100%\"\n flexDirection=\"row\"\n justifyContent=\"center\"\n >\n <Box width={64}>\n <AiConsole\n onClose={onCloseAi}\n onStartCountdown={startCountdown}\n onShowBubble={showBubble}\n onThrowProjectile={throwProjectile}\n localName={props.localName}\n peerName={\n firstPeerName ??\n (props.role === \"client\" ? props.hostName : undefined) ??\n \"Buddy\"\n }\n />\n </Box>\n </Box>\n ) : null}\n </Box>\n );\n}\n","export { MainMenu } from \"./MainMenu.js\";\nexport { NicknamePrompt } from \"./NicknamePrompt.js\";\nexport { RoomScanner } from \"./RoomScanner.js\";\nexport { LeavePage } from \"./LeavePage.js\";\nexport { Session } from \"./Session.js\";\n","import React, { useCallback, useMemo, useState } from \"react\";\nimport os from \"node:os\";\nimport { useApp } from \"ink\";\nimport {\n LeavePage,\n MainMenu,\n NicknamePrompt,\n RoomScanner,\n Session,\n} from \"../page/index.js\";\nimport type { LeaveStats } from \"../types.js\";\n\ntype View =\n | { name: \"NICKNAME\" }\n | { name: \"MENU\" }\n | { name: \"SCANNING\" }\n | { name: \"LEAVE\"; stats: LeaveStats }\n | { name: \"SESSION\"; role: \"host\" }\n | {\n name: \"SESSION\";\n role: \"client\";\n hostIp: string;\n tcpPort: number;\n roomName: string;\n hostName: string;\n };\n\nexport function App() {\n const { exit } = useApp();\n const [view, setView] = useState<View>({ name: \"NICKNAME\" });\n const [nickname, setNickname] = useState<string | null>(null);\n\n const localName = useMemo(() => nickname ?? os.hostname(), [nickname]);\n\n const goMenu = useCallback(() => setView({ name: \"MENU\" }), []);\n\n if (view.name === \"NICKNAME\") {\n return (\n <NicknamePrompt\n onExit={() => exit()}\n onSubmit={(name) => {\n setNickname(name);\n setView({ name: \"MENU\" });\n }}\n />\n );\n }\n\n if (view.name === \"MENU\") {\n return (\n <MainMenu\n onHost={() => setView({ name: \"SESSION\", role: \"host\" })}\n onJoin={() => setView({ name: \"SCANNING\" })}\n onExit={() => exit()}\n />\n );\n }\n\n if (view.name === \"LEAVE\") {\n return (\n <LeavePage stats={view.stats} onBack={goMenu} onExit={() => exit()} />\n );\n }\n\n if (view.name === \"SCANNING\") {\n return (\n <RoomScanner\n onBack={goMenu}\n onExit={() => exit()}\n onSelectRoom={(room) =>\n setView({\n name: \"SESSION\",\n role: \"client\",\n hostIp: room.ip,\n tcpPort: room.tcpPort,\n roomName: room.roomName,\n hostName: room.hostName,\n })\n }\n />\n );\n }\n\n if (view.name === \"SESSION\" && view.role === \"host\") {\n return (\n <Session\n localName={localName}\n role=\"host\"\n onLeave={(stats) => setView({ name: \"LEAVE\", stats })}\n />\n );\n }\n\n return (\n <Session\n localName={localName}\n role=\"client\"\n onLeave={(stats) => setView({ name: \"LEAVE\", stats })}\n hostIp={view.hostIp}\n tcpPort={view.tcpPort}\n roomName={view.roomName}\n hostName={view.hostName}\n />\n );\n}\n","export { App } from \"./App.js\";\n","process.env.NODE_ENV ??= 'production';\n\nconst React = await import('react');\nconst {render} = await import('ink');\nconst {App} = await import('./app/index.js');\n\nrender(React.createElement(App));\n"],"mappings":"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","names":["Box","Text","useInput","jsx","jsxs","useState","useInput","tool","tool","tool","useCallback","useEffect","useRef","useState","os","useEffect","useEffect","useState","dgram","useCallback","useEffect","useRef","useState","socket","useMemo","Box","Text","useInput","jsx","jsxs","useMemo","Box","Text","useInput","jsx","jsxs","useEffect","useMemo","useState","Box","Text","useInput","jsx","jsxs","useMemo","Box","Text","jsx","Box","Text","jsx","jsxs","useMemo","Box","Text","jsx","jsxs","face","useEffect","useMemo","useState","Box","Text","jsx","jsxs","clamp01","Box","Text","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useState","Box","Text","useInput","Fragment","jsx","jsxs","useCallback","useMemo","useState","os","jsx","React","App"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@three333/termbuddy",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -102,20 +102,9 @@ export function Session(
102
102
 
103
103
  const localActivity = useActivityMonitor();
104
104
 
105
- // Fix: Derive peers from single peerName until multi-peer is supported
106
- const peers = useMemo(() => {
107
- return tcp.peerName
108
- ? [
109
- {
110
- id: "remote",
111
- name: tcp.peerName,
112
- state: tcp.remoteState ?? ("OFFLINE" as const),
113
- },
114
- ]
115
- : [];
116
- }, [tcp.peerName, tcp.remoteState]);
117
-
118
- const firstPeerName = tcp.peerName;
105
+ // Use peers array from TCP sync for multi-peer support
106
+ const peers = tcp.peers;
107
+ const firstPeerName = peers.length > 0 ? peers[0].name : undefined;
119
108
 
120
109
  const onToggleAi = useCallback(() => setShowAi((v) => !v), []);
121
110
  const onCloseAi = useCallback(() => setShowAi(false), []);