swarmlancer-cli 0.2.0

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 (48) hide show
  1. package/README.md +15 -0
  2. package/dist/agent.d.ts +13 -0
  3. package/dist/agent.js +202 -0
  4. package/dist/app.d.ts +4 -0
  5. package/dist/app.js +496 -0
  6. package/dist/config.d.ts +49 -0
  7. package/dist/config.js +175 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +129 -0
  10. package/dist/inference.d.ts +13 -0
  11. package/dist/inference.js +105 -0
  12. package/dist/login.d.ts +1 -0
  13. package/dist/login.js +57 -0
  14. package/dist/screening.d.ts +22 -0
  15. package/dist/screening.js +101 -0
  16. package/dist/screens/agent-config.d.ts +14 -0
  17. package/dist/screens/agent-config.js +64 -0
  18. package/dist/screens/agent-editor.d.ts +13 -0
  19. package/dist/screens/agent-editor.js +64 -0
  20. package/dist/screens/agent-list.d.ts +22 -0
  21. package/dist/screens/agent-list.js +73 -0
  22. package/dist/screens/agent-picker.d.ts +15 -0
  23. package/dist/screens/agent-picker.js +51 -0
  24. package/dist/screens/agent-running.d.ts +20 -0
  25. package/dist/screens/agent-running.js +68 -0
  26. package/dist/screens/banner.d.ts +6 -0
  27. package/dist/screens/banner.js +27 -0
  28. package/dist/screens/dashboard.d.ts +16 -0
  29. package/dist/screens/dashboard.js +59 -0
  30. package/dist/screens/discovery-settings.d.ts +17 -0
  31. package/dist/screens/discovery-settings.js +189 -0
  32. package/dist/screens/message.d.ts +15 -0
  33. package/dist/screens/message.js +39 -0
  34. package/dist/screens/model-picker.d.ts +14 -0
  35. package/dist/screens/model-picker.js +49 -0
  36. package/dist/screens/name-editor.d.ts +15 -0
  37. package/dist/screens/name-editor.js +67 -0
  38. package/dist/screens/session-goal.d.ts +13 -0
  39. package/dist/screens/session-goal.js +61 -0
  40. package/dist/screens/settings.d.ts +15 -0
  41. package/dist/screens/settings.js +126 -0
  42. package/dist/screens/setup-wizard.d.ts +20 -0
  43. package/dist/screens/setup-wizard.js +120 -0
  44. package/dist/screens/status-panel.d.ts +15 -0
  45. package/dist/screens/status-panel.js +37 -0
  46. package/dist/theme.d.ts +42 -0
  47. package/dist/theme.js +56 -0
  48. package/package.json +49 -0
@@ -0,0 +1,64 @@
1
+ import { Container, Text, Spacer, SelectList, truncateToWidth, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ export class AgentConfigScreen {
4
+ container;
5
+ selectList;
6
+ tui;
7
+ onAction;
8
+ constructor(tui, agent) {
9
+ this.tui = tui;
10
+ this.container = new Container();
11
+ this.container.addChild(new Spacer(1));
12
+ this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
13
+ this.container.addChild(new Text(theme.title(` Agent: ${agent.name}`), 1, 0));
14
+ this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
15
+ this.container.addChild(new Spacer(1));
16
+ // Status summary
17
+ const modelStr = agent.modelPattern || "(auto — cheapest)";
18
+ const instrStr = agent.instructions.length > 0
19
+ ? `${agent.instructions.split("\n").length} lines`
20
+ : "empty";
21
+ const discoveryStr = `threshold ${agent.discovery.matchThreshold}/10, ${agent.discovery.maxScreenPerSession} max`;
22
+ const limitsStr = `${agent.limits.maxConcurrentConversations} concurrent, ${agent.limits.maxMessagesPerConversation} msgs`;
23
+ this.container.addChild(new Text(` ${colors.gray("Model:")} ${modelStr}`, 0, 0));
24
+ this.container.addChild(new Text(` ${colors.gray("Instructions:")} ${instrStr}`, 0, 0));
25
+ this.container.addChild(new Text(` ${colors.gray("Discovery:")} ${discoveryStr}`, 0, 0));
26
+ this.container.addChild(new Text(` ${colors.gray("Limits:")} ${limitsStr}`, 0, 0));
27
+ this.container.addChild(new Spacer(1));
28
+ this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
29
+ this.container.addChild(new Spacer(1));
30
+ const items = [
31
+ { value: "edit-name", label: "Rename agent", description: `Currently: ${agent.name}` },
32
+ { value: "edit-instructions", label: "Edit instructions", description: "How your agent behaves" },
33
+ { value: "edit-discovery", label: "Discovery settings", description: "Keywords, match threshold, filters" },
34
+ { value: "edit-limits", label: "Agent limits", description: "Max conversations, cooldown, auto-stop" },
35
+ { value: "edit-model", label: "Change model", description: `Currently: ${modelStr}` },
36
+ { value: "delete", label: "Delete agent", description: "Remove this agent permanently" },
37
+ { value: "back", label: "← Back", description: "" },
38
+ ];
39
+ this.selectList = new SelectList(items, items.length, {
40
+ selectedPrefix: (t) => theme.accent(t),
41
+ selectedText: (t) => theme.accent(t),
42
+ description: (t) => colors.gray(t),
43
+ scrollInfo: (t) => colors.gray(t),
44
+ noMatch: (t) => colors.yellow(t),
45
+ });
46
+ this.selectList.onSelect = (item) => {
47
+ this.onAction?.(item.value);
48
+ };
49
+ this.selectList.onCancel = () => this.onAction?.("back");
50
+ this.container.addChild(this.selectList);
51
+ this.container.addChild(new Spacer(1));
52
+ this.container.addChild(new Text(colors.gray(" ↑↓ navigate • enter select • esc back"), 1, 0));
53
+ }
54
+ handleInput(data) {
55
+ this.selectList.handleInput(data);
56
+ this.tui.requestRender();
57
+ }
58
+ render(width) {
59
+ return this.container.render(width);
60
+ }
61
+ invalidate() {
62
+ this.container.invalidate();
63
+ }
64
+ }
@@ -0,0 +1,13 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ export declare class AgentEditorScreen implements Component {
4
+ private tui;
5
+ private editor;
6
+ private cachedLines?;
7
+ onSave?: (content: string) => void;
8
+ onCancel?: () => void;
9
+ constructor(tui: TUI, content: string);
10
+ handleInput(data: string): void;
11
+ render(width: number): string[];
12
+ invalidate(): void;
13
+ }
@@ -0,0 +1,64 @@
1
+ import { Editor, matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ const EDITOR_THEME = {
4
+ borderColor: (s) => colors.cyan(s),
5
+ selectList: {
6
+ selectedPrefix: (t) => colors.cyan(t),
7
+ selectedText: (t) => colors.cyan(t),
8
+ description: (t) => colors.gray(t),
9
+ scrollInfo: (t) => colors.gray(t),
10
+ noMatch: (t) => colors.yellow(t),
11
+ },
12
+ };
13
+ export class AgentEditorScreen {
14
+ tui;
15
+ editor;
16
+ cachedLines;
17
+ onSave;
18
+ onCancel;
19
+ constructor(tui, content) {
20
+ this.tui = tui;
21
+ this.editor = new Editor(tui, EDITOR_THEME, { paddingX: 1 });
22
+ this.editor.setText(content);
23
+ this.editor.disableSubmit = true; // Enter = new line, not submit
24
+ }
25
+ handleInput(data) {
26
+ // Ctrl+S to save
27
+ if (matchesKey(data, Key.ctrl("s"))) {
28
+ this.onSave?.(this.editor.getText());
29
+ return;
30
+ }
31
+ // Escape to cancel
32
+ if (matchesKey(data, Key.escape)) {
33
+ this.onCancel?.();
34
+ return;
35
+ }
36
+ // Everything else goes to the editor
37
+ this.editor.handleInput(data);
38
+ this.cachedLines = undefined;
39
+ this.tui.requestRender();
40
+ }
41
+ render(width) {
42
+ if (this.cachedLines)
43
+ return this.cachedLines;
44
+ const lines = [];
45
+ lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
46
+ lines.push(truncateToWidth(` ${theme.title("Edit Agent Instructions")} ${colors.gray("~/.swarmlancer/agent.md")}`, width));
47
+ lines.push(truncateToWidth(colors.gray(" This controls how your agent behaves in conversations."), width));
48
+ lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
49
+ lines.push("");
50
+ // Editor takes most of the space
51
+ for (const line of this.editor.render(width)) {
52
+ lines.push(line);
53
+ }
54
+ lines.push("");
55
+ lines.push(truncateToWidth(theme.border("─".repeat(width)), width));
56
+ lines.push(truncateToWidth(colors.gray(" shift+enter new line • ctrl+s save • esc cancel"), width));
57
+ this.cachedLines = lines;
58
+ return lines;
59
+ }
60
+ invalidate() {
61
+ this.cachedLines = undefined;
62
+ this.editor.invalidate();
63
+ }
64
+ }
@@ -0,0 +1,22 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ import type { AgentProfile } from "../config.js";
4
+ export type AgentListAction = {
5
+ type: "select";
6
+ agent: AgentProfile;
7
+ } | {
8
+ type: "create";
9
+ } | {
10
+ type: "back";
11
+ };
12
+ export declare class AgentListScreen implements Component {
13
+ private container;
14
+ private selectList;
15
+ private tui;
16
+ private agents;
17
+ onAction?: (action: AgentListAction) => void;
18
+ constructor(tui: TUI, agents: AgentProfile[]);
19
+ handleInput(data: string): void;
20
+ render(width: number): string[];
21
+ invalidate(): void;
22
+ }
@@ -0,0 +1,73 @@
1
+ import { Container, Text, Spacer, SelectList, truncateToWidth, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ export class AgentListScreen {
4
+ container;
5
+ selectList;
6
+ tui;
7
+ agents;
8
+ onAction;
9
+ constructor(tui, agents) {
10
+ this.tui = tui;
11
+ this.agents = agents;
12
+ this.container = new Container();
13
+ this.container.addChild(new Spacer(1));
14
+ this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
15
+ this.container.addChild(new Text(theme.title(" Manage Agents"), 1, 0));
16
+ this.container.addChild(new Text(colors.gray(" Each agent has its own instructions, model, discovery & limits."), 1, 0));
17
+ this.container.addChild(new Text(truncateToWidth(theme.border("─".repeat(60)), 60), 0, 0));
18
+ this.container.addChild(new Spacer(1));
19
+ const items = [];
20
+ // Create new agent always at top
21
+ items.push({
22
+ value: "__create__",
23
+ label: "+ Create new agent",
24
+ description: "",
25
+ });
26
+ // Existing agents
27
+ for (const agent of agents) {
28
+ const modelStr = agent.modelPattern
29
+ ? colors.gray(` (${agent.modelPattern})`)
30
+ : "";
31
+ const instrPreview = agent.instructions.length > 0
32
+ ? `${agent.instructions.slice(0, 50).replace(/\n/g, " ").trim()}…`
33
+ : "(no instructions)";
34
+ items.push({
35
+ value: agent.id,
36
+ label: agent.name,
37
+ description: instrPreview,
38
+ });
39
+ }
40
+ const maxVisible = Math.min(items.length, 15);
41
+ this.selectList = new SelectList(items, maxVisible, {
42
+ selectedPrefix: (t) => theme.accent(t),
43
+ selectedText: (t) => theme.accent(t),
44
+ description: (t) => colors.gray(t),
45
+ scrollInfo: (t) => colors.gray(t),
46
+ noMatch: (t) => colors.yellow(t),
47
+ });
48
+ this.selectList.onSelect = (item) => {
49
+ if (item.value === "__create__") {
50
+ this.onAction?.({ type: "create" });
51
+ }
52
+ else {
53
+ const agent = agents.find((a) => a.id === item.value);
54
+ if (agent)
55
+ this.onAction?.({ type: "select", agent });
56
+ }
57
+ };
58
+ this.selectList.onCancel = () => this.onAction?.({ type: "back" });
59
+ this.container.addChild(this.selectList);
60
+ this.container.addChild(new Spacer(1));
61
+ this.container.addChild(new Text(colors.gray(" ↑↓ navigate • enter select • esc back"), 1, 0));
62
+ }
63
+ handleInput(data) {
64
+ this.selectList.handleInput(data);
65
+ this.tui.requestRender();
66
+ }
67
+ render(width) {
68
+ return this.container.render(width);
69
+ }
70
+ invalidate() {
71
+ this.container.invalidate();
72
+ }
73
+ }
@@ -0,0 +1,15 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ import type { AgentProfile } from "../config.js";
4
+ export declare class AgentPickerScreen implements Component {
5
+ private container;
6
+ private selectList;
7
+ private tui;
8
+ private agents;
9
+ onSelect?: (agent: AgentProfile) => void;
10
+ onCancel?: () => void;
11
+ constructor(tui: TUI, agents: AgentProfile[]);
12
+ handleInput(data: string): void;
13
+ render(width: number): string[];
14
+ invalidate(): void;
15
+ }
@@ -0,0 +1,51 @@
1
+ import { Container, Text, Spacer, SelectList, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ export class AgentPickerScreen {
4
+ container;
5
+ selectList;
6
+ tui;
7
+ agents;
8
+ onSelect;
9
+ onCancel;
10
+ constructor(tui, agents) {
11
+ this.tui = tui;
12
+ this.agents = agents;
13
+ this.container = new Container();
14
+ this.container.addChild(new Spacer(1));
15
+ this.container.addChild(new Text(theme.border("─".repeat(50)), 0, 0));
16
+ this.container.addChild(new Text(theme.title(" Pick an agent to start"), 1, 0));
17
+ this.container.addChild(new Spacer(1));
18
+ const items = agents.map((a) => ({
19
+ value: a.id,
20
+ label: a.name,
21
+ description: a.modelPattern || "(auto model)",
22
+ }));
23
+ this.selectList = new SelectList(items, Math.min(items.length, 15), {
24
+ selectedPrefix: (t) => theme.accent(t),
25
+ selectedText: (t) => theme.accent(t),
26
+ description: (t) => colors.gray(t),
27
+ scrollInfo: (t) => colors.gray(t),
28
+ noMatch: (t) => colors.yellow(t),
29
+ });
30
+ this.selectList.onSelect = (item) => {
31
+ const agent = agents.find((a) => a.id === item.value);
32
+ if (agent)
33
+ this.onSelect?.(agent);
34
+ };
35
+ this.selectList.onCancel = () => this.onCancel?.();
36
+ this.container.addChild(this.selectList);
37
+ this.container.addChild(new Spacer(1));
38
+ this.container.addChild(new Text(colors.gray(" ↑↓ navigate • enter select • esc back"), 1, 0));
39
+ this.container.addChild(new Text(theme.border("─".repeat(50)), 0, 0));
40
+ }
41
+ handleInput(data) {
42
+ this.selectList.handleInput(data);
43
+ this.tui.requestRender();
44
+ }
45
+ render(width) {
46
+ return this.container.render(width);
47
+ }
48
+ invalidate() {
49
+ this.container.invalidate();
50
+ }
51
+ }
@@ -0,0 +1,20 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ import type { Model, Api } from "@mariozechner/pi-ai";
4
+ export declare class AgentRunningScreen implements Component {
5
+ private tui;
6
+ private logLines;
7
+ private cachedRender?;
8
+ private model;
9
+ private serverUrl;
10
+ private agentName;
11
+ private sessionGoal;
12
+ private statusLine;
13
+ onStop?: () => void;
14
+ constructor(tui: TUI, model: Model<Api>, serverUrl: string, agentName: string, sessionGoal?: string);
15
+ setStatus(status: string): void;
16
+ addLog(line: string): void;
17
+ handleInput(data: string): void;
18
+ render(width: number): string[];
19
+ invalidate(): void;
20
+ }
@@ -0,0 +1,68 @@
1
+ import { matchesKey, Key, truncateToWidth, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ const MAX_LOG_LINES = 200;
4
+ export class AgentRunningScreen {
5
+ tui;
6
+ logLines = [];
7
+ cachedRender;
8
+ model;
9
+ serverUrl;
10
+ agentName;
11
+ sessionGoal;
12
+ statusLine = "starting...";
13
+ onStop;
14
+ constructor(tui, model, serverUrl, agentName, sessionGoal = "") {
15
+ this.tui = tui;
16
+ this.model = model;
17
+ this.serverUrl = serverUrl;
18
+ this.agentName = agentName;
19
+ this.sessionGoal = sessionGoal;
20
+ }
21
+ setStatus(status) {
22
+ this.statusLine = status;
23
+ this.cachedRender = undefined;
24
+ this.tui.requestRender();
25
+ }
26
+ addLog(line) {
27
+ this.logLines.push(line);
28
+ if (this.logLines.length > MAX_LOG_LINES) {
29
+ this.logLines.shift();
30
+ }
31
+ this.cachedRender = undefined;
32
+ this.tui.requestRender();
33
+ }
34
+ handleInput(data) {
35
+ if (matchesKey(data, Key.escape) ||
36
+ matchesKey(data, "q") ||
37
+ matchesKey(data, Key.ctrl("c"))) {
38
+ this.onStop?.();
39
+ }
40
+ }
41
+ render(width) {
42
+ if (this.cachedRender)
43
+ return this.cachedRender;
44
+ const lines = [];
45
+ // Header
46
+ lines.push(theme.border("─".repeat(width)));
47
+ const modelInfo = `${this.model.provider}/${this.model.id}`;
48
+ lines.push(truncateToWidth(` ${theme.title("⚡ AGENT ONLINE")} ${colors.cyan(this.agentName)} ${colors.gray("model:")} ${colors.green(modelInfo)}`, width));
49
+ if (this.sessionGoal) {
50
+ lines.push(truncateToWidth(` ${colors.gray("goal:")} ${colors.cyan(this.sessionGoal)}`, width));
51
+ }
52
+ lines.push(theme.border("─".repeat(width)));
53
+ lines.push("");
54
+ // Log
55
+ for (const logLine of this.logLines) {
56
+ lines.push(truncateToWidth(` ${logLine}`, width));
57
+ }
58
+ // Footer
59
+ lines.push("");
60
+ lines.push(theme.border("─".repeat(width)));
61
+ lines.push(truncateToWidth(` ${colors.gray(this.statusLine)} ${colors.gray("• esc/q stop")}`, width));
62
+ this.cachedRender = lines;
63
+ return lines;
64
+ }
65
+ invalidate() {
66
+ this.cachedRender = undefined;
67
+ }
68
+ }
@@ -0,0 +1,6 @@
1
+ import { Container } from "@mariozechner/pi-tui";
2
+ export declare class BannerComponent extends Container {
3
+ constructor();
4
+ private rebuild;
5
+ invalidate(): void;
6
+ }
@@ -0,0 +1,27 @@
1
+ import { Container, Text, Spacer } from "@mariozechner/pi-tui";
2
+ import { colors } from "../theme.js";
3
+ // "LET THE SWARM BEGIN" — figlet Mini font, 70 chars wide, single horizontal block
4
+ const BANNER_ART = [
5
+ ` _ ___ ___ _ __ _ _ _ __ ___`,
6
+ ` | |_ | | |_| |_ (_ \\ / /\\ |_) |\\/| |_) |_ /__ | |\\ |`,
7
+ ` |_ |_ | | | | |_ __) \\/\\/ /--\\ | \\ | | |_) |_ \\_| _|_ | \\|`,
8
+ ];
9
+ export class BannerComponent extends Container {
10
+ constructor() {
11
+ super();
12
+ this.rebuild();
13
+ }
14
+ rebuild() {
15
+ this.clear();
16
+ this.addChild(new Spacer(1));
17
+ for (const line of BANNER_ART) {
18
+ this.addChild(new Text(colors.bold(colors.lime(line)), 1, 0));
19
+ }
20
+ this.addChild(new Text(colors.gray(" swarmlancer.com — let the swarm begin"), 1, 0));
21
+ this.addChild(new Spacer(1));
22
+ }
23
+ invalidate() {
24
+ super.invalidate();
25
+ this.rebuild();
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ import { type StatusInfo } from "./status-panel.js";
4
+ export type MenuAction = "start" | "agents" | "quit";
5
+ export declare class DashboardScreen implements Component {
6
+ private container;
7
+ private statusPanel;
8
+ private selectList;
9
+ private tui;
10
+ onAction?: (action: MenuAction) => void;
11
+ constructor(tui: TUI, status: StatusInfo);
12
+ updateStatus(info: Partial<StatusInfo>): void;
13
+ handleInput(data: string): void;
14
+ render(width: number): string[];
15
+ invalidate(): void;
16
+ }
@@ -0,0 +1,59 @@
1
+ import { Container, Text, Spacer, SelectList, matchesKey, } from "@mariozechner/pi-tui";
2
+ import { colors, theme } from "../theme.js";
3
+ import { StatusPanel } from "./status-panel.js";
4
+ import { BannerComponent } from "./banner.js";
5
+ const MENU_ITEMS = [
6
+ { value: "start", label: "Start agent", description: "Pick an agent → set goal → discover → connect" },
7
+ { value: "agents", label: "Manage agents", description: "Create, edit, or delete agents" },
8
+ { value: "quit", label: "Quit", description: "Exit swarmlancer" },
9
+ ];
10
+ export class DashboardScreen {
11
+ container;
12
+ statusPanel;
13
+ selectList;
14
+ tui;
15
+ onAction;
16
+ constructor(tui, status) {
17
+ this.tui = tui;
18
+ this.container = new Container();
19
+ // Banner
20
+ this.container.addChild(new BannerComponent());
21
+ // Status
22
+ this.statusPanel = new StatusPanel(status);
23
+ this.container.addChild(this.statusPanel);
24
+ this.container.addChild(new Spacer(1));
25
+ // Menu
26
+ this.container.addChild(new Text(colors.bold(" What do you want to do?"), 1, 0));
27
+ this.container.addChild(new Spacer(1));
28
+ this.selectList = new SelectList(MENU_ITEMS, MENU_ITEMS.length, {
29
+ selectedPrefix: (t) => theme.accent(t),
30
+ selectedText: (t) => theme.accent(t),
31
+ description: (t) => colors.gray(t),
32
+ scrollInfo: (t) => colors.gray(t),
33
+ noMatch: (t) => colors.yellow(t),
34
+ });
35
+ this.selectList.onSelect = (item) => {
36
+ this.onAction?.(item.value);
37
+ };
38
+ this.container.addChild(this.selectList);
39
+ this.container.addChild(new Spacer(1));
40
+ this.container.addChild(new Text(colors.gray(" ↑↓ navigate • enter select • q quit"), 1, 0));
41
+ }
42
+ updateStatus(info) {
43
+ this.statusPanel.update(info);
44
+ }
45
+ handleInput(data) {
46
+ if (matchesKey(data, "q")) {
47
+ this.onAction?.("quit");
48
+ return;
49
+ }
50
+ this.selectList.handleInput(data);
51
+ this.tui.requestRender();
52
+ }
53
+ render(width) {
54
+ return this.container.render(width);
55
+ }
56
+ invalidate() {
57
+ this.container.invalidate();
58
+ }
59
+ }
@@ -0,0 +1,17 @@
1
+ import { type Component } from "@mariozechner/pi-tui";
2
+ import type { TUI } from "@mariozechner/pi-tui";
3
+ import type { DiscoverySettings } from "../config.js";
4
+ export declare class DiscoverySettingsScreen implements Component {
5
+ private tui;
6
+ private settings;
7
+ private selectedIndex;
8
+ private editingKeywords;
9
+ private keywordInput;
10
+ private cachedRender?;
11
+ onSave?: (settings: DiscoverySettings) => void;
12
+ onCancel?: () => void;
13
+ constructor(tui: TUI, settings: DiscoverySettings);
14
+ handleInput(data: string): void;
15
+ render(width: number): string[];
16
+ invalidate(): void;
17
+ }