@byterover/claude-plugin 1.0.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.
@@ -0,0 +1,150 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import pc from "picocolors";
5
+ import { isBridgeHook, resolveBridgeExecutable } from "../bridge-command.js";
6
+ import { getCcMemoryDir, getClaudeConfigHome } from "../memory-path.js";
7
+ import { readSettingsRaw } from "../schemas/cc-settings.js";
8
+ export function registerDoctorCommand(program) {
9
+ program
10
+ .command("doctor")
11
+ .description("Check that the bridge is correctly configured")
12
+ .action(async () => {
13
+ const cwd = process.cwd();
14
+ const results = [];
15
+ // 1. brv CLI found
16
+ try {
17
+ const version = execSync("brv --version", {
18
+ encoding: "utf-8",
19
+ timeout: 5_000,
20
+ }).trim();
21
+ results.push({ label: "brv CLI", pass: true, detail: version });
22
+ }
23
+ catch {
24
+ results.push({
25
+ label: "brv CLI",
26
+ pass: false,
27
+ detail: "not found in PATH",
28
+ });
29
+ }
30
+ // 2. .brv/context-tree/ exists
31
+ const ctPath = join(cwd, ".brv", "context-tree");
32
+ results.push({
33
+ label: "Context tree",
34
+ pass: existsSync(ctPath),
35
+ detail: existsSync(ctPath) ? ctPath : `${ctPath} not found`,
36
+ });
37
+ // 3. Settings file exists and is valid JSON
38
+ const settingsPath = join(getClaudeConfigHome(), "settings.json");
39
+ let settingsValid = false;
40
+ try {
41
+ readSettingsRaw(settingsPath);
42
+ settingsValid = existsSync(settingsPath);
43
+ }
44
+ catch {
45
+ settingsValid = false;
46
+ }
47
+ results.push({
48
+ label: "Claude settings",
49
+ pass: settingsValid,
50
+ detail: settingsValid ? settingsPath : `${settingsPath} missing or invalid`,
51
+ });
52
+ // 4. Bridge hooks installed
53
+ if (settingsValid) {
54
+ const settings = readSettingsRaw(settingsPath);
55
+ const hooks = settings.hooks;
56
+ const hasPostToolUse = findBridgeHookInEvent(hooks, "PostToolUse");
57
+ const hasStop = findBridgeHookInEvent(hooks, "Stop");
58
+ const hasUserPrompt = findBridgeHookInEvent(hooks, "UserPromptSubmit");
59
+ const installed = hasPostToolUse && hasStop && hasUserPrompt;
60
+ results.push({
61
+ label: "Bridge hooks",
62
+ pass: installed,
63
+ detail: installed
64
+ ? "PostToolUse + Stop + UserPromptSubmit hooks found"
65
+ : `missing: ${[
66
+ !hasPostToolUse && "PostToolUse",
67
+ !hasStop && "Stop",
68
+ !hasUserPrompt && "UserPromptSubmit",
69
+ ]
70
+ .filter(Boolean)
71
+ .join(", ")}`,
72
+ });
73
+ }
74
+ else {
75
+ results.push({
76
+ label: "Bridge hooks",
77
+ pass: false,
78
+ detail: "cannot check — settings invalid",
79
+ });
80
+ }
81
+ // 5. Bridge executable resolves
82
+ try {
83
+ const exe = resolveBridgeExecutable();
84
+ results.push({
85
+ label: "Bridge executable",
86
+ pass: true,
87
+ detail: exe,
88
+ });
89
+ }
90
+ catch (err) {
91
+ results.push({
92
+ label: "Bridge executable",
93
+ pass: false,
94
+ detail: err instanceof Error ? err.message : String(err),
95
+ });
96
+ }
97
+ // 6. cc memory dir resolves
98
+ try {
99
+ const memDir = getCcMemoryDir(cwd);
100
+ const memExists = existsSync(memDir);
101
+ results.push({
102
+ label: "Memory directory",
103
+ pass: memExists,
104
+ detail: memExists
105
+ ? memDir
106
+ : `${memDir} (resolved but does not exist yet — will be created on first Claude session)`,
107
+ });
108
+ }
109
+ catch (err) {
110
+ results.push({
111
+ label: "Memory directory",
112
+ pass: false,
113
+ detail: err instanceof Error ? err.message : String(err),
114
+ });
115
+ }
116
+ // Print results
117
+ console.log(pc.bold("\nbrv-claude-plugin doctor\n"));
118
+ let allPass = true;
119
+ for (const r of results) {
120
+ const icon = r.pass ? pc.green("\u2713") : pc.red("\u2717");
121
+ const detail = r.detail ? pc.dim(` — ${r.detail}`) : "";
122
+ console.log(` ${icon} ${r.label}${detail}`);
123
+ if (!r.pass)
124
+ allPass = false;
125
+ }
126
+ console.log();
127
+ if (allPass) {
128
+ console.log(pc.green("All checks passed."));
129
+ }
130
+ else {
131
+ console.log(pc.yellow("Some checks failed. Run 'brv-claude-plugin install' to set up."));
132
+ }
133
+ });
134
+ }
135
+ function findBridgeHookInEvent(hooks, event) {
136
+ if (!hooks)
137
+ return false;
138
+ const eventHooks = hooks[event];
139
+ if (!Array.isArray(eventHooks))
140
+ return false;
141
+ return eventHooks.some((entry) => {
142
+ const innerHooks = entry.hooks;
143
+ if (!Array.isArray(innerHooks))
144
+ return false;
145
+ return innerHooks.some((h) => typeof h === "object" &&
146
+ h !== null &&
147
+ isBridgeHook(h));
148
+ });
149
+ }
150
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerIngestCommand(program: Command): void;
@@ -0,0 +1,101 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import { BrvBridge } from "@byterover/brv-bridge";
4
+ import { parseCcMemoryFile } from "../cc-frontmatter.js";
5
+ import { getCcMemoryDir, isCcMemoryPath } from "../memory-path.js";
6
+ import { PostToolUseHookInputSchema } from "../schemas/cc-hook-input.js";
7
+ import { readStdinJson } from "../stdin.js";
8
+ // Files in the memory dir that we should never ingest
9
+ const SKIP_FILES = new Set(["MEMORY.md", "_brv_context.md"]);
10
+ export function registerIngestCommand(program) {
11
+ program
12
+ .command("ingest")
13
+ .description("Ingest a Claude Code memory file into ByteRover context tree (called by PostToolUse hook)")
14
+ .option("--json", "Output result as JSON")
15
+ .action(async (opts) => {
16
+ try {
17
+ const input = await readStdinJson(PostToolUseHookInputSchema);
18
+ const toolInput = input.tool_input;
19
+ const filePath = toolInput.file_path;
20
+ const toolName = input.tool_name;
21
+ const cwd = input.cwd;
22
+ if (!filePath || typeof filePath !== "string") {
23
+ exit(opts, { ingested: false, reason: "no file_path in tool_input" });
24
+ return;
25
+ }
26
+ // Guard: only process files in cc memory directory
27
+ const memoryDir = getCcMemoryDir(cwd);
28
+ if (!isCcMemoryPath(filePath, memoryDir)) {
29
+ exit(opts, { ingested: false, reason: "not a memory path" });
30
+ return;
31
+ }
32
+ // Guard: skip index and our own file
33
+ const fileName = basename(filePath);
34
+ if (SKIP_FILES.has(fileName)) {
35
+ exit(opts, { ingested: false, reason: `skipped ${fileName}` });
36
+ return;
37
+ }
38
+ // Get file content based on tool type
39
+ let content;
40
+ if (toolName === "Write") {
41
+ // Write tool: content is in tool_input
42
+ const rawContent = toolInput.content;
43
+ if (typeof rawContent !== "string") {
44
+ exit(opts, { ingested: false, reason: "no content in Write input" });
45
+ return;
46
+ }
47
+ content = rawContent;
48
+ }
49
+ else if (toolName === "Edit") {
50
+ // Edit tool: only has old_string/new_string — read from disk
51
+ try {
52
+ content = readFileSync(filePath, "utf-8");
53
+ }
54
+ catch {
55
+ exit(opts, {
56
+ ingested: false,
57
+ reason: `cannot read file after Edit: ${filePath}`,
58
+ });
59
+ return;
60
+ }
61
+ }
62
+ else {
63
+ exit(opts, { ingested: false, reason: `unexpected tool: ${toolName}` });
64
+ return;
65
+ }
66
+ // Parse cc-ts frontmatter
67
+ const parsed = parseCcMemoryFile(content);
68
+ if (!parsed) {
69
+ exit(opts, {
70
+ ingested: false,
71
+ reason: "invalid cc-ts memory frontmatter",
72
+ });
73
+ return;
74
+ }
75
+ const { frontmatter, body } = parsed;
76
+ // Pass content to brv curate without path constraints.
77
+ // Let ByteRover's agent decide the best domain/topic structure.
78
+ const curateContext = body.trim();
79
+ // Fire-and-forget curate
80
+ const bridge = new BrvBridge({ cwd, persistTimeoutMs: 15_000 });
81
+ await bridge.persist(curateContext);
82
+ exit(opts, {
83
+ ingested: true,
84
+ name: frontmatter.name,
85
+ type: frontmatter.type,
86
+ });
87
+ }
88
+ catch (err) {
89
+ // All errors → stderr + exit 0. Never exit 2 (would block Claude).
90
+ process.stderr.write(`brv-claude-plugin ingest error: ${err instanceof Error ? err.message : String(err)}\n`);
91
+ process.exit(0);
92
+ }
93
+ });
94
+ }
95
+ function exit(opts, result) {
96
+ if (opts.json) {
97
+ console.log(JSON.stringify(result));
98
+ }
99
+ process.exit(0);
100
+ }
101
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerInstallCommand(program: Command): void;
@@ -0,0 +1,130 @@
1
+ import { join } from "node:path";
2
+ import pc from "picocolors";
3
+ import { buildHookCommand, isBridgeHook, resolveBridgeExecutable, } from "../bridge-command.js";
4
+ import { getClaudeConfigHome } from "../memory-path.js";
5
+ import { backupSettings, readSettingsRaw, writeSettingsRaw, } from "../schemas/cc-settings.js";
6
+ // The hook entries we want to install
7
+ function buildDesiredHooks() {
8
+ return [
9
+ {
10
+ event: "PostToolUse",
11
+ entry: {
12
+ matcher: "Write",
13
+ hooks: [
14
+ {
15
+ type: "command",
16
+ command: buildHookCommand("ingest"),
17
+ async: true,
18
+ timeout: 15,
19
+ },
20
+ ],
21
+ },
22
+ },
23
+ {
24
+ event: "PostToolUse",
25
+ entry: {
26
+ matcher: "Edit",
27
+ hooks: [
28
+ {
29
+ type: "command",
30
+ command: buildHookCommand("ingest"),
31
+ async: true,
32
+ timeout: 15,
33
+ },
34
+ ],
35
+ },
36
+ },
37
+ {
38
+ event: "Stop",
39
+ entry: {
40
+ hooks: [
41
+ {
42
+ type: "command",
43
+ command: buildHookCommand("sync"),
44
+ async: true,
45
+ timeout: 10,
46
+ },
47
+ ],
48
+ },
49
+ },
50
+ {
51
+ event: "UserPromptSubmit",
52
+ entry: {
53
+ hooks: [
54
+ {
55
+ type: "command",
56
+ command: buildHookCommand("recall"),
57
+ timeout: 8,
58
+ },
59
+ ],
60
+ },
61
+ },
62
+ ];
63
+ }
64
+ export function registerInstallCommand(program) {
65
+ program
66
+ .command("install")
67
+ .description("Install Claude Code hooks that bridge auto-memory to ByteRover context tree")
68
+ .option("--dry-run", "Show what would be written without modifying files")
69
+ .option("--settings-path <path>", "Override path to Claude Code settings.json")
70
+ .action(async (opts) => {
71
+ try {
72
+ // Validate executable resolves before touching settings
73
+ const exe = resolveBridgeExecutable();
74
+ console.log(pc.dim(`Resolved executable: ${exe}`));
75
+ const settingsPath = opts.settingsPath ??
76
+ join(getClaudeConfigHome(), "settings.json");
77
+ const settings = readSettingsRaw(settingsPath);
78
+ // Ensure hooks object exists
79
+ if (!settings.hooks || typeof settings.hooks !== "object") {
80
+ settings.hooks = {};
81
+ }
82
+ const hooks = settings.hooks;
83
+ const desired = buildDesiredHooks();
84
+ let added = 0;
85
+ for (const { event, entry } of desired) {
86
+ if (!Array.isArray(hooks[event])) {
87
+ hooks[event] = [];
88
+ }
89
+ const eventHooks = hooks[event];
90
+ // Per-hook dedupe: check if any existing matcher entry with the
91
+ // same matcher value already contains a bridge hook
92
+ const matcherValue = "matcher" in entry ? entry.matcher : undefined;
93
+ const alreadyInstalled = eventHooks.some((existing) => {
94
+ const existingMatcher = existing.matcher;
95
+ if (existingMatcher !== matcherValue)
96
+ return false;
97
+ const innerHooks = existing.hooks;
98
+ if (!Array.isArray(innerHooks))
99
+ return false;
100
+ return innerHooks.some((h) => typeof h === "object" &&
101
+ h !== null &&
102
+ isBridgeHook(h));
103
+ });
104
+ if (!alreadyInstalled) {
105
+ eventHooks.push(entry);
106
+ added++;
107
+ }
108
+ }
109
+ if (added === 0) {
110
+ console.log(pc.yellow("Bridge hooks already installed. No changes made."));
111
+ return;
112
+ }
113
+ if (opts.dryRun) {
114
+ console.log(pc.cyan("Dry run — would write:"));
115
+ console.log(JSON.stringify(settings, null, 2));
116
+ return;
117
+ }
118
+ const backupPath = backupSettings(settingsPath);
119
+ console.log(pc.dim(`Backup: ${backupPath}`));
120
+ writeSettingsRaw(settingsPath, settings);
121
+ console.log(pc.green(`Installed ${added} hook(s) into ${settingsPath}`));
122
+ console.log(pc.dim("Hooks: PostToolUse(Write), PostToolUse(Edit), Stop"));
123
+ }
124
+ catch (err) {
125
+ console.error(pc.red(`Install failed: ${err instanceof Error ? err.message : String(err)}`));
126
+ process.exit(1);
127
+ }
128
+ });
129
+ }
130
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerRecallCommand(program: Command): void;
@@ -0,0 +1,41 @@
1
+ import { BrvBridge } from "@byterover/brv-bridge";
2
+ import { UserPromptSubmitHookInputSchema } from "../schemas/cc-hook-input.js";
3
+ import { readStdinJson } from "../stdin.js";
4
+ export function registerRecallCommand(program) {
5
+ program
6
+ .command("recall")
7
+ .description("Query ByteRover for context relevant to the user prompt (called by UserPromptSubmit hook)")
8
+ .action(async () => {
9
+ try {
10
+ const input = await readStdinJson(UserPromptSubmitHookInputSchema);
11
+ const { prompt, cwd } = input;
12
+ // Skip trivially short prompts
13
+ if (prompt.trim().length < 5) {
14
+ process.exit(0);
15
+ }
16
+ // Query ByteRover with the actual user prompt
17
+ const bridge = new BrvBridge({ cwd, recallTimeoutMs: 6_000 });
18
+ const { content } = await bridge.recall(prompt);
19
+ if (!content) {
20
+ process.exit(0);
21
+ }
22
+ // Return additionalContext wrapped in hookSpecificOutput for Claude Code
23
+ const output = {
24
+ hookSpecificOutput: {
25
+ hookEventName: "UserPromptSubmit",
26
+ additionalContext: `<byterover-context>\n` +
27
+ `The following knowledge is from ByteRover context engine:\n\n` +
28
+ `${content}\n` +
29
+ `</byterover-context>`,
30
+ },
31
+ };
32
+ console.log(JSON.stringify(output));
33
+ process.exit(0);
34
+ }
35
+ catch {
36
+ // All errors → silent exit 0. Never block the prompt.
37
+ process.exit(0);
38
+ }
39
+ });
40
+ }
41
+ //# sourceMappingURL=recall.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerSyncCommand(program: Command): void;
@@ -0,0 +1,122 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getCcMemoryDir } from "../memory-path.js";
4
+ import { StopHookInputSchema } from "../schemas/cc-hook-input.js";
5
+ import { readStdinJson } from "../stdin.js";
6
+ const BRV_CONTEXT_FILE = "_brv_context.md";
7
+ const CONTEXT_TREE_INDEX = ".brv/context-tree/_index.md";
8
+ const MEMORY_INDEX = "MEMORY.md";
9
+ const POINTER_LINE = "- [ByteRover context](_brv_context.md) \u2014 cross-references from project knowledge base";
10
+ function buildContextTreeGuide(cwd) {
11
+ const treePath = join(cwd, ".brv/context-tree");
12
+ return [
13
+ "<Note>",
14
+ `The full ByteRover context tree is located at \`${treePath}/\`.`,
15
+ "All paths referenced below are relative to this directory.",
16
+ "When you need deeper context on any topic, read the relevant files there.",
17
+ "Each domain contains topics with detailed narratives, facts, and code references that go beyond this summary.",
18
+ "</Note>",
19
+ ].join("\n");
20
+ }
21
+ /**
22
+ * Strip YAML frontmatter (--- ... ---) from the beginning of a markdown string.
23
+ * Returns the body content after the closing --- delimiter.
24
+ */
25
+ function stripFrontmatter(content) {
26
+ const match = content.match(/^---\n[\s\S]*?\n---\n?/);
27
+ if (match) {
28
+ return content.slice(match[0].length);
29
+ }
30
+ return content;
31
+ }
32
+ export function registerSyncCommand(program) {
33
+ program
34
+ .command("sync")
35
+ .description("Regenerate _brv_context.md with cross-references from ByteRover context tree (called by Stop hook)")
36
+ .option("--json", "Output result as JSON")
37
+ .option("--memory-dir <path>", "Override path to Claude Code memory directory")
38
+ .action(async (opts) => {
39
+ try {
40
+ const input = await readStdinJson(StopHookInputSchema);
41
+ const cwd = input.cwd;
42
+ const memoryDir = opts.memoryDir ?? getCcMemoryDir(cwd);
43
+ // Read the context tree root _index.md directly from disk
44
+ const indexPath = join(cwd, CONTEXT_TREE_INDEX);
45
+ let indexBody;
46
+ if (existsSync(indexPath)) {
47
+ try {
48
+ const raw = readFileSync(indexPath, "utf-8");
49
+ const body = stripFrontmatter(raw).trim();
50
+ if (body) {
51
+ indexBody = body;
52
+ }
53
+ }
54
+ catch {
55
+ // Read failed — fall through to stub
56
+ }
57
+ }
58
+ // Ensure memory dir exists
59
+ mkdirSync(memoryDir, { recursive: true });
60
+ const now = new Date().toISOString();
61
+ const contextPath = join(memoryDir, BRV_CONTEXT_FILE);
62
+ if (indexBody) {
63
+ // Success: write guide first, then context tree index body
64
+ const content = [
65
+ "---",
66
+ "name: byterover context",
67
+ "description: cross-references from ByteRover knowledge base",
68
+ "type: reference",
69
+ "---",
70
+ `Last synced: ${now}`,
71
+ "",
72
+ buildContextTreeGuide(cwd),
73
+ "",
74
+ indexBody,
75
+ "",
76
+ ].join("\n");
77
+ writeFileSync(contextPath, content, "utf-8");
78
+ }
79
+ else if (!existsSync(contextPath)) {
80
+ // No context tree and no existing file — write stub for first run
81
+ const content = [
82
+ "---",
83
+ "name: byterover context",
84
+ "description: cross-references from ByteRover knowledge base (sync pending)",
85
+ "type: reference",
86
+ "---",
87
+ `Last sync attempt: ${now}`,
88
+ "Status: no context tree index available \u2014 .brv/context-tree/_index.md not found or empty.",
89
+ "",
90
+ ].join("\n");
91
+ writeFileSync(contextPath, content, "utf-8");
92
+ }
93
+ // Otherwise: _index.md unavailable but _brv_context.md exists — keep existing content
94
+ // Add pointer to MEMORY.md if not already present (idempotent)
95
+ const memoryPath = join(memoryDir, MEMORY_INDEX);
96
+ let memoryContent = "";
97
+ if (existsSync(memoryPath)) {
98
+ memoryContent = readFileSync(memoryPath, "utf-8");
99
+ }
100
+ if (!memoryContent.includes(BRV_CONTEXT_FILE)) {
101
+ const separator = memoryContent.endsWith("\n") || !memoryContent
102
+ ? ""
103
+ : "\n";
104
+ writeFileSync(memoryPath, memoryContent + separator + POINTER_LINE + "\n", "utf-8");
105
+ }
106
+ if (opts.json) {
107
+ console.log(JSON.stringify({
108
+ synced: true,
109
+ hasContent: !!indexBody,
110
+ contextPath,
111
+ }));
112
+ }
113
+ process.exit(0);
114
+ }
115
+ catch (err) {
116
+ // Best-effort — never block Claude
117
+ process.stderr.write(`brv-claude-plugin sync error: ${err instanceof Error ? err.message : String(err)}\n`);
118
+ process.exit(0);
119
+ }
120
+ });
121
+ }
122
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerUninstallCommand(program: Command): void;
@@ -0,0 +1,72 @@
1
+ import { join } from "node:path";
2
+ import pc from "picocolors";
3
+ import { isBridgeHook } from "../bridge-command.js";
4
+ import { getClaudeConfigHome } from "../memory-path.js";
5
+ import { backupSettings, readSettingsRaw, writeSettingsRaw, } from "../schemas/cc-settings.js";
6
+ export function registerUninstallCommand(program) {
7
+ program
8
+ .command("uninstall")
9
+ .description("Remove Claude Code hooks installed by the bridge")
10
+ .option("--settings-path <path>", "Override path to Claude Code settings.json")
11
+ .action(async (opts) => {
12
+ try {
13
+ const settingsPath = opts.settingsPath ??
14
+ join(getClaudeConfigHome(), "settings.json");
15
+ const settings = readSettingsRaw(settingsPath);
16
+ const hooks = settings.hooks;
17
+ if (!hooks || typeof hooks !== "object") {
18
+ console.log(pc.yellow("No hooks found in settings. Nothing to remove."));
19
+ return;
20
+ }
21
+ let removed = 0;
22
+ for (const event of Object.keys(hooks)) {
23
+ const eventHooks = hooks[event];
24
+ if (!Array.isArray(eventHooks))
25
+ continue;
26
+ // Per-hook removal: within each matcher entry, remove only bridge hooks
27
+ for (let i = eventHooks.length - 1; i >= 0; i--) {
28
+ const matcherEntry = eventHooks[i];
29
+ const innerHooks = matcherEntry.hooks;
30
+ if (!Array.isArray(innerHooks))
31
+ continue;
32
+ const filtered = innerHooks.filter((h) => {
33
+ if (typeof h === "object" &&
34
+ h !== null &&
35
+ isBridgeHook(h)) {
36
+ removed++;
37
+ return false;
38
+ }
39
+ return true;
40
+ });
41
+ if (filtered.length === 0) {
42
+ // All hooks in this matcher entry were bridge hooks — remove the entry
43
+ eventHooks.splice(i, 1);
44
+ }
45
+ else {
46
+ matcherEntry.hooks = filtered;
47
+ }
48
+ }
49
+ // Clean up empty event arrays
50
+ if (eventHooks.length === 0) {
51
+ delete hooks[event];
52
+ }
53
+ }
54
+ // Clean up empty hooks object
55
+ if (Object.keys(hooks).length === 0) {
56
+ delete settings.hooks;
57
+ }
58
+ if (removed === 0) {
59
+ console.log(pc.yellow("No bridge hooks found. Nothing to remove."));
60
+ return;
61
+ }
62
+ backupSettings(settingsPath);
63
+ writeSettingsRaw(settingsPath, settings);
64
+ console.log(pc.green(`Removed ${removed} bridge hook(s) from ${settingsPath}`));
65
+ }
66
+ catch (err) {
67
+ console.error(pc.red(`Uninstall failed: ${err instanceof Error ? err.message : String(err)}`));
68
+ process.exit(1);
69
+ }
70
+ });
71
+ }
72
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1,16 @@
1
+ export declare function sanitizePath(name: string): string;
2
+ export declare function getClaudeConfigHome(): string;
3
+ export declare function findCanonicalGitRoot(startPath: string): string | null;
4
+ /**
5
+ * Resolve the Claude Code auto-memory directory for a given project cwd.
6
+ * Matches cc-ts resolution priority:
7
+ * 1. CLAUDE_COWORK_MEMORY_PATH_OVERRIDE env var
8
+ * 2. autoMemoryDirectory from settings (local → user)
9
+ * 3. <memoryBase>/projects/<sanitized-git-root>/memory/
10
+ */
11
+ export declare function getCcMemoryDir(cwd: string): string;
12
+ /**
13
+ * Check if a file path is inside a cc-ts memory directory.
14
+ * Takes pre-resolved memoryDir for efficiency and clarity.
15
+ */
16
+ export declare function isCcMemoryPath(filePath: string, memoryDir: string): boolean;