botholomew 0.18.0 → 0.18.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.
package/README.md CHANGED
@@ -19,7 +19,7 @@ agent's world is a per-project knowledge store managed by
19
19
  search, and delete is addressed by `logical_path` (a DB key, not a
20
20
  filesystem path), so a prompt-injected attempt to reach `~/.ssh/id_rsa`
21
21
  has nowhere to land. Local files and URLs are brought in through
22
- `botholomew context add`. External capabilities (email, Slack, the web,
22
+ `botholomew membot add`. External capabilities (email, Slack, the web,
23
23
  and hundreds of other services) are granted deliberately, per project,
24
24
  through MCP servers wired up via
25
25
  [MCPX](https://github.com/evantahler/mcpx).
@@ -165,11 +165,6 @@ semantic search, append-only versioning, and URL refresh all live there.
165
165
 
166
166
  ![CLI walkthrough: task list, task add, schedule list, context list](docs/assets/cli-tour.gif)
167
167
 
168
- Pulling a remote document straight into the knowledge store via an
169
- LLM-driven fetcher (`mcp_search` → `mcp_exec` → `membot_pipe`):
170
-
171
- ![Importing a Google Doc into context](docs/assets/context-import-gdoc.gif)
172
-
173
168
  | Command | Purpose |
174
169
  |---|---|
175
170
  | `botholomew init` | Initialize the current directory as a project (refuses on iCloud/Dropbox/NFS without `--force`) |
@@ -178,8 +173,8 @@ LLM-driven fetcher (`mcp_search` → `mcp_exec` → `membot_pipe`):
178
173
  | `botholomew chat` | Interactive Ink/React TUI |
179
174
  | `botholomew task list\|add\|view\|update\|reset\|delete` | Manage the task queue (markdown files in `tasks/`) |
180
175
  | `botholomew schedule list\|add\|view\|enable\|disable\|trigger\|delete` | Recurring work (markdown files in `schedules/`) |
181
- | `botholomew context add\|ls\|tree\|read\|write\|search\|info\|versions\|diff\|refresh\|…` | Knowledge-store passthrough to [`membot`](https://github.com/evantahler/membot) — `--config` is set to the project dir automatically |
182
- | `botholomew context import-global` | Seed the project from `~/.membot` (copies `index.duckdb` + `config.json` in) |
176
+ | `botholomew membot add\|ls\|tree\|read\|write\|search\|info\|versions\|diff\|refresh\|…` | Knowledge-store passthrough to [`membot`](https://github.com/evantahler/membot) — `--config` is resolved from `membot_scope` (default `~/.membot`) |
177
+ | `botholomew membot import-global` | Seed the project from `~/.membot` (copies `index.duckdb` + `config.json` in) |
183
178
  | `botholomew capabilities` | Rescan built-in + MCPX tools and rewrite `prompts/capabilities.md` |
184
179
  | `botholomew prompts list\|show\|create\|edit\|delete\|validate` | CRUD over the markdown files in `prompts/` (with strict frontmatter validation) |
185
180
  | `botholomew mcpx servers\|list\|add\|remove\|info\|search\|exec\|ping\|auth\|deauth\|import-global\|…` | Configure external MCP servers (passthrough to `mcpx`) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botholomew",
3
- "version": "0.18.0",
3
+ "version": "0.18.2",
4
4
  "description": "An autonomous AI agent for knowledge work — works your task queue while you sleep.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,31 +27,31 @@
27
27
  "docs:preview": "vitepress preview docs"
28
28
  },
29
29
  "dependencies": {
30
- "@anthropic-ai/sdk": "^0.92.0",
31
- "@evantahler/mcpx": "0.21.6",
32
- "ansis": "^4.2.0",
30
+ "@anthropic-ai/sdk": "^0.95.2",
31
+ "@evantahler/mcpx": "0.21.7",
32
+ "ansis": "^4.3.0",
33
33
  "commander": "^14.0.0",
34
34
  "gray-matter": "^4.0.3",
35
35
  "ink": "^7.0.1",
36
36
  "ink-spinner": "^5.0.0",
37
37
  "ink-text-input": "^6.0.0",
38
38
  "istextorbinary": "^9.5.0",
39
- "membot": "^0.14.0",
39
+ "membot": "^0.15.0",
40
40
  "nanospinner": "^1.2.2",
41
- "react": "^19.2.0",
41
+ "react": "^19.2.6",
42
42
  "uuid": "^14.0.0",
43
43
  "wrap-ansi": "^10.0.0",
44
- "zod": "^4.4.2"
44
+ "zod": "^4.4.3"
45
45
  },
46
46
  "devDependencies": {
47
- "@biomejs/biome": "^2.4.14",
47
+ "@biomejs/biome": "^2.4.15",
48
48
  "@types/bun": "latest",
49
49
  "@types/react": "^19.2.0",
50
50
  "@types/uuid": "^11.0.0",
51
51
  "typescript": "^6.0.3",
52
52
  "vitepress": "^1.5.0",
53
- "vitepress-plugin-llms": "^1.12.1",
54
- "vue": "^3.5.0"
53
+ "vitepress-plugin-llms": "^1.12.2",
54
+ "vue": "^3.5.34"
55
55
  },
56
56
  "trustedDependencies": [
57
57
  "protobufjs"
package/src/cli.ts CHANGED
@@ -5,9 +5,9 @@ import { program } from "commander";
5
5
  import { registerCapabilitiesCommand } from "./commands/capabilities.ts";
6
6
  import { registerChatCommand } from "./commands/chat.ts";
7
7
  import { registerCheckUpdateCommand } from "./commands/check-update.ts";
8
- import { registerContextCommand } from "./commands/context.ts";
9
8
  import { registerInitCommand } from "./commands/init.ts";
10
9
  import { registerMcpxCommand } from "./commands/mcpx.ts";
10
+ import { registerMembotCommand } from "./commands/membot.ts";
11
11
  import { registerNukeCommand } from "./commands/nuke.ts";
12
12
  import { registerPrepareCommand } from "./commands/prepare.ts";
13
13
  import { registerPromptsCommand } from "./commands/prompts.ts";
@@ -29,9 +29,13 @@ program
29
29
  .configureHelp({
30
30
  styleTitle: (str) => ansis.bold(str),
31
31
  styleUsage: (str) => ansis.cyan(str),
32
- styleCommandText: (str) => ansis.green(str),
32
+ styleCommandText: (str) => ansis.cyan.bold(str),
33
+ styleSubcommandTerm: (str) => ansis.green(str),
34
+ styleSubcommandDescription: (str) => ansis.dim(str),
33
35
  styleOptionTerm: (str) => ansis.yellow(str),
34
- styleDescriptionText: (str) => ansis.dim(str),
36
+ styleOptionDescription: (str) => ansis.dim(str),
37
+ styleArgumentTerm: (str) => ansis.magenta(str),
38
+ styleArgumentDescription: (str) => ansis.dim(str),
35
39
  });
36
40
 
37
41
  registerInitCommand(program);
@@ -40,7 +44,7 @@ registerTaskCommand(program);
40
44
  registerThreadCommand(program);
41
45
  registerScheduleCommand(program);
42
46
  registerChatCommand(program);
43
- registerContextCommand(program);
47
+ registerMembotCommand(program);
44
48
  registerCapabilitiesCommand(program);
45
49
  registerPromptsCommand(program);
46
50
  registerMcpxCommand(program);
@@ -29,11 +29,11 @@ function getDir(program: Command): string {
29
29
  }
30
30
 
31
31
  /**
32
- * Slice process.argv from the token after "context" so flags (including
32
+ * Slice process.argv from the token after "membot" so flags (including
33
33
  * --help) and positional args flow through to upstream membot verbatim.
34
34
  */
35
- function getRawContextArgs(): string[] {
36
- const idx = process.argv.indexOf("context");
35
+ function getRawMembotArgs(): string[] {
36
+ const idx = process.argv.indexOf("membot");
37
37
  return idx === -1 ? [] : process.argv.slice(idx + 1);
38
38
  }
39
39
 
@@ -121,37 +121,37 @@ function registerImportGlobal(parent: Command, program: Command): void {
121
121
  });
122
122
  }
123
123
 
124
- export function registerContextCommand(program: Command) {
125
- const context = program
126
- .command("context")
124
+ export function registerMembotCommand(program: Command) {
125
+ const membot = program
126
+ .command("membot")
127
127
  .description(
128
- "Manage the project's knowledge store via membot (add, search, ls, read, …)",
128
+ "Manage the project's knowledge store (passthrough to membot: add, search, ls, read, …)",
129
129
  );
130
130
 
131
131
  // Botholomew-specific helpers first so they show up before the membot
132
132
  // passthrough subcommands in --help.
133
- registerImportGlobal(context, program);
133
+ registerImportGlobal(membot, program);
134
134
 
135
135
  // One Commander subcommand per membot Operation. We don't redeclare any
136
136
  // flags — Commander hands the raw argv slice to membot, which owns the
137
137
  // canonical schema.
138
138
  for (const op of OPERATIONS) {
139
139
  const name = defaultCliName(op);
140
- context
140
+ membot
141
141
  .command(name)
142
142
  .description(op.description.split("\n")[0] ?? op.description)
143
143
  .allowUnknownOption(true)
144
144
  .helpOption(false)
145
145
  .argument("[args...]", "arguments forwarded to membot")
146
146
  .action(async () => {
147
- const exitCode = await runMembot(getDir(program), getRawContextArgs());
147
+ const exitCode = await runMembot(getDir(program), getRawMembotArgs());
148
148
  if (exitCode !== 0) process.exit(exitCode);
149
149
  });
150
150
  }
151
151
 
152
- // `botholomew context` (no subcommand) → membot's default action.
153
- context.action(async () => {
154
- const exitCode = await runMembot(getDir(program), getRawContextArgs());
152
+ // `botholomew membot` (no subcommand) → membot's default action.
153
+ membot.action(async () => {
154
+ const exitCode = await runMembot(getDir(program), getRawMembotArgs());
155
155
  if (exitCode !== 0) process.exit(exitCode);
156
156
  });
157
157
  }
@@ -103,7 +103,7 @@ export function adaptOperation(
103
103
  error_type: "internal_error",
104
104
  message: err instanceof Error ? err.message : String(err),
105
105
  next_action_hint:
106
- "Check the project's membot store (run `botholomew context stats`) and try again. If this persists, file a bug.",
106
+ "Check the project's membot store (run `botholomew membot stats`) and try again. If this persists, file a bug.",
107
107
  };
108
108
  }
109
109
  },
@@ -1,7 +1,8 @@
1
1
  import { Box, Text, useInput } from "ink";
2
2
  import type { MembotClient } from "membot";
3
3
  import { memo, useCallback, useEffect, useMemo, useState } from "react";
4
- import { openMembot } from "../../mem/client.ts";
4
+ import { loadConfig } from "../../config/loader.ts";
5
+ import { openMembot, resolveMembotDir } from "../../mem/client.ts";
5
6
  import {
6
7
  detailPaneBorderProps,
7
8
  type FocusState,
@@ -36,8 +37,8 @@ const PAGE_SCROLL_LINES = 10;
36
37
  * Browse the membot knowledge store. Each row is a current-version entry; the
37
38
  * detail pane shows the cleaned markdown surrogate. Membot has no real
38
39
  * directories — `logical_path` segments are just slashes — so this is a flat
39
- * paginated list rather than a tree drill-in. Use `botholomew context tree` /
40
- * `botholomew context search` for hierarchical or content-based discovery.
40
+ * paginated list rather than a tree drill-in. Use `botholomew membot tree` /
41
+ * `botholomew membot search` for hierarchical or content-based discovery.
41
42
  */
42
43
  export const ContextPanel = memo(function ContextPanel({
43
44
  projectDir,
@@ -47,13 +48,22 @@ export const ContextPanel = memo(function ContextPanel({
47
48
  const detailWidth = Math.max(1, termCols - SIDEBAR_WIDTH - 5);
48
49
 
49
50
  // One MembotClient per panel mount. Membot manages its DB lock per-op so
50
- // sharing the file with the chat session / workers is safe.
51
+ // sharing the file with the chat session / workers is safe. The data dir is
52
+ // resolved from `membot_scope` (global → ~/.membot, project → <projectDir>)
53
+ // so the tab agrees with the worker / chat session / CLI.
51
54
  const [client, setClient] = useState<MembotClient | null>(null);
52
55
  useEffect(() => {
53
- const c = openMembot(projectDir);
54
- setClient(c);
56
+ let cancelled = false;
57
+ let opened: MembotClient | null = null;
58
+ (async () => {
59
+ const config = await loadConfig(projectDir);
60
+ if (cancelled) return;
61
+ opened = openMembot(resolveMembotDir(projectDir, config));
62
+ setClient(opened);
63
+ })();
55
64
  return () => {
56
- void c.close();
65
+ cancelled = true;
66
+ if (opened) void opened.close();
57
67
  };
58
68
  }, [projectDir]);
59
69
 
@@ -227,7 +237,7 @@ export const ContextPanel = memo(function ContextPanel({
227
237
  </Box>
228
238
  {entries.length === 0 ? (
229
239
  <Box paddingX={1}>
230
- <Text dimColor>(empty — try `botholomew context add …`)</Text>
240
+ <Text dimColor>(empty — try `botholomew membot add …`)</Text>
231
241
  </Box>
232
242
  ) : (
233
243
  visibleItems.map((entry, vi) => {