@falkenslab/agent-kit 0.10.2 → 0.13.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 (68) hide show
  1. package/README.md +105 -97
  2. package/dist/core/agentSpec.d.ts +31 -1
  3. package/dist/core/claudeAuth.d.ts +1 -0
  4. package/dist/core/hooks/stepGate.js +3 -2
  5. package/dist/core/hooks/transcriptLogger.d.ts +1 -0
  6. package/dist/core/interaction.d.ts +3 -0
  7. package/dist/core/interaction.js +2 -0
  8. package/dist/core/language.d.ts +41 -0
  9. package/dist/core/language.js +60 -0
  10. package/dist/core/messages/de.d.ts +2 -0
  11. package/dist/core/messages/de.js +103 -0
  12. package/dist/core/messages/en.d.ts +90 -0
  13. package/dist/core/messages/en.js +102 -0
  14. package/dist/core/messages/es.d.ts +2 -0
  15. package/dist/core/messages/es.js +103 -0
  16. package/dist/core/messages/fr.d.ts +2 -0
  17. package/dist/core/messages/fr.js +103 -0
  18. package/dist/core/messages/index.d.ts +23 -0
  19. package/dist/core/messages/index.js +67 -0
  20. package/dist/core/runner.d.ts +2 -0
  21. package/dist/core/runs.d.ts +53 -0
  22. package/dist/core/runs.js +194 -0
  23. package/dist/core/session.d.ts +9 -0
  24. package/dist/core/session.js +43 -7
  25. package/dist/core/toolLabels.d.ts +8 -1
  26. package/dist/core/toolLabels.js +36 -54
  27. package/dist/core/tools/humanApproval.d.ts +1 -0
  28. package/dist/core/tools/humanApproval.js +3 -2
  29. package/dist/core/tools/manualLogin.d.ts +1 -0
  30. package/dist/index.d.ts +6 -0
  31. package/dist/index.js +7 -0
  32. package/dist/tui/chatTui.d.ts +31 -2
  33. package/dist/tui/chatTui.js +73 -7
  34. package/dist/tui/claudeAuth.d.ts +3 -1
  35. package/dist/tui/claudeAuth.js +12 -17
  36. package/dist/tui/consoleRenderer.d.ts +2 -0
  37. package/dist/tui/consoleRenderer.js +2 -1
  38. package/dist/tui/ink/PromptInput.d.ts +0 -2
  39. package/dist/tui/ink/PromptInput.js +5 -15
  40. package/dist/tui/ink/SessionView.js +17 -16
  41. package/dist/tui/ink/header.d.ts +1 -0
  42. package/dist/tui/ink/inkInteraction.js +4 -7
  43. package/dist/tui/ink/inkTheme.d.ts +9 -0
  44. package/dist/tui/ink/inkTheme.js +25 -0
  45. package/dist/tui/ink/markdown.js +49 -8
  46. package/dist/tui/ink/progressView.d.ts +15 -0
  47. package/dist/tui/ink/progressView.js +6 -1
  48. package/dist/tui/ink/promptEditing.d.ts +2 -5
  49. package/dist/tui/ink/promptEditing.js +11 -3
  50. package/dist/tui/ink/runChatInk.d.ts +26 -2
  51. package/dist/tui/ink/runChatInk.js +159 -48
  52. package/dist/tui/ink/sessionModel.d.ts +10 -0
  53. package/dist/tui/ink/sessionModel.js +27 -2
  54. package/dist/tui/ink/toolGroup.d.ts +2 -1
  55. package/dist/tui/ink/toolGroup.js +10 -21
  56. package/dist/tui/ink/wizard.d.ts +20 -0
  57. package/dist/tui/ink/wizard.js +8 -2
  58. package/dist/tui/language.d.ts +5 -0
  59. package/dist/tui/language.js +11 -0
  60. package/dist/tui/runs.d.ts +27 -0
  61. package/dist/tui/runs.js +30 -0
  62. package/dist/tui/terminalInteraction.d.ts +2 -0
  63. package/dist/tui/terminalInteraction.js +4 -2
  64. package/dist/tui/theme.d.ts +60 -0
  65. package/dist/tui/theme.js +65 -0
  66. package/dist/tui/ui.d.ts +23 -3
  67. package/dist/tui/ui.js +42 -18
  68. package/package.json +79 -75
@@ -1,3 +1,5 @@
1
+ import { type Theme } from "../theme.js";
2
+ /** The wizard's answers, by step name. */
1
3
  export type WizardAnswers = Record<string, unknown>;
2
4
  /** A value, or one computed from the answers given so far. */
3
5
  type FromAnswers<T> = T | ((answers: WizardAnswers) => T);
@@ -8,6 +10,7 @@ interface BaseStep {
8
10
  /** Skips the step (leaving no answer) when it returns false. */
9
11
  when?: (answers: WizardAnswers) => boolean;
10
12
  }
13
+ /** A choice among `choices`; the answer is the chosen `value`. */
11
14
  export interface SelectStep<T = unknown> extends BaseStep {
12
15
  type: "select";
13
16
  choices: FromAnswers<{
@@ -17,26 +20,43 @@ export interface SelectStep<T = unknown> extends BaseStep {
17
20
  /** Preselects the choice with this value. */
18
21
  default?: FromAnswers<T>;
19
22
  }
23
+ /** A line of text. */
20
24
  export interface InputStep extends BaseStep {
21
25
  type: "input";
22
26
  default?: FromAnswers<string>;
23
27
  /** `true` to accept, or the message to show. */
24
28
  validate?: (value: string, answers: WizardAnswers) => true | string;
25
29
  }
30
+ /** A line of text, masked while typed and in the summary. */
26
31
  export interface PasswordStep extends BaseStep {
27
32
  type: "password";
28
33
  validate?: (value: string, answers: WizardAnswers) => true | string;
29
34
  }
35
+ /** A yes/no question; the answer is a boolean. */
30
36
  export interface ConfirmStep extends BaseStep {
31
37
  type: "confirm";
32
38
  default?: FromAnswers<boolean>;
33
39
  }
40
+ /** One question of `runWizard()`. */
34
41
  export type WizardStep = SelectStep | InputStep | PasswordStep | ConfirmStep;
42
+ /** Options of `runWizard()`. */
35
43
  export interface WizardOptions {
36
44
  /** Printed above the first question. */
37
45
  title?: string;
38
46
  /** Use the plain @inquirer/prompts questions even on a TTY. */
39
47
  plain?: boolean;
48
+ /**
49
+ * Colors for the kit's roles (see `Theme`), on top of the kit's defaults: only the roles
50
+ * given change, e.g. `{ toolResult: "yellow", selection: "#00ff00" }`. One theme per
51
+ * process: without this option, the one already set stays.
52
+ */
53
+ theme?: Partial<Theme>;
54
+ /**
55
+ * The language of the kit's texts ("en", "es", "fr", "de"). `--language=<code>` on the
56
+ * command line wins; without either, the one `buildSessionOptions()` chose from
57
+ * `config.language`, or else the system's.
58
+ */
59
+ language?: string;
40
60
  }
41
61
  /**
42
62
  * How many choices a select shows at once, so the question, its choices and a validation
@@ -7,6 +7,10 @@ import { liveWidth } from "./sessionModel.js";
7
7
  import { ConfirmInput, PasswordInput, Select, TextInput } from "@inkjs/ui";
8
8
  import * as inquirer from "@inquirer/prompts";
9
9
  import * as ui from "../ui.js";
10
+ import { t } from "../../core/messages/index.js";
11
+ import { applyLanguage } from "../language.js";
12
+ import { applyTheme } from "../theme.js";
13
+ import { KitTheme } from "./inkTheme.js";
10
14
  function resolve(value, answers) {
11
15
  return typeof value === "function" ? value(answers) : value;
12
16
  }
@@ -63,7 +67,7 @@ function summary(step, value, answers) {
63
67
  if (step.type === "password")
64
68
  return "*".repeat(String(value).length);
65
69
  if (step.type === "confirm")
66
- return value ? "Yes" : "No";
70
+ return value ? t().yes : t().no;
67
71
  if (step.type === "select")
68
72
  return resolve(step.choices, answers).find((c) => c.value === value)?.name ?? String(value);
69
73
  return String(value);
@@ -154,12 +158,14 @@ async function runPlainWizard(steps, title) {
154
158
  * steps through @inquirer/prompts.
155
159
  */
156
160
  export async function runWizard(steps, options = {}) {
161
+ applyLanguage(options.language);
162
+ applyTheme(options.theme);
157
163
  if (options.plain || !stdin.isTTY || !stdout.isTTY)
158
164
  return await runPlainWizard(steps, options.title);
159
165
  if (nextIndex(steps, -1, {}) >= steps.length)
160
166
  return {};
161
167
  let result = null;
162
- const app = render(_jsx(Wizard, { steps: steps, title: options.title, onDone: (answers) => (result = answers) }), { exitOnCtrlC: false });
168
+ const app = render(_jsx(KitTheme, { children: _jsx(Wizard, { steps: steps, title: options.title, onDone: (answers) => (result = answers) }) }), { exitOnCtrlC: false });
163
169
  await app.waitUntilExit();
164
170
  if (result === null)
165
171
  throw exitPromptError();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Chooses the kit's language for a terminal entry point (see messages/'s chooseLanguage())
3
+ * and prints the warnings about unsupported codes not shown yet, or hands them to `show`.
4
+ */
5
+ export declare function applyLanguage(option: string | undefined, show?: (line: string) => void): void;
@@ -0,0 +1,11 @@
1
+ import { chooseLanguage, takeLanguageWarnings } from "../core/messages/index.js";
2
+ import * as ui from "./ui.js";
3
+ /**
4
+ * Chooses the kit's language for a terminal entry point (see messages/'s chooseLanguage())
5
+ * and prints the warnings about unsupported codes not shown yet, or hands them to `show`.
6
+ */
7
+ export function applyLanguage(option, show = (line) => console.warn(ui.warn(line))) {
8
+ chooseLanguage(option);
9
+ for (const warning of takeLanguageWarnings())
10
+ show(warning);
11
+ }
@@ -0,0 +1,27 @@
1
+ import type { Options } from "@anthropic-ai/claude-agent-sdk";
2
+ import type { ModeControl } from "../core/session.js";
3
+ import { type RunFolder, type RunSummary } from "../core/runs.js";
4
+ /**
5
+ * Builds the session's options for a run folder, e.g.
6
+ * `(run) => buildSessionOptions(config, run.dir, spec, { run })`: called for the first run
7
+ * and again for each one resumed with /resume (MCP servers, the step gate and the transcript
8
+ * are bound to the run's folder, so they're built anew).
9
+ */
10
+ export type SessionOpener = (run: RunFolder) => Promise<Options | {
11
+ options: Options;
12
+ modeControl?: ModeControl;
13
+ }>;
14
+ export interface OpenedSession {
15
+ run: RunFolder;
16
+ options: Options;
17
+ modeControl?: ModeControl;
18
+ }
19
+ /** The run a chat starts with: the latest one with `--continue` (if any), a new one otherwise. */
20
+ export declare function firstRun(runsDir: string, argv?: readonly string[]): Promise<RunFolder>;
21
+ export declare function openSession(opener: SessionOpener, run: RunFolder): Promise<OpenedSession>;
22
+ /** A run's date for a person, in the kit's language. */
23
+ export declare function runDate(date: Date): string;
24
+ /** A run in the /resume list: its date and the human's last message. */
25
+ export declare function runLabel(run: RunSummary, current?: RunFolder): string;
26
+ /** The run folder of a summary, re-reading its session (a run resumed a moment ago may have changed). */
27
+ export declare function runFolderOf(run: RunSummary): Promise<RunFolder>;
@@ -0,0 +1,30 @@
1
+ import path from "node:path";
2
+ import { continueArgument, createRunFolder, listRuns, readRunSession } from "../core/runs.js";
3
+ import { getLanguage, t } from "../core/messages/index.js";
4
+ /** The run a chat starts with: the latest one with `--continue` (if any), a new one otherwise. */
5
+ export async function firstRun(runsDir, argv = process.argv.slice(2)) {
6
+ if (continueArgument(argv)) {
7
+ const [latest] = await listRuns(runsDir);
8
+ if (latest)
9
+ return { dir: latest.dir, sessionId: latest.sessionId };
10
+ }
11
+ return await createRunFolder(runsDir);
12
+ }
13
+ export async function openSession(opener, run) {
14
+ const opened = await opener(run);
15
+ // The SDK's Options has no "options" field: this is buildSessionOptions()'s result.
16
+ return "options" in opened ? { run, options: opened.options, modeControl: opened.modeControl } : { run, options: opened };
17
+ }
18
+ /** A run's date for a person, in the kit's language. */
19
+ export function runDate(date) {
20
+ return new Intl.DateTimeFormat(getLanguage(), { dateStyle: "medium", timeStyle: "short" }).format(date);
21
+ }
22
+ /** A run in the /resume list: its date and the human's last message. */
23
+ export function runLabel(run, current) {
24
+ const mark = current && path.resolve(current.dir) === path.resolve(run.dir) ? ` ${t().currentRun}` : "";
25
+ return `${runDate(run.updatedAt)}${mark}${run.lastMessage ? ` · ${run.lastMessage}` : ""}`;
26
+ }
27
+ /** The run folder of a summary, re-reading its session (a run resumed a moment ago may have changed). */
28
+ export async function runFolderOf(run) {
29
+ return { dir: run.dir, sessionId: (await readRunSession(run.dir)) ?? run.sessionId };
30
+ }
@@ -1,6 +1,8 @@
1
1
  import readline from "node:readline/promises";
2
2
  import type { InteractionPort } from "../core/interaction.js";
3
+ /** Registers the chat's `readline` interface, so checkpoints ask on it instead of opening a second one (`null` to unregister). */
3
4
  export declare function setSharedReadline(rl: readline.Interface | null): void;
5
+ /** The registered `readline` interface, or `null`. */
4
6
  export declare function getSharedReadline(): readline.Interface | null;
5
7
  /**
6
8
  * Asks `question` on the shared interface, flagging it as in progress meanwhile — so the
@@ -1,6 +1,6 @@
1
1
  import readline from "node:readline/promises";
2
2
  import { stdin, stdout } from "node:process";
3
- const DEFAULT_QUESTION = "Allow this to continue? [Y/n/q] ";
3
+ import { t } from "../core/messages/index.js";
4
4
  /**
5
5
  * A long-lived chat REPL's readline interface (if any), so that the terminal port reuses
6
6
  * it instead of creating its own.
@@ -14,9 +14,11 @@ const DEFAULT_QUESTION = "Allow this to continue? [Y/n/q] ";
14
14
  * interface here, the port reuses it (creating or closing nothing) whenever it's available.
15
15
  */
16
16
  let sharedReadline = null;
17
+ /** Registers the chat's `readline` interface, so checkpoints ask on it instead of opening a second one (`null` to unregister). */
17
18
  export function setSharedReadline(rl) {
18
19
  sharedReadline = rl;
19
20
  }
21
+ /** The registered `readline` interface, or `null`. */
20
22
  export function getSharedReadline() {
21
23
  return sharedReadline;
22
24
  }
@@ -55,7 +57,7 @@ async function askOnTerminal(prompt, signal) {
55
57
  console.log(`\n=== ${prompt.title} ===`);
56
58
  for (const line of prompt.lines)
57
59
  console.log(line);
58
- const question = prompt.question ?? DEFAULT_QUESTION;
60
+ const question = prompt.question ?? t().terminalQuestion;
59
61
  const shared = sharedReadline;
60
62
  if (shared)
61
63
  return await askOnSharedReadline(shared, question);
@@ -0,0 +1,60 @@
1
+ /**
2
+ * A color for one role of the theme: a color name (`"gray"`, `"cyanBright"`: picocolors' and
3
+ * Ink's names), a hex (`"#ff8800"`), or a function that styles the text itself (bold, a
4
+ * background...). Roles drawn by Ink props (`border`, `selection`, the panels' `accent`) need
5
+ * a name or a hex: a function there falls back to the default color.
6
+ */
7
+ export type ThemeColor = string | ((text: string) => string);
8
+ /** The terminal UI's colors, by what they're for. */
9
+ export interface Theme {
10
+ /** The agent's replies and its label. */
11
+ agent: ThemeColor;
12
+ /** The human's prompt label. */
13
+ user: ThemeColor;
14
+ /** The background of the human's lines in the Ink chat (a name or a hex). */
15
+ userBar: ThemeColor;
16
+ /** The border of the approval and manual-intervention panels (a name or a hex). */
17
+ accent: ThemeColor;
18
+ /** The spinner with what the agent is doing, and the mode in the status bar. */
19
+ working: ThemeColor;
20
+ /** Inline code and code blocks in the agent's replies. */
21
+ code: ThemeColor;
22
+ /** The `●` before each tool call. */
23
+ toolBullet: ThemeColor;
24
+ /** A tool call's label (`● Reading notes.md`). */
25
+ toolLabel: ThemeColor;
26
+ /** The one-line result under a tool call (`⎿ …`); an error is `error` instead. */
27
+ toolResult: ThemeColor;
28
+ /** The focused option of a choice list (approval panels, /resume, the wizard), in bold. */
29
+ selection: ThemeColor;
30
+ /** The frame around the prompt and the /resume list. */
31
+ border: ThemeColor;
32
+ /** Secondary text: notices, summaries, hints. */
33
+ dim: ThemeColor;
34
+ /** Titles (checkpoints, the wizard's questions). */
35
+ heading: ThemeColor;
36
+ /** The plain console's `[action]` lines. */
37
+ action: ThemeColor;
38
+ success: ThemeColor;
39
+ warn: ThemeColor;
40
+ error: ThemeColor;
41
+ }
42
+ /** The kit's own look. */
43
+ export declare const DEFAULT_THEME: Readonly<Theme>;
44
+ /** The kit's default theme with `overrides` on top: only the roles given change. */
45
+ export declare function setTheme(overrides?: Partial<Theme>): void;
46
+ /** The theme in use right now. */
47
+ export declare function getTheme(): Readonly<Theme>;
48
+ /** Changes the theme when an entry point was given one; without it, keeps the current one. */
49
+ export declare function applyTheme(overrides: Partial<Theme> | undefined): void;
50
+ /**
51
+ * `text` in `color`: a function is applied as given; a name or a hex becomes the terminal's
52
+ * escape codes, or nothing when the terminal has no color (`enabled`). `background` for a
53
+ * background color (a name becomes its `bg` form).
54
+ */
55
+ export declare function paint(color: ThemeColor, text: string, options?: {
56
+ background?: boolean;
57
+ enabled?: boolean;
58
+ }): string;
59
+ /** A role's color as an Ink prop (a name or a hex); a function falls back to the default's. */
60
+ export declare function inkColor(role: "accent" | "border" | "selection"): string;
@@ -0,0 +1,65 @@
1
+ import pc from "picocolors";
2
+ /** The kit's own look. */
3
+ export const DEFAULT_THEME = {
4
+ agent: "cyanBright",
5
+ user: "white",
6
+ userBar: "#373737",
7
+ accent: "#d77757",
8
+ working: "#89b4fa",
9
+ code: "#b1b9f9",
10
+ toolBullet: "green",
11
+ toolLabel: (text) => pc.dim(text),
12
+ toolResult: (text) => pc.dim(text),
13
+ selection: "#d77757",
14
+ border: "gray",
15
+ dim: (text) => pc.dim(text),
16
+ heading: (text) => pc.bold(text),
17
+ action: "magenta",
18
+ success: "green",
19
+ warn: "yellow",
20
+ error: "red",
21
+ };
22
+ // One theme per process, like the language (ADR-019).
23
+ let current = { ...DEFAULT_THEME };
24
+ /** The kit's default theme with `overrides` on top: only the roles given change. */
25
+ export function setTheme(overrides = {}) {
26
+ current = { ...DEFAULT_THEME, ...overrides };
27
+ }
28
+ /** The theme in use right now. */
29
+ export function getTheme() {
30
+ return current;
31
+ }
32
+ /** Changes the theme when an entry point was given one; without it, keeps the current one. */
33
+ export function applyTheme(overrides) {
34
+ if (overrides)
35
+ setTheme(overrides);
36
+ }
37
+ const HEX = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i;
38
+ const COLORS = pc.createColors(true);
39
+ const NAMES = new Set(Object.keys(pc).filter((key) => typeof pc[key] === "function" && key !== "createColors"));
40
+ /**
41
+ * `text` in `color`: a function is applied as given; a name or a hex becomes the terminal's
42
+ * escape codes, or nothing when the terminal has no color (`enabled`). `background` for a
43
+ * background color (a name becomes its `bg` form).
44
+ */
45
+ export function paint(color, text, options = {}) {
46
+ if (typeof color === "function")
47
+ return color(text);
48
+ const enabled = options.enabled ?? pc.isColorSupported;
49
+ if (!enabled)
50
+ return text;
51
+ const hex = HEX.exec(color);
52
+ if (hex) {
53
+ const [r, g, b] = hex.slice(1).map((part) => parseInt(part, 16));
54
+ return options.background ? `\x1b[48;2;${r};${g};${b}m${text}\x1b[49m` : `\x1b[38;2;${r};${g};${b}m${text}\x1b[39m`;
55
+ }
56
+ const name = options.background ? `bg${color.charAt(0).toUpperCase()}${color.slice(1)}` : color;
57
+ if (!NAMES.has(name))
58
+ return text;
59
+ return COLORS[name](text);
60
+ }
61
+ /** A role's color as an Ink prop (a name or a hex); a function falls back to the default's. */
62
+ export function inkColor(role) {
63
+ const color = current[role];
64
+ return typeof color === "string" ? color : DEFAULT_THEME[role];
65
+ }
package/dist/tui/ui.d.ts CHANGED
@@ -1,13 +1,25 @@
1
- /** Color palette for a consistent console look across whatever CLI is built on this kit. */
1
+ /**
2
+ * The terminal palette: one function per theme role, drawing text in the current theme.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ /** The agent's label and texts (`agent` role). */
2
7
  export declare const agent: (s: string) => string;
8
+ /** The person's prompt label (`user` role). */
3
9
  export declare const user: (s: string) => string;
10
+ /** The plain console's `[action]` lines (`action` role). */
4
11
  export declare const action: (s: string) => string;
12
+ /** Titles (`heading` role, bold by default). */
5
13
  export declare const heading: (s: string) => string;
14
+ /** Good outcomes (`success` role). */
6
15
  export declare const success: (s: string) => string;
16
+ /** Warnings and notices (`warn` role). */
7
17
  export declare const warn: (s: string) => string;
18
+ /** Errors (`error` role). */
8
19
  export declare const error: (s: string) => string;
20
+ /** Secondary text (`dim` role). */
9
21
  export declare const dim: (s: string) => string;
10
- /** The orange accent: spinner, turn summary, mode. */
22
+ /** The accent (the approval panels' border). */
11
23
  export declare const accent: (s: string) => string;
12
24
  /** The spinner and what the agent is doing. */
13
25
  export declare const working: (s: string) => string;
@@ -15,7 +27,15 @@ export declare const working: (s: string) => string;
15
27
  export declare const code: (s: string) => string;
16
28
  /** The background of the human's lines. */
17
29
  export declare const userBar: (s: string) => string;
30
+ /** The `●` before a tool call (`toolBullet` role). */
31
+ export declare const toolBullet: (s: string) => string;
32
+ /** A tool call's label. */
33
+ export declare const toolLabel: (s: string) => string;
34
+ /** The one-line result under a tool call. */
35
+ export declare const toolResult: (s: string) => string;
36
+ /** Bold, whatever the theme. */
18
37
  export declare const bold: (s: string) => string;
38
+ /** Italics, whatever the theme. */
19
39
  export declare const italic: (s: string) => string;
40
+ /** Strikethrough, whatever the theme. */
20
41
  export declare const strike: (s: string) => string;
21
- export declare const toolBullet: (s: string) => string;
package/dist/tui/ui.js CHANGED
@@ -1,25 +1,49 @@
1
+ /**
2
+ * The terminal palette: one function per theme role, drawing text in the current theme.
3
+ *
4
+ * @packageDocumentation
5
+ */
1
6
  import pc from "picocolors";
2
- /** Color palette for a consistent console look across whatever CLI is built on this kit. */
3
- export const agent = (s) => pc.cyanBright(s);
4
- export const user = (s) => pc.white(s);
5
- export const action = (s) => pc.magenta(s);
6
- export const heading = (s) => pc.bold(s);
7
- export const success = (s) => pc.green(s);
8
- export const warn = (s) => pc.yellow(s);
9
- export const error = (s) => pc.red(s);
10
- export const dim = (s) => pc.dim(s);
11
- // The Claude Code-like look of the Ink views (see the feature ink-claude-style), in 24-bit
12
- // color when the terminal supports color at all, like the rest of this palette.
13
- const rgb = (r, g, b) => (s) => pc.isColorSupported ? `\x1b[38;2;${r};${g};${b}m${s}\x1b[39m` : s;
14
- /** The orange accent: spinner, turn summary, mode. */
15
- export const accent = rgb(215, 119, 87);
7
+ import { getTheme, paint } from "./theme.js";
8
+ /*
9
+ * Color palette for a consistent console look across whatever CLI is built on this kit.
10
+ * Each function draws its role in the current theme (see theme.ts), so an agent's theme
11
+ * reaches everything that uses them, its own texts included.
12
+ */
13
+ /** The agent's label and texts (`agent` role). */
14
+ export const agent = (s) => paint(getTheme().agent, s);
15
+ /** The person's prompt label (`user` role). */
16
+ export const user = (s) => paint(getTheme().user, s);
17
+ /** The plain console's `[action]` lines (`action` role). */
18
+ export const action = (s) => paint(getTheme().action, s);
19
+ /** Titles (`heading` role, bold by default). */
20
+ export const heading = (s) => paint(getTheme().heading, s);
21
+ /** Good outcomes (`success` role). */
22
+ export const success = (s) => paint(getTheme().success, s);
23
+ /** Warnings and notices (`warn` role). */
24
+ export const warn = (s) => paint(getTheme().warn, s);
25
+ /** Errors (`error` role). */
26
+ export const error = (s) => paint(getTheme().error, s);
27
+ /** Secondary text (`dim` role). */
28
+ export const dim = (s) => paint(getTheme().dim, s);
29
+ // The Claude Code-like look of the Ink views (see the feature ink-claude-style).
30
+ /** The accent (the approval panels' border). */
31
+ export const accent = (s) => paint(getTheme().accent, s);
16
32
  /** The spinner and what the agent is doing. */
17
- export const working = rgb(137, 180, 250);
33
+ export const working = (s) => paint(getTheme().working, s);
18
34
  /** Inline code and code blocks. */
19
- export const code = rgb(177, 185, 249);
35
+ export const code = (s) => paint(getTheme().code, s);
20
36
  /** The background of the human's lines. */
21
- export const userBar = (s) => (pc.isColorSupported ? `\x1b[48;2;55;55;55m${s}\x1b[49m` : s);
37
+ export const userBar = (s) => paint(getTheme().userBar, s, { background: true });
38
+ /** The `●` before a tool call (`toolBullet` role). */
39
+ export const toolBullet = (s) => paint(getTheme().toolBullet, s);
40
+ /** A tool call's label. */
41
+ export const toolLabel = (s) => paint(getTheme().toolLabel, s);
42
+ /** The one-line result under a tool call. */
43
+ export const toolResult = (s) => paint(getTheme().toolResult, s);
44
+ /** Bold, whatever the theme. */
22
45
  export const bold = (s) => pc.bold(s);
46
+ /** Italics, whatever the theme. */
23
47
  export const italic = (s) => pc.italic(s);
48
+ /** Strikethrough, whatever the theme. */
24
49
  export const strike = (s) => pc.strikethrough(s);
25
- export const toolBullet = (s) => pc.green(s);
package/package.json CHANGED
@@ -1,75 +1,79 @@
1
- {
2
- "name": "@falkenslab/agent-kit",
3
- "version": "0.10.2",
4
- "description": "Library for building an agent on top of the Claude Agent SDK",
5
- "author": "Francisco Vargas Ruiz",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/falkenslab/agent-kit.git"
10
- },
11
- "homepage": "https://github.com/falkenslab/agent-kit#readme",
12
- "bugs": {
13
- "url": "https://github.com/falkenslab/agent-kit/issues"
14
- },
15
- "keywords": [
16
- "claude",
17
- "claude-agent-sdk",
18
- "ai-agent",
19
- "agent",
20
- "anthropic",
21
- "ink",
22
- "tui",
23
- "cli",
24
- "human-in-the-loop",
25
- "mcp"
26
- ],
27
- "type": "module",
28
- "engines": {
29
- "node": ">=20"
30
- },
31
- "main": "./dist/index.js",
32
- "types": "./dist/index.d.ts",
33
- "files": [
34
- "dist",
35
- "assets"
36
- ],
37
- "scripts": {
38
- "build": "tsc",
39
- "typecheck": "tsc --noEmit",
40
- "test": "tsx --test \"test/**/*.test.ts\" \"test/**/*.test.tsx\"",
41
- "lint": "eslint .",
42
- "prepare": "npm run build",
43
- "prepublishOnly": "npm run typecheck && npm run lint && npm test && npm run build"
44
- },
45
- "dependencies": {
46
- "@anthropic-ai/claude-agent-sdk": "^0.3.234",
47
- "@inkjs/ui": "^2.0.0",
48
- "@inquirer/prompts": "^8.5.2",
49
- "@types/react": "^19.3.0",
50
- "ink": "^6.8.0",
51
- "marked": "^18.0.14",
52
- "picocolors": "^1.1.1",
53
- "react": "^19.3.0",
54
- "slice-ansi": "^8.0.0",
55
- "string-width": "^8.3.0",
56
- "wrap-ansi": "^9.0.2",
57
- "zod": "^4.4.3"
58
- },
59
- "devDependencies": {
60
- "@eslint/js": "^10.0.1",
61
- "@types/node": "^24.0.0",
62
- "eslint": "^10.9.1",
63
- "globals": "^17.11.0",
64
- "ink-testing-library": "^4.0.0",
65
- "tsx": "^4.19.0",
66
- "typescript": "^5.7.0",
67
- "typescript-eslint": "^8.68.0"
68
- },
69
- "allowScripts": {
70
- "esbuild@0.28.2": true
71
- },
72
- "publishConfig": {
73
- "access": "public"
74
- }
75
- }
1
+ {
2
+ "name": "@falkenslab/agent-kit",
3
+ "version": "0.13.0",
4
+ "description": "Library for building an agent on top of the Claude Agent SDK",
5
+ "author": "Francisco Vargas Ruiz",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/falkenslab/agent-kit.git"
10
+ },
11
+ "homepage": "https://github.com/falkenslab/agent-kit#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/falkenslab/agent-kit/issues"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "claude-agent-sdk",
18
+ "ai-agent",
19
+ "agent",
20
+ "anthropic",
21
+ "ink",
22
+ "tui",
23
+ "cli",
24
+ "human-in-the-loop",
25
+ "mcp"
26
+ ],
27
+ "type": "module",
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "assets"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "typecheck": "tsc --noEmit",
40
+ "test": "tsx --test \"test/**/*.test.ts\" \"test/**/*.test.tsx\"",
41
+ "lint": "eslint .",
42
+ "docs:install": "npm --prefix docs ci",
43
+ "docs:start": "npm --prefix docs start",
44
+ "docs:build": "npm --prefix docs run build",
45
+ "docs:version": "npm --prefix docs run docs:version --",
46
+ "prepare": "npm run build",
47
+ "prepublishOnly": "npm run typecheck && npm run lint && npm test && npm run build"
48
+ },
49
+ "dependencies": {
50
+ "@anthropic-ai/claude-agent-sdk": "^0.3.234",
51
+ "@inkjs/ui": "^2.0.0",
52
+ "@inquirer/prompts": "^8.5.2",
53
+ "@types/react": "^19.3.0",
54
+ "ink": "^6.8.0",
55
+ "marked": "^18.0.14",
56
+ "picocolors": "^1.1.1",
57
+ "react": "^19.3.0",
58
+ "slice-ansi": "^8.0.0",
59
+ "string-width": "^8.3.0",
60
+ "wrap-ansi": "^9.0.2",
61
+ "zod": "^4.4.3"
62
+ },
63
+ "devDependencies": {
64
+ "@eslint/js": "^10.0.1",
65
+ "@types/node": "^24.0.0",
66
+ "eslint": "^10.9.1",
67
+ "globals": "^17.11.0",
68
+ "ink-testing-library": "^4.0.0",
69
+ "tsx": "^4.19.0",
70
+ "typescript": "^5.7.0",
71
+ "typescript-eslint": "^8.68.0"
72
+ },
73
+ "allowScripts": {
74
+ "esbuild@0.28.2": true
75
+ },
76
+ "publishConfig": {
77
+ "access": "public"
78
+ }
79
+ }