@agentick/tui 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +167 -0
  2. package/dist/bin.d.ts +12 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +199 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/components/ErrorDisplay.d.ts +12 -0
  7. package/dist/components/ErrorDisplay.d.ts.map +1 -0
  8. package/dist/components/ErrorDisplay.js +17 -0
  9. package/dist/components/ErrorDisplay.js.map +1 -0
  10. package/dist/components/InputBar.d.ts +13 -0
  11. package/dist/components/InputBar.d.ts.map +1 -0
  12. package/dist/components/InputBar.js +20 -0
  13. package/dist/components/InputBar.js.map +1 -0
  14. package/dist/components/MessageList.d.ts +12 -0
  15. package/dist/components/MessageList.d.ts.map +1 -0
  16. package/dist/components/MessageList.js +81 -0
  17. package/dist/components/MessageList.js.map +1 -0
  18. package/dist/components/StreamingMessage.d.ts +7 -0
  19. package/dist/components/StreamingMessage.d.ts.map +1 -0
  20. package/dist/components/StreamingMessage.js +15 -0
  21. package/dist/components/StreamingMessage.js.map +1 -0
  22. package/dist/components/TUIApp.d.ts +18 -0
  23. package/dist/components/TUIApp.d.ts.map +1 -0
  24. package/dist/components/TUIApp.js +97 -0
  25. package/dist/components/TUIApp.js.map +1 -0
  26. package/dist/components/ToolCallIndicator.d.ts +12 -0
  27. package/dist/components/ToolCallIndicator.d.ts.map +1 -0
  28. package/dist/components/ToolCallIndicator.js +49 -0
  29. package/dist/components/ToolCallIndicator.js.map +1 -0
  30. package/dist/components/ToolConfirmationPrompt.d.ts +14 -0
  31. package/dist/components/ToolConfirmationPrompt.d.ts.map +1 -0
  32. package/dist/components/ToolConfirmationPrompt.js +33 -0
  33. package/dist/components/ToolConfirmationPrompt.js.map +1 -0
  34. package/dist/create-tui.d.ts +44 -0
  35. package/dist/create-tui.d.ts.map +1 -0
  36. package/dist/create-tui.js +29 -0
  37. package/dist/create-tui.js.map +1 -0
  38. package/dist/index.d.ts +41 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +43 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/testing.d.ts +31 -0
  43. package/dist/testing.d.ts.map +1 -0
  44. package/dist/testing.js +31 -0
  45. package/dist/testing.js.map +1 -0
  46. package/dist/ui/chat.d.ts +18 -0
  47. package/dist/ui/chat.d.ts.map +1 -0
  48. package/dist/ui/chat.js +97 -0
  49. package/dist/ui/chat.js.map +1 -0
  50. package/dist/ui/index.d.ts +8 -0
  51. package/dist/ui/index.d.ts.map +1 -0
  52. package/dist/ui/index.js +5 -0
  53. package/dist/ui/index.js.map +1 -0
  54. package/package.json +73 -0
  55. package/src/index.ts +45 -0
@@ -0,0 +1,97 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * TUIApp — top-level TUI layout.
4
+ *
5
+ * Orchestrates the conversation: message history, streaming response,
6
+ * tool call indicators, tool confirmation prompts, error display, and user input.
7
+ *
8
+ * State machine: idle → streaming → (confirming_tool → streaming) → idle
9
+ * Ctrl+C behavior depends on state:
10
+ * - idle: exit the process
11
+ * - streaming: abort current execution
12
+ * - confirming_tool: reject tool, return to streaming
13
+ */
14
+ import { useCallback, useEffect, useState } from "react";
15
+ import { Box, Text, useApp, useInput } from "ink";
16
+ import { useSession, useStreamingText } from "@agentick/react";
17
+ import { MessageList } from "./MessageList.js";
18
+ import { StreamingMessage } from "./StreamingMessage.js";
19
+ import { ToolCallIndicator } from "./ToolCallIndicator.js";
20
+ import { ToolConfirmationPrompt } from "./ToolConfirmationPrompt.js";
21
+ import { ErrorDisplay } from "./ErrorDisplay.js";
22
+ import { InputBar } from "./InputBar.js";
23
+ export function TUIApp({ sessionId }) {
24
+ const { exit } = useApp();
25
+ const { send, abort, accessor } = useSession({ sessionId, autoSubscribe: true });
26
+ const { isStreaming } = useStreamingText();
27
+ const [tuiState, setTuiState] = useState("idle");
28
+ const [toolConfirmation, setToolConfirmation] = useState(null);
29
+ const [error, setError] = useState(null);
30
+ // Sync streaming state → tuiState (unless we're in confirming_tool, which takes priority)
31
+ useEffect(() => {
32
+ if (isStreaming && tuiState === "idle") {
33
+ setTuiState("streaming");
34
+ setError(null); // Clear previous errors on new execution
35
+ }
36
+ else if (!isStreaming && tuiState === "streaming") {
37
+ setTuiState("idle");
38
+ }
39
+ }, [isStreaming, tuiState]);
40
+ // Register tool confirmation handler
41
+ useEffect(() => {
42
+ if (!accessor)
43
+ return;
44
+ return accessor.onToolConfirmation((request, respond) => {
45
+ setToolConfirmation({ request, respond });
46
+ setTuiState("confirming_tool");
47
+ });
48
+ }, [accessor]);
49
+ // Ctrl+C handling
50
+ useInput((_input, key) => {
51
+ if (!key.ctrl || _input !== "c")
52
+ return;
53
+ if (tuiState === "idle") {
54
+ exit();
55
+ }
56
+ else if (tuiState === "streaming") {
57
+ abort();
58
+ setTuiState("idle");
59
+ }
60
+ else if (tuiState === "confirming_tool" && toolConfirmation) {
61
+ toolConfirmation.respond({ approved: false, reason: "cancelled by user" });
62
+ setToolConfirmation(null);
63
+ setTuiState("streaming");
64
+ }
65
+ });
66
+ const handleSubmit = useCallback((text) => {
67
+ if (text === "/exit" || text === "/quit") {
68
+ exit();
69
+ return;
70
+ }
71
+ setError(null);
72
+ try {
73
+ send(text);
74
+ }
75
+ catch (err) {
76
+ setError(err instanceof Error ? err : String(err));
77
+ }
78
+ }, [send, exit]);
79
+ const handleToolConfirmationResponse = useCallback((response) => {
80
+ if (toolConfirmation) {
81
+ toolConfirmation.respond(response);
82
+ setToolConfirmation(null);
83
+ setTuiState("streaming");
84
+ }
85
+ }, [toolConfirmation]);
86
+ const handleErrorDismiss = useCallback(() => {
87
+ setError(null);
88
+ }, []);
89
+ const isInputDisabled = tuiState !== "idle";
90
+ const placeholder = tuiState === "streaming"
91
+ ? "Waiting for response... (Ctrl+C to abort)"
92
+ : tuiState === "confirming_tool"
93
+ ? "Confirm or reject the tool above..."
94
+ : undefined;
95
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "agentick" }), _jsx(Text, { color: "gray", children: " \u2014 type /exit to quit" })] }), _jsx(MessageList, { sessionId: sessionId }), _jsx(StreamingMessage, {}), _jsx(ToolCallIndicator, { sessionId: sessionId }), tuiState === "confirming_tool" && toolConfirmation && (_jsx(ToolConfirmationPrompt, { request: toolConfirmation.request, onRespond: handleToolConfirmationResponse })), _jsx(ErrorDisplay, { error: error, onDismiss: handleErrorDismiss }), _jsx(Box, { marginTop: 1, children: _jsx(InputBar, { onSubmit: handleSubmit, isDisabled: isInputDisabled, placeholder: placeholder }) })] }));
96
+ }
97
+ //# sourceMappingURL=TUIApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TUIApp.js","sourceRoot":"","sources":["../../src/components/TUIApp.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * ToolCallIndicator — shows tool execution feedback.
3
+ *
4
+ * Shows a spinner + tool name during execution,
5
+ * completed indicator when done.
6
+ */
7
+ interface ToolCallIndicatorProps {
8
+ sessionId?: string;
9
+ }
10
+ export declare function ToolCallIndicator({ sessionId }: ToolCallIndicatorProps): import("react/jsx-runtime").JSX.Element | null;
11
+ export {};
12
+ //# sourceMappingURL=ToolCallIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolCallIndicator.d.ts","sourceRoot":"","sources":["../../src/components/ToolCallIndicator.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,UAAU,sBAAsB;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,EAAE,EAAE,sBAAsB,kDAwDtE"}
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ToolCallIndicator — shows tool execution feedback.
4
+ *
5
+ * Shows a spinner + tool name during execution,
6
+ * completed indicator when done.
7
+ */
8
+ import { useState, useEffect } from "react";
9
+ import { Box, Text } from "ink";
10
+ import Spinner from "ink-spinner";
11
+ import { useEvents } from "@agentick/react";
12
+ export function ToolCallIndicator({ sessionId }) {
13
+ const [tools, setTools] = useState([]);
14
+ const { event } = useEvents({
15
+ sessionId,
16
+ filter: ["tool_call_start", "tool_call", "tool_result"],
17
+ });
18
+ useEffect(() => {
19
+ if (!event)
20
+ return;
21
+ if (event.type === "tool_call_start" || event.type === "tool_call") {
22
+ const e = event;
23
+ const id = e.toolUseId ?? e.id ?? "unknown";
24
+ const name = e.name ?? "tool";
25
+ setTools((prev) => {
26
+ if (prev.some((t) => t.id === id))
27
+ return prev;
28
+ return [...prev, { id, name, status: "running" }];
29
+ });
30
+ }
31
+ if (event.type === "tool_result") {
32
+ const e = event;
33
+ const id = e.toolUseId ?? "unknown";
34
+ setTools((prev) => prev.map((t) => (t.id === id ? { ...t, status: "done" } : t)));
35
+ }
36
+ }, [event]);
37
+ // Clean up completed tools after a short delay
38
+ useEffect(() => {
39
+ const allDone = tools.length > 0 && tools.every((t) => t.status === "done");
40
+ if (allDone) {
41
+ const timer = setTimeout(() => setTools([]), 1500);
42
+ return () => clearTimeout(timer);
43
+ }
44
+ }, [tools]);
45
+ if (tools.length === 0)
46
+ return null;
47
+ return (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: tools.map((tool) => (_jsxs(Box, { gap: 1, children: [tool.status === "running" ? (_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) })) : (_jsx(Text, { color: "green", children: "\u2713" })), _jsx(Text, { color: tool.status === "running" ? "yellow" : "gray", dimColor: tool.status === "done", children: tool.name })] }, tool.id))) }));
48
+ }
49
+ //# sourceMappingURL=ToolCallIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolCallIndicator.js","sourceRoot":"","sources":["../../src/components/ToolCallIndicator.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ToolConfirmationPrompt — inline confirmation UI for tools that require approval.
3
+ *
4
+ * Shows tool name, arguments, and Y/N/A key bindings.
5
+ * Renders as a bordered box inline in the terminal (no overlays).
6
+ */
7
+ import type { ToolConfirmationRequest, ToolConfirmationResponse } from "@agentick/client";
8
+ interface ToolConfirmationPromptProps {
9
+ request: ToolConfirmationRequest;
10
+ onRespond: (response: ToolConfirmationResponse) => void;
11
+ }
12
+ export declare function ToolConfirmationPrompt({ request, onRespond }: ToolConfirmationPromptProps): import("react/jsx-runtime").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=ToolConfirmationPrompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolConfirmationPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ToolConfirmationPrompt.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,UAAU,2BAA2B;IACnC,OAAO,EAAE,uBAAuB,CAAC;IACjC,SAAS,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACzD;AAWD,wBAAgB,sBAAsB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,2BAA2B,2CAsDzF"}
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ToolConfirmationPrompt — inline confirmation UI for tools that require approval.
4
+ *
5
+ * Shows tool name, arguments, and Y/N/A key bindings.
6
+ * Renders as a bordered box inline in the terminal (no overlays).
7
+ */
8
+ import { Box, Text, useInput } from "ink";
9
+ function formatArguments(args) {
10
+ const json = JSON.stringify(args, null, 2);
11
+ const lines = json.split("\n");
12
+ if (lines.length > 10) {
13
+ return lines.slice(0, 10).join("\n") + "\n ...";
14
+ }
15
+ return json;
16
+ }
17
+ export function ToolConfirmationPrompt({ request, onRespond }) {
18
+ useInput((input) => {
19
+ const key = input.toLowerCase();
20
+ if (key === "y") {
21
+ onRespond({ approved: true });
22
+ }
23
+ else if (key === "n") {
24
+ onRespond({ approved: false, reason: "rejected by user" });
25
+ }
26
+ else if (key === "a") {
27
+ // "Always allow" — for now just approves (no persistence, YAGNI)
28
+ onRespond({ approved: true });
29
+ }
30
+ });
31
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: "yellow", bold: true, children: "Tool Confirmation" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: [_jsx(Text, { bold: true, children: request.name }), " wants to run:"] }) }), request.message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: request.message }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: formatArguments(request.arguments) }) }), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsx(Text, { color: "green", bold: true, children: "[Y] Approve" }), _jsx(Text, { color: "red", bold: true, children: "[N] Reject" }), _jsx(Text, { color: "cyan", bold: true, children: "[A] Always Allow" })] })] }));
32
+ }
33
+ //# sourceMappingURL=ToolConfirmationPrompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolConfirmationPrompt.js","sourceRoot":"","sources":["../../src/components/ToolConfirmationPrompt.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAQ1C,SAAS,eAAe,CAAC,IAA6B;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAE,OAAO,EAAE,SAAS,EAA+B;IACxF,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;QACjB,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YAChB,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YACvB,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YACvB,iEAAiE;YACjE,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAC,QAAQ,EACpB,QAAQ,EAAE,CAAC,EACX,SAAS,EAAE,CAAC,aAEZ,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,wCAElB,EAEP,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,IAAI,kBAAE,OAAO,CAAC,IAAI,GAAQ,sBAC3B,GACH,EAEL,OAAO,CAAC,OAAO,IAAI,CAClB,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,OAAO,CAAC,OAAO,GAAQ,GACvC,CACP,EAED,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,GAAQ,GAC1D,EAEN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,aACvB,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,kCAEjB,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,EAAC,IAAI,iCAEf,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,uCAEhB,IACH,IACF,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * createTUI — entry point for the terminal UI.
3
+ *
4
+ * Supports local (in-process) and remote (gateway) agents.
5
+ * The TUI components don't know or care about local vs remote.
6
+ * Same hooks, same rendering. The transport determines where the agent lives.
7
+ *
8
+ * @example Local
9
+ * ```typescript
10
+ * createTUI({ app: myApp }).start();
11
+ * ```
12
+ *
13
+ * @example Remote
14
+ * ```typescript
15
+ * createTUI({ url: 'https://my-agent.fly.dev/api' }).start();
16
+ * ```
17
+ *
18
+ * @example Custom UI
19
+ * ```typescript
20
+ * createTUI({ app: myApp, ui: MyDashboard }).start();
21
+ * ```
22
+ *
23
+ * @module @agentick/tui/create-tui
24
+ */
25
+ import type { ComponentType } from "react";
26
+ import type { App } from "@agentick/core";
27
+ /** A TUI component receives a sessionId and renders the full interface. */
28
+ export type TUIComponent = ComponentType<{
29
+ sessionId: string;
30
+ }>;
31
+ export type TUIOptions = {
32
+ app: App;
33
+ sessionId?: string;
34
+ ui?: TUIComponent;
35
+ } | {
36
+ url: string;
37
+ token?: string;
38
+ sessionId?: string;
39
+ ui?: TUIComponent;
40
+ };
41
+ export declare function createTUI(options: TUIOptions): {
42
+ start(): Promise<void>;
43
+ };
44
+ //# sourceMappingURL=create-tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-tui.d.ts","sourceRoot":"","sources":["../src/create-tui.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAM3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAG1C,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhE,MAAM,MAAM,UAAU,GAClB;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,YAAY,CAAA;CAAE,GACnD;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3E,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU;;EA6B5C"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "ink";
3
+ import { createClient } from "@agentick/client";
4
+ import { createLocalTransport } from "@agentick/core";
5
+ import { AgentickProvider } from "@agentick/react";
6
+ import { Chat } from "./ui/chat.js";
7
+ import EventSourcePolyfill from "eventsource";
8
+ export function createTUI(options) {
9
+ return {
10
+ start() {
11
+ const sessionId = options.sessionId ?? "main";
12
+ const Component = options.ui ?? Chat;
13
+ const client = "app" in options
14
+ ? createClient({
15
+ baseUrl: "local://",
16
+ transport: createLocalTransport(options.app),
17
+ })
18
+ : createClient({
19
+ baseUrl: options.url,
20
+ token: options.token,
21
+ EventSource: (globalThis.EventSource ??
22
+ EventSourcePolyfill),
23
+ });
24
+ const { waitUntilExit } = render(_jsx(AgentickProvider, { client: client, children: _jsx(Component, { sessionId: sessionId }) }), { exitOnCtrlC: false });
25
+ return waitUntilExit();
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=create-tui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-tui.js","sourceRoot":"","sources":["../src/create-tui.tsx"],"names":[],"mappings":";AA0BA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,OAAO,mBAAmB,MAAM,aAAa,CAAC;AAS9C,MAAM,UAAU,SAAS,CAAC,OAAmB;IAC3C,OAAO;QACL,KAAK;YACH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC;YAErC,MAAM,MAAM,GACV,KAAK,IAAI,OAAO;gBACd,CAAC,CAAC,YAAY,CAAC;oBACX,OAAO,EAAE,UAAU;oBACnB,SAAS,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC;iBAC7C,CAAC;gBACJ,CAAC,CAAC,YAAY,CAAC;oBACX,OAAO,EAAE,OAAO,CAAC,GAAG;oBACpB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,WAAW,EAAE,CAAC,UAAU,CAAC,WAAW;wBAClC,mBAAmB,CAAkC;iBACxD,CAAC,CAAC;YAET,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAC,gBAAgB,IAAC,MAAM,EAAE,MAAM,YAC9B,KAAC,SAAS,IAAC,SAAS,EAAE,SAAS,GAAI,GAClB,EACnB,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAC;YAEF,OAAO,aAAa,EAAE,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @agentick/tui - Terminal UI for Agentick
3
+ *
4
+ * Ink-based terminal UI that reuses @agentick/react hooks.
5
+ * Works with both local (in-process) and remote agents.
6
+ *
7
+ * @example Local agent
8
+ * ```typescript
9
+ * import { createApp } from '@agentick/core';
10
+ * import { createTUI } from '@agentick/tui';
11
+ *
12
+ * const app = createApp(MyAgent, { model });
13
+ * createTUI({ app }).start();
14
+ * ```
15
+ *
16
+ * @example Remote agent
17
+ * ```typescript
18
+ * import { createTUI } from '@agentick/tui';
19
+ *
20
+ * createTUI({ url: 'https://my-agent.fly.dev/api' }).start();
21
+ * ```
22
+ *
23
+ * @example Custom UI
24
+ * ```typescript
25
+ * import { createTUI } from '@agentick/tui';
26
+ * import { MyDashboard } from './my-dashboard.js';
27
+ *
28
+ * createTUI({ app, ui: MyDashboard }).start();
29
+ * ```
30
+ *
31
+ * @module @agentick/tui
32
+ */
33
+ export { createTUI, type TUIOptions, type TUIComponent } from "./create-tui.js";
34
+ export { Chat } from "./ui/chat.js";
35
+ export { MessageList } from "./components/MessageList.js";
36
+ export { StreamingMessage } from "./components/StreamingMessage.js";
37
+ export { ToolCallIndicator } from "./components/ToolCallIndicator.js";
38
+ export { ToolConfirmationPrompt } from "./components/ToolConfirmationPrompt.js";
39
+ export { ErrorDisplay } from "./components/ErrorDisplay.js";
40
+ export { InputBar } from "./components/InputBar.js";
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGhF,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @agentick/tui - Terminal UI for Agentick
3
+ *
4
+ * Ink-based terminal UI that reuses @agentick/react hooks.
5
+ * Works with both local (in-process) and remote agents.
6
+ *
7
+ * @example Local agent
8
+ * ```typescript
9
+ * import { createApp } from '@agentick/core';
10
+ * import { createTUI } from '@agentick/tui';
11
+ *
12
+ * const app = createApp(MyAgent, { model });
13
+ * createTUI({ app }).start();
14
+ * ```
15
+ *
16
+ * @example Remote agent
17
+ * ```typescript
18
+ * import { createTUI } from '@agentick/tui';
19
+ *
20
+ * createTUI({ url: 'https://my-agent.fly.dev/api' }).start();
21
+ * ```
22
+ *
23
+ * @example Custom UI
24
+ * ```typescript
25
+ * import { createTUI } from '@agentick/tui';
26
+ * import { MyDashboard } from './my-dashboard.js';
27
+ *
28
+ * createTUI({ app, ui: MyDashboard }).start();
29
+ * ```
30
+ *
31
+ * @module @agentick/tui
32
+ */
33
+ export { createTUI } from "./create-tui.js";
34
+ // Built-in UIs
35
+ export { Chat } from "./ui/chat.js";
36
+ // Components for custom UI composition
37
+ export { MessageList } from "./components/MessageList.js";
38
+ export { StreamingMessage } from "./components/StreamingMessage.js";
39
+ export { ToolCallIndicator } from "./components/ToolCallIndicator.js";
40
+ export { ToolConfirmationPrompt } from "./components/ToolConfirmationPrompt.js";
41
+ export { ErrorDisplay } from "./components/ErrorDisplay.js";
42
+ export { InputBar } from "./components/InputBar.js";
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,SAAS,EAAsC,MAAM,iBAAiB,CAAC;AAEhF,eAAe;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,uCAAuC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Test utilities for @agentick/tui.
3
+ *
4
+ * react-reconciler@0.31 with `supportsMicrotasks: true` schedules render work
5
+ * via queueMicrotask, and React's Scheduler flushes passive effects (useEffect)
6
+ * via setImmediate in Node.js.
7
+ *
8
+ * After render() or state changes, we need to wait for:
9
+ * 1. Microtasks — React render + commit, Ink stdout.write
10
+ * 2. Passive effects — useEffect callbacks (e.g., useInput's stdin listener)
11
+ *
12
+ * The flush() utility chains setTimeout(0) → setImmediate to guarantee both
13
+ * have completed:
14
+ * - setTimeout(0) yields to the macrotask queue, ensuring all microtasks
15
+ * (render + commit) have drained
16
+ * - setImmediate runs in Node's check phase, AFTER React's Scheduler has
17
+ * flushed passive effects (also scheduled via setImmediate, but earlier)
18
+ *
19
+ * This works regardless of setTimeout vs setImmediate ordering (which is
20
+ * non-deterministic at the top level in Node.js):
21
+ * - If setImmediate fires first: effects already ran, our flush confirms it
22
+ * - If setTimeout fires first: our setImmediate queues after React's, runs after effects
23
+ */
24
+ /**
25
+ * Flush pending React renders and effects.
26
+ *
27
+ * Call after render(), stdin.write(), or any state-triggering action.
28
+ * One call is sufficient — no need for double-flush or magic timeouts.
29
+ */
30
+ export declare const flush: () => Promise<void>;
31
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,KAAK,qBAC8C,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Test utilities for @agentick/tui.
3
+ *
4
+ * react-reconciler@0.31 with `supportsMicrotasks: true` schedules render work
5
+ * via queueMicrotask, and React's Scheduler flushes passive effects (useEffect)
6
+ * via setImmediate in Node.js.
7
+ *
8
+ * After render() or state changes, we need to wait for:
9
+ * 1. Microtasks — React render + commit, Ink stdout.write
10
+ * 2. Passive effects — useEffect callbacks (e.g., useInput's stdin listener)
11
+ *
12
+ * The flush() utility chains setTimeout(0) → setImmediate to guarantee both
13
+ * have completed:
14
+ * - setTimeout(0) yields to the macrotask queue, ensuring all microtasks
15
+ * (render + commit) have drained
16
+ * - setImmediate runs in Node's check phase, AFTER React's Scheduler has
17
+ * flushed passive effects (also scheduled via setImmediate, but earlier)
18
+ *
19
+ * This works regardless of setTimeout vs setImmediate ordering (which is
20
+ * non-deterministic at the top level in Node.js):
21
+ * - If setImmediate fires first: effects already ran, our flush confirms it
22
+ * - If setTimeout fires first: our setImmediate queues after React's, runs after effects
23
+ */
24
+ /**
25
+ * Flush pending React renders and effects.
26
+ *
27
+ * Call after render(), stdin.write(), or any state-triggering action.
28
+ * One call is sufficient — no need for double-flush or magic timeouts.
29
+ */
30
+ export const flush = () => new Promise((r) => setTimeout(() => setImmediate(r), 0));
31
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,EAAE,CACxB,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Chat — default TUI layout.
3
+ *
4
+ * Orchestrates the conversation: message history, streaming response,
5
+ * tool call indicators, tool confirmation prompts, error display, and user input.
6
+ *
7
+ * State machine: idle → streaming → (confirming_tool → streaming) → idle
8
+ * Ctrl+C behavior depends on state:
9
+ * - idle: exit the process
10
+ * - streaming: abort current execution
11
+ * - confirming_tool: reject tool, return to streaming
12
+ */
13
+ interface ChatProps {
14
+ sessionId: string;
15
+ }
16
+ export declare function Chat({ sessionId }: ChatProps): import("react/jsx-runtime").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/ui/chat.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,UAAU,SAAS;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AASD,wBAAgB,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,2CAkH5C"}
@@ -0,0 +1,97 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Chat — default TUI layout.
4
+ *
5
+ * Orchestrates the conversation: message history, streaming response,
6
+ * tool call indicators, tool confirmation prompts, error display, and user input.
7
+ *
8
+ * State machine: idle → streaming → (confirming_tool → streaming) → idle
9
+ * Ctrl+C behavior depends on state:
10
+ * - idle: exit the process
11
+ * - streaming: abort current execution
12
+ * - confirming_tool: reject tool, return to streaming
13
+ */
14
+ import { useCallback, useEffect, useState } from "react";
15
+ import { Box, Text, useApp, useInput } from "ink";
16
+ import { useSession, useStreamingText } from "@agentick/react";
17
+ import { MessageList } from "../components/MessageList.js";
18
+ import { StreamingMessage } from "../components/StreamingMessage.js";
19
+ import { ToolCallIndicator } from "../components/ToolCallIndicator.js";
20
+ import { ToolConfirmationPrompt } from "../components/ToolConfirmationPrompt.js";
21
+ import { ErrorDisplay } from "../components/ErrorDisplay.js";
22
+ import { InputBar } from "../components/InputBar.js";
23
+ export function Chat({ sessionId }) {
24
+ const { exit } = useApp();
25
+ const { send, abort, accessor } = useSession({ sessionId, autoSubscribe: true });
26
+ const { isStreaming } = useStreamingText();
27
+ const [chatState, setChatState] = useState("idle");
28
+ const [toolConfirmation, setToolConfirmation] = useState(null);
29
+ const [error, setError] = useState(null);
30
+ // Sync streaming state → chatState (unless we're in confirming_tool, which takes priority)
31
+ useEffect(() => {
32
+ if (isStreaming && chatState === "idle") {
33
+ setChatState("streaming");
34
+ setError(null); // Clear previous errors on new execution
35
+ }
36
+ else if (!isStreaming && chatState === "streaming") {
37
+ setChatState("idle");
38
+ }
39
+ }, [isStreaming, chatState]);
40
+ // Register tool confirmation handler
41
+ useEffect(() => {
42
+ if (!accessor)
43
+ return;
44
+ return accessor.onToolConfirmation((request, respond) => {
45
+ setToolConfirmation({ request, respond });
46
+ setChatState("confirming_tool");
47
+ });
48
+ }, [accessor]);
49
+ // Ctrl+C handling
50
+ useInput((_input, key) => {
51
+ if (!key.ctrl || _input !== "c")
52
+ return;
53
+ if (chatState === "idle") {
54
+ exit();
55
+ }
56
+ else if (chatState === "streaming") {
57
+ abort();
58
+ setChatState("idle");
59
+ }
60
+ else if (chatState === "confirming_tool" && toolConfirmation) {
61
+ toolConfirmation.respond({ approved: false, reason: "cancelled by user" });
62
+ setToolConfirmation(null);
63
+ setChatState("streaming");
64
+ }
65
+ });
66
+ const handleSubmit = useCallback((text) => {
67
+ if (text === "/exit" || text === "/quit") {
68
+ exit();
69
+ return;
70
+ }
71
+ setError(null);
72
+ try {
73
+ send(text);
74
+ }
75
+ catch (err) {
76
+ setError(err instanceof Error ? err : String(err));
77
+ }
78
+ }, [send, exit]);
79
+ const handleToolConfirmationResponse = useCallback((response) => {
80
+ if (toolConfirmation) {
81
+ toolConfirmation.respond(response);
82
+ setToolConfirmation(null);
83
+ setChatState("streaming");
84
+ }
85
+ }, [toolConfirmation]);
86
+ const handleErrorDismiss = useCallback(() => {
87
+ setError(null);
88
+ }, []);
89
+ const isInputDisabled = chatState !== "idle";
90
+ const placeholder = chatState === "streaming"
91
+ ? "Waiting for response... (Ctrl+C to abort)"
92
+ : chatState === "confirming_tool"
93
+ ? "Confirm or reject the tool above..."
94
+ : undefined;
95
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "agentick" }), _jsx(Text, { color: "gray", children: " \u2014 type /exit to quit" })] }), _jsx(MessageList, { sessionId: sessionId }), _jsx(StreamingMessage, {}), _jsx(ToolCallIndicator, { sessionId: sessionId }), chatState === "confirming_tool" && toolConfirmation && (_jsx(ToolConfirmationPrompt, { request: toolConfirmation.request, onRespond: handleToolConfirmationResponse })), _jsx(ErrorDisplay, { error: error, onDismiss: handleErrorDismiss }), _jsx(Box, { marginTop: 1, children: _jsx(InputBar, { onSubmit: handleSubmit, isDisabled: isInputDisabled, placeholder: placeholder }) })] }));
96
+ }
97
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/ui/chat.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { Chat } from "./chat.js";
2
+ export { Chat };
3
+ /** Registry of built-in UIs, keyed by CLI name. */
4
+ export declare const builtinUIs: {
5
+ chat: typeof Chat;
6
+ };
7
+ export type BuiltinUIName = keyof typeof builtinUIs;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,IAAI,EAAE,CAAC;AAEhB,mDAAmD;AACnD,eAAO,MAAM,UAAU;;CAAiB,CAAC;AAEzC,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Chat } from "./chat.js";
2
+ export { Chat };
3
+ /** Registry of built-in UIs, keyed by CLI name. */
4
+ export const builtinUIs = { chat: Chat };
5
+ //# sourceMappingURL=index.js.map