botholomew 0.3.0 → 0.3.2

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 (70) hide show
  1. package/README.md +9 -0
  2. package/package.json +3 -1
  3. package/src/chat/agent.ts +87 -23
  4. package/src/chat/session.ts +19 -6
  5. package/src/cli.ts +2 -0
  6. package/src/commands/chat.ts +5 -2
  7. package/src/commands/context.ts +91 -35
  8. package/src/commands/thread.ts +180 -0
  9. package/src/config/schemas.ts +3 -1
  10. package/src/context/embedder.ts +0 -3
  11. package/src/daemon/context.ts +146 -0
  12. package/src/daemon/large-results.ts +100 -0
  13. package/src/daemon/llm.ts +45 -19
  14. package/src/daemon/prompt.ts +1 -6
  15. package/src/daemon/tick.ts +9 -0
  16. package/src/db/sql/4-unique_context_path.sql +1 -0
  17. package/src/db/threads.ts +17 -0
  18. package/src/init/templates.ts +2 -1
  19. package/src/tools/context/read-large-result.ts +33 -0
  20. package/src/tools/context/search.ts +2 -0
  21. package/src/tools/context/update-beliefs.ts +2 -0
  22. package/src/tools/context/update-goals.ts +2 -0
  23. package/src/tools/dir/create.ts +3 -2
  24. package/src/tools/dir/list.ts +2 -1
  25. package/src/tools/dir/size.ts +2 -1
  26. package/src/tools/dir/tree.ts +3 -2
  27. package/src/tools/file/copy.ts +12 -3
  28. package/src/tools/file/count-lines.ts +2 -1
  29. package/src/tools/file/delete.ts +3 -2
  30. package/src/tools/file/edit.ts +3 -2
  31. package/src/tools/file/exists.ts +2 -1
  32. package/src/tools/file/info.ts +2 -0
  33. package/src/tools/file/move.ts +12 -3
  34. package/src/tools/file/read.ts +2 -1
  35. package/src/tools/file/write.ts +5 -4
  36. package/src/tools/mcp/exec.ts +70 -3
  37. package/src/tools/mcp/info.ts +8 -0
  38. package/src/tools/mcp/list-tools.ts +18 -6
  39. package/src/tools/mcp/search.ts +38 -10
  40. package/src/tools/registry.ts +4 -0
  41. package/src/tools/schedule/create.ts +2 -0
  42. package/src/tools/schedule/list.ts +2 -0
  43. package/src/tools/search/grep.ts +3 -2
  44. package/src/tools/search/semantic.ts +2 -0
  45. package/src/tools/task/complete.ts +2 -0
  46. package/src/tools/task/create.ts +17 -4
  47. package/src/tools/task/fail.ts +2 -0
  48. package/src/tools/task/list.ts +2 -0
  49. package/src/tools/task/update.ts +87 -0
  50. package/src/tools/task/view.ts +3 -1
  51. package/src/tools/task/wait.ts +2 -0
  52. package/src/tools/thread/list.ts +2 -0
  53. package/src/tools/thread/view.ts +3 -1
  54. package/src/tools/tool.ts +7 -3
  55. package/src/tui/App.tsx +323 -78
  56. package/src/tui/components/ContextPanel.tsx +415 -0
  57. package/src/tui/components/Divider.tsx +14 -0
  58. package/src/tui/components/HelpPanel.tsx +166 -0
  59. package/src/tui/components/InputBar.tsx +157 -47
  60. package/src/tui/components/Logo.tsx +79 -0
  61. package/src/tui/components/MessageList.tsx +50 -23
  62. package/src/tui/components/QueuePanel.tsx +57 -0
  63. package/src/tui/components/StatusBar.tsx +21 -9
  64. package/src/tui/components/TabBar.tsx +40 -0
  65. package/src/tui/components/TaskPanel.tsx +409 -0
  66. package/src/tui/components/ThreadPanel.tsx +541 -0
  67. package/src/tui/components/ToolCall.tsx +68 -5
  68. package/src/tui/components/ToolPanel.tsx +295 -281
  69. package/src/tui/theme.ts +75 -0
  70. package/src/utils/title.ts +47 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Terminal-background-aware color theme for the TUI.
3
+ *
4
+ * Detection order:
5
+ * 1. COLORFGBG env var (set by Terminal.app, iTerm2, xterm)
6
+ * 2. macOS system appearance via `defaults read -g AppleInterfaceStyle`
7
+ * 3. Falls back to dark theme
8
+ */
9
+
10
+ import { spawnSync } from "node:child_process";
11
+
12
+ function detectDarkBackground(): boolean {
13
+ // 1. Check COLORFGBG env var
14
+ const colorfgbg = process.env.COLORFGBG;
15
+ if (colorfgbg) {
16
+ const parts = colorfgbg.split(";");
17
+ const bg = Number.parseInt(parts[parts.length - 1] ?? "", 10);
18
+ if (!Number.isNaN(bg)) {
19
+ // Standard terminal colors: 0-6 are dark, 7+ are light
20
+ return bg <= 6;
21
+ }
22
+ }
23
+
24
+ // 2. On macOS, check system appearance
25
+ if (process.platform === "darwin") {
26
+ try {
27
+ const result = spawnSync(
28
+ "defaults",
29
+ ["read", "-g", "AppleInterfaceStyle"],
30
+ { encoding: "utf-8", timeout: 500 },
31
+ );
32
+ // Returns "Dark" in dark mode, "Light" or exit 1 in light mode
33
+ // Only trust the result if the command succeeded (status 0)
34
+ if (result.status === 0) {
35
+ return result.stdout?.trim() === "Dark";
36
+ }
37
+ } catch {
38
+ // fall through to default
39
+ }
40
+ }
41
+
42
+ return true; // default to dark
43
+ }
44
+
45
+ const isDark = detectDarkBackground();
46
+
47
+ export const theme = {
48
+ accent: isDark ? "yellow" : "#B8860B",
49
+ accentBorder: isDark ? "yellow" : "#B8860B",
50
+ userBg: isDark ? "#2a5a8c" : "#d0e0f0",
51
+ selectionBg: isDark ? "#333" : "#ddd",
52
+ success: "green",
53
+ error: "red",
54
+ info: "cyan",
55
+ primary: "blue",
56
+ toolName: "magenta",
57
+ muted: "gray",
58
+ } as const;
59
+
60
+ /** ANSI escape codes for raw string building (detail panes, etc.) */
61
+ export const ansi = {
62
+ reset: "\x1b[0m",
63
+ bold: "\x1b[1m",
64
+ dim: "\x1b[2m",
65
+ success: "\x1b[32m",
66
+ error: "\x1b[31m",
67
+ info: "\x1b[36m",
68
+ primary: "\x1b[34m",
69
+ accent: "\x1b[33m",
70
+ toolName: "\x1b[35m",
71
+ muted: "\x1b[2m",
72
+ } as const;
73
+
74
+ // Exported for testing
75
+ export { detectDarkBackground };
@@ -0,0 +1,47 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ import type { BotholomewConfig } from "../config/schemas.ts";
3
+ import type { DbConnection } from "../db/connection.ts";
4
+ import { updateThreadTitle } from "../db/threads.ts";
5
+ import { logger } from "./logger.ts";
6
+
7
+ /**
8
+ * Generate a short title for a thread using the chunker model (Haiku).
9
+ * Fire-and-forget — errors are logged at debug level and never propagated.
10
+ */
11
+ export async function generateThreadTitle(
12
+ config: Required<BotholomewConfig>,
13
+ conn: DbConnection,
14
+ threadId: string,
15
+ context: string,
16
+ ): Promise<void> {
17
+ try {
18
+ const client = new Anthropic({
19
+ apiKey: config.anthropic_api_key || undefined,
20
+ });
21
+
22
+ const response = await client.messages.create({
23
+ model: config.chunker_model,
24
+ max_tokens: 50,
25
+ system:
26
+ "You are a title generator. The user will provide the first message from a conversation. Output a short descriptive title (5-8 words). Output ONLY the title, nothing else.",
27
+ messages: [
28
+ {
29
+ role: "user",
30
+ content: `Generate a title for this message:\n\n"${context}"`,
31
+ },
32
+ ],
33
+ });
34
+
35
+ const title = response.content
36
+ .filter((b) => b.type === "text")
37
+ .map((b) => b.text)
38
+ .join("")
39
+ .trim();
40
+
41
+ if (title) {
42
+ await updateThreadTitle(conn, threadId, title);
43
+ }
44
+ } catch (err) {
45
+ logger.warn(`Failed to generate thread title: ${err}`);
46
+ }
47
+ }