@pentoshi/clai 1.2.6 → 1.2.7

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 (69) hide show
  1. package/dist/agent/classic-renderer.d.ts +5 -0
  2. package/dist/agent/classic-renderer.js +124 -0
  3. package/dist/agent/classic-renderer.js.map +1 -0
  4. package/dist/agent/events.d.ts +62 -0
  5. package/dist/agent/events.js +2 -0
  6. package/dist/agent/events.js.map +1 -0
  7. package/dist/agent/runner.d.ts +8 -0
  8. package/dist/agent/runner.js +195 -71
  9. package/dist/agent/runner.js.map +1 -1
  10. package/dist/commands/update.js +1 -1
  11. package/dist/index.js +32 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/llm/capabilities.js +1 -0
  14. package/dist/llm/capabilities.js.map +1 -1
  15. package/dist/llm/http.js +19 -11
  16. package/dist/llm/http.js.map +1 -1
  17. package/dist/llm/openai.js +10 -1
  18. package/dist/llm/openai.js.map +1 -1
  19. package/dist/modes/agent.d.ts +4 -1
  20. package/dist/modes/agent.js.map +1 -1
  21. package/dist/repl.js +57 -15
  22. package/dist/repl.js.map +1 -1
  23. package/dist/tui/App.d.ts +8 -0
  24. package/dist/tui/App.js +273 -0
  25. package/dist/tui/App.js.map +1 -0
  26. package/dist/tui/can-use-tui.d.ts +20 -0
  27. package/dist/tui/can-use-tui.js +28 -0
  28. package/dist/tui/can-use-tui.js.map +1 -0
  29. package/dist/tui/components/Composer.d.ts +6 -0
  30. package/dist/tui/components/Composer.js +122 -0
  31. package/dist/tui/components/Composer.js.map +1 -0
  32. package/dist/tui/components/ConfirmModal.d.ts +6 -0
  33. package/dist/tui/components/ConfirmModal.js +16 -0
  34. package/dist/tui/components/ConfirmModal.js.map +1 -0
  35. package/dist/tui/components/Header.d.ts +7 -0
  36. package/dist/tui/components/Header.js +6 -0
  37. package/dist/tui/components/Header.js.map +1 -0
  38. package/dist/tui/components/JobsPanel.d.ts +11 -0
  39. package/dist/tui/components/JobsPanel.js +55 -0
  40. package/dist/tui/components/JobsPanel.js.map +1 -0
  41. package/dist/tui/components/Pager.d.ts +13 -0
  42. package/dist/tui/components/Pager.js +46 -0
  43. package/dist/tui/components/Pager.js.map +1 -0
  44. package/dist/tui/components/StatusLine.d.ts +7 -0
  45. package/dist/tui/components/StatusLine.js +25 -0
  46. package/dist/tui/components/StatusLine.js.map +1 -0
  47. package/dist/tui/components/items.d.ts +5 -0
  48. package/dist/tui/components/items.js +57 -0
  49. package/dist/tui/components/items.js.map +1 -0
  50. package/dist/tui/confirm.d.ts +16 -0
  51. package/dist/tui/confirm.js +41 -0
  52. package/dist/tui/confirm.js.map +1 -0
  53. package/dist/tui/hooks/useAgentRunner.d.ts +36 -0
  54. package/dist/tui/hooks/useAgentRunner.js +90 -0
  55. package/dist/tui/hooks/useAgentRunner.js.map +1 -0
  56. package/dist/tui/hooks/useJobs.d.ts +7 -0
  57. package/dist/tui/hooks/useJobs.js +39 -0
  58. package/dist/tui/hooks/useJobs.js.map +1 -0
  59. package/dist/tui/hooks/useSpinner.d.ts +5 -0
  60. package/dist/tui/hooks/useSpinner.js +19 -0
  61. package/dist/tui/hooks/useSpinner.js.map +1 -0
  62. package/dist/tui/index.d.ts +8 -0
  63. package/dist/tui/index.js +22 -0
  64. package/dist/tui/index.js.map +1 -0
  65. package/dist/tui/state.d.ts +101 -0
  66. package/dist/tui/state.js +323 -0
  67. package/dist/tui/state.js.map +1 -0
  68. package/dist/types.d.ts +1 -1
  69. package/package.json +5 -2
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useInput, useStdout } from "ink";
3
+ import { useState } from "react";
4
+ /**
5
+ * A full-height scrollable overlay for long content (full tool output, the
6
+ * plan document). Replaces the classic `openPager` — it can't run inside Ink
7
+ * because both own stdout/raw-mode. Arrow keys / PgUp-PgDn / g-G scroll;
8
+ * q or Esc closes.
9
+ */
10
+ export function Pager({ title, body, onClose }) {
11
+ const { stdout } = useStdout();
12
+ const rows = stdout?.rows ?? 24;
13
+ const cols = stdout?.columns ?? 80;
14
+ const viewport = Math.max(3, rows - 4);
15
+ const lines = body.replace(/\n+$/, "").split("\n");
16
+ const maxOffset = Math.max(0, lines.length - viewport);
17
+ const [offset, setOffset] = useState(0);
18
+ useInput((input, key) => {
19
+ if (input === "q" || key.escape) {
20
+ onClose();
21
+ return;
22
+ }
23
+ if (key.downArrow || input === "j") {
24
+ setOffset((o) => Math.min(maxOffset, o + 1));
25
+ }
26
+ else if (key.upArrow || input === "k") {
27
+ setOffset((o) => Math.max(0, o - 1));
28
+ }
29
+ else if (key.pageDown || input === " ") {
30
+ setOffset((o) => Math.min(maxOffset, o + viewport));
31
+ }
32
+ else if (key.pageUp) {
33
+ setOffset((o) => Math.max(0, o - viewport));
34
+ }
35
+ else if (input === "g") {
36
+ setOffset(0);
37
+ }
38
+ else if (input === "G") {
39
+ setOffset(maxOffset);
40
+ }
41
+ });
42
+ const visible = lines.slice(offset, offset + viewport);
43
+ const pct = maxOffset === 0 ? 100 : Math.round((offset / maxOffset) * 100);
44
+ return (_jsxs(Box, { flexDirection: "column", width: cols, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: title }), _jsx(Text, { dimColor: true, children: ` (${pct}% · ↑↓/PgUp/PgDn/g/G scroll · q to close)` })] }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: visible.map((line, i) => (_jsx(Text, { children: line }, offset + i))) })] }));
45
+ }
46
+ //# sourceMappingURL=Pager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Pager.js","sourceRoot":"","sources":["../../../src/tui/components/Pager.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { TurnStatus } from "../state.js";
2
+ export interface StatusLineProps {
3
+ status: TurnStatus;
4
+ thinkingPreview: string;
5
+ queued: number;
6
+ }
7
+ export declare function StatusLine({ status, thinkingPreview, queued }: StatusLineProps): import("react").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { useEffect, useState } from "react";
4
+ import { useSpinner } from "../hooks/useSpinner.js";
5
+ function useElapsed(startedAt) {
6
+ const [now, setNow] = useState(Date.now());
7
+ useEffect(() => {
8
+ if (startedAt === undefined)
9
+ return;
10
+ const timer = setInterval(() => setNow(Date.now()), 250);
11
+ return () => clearInterval(timer);
12
+ }, [startedAt]);
13
+ if (startedAt === undefined)
14
+ return 0;
15
+ return Math.max(0, Math.floor((now - startedAt) / 1000));
16
+ }
17
+ export function StatusLine({ status, thinkingPreview, queued }) {
18
+ const spinner = useSpinner(status.running);
19
+ const elapsed = useElapsed(status.running ? status.startedAt : undefined);
20
+ if (!status.running) {
21
+ return (_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [" ", "ready", queued > 0 ? ` · ${queued} queued` : ""] }) }));
22
+ }
23
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: "magenta", children: [" ", spinner, " "] }), _jsx(Text, { color: "yellow", children: status.activity || "working" }), status.step > 0 ? _jsx(Text, { dimColor: true, children: ` · step ${status.step}` }) : null, _jsx(Text, { dimColor: true, children: ` · ${elapsed}s` }), queued > 0 ? _jsx(Text, { dimColor: true, children: ` · ${queued} queued` }) : null, _jsx(Text, { dimColor: true, children: " · esc to cancel" })] }), thinkingPreview ? (_jsxs(Text, { dimColor: true, italic: true, children: [" ", thinkingPreview.slice(-120)] })) : null] }));
24
+ }
25
+ //# sourceMappingURL=StatusLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusLine.js","sourceRoot":"","sources":["../../../src/tui/components/StatusLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQpD,SAAS,UAAU,CAAC,SAA6B;IAC/C,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,KAAK,SAAS;YAAE,OAAO;QACpC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACzD,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAChB,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAmB;IAC7E,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CACL,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,QAAQ,mBACX,IAAI,WAAO,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,IAChD,GACH,CACP,CAAC;IACJ,CAAC;IACD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,aAClB,IAAI,EACJ,OAAO,EAAE,GAAG,IACR,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,YAAE,MAAM,CAAC,QAAQ,IAAI,SAAS,GAAQ,EACzD,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,QAAQ,kBAAE,aAAa,MAAM,CAAC,IAAI,EAAE,GAAQ,CAAC,CAAC,CAAC,IAAI,EAC5E,KAAC,IAAI,IAAC,QAAQ,kBAAE,QAAQ,OAAO,GAAG,GAAQ,EACzC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,QAAQ,kBAAE,QAAQ,MAAM,SAAS,GAAQ,CAAC,CAAC,CAAC,IAAI,EACpE,KAAC,IAAI,IAAC,QAAQ,kBAAE,oBAAoB,GAAQ,IACxC,EACL,eAAe,CAAC,CAAC,CAAC,CACjB,MAAC,IAAI,IAAC,QAAQ,QAAC,MAAM,mBAClB,MAAM,EACN,eAAe,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IACvB,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { TranscriptItem } from "../state.js";
2
+ export declare function ItemView({ item, thinkingExpanded, }: {
3
+ item: TranscriptItem;
4
+ thinkingExpanded: boolean;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { renderMarkdown } from "../../ui/markdown.js";
4
+ import { renderPlanChecklist } from "../../ui/plan-pane.js";
5
+ const TOOL_PREVIEW_LINES = 12;
6
+ function UserMessage({ item }) {
7
+ return (_jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "magenta", children: "❯ " }), _jsx(Text, { children: item.text })] }));
8
+ }
9
+ function AssistantMessage({ item }) {
10
+ const rendered = renderMarkdown(item.text).replace(/\n+$/, "");
11
+ return (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: rendered }), item.streaming ? _jsx(Text, { color: "magenta", children: "\u258C" }) : null] }));
12
+ }
13
+ function ThinkingBlock({ item, expanded, }) {
14
+ const lines = item.content.trim().split(/\r?\n/);
15
+ const preview = expanded ? lines : lines.slice(0, 1);
16
+ return (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, italic: true, children: [" ✦ thinking", expanded ? "" : lines.length > 1 ? ` (${lines.length} lines · Ctrl+T)` : ""] }), preview.map((line, i) => (_jsxs(Text, { dimColor: true, children: [" ", line] }, i)))] }));
17
+ }
18
+ const STATUS_GLYPH = {
19
+ running: { glyph: "●", color: "yellow" },
20
+ ok: { glyph: "✓", color: "green" },
21
+ fail: { glyph: "✗", color: "red" },
22
+ blocked: { glyph: "⊘", color: "red" },
23
+ };
24
+ function ToolCard({ item }) {
25
+ const status = STATUS_GLYPH[item.status];
26
+ const outputLines = item.output ? item.output.replace(/\n+$/, "").split("\n") : [];
27
+ const showLines = item.status === "running"
28
+ ? outputLines.slice(-TOOL_PREVIEW_LINES)
29
+ : outputLines.slice(0, TOOL_PREVIEW_LINES);
30
+ const hidden = outputLines.length - showLines.length;
31
+ return (_jsxs(Box, { marginTop: 1, flexDirection: "column", borderStyle: "round", borderColor: status.color, paddingX: 1, children: [_jsxs(Text, { children: [_jsxs(Text, { color: status.color, children: [status.glyph, " "] }), _jsx(Text, { bold: true, color: "cyan", children: item.name }), item.argsDisplay ? _jsxs(Text, { dimColor: true, children: [" ", item.argsDisplay] }) : null, typeof item.exitCode === "number" && item.exitCode !== 0 ? (_jsxs(Text, { color: "red", children: [" (exit ", item.exitCode, ")"] })) : null] }), item.status === "blocked" && item.summary ? (_jsxs(Text, { color: "red", children: [" blocked: ", item.summary] })) : null, showLines.length > 0 ? (_jsxs(Box, { flexDirection: "column", marginTop: hidden > 0 ? 0 : 0, children: [hidden > 0 && item.status !== "running" ? (_jsx(Text, { dimColor: true, children: ` … ${hidden} more line(s)` })) : null, showLines.map((line, i) => (_jsxs(Text, { dimColor: true, children: [" ", line] }, i)))] })) : null] }));
32
+ }
33
+ function Notice({ item }) {
34
+ const color = item.level === "warn" ? "yellow" : "gray";
35
+ const glyph = item.level === "warn" ? "⚠" : "ℹ";
36
+ return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: color, dimColor: item.level === "info", children: [" ", glyph, " ", item.text] }) }));
37
+ }
38
+ function PlanCard({ item }) {
39
+ return (_jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Text, { children: renderPlanChecklist(item.plan) }) }));
40
+ }
41
+ export function ItemView({ item, thinkingExpanded, }) {
42
+ switch (item.kind) {
43
+ case "user":
44
+ return _jsx(UserMessage, { item: item });
45
+ case "assistant":
46
+ return _jsx(AssistantMessage, { item: item });
47
+ case "thinking":
48
+ return _jsx(ThinkingBlock, { item: item, expanded: thinkingExpanded });
49
+ case "tool":
50
+ return _jsx(ToolCard, { item: item });
51
+ case "notice":
52
+ return _jsx(Notice, { item: item });
53
+ case "plan":
54
+ return _jsx(PlanCard, { item: item });
55
+ }
56
+ }
57
+ //# sourceMappingURL=items.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"items.js","sourceRoot":"","sources":["../../../src/tui/components/items.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ConfirmPort } from "../agent/runner.js";
2
+ /**
3
+ * A confirm provider for the TUI. Inquirer can't run inside Ink (both fight
4
+ * for stdin), so instead of prompting directly we hand the request to the
5
+ * React layer via `request()`, which renders an in-app modal and resolves the
6
+ * returned promise when the user answers.
7
+ */
8
+ export interface TuiConfirmController {
9
+ port: ConfirmPort;
10
+ /** Called by the App to register how confirm requests reach the UI. */
11
+ setHandler: (handler: (req: {
12
+ kind: "tool" | "pentest";
13
+ prompt: string;
14
+ }) => Promise<boolean>) => void;
15
+ }
16
+ export declare function createTuiConfirmPort(): TuiConfirmController;
@@ -0,0 +1,41 @@
1
+ function describeCall(call) {
2
+ if (call.name === "shell.exec")
3
+ return String(call.args.command ?? "");
4
+ try {
5
+ const json = JSON.stringify(call.args);
6
+ return json.length > 120 ? `${json.slice(0, 117)}…` : json;
7
+ }
8
+ catch {
9
+ return "";
10
+ }
11
+ }
12
+ export function createTuiConfirmPort() {
13
+ let handler;
14
+ const ask = async (req) => {
15
+ if (!handler)
16
+ return false;
17
+ return handler(req);
18
+ };
19
+ const port = {
20
+ async confirmTool(call) {
21
+ const args = describeCall(call);
22
+ return ask({
23
+ kind: "tool",
24
+ prompt: `Run ${call.name}${args ? ` ${args}` : ""}?`,
25
+ });
26
+ },
27
+ async confirmPentest() {
28
+ return ask({
29
+ kind: "pentest",
30
+ prompt: "This is a security/pentest action. Confirm you are authorized to run it against this target.",
31
+ });
32
+ },
33
+ };
34
+ return {
35
+ port,
36
+ setHandler(h) {
37
+ handler = h;
38
+ },
39
+ };
40
+ }
41
+ //# sourceMappingURL=confirm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/tui/confirm.ts"],"names":[],"mappings":"AAGA,SAAS,YAAY,CAAC,IAAc;IAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAgBD,MAAM,UAAU,oBAAoB;IAClC,IAAI,OAES,CAAC;IAEd,MAAM,GAAG,GAAG,KAAK,EAAE,GAGlB,EAAoB,EAAE;QACrB,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAgB;QACxB,KAAK,CAAC,WAAW,CAAC,IAAc;YAC9B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,OAAO,GAAG,CAAC;gBACT,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,OAAO,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;aACrD,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,cAAc;YAClB,OAAO,GAAG,CAAC;gBACT,IAAI,EAAE,SAAS;gBACf,MAAM,EACJ,8FAA8F;aACjG,CAAC,CAAC;QACL,CAAC;KACF,CAAC;IAEF,OAAO;QACL,IAAI;QACJ,UAAU,CAAC,CAAC;YACV,OAAO,GAAG,CAAC,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { ChatImage, ProviderId } from "../../types.js";
2
+ import type { AgentEvent } from "../../agent/events.js";
3
+ import { type SessionPolicy } from "../../agent/runner.js";
4
+ import type { ConfirmPort } from "../../agent/runner.js";
5
+ export interface RunnerContext {
6
+ mode: "ask" | "agent";
7
+ provider?: ProviderId | undefined;
8
+ model?: string | undefined;
9
+ }
10
+ export interface RunOptions {
11
+ images?: ChatImage[] | undefined;
12
+ }
13
+ export interface UseAgentRunnerArgs {
14
+ dispatchEvent: (event: AgentEvent) => void;
15
+ confirm: ConfirmPort;
16
+ getContext: () => RunnerContext;
17
+ }
18
+ export interface AgentRunner {
19
+ /** True while a turn is in flight. */
20
+ isRunning: () => boolean;
21
+ /** Start a turn for `input`. Resolves when the turn finishes. */
22
+ run: (input: string, opts?: RunOptions) => Promise<void>;
23
+ /** Abort the current turn (model stream + foreground tool). */
24
+ abort: () => void;
25
+ /** Clear conversation history and session policy (for /clear, /new). */
26
+ reset: () => void;
27
+ /** The live session policy (sessionId, planApproved, allow set). */
28
+ getSession: () => SessionPolicy;
29
+ }
30
+ /**
31
+ * Bridges the React UI to the single agent implementation. On submit it
32
+ * creates an AbortController, calls `runAgent`/`runAskStream` with
33
+ * `onEvent: dispatchEvent`, and keeps conversation history so follow-ups
34
+ * have context — mirroring the classic REPL's session handling.
35
+ */
36
+ export declare function useAgentRunner({ dispatchEvent, confirm, getContext, }: UseAgentRunnerArgs): AgentRunner;
@@ -0,0 +1,90 @@
1
+ import { useCallback, useMemo, useRef } from "react";
2
+ import { runAgent } from "../../modes/agent.js";
3
+ import { runAskStream } from "../../modes/ask.js";
4
+ import { createSessionPolicy, } from "../../agent/runner.js";
5
+ import { createThinkingStreamParser, rememberThinkingFromText, } from "../../ui/thinking.js";
6
+ /**
7
+ * Bridges the React UI to the single agent implementation. On submit it
8
+ * creates an AbortController, calls `runAgent`/`runAskStream` with
9
+ * `onEvent: dispatchEvent`, and keeps conversation history so follow-ups
10
+ * have context — mirroring the classic REPL's session handling.
11
+ */
12
+ export function useAgentRunner({ dispatchEvent, confirm, getContext, }) {
13
+ const messagesRef = useRef([]);
14
+ const sessionRef = useRef(createSessionPolicy());
15
+ const abortRef = useRef(undefined);
16
+ const runningRef = useRef(false);
17
+ const isRunning = useCallback(() => runningRef.current, []);
18
+ const abort = useCallback(() => {
19
+ abortRef.current?.abort();
20
+ }, []);
21
+ const reset = useCallback(() => {
22
+ messagesRef.current = [];
23
+ sessionRef.current = createSessionPolicy();
24
+ }, []);
25
+ const getSession = useCallback(() => sessionRef.current, []);
26
+ const run = useCallback(async (input, opts) => {
27
+ if (runningRef.current)
28
+ return;
29
+ runningRef.current = true;
30
+ const ctx = getContext();
31
+ const ac = new AbortController();
32
+ abortRef.current = ac;
33
+ messagesRef.current.push({ role: "user", content: input });
34
+ try {
35
+ let answer = "";
36
+ if (ctx.mode === "ask") {
37
+ dispatchEvent({ type: "turn-start", prompt: input });
38
+ dispatchEvent({ type: "status", text: "thinking" });
39
+ const parser = createThinkingStreamParser((visible) => dispatchEvent({ type: "assistant-delta", text: visible }), (think) => dispatchEvent({ type: "thinking-delta", text: think }));
40
+ let sawToken = false;
41
+ const raw = await runAskStream(input, (token) => {
42
+ sawToken = true;
43
+ parser.push(token);
44
+ }, {
45
+ provider: ctx.provider,
46
+ model: ctx.model,
47
+ history: messagesRef.current.slice(0, -1),
48
+ signal: ac.signal,
49
+ });
50
+ const result = sawToken ? parser.finish() : rememberThinkingFromText(raw);
51
+ if (result.hasThinking && result.thinkContent) {
52
+ dispatchEvent({ type: "thinking-block", content: result.thinkContent });
53
+ }
54
+ answer = result.visible;
55
+ dispatchEvent({ type: "assistant-message", text: answer });
56
+ dispatchEvent({ type: "turn-end", finalAnswer: answer, steps: 1 });
57
+ }
58
+ else {
59
+ answer = await runAgent(input, {
60
+ provider: ctx.provider,
61
+ model: ctx.model,
62
+ history: messagesRef.current.slice(0, -1),
63
+ signal: ac.signal,
64
+ session: sessionRef.current,
65
+ images: opts?.images,
66
+ onEvent: dispatchEvent,
67
+ confirm,
68
+ });
69
+ }
70
+ messagesRef.current.push({ role: "assistant", content: answer });
71
+ }
72
+ catch (err) {
73
+ if (ac.signal.aborted) {
74
+ dispatchEvent({ type: "turn-aborted" });
75
+ }
76
+ else {
77
+ dispatchEvent({
78
+ type: "turn-error",
79
+ message: err instanceof Error ? err.message : String(err),
80
+ });
81
+ }
82
+ }
83
+ finally {
84
+ runningRef.current = false;
85
+ abortRef.current = undefined;
86
+ }
87
+ }, [dispatchEvent, confirm, getContext]);
88
+ return useMemo(() => ({ isRunning, run, abort, reset, getSession }), [isRunning, run, abort, reset, getSession]);
89
+ }
90
+ //# sourceMappingURL=useAgentRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAgentRunner.js","sourceRoot":"","sources":["../../../src/tui/hooks/useAgentRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAGrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EACL,mBAAmB,GAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAgC9B;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,aAAa,EACb,OAAO,EACP,UAAU,GACS;IACnB,MAAM,WAAW,GAAG,MAAM,CAAgB,EAAE,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAgB,mBAAmB,EAAE,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,CAA8B,SAAS,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEjC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAE5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,WAAW,CAAC,OAAO,GAAG,EAAE,CAAC;QACzB,UAAU,CAAC,OAAO,GAAG,mBAAmB,EAAE,CAAC;IAC7C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAE7D,MAAM,GAAG,GAAG,WAAW,CACrB,KAAK,EAAE,KAAa,EAAE,IAAiB,EAAiB,EAAE;QACxD,IAAI,UAAU,CAAC,OAAO;YAAE,OAAO;QAC/B,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACjC,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAC;QACtB,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAE3D,IAAI,CAAC;YACH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACvB,aAAa,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBACrD,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;gBACpD,MAAM,MAAM,GAAG,0BAA0B,CACvC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EACtE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAClE,CAAC;gBACF,IAAI,QAAQ,GAAG,KAAK,CAAC;gBACrB,MAAM,GAAG,GAAG,MAAM,YAAY,CAC5B,KAAK,EACL,CAAC,KAAK,EAAE,EAAE;oBACR,QAAQ,GAAG,IAAI,CAAC;oBAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC,EACD;oBACE,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,MAAM,EAAE,EAAE,CAAC,MAAM;iBAClB,CACF,CAAC;gBACF,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;gBAC1E,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;oBAC9C,aAAa,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;gBAC1E,CAAC;gBACD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;gBACxB,aAAa,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC3D,aAAa,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACrE,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE;oBAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzC,MAAM,EAAE,EAAE,CAAC,MAAM;oBACjB,OAAO,EAAE,UAAU,CAAC,OAAO;oBAC3B,MAAM,EAAE,IAAI,EAAE,MAAM;oBACpB,OAAO,EAAE,aAAa;oBACtB,OAAO;iBACR,CAAC,CAAC;YACL,CAAC;YACD,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACtB,aAAa,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC;oBACZ,IAAI,EAAE,YAAY;oBAClB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;iBAC1D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC;QAC/B,CAAC;IACH,CAAC,EACD,CAAC,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC,CACrC,CAAC;IAEF,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EACpD,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type BackgroundJob } from "../../tools/jobs.js";
2
+ /**
3
+ * Polls the shared `jobManager` so the UI can surface background jobs
4
+ * (long-running shell commands the agent detached). Polling — rather than
5
+ * events — keeps `jobs.ts` decoupled from the frontend.
6
+ */
7
+ export declare function useJobs(active: boolean, intervalMs?: number): BackgroundJob[];
@@ -0,0 +1,39 @@
1
+ import { useEffect, useState } from "react";
2
+ import { jobManager } from "../../tools/jobs.js";
3
+ /**
4
+ * Polls the shared `jobManager` so the UI can surface background jobs
5
+ * (long-running shell commands the agent detached). Polling — rather than
6
+ * events — keeps `jobs.ts` decoupled from the frontend.
7
+ */
8
+ export function useJobs(active, intervalMs = 1500) {
9
+ const [jobs, setJobs] = useState([]);
10
+ useEffect(() => {
11
+ if (!active)
12
+ return;
13
+ const tick = () => {
14
+ // jobManager exposes running jobs directly; for the full list we read
15
+ // the private map via listJobs parsing-free by snapshotting running +
16
+ // recently-finished through getRunningJobs plus a best-effort scan.
17
+ setJobs(snapshotJobs());
18
+ };
19
+ tick();
20
+ const timer = setInterval(tick, intervalMs);
21
+ return () => clearInterval(timer);
22
+ }, [active, intervalMs]);
23
+ return jobs;
24
+ }
25
+ /**
26
+ * Build a stable snapshot of all known jobs. `JobManager` only exposes
27
+ * `getRunningJobs()` publicly; finished jobs still matter for the panel, so
28
+ * we read the internal registry defensively (it's the same in-process
29
+ * singleton) and fall back to running-only if the shape ever changes.
30
+ */
31
+ function snapshotJobs() {
32
+ const internal = jobManager
33
+ .jobs;
34
+ if (internal instanceof Map) {
35
+ return [...internal.values()];
36
+ }
37
+ return jobManager.getRunningJobs();
38
+ }
39
+ //# sourceMappingURL=useJobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useJobs.js","sourceRoot":"","sources":["../../../src/tui/hooks/useJobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAsB,MAAM,qBAAqB,CAAC;AAErE;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,MAAe,EAAE,UAAU,GAAG,IAAI;IACxD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAkB,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,IAAI,GAAG,GAAS,EAAE;YACtB,sEAAsE;YACtE,sEAAsE;YACtE,oEAAoE;YACpE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC;QACF,IAAI,EAAE,CAAC;QACP,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC5C,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACzB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY;IACnB,MAAM,QAAQ,GAAI,UAA+D;SAC9E,IAAI,CAAC;IACR,IAAI,QAAQ,YAAY,GAAG,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,UAAU,CAAC,cAAc,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Returns the current spinner glyph, advancing on a timer while `active`.
3
+ * No-op (and steady frame) when inactive so idle renders stay still.
4
+ */
5
+ export declare function useSpinner(active: boolean, intervalMs?: number): string;
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from "react";
2
+ const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
3
+ /**
4
+ * Returns the current spinner glyph, advancing on a timer while `active`.
5
+ * No-op (and steady frame) when inactive so idle renders stay still.
6
+ */
7
+ export function useSpinner(active, intervalMs = 80) {
8
+ const [frame, setFrame] = useState(0);
9
+ useEffect(() => {
10
+ if (!active)
11
+ return;
12
+ const timer = setInterval(() => {
13
+ setFrame((f) => (f + 1) % FRAMES.length);
14
+ }, intervalMs);
15
+ return () => clearInterval(timer);
16
+ }, [active, intervalMs]);
17
+ return FRAMES[active ? frame : 0];
18
+ }
19
+ //# sourceMappingURL=useSpinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpinner.js","sourceRoot":"","sources":["../../../src/tui/hooks/useSpinner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAElE;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAe,EAAE,UAAU,GAAG,EAAE;IACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACzB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Mode, ProviderId } from "../types.js";
2
+ export interface StartTuiOptions {
3
+ mode?: Mode | undefined;
4
+ provider?: ProviderId | undefined;
5
+ model?: string | undefined;
6
+ noHistory?: boolean | undefined;
7
+ }
8
+ export declare function startTui(opts?: StartTuiOptions): Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { render } from "ink";
2
+ import { createElement } from "react";
3
+ import { getConfig, getProviderModel } from "../store/config.js";
4
+ import { getCurrentVersion } from "../commands/update.js";
5
+ import { App } from "./App.js";
6
+ export async function startTui(opts = {}) {
7
+ const config = getConfig();
8
+ const provider = opts.provider ?? config.defaultProvider;
9
+ const model = opts.model ?? getProviderModel(provider);
10
+ const mode = opts.mode ?? config.defaultMode;
11
+ const app = render(createElement(App, {
12
+ version: getCurrentVersion(),
13
+ initialMode: mode,
14
+ provider,
15
+ initialModel: model,
16
+ }), {
17
+ // We own Ctrl+C handling (abort vs. exit), so Ink must not exit on it.
18
+ exitOnCtrlC: false,
19
+ });
20
+ await app.waitUntilExit();
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tui/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAS/B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB,EAAE;IACvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,WAAW,CAAC;IAE7C,MAAM,GAAG,GAAG,MAAM,CAChB,aAAa,CAAC,GAAG,EAAE;QACjB,OAAO,EAAE,iBAAiB,EAAE;QAC5B,WAAW,EAAE,IAAI;QACjB,QAAQ;QACR,YAAY,EAAE,KAAK;KACpB,CAAC,EACF;QACE,uEAAuE;QACvE,WAAW,EAAE,KAAK;KACnB,CACF,CAAC;IAEF,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,101 @@
1
+ import type { AgentEvent } from "../agent/events.js";
2
+ import type { SessionPlan } from "../store/plan.js";
3
+ export type ToolStatus = "running" | "ok" | "fail" | "blocked";
4
+ export interface UserItem {
5
+ kind: "user";
6
+ id: string;
7
+ text: string;
8
+ done: boolean;
9
+ }
10
+ export interface AssistantItem {
11
+ kind: "assistant";
12
+ id: string;
13
+ text: string;
14
+ streaming: boolean;
15
+ done: boolean;
16
+ }
17
+ export interface ThinkingItem {
18
+ kind: "thinking";
19
+ id: string;
20
+ content: string;
21
+ done: boolean;
22
+ }
23
+ export interface ToolItem {
24
+ kind: "tool";
25
+ id: string;
26
+ name: string;
27
+ argsDisplay: string;
28
+ output: string;
29
+ status: ToolStatus;
30
+ exitCode?: number | undefined;
31
+ summary?: string | undefined;
32
+ artifactPath?: string | undefined;
33
+ done: boolean;
34
+ }
35
+ export interface NoticeItem {
36
+ kind: "notice";
37
+ id: string;
38
+ level: "info" | "warn";
39
+ text: string;
40
+ done: boolean;
41
+ }
42
+ export interface PlanItem {
43
+ kind: "plan";
44
+ id: string;
45
+ plan: SessionPlan;
46
+ done: boolean;
47
+ }
48
+ export type TranscriptItem = UserItem | AssistantItem | ThinkingItem | ToolItem | NoticeItem | PlanItem;
49
+ export interface PendingConfirm {
50
+ id: string;
51
+ kind: "tool" | "pentest";
52
+ prompt: string;
53
+ }
54
+ export interface TurnStatus {
55
+ running: boolean;
56
+ activity: string;
57
+ step: number;
58
+ startedAt: number | undefined;
59
+ }
60
+ export interface TuiState {
61
+ items: TranscriptItem[];
62
+ status: TurnStatus;
63
+ thinkingPreview: string;
64
+ thinkingExpanded: boolean;
65
+ pendingConfirm: PendingConfirm | undefined;
66
+ queued: string[];
67
+ }
68
+ export declare function initialState(): TuiState;
69
+ export type TuiAction = {
70
+ type: "event";
71
+ event: AgentEvent;
72
+ } | {
73
+ type: "submit";
74
+ text: string;
75
+ } | {
76
+ type: "queue";
77
+ text: string;
78
+ } | {
79
+ type: "dequeue";
80
+ } | {
81
+ type: "notice";
82
+ level: "info" | "warn";
83
+ text: string;
84
+ } | {
85
+ type: "toggle-thinking";
86
+ } | {
87
+ type: "confirm-resolved";
88
+ } | {
89
+ type: "reset";
90
+ };
91
+ export declare function reducer(state: TuiState, action: TuiAction): TuiState;
92
+ /**
93
+ * Split the transcript into a finalized prefix (safe to render once in
94
+ * Ink's <Static>) and a live suffix that may still mutate this turn.
95
+ * The boundary is the first not-yet-done item, which keeps chronological
96
+ * order intact even when later items finalize before earlier ones.
97
+ */
98
+ export declare function splitItems(items: TranscriptItem[]): {
99
+ committed: TranscriptItem[];
100
+ live: TranscriptItem[];
101
+ };