botholomew 0.16.3 → 0.17.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 (96) hide show
  1. package/README.md +46 -41
  2. package/package.json +3 -8
  3. package/src/chat/agent.ts +37 -40
  4. package/src/chat/session.ts +8 -8
  5. package/src/cli.ts +0 -2
  6. package/src/commands/capabilities.ts +32 -32
  7. package/src/commands/context.ts +124 -223
  8. package/src/commands/mcpx.ts +1 -1
  9. package/src/commands/nuke.ts +44 -15
  10. package/src/commands/prepare.ts +17 -13
  11. package/src/config/loader.ts +1 -8
  12. package/src/constants.ts +16 -32
  13. package/src/init/index.ts +11 -14
  14. package/src/mem/client.ts +17 -0
  15. package/src/{context → prompts}/capabilities.ts +11 -7
  16. package/src/schedules/store.ts +1 -1
  17. package/src/tasks/store.ts +1 -1
  18. package/src/threads/store.ts +1 -1
  19. package/src/tools/capabilities/refresh.ts +1 -1
  20. package/src/tools/membot/adapter.ts +111 -0
  21. package/src/tools/membot/copy.ts +59 -0
  22. package/src/tools/membot/count_lines.ts +53 -0
  23. package/src/tools/membot/edit.ts +72 -0
  24. package/src/tools/membot/exists.ts +54 -0
  25. package/src/tools/membot/index.ts +26 -0
  26. package/src/tools/{context → membot}/pipe.ts +34 -32
  27. package/src/tools/registry.ts +6 -37
  28. package/src/tools/tool.ts +6 -8
  29. package/src/tui/App.tsx +3 -4
  30. package/src/tui/components/ContextPanel.tsx +109 -226
  31. package/src/tui/components/HelpPanel.tsx +2 -2
  32. package/src/tui/components/MessageList.tsx +0 -1
  33. package/src/tui/components/StatusBar.tsx +0 -6
  34. package/src/tui/components/ThreadPanel.tsx +8 -7
  35. package/src/tui/wrapDetail.ts +11 -0
  36. package/src/worker/heartbeat.ts +0 -20
  37. package/src/worker/index.ts +11 -11
  38. package/src/worker/llm.ts +7 -9
  39. package/src/worker/prompt.ts +25 -13
  40. package/src/worker/spawn.ts +1 -1
  41. package/src/worker/tick.ts +10 -9
  42. package/src/commands/db.ts +0 -119
  43. package/src/commands/with-db.ts +0 -22
  44. package/src/context/chunker.ts +0 -275
  45. package/src/context/embedder-impl.ts +0 -100
  46. package/src/context/embedder.ts +0 -9
  47. package/src/context/fetcher-errors.ts +0 -8
  48. package/src/context/fetcher.ts +0 -515
  49. package/src/context/locks.ts +0 -146
  50. package/src/context/markdown-converter.ts +0 -186
  51. package/src/context/reindex.ts +0 -198
  52. package/src/context/store.ts +0 -841
  53. package/src/context/url-utils.ts +0 -25
  54. package/src/db/connection.ts +0 -255
  55. package/src/db/doctor.ts +0 -235
  56. package/src/db/embeddings.ts +0 -317
  57. package/src/db/query.ts +0 -56
  58. package/src/db/schema.ts +0 -93
  59. package/src/db/sql/1-core_tables.sql +0 -53
  60. package/src/db/sql/10-dedupe_context_items.sql +0 -26
  61. package/src/db/sql/11-rebuild_hnsw.sql +0 -8
  62. package/src/db/sql/12-workers.sql +0 -66
  63. package/src/db/sql/13-drive-paths.sql +0 -47
  64. package/src/db/sql/14-drop_hnsw_index.sql +0 -8
  65. package/src/db/sql/15-fts_index.sql +0 -8
  66. package/src/db/sql/16-source_url.sql +0 -7
  67. package/src/db/sql/17-worker_log_path.sql +0 -3
  68. package/src/db/sql/18-reset_embeddings_for_local.sql +0 -39
  69. package/src/db/sql/19-disk_backed_index.sql +0 -36
  70. package/src/db/sql/2-logging_tables.sql +0 -24
  71. package/src/db/sql/20-drop_db_tables_for_files.sql +0 -19
  72. package/src/db/sql/3-daemon_state.sql +0 -5
  73. package/src/db/sql/4-unique_context_path.sql +0 -1
  74. package/src/db/sql/5-reset_embeddings_for_openai.sql +0 -1
  75. package/src/db/sql/6-vss_index.sql +0 -7
  76. package/src/db/sql/7-drop_embeddings_fk.sql +0 -23
  77. package/src/db/sql/8-task_output.sql +0 -1
  78. package/src/db/sql/9-source-type.sql +0 -1
  79. package/src/tools/context/read-large-result.ts +0 -33
  80. package/src/tools/dir/create.ts +0 -47
  81. package/src/tools/dir/size.ts +0 -77
  82. package/src/tools/dir/tree.ts +0 -124
  83. package/src/tools/file/copy.ts +0 -73
  84. package/src/tools/file/count-lines.ts +0 -54
  85. package/src/tools/file/delete.ts +0 -83
  86. package/src/tools/file/edit.ts +0 -76
  87. package/src/tools/file/exists.ts +0 -33
  88. package/src/tools/file/info.ts +0 -66
  89. package/src/tools/file/move.ts +0 -66
  90. package/src/tools/file/read.ts +0 -67
  91. package/src/tools/file/write.ts +0 -58
  92. package/src/tools/search/fuse.ts +0 -96
  93. package/src/tools/search/index.ts +0 -127
  94. package/src/tools/search/regexp.ts +0 -82
  95. package/src/tools/search/semantic.ts +0 -167
  96. /package/src/{db → utils}/uuid.ts +0 -0
@@ -1,167 +0,0 @@
1
- import type { BotholomewConfig } from "../../config/schemas.ts";
2
- import { embed, embedSingle } from "../../context/embedder.ts";
3
- import { listContextDir, readContextFile } from "../../context/store.ts";
4
- import { withDb } from "../../db/connection.ts";
5
- import { indexStats, searchSemantic } from "../../db/embeddings.ts";
6
- import { globToRegex } from "./regexp.ts";
7
-
8
- export interface SemanticHit {
9
- path: string;
10
- chunk_index: number;
11
- chunk_content: string;
12
- score: number;
13
- }
14
-
15
- export interface SemanticOptions {
16
- query: string;
17
- scope?: string;
18
- glob?: string;
19
- limit?: number;
20
- }
21
-
22
- // On-the-fly fallback (used when the index sidecar is empty / stale).
23
- // One chunk per file truncated to MAX_CHARS; the indexed path is much faster
24
- // and supports proper chunking via `botholomew context reindex`.
25
- const MAX_CHARS = 4_000;
26
- const MAX_FILES_TO_EMBED = 200;
27
-
28
- /**
29
- * Semantic search over `context/`. Prefers the persistent index sidecar
30
- * (`context_index` table, populated by `botholomew context reindex`) when
31
- * it has rows. Falls back to embedding files on the fly so a fresh project
32
- * still gets useful results before the user has reindexed once.
33
- */
34
- export async function runSemantic(
35
- projectDir: string,
36
- config: Required<BotholomewConfig>,
37
- dbPath: string | null,
38
- options: SemanticOptions,
39
- ): Promise<SemanticHit[]> {
40
- if (dbPath) {
41
- const indexed = await tryIndexedSearch(dbPath, config, options);
42
- if (indexed) return indexed;
43
- }
44
- return runOnTheFly(projectDir, config, options);
45
- }
46
-
47
- async function tryIndexedSearch(
48
- dbPath: string,
49
- config: Required<BotholomewConfig>,
50
- options: SemanticOptions,
51
- ): Promise<SemanticHit[] | null> {
52
- let stats: Awaited<ReturnType<typeof indexStats>>;
53
- try {
54
- stats = await withDb(dbPath, indexStats);
55
- } catch {
56
- return null;
57
- }
58
- if (stats.embedded === 0) return null;
59
-
60
- const queryVec = await embedSingle(options.query, config);
61
- const limit = options.limit ?? 100;
62
- const rows = await withDb(dbPath, (conn) =>
63
- searchSemantic(conn, queryVec, limit * 4),
64
- );
65
-
66
- const globRegex = options.glob ? globToRegex(options.glob) : null;
67
- const scope = options.scope
68
- ? options.scope.endsWith("/")
69
- ? options.scope
70
- : `${options.scope}/`
71
- : null;
72
-
73
- const filtered: SemanticHit[] = [];
74
- for (const r of rows) {
75
- if (scope && !r.path.startsWith(scope) && r.path !== options.scope) {
76
- continue;
77
- }
78
- if (globRegex) {
79
- const filename = r.path.split("/").pop() ?? "";
80
- if (!globRegex.test(filename)) continue;
81
- }
82
- filtered.push({
83
- path: r.path,
84
- chunk_index: r.chunk_index,
85
- chunk_content: r.chunk_content,
86
- score: r.score,
87
- });
88
- if (filtered.length >= limit) break;
89
- }
90
- return filtered;
91
- }
92
-
93
- async function runOnTheFly(
94
- projectDir: string,
95
- config: Required<BotholomewConfig>,
96
- options: SemanticOptions,
97
- ): Promise<SemanticHit[]> {
98
- const entries = await listContextDir(projectDir, options.scope ?? "", {
99
- recursive: true,
100
- });
101
- const globRegex = options.glob ? globToRegex(options.glob) : null;
102
-
103
- const candidates: Array<{ path: string; content: string }> = [];
104
- for (const entry of entries) {
105
- if (entry.is_directory) continue;
106
- if (!entry.is_textual) continue;
107
- if (globRegex) {
108
- const filename = entry.path.split("/").pop() ?? "";
109
- if (!globRegex.test(filename)) continue;
110
- }
111
- let content: string;
112
- try {
113
- content = await readContextFile(projectDir, entry.path);
114
- } catch {
115
- continue;
116
- }
117
- if (content.trim().length === 0) continue;
118
- candidates.push({
119
- path: entry.path,
120
- content: content.slice(0, MAX_CHARS),
121
- });
122
- if (candidates.length >= MAX_FILES_TO_EMBED) break;
123
- }
124
-
125
- if (candidates.length === 0) return [];
126
-
127
- const [queryVec, fileVecs] = await Promise.all([
128
- embedSingle(options.query, config),
129
- embed(
130
- candidates.map((c) => c.content),
131
- config,
132
- ),
133
- ]);
134
-
135
- const limit = options.limit ?? 100;
136
- const scored: SemanticHit[] = [];
137
- for (let i = 0; i < candidates.length; i++) {
138
- const c = candidates[i];
139
- const v = fileVecs[i];
140
- if (!c || !v) continue;
141
- const score = cosine(queryVec, v);
142
- scored.push({
143
- path: c.path,
144
- chunk_index: 0,
145
- chunk_content: c.content,
146
- score,
147
- });
148
- }
149
- scored.sort((a, b) => b.score - a.score);
150
- return scored.slice(0, limit);
151
- }
152
-
153
- function cosine(a: number[], b: number[]): number {
154
- let dot = 0;
155
- let na = 0;
156
- let nb = 0;
157
- const len = Math.min(a.length, b.length);
158
- for (let i = 0; i < len; i++) {
159
- const ai = a[i] ?? 0;
160
- const bi = b[i] ?? 0;
161
- dot += ai * bi;
162
- na += ai * ai;
163
- nb += bi * bi;
164
- }
165
- const denom = Math.sqrt(na) * Math.sqrt(nb);
166
- return denom === 0 ? 0 : dot / denom;
167
- }
File without changes