@matheuskrumenauer/tanya 0.17.0 → 0.17.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ import {
13
13
  sessionToInkMessages,
14
14
  startChatSession,
15
15
  statsToInkStats
16
- } from "./chunk-5PSV2Y3X.js";
16
+ } from "./chunk-3NV2QP7J.js";
17
17
 
18
18
  // src/ui/ink/runInkChat.tsx
19
19
  import { render } from "ink";
@@ -22,6 +22,14 @@ import { render } from "ink";
22
22
  import { useEffect as useEffect2, useReducer, useRef as useRef2 } from "react";
23
23
  import { Box as Box7, useApp } from "ink";
24
24
 
25
+ // src/agent/compression.ts
26
+ function estimateTokens(messages) {
27
+ return messages.reduce((sum, msg) => {
28
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content ?? "");
29
+ return sum + Math.ceil(text.length / 4);
30
+ }, 0);
31
+ }
32
+
25
33
  // src/ui/ink/Footer.tsx
26
34
  import { Box, Text } from "ink";
27
35
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -37,11 +45,22 @@ function formatFooterCost(costUsd) {
37
45
  if (costUsd === 0) return "$0.00";
38
46
  return formatUsd(costUsd);
39
47
  }
40
- function Footer({ provider, model, sessionStartMs, stats, now, showColdStartHint = false }) {
41
- const cost = formatFooterCost(stats.costUsd);
48
+ function inflightTokenTotal(inflight) {
49
+ if (!inflight) return 0;
50
+ return inflight.promptTokens + inflight.completionTokens + inflight.reasoningTokens;
51
+ }
52
+ function Footer({ provider, model, sessionStartMs, stats, inflight, now, showColdStartHint = false }) {
53
+ const inflightTokens = inflightTokenTotal(inflight);
54
+ const inflightCost = inflight?.costUsd ?? 0;
55
+ const baseCost = stats.costUsd ?? 0;
56
+ const liveCost = inflightTokens > 0 || inflightCost > 0 ? baseCost + inflightCost : stats.costUsd;
57
+ const baseTokens = stats.totalTokens ?? 0;
58
+ const liveTokens = inflightTokens > 0 ? baseTokens + inflightTokens : stats.totalTokens;
59
+ const livePrefix = inflightTokens > 0 ? "~" : "";
60
+ const cost = formatFooterCost(liveCost);
42
61
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
43
62
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: divider }),
44
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: showColdStartHint ? "First turn may take ~30-60s on DeepSeek V4-Pro (cold-start + skill loading)." : `${provider}:${model} \xB7 session ${formatElapsed(now - sessionStartMs)} \xB7 ${cost} \xB7 ${formatTokens(stats.totalTokens)} \xB7 /help` })
63
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: showColdStartHint ? "First turn may take ~30-60s on DeepSeek V4-Pro (cold-start + skill loading)." : `${provider}:${model} \xB7 session ${formatElapsed(now - sessionStartMs)} \xB7 ${livePrefix}${cost} \xB7 ${livePrefix}${formatTokens(liveTokens)} \xB7 /help` })
45
64
  ] });
46
65
  }
47
66
 
@@ -325,8 +344,19 @@ function createInkSink(dispatch, options) {
325
344
  let reasoningFlushHandle = null;
326
345
  let reasoningStartedAt = null;
327
346
  let streamedTokenChars = 0;
347
+ let streamedReasoningChars = 0;
348
+ let lastProgressCompletionTokens = 0;
349
+ let lastProgressReasoningTokens = 0;
328
350
  let toolCount = 0;
329
351
  const flushIntervalMs = options.flushIntervalMs ?? 30;
352
+ const dispatchProgressEstimate = () => {
353
+ const completionTokens = Math.ceil(streamedTokenChars / 4);
354
+ const reasoningTokens = Math.ceil(streamedReasoningChars / 4);
355
+ if (completionTokens === lastProgressCompletionTokens && reasoningTokens === lastProgressReasoningTokens) return;
356
+ lastProgressCompletionTokens = completionTokens;
357
+ lastProgressReasoningTokens = reasoningTokens;
358
+ dispatch({ type: "turn_progress", completionTokens, reasoningTokens });
359
+ };
330
360
  const ensureAssistant = () => {
331
361
  if (assistantId) return assistantId;
332
362
  const timestampMs = Date.now();
@@ -397,6 +427,7 @@ function createInkSink(dispatch, options) {
397
427
  ensureAssistant();
398
428
  buffer += event.text;
399
429
  streamedTokenChars += event.text.length;
430
+ dispatchProgressEstimate();
400
431
  scheduleFlush();
401
432
  break;
402
433
  }
@@ -405,6 +436,8 @@ function createInkSink(dispatch, options) {
405
436
  break;
406
437
  case "reasoning_chunk":
407
438
  reasoningBuffer += event.content;
439
+ streamedReasoningChars += event.content.length;
440
+ dispatchProgressEstimate();
408
441
  scheduleReasoningFlush();
409
442
  break;
410
443
  case "tool_call": {
@@ -509,6 +542,26 @@ function formatToolValue(value) {
509
542
  }
510
543
 
511
544
  // src/ui/ink/state.ts
545
+ var EMPTY_INFLIGHT = { promptTokens: 0, completionTokens: 0, reasoningTokens: 0, costUsd: 0 };
546
+ function computeInflight(state, partial, previous) {
547
+ const next = {
548
+ promptTokens: partial.promptTokens ?? previous.promptTokens,
549
+ completionTokens: partial.completionTokens ?? previous.completionTokens,
550
+ reasoningTokens: partial.reasoningTokens ?? previous.reasoningTokens,
551
+ costUsd: previous.costUsd
552
+ };
553
+ if (state.provider && state.model) {
554
+ const cost = estimateRunCost({
555
+ provider: state.provider,
556
+ model: state.model,
557
+ promptTokens: next.promptTokens,
558
+ completionTokens: next.completionTokens,
559
+ reasoningTokens: next.reasoningTokens
560
+ });
561
+ next.costUsd = cost.usd;
562
+ }
563
+ return next;
564
+ }
512
565
  function createInitialInkState(options = {}) {
513
566
  const now = options.now ?? Date.now();
514
567
  const warmupMessages = options.provider && options.model ? [{
@@ -528,6 +581,9 @@ function createInitialInkState(options = {}) {
528
581
  sessionGenerateMs: options.initialGenerateMs ?? 0,
529
582
  turnCount: options.initialTurnCount ?? 0,
530
583
  stats: options.initialStats ?? { costUsd: 0, totalTokens: 0 },
584
+ inflight: { ...EMPTY_INFLIGHT },
585
+ provider: options.provider ?? "",
586
+ model: options.model ?? "",
531
587
  pendingPermission: null
532
588
  };
533
589
  }
@@ -590,7 +646,9 @@ function inkReducer(state, action) {
590
646
  };
591
647
  }
592
648
  case "turn_start":
593
- return { ...state, pendingTurn: { startedAt: action.startedAt, spinnerVisible: true }, activityItems: [] };
649
+ return { ...state, pendingTurn: { startedAt: action.startedAt, spinnerVisible: true }, activityItems: [], inflight: { ...EMPTY_INFLIGHT } };
650
+ case "turn_progress":
651
+ return { ...state, inflight: computeInflight(state, action, state.inflight) };
594
652
  case "turn_complete": {
595
653
  const turnTokens = (action.promptTokens ?? 0) + (action.completionTokens ?? 0) + (action.reasoningTokens ?? 0);
596
654
  const currentCost = state.stats.costUsd ?? 0;
@@ -605,7 +663,8 @@ function inkReducer(state, action) {
605
663
  stats: {
606
664
  costUsd: action.costUsd === null || action.costUsd === void 0 ? state.stats.costUsd : currentCost + action.costUsd,
607
665
  totalTokens: turnTokens > 0 ? currentTokens + turnTokens : state.stats.totalTokens
608
- }
666
+ },
667
+ inflight: { ...EMPTY_INFLIGHT }
609
668
  };
610
669
  }
611
670
  case "turn_error":
@@ -614,6 +673,7 @@ function inkReducer(state, action) {
614
673
  liveAssistantId: null,
615
674
  pendingTurn: null,
616
675
  activityItems: [],
676
+ inflight: { ...EMPTY_INFLIGHT },
617
677
  messages: [...state.messages, {
618
678
  id: `error-${Date.now()}-${state.messages.length}`,
619
679
  role: "system",
@@ -650,7 +710,8 @@ function inkReducer(state, action) {
650
710
  activityItems: [],
651
711
  sessionGenerateMs: action.generateMs,
652
712
  turnCount: action.turnCount,
653
- stats: action.stats
713
+ stats: action.stats,
714
+ inflight: { ...EMPTY_INFLIGHT }
654
715
  };
655
716
  case "clear":
656
717
  return { ...state, messages: [], assistantMessageIndexes: {}, liveAssistantId: null, activityItems: [] };
@@ -810,6 +871,11 @@ function App({
810
871
  dispatch({ type: "user_message", content: prompt, timestampMs });
811
872
  const startedAt = Date.now();
812
873
  dispatch({ type: "turn_start", startedAt });
874
+ const estimatedPromptTokens = estimateTokens([
875
+ ...historyRef.current,
876
+ { role: "user", content: prompt }
877
+ ]);
878
+ dispatch({ type: "turn_progress", promptTokens: estimatedPromptTokens });
813
879
  const abortController = new AbortController();
814
880
  activeAbortController.current = abortController;
815
881
  try {
@@ -866,8 +932,9 @@ function App({
866
932
  model: provider.model,
867
933
  sessionStartMs: state.sessionStartMs,
868
934
  stats: state.stats,
935
+ inflight: state.inflight,
869
936
  now,
870
- showColdStartHint: state.turnCount === 0
937
+ showColdStartHint: state.turnCount === 0 && state.pendingTurn === null
871
938
  }
872
939
  )
873
940
  ] });
@@ -947,4 +1014,4 @@ async function startInkChat(options) {
947
1014
  export {
948
1015
  startInkChat
949
1016
  };
950
- //# sourceMappingURL=runInkChat-AZFI7553.js.map
1017
+ //# sourceMappingURL=runInkChat-SVBEQCQ4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/ink/runInkChat.tsx","../src/ui/ink/App.tsx","../src/agent/compression.ts","../src/ui/ink/Footer.tsx","../src/ui/ink/History.tsx","../src/ui/ink/markdown.tsx","../src/ui/ink/Input.tsx","../src/ui/ink/Spinner.tsx","../src/ui/ink/PermissionPrompt.tsx","../src/ui/ink/ActivityPanel.tsx","../src/ui/ink/sinkAdapter.ts","../src/ui/ink/state.ts","../src/ui/ink/useSessionTicker.ts"],"sourcesContent":["import React from \"react\";\nimport { render } from \"ink\";\nimport type { ChatProvider } from \"../../providers/types\";\nimport type { RunAgentOptions } from \"../../agent/runner\";\nimport { App } from \"./App\";\nimport {\n resumeBanner,\n sessionToChatHistory,\n sessionToInkMessages,\n startChatSession,\n statsToInkStats,\n} from \"../../sessions/repl\";\nimport type { InkMessage } from \"./types\";\n\nexport async function startInkChat(options: {\n provider: ChatProvider;\n cwd: string;\n routing?: RunAgentOptions[\"routing\"];\n continueSession?: boolean | undefined;\n resumeSessionId?: string | undefined;\n}): Promise<void> {\n const sessionStart = startChatSession({\n cwd: options.cwd,\n provider: options.provider.id,\n model: options.provider.model,\n continueSession: options.continueSession,\n resumeSessionId: options.resumeSessionId,\n });\n const initialMessages: InkMessage[] = [];\n if (sessionStart.notice) {\n initialMessages.push({\n id: `session-notice-${Date.now()}`,\n role: \"system\",\n content: sessionStart.notice,\n timestampMs: Date.now(),\n });\n }\n if (sessionStart.resumedSession) {\n initialMessages.push({\n id: `session-banner-${sessionStart.resumedSession.id}`,\n role: \"system\",\n content: resumeBanner(sessionStart.resumedSession),\n timestampMs: Date.now(),\n });\n initialMessages.push(...sessionToInkMessages(sessionStart.resumedSession, 10));\n }\n let summary = \"\";\n const instance = render(\n <App\n provider={options.provider}\n cwd={options.cwd}\n {...(options.routing ? { routing: options.routing } : {})}\n sessionController={sessionStart.controller}\n initialMessages={initialMessages}\n initialHistory={sessionStart.resumedSession ? sessionToChatHistory(sessionStart.resumedSession) : []}\n initialStats={statsToInkStats(sessionStart.controller.session.sessionStats)}\n initialGenerateMs={sessionStart.controller.session.sessionStats.generateMs}\n initialTurnCount={sessionStart.controller.session.sessionStats.turnCount}\n onExitSummary={(line) => {\n summary = line;\n }}\n />,\n { exitOnCtrlC: false },\n );\n await instance.waitUntilExit();\n if (summary) process.stdout.write(`${summary}\\n`);\n}\n","import React, { useEffect, useReducer, useRef } from \"react\";\nimport { Box, useApp } from \"ink\";\nimport { runAgent } from \"../../agent/runner\";\nimport { estimateTokens } from \"../../agent/compression\";\nimport type { ChatProvider } from \"../../providers/types\";\nimport type { ChatMessage } from \"../../providers/types\";\nimport type { RunAgentOptions } from \"../../agent/runner\";\nimport type { HostPermissionAnswer, PermissionRequestHandler } from \"../../safety/permissions/host\";\nimport { dispatchInteractiveCommand } from \"../../agent/chat\";\nimport { loadProjectCommands } from \"../../commands/project\";\nimport { listCommands } from \"../../commands/registry\";\nimport { formatElapsed } from \"../../utils/formatElapsed\";\nimport { Footer } from \"./Footer\";\nimport { History } from \"./History\";\nimport { Input } from \"./Input\";\nimport { PermissionPrompt } from \"./PermissionPrompt\";\nimport { ActivityPanel } from \"./ActivityPanel\";\nimport { createInkSink } from \"./sinkAdapter\";\nimport { createInitialInkState, inkReducer, type InkAction, type InkState } from \"./state\";\nimport type { InkMessage, InkSessionStats } from \"./types\";\nimport { useSessionTicker } from \"./useSessionTicker\";\nimport {\n resumeBanner,\n sessionToInkMessages,\n statsToInkStats,\n type ChatSessionController,\n} from \"../../sessions/repl\";\nimport type { ChatSession } from \"../../sessions/types\";\n\nfunction createInkCommandOutput(dispatch: React.Dispatch<InkAction>): NodeJS.WritableStream {\n return {\n write(chunk: unknown) {\n const content = String(chunk).trimEnd();\n if (content) dispatch({ type: \"system_message\", content });\n return true;\n },\n } as NodeJS.WritableStream;\n}\n\nfunction sessionSummary(state: InkState): string {\n return `Session: ${formatElapsed(Date.now() - state.sessionStartMs)} elapsed · ${formatElapsed(state.sessionGenerateMs)} generating · ${state.turnCount} turn${state.turnCount === 1 ? \"\" : \"s\"}`;\n}\n\nexport function App({\n provider,\n cwd,\n routing,\n initialMessages = [],\n initialHistory,\n initialStats,\n initialGenerateMs,\n initialTurnCount,\n sessionController,\n onSubmit,\n onExitSummary,\n}: {\n provider: ChatProvider;\n cwd: string;\n routing?: RunAgentOptions[\"routing\"];\n initialMessages?: InkMessage[] | undefined;\n initialHistory?: ChatMessage[] | undefined;\n initialStats?: InkSessionStats | undefined;\n initialGenerateMs?: number | undefined;\n initialTurnCount?: number | undefined;\n sessionController?: ChatSessionController | undefined;\n onSubmit?: (value: string) => void;\n onExitSummary?: (summary: string) => void;\n}) {\n const app = useApp();\n const [state, dispatch] = useReducer(\n inkReducer,\n {\n provider: provider.id,\n model: provider.model,\n initialMessages,\n initialStats,\n initialGenerateMs,\n initialTurnCount,\n },\n createInitialInkState,\n );\n const historyRef = useRef<ChatMessage[]>(initialHistory ?? []);\n const stateRef = useRef(state);\n const activeAbortController = useRef<AbortController | null>(null);\n const permissionResolver = useRef<((answer: HostPermissionAnswer) => void) | null>(null);\n const now = useSessionTicker(1000);\n\n useEffect(() => {\n stateRef.current = state;\n }, [state]);\n\n useEffect(() => {\n const handleBeforeExit = () => {\n try {\n sessionController?.materialize();\n } catch {\n // Session materialization should not mask process shutdown.\n }\n };\n process.on(\"beforeExit\", handleBeforeExit);\n return () => {\n process.off(\"beforeExit\", handleBeforeExit);\n handleBeforeExit();\n };\n }, [sessionController]);\n\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n await loadProjectCommands(cwd);\n if (cancelled) return;\n const projectCommandCount = listCommands().filter((command) => command.category === \"project\").length;\n dispatch({ type: \"system_message\", content: `Tanya · loaded ${projectCommandCount} project command${projectCommandCount === 1 ? \"\" : \"s\"} · ready.` });\n })();\n return () => {\n cancelled = true;\n };\n }, [cwd]);\n\n const handlePermissionRequest: PermissionRequestHandler = async (request) => {\n return new Promise((resolve) => {\n permissionResolver.current = resolve;\n dispatch({ type: \"permission_request\", request });\n });\n };\n\n const answerPermission = (answer: HostPermissionAnswer) => {\n const resolve = permissionResolver.current;\n permissionResolver.current = null;\n dispatch({ type: \"permission_clear\" });\n resolve?.(answer);\n };\n\n const handleExit = () => {\n if (stateRef.current.pendingPermission) {\n answerPermission({ decision: \"deny\" });\n dispatch({ type: \"system_message\", content: \"Denied pending permission request.\" });\n return;\n }\n if (activeAbortController.current && !activeAbortController.current.signal.aborted) {\n activeAbortController.current.abort();\n dispatch({ type: \"system_message\", content: \"Cancelled active run.\" });\n return;\n }\n try {\n sessionController?.materialize();\n } catch {\n // Session materialization should not mask UI exit.\n }\n onExitSummary?.(sessionSummary(stateRef.current));\n app.exit();\n };\n\n const handleSubmit = (value: string) => {\n if (onSubmit) {\n onSubmit(value);\n return;\n }\n void (async () => {\n const prompt = value.trim();\n if (!prompt) return;\n if (prompt.startsWith(\"/\")) {\n const output = createInkCommandOutput(dispatch);\n await dispatchInteractiveCommand(prompt, {\n provider,\n cwd,\n sink: async () => {},\n output,\n history: historyRef.current,\n ...(routing ? { routing } : {}),\n sessionController,\n clearHistory: () => {\n historyRef.current.length = 0;\n dispatch({ type: \"clear\" });\n },\n replaceHistory: (nextHistory) => {\n historyRef.current = nextHistory;\n },\n onSessionResumed: (session) => {\n replaceRenderedSession(dispatch, session);\n },\n onPermissionRequest: handlePermissionRequest,\n });\n return;\n }\n const timestampMs = Date.now();\n dispatch({ type: \"user_message\", content: prompt, timestampMs });\n const startedAt = Date.now();\n dispatch({ type: \"turn_start\", startedAt });\n const estimatedPromptTokens = estimateTokens([\n ...historyRef.current,\n { role: \"user\", content: prompt },\n ]);\n dispatch({ type: \"turn_progress\", promptTokens: estimatedPromptTokens });\n const abortController = new AbortController();\n activeAbortController.current = abortController;\n try {\n const sink = createInkSink(dispatch, {\n provider: provider.id,\n model: provider.model,\n startedAt,\n });\n const result = await runAgent({\n provider,\n prompt,\n cwd,\n sink,\n history: historyRef.current,\n signal: abortController.signal,\n onPermissionRequest: handlePermissionRequest,\n ...(routing ? { routing } : {}),\n });\n historyRef.current.push({ role: \"user\", content: prompt });\n historyRef.current.push({ role: \"assistant\", content: result.message });\n sessionController?.appendCompletedTurn(prompt, result.message, startedAt, Date.now() - startedAt, result);\n } catch (error) {\n dispatch({ type: \"turn_error\", message: error instanceof Error ? error.message : String(error) });\n } finally {\n activeAbortController.current = null;\n }\n })();\n };\n\n return (\n <Box flexDirection=\"column\" height=\"100%\" minHeight={8}>\n <History\n messages={state.messages}\n pendingTurn={state.pendingTurn}\n liveAssistantId={state.liveAssistantId}\n />\n <ActivityPanel items={state.activityItems} />\n <PermissionPrompt request={state.pendingPermission} onAnswer={answerPermission} />\n <Input\n disabled={state.pendingTurn !== null || state.pendingPermission !== null}\n {...(state.pendingTurn?.spinnerVisible ? { pendingStartedAt: state.pendingTurn.startedAt } : {})}\n now={now}\n onSubmit={handleSubmit}\n onExit={handleExit}\n />\n <Footer\n provider={provider.id}\n model={provider.model}\n sessionStartMs={state.sessionStartMs}\n stats={state.stats}\n inflight={state.inflight}\n now={now}\n showColdStartHint={state.turnCount === 0 && state.pendingTurn === null}\n />\n </Box>\n );\n}\n\nfunction replaceRenderedSession(dispatch: React.Dispatch<InkAction>, session: ChatSession): void {\n const now = Date.now();\n dispatch({\n type: \"replace_session\",\n messages: [\n {\n id: `session-banner-${session.id}-${now}`,\n role: \"system\",\n content: resumeBanner(session),\n timestampMs: now,\n },\n ...sessionToInkMessages(session, 10),\n ],\n stats: statsToInkStats(session.sessionStats),\n generateMs: session.sessionStats.generateMs,\n turnCount: session.sessionStats.turnCount,\n });\n}\n","import type { ChatMessage, ChatProvider } from \"../providers/types\";\n\nexport function estimateTokens(messages: ChatMessage[]): number {\n return messages.reduce((sum, msg) => {\n const text = typeof msg.content === \"string\" ? msg.content : JSON.stringify(msg.content ?? \"\");\n return sum + Math.ceil(text.length / 4);\n }, 0);\n}\n\nexport async function summarizeOldMessages(\n provider: ChatProvider,\n messages: ChatMessage[],\n): Promise<ChatMessage> {\n const text = messages\n .map((message) => {\n const role = message.role.toUpperCase();\n const content = typeof message.content === \"string\" ? message.content : JSON.stringify(message.content ?? \"\");\n return `[${role}]: ${content.slice(0, 800)}`;\n })\n .join(\"\\n\\n\");\n\n try {\n let summary = \"\";\n for await (const delta of provider.streamChat({\n messages: [\n {\n role: \"user\",\n content: `Summarize these agent turns into a compact factual block (max 400 words).\nInclude: what files were read, what edits were made, what commands ran and their outcomes, any blockers hit.\nDo not include reasoning or explanations — only facts.\n\n${text}`,\n },\n ],\n tools: [],\n temperature: 0,\n maxTokens: 512,\n })) {\n if (delta.content) summary += delta.content;\n }\n\n return {\n role: \"user\",\n content: `[CONTEXT SUMMARY — earlier turns compressed to save context]\\n${summary.trim()}\\n[END SUMMARY — continuing task below]`,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`[tanya] Context summarization failed; dropping ${messages.length} older turns without summarization: ${message}`);\n return {\n role: \"user\",\n content: `[CONTEXT SUMMARY — earlier turns dropped to save context]\\nDropped ${messages.length} older turns because summarization failed: ${message}\\n[END SUMMARY — continuing task below]`,\n };\n }\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { formatUsd } from \"../../memory/runLogs\";\nimport { formatElapsed } from \"../../utils/formatElapsed\";\nimport type { InflightTurn } from \"./state\";\nimport type { InkSessionStats } from \"./types\";\n\nconst divider = \"─\".repeat(80);\n\nfunction formatTokens(tokens: number | null): string {\n if (tokens === null) return \"— tokens\";\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M tokens`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}k tokens`;\n return `${tokens} tokens`;\n}\n\nfunction formatFooterCost(costUsd: number | null): string {\n if (costUsd === null) return \"$—\";\n if (costUsd === 0) return \"$0.00\";\n return formatUsd(costUsd);\n}\n\nfunction inflightTokenTotal(inflight: InflightTurn | undefined): number {\n if (!inflight) return 0;\n return inflight.promptTokens + inflight.completionTokens + inflight.reasoningTokens;\n}\n\nexport function Footer({ provider, model, sessionStartMs, stats, inflight, now, showColdStartHint = false }: {\n provider: string;\n model: string;\n sessionStartMs: number;\n stats: InkSessionStats;\n inflight?: InflightTurn;\n now: number;\n showColdStartHint?: boolean;\n}) {\n const inflightTokens = inflightTokenTotal(inflight);\n const inflightCost = inflight?.costUsd ?? 0;\n const baseCost = stats.costUsd ?? 0;\n const liveCost = inflightTokens > 0 || inflightCost > 0 ? baseCost + inflightCost : stats.costUsd;\n const baseTokens = stats.totalTokens ?? 0;\n const liveTokens = inflightTokens > 0 ? baseTokens + inflightTokens : stats.totalTokens;\n const livePrefix = inflightTokens > 0 ? \"~\" : \"\";\n const cost = formatFooterCost(liveCost);\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>{divider}</Text>\n <Text dimColor>\n {showColdStartHint\n ? \"First turn may take ~30-60s on DeepSeek V4-Pro (cold-start + skill loading).\"\n : `${provider}:${model} · session ${formatElapsed(now - sessionStartMs)} · ${livePrefix}${cost} · ${livePrefix}${formatTokens(liveTokens)} · /help`}\n </Text>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Static, Text } from \"ink\";\nimport { formatClock, formatElapsed } from \"../../utils/formatElapsed\";\nimport type { InkMessage } from \"./types\";\nimport type { PendingTurn } from \"./state\";\nimport { MarkdownText } from \"./markdown\";\n\nfunction messagePrefix(message: InkMessage): string {\n const clock = `[${formatClock(new Date(message.timestampMs))}]`;\n if (message.role === \"user\") return `${clock} You:`;\n if (message.role === \"assistant\") {\n return `${clock} Tanya${message.elapsedMs !== undefined ? ` · ${formatElapsed(message.elapsedMs)}` : \"\"}:`;\n }\n if (message.role === \"tool\") return `${clock} tool:`;\n return `${clock} ·`;\n}\n\nconst MessageBlock = React.memo(function MessageBlock({ message, live = false }: { message: InkMessage; live?: boolean }) {\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color={message.role === \"user\" ? \"green\" : message.role === \"assistant\" ? \"cyan\" : \"gray\"}>\n {messagePrefix(message)}\n </Text>\n {message.content\n ? message.role === \"assistant\"\n ? <MarkdownText source={message.content} formatPartialLine={!live} />\n : <Text wrap=\"wrap\">{message.content}</Text>\n : null}\n </Box>\n );\n}, (previous, next) => previous.live === next.live &&\n previous.message.id === next.message.id &&\n previous.message.role === next.message.role &&\n previous.message.elapsedMs === next.message.elapsedMs &&\n previous.message.content.length === next.message.content.length);\n\nexport function splitHistoryMessages(messages: InkMessage[], pendingTurn: PendingTurn | null, liveAssistantId: string | null): {\n finalized: InkMessage[];\n live: InkMessage[];\n} {\n if (!pendingTurn) return { finalized: messages, live: [] };\n\n const finalized: InkMessage[] = [];\n const live: InkMessage[] = [];\n for (const message of messages) {\n if (message.id === liveAssistantId || (message.role === \"system\" && message.timestampMs >= pendingTurn.startedAt)) {\n live.push(message);\n } else {\n finalized.push(message);\n }\n }\n return { finalized, live };\n}\n\nexport function History({ messages, pendingTurn, liveAssistantId }: {\n messages: InkMessage[];\n pendingTurn: PendingTurn | null;\n liveAssistantId: string | null;\n}) {\n const { finalized, live } = splitHistoryMessages(messages, pendingTurn, liveAssistantId);\n return (\n <Box flexDirection=\"column\" flexGrow={1} overflow=\"hidden\">\n {messages.length === 0 ? (\n <Text dimColor>Tanya chat ready.</Text>\n ) : (\n <>\n <Static<InkMessage> items={finalized}>\n {(message) => <MessageBlock key={message.id} message={message} />}\n </Static>\n {live.map((message) => (\n <MessageBlock key={message.id} message={message} live />\n ))}\n </>\n )}\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\n\ntype InlineNode = string | React.ReactElement;\n\nfunction hasBalancedMarkers(line: string, marker: string): boolean {\n return line.split(marker).length % 2 === 1;\n}\n\nfunction renderInline(line: string): InlineNode[] {\n if (\n (line.includes(\"**\") && !hasBalancedMarkers(line, \"**\")) ||\n (line.includes(\"`\") && !hasBalancedMarkers(line, \"`\")) ||\n (line.includes(\"*\") && !line.includes(\"**\") && !hasBalancedMarkers(line, \"*\")) ||\n (line.includes(\"_\") && !hasBalancedMarkers(line, \"_\"))\n ) {\n return [line];\n }\n\n const nodes: InlineNode[] = [];\n const pattern = /(\\*\\*[^*]+\\*\\*|`[^`]+`|\\[[^\\]]+\\]\\([^)]+\\)|\\*[^*]+\\*|_[^_]+_)/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n let key = 0;\n while ((match = pattern.exec(line)) !== null) {\n if (match.index > lastIndex) nodes.push(line.slice(lastIndex, match.index));\n const token = match[0]!;\n if (token.startsWith(\"**\")) {\n nodes.push(<Text key={`b-${key++}`} bold>{token.slice(2, -2)}</Text>);\n } else if (token.startsWith(\"`\")) {\n nodes.push(<Text key={`c-${key++}`} inverse>{token.slice(1, -1)}</Text>);\n } else if (token.startsWith(\"[\")) {\n const linkMatch = token.match(/^\\[([^\\]]+)\\]\\(([^)]+)\\)$/);\n if (linkMatch) {\n nodes.push(\n <React.Fragment key={`l-${key++}`}>\n <Text underline>{linkMatch[1]}</Text>\n <Text dimColor> ({linkMatch[2]})</Text>\n </React.Fragment>,\n );\n }\n } else {\n nodes.push(<Text key={`i-${key++}`} italic>{token.slice(1, -1)}</Text>);\n }\n lastIndex = pattern.lastIndex;\n }\n if (lastIndex < line.length) nodes.push(line.slice(lastIndex));\n return nodes;\n}\n\nfunction renderFormattedLine(line: string, key: string): React.ReactElement {\n if (/^#{1,3}\\s/.test(line)) {\n const [, hashes = \"\", text = \"\"] = line.match(/^(#{1,3})\\s+(.*)$/) ?? [];\n return <Text key={key} bold color={hashes.length === 1 ? \"cyan\" : \"blue\"}>{renderInline(text)}</Text>;\n }\n if (/^\\s*[-*]\\s+/.test(line)) {\n return <Text key={key}>• {renderInline(line.replace(/^\\s*[-*]\\s+/, \"\"))}</Text>;\n }\n if (/^\\s*\\d+\\.\\s+/.test(line)) {\n const marker = line.match(/^\\s*(\\d+\\.)\\s+/)?.[1] ?? \"1.\";\n return <Text key={key}>{marker} {renderInline(line.replace(/^\\s*\\d+\\.\\s+/, \"\"))}</Text>;\n }\n if (/^\\s*>\\s?/.test(line)) {\n return <Text key={key} dimColor italic>│ {renderInline(line.replace(/^\\s*>\\s?/, \"\"))}</Text>;\n }\n return <Text key={key}>{renderInline(line)}</Text>;\n}\n\nexport function MarkdownText({ source, formatPartialLine = false }: { source: string; formatPartialLine?: boolean }) {\n if (!source) return null;\n\n const lines = source.split(\"\\n\");\n const hasTrailingNewline = source.endsWith(\"\\n\");\n const completeLineCount = lines.length - 1;\n const nodes: React.ReactElement[] = [];\n let index = 0;\n\n while (index < completeLineCount) {\n const line = lines[index] ?? \"\";\n if (line.startsWith(\"```\")) {\n const closingIndex = lines.findIndex((candidate, candidateIndex) => candidateIndex > index && candidate.startsWith(\"```\"));\n if (closingIndex > index && closingIndex < lines.length) {\n const code = lines.slice(index + 1, closingIndex).join(\"\\n\");\n nodes.push(\n <Box key={`code-${index}`} borderStyle=\"round\" paddingX={1} flexDirection=\"column\">\n <Text>{code}</Text>\n </Box>,\n );\n index = closingIndex + 1;\n continue;\n }\n }\n nodes.push(renderFormattedLine(line, `line-${index}`));\n index += 1;\n }\n\n if (!hasTrailingNewline) {\n const partial = lines.at(-1) ?? \"\";\n if (partial) {\n nodes.push(formatPartialLine\n ? renderFormattedLine(partial, \"partial\")\n : <Text key=\"partial\">{partial}</Text>);\n }\n }\n\n return <Box flexDirection=\"column\">{nodes}</Box>;\n}\n","import React, { useRef, useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { formatClock } from \"../../utils/formatElapsed\";\nimport { Spinner } from \"./Spinner\";\n\nconst divider = \"─\".repeat(80);\n\nexport function Input({ disabled = false, pendingStartedAt, now, onSubmit, onExit }: {\n disabled?: boolean;\n pendingStartedAt?: number;\n now: number;\n onSubmit?: (value: string) => void;\n onExit?: () => void;\n}) {\n const [value, setValue] = useState(\"\");\n const valueRef = useRef(\"\");\n\n useInput((input, key) => {\n if (key.ctrl && input === \"c\") {\n onExit?.();\n return;\n }\n if (key.ctrl && input === \"d\") {\n onExit?.();\n return;\n }\n if (disabled) return;\n const newlineIndex = input.search(/[\\r\\n]/);\n if (key.return || newlineIndex >= 0) {\n if (newlineIndex > 0) {\n valueRef.current += input.slice(0, newlineIndex);\n }\n const submitted = valueRef.current.trim();\n valueRef.current = \"\";\n setValue(\"\");\n if (submitted === \"/exit\" || submitted === \"/quit\") {\n onExit?.();\n return;\n }\n if (submitted) onSubmit?.(submitted);\n return;\n }\n if (key.backspace || key.delete) {\n valueRef.current = valueRef.current.slice(0, -1);\n setValue(valueRef.current);\n return;\n }\n if (input && !key.ctrl && !key.meta) {\n valueRef.current += input;\n setValue(valueRef.current);\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>{divider}</Text>\n <Box>\n <Text color=\"green\">[{formatClock(new Date(now))}] &gt; </Text>\n <Text>{disabled ? \"\" : value}</Text>\n {!disabled ? <Text inverse> </Text> : pendingStartedAt ? <Spinner startedAt={pendingStartedAt} now={now} /> : <Text dimColor>streaming…</Text>}\n </Box>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Text } from \"ink\";\n\nconst frames = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\nexport function Spinner({ startedAt, now }: { startedAt: number; now: number }) {\n const elapsedMs = Math.max(0, now - startedAt);\n const frameIndex = Math.floor(elapsedMs / 120) % frames.length;\n const elapsedSec = Math.floor(elapsedMs / 1000);\n return <Text color=\"cyan\">{frames[frameIndex]} thinking… ({elapsedSec}s)</Text>;\n}\n","import React from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport type { HostPermissionAnswer, PermissionRequest } from \"../../safety/permissions/host\";\n\nexport function PermissionPrompt({ request, onAnswer }: {\n request: PermissionRequest | null;\n onAnswer: (answer: HostPermissionAnswer) => void;\n}) {\n useInput((input) => {\n if (!request) return;\n const normalized = input.trim().toLowerCase();\n if (normalized === \"y\") onAnswer({ decision: \"allow\" });\n if (normalized === \"n\") onAnswer({ decision: \"deny\" });\n }, { isActive: request !== null });\n\n if (!request) return null;\n const label = request.matchedRule ? `${request.tool} (${request.matchedRule})` : request.tool;\n const question = request.input && typeof request.input === \"object\" && typeof (request.input as { question?: unknown }).question === \"string\"\n ? (request.input as { question: string }).question\n : undefined;\n return (\n <Box borderStyle=\"round\" borderColor=\"yellow\" paddingX={1} marginBottom={1}>\n <Text color=\"yellow\">{question ?? `Permission required for ${label}.`} Press y to allow, n to deny.</Text>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ActivityItem } from \"./types\";\n\nfunction activityGlyph(item: ActivityItem): string {\n if (item.kind === \"reasoning\") return \"⚙\";\n if (item.status === \"done\") return \"✓\";\n if (item.status === \"error\") return \"×\";\n return \"⚙\";\n}\n\nfunction ActivityPanelView({ items }: { items: ActivityItem[] }) {\n if (items.length === 0) return null;\n\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n {items.map((item) => (\n <Box key={item.id} flexDirection=\"column\">\n <Text color={item.status === \"error\" ? \"red\" : item.status === \"done\" ? \"green\" : \"yellow\"}>\n {activityGlyph(item)} {item.summary}\n </Text>\n {item.kind === \"reasoning\" && item.content ? <Text dimColor italic wrap=\"wrap\">{item.content}</Text> : null}\n {item.kind === \"tool\" && item.content ? <Text dimColor wrap=\"wrap\">{item.content}</Text> : null}\n </Box>\n ))}\n </Box>\n );\n}\n\nfunction activityPanelPropsAreEqual(previous: { items: ActivityItem[] }, next: { items: ActivityItem[] }): boolean {\n const previousLast = previous.items.at(-1);\n const nextLast = next.items.at(-1);\n return previous.items.length === next.items.length &&\n previousLast?.id === nextLast?.id &&\n previousLast?.status === nextLast?.status &&\n previousLast?.summary === nextLast?.summary &&\n (previousLast?.content?.length ?? 0) === (nextLast?.content?.length ?? 0);\n}\n\nexport const ActivityPanel = React.memo(ActivityPanelView, activityPanelPropsAreEqual);\n","import type { Dispatch } from \"react\";\nimport type { EventSink, TanyaEvent } from \"../../events/types\";\nimport { estimateRunCost } from \"../../memory/runLogs\";\nimport { formatClock, formatElapsed } from \"../../utils/formatElapsed\";\nimport type { InkAction } from \"./state\";\n\nexport function createInkSink(dispatch: Dispatch<InkAction>, options: {\n provider: string;\n model: string;\n startedAt: number;\n flushIntervalMs?: number;\n}): EventSink {\n let assistantId: string | null = null;\n let streamedText = false;\n let buffer = \"\";\n let flushHandle: ReturnType<typeof setTimeout> | null = null;\n let reasoningId: string | null = null;\n let reasoningBuffer = \"\";\n let reasoningFlushHandle: ReturnType<typeof setTimeout> | null = null;\n let reasoningStartedAt: number | null = null;\n let streamedTokenChars = 0;\n let streamedReasoningChars = 0;\n let lastProgressCompletionTokens = 0;\n let lastProgressReasoningTokens = 0;\n let toolCount = 0;\n const flushIntervalMs = options.flushIntervalMs ?? 30;\n\n const dispatchProgressEstimate = () => {\n const completionTokens = Math.ceil(streamedTokenChars / 4);\n const reasoningTokens = Math.ceil(streamedReasoningChars / 4);\n if (completionTokens === lastProgressCompletionTokens && reasoningTokens === lastProgressReasoningTokens) return;\n lastProgressCompletionTokens = completionTokens;\n lastProgressReasoningTokens = reasoningTokens;\n dispatch({ type: \"turn_progress\", completionTokens, reasoningTokens });\n };\n\n const ensureAssistant = () => {\n if (assistantId) return assistantId;\n const timestampMs = Date.now();\n assistantId = `assistant-${timestampMs}`;\n dispatch({\n type: \"assistant_start\",\n id: assistantId,\n timestampMs,\n elapsedMs: timestampMs - options.startedAt,\n });\n return assistantId;\n };\n\n const flushBuffer = () => {\n if (flushHandle !== null) {\n clearTimeout(flushHandle);\n flushHandle = null;\n }\n if (!buffer) return;\n const text = buffer;\n buffer = \"\";\n dispatch({ type: \"assistant_delta\", id: ensureAssistant(), text });\n };\n\n const scheduleFlush = () => {\n if (flushHandle !== null) return;\n flushHandle = setTimeout(() => {\n flushHandle = null;\n flushBuffer();\n }, flushIntervalMs);\n };\n\n const ensureReasoning = () => {\n if (reasoningId) return reasoningId;\n const startedAt = Date.now();\n reasoningStartedAt = startedAt;\n reasoningId = `reasoning-${startedAt}`;\n dispatch({\n type: \"activity_start\",\n item: {\n id: reasoningId,\n kind: \"reasoning\",\n status: \"active\",\n summary: \"thinking…\",\n startedAt,\n },\n });\n return reasoningId;\n };\n\n const flushReasoningBuffer = () => {\n if (reasoningFlushHandle !== null) {\n clearTimeout(reasoningFlushHandle);\n reasoningFlushHandle = null;\n }\n if (!reasoningBuffer) return;\n const text = reasoningBuffer;\n reasoningBuffer = \"\";\n dispatch({ type: \"activity_progress\", id: ensureReasoning(), text });\n };\n\n const scheduleReasoningFlush = () => {\n if (reasoningFlushHandle !== null) return;\n reasoningFlushHandle = setTimeout(() => {\n reasoningFlushHandle = null;\n flushReasoningBuffer();\n }, flushIntervalMs);\n };\n\n const sink: EventSink = (event: TanyaEvent) => {\n switch (event.type) {\n case \"message_delta\": {\n streamedText = true;\n ensureAssistant();\n buffer += event.text;\n streamedTokenChars += event.text.length;\n dispatchProgressEstimate();\n scheduleFlush();\n break;\n }\n case \"message_end\":\n flushBuffer();\n break;\n case \"reasoning_chunk\":\n reasoningBuffer += event.content;\n streamedReasoningChars += event.content.length;\n dispatchProgressEstimate();\n scheduleReasoningFlush();\n break;\n case \"tool_call\": {\n flushBuffer();\n flushReasoningBuffer();\n toolCount += 1;\n dispatch({\n type: \"activity_start\",\n item: {\n id: event.id,\n kind: \"tool\",\n status: \"active\",\n summary: `running ${formatToolCallSummary(event.tool, event.input)}`,\n startedAt: Date.now(),\n },\n });\n break;\n }\n case \"tool_result\":\n flushBuffer();\n flushReasoningBuffer();\n dispatch({\n type: \"activity_end\",\n id: event.id,\n summary: `${event.tool}: ${event.summary}`,\n status: event.ok ? \"done\" : \"error\",\n endedAt: Date.now(),\n });\n break;\n case \"tool_progress\":\n flushBuffer();\n flushReasoningBuffer();\n dispatch({ type: \"activity_progress\", id: event.toolCallId, text: event.chunk.trimEnd() });\n break;\n case \"status\":\n flushBuffer();\n dispatch({ type: \"system_message\", content: event.message });\n break;\n case \"error\":\n flushBuffer();\n dispatch({ type: \"system_message\", content: `Error: ${event.message}${event.detail ? `\\n${event.detail}` : \"\"}` });\n break;\n case \"final\": {\n flushBuffer();\n flushReasoningBuffer();\n if (!streamedText && event.message.trim()) {\n buffer += event.message.trim();\n flushBuffer();\n }\n const now = Date.now();\n const streamedTokens = event.metrics?.completionTokens ?? streamedTokenChars;\n dispatch({\n type: \"system_message\",\n content: `[${formatClock(new Date(now))}] · ran ${toolCount} tool${toolCount === 1 ? \"\" : \"s\"} · thought for ${formatElapsed(\n reasoningStartedAt === null ? 0 : now - reasoningStartedAt,\n )} · streamed ${streamedTokens} token${streamedTokens === 1 ? \"\" : \"s\"}`,\n timestampMs: now,\n });\n const metrics = event.metrics;\n const cost = metrics ? estimateRunCost({\n provider: options.provider,\n model: options.model,\n promptTokens: metrics.promptTokens ?? 0,\n completionTokens: metrics.completionTokens ?? 0,\n reasoningTokens: metrics.reasoningTokens ?? 0,\n }).usd : null;\n if (event.metrics) {\n dispatch({\n type: \"turn_complete\",\n elapsedMs: Date.now() - options.startedAt,\n costUsd: cost,\n ...(metrics?.promptTokens !== undefined ? { promptTokens: metrics.promptTokens } : {}),\n ...(metrics?.completionTokens !== undefined ? { completionTokens: metrics.completionTokens } : {}),\n ...(metrics?.reasoningTokens !== undefined ? { reasoningTokens: metrics.reasoningTokens } : {}),\n });\n } else {\n dispatch({ type: \"turn_complete\", elapsedMs: Date.now() - options.startedAt, costUsd: null });\n }\n break;\n }\n default:\n break;\n }\n };\n (sink as EventSink & { tanyaSinkKind?: \"ink\" }).tanyaSinkKind = \"ink\";\n return sink;\n}\n\nfunction formatToolCallSummary(tool: string, input: unknown): string {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) return `${tool}()`;\n const entries = Object.entries(input as Record<string, unknown>)\n .filter(([, value]) => value !== undefined && value !== null)\n .slice(0, 2)\n .map(([key, value]) => `${key}=${formatToolValue(value)}`);\n return `${tool}(${entries.join(\", \")})`;\n}\n\nfunction formatToolValue(value: unknown): string {\n if (typeof value === \"string\") {\n const compact = value.replace(/\\s+/g, \" \").trim();\n return `\"${compact.length > 40 ? `${compact.slice(0, 37)}...` : compact}\"`;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) return `[${value.length}]`;\n return \"{…}\";\n}\n","import type { ActivityItem, InkMessage, InkSessionStats } from \"./types\";\nimport type { PermissionRequest } from \"../../safety/permissions/host\";\nimport { estimateRunCost } from \"../../memory/runLogs\";\n\nexport interface PendingTurn {\n startedAt: number;\n spinnerVisible: boolean;\n}\n\nexport interface InflightTurn {\n promptTokens: number;\n completionTokens: number;\n reasoningTokens: number;\n costUsd: number | null;\n}\n\nexport interface InkState {\n messages: InkMessage[];\n assistantMessageIndexes: Record<string, number>;\n liveAssistantId: string | null;\n pendingTurn: PendingTurn | null;\n activityItems: ActivityItem[];\n sessionStartMs: number;\n sessionGenerateMs: number;\n turnCount: number;\n stats: InkSessionStats;\n inflight: InflightTurn;\n provider: string;\n model: string;\n pendingPermission: PermissionRequest | null;\n}\n\nconst EMPTY_INFLIGHT: InflightTurn = { promptTokens: 0, completionTokens: 0, reasoningTokens: 0, costUsd: 0 };\n\nfunction computeInflight(state: { provider: string; model: string }, partial: { promptTokens?: number; completionTokens?: number; reasoningTokens?: number }, previous: InflightTurn): InflightTurn {\n const next: InflightTurn = {\n promptTokens: partial.promptTokens ?? previous.promptTokens,\n completionTokens: partial.completionTokens ?? previous.completionTokens,\n reasoningTokens: partial.reasoningTokens ?? previous.reasoningTokens,\n costUsd: previous.costUsd,\n };\n if (state.provider && state.model) {\n const cost = estimateRunCost({\n provider: state.provider,\n model: state.model,\n promptTokens: next.promptTokens,\n completionTokens: next.completionTokens,\n reasoningTokens: next.reasoningTokens,\n });\n next.costUsd = cost.usd;\n }\n return next;\n}\n\nexport interface InitialInkStateOptions {\n provider?: string | undefined;\n model?: string | undefined;\n now?: number | undefined;\n initialMessages?: InkMessage[] | undefined;\n initialStats?: InkSessionStats | undefined;\n initialGenerateMs?: number | undefined;\n initialTurnCount?: number | undefined;\n}\n\nexport type InkAction =\n | { type: \"user_message\"; content: string; timestampMs: number }\n | { type: \"system_message\"; content: string; timestampMs?: number }\n | { type: \"assistant_start\"; id: string; timestampMs: number; elapsedMs: number }\n | { type: \"assistant_delta\"; id: string; text: string }\n | { type: \"turn_start\"; startedAt: number }\n | { type: \"turn_progress\"; promptTokens?: number; completionTokens?: number; reasoningTokens?: number }\n | { type: \"turn_complete\"; elapsedMs: number; promptTokens?: number; completionTokens?: number; reasoningTokens?: number; costUsd?: number | null }\n | { type: \"turn_error\"; message: string }\n | { type: \"activity_start\"; item: ActivityItem }\n | { type: \"activity_progress\"; id: string; text: string }\n | { type: \"activity_end\"; id: string; summary: string; status: \"done\" | \"error\"; endedAt: number }\n | { type: \"permission_request\"; request: PermissionRequest }\n | { type: \"permission_clear\" }\n | { type: \"replace_session\"; messages: InkMessage[]; stats: InkSessionStats; generateMs: number; turnCount: number }\n | { type: \"clear\" };\n\nexport function createInitialInkState(options: InitialInkStateOptions = {}): InkState {\n const now = options.now ?? Date.now();\n const warmupMessages: InkMessage[] = options.provider && options.model\n ? [{\n id: `system-connect-${now}`,\n role: \"system\",\n content: `Tanya · connecting to ${options.provider}:${options.model}…`,\n timestampMs: now,\n }]\n : [];\n const messages = [...warmupMessages, ...(options.initialMessages ?? [])];\n return {\n messages,\n assistantMessageIndexes: {},\n liveAssistantId: null,\n pendingTurn: null,\n activityItems: [],\n sessionStartMs: now,\n sessionGenerateMs: options.initialGenerateMs ?? 0,\n turnCount: options.initialTurnCount ?? 0,\n stats: options.initialStats ?? { costUsd: 0, totalTokens: 0 },\n inflight: { ...EMPTY_INFLIGHT },\n provider: options.provider ?? \"\",\n model: options.model ?? \"\",\n pendingPermission: null,\n };\n}\n\nexport function inkReducer(state: InkState, action: InkAction): InkState {\n switch (action.type) {\n case \"user_message\":\n return {\n ...state,\n messages: [...state.messages, {\n id: `user-${action.timestampMs}-${state.messages.length}`,\n role: \"user\",\n content: action.content,\n timestampMs: action.timestampMs,\n }],\n };\n case \"system_message\":\n return {\n ...state,\n messages: [...state.messages, {\n id: `system-${action.timestampMs ?? Date.now()}-${state.messages.length}`,\n role: \"system\",\n content: action.content,\n timestampMs: action.timestampMs ?? Date.now(),\n }],\n };\n case \"assistant_start\":\n if (state.messages.some((message) => message.id === action.id)) return state;\n return {\n ...state,\n pendingTurn: state.pendingTurn ? { ...state.pendingTurn, spinnerVisible: false } : state.pendingTurn,\n messages: [...state.messages, {\n id: action.id,\n role: \"assistant\",\n content: \"\",\n timestampMs: action.timestampMs,\n elapsedMs: action.elapsedMs,\n }],\n assistantMessageIndexes: {\n ...state.assistantMessageIndexes,\n [action.id]: state.messages.length,\n },\n liveAssistantId: action.id,\n };\n case \"assistant_delta\": {\n const cachedIndex = state.assistantMessageIndexes[action.id];\n const index = cachedIndex !== undefined && state.messages[cachedIndex]?.id === action.id\n ? cachedIndex\n : state.messages.findIndex((message) => message.id === action.id);\n if (index < 0) return state;\n const messages = state.messages.slice();\n const message = messages[index]!;\n messages[index] = { ...message, content: `${message.content}${action.text}` };\n return {\n ...state,\n messages,\n ...(cachedIndex === index ? {} : {\n assistantMessageIndexes: {\n ...state.assistantMessageIndexes,\n [action.id]: index,\n },\n }),\n };\n }\n case \"turn_start\":\n return { ...state, pendingTurn: { startedAt: action.startedAt, spinnerVisible: true }, activityItems: [], inflight: { ...EMPTY_INFLIGHT } };\n case \"turn_progress\":\n return { ...state, inflight: computeInflight(state, action, state.inflight) };\n case \"turn_complete\": {\n const turnTokens = (action.promptTokens ?? 0) + (action.completionTokens ?? 0) + (action.reasoningTokens ?? 0);\n const currentCost = state.stats.costUsd ?? 0;\n const currentTokens = state.stats.totalTokens ?? 0;\n return {\n ...state,\n liveAssistantId: null,\n pendingTurn: null,\n activityItems: [],\n sessionGenerateMs: state.sessionGenerateMs + action.elapsedMs,\n turnCount: state.turnCount + 1,\n stats: {\n costUsd: action.costUsd === null || action.costUsd === undefined ? state.stats.costUsd : currentCost + action.costUsd,\n totalTokens: turnTokens > 0 ? currentTokens + turnTokens : state.stats.totalTokens,\n },\n inflight: { ...EMPTY_INFLIGHT },\n };\n }\n case \"turn_error\":\n return {\n ...state,\n liveAssistantId: null,\n pendingTurn: null,\n activityItems: [],\n inflight: { ...EMPTY_INFLIGHT },\n messages: [...state.messages, {\n id: `error-${Date.now()}-${state.messages.length}`,\n role: \"system\",\n content: `Error: ${action.message}`,\n timestampMs: Date.now(),\n }],\n };\n case \"activity_start\":\n return {\n ...state,\n activityItems: [...state.activityItems, action.item],\n };\n case \"activity_progress\":\n return {\n ...state,\n activityItems: state.activityItems.map((item) => item.id === action.id\n ? { ...item, content: `${item.content ?? \"\"}${action.text}` }\n : item),\n };\n case \"activity_end\":\n return {\n ...state,\n activityItems: state.activityItems.map((item) => item.id === action.id\n ? { ...item, status: action.status, summary: action.summary, endedAt: action.endedAt }\n : item),\n };\n case \"permission_request\":\n return { ...state, pendingPermission: action.request };\n case \"permission_clear\":\n return { ...state, pendingPermission: null };\n case \"replace_session\":\n return {\n ...state,\n messages: action.messages,\n assistantMessageIndexes: {},\n liveAssistantId: null,\n pendingTurn: null,\n activityItems: [],\n sessionGenerateMs: action.generateMs,\n turnCount: action.turnCount,\n stats: action.stats,\n inflight: { ...EMPTY_INFLIGHT },\n };\n case \"clear\":\n return { ...state, messages: [], assistantMessageIndexes: {}, liveAssistantId: null, activityItems: [] };\n default:\n return state;\n }\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useSessionTicker(intervalMs = 1000): number {\n const [now, setNow] = useState(() => Date.now());\n\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), intervalMs);\n return () => clearInterval(timer);\n }, [intervalMs]);\n\n return now;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AACA,SAAS,cAAc;;;ACDvB,SAAgB,aAAAA,YAAW,YAAY,UAAAC,eAAc;AACrD,SAAS,OAAAC,MAAK,cAAc;;;ACCrB,SAAS,eAAe,UAAiC;AAC9D,SAAO,SAAS,OAAO,CAAC,KAAK,QAAQ;AACnC,UAAM,OAAO,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,KAAK,UAAU,IAAI,WAAW,EAAE;AAC7F,WAAO,MAAM,KAAK,KAAK,KAAK,SAAS,CAAC;AAAA,EACxC,GAAG,CAAC;AACN;;;ACNA,SAAS,KAAK,YAAY;AA4CtB,SACE,KADF;AAtCJ,IAAM,UAAU,SAAI,OAAO,EAAE;AAE7B,SAAS,aAAa,QAA+B;AACnD,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,UAAU,IAAW,QAAO,IAAI,SAAS,KAAW,QAAQ,CAAC,CAAC;AAClE,MAAI,UAAU,IAAO,QAAO,IAAI,SAAS,KAAO,QAAQ,CAAC,CAAC;AAC1D,SAAO,GAAG,MAAM;AAClB;AAEA,SAAS,iBAAiB,SAAgC;AACxD,MAAI,YAAY,KAAM,QAAO;AAC7B,MAAI,YAAY,EAAG,QAAO;AAC1B,SAAO,UAAU,OAAO;AAC1B;AAEA,SAAS,mBAAmB,UAA4C;AACtE,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,SAAS,eAAe,SAAS,mBAAmB,SAAS;AACtE;AAEO,SAAS,OAAO,EAAE,UAAU,OAAO,gBAAgB,OAAO,UAAU,KAAK,oBAAoB,MAAM,GAQvG;AACD,QAAM,iBAAiB,mBAAmB,QAAQ;AAClD,QAAM,eAAe,UAAU,WAAW;AAC1C,QAAM,WAAW,MAAM,WAAW;AAClC,QAAM,WAAW,iBAAiB,KAAK,eAAe,IAAI,WAAW,eAAe,MAAM;AAC1F,QAAM,aAAa,MAAM,eAAe;AACxC,QAAM,aAAa,iBAAiB,IAAI,aAAa,iBAAiB,MAAM;AAC5E,QAAM,aAAa,iBAAiB,IAAI,MAAM;AAC9C,QAAM,OAAO,iBAAiB,QAAQ;AACtC,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,wBAAC,QAAK,UAAQ,MAAE,mBAAQ;AAAA,IACxB,oBAAC,QAAK,UAAQ,MACX,8BACG,iFACA,GAAG,QAAQ,IAAI,KAAK,iBAAc,cAAc,MAAM,cAAc,CAAC,SAAM,UAAU,GAAG,IAAI,SAAM,UAAU,GAAG,aAAa,UAAU,CAAC,eAC7I;AAAA,KACF;AAEJ;;;ACtDA,OAAOC,YAAW;AAClB,SAAS,OAAAC,MAAK,QAAQ,QAAAC,aAAY;;;ACDlC,OAAO,WAAW;AAClB,SAAS,OAAAC,MAAK,QAAAC,aAAY;AA2BT,gBAAAC,MASL,QAAAC,aATK;AAvBjB,SAAS,mBAAmB,MAAc,QAAyB;AACjE,SAAO,KAAK,MAAM,MAAM,EAAE,SAAS,MAAM;AAC3C;AAEA,SAAS,aAAa,MAA4B;AAChD,MACG,KAAK,SAAS,IAAI,KAAK,CAAC,mBAAmB,MAAM,IAAI,KACrD,KAAK,SAAS,GAAG,KAAK,CAAC,mBAAmB,MAAM,GAAG,KACnD,KAAK,SAAS,GAAG,KAAK,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,mBAAmB,MAAM,GAAG,KAC3E,KAAK,SAAS,GAAG,KAAK,CAAC,mBAAmB,MAAM,GAAG,GACpD;AACA,WAAO,CAAC,IAAI;AAAA,EACd;AAEA,QAAM,QAAsB,CAAC;AAC7B,QAAM,UAAU;AAChB,MAAI,YAAY;AAChB,MAAI;AACJ,MAAI,MAAM;AACV,UAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC5C,QAAI,MAAM,QAAQ,UAAW,OAAM,KAAK,KAAK,MAAM,WAAW,MAAM,KAAK,CAAC;AAC1E,UAAM,QAAQ,MAAM,CAAC;AACrB,QAAI,MAAM,WAAW,IAAI,GAAG;AAC1B,YAAM,KAAK,gBAAAD,KAACD,OAAA,EAAwB,MAAI,MAAE,gBAAM,MAAM,GAAG,EAAE,KAArC,KAAK,KAAK,EAA6B,CAAO;AAAA,IACtE,WAAW,MAAM,WAAW,GAAG,GAAG;AAChC,YAAM,KAAK,gBAAAC,KAACD,OAAA,EAAwB,SAAO,MAAE,gBAAM,MAAM,GAAG,EAAE,KAAxC,KAAK,KAAK,EAAgC,CAAO;AAAA,IACzE,WAAW,MAAM,WAAW,GAAG,GAAG;AAChC,YAAM,YAAY,MAAM,MAAM,2BAA2B;AACzD,UAAI,WAAW;AACb,cAAM;AAAA,UACJ,gBAAAE,MAAC,MAAM,UAAN,EACC;AAAA,4BAAAD,KAACD,OAAA,EAAK,WAAS,MAAE,oBAAU,CAAC,GAAE;AAAA,YAC9B,gBAAAE,MAACF,OAAA,EAAK,UAAQ,MAAC;AAAA;AAAA,cAAG,UAAU,CAAC;AAAA,cAAE;AAAA,eAAC;AAAA,eAFb,KAAK,KAAK,EAG/B;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,KAAK,gBAAAC,KAACD,OAAA,EAAwB,QAAM,MAAE,gBAAM,MAAM,GAAG,EAAE,KAAvC,KAAK,KAAK,EAA+B,CAAO;AAAA,IACxE;AACA,gBAAY,QAAQ;AAAA,EACtB;AACA,MAAI,YAAY,KAAK,OAAQ,OAAM,KAAK,KAAK,MAAM,SAAS,CAAC;AAC7D,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAc,KAAiC;AAC1E,MAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,UAAM,CAAC,EAAE,SAAS,IAAI,OAAO,EAAE,IAAI,KAAK,MAAM,mBAAmB,KAAK,CAAC;AACvE,WAAO,gBAAAC,KAACD,OAAA,EAAe,MAAI,MAAC,OAAO,OAAO,WAAW,IAAI,SAAS,QAAS,uBAAa,IAAI,KAA1E,GAA4E;AAAA,EAChG;AACA,MAAI,cAAc,KAAK,IAAI,GAAG;AAC5B,WAAO,gBAAAE,MAACF,OAAA,EAAe;AAAA;AAAA,MAAG,aAAa,KAAK,QAAQ,eAAe,EAAE,CAAC;AAAA,SAApD,GAAsD;AAAA,EAC1E;AACA,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,UAAM,SAAS,KAAK,MAAM,gBAAgB,IAAI,CAAC,KAAK;AACpD,WAAO,gBAAAE,MAACF,OAAA,EAAgB;AAAA;AAAA,MAAO;AAAA,MAAE,aAAa,KAAK,QAAQ,gBAAgB,EAAE,CAAC;AAAA,SAA5D,GAA8D;AAAA,EAClF;AACA,MAAI,WAAW,KAAK,IAAI,GAAG;AACzB,WAAO,gBAAAE,MAACF,OAAA,EAAe,UAAQ,MAAC,QAAM,MAAC;AAAA;AAAA,MAAG,aAAa,KAAK,QAAQ,YAAY,EAAE,CAAC;AAAA,SAAjE,GAAmE;AAAA,EACvF;AACA,SAAO,gBAAAC,KAACD,OAAA,EAAgB,uBAAa,IAAI,KAAvB,GAAyB;AAC7C;AAEO,SAAS,aAAa,EAAE,QAAQ,oBAAoB,MAAM,GAAoD;AACnH,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,qBAAqB,OAAO,SAAS,IAAI;AAC/C,QAAM,oBAAoB,MAAM,SAAS;AACzC,QAAM,QAA8B,CAAC;AACrC,MAAI,QAAQ;AAEZ,SAAO,QAAQ,mBAAmB;AAChC,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,YAAM,eAAe,MAAM,UAAU,CAAC,WAAW,mBAAmB,iBAAiB,SAAS,UAAU,WAAW,KAAK,CAAC;AACzH,UAAI,eAAe,SAAS,eAAe,MAAM,QAAQ;AACvD,cAAM,OAAO,MAAM,MAAM,QAAQ,GAAG,YAAY,EAAE,KAAK,IAAI;AAC3D,cAAM;AAAA,UACJ,gBAAAC,KAACF,MAAA,EAA0B,aAAY,SAAQ,UAAU,GAAG,eAAc,UACxE,0BAAAE,KAACD,OAAA,EAAM,gBAAK,KADJ,QAAQ,KAAK,EAEvB;AAAA,QACF;AACA,gBAAQ,eAAe;AACvB;AAAA,MACF;AAAA,IACF;AACA,UAAM,KAAK,oBAAoB,MAAM,QAAQ,KAAK,EAAE,CAAC;AACrD,aAAS;AAAA,EACX;AAEA,MAAI,CAAC,oBAAoB;AACvB,UAAM,UAAU,MAAM,GAAG,EAAE,KAAK;AAChC,QAAI,SAAS;AACX,YAAM,KAAK,oBACP,oBAAoB,SAAS,SAAS,IACtC,gBAAAC,KAACD,OAAA,EAAoB,qBAAX,SAAmB,CAAO;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO,gBAAAC,KAACF,MAAA,EAAI,eAAc,UAAU,iBAAM;AAC5C;;;ADvFI,SA8CI,UA7CF,OAAAI,MADF,QAAAC,aAAA;AAZJ,SAAS,cAAc,SAA6B;AAClD,QAAM,QAAQ,IAAI,YAAY,IAAI,KAAK,QAAQ,WAAW,CAAC,CAAC;AAC5D,MAAI,QAAQ,SAAS,OAAQ,QAAO,GAAG,KAAK;AAC5C,MAAI,QAAQ,SAAS,aAAa;AAChC,WAAO,GAAG,KAAK,SAAS,QAAQ,cAAc,SAAY,SAAM,cAAc,QAAQ,SAAS,CAAC,KAAK,EAAE;AAAA,EACzG;AACA,MAAI,QAAQ,SAAS,OAAQ,QAAO,GAAG,KAAK;AAC5C,SAAO,GAAG,KAAK;AACjB;AAEA,IAAM,eAAeC,OAAM,KAAK,SAASC,cAAa,EAAE,SAAS,OAAO,MAAM,GAA4C;AACxH,SACE,gBAAAF,MAACG,MAAA,EAAI,eAAc,UAAS,cAAc,GACxC;AAAA,oBAAAJ,KAACK,OAAA,EAAK,OAAO,QAAQ,SAAS,SAAS,UAAU,QAAQ,SAAS,cAAc,SAAS,QACtF,wBAAc,OAAO,GACxB;AAAA,IACC,QAAQ,UACL,QAAQ,SAAS,cACf,gBAAAL,KAAC,gBAAa,QAAQ,QAAQ,SAAS,mBAAmB,CAAC,MAAM,IACjE,gBAAAA,KAACK,OAAA,EAAK,MAAK,QAAQ,kBAAQ,SAAQ,IACrC;AAAA,KACN;AAEJ,GAAG,CAAC,UAAU,SAAS,SAAS,SAAS,KAAK,QAC5C,SAAS,QAAQ,OAAO,KAAK,QAAQ,MACrC,SAAS,QAAQ,SAAS,KAAK,QAAQ,QACvC,SAAS,QAAQ,cAAc,KAAK,QAAQ,aAC5C,SAAS,QAAQ,QAAQ,WAAW,KAAK,QAAQ,QAAQ,MAAM;AAE1D,SAAS,qBAAqB,UAAwB,aAAiC,iBAG5F;AACA,MAAI,CAAC,YAAa,QAAO,EAAE,WAAW,UAAU,MAAM,CAAC,EAAE;AAEzD,QAAM,YAA0B,CAAC;AACjC,QAAM,OAAqB,CAAC;AAC5B,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,OAAO,mBAAoB,QAAQ,SAAS,YAAY,QAAQ,eAAe,YAAY,WAAY;AACjH,WAAK,KAAK,OAAO;AAAA,IACnB,OAAO;AACL,gBAAU,KAAK,OAAO;AAAA,IACxB;AAAA,EACF;AACA,SAAO,EAAE,WAAW,KAAK;AAC3B;AAEO,SAAS,QAAQ,EAAE,UAAU,aAAa,gBAAgB,GAI9D;AACD,QAAM,EAAE,WAAW,KAAK,IAAI,qBAAqB,UAAU,aAAa,eAAe;AACvF,SACE,gBAAAL,KAACI,MAAA,EAAI,eAAc,UAAS,UAAU,GAAG,UAAS,UAC/C,mBAAS,WAAW,IACnB,gBAAAJ,KAACK,OAAA,EAAK,UAAQ,MAAC,+BAAiB,IAEhC,gBAAAJ,MAAA,YACE;AAAA,oBAAAD,KAAC,UAAmB,OAAO,WACxB,WAAC,YAAY,gBAAAA,KAAC,gBAA8B,WAAZ,QAAQ,EAAsB,GACjE;AAAA,IACC,KAAK,IAAI,CAAC,YACT,gBAAAA,KAAC,gBAA8B,SAAkB,MAAI,QAAlC,QAAQ,EAA2B,CACvD;AAAA,KACH,GAEJ;AAEJ;;;AE5EA,SAAgB,QAAQ,gBAAgB;AACxC,SAAS,OAAAM,MAAK,QAAAC,OAAM,gBAAgB;;;ACApC,SAAS,QAAAC,aAAY;AAQZ,iBAAAC,aAAA;AANT,IAAM,SAAS,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AAEzD,SAAS,QAAQ,EAAE,WAAW,IAAI,GAAuC;AAC9E,QAAM,YAAY,KAAK,IAAI,GAAG,MAAM,SAAS;AAC7C,QAAM,aAAa,KAAK,MAAM,YAAY,GAAG,IAAI,OAAO;AACxD,QAAM,aAAa,KAAK,MAAM,YAAY,GAAI;AAC9C,SAAO,gBAAAA,MAACD,OAAA,EAAK,OAAM,QAAQ;AAAA,WAAO,UAAU;AAAA,IAAE;AAAA,IAAa;AAAA,IAAW;AAAA,KAAE;AAC1E;;;AD6CM,gBAAAE,MAEE,QAAAC,aAFF;AAlDN,IAAMC,WAAU,SAAI,OAAO,EAAE;AAEtB,SAAS,MAAM,EAAE,WAAW,OAAO,kBAAkB,KAAK,UAAU,OAAO,GAM/E;AACD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,WAAW,OAAO,EAAE;AAE1B,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ,UAAU,KAAK;AAC7B,eAAS;AACT;AAAA,IACF;AACA,QAAI,IAAI,QAAQ,UAAU,KAAK;AAC7B,eAAS;AACT;AAAA,IACF;AACA,QAAI,SAAU;AACd,UAAM,eAAe,MAAM,OAAO,QAAQ;AAC1C,QAAI,IAAI,UAAU,gBAAgB,GAAG;AACnC,UAAI,eAAe,GAAG;AACpB,iBAAS,WAAW,MAAM,MAAM,GAAG,YAAY;AAAA,MACjD;AACA,YAAM,YAAY,SAAS,QAAQ,KAAK;AACxC,eAAS,UAAU;AACnB,eAAS,EAAE;AACX,UAAI,cAAc,WAAW,cAAc,SAAS;AAClD,iBAAS;AACT;AAAA,MACF;AACA,UAAI,UAAW,YAAW,SAAS;AACnC;AAAA,IACF;AACA,QAAI,IAAI,aAAa,IAAI,QAAQ;AAC/B,eAAS,UAAU,SAAS,QAAQ,MAAM,GAAG,EAAE;AAC/C,eAAS,SAAS,OAAO;AACzB;AAAA,IACF;AACA,QAAI,SAAS,CAAC,IAAI,QAAQ,CAAC,IAAI,MAAM;AACnC,eAAS,WAAW;AACpB,eAAS,SAAS,OAAO;AAAA,IAC3B;AAAA,EACF,CAAC;AAED,SACE,gBAAAD,MAACE,MAAA,EAAI,eAAc,UACjB;AAAA,oBAAAH,KAACI,OAAA,EAAK,UAAQ,MAAE,UAAAF,UAAQ;AAAA,IACxB,gBAAAD,MAACE,MAAA,EACC;AAAA,sBAAAF,MAACG,OAAA,EAAK,OAAM,SAAQ;AAAA;AAAA,QAAE,YAAY,IAAI,KAAK,GAAG,CAAC;AAAA,QAAE;AAAA,SAAO;AAAA,MACxD,gBAAAJ,KAACI,OAAA,EAAM,qBAAW,KAAK,OAAM;AAAA,MAC5B,CAAC,WAAW,gBAAAJ,KAACI,OAAA,EAAK,SAAO,MAAC,eAAC,IAAU,mBAAmB,gBAAAJ,KAAC,WAAQ,WAAW,kBAAkB,KAAU,IAAK,gBAAAA,KAACI,OAAA,EAAK,UAAQ,MAAC,6BAAU;AAAA,OACzI;AAAA,KACF;AAEJ;;;AE9DA,SAAS,OAAAC,MAAK,QAAAC,OAAM,YAAAC,iBAAgB;AAoBhC,gBAAAC,MACE,QAAAC,aADF;AAjBG,SAAS,iBAAiB,EAAE,SAAS,SAAS,GAGlD;AACD,EAAAF,UAAS,CAAC,UAAU;AAClB,QAAI,CAAC,QAAS;AACd,UAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,QAAI,eAAe,IAAK,UAAS,EAAE,UAAU,QAAQ,CAAC;AACtD,QAAI,eAAe,IAAK,UAAS,EAAE,UAAU,OAAO,CAAC;AAAA,EACvD,GAAG,EAAE,UAAU,YAAY,KAAK,CAAC;AAEjC,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,QAAQ,cAAc,GAAG,QAAQ,IAAI,KAAK,QAAQ,WAAW,MAAM,QAAQ;AACzF,QAAM,WAAW,QAAQ,SAAS,OAAO,QAAQ,UAAU,YAAY,OAAQ,QAAQ,MAAiC,aAAa,WAChI,QAAQ,MAA+B,WACxC;AACJ,SACE,gBAAAC,KAACH,MAAA,EAAI,aAAY,SAAQ,aAAY,UAAS,UAAU,GAAG,cAAc,GACvE,0BAAAI,MAACH,OAAA,EAAK,OAAM,UAAU;AAAA,gBAAY,2BAA2B,KAAK;AAAA,IAAI;AAAA,KAA6B,GACrG;AAEJ;;;ACzBA,OAAOI,YAAW;AAClB,SAAS,OAAAC,MAAK,QAAAC,aAAY;AAiBhB,SAG6C,OAAAC,MAH7C,QAAAC,aAAA;AAdV,SAAS,cAAc,MAA4B;AACjD,MAAI,KAAK,SAAS,YAAa,QAAO;AACtC,MAAI,KAAK,WAAW,OAAQ,QAAO;AACnC,MAAI,KAAK,WAAW,QAAS,QAAO;AACpC,SAAO;AACT;AAEA,SAAS,kBAAkB,EAAE,MAAM,GAA8B;AAC/D,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SACE,gBAAAD,KAACF,MAAA,EAAI,eAAc,UAAS,cAAc,GACvC,gBAAM,IAAI,CAAC,SACV,gBAAAG,MAACH,MAAA,EAAkB,eAAc,UAC/B;AAAA,oBAAAG,MAACF,OAAA,EAAK,OAAO,KAAK,WAAW,UAAU,QAAQ,KAAK,WAAW,SAAS,UAAU,UAC/E;AAAA,oBAAc,IAAI;AAAA,MAAE;AAAA,MAAE,KAAK;AAAA,OAC9B;AAAA,IACC,KAAK,SAAS,eAAe,KAAK,UAAU,gBAAAC,KAACD,OAAA,EAAK,UAAQ,MAAC,QAAM,MAAC,MAAK,QAAQ,eAAK,SAAQ,IAAU;AAAA,IACtG,KAAK,SAAS,UAAU,KAAK,UAAU,gBAAAC,KAACD,OAAA,EAAK,UAAQ,MAAC,MAAK,QAAQ,eAAK,SAAQ,IAAU;AAAA,OALnF,KAAK,EAMf,CACD,GACH;AAEJ;AAEA,SAAS,2BAA2B,UAAqC,MAA0C;AACjH,QAAM,eAAe,SAAS,MAAM,GAAG,EAAE;AACzC,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE;AACjC,SAAO,SAAS,MAAM,WAAW,KAAK,MAAM,UAC1C,cAAc,OAAO,UAAU,MAC/B,cAAc,WAAW,UAAU,UACnC,cAAc,YAAY,UAAU,YACnC,cAAc,SAAS,UAAU,QAAQ,UAAU,SAAS,UAAU;AAC3E;AAEO,IAAM,gBAAgBF,OAAM,KAAK,mBAAmB,0BAA0B;;;ACjC9E,SAAS,cAAc,UAA+B,SAK/C;AACZ,MAAI,cAA6B;AACjC,MAAI,eAAe;AACnB,MAAI,SAAS;AACb,MAAI,cAAoD;AACxD,MAAI,cAA6B;AACjC,MAAI,kBAAkB;AACtB,MAAI,uBAA6D;AACjE,MAAI,qBAAoC;AACxC,MAAI,qBAAqB;AACzB,MAAI,yBAAyB;AAC7B,MAAI,+BAA+B;AACnC,MAAI,8BAA8B;AAClC,MAAI,YAAY;AAChB,QAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,QAAM,2BAA2B,MAAM;AACrC,UAAM,mBAAmB,KAAK,KAAK,qBAAqB,CAAC;AACzD,UAAM,kBAAkB,KAAK,KAAK,yBAAyB,CAAC;AAC5D,QAAI,qBAAqB,gCAAgC,oBAAoB,4BAA6B;AAC1G,mCAA+B;AAC/B,kCAA8B;AAC9B,aAAS,EAAE,MAAM,iBAAiB,kBAAkB,gBAAgB,CAAC;AAAA,EACvE;AAEA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,YAAa,QAAO;AACxB,UAAM,cAAc,KAAK,IAAI;AAC7B,kBAAc,aAAa,WAAW;AACtC,aAAS;AAAA,MACP,MAAM;AAAA,MACN,IAAI;AAAA,MACJ;AAAA,MACA,WAAW,cAAc,QAAQ;AAAA,IACnC,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,MAAM;AACxB,QAAI,gBAAgB,MAAM;AACxB,mBAAa,WAAW;AACxB,oBAAc;AAAA,IAChB;AACA,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO;AACb,aAAS;AACT,aAAS,EAAE,MAAM,mBAAmB,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAAA,EACnE;AAEA,QAAM,gBAAgB,MAAM;AAC1B,QAAI,gBAAgB,KAAM;AAC1B,kBAAc,WAAW,MAAM;AAC7B,oBAAc;AACd,kBAAY;AAAA,IACd,GAAG,eAAe;AAAA,EACpB;AAEA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,YAAa,QAAO;AACxB,UAAM,YAAY,KAAK,IAAI;AAC3B,yBAAqB;AACrB,kBAAc,aAAa,SAAS;AACpC,aAAS;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,uBAAuB,MAAM;AACjC,QAAI,yBAAyB,MAAM;AACjC,mBAAa,oBAAoB;AACjC,6BAAuB;AAAA,IACzB;AACA,QAAI,CAAC,gBAAiB;AACtB,UAAM,OAAO;AACb,sBAAkB;AAClB,aAAS,EAAE,MAAM,qBAAqB,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAAA,EACrE;AAEA,QAAM,yBAAyB,MAAM;AACnC,QAAI,yBAAyB,KAAM;AACnC,2BAAuB,WAAW,MAAM;AACtC,6BAAuB;AACvB,2BAAqB;AAAA,IACvB,GAAG,eAAe;AAAA,EACpB;AAEA,QAAM,OAAkB,CAAC,UAAsB;AAC7C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,iBAAiB;AACpB,uBAAe;AACf,wBAAgB;AAChB,kBAAU,MAAM;AAChB,8BAAsB,MAAM,KAAK;AACjC,iCAAyB;AACzB,sBAAc;AACd;AAAA,MACF;AAAA,MACA,KAAK;AACH,oBAAY;AACZ;AAAA,MACF,KAAK;AACH,2BAAmB,MAAM;AACzB,kCAA0B,MAAM,QAAQ;AACxC,iCAAyB;AACzB,+BAAuB;AACvB;AAAA,MACF,KAAK,aAAa;AAChB,oBAAY;AACZ,6BAAqB;AACrB,qBAAa;AACb,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,IAAI,MAAM;AAAA,YACV,MAAM;AAAA,YACN,QAAQ;AAAA,YACR,SAAS,WAAW,sBAAsB,MAAM,MAAM,MAAM,KAAK,CAAC;AAAA,YAClE,WAAW,KAAK,IAAI;AAAA,UACtB;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,MACA,KAAK;AACH,oBAAY;AACZ,6BAAqB;AACrB,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,SAAS,GAAG,MAAM,IAAI,KAAK,MAAM,OAAO;AAAA,UACxC,QAAQ,MAAM,KAAK,SAAS;AAAA,UAC5B,SAAS,KAAK,IAAI;AAAA,QACpB,CAAC;AACD;AAAA,MACF,KAAK;AACH,oBAAY;AACZ,6BAAqB;AACrB,iBAAS,EAAE,MAAM,qBAAqB,IAAI,MAAM,YAAY,MAAM,MAAM,MAAM,QAAQ,EAAE,CAAC;AACzF;AAAA,MACF,KAAK;AACH,oBAAY;AACZ,iBAAS,EAAE,MAAM,kBAAkB,SAAS,MAAM,QAAQ,CAAC;AAC3D;AAAA,MACF,KAAK;AACH,oBAAY;AACZ,iBAAS,EAAE,MAAM,kBAAkB,SAAS,UAAU,MAAM,OAAO,GAAG,MAAM,SAAS;AAAA,EAAK,MAAM,MAAM,KAAK,EAAE,GAAG,CAAC;AACjH;AAAA,MACF,KAAK,SAAS;AACZ,oBAAY;AACZ,6BAAqB;AACrB,YAAI,CAAC,gBAAgB,MAAM,QAAQ,KAAK,GAAG;AACzC,oBAAU,MAAM,QAAQ,KAAK;AAC7B,sBAAY;AAAA,QACd;AACA,cAAM,MAAM,KAAK,IAAI;AACrB,cAAM,iBAAiB,MAAM,SAAS,oBAAoB;AAC1D,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS,IAAI,YAAY,IAAI,KAAK,GAAG,CAAC,CAAC,cAAW,SAAS,QAAQ,cAAc,IAAI,KAAK,GAAG,qBAAkB;AAAA,YAC7G,uBAAuB,OAAO,IAAI,MAAM;AAAA,UAC1C,CAAC,kBAAe,cAAc,SAAS,mBAAmB,IAAI,KAAK,GAAG;AAAA,UACtE,aAAa;AAAA,QACf,CAAC;AACD,cAAM,UAAU,MAAM;AACtB,cAAM,OAAO,UAAU,gBAAgB;AAAA,UACrC,UAAU,QAAQ;AAAA,UAClB,OAAO,QAAQ;AAAA,UACf,cAAc,QAAQ,gBAAgB;AAAA,UACtC,kBAAkB,QAAQ,oBAAoB;AAAA,UAC9C,iBAAiB,QAAQ,mBAAmB;AAAA,QAC9C,CAAC,EAAE,MAAM;AACT,YAAI,MAAM,SAAS;AACjB,mBAAS;AAAA,YACP,MAAM;AAAA,YACN,WAAW,KAAK,IAAI,IAAI,QAAQ;AAAA,YAChC,SAAS;AAAA,YACT,GAAI,SAAS,iBAAiB,SAAY,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;AAAA,YACpF,GAAI,SAAS,qBAAqB,SAAY,EAAE,kBAAkB,QAAQ,iBAAiB,IAAI,CAAC;AAAA,YAChG,GAAI,SAAS,oBAAoB,SAAY,EAAE,iBAAiB,QAAQ,gBAAgB,IAAI,CAAC;AAAA,UAC/F,CAAC;AAAA,QACH,OAAO;AACL,mBAAS,EAAE,MAAM,iBAAiB,WAAW,KAAK,IAAI,IAAI,QAAQ,WAAW,SAAS,KAAK,CAAC;AAAA,QAC9F;AACA;AAAA,MACF;AAAA,MACA;AACE;AAAA,IACJ;AAAA,EACF;AACA,EAAC,KAA+C,gBAAgB;AAChE,SAAO;AACT;AAEA,SAAS,sBAAsB,MAAc,OAAwB;AACnE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO,GAAG,IAAI;AAC/E,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,UAAa,UAAU,IAAI,EAC3D,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI,gBAAgB,KAAK,CAAC,EAAE;AAC3D,SAAO,GAAG,IAAI,IAAI,QAAQ,KAAK,IAAI,CAAC;AACtC;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAChD,WAAO,IAAI,QAAQ,SAAS,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC,QAAQ,OAAO;AAAA,EACzE;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,MAAM;AACjD,SAAO;AACT;;;ACpMA,IAAM,iBAA+B,EAAE,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,SAAS,EAAE;AAE5G,SAAS,gBAAgB,OAA4C,SAAyF,UAAsC;AAClM,QAAM,OAAqB;AAAA,IACzB,cAAc,QAAQ,gBAAgB,SAAS;AAAA,IAC/C,kBAAkB,QAAQ,oBAAoB,SAAS;AAAA,IACvD,iBAAiB,QAAQ,mBAAmB,SAAS;AAAA,IACrD,SAAS,SAAS;AAAA,EACpB;AACA,MAAI,MAAM,YAAY,MAAM,OAAO;AACjC,UAAM,OAAO,gBAAgB;AAAA,MAC3B,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,cAAc,KAAK;AAAA,MACnB,kBAAkB,KAAK;AAAA,MACvB,iBAAiB,KAAK;AAAA,IACxB,CAAC;AACD,SAAK,UAAU,KAAK;AAAA,EACtB;AACA,SAAO;AACT;AA6BO,SAAS,sBAAsB,UAAkC,CAAC,GAAa;AACpF,QAAM,MAAM,QAAQ,OAAO,KAAK,IAAI;AACpC,QAAM,iBAA+B,QAAQ,YAAY,QAAQ,QAC7D,CAAC;AAAA,IACC,IAAI,kBAAkB,GAAG;AAAA,IACzB,MAAM;AAAA,IACN,SAAS,4BAAyB,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AAAA,IACnE,aAAa;AAAA,EACf,CAAC,IACD,CAAC;AACL,QAAM,WAAW,CAAC,GAAG,gBAAgB,GAAI,QAAQ,mBAAmB,CAAC,CAAE;AACvE,SAAO;AAAA,IACL;AAAA,IACA,yBAAyB,CAAC;AAAA,IAC1B,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,eAAe,CAAC;AAAA,IAChB,gBAAgB;AAAA,IAChB,mBAAmB,QAAQ,qBAAqB;AAAA,IAChD,WAAW,QAAQ,oBAAoB;AAAA,IACvC,OAAO,QAAQ,gBAAgB,EAAE,SAAS,GAAG,aAAa,EAAE;AAAA,IAC5D,UAAU,EAAE,GAAG,eAAe;AAAA,IAC9B,UAAU,QAAQ,YAAY;AAAA,IAC9B,OAAO,QAAQ,SAAS;AAAA,IACxB,mBAAmB;AAAA,EACrB;AACF;AAEO,SAAS,WAAW,OAAiB,QAA6B;AACvE,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU,CAAC,GAAG,MAAM,UAAU;AAAA,UAC5B,IAAI,QAAQ,OAAO,WAAW,IAAI,MAAM,SAAS,MAAM;AAAA,UACvD,MAAM;AAAA,UACN,SAAS,OAAO;AAAA,UAChB,aAAa,OAAO;AAAA,QACtB,CAAC;AAAA,MACH;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU,CAAC,GAAG,MAAM,UAAU;AAAA,UAC5B,IAAI,UAAU,OAAO,eAAe,KAAK,IAAI,CAAC,IAAI,MAAM,SAAS,MAAM;AAAA,UACvE,MAAM;AAAA,UACN,SAAS,OAAO;AAAA,UAChB,aAAa,OAAO,eAAe,KAAK,IAAI;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF,KAAK;AACH,UAAI,MAAM,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,OAAO,EAAE,EAAG,QAAO;AACvE,aAAO;AAAA,QACL,GAAG;AAAA,QACH,aAAa,MAAM,cAAc,EAAE,GAAG,MAAM,aAAa,gBAAgB,MAAM,IAAI,MAAM;AAAA,QACzF,UAAU,CAAC,GAAG,MAAM,UAAU;AAAA,UAC5B,IAAI,OAAO;AAAA,UACX,MAAM;AAAA,UACN,SAAS;AAAA,UACT,aAAa,OAAO;AAAA,UACpB,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,QACD,yBAAyB;AAAA,UACvB,GAAG,MAAM;AAAA,UACT,CAAC,OAAO,EAAE,GAAG,MAAM,SAAS;AAAA,QAC9B;AAAA,QACA,iBAAiB,OAAO;AAAA,MAC1B;AAAA,IACF,KAAK,mBAAmB;AACtB,YAAM,cAAc,MAAM,wBAAwB,OAAO,EAAE;AAC3D,YAAM,QAAQ,gBAAgB,UAAa,MAAM,SAAS,WAAW,GAAG,OAAO,OAAO,KAClF,cACA,MAAM,SAAS,UAAU,CAACK,aAAYA,SAAQ,OAAO,OAAO,EAAE;AAClE,UAAI,QAAQ,EAAG,QAAO;AACtB,YAAM,WAAW,MAAM,SAAS,MAAM;AACtC,YAAM,UAAU,SAAS,KAAK;AAC9B,eAAS,KAAK,IAAI,EAAE,GAAG,SAAS,SAAS,GAAG,QAAQ,OAAO,GAAG,OAAO,IAAI,GAAG;AAC5E,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA,GAAI,gBAAgB,QAAQ,CAAC,IAAI;AAAA,UAC/B,yBAAyB;AAAA,YACvB,GAAG,MAAM;AAAA,YACT,CAAC,OAAO,EAAE,GAAG;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,aAAa,EAAE,WAAW,OAAO,WAAW,gBAAgB,KAAK,GAAG,eAAe,CAAC,GAAG,UAAU,EAAE,GAAG,eAAe,EAAE;AAAA,IAC5I,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,UAAU,gBAAgB,OAAO,QAAQ,MAAM,QAAQ,EAAE;AAAA,IAC9E,KAAK,iBAAiB;AACpB,YAAM,cAAc,OAAO,gBAAgB,MAAM,OAAO,oBAAoB,MAAM,OAAO,mBAAmB;AAC5G,YAAM,cAAc,MAAM,MAAM,WAAW;AAC3C,YAAM,gBAAgB,MAAM,MAAM,eAAe;AACjD,aAAO;AAAA,QACL,GAAG;AAAA,QACH,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,eAAe,CAAC;AAAA,QAChB,mBAAmB,MAAM,oBAAoB,OAAO;AAAA,QACpD,WAAW,MAAM,YAAY;AAAA,QAC7B,OAAO;AAAA,UACL,SAAS,OAAO,YAAY,QAAQ,OAAO,YAAY,SAAY,MAAM,MAAM,UAAU,cAAc,OAAO;AAAA,UAC9G,aAAa,aAAa,IAAI,gBAAgB,aAAa,MAAM,MAAM;AAAA,QACzE;AAAA,QACA,UAAU,EAAE,GAAG,eAAe;AAAA,MAChC;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,eAAe,CAAC;AAAA,QAChB,UAAU,EAAE,GAAG,eAAe;AAAA,QAC9B,UAAU,CAAC,GAAG,MAAM,UAAU;AAAA,UAC5B,IAAI,SAAS,KAAK,IAAI,CAAC,IAAI,MAAM,SAAS,MAAM;AAAA,UAChD,MAAM;AAAA,UACN,SAAS,UAAU,OAAO,OAAO;AAAA,UACjC,aAAa,KAAK,IAAI;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,CAAC,GAAG,MAAM,eAAe,OAAO,IAAI;AAAA,MACrD;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,MAAM,cAAc,IAAI,CAAC,SAAS,KAAK,OAAO,OAAO,KAChE,EAAE,GAAG,MAAM,SAAS,GAAG,KAAK,WAAW,EAAE,GAAG,OAAO,IAAI,GAAG,IAC1D,IAAI;AAAA,MACV;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,MAAM,cAAc,IAAI,CAAC,SAAS,KAAK,OAAO,OAAO,KAChE,EAAE,GAAG,MAAM,QAAQ,OAAO,QAAQ,SAAS,OAAO,SAAS,SAAS,OAAO,QAAQ,IACnF,IAAI;AAAA,MACV;AAAA,IACF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,mBAAmB,OAAO,QAAQ;AAAA,IACvD,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,mBAAmB,KAAK;AAAA,IAC7C,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU,OAAO;AAAA,QACjB,yBAAyB,CAAC;AAAA,QAC1B,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,eAAe,CAAC;AAAA,QAChB,mBAAmB,OAAO;AAAA,QAC1B,WAAW,OAAO;AAAA,QAClB,OAAO,OAAO;AAAA,QACd,UAAU,EAAE,GAAG,eAAe;AAAA,MAChC;AAAA,IACF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,UAAU,CAAC,GAAG,yBAAyB,CAAC,GAAG,iBAAiB,MAAM,eAAe,CAAC,EAAE;AAAA,IACzG;AACE,aAAO;AAAA,EACX;AACF;;;ACtPA,SAAS,WAAW,YAAAC,iBAAgB;AAE7B,SAAS,iBAAiB,aAAa,KAAc;AAC1D,QAAM,CAAC,KAAK,MAAM,IAAIA,UAAS,MAAM,KAAK,IAAI,CAAC;AAE/C,YAAU,MAAM;AACd,UAAM,QAAQ,YAAY,MAAM,OAAO,KAAK,IAAI,CAAC,GAAG,UAAU;AAC9D,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO;AACT;;;AXqNI,SACE,OAAAC,MADF,QAAAC,aAAA;AAnMJ,SAAS,uBAAuB,UAA4D;AAC1F,SAAO;AAAA,IACL,MAAM,OAAgB;AACpB,YAAM,UAAU,OAAO,KAAK,EAAE,QAAQ;AACtC,UAAI,QAAS,UAAS,EAAE,MAAM,kBAAkB,QAAQ,CAAC;AACzD,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,eAAe,OAAyB;AAC/C,SAAO,YAAY,cAAc,KAAK,IAAI,IAAI,MAAM,cAAc,CAAC,iBAAc,cAAc,MAAM,iBAAiB,CAAC,oBAAiB,MAAM,SAAS,QAAQ,MAAM,cAAc,IAAI,KAAK,GAAG;AACjM;AAEO,SAAS,IAAI;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAYG;AACD,QAAM,MAAM,OAAO;AACnB,QAAM,CAAC,OAAO,QAAQ,IAAI;AAAA,IACxB;AAAA,IACA;AAAA,MACE,UAAU,SAAS;AAAA,MACnB,OAAO,SAAS;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,QAAM,aAAaC,QAAsB,kBAAkB,CAAC,CAAC;AAC7D,QAAM,WAAWA,QAAO,KAAK;AAC7B,QAAM,wBAAwBA,QAA+B,IAAI;AACjE,QAAM,qBAAqBA,QAAwD,IAAI;AACvF,QAAM,MAAM,iBAAiB,GAAI;AAEjC,EAAAC,WAAU,MAAM;AACd,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,KAAK,CAAC;AAEV,EAAAA,WAAU,MAAM;AACd,UAAM,mBAAmB,MAAM;AAC7B,UAAI;AACF,2BAAmB,YAAY;AAAA,MACjC,QAAQ;AAAA,MAER;AAAA,IACF;AACA,YAAQ,GAAG,cAAc,gBAAgB;AACzC,WAAO,MAAM;AACX,cAAQ,IAAI,cAAc,gBAAgB;AAC1C,uBAAiB;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,iBAAiB,CAAC;AAEtB,EAAAA,WAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,YAAY;AAChB,YAAM,oBAAoB,GAAG;AAC7B,UAAI,UAAW;AACf,YAAM,sBAAsB,aAAa,EAAE,OAAO,CAAC,YAAY,QAAQ,aAAa,SAAS,EAAE;AAC/F,eAAS,EAAE,MAAM,kBAAkB,SAAS,qBAAkB,mBAAmB,mBAAmB,wBAAwB,IAAI,KAAK,GAAG,eAAY,CAAC;AAAA,IACvJ,GAAG;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,0BAAoD,OAAO,YAAY;AAC3E,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,yBAAmB,UAAU;AAC7B,eAAS,EAAE,MAAM,sBAAsB,QAAQ,CAAC;AAAA,IAClD,CAAC;AAAA,EACH;AAEA,QAAM,mBAAmB,CAAC,WAAiC;AACzD,UAAM,UAAU,mBAAmB;AACnC,uBAAmB,UAAU;AAC7B,aAAS,EAAE,MAAM,mBAAmB,CAAC;AACrC,cAAU,MAAM;AAAA,EAClB;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,SAAS,QAAQ,mBAAmB;AACtC,uBAAiB,EAAE,UAAU,OAAO,CAAC;AACrC,eAAS,EAAE,MAAM,kBAAkB,SAAS,qCAAqC,CAAC;AAClF;AAAA,IACF;AACA,QAAI,sBAAsB,WAAW,CAAC,sBAAsB,QAAQ,OAAO,SAAS;AAClF,4BAAsB,QAAQ,MAAM;AACpC,eAAS,EAAE,MAAM,kBAAkB,SAAS,wBAAwB,CAAC;AACrE;AAAA,IACF;AACA,QAAI;AACF,yBAAmB,YAAY;AAAA,IACjC,QAAQ;AAAA,IAER;AACA,oBAAgB,eAAe,SAAS,OAAO,CAAC;AAChD,QAAI,KAAK;AAAA,EACX;AAEA,QAAM,eAAe,CAAC,UAAkB;AACtC,QAAI,UAAU;AACZ,eAAS,KAAK;AACd;AAAA,IACF;AACA,UAAM,YAAY;AAChB,YAAM,SAAS,MAAM,KAAK;AAC1B,UAAI,CAAC,OAAQ;AACb,UAAI,OAAO,WAAW,GAAG,GAAG;AAC1B,cAAM,SAAS,uBAAuB,QAAQ;AAC9C,cAAM,2BAA2B,QAAQ;AAAA,UACvC;AAAA,UACA;AAAA,UACA,MAAM,YAAY;AAAA,UAAC;AAAA,UACnB;AAAA,UACA,SAAS,WAAW;AAAA,UACpB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,UAC7B;AAAA,UACA,cAAc,MAAM;AAClB,uBAAW,QAAQ,SAAS;AAC5B,qBAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,UAC5B;AAAA,UACA,gBAAgB,CAAC,gBAAgB;AAC/B,uBAAW,UAAU;AAAA,UACvB;AAAA,UACA,kBAAkB,CAAC,YAAY;AAC7B,mCAAuB,UAAU,OAAO;AAAA,UAC1C;AAAA,UACA,qBAAqB;AAAA,QACvB,CAAC;AACD;AAAA,MACF;AACA,YAAM,cAAc,KAAK,IAAI;AAC7B,eAAS,EAAE,MAAM,gBAAgB,SAAS,QAAQ,YAAY,CAAC;AAC/D,YAAM,YAAY,KAAK,IAAI;AAC3B,eAAS,EAAE,MAAM,cAAc,UAAU,CAAC;AAC1C,YAAM,wBAAwB,eAAe;AAAA,QAC3C,GAAG,WAAW;AAAA,QACd,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,MAClC,CAAC;AACD,eAAS,EAAE,MAAM,iBAAiB,cAAc,sBAAsB,CAAC;AACvE,YAAM,kBAAkB,IAAI,gBAAgB;AAC5C,4BAAsB,UAAU;AAChC,UAAI;AACF,cAAM,OAAO,cAAc,UAAU;AAAA,UACnC,UAAU,SAAS;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB;AAAA,QACF,CAAC;AACD,cAAM,SAAS,MAAM,SAAS;AAAA,UAC5B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,SAAS,WAAW;AAAA,UACpB,QAAQ,gBAAgB;AAAA,UACxB,qBAAqB;AAAA,UACrB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC/B,CAAC;AACD,mBAAW,QAAQ,KAAK,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AACzD,mBAAW,QAAQ,KAAK,EAAE,MAAM,aAAa,SAAS,OAAO,QAAQ,CAAC;AACtE,2BAAmB,oBAAoB,QAAQ,OAAO,SAAS,WAAW,KAAK,IAAI,IAAI,WAAW,MAAM;AAAA,MAC1G,SAAS,OAAO;AACd,iBAAS,EAAE,MAAM,cAAc,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;AAAA,MAClG,UAAE;AACA,8BAAsB,UAAU;AAAA,MAClC;AAAA,IACF,GAAG;AAAA,EACL;AAEA,SACE,gBAAAF,MAACG,MAAA,EAAI,eAAc,UAAS,QAAO,QAAO,WAAW,GACnD;AAAA,oBAAAJ;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,MAAM;AAAA,QAChB,aAAa,MAAM;AAAA,QACnB,iBAAiB,MAAM;AAAA;AAAA,IACzB;AAAA,IACA,gBAAAA,KAAC,iBAAc,OAAO,MAAM,eAAe;AAAA,IAC3C,gBAAAA,KAAC,oBAAiB,SAAS,MAAM,mBAAmB,UAAU,kBAAkB;AAAA,IAChF,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,MAAM,gBAAgB,QAAQ,MAAM,sBAAsB;AAAA,QACnE,GAAI,MAAM,aAAa,iBAAiB,EAAE,kBAAkB,MAAM,YAAY,UAAU,IAAI,CAAC;AAAA,QAC9F;AAAA,QACA,UAAU;AAAA,QACV,QAAQ;AAAA;AAAA,IACV;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,SAAS;AAAA,QACnB,OAAO,SAAS;AAAA,QAChB,gBAAgB,MAAM;AAAA,QACtB,OAAO,MAAM;AAAA,QACb,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,mBAAmB,MAAM,cAAc,KAAK,MAAM,gBAAgB;AAAA;AAAA,IACpE;AAAA,KACF;AAEJ;AAEA,SAAS,uBAAuB,UAAqC,SAA4B;AAC/F,QAAM,MAAM,KAAK,IAAI;AACrB,WAAS;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,QACE,IAAI,kBAAkB,QAAQ,EAAE,IAAI,GAAG;AAAA,QACvC,MAAM;AAAA,QACN,SAAS,aAAa,OAAO;AAAA,QAC7B,aAAa;AAAA,MACf;AAAA,MACA,GAAG,qBAAqB,SAAS,EAAE;AAAA,IACrC;AAAA,IACA,OAAO,gBAAgB,QAAQ,YAAY;AAAA,IAC3C,YAAY,QAAQ,aAAa;AAAA,IACjC,WAAW,QAAQ,aAAa;AAAA,EAClC,CAAC;AACH;;;AD7NI,gBAAAK,YAAA;AAlCJ,eAAsB,aAAa,SAMjB;AAChB,QAAM,eAAe,iBAAiB;AAAA,IACpC,KAAK,QAAQ;AAAA,IACb,UAAU,QAAQ,SAAS;AAAA,IAC3B,OAAO,QAAQ,SAAS;AAAA,IACxB,iBAAiB,QAAQ;AAAA,IACzB,iBAAiB,QAAQ;AAAA,EAC3B,CAAC;AACD,QAAM,kBAAgC,CAAC;AACvC,MAAI,aAAa,QAAQ;AACvB,oBAAgB,KAAK;AAAA,MACnB,IAAI,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAChC,MAAM;AAAA,MACN,SAAS,aAAa;AAAA,MACtB,aAAa,KAAK,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AACA,MAAI,aAAa,gBAAgB;AAC/B,oBAAgB,KAAK;AAAA,MACnB,IAAI,kBAAkB,aAAa,eAAe,EAAE;AAAA,MACpD,MAAM;AAAA,MACN,SAAS,aAAa,aAAa,cAAc;AAAA,MACjD,aAAa,KAAK,IAAI;AAAA,IACxB,CAAC;AACD,oBAAgB,KAAK,GAAG,qBAAqB,aAAa,gBAAgB,EAAE,CAAC;AAAA,EAC/E;AACA,MAAI,UAAU;AACd,QAAM,WAAW;AAAA,IACf,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,QAAQ;AAAA,QAClB,KAAK,QAAQ;AAAA,QACZ,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,QACvD,mBAAmB,aAAa;AAAA,QAChC;AAAA,QACA,gBAAgB,aAAa,iBAAiB,qBAAqB,aAAa,cAAc,IAAI,CAAC;AAAA,QACnG,cAAc,gBAAgB,aAAa,WAAW,QAAQ,YAAY;AAAA,QAC1E,mBAAmB,aAAa,WAAW,QAAQ,aAAa;AAAA,QAChE,kBAAkB,aAAa,WAAW,QAAQ,aAAa;AAAA,QAC/D,eAAe,CAAC,SAAS;AACvB,oBAAU;AAAA,QACZ;AAAA;AAAA,IACF;AAAA,IACA,EAAE,aAAa,MAAM;AAAA,EACvB;AACA,QAAM,SAAS,cAAc;AAC7B,MAAI,QAAS,SAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAClD;","names":["useEffect","useRef","Box","React","Box","Text","Box","Text","jsx","jsxs","jsx","jsxs","React","MessageBlock","Box","Text","Box","Text","Text","jsxs","jsx","jsxs","divider","Box","Text","Box","Text","useInput","jsx","jsxs","React","Box","Text","jsx","jsxs","message","useState","jsx","jsxs","useRef","useEffect","Box","jsx"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matheuskrumenauer/tanya",
3
- "version": "0.17.0",
3
+ "version": "0.17.6",
4
4
  "description": "A live, tool-using AI CLI for DeepSeek and OpenAI-compatible providers.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,6 +30,7 @@
30
30
  "smoke:examples": "node scripts/smoke-examples.mjs",
31
31
  "test": "vitest run",
32
32
  "typecheck": "tsc --noEmit",
33
+ "publish:npm": "node scripts/npm-publish.mjs",
33
34
  "prepublishOnly": "npm run typecheck && npm test && npm run build"
34
35
  },
35
36
  "keywords": [