@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.
- package/LICENSE +44 -0
- package/README.md +304 -0
- package/dist/bridge-command.d.ts +23 -0
- package/dist/bridge-command.js +103 -0
- package/dist/cc-frontmatter.d.ts +21 -0
- package/dist/cc-frontmatter.js +51 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +20 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +150 -0
- package/dist/commands/ingest.d.ts +2 -0
- package/dist/commands/ingest.js +101 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +130 -0
- package/dist/commands/recall.d.ts +2 -0
- package/dist/commands/recall.js +41 -0
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.js +122 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.js +72 -0
- package/dist/memory-path.d.ts +16 -0
- package/dist/memory-path.js +214 -0
- package/dist/schemas/cc-hook-input.d.ts +129 -0
- package/dist/schemas/cc-hook-input.js +30 -0
- package/dist/schemas/cc-settings.d.ts +24 -0
- package/dist/schemas/cc-settings.js +35 -0
- package/dist/stdin.d.ts +7 -0
- package/dist/stdin.js +24 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Elastic License 2.0 (ELv2)
|
|
2
|
+
|
|
3
|
+
Acceptance
|
|
4
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
5
|
+
|
|
6
|
+
Copyright License
|
|
7
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below.
|
|
8
|
+
|
|
9
|
+
Limitations
|
|
10
|
+
You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software.
|
|
11
|
+
|
|
12
|
+
You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key.
|
|
13
|
+
|
|
14
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
15
|
+
|
|
16
|
+
Patents
|
|
17
|
+
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
18
|
+
|
|
19
|
+
Notices
|
|
20
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
|
|
21
|
+
|
|
22
|
+
If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software.
|
|
23
|
+
|
|
24
|
+
No Other Rights
|
|
25
|
+
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
26
|
+
|
|
27
|
+
Termination
|
|
28
|
+
If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently.
|
|
29
|
+
|
|
30
|
+
No Liability
|
|
31
|
+
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
32
|
+
|
|
33
|
+
Definitions
|
|
34
|
+
The _licensor_ is the entity offering these terms, and the _software_ is the software the licensor makes available under these terms, including any portion of it.
|
|
35
|
+
|
|
36
|
+
_you_ refers to the individual or entity agreeing to these terms.
|
|
37
|
+
|
|
38
|
+
_your company_ is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. _control_ means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
39
|
+
|
|
40
|
+
_your licenses_ are all the licenses granted to you for the software under these terms.
|
|
41
|
+
|
|
42
|
+
_use_ means anything you do with the software requiring one of your licenses.
|
|
43
|
+
|
|
44
|
+
_trademark_ means trademarks, service marks, and similar rights.
|
package/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# @byterover/claude-bridge
|
|
2
|
+
|
|
3
|
+
Native bridge between [ByteRover](https://www.byterover.dev) and [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Enriches Claude's auto-memory with ByteRover's full multi-tier retrieval — BM25 search, importance scoring, performance correlation, and LLM synthesis — giving Claude persistent, cross-referenced context that improves over time.
|
|
4
|
+
|
|
5
|
+
## Table of contents
|
|
6
|
+
|
|
7
|
+
- [What it does](#what-it-does)
|
|
8
|
+
- [Prerequisites](#prerequisites)
|
|
9
|
+
- [Quick start](#quick-start)
|
|
10
|
+
- [Commands](#commands)
|
|
11
|
+
- [How it works](#how-it-works)
|
|
12
|
+
- [Development](#development)
|
|
13
|
+
- [Project structure](#project-structure)
|
|
14
|
+
- [License](#license)
|
|
15
|
+
|
|
16
|
+
## What it does
|
|
17
|
+
|
|
18
|
+
Claude Code has a built-in auto-memory system — it saves observations across sessions as flat markdown files. ByteRover has a richer context tree with multi-tier retrieval: BM25 text search, importance/recency scoring, maturity tier boosting, performance-memory correlation, and LLM-powered synthesis. This bridge connects the two:
|
|
19
|
+
|
|
20
|
+
1. **Ingesting memories** — when Claude's extraction agent writes a memory file, a hook fires and sends the content to `brv curate`, which enriches it with tags, keywords, scoring metadata, and stores it in the context tree
|
|
21
|
+
2. **Syncing context** — after each turn, a hook queries ByteRover for ranked knowledge and writes a cross-reference file that Claude's recall system can pick up
|
|
22
|
+
3. **Zero workflow change** — you use `claude` exactly as before. The bridge runs in the background via Claude Code's hook system
|
|
23
|
+
|
|
24
|
+
The result: Claude's memories are indexed, scored, and searchable alongside the rest of your project knowledge in ByteRover.
|
|
25
|
+
|
|
26
|
+
## Prerequisites
|
|
27
|
+
|
|
28
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed
|
|
29
|
+
- Node.js 20+
|
|
30
|
+
- [brv CLI](https://docs.byterover.dev/quickstart) installed and available on your `PATH`
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
### 1. Install the bridge
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @byterover/claude-bridge
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Install hooks
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
brv-claude-plugin install
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This adds four hooks to `~/.claude/settings.json`:
|
|
47
|
+
|
|
48
|
+
- **PostToolUse(Write)** — triggers `brv-claude-plugin ingest` when Claude writes a memory file
|
|
49
|
+
- **PostToolUse(Edit)** — triggers `brv-claude-plugin ingest` when Claude edits a memory file
|
|
50
|
+
- **Stop** — triggers `brv-claude-plugin sync` after each turn to refresh cross-references
|
|
51
|
+
- **UserPromptSubmit** — triggers `brv-claude-plugin recall` to query ByteRover with the user's prompt and inject relevant context before the model call
|
|
52
|
+
|
|
53
|
+
Your existing settings and hooks are preserved. A backup is saved to `settings.json.brv-backup`.
|
|
54
|
+
|
|
55
|
+
### 3. Verify
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
brv-claude-plugin doctor
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You should see all checks passing:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
brv-claude-plugin doctor
|
|
65
|
+
|
|
66
|
+
✓ brv CLI — byterover-cli/2.5.0
|
|
67
|
+
✓ Context tree — /path/to/project/.brv/context-tree
|
|
68
|
+
✓ Claude settings — ~/.claude/settings.json
|
|
69
|
+
✓ Bridge hooks — PostToolUse + Stop + UserPromptSubmit hooks found
|
|
70
|
+
✓ Bridge executable — /usr/local/bin/brv-claude-plugin
|
|
71
|
+
✓ Memory directory — ~/.claude/projects/-path-to-project/memory/
|
|
72
|
+
|
|
73
|
+
All checks passed.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 4. Use Claude normally
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
claude "fix the auth bug"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Memories are ingested into `.brv/context-tree/_cc/` automatically. No changes to your workflow.
|
|
83
|
+
|
|
84
|
+
### 5. Uninstall (if needed)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
brv-claude-plugin uninstall
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Removes only bridge hooks. Your other hooks and settings are untouched.
|
|
91
|
+
|
|
92
|
+
## Commands
|
|
93
|
+
|
|
94
|
+
### `brv-claude-plugin install`
|
|
95
|
+
|
|
96
|
+
Installs hooks into Claude Code's `~/.claude/settings.json`.
|
|
97
|
+
|
|
98
|
+
| Option | Description |
|
|
99
|
+
| ------------------- | ------------------------------------------ |
|
|
100
|
+
| `--dry-run` | Show what would be written without saving |
|
|
101
|
+
| `--settings-path` | Override path to Claude Code settings.json |
|
|
102
|
+
|
|
103
|
+
Idempotent — safe to run multiple times. Deduplicates by checking for the `#brv-claude-plugin` marker in existing hooks.
|
|
104
|
+
|
|
105
|
+
### `brv-claude-plugin uninstall`
|
|
106
|
+
|
|
107
|
+
Removes bridge hooks from settings. Per-hook removal — if a matcher entry contains both a bridge hook and your own hook, only the bridge hook is deleted.
|
|
108
|
+
|
|
109
|
+
| Option | Description |
|
|
110
|
+
| ------------------- | ------------------------------------------ |
|
|
111
|
+
| `--settings-path` | Override path to Claude Code settings.json |
|
|
112
|
+
|
|
113
|
+
### `brv-claude-plugin ingest`
|
|
114
|
+
|
|
115
|
+
Called by the PostToolUse hook. Reads hook JSON from stdin, parses the memory file, and sends it to `brv curate --detach`.
|
|
116
|
+
|
|
117
|
+
- **Write tool**: reads content from `tool_input.content`
|
|
118
|
+
- **Edit tool**: reads the file from disk (Edit only carries `old_string`/`new_string`)
|
|
119
|
+
- Skips non-memory files, `MEMORY.md`, and `_brv_context.md`
|
|
120
|
+
- Always exits 0 — never blocks Claude
|
|
121
|
+
|
|
122
|
+
| Option | Description |
|
|
123
|
+
| --------- | ------------------------ |
|
|
124
|
+
| `--json` | Output result as JSON |
|
|
125
|
+
|
|
126
|
+
### `brv-claude-plugin sync`
|
|
127
|
+
|
|
128
|
+
Called by the Stop hook. Copies the context tree index from `.brv/context-tree/_index.md` into `_brv_context.md` in Claude's memory directory with a single pointer in `MEMORY.md`.
|
|
129
|
+
|
|
130
|
+
- On success: writes context tree index with a guide note pointing to the full tree
|
|
131
|
+
- If `_index.md` unavailable but `_brv_context.md` exists: preserves existing content
|
|
132
|
+
- If `_index.md` unavailable and no existing file: writes a stub with "(sync pending)"
|
|
133
|
+
- Runs async in the background — never blocks Claude
|
|
134
|
+
|
|
135
|
+
| Option | Description |
|
|
136
|
+
| ---------------- | ---------------------------------------- |
|
|
137
|
+
| `--json` | Output result as JSON |
|
|
138
|
+
| `--memory-dir` | Override path to Claude memory directory |
|
|
139
|
+
|
|
140
|
+
### `brv-claude-plugin recall`
|
|
141
|
+
|
|
142
|
+
Called by the UserPromptSubmit hook. Reads the user's prompt from stdin, queries ByteRover with it, and returns targeted context as `additionalContext` that Claude sees before generating a response.
|
|
143
|
+
|
|
144
|
+
- Runs **synchronously** — delays the model call until ByteRover responds (6s internal timeout, 8s hook timeout)
|
|
145
|
+
- Skips trivially short prompts (< 5 chars)
|
|
146
|
+
- If ByteRover query fails or times out, exits silently — prompt proceeds without context
|
|
147
|
+
- Wraps results in `<byterover-context>` tags
|
|
148
|
+
|
|
149
|
+
### `brv-claude-plugin doctor`
|
|
150
|
+
|
|
151
|
+
Runs 6 diagnostic checks: brv CLI, context tree, settings file, installed hooks, bridge executable, and memory directory resolution.
|
|
152
|
+
|
|
153
|
+
## How it works
|
|
154
|
+
|
|
155
|
+
The bridge uses Claude Code's [hook system](https://docs.anthropic.com/en/docs/claude-code/hooks) to intercept memory operations without modifying Claude Code's source.
|
|
156
|
+
|
|
157
|
+
### Recall flow (UserPromptSubmit hook)
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
User types: "fix the combo scoring bug"
|
|
161
|
+
│
|
|
162
|
+
▼ UserPromptSubmit hook fires (before model call)
|
|
163
|
+
brv-claude-plugin recall
|
|
164
|
+
│ brv query "fix the combo scoring bug" → targeted results
|
|
165
|
+
▼
|
|
166
|
+
Claude sees <byterover-context> as system reminder
|
|
167
|
+
(live, relevant to this specific prompt)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Ingest flow (PostToolUse hook)
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
Claude writes ~/.claude/projects/.../memory/feedback_testing.md
|
|
174
|
+
│
|
|
175
|
+
▼ PostToolUse hook fires, pipes JSON to stdin
|
|
176
|
+
brv-claude-plugin ingest
|
|
177
|
+
│ Parse cc-ts frontmatter (name, description, type)
|
|
178
|
+
│ Map type → domain (_cc/user, _cc/feedback, _cc/project, _cc/reference)
|
|
179
|
+
▼
|
|
180
|
+
brv curate --detach --format json -- "context string"
|
|
181
|
+
│ Daemon queues curation (async, non-blocking)
|
|
182
|
+
▼
|
|
183
|
+
.brv/context-tree/_cc/feedback/testing.md
|
|
184
|
+
(enriched with tags, keywords, importance scoring)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Sync flow (Stop hook)
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
Turn ends
|
|
191
|
+
│
|
|
192
|
+
▼ Stop hook fires
|
|
193
|
+
brv-claude-plugin sync
|
|
194
|
+
│ read .brv/context-tree/_index.md → copy to memory dir
|
|
195
|
+
▼
|
|
196
|
+
~/.claude/projects/.../memory/_brv_context.md
|
|
197
|
+
(context tree index + guide to full tree)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Memory path resolution
|
|
201
|
+
|
|
202
|
+
The bridge resolves Claude's memory directory using the same logic as Claude Code:
|
|
203
|
+
|
|
204
|
+
1. `CLAUDE_COWORK_MEMORY_PATH_OVERRIDE` env var (full override)
|
|
205
|
+
2. `autoMemoryDirectory` from settings (local → user, excluding project settings for security)
|
|
206
|
+
3. `~/.claude/projects/<sanitized-canonical-git-root>/memory/`
|
|
207
|
+
|
|
208
|
+
Git worktrees are resolved to their canonical root so all worktrees share one memory directory.
|
|
209
|
+
|
|
210
|
+
### Multi-project support
|
|
211
|
+
|
|
212
|
+
The bridge naturally supports multiple projects. Claude Code scopes memory per git repository, and ByteRover scopes its context tree per `.brv/` directory. Both use the same `cwd` from the hook input as their anchor:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
/Users/x/project-a/ ← claude session here
|
|
216
|
+
├── .git/ ← Claude memory: ~/.claude/projects/-Users-x-project-a/memory/
|
|
217
|
+
├── .brv/ ← ByteRover tree: project-a/.brv/context-tree/
|
|
218
|
+
└── src/
|
|
219
|
+
|
|
220
|
+
/Users/x/project-b/ ← separate claude session here
|
|
221
|
+
├── .git/ ← Claude memory: ~/.claude/projects/-Users-x-project-b/memory/
|
|
222
|
+
├── .brv/ ← ByteRover tree: project-b/.brv/context-tree/
|
|
223
|
+
└── src/
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Each project's memories are ingested into its own context tree and synced back to its own memory directory. No cross-project leakage.
|
|
227
|
+
|
|
228
|
+
**Important: initialize `.brv/` at the git root.** Claude Code resolves memory directories from the canonical git root. ByteRover walks up from `cwd` to find `.brv/`. When both are at the same level, everything maps correctly.
|
|
229
|
+
|
|
230
|
+
If you initialize `.brv/` in a subdirectory instead of the git root, the bridge will encounter mismatches:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
/monorepo/ ← git root (Claude memory lives here)
|
|
234
|
+
├── .git/
|
|
235
|
+
├── frontend/
|
|
236
|
+
│ └── .brv/ ← brv initialized here, not at git root
|
|
237
|
+
└── backend/ ← sessions from here won't find .brv/
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
In this layout, Claude sessions from `/monorepo/backend/` would fail to reach the `.brv/` in `frontend/`. To fix this, initialize ByteRover at the git root:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
cd /monorepo
|
|
244
|
+
brv init # .brv/ at git root — matches Claude's project boundary
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
If you need separate context trees for subdirectories in a monorepo, initialize `.brv/` in each subdirectory and run `claude` from within that subdirectory (not from the monorepo root).
|
|
248
|
+
|
|
249
|
+
### Hook identification
|
|
250
|
+
|
|
251
|
+
Every stored hook command includes a `#brv-claude-plugin` shell comment marker. This marker — not the path text — is used by `install` (dedupe), `uninstall` (removal), and `doctor` (detection). A clone in any directory will work correctly.
|
|
252
|
+
|
|
253
|
+
## Development
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Install dependencies
|
|
257
|
+
npm install
|
|
258
|
+
|
|
259
|
+
# Type check
|
|
260
|
+
npm run typecheck
|
|
261
|
+
|
|
262
|
+
# Build
|
|
263
|
+
npm run build
|
|
264
|
+
|
|
265
|
+
# Run in dev mode
|
|
266
|
+
npm run dev -- doctor
|
|
267
|
+
|
|
268
|
+
# Run built CLI
|
|
269
|
+
node dist/cli.js doctor
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Testing locally
|
|
273
|
+
|
|
274
|
+
1. Initialize a brv project: `cd /your/project && brv init`
|
|
275
|
+
2. Build the bridge: `npm run build`
|
|
276
|
+
3. Install hooks (dev mode): `node dist/cli.js install`
|
|
277
|
+
4. Start a Claude session and make a few changes
|
|
278
|
+
5. Check `.brv/context-tree/_cc/` for ingested memories
|
|
279
|
+
6. Check `~/.claude/projects/.../memory/_brv_context.md` for synced context
|
|
280
|
+
|
|
281
|
+
## Project structure
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
src/
|
|
285
|
+
cli.ts # Commander.js entry point
|
|
286
|
+
cc-frontmatter.ts # Claude Code memory YAML frontmatter parser
|
|
287
|
+
memory-path.ts # Full cc-ts memory path resolution (git root, worktrees, env vars)
|
|
288
|
+
stdin.ts # Read + validate JSON from stdin
|
|
289
|
+
bridge-command.ts # Executable resolution + #brv-claude-plugin marker
|
|
290
|
+
schemas/
|
|
291
|
+
cc-hook-input.ts # Zod schemas for PostToolUse and Stop hook input
|
|
292
|
+
cc-settings.ts # Raw JSON read/write for settings.json (lossless)
|
|
293
|
+
commands/
|
|
294
|
+
install.ts # Install hooks into settings.json (per-hook dedupe, backup)
|
|
295
|
+
uninstall.ts # Remove bridge hooks (per-hook removal)
|
|
296
|
+
ingest.ts # PostToolUse handler — Write/Edit split, brv curate
|
|
297
|
+
sync.ts # Stop handler — _index.md copy, _brv_context.md, MEMORY.md pointer
|
|
298
|
+
recall.ts # UserPromptSubmit handler — live brv query with user prompt
|
|
299
|
+
doctor.ts # 6 diagnostic checks
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
[Elastic License 2.0 (ELv2)](./LICENSE)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const BRIDGE_HOOK_MARKER = "#brv-claude-plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the executable prefix for hook commands.
|
|
4
|
+
* Returns ONLY the executable part — callers append subcommand via buildHookCommand().
|
|
5
|
+
*
|
|
6
|
+
* Production: "/usr/local/bin/brv-claude-plugin"
|
|
7
|
+
* Dev: "node /abs/path/to/dist/cli.js"
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveBridgeExecutable(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Build the full hook command string for a subcommand.
|
|
12
|
+
* Appends the marker as a trailing shell comment so isBridgeHook() works
|
|
13
|
+
* regardless of install path or directory name.
|
|
14
|
+
*
|
|
15
|
+
* "/usr/local/bin/brv-claude-plugin ingest #brv-claude-plugin"
|
|
16
|
+
* "node /tmp/bridge/dist/cli.js sync #brv-claude-plugin"
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildHookCommand(subcommand: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a hook object was installed by this bridge.
|
|
21
|
+
* Matches on BRIDGE_HOOK_MARKER, not path text.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isBridgeHook(hook: Record<string, unknown>): boolean;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Marker — explicit shell comment suffix for hook identification.
|
|
6
|
+
// Not derived from path text. Injected deliberately into every stored command.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
export const BRIDGE_HOOK_MARKER = "#brv-claude-plugin";
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Executable resolution
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the executable prefix for hook commands.
|
|
14
|
+
* Returns ONLY the executable part — callers append subcommand via buildHookCommand().
|
|
15
|
+
*
|
|
16
|
+
* Production: "/usr/local/bin/brv-claude-plugin"
|
|
17
|
+
* Dev: "node /abs/path/to/dist/cli.js"
|
|
18
|
+
*/
|
|
19
|
+
export function resolveBridgeExecutable() {
|
|
20
|
+
const pkgRoot = findPackageRoot();
|
|
21
|
+
// Try production bin first
|
|
22
|
+
const pkgJson = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf-8"));
|
|
23
|
+
const bin = pkgJson.bin;
|
|
24
|
+
const binEntry = typeof bin === "string"
|
|
25
|
+
? bin
|
|
26
|
+
: typeof bin === "object" && bin !== null
|
|
27
|
+
? bin["brv-claude-plugin"]
|
|
28
|
+
: undefined;
|
|
29
|
+
if (binEntry) {
|
|
30
|
+
const resolved = resolve(pkgRoot, binEntry);
|
|
31
|
+
if (existsSync(resolved)) {
|
|
32
|
+
assertNoSpaces(resolved);
|
|
33
|
+
// Only return the bare path if it's actually executable (e.g. npm
|
|
34
|
+
// global install creates a proper shim with +x). tsc output and
|
|
35
|
+
// local dev builds are 0644, so we must prefix with node.
|
|
36
|
+
if (isExecutable(resolved)) {
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
return `node ${resolved}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Dev fallback: dist/cli.js (never executable — always prefix with node)
|
|
43
|
+
const distCli = join(pkgRoot, "dist", "cli.js");
|
|
44
|
+
if (existsSync(distCli)) {
|
|
45
|
+
assertNoSpaces(distCli);
|
|
46
|
+
return `node ${distCli}`;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Cannot resolve bridge executable. Run 'pnpm build' first, ` +
|
|
49
|
+
`or install the package globally.`);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the full hook command string for a subcommand.
|
|
53
|
+
* Appends the marker as a trailing shell comment so isBridgeHook() works
|
|
54
|
+
* regardless of install path or directory name.
|
|
55
|
+
*
|
|
56
|
+
* "/usr/local/bin/brv-claude-plugin ingest #brv-claude-plugin"
|
|
57
|
+
* "node /tmp/bridge/dist/cli.js sync #brv-claude-plugin"
|
|
58
|
+
*/
|
|
59
|
+
export function buildHookCommand(subcommand) {
|
|
60
|
+
const exe = resolveBridgeExecutable();
|
|
61
|
+
return `${exe} ${subcommand} ${BRIDGE_HOOK_MARKER}`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a hook object was installed by this bridge.
|
|
65
|
+
* Matches on BRIDGE_HOOK_MARKER, not path text.
|
|
66
|
+
*/
|
|
67
|
+
export function isBridgeHook(hook) {
|
|
68
|
+
return (typeof hook.command === "string" &&
|
|
69
|
+
hook.command.includes(BRIDGE_HOOK_MARKER));
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Helpers
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
function findPackageRoot() {
|
|
75
|
+
// Walk up from this file to find package.json
|
|
76
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
77
|
+
for (let i = 0; i < 10; i++) {
|
|
78
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
79
|
+
return dir;
|
|
80
|
+
}
|
|
81
|
+
const parent = dirname(dir);
|
|
82
|
+
if (parent === dir)
|
|
83
|
+
break;
|
|
84
|
+
dir = parent;
|
|
85
|
+
}
|
|
86
|
+
throw new Error("Cannot find package.json for brv-claude-plugin");
|
|
87
|
+
}
|
|
88
|
+
function isExecutable(filePath) {
|
|
89
|
+
try {
|
|
90
|
+
accessSync(filePath, constants.X_OK);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function assertNoSpaces(resolvedPath) {
|
|
98
|
+
if (/\s/.test(resolvedPath)) {
|
|
99
|
+
throw new Error(`Bridge install path contains spaces: "${resolvedPath}"\n` +
|
|
100
|
+
`Install brv-claude-plugin to a path without spaces, or use a symlink.`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=bridge-command.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
declare const VALID_TYPES: readonly ["user", "feedback", "project", "reference"];
|
|
2
|
+
export type CcMemoryType = (typeof VALID_TYPES)[number];
|
|
3
|
+
export interface CcMemoryFrontmatter {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
type: CcMemoryType;
|
|
7
|
+
}
|
|
8
|
+
export interface CcMemoryFile {
|
|
9
|
+
frontmatter: CcMemoryFrontmatter;
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse a Claude Code memory file into frontmatter + body.
|
|
14
|
+
* Returns null if the file is not a valid cc-ts memory file.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseCcMemoryFile(content: string): CcMemoryFile | null;
|
|
17
|
+
/**
|
|
18
|
+
* Map cc-ts memory type to ByteRover context tree domain path.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ccTypeToDomain(type: CcMemoryType): string;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import yaml from "js-yaml";
|
|
2
|
+
// Match cc-ts/utils/frontmatterParser.ts line 123
|
|
3
|
+
const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)---\s*\n?/;
|
|
4
|
+
const VALID_TYPES = ["user", "feedback", "project", "reference"];
|
|
5
|
+
/**
|
|
6
|
+
* Parse a Claude Code memory file into frontmatter + body.
|
|
7
|
+
* Returns null if the file is not a valid cc-ts memory file.
|
|
8
|
+
*/
|
|
9
|
+
export function parseCcMemoryFile(content) {
|
|
10
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
11
|
+
if (!match)
|
|
12
|
+
return null;
|
|
13
|
+
const raw = match[1] || "";
|
|
14
|
+
const body = content.slice(match[0].length);
|
|
15
|
+
try {
|
|
16
|
+
const fm = yaml.load(raw);
|
|
17
|
+
if (!fm || typeof fm !== "object")
|
|
18
|
+
return null;
|
|
19
|
+
if (typeof fm.name !== "string")
|
|
20
|
+
return null;
|
|
21
|
+
if (typeof fm.type !== "string")
|
|
22
|
+
return null;
|
|
23
|
+
const type = fm.type;
|
|
24
|
+
if (!VALID_TYPES.includes(type))
|
|
25
|
+
return null;
|
|
26
|
+
return {
|
|
27
|
+
frontmatter: {
|
|
28
|
+
name: fm.name,
|
|
29
|
+
description: typeof fm.description === "string" ? fm.description : "",
|
|
30
|
+
type: type,
|
|
31
|
+
},
|
|
32
|
+
body,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Map cc-ts memory type to ByteRover context tree domain path.
|
|
41
|
+
*/
|
|
42
|
+
export function ccTypeToDomain(type) {
|
|
43
|
+
const map = {
|
|
44
|
+
user: "_cc/user",
|
|
45
|
+
feedback: "_cc/feedback",
|
|
46
|
+
project: "_cc/project",
|
|
47
|
+
reference: "_cc/reference",
|
|
48
|
+
};
|
|
49
|
+
return map[type];
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=cc-frontmatter.js.map
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { registerInstallCommand } from "./commands/install.js";
|
|
4
|
+
import { registerUninstallCommand } from "./commands/uninstall.js";
|
|
5
|
+
import { registerIngestCommand } from "./commands/ingest.js";
|
|
6
|
+
import { registerSyncCommand } from "./commands/sync.js";
|
|
7
|
+
import { registerRecallCommand } from "./commands/recall.js";
|
|
8
|
+
import { registerDoctorCommand } from "./commands/doctor.js";
|
|
9
|
+
program
|
|
10
|
+
.name("brv-claude-plugin")
|
|
11
|
+
.description("Native bridge between ByteRover context engine and Claude Code auto-memory")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
registerInstallCommand(program);
|
|
14
|
+
registerUninstallCommand(program);
|
|
15
|
+
registerIngestCommand(program);
|
|
16
|
+
registerSyncCommand(program);
|
|
17
|
+
registerRecallCommand(program);
|
|
18
|
+
registerDoctorCommand(program);
|
|
19
|
+
program.parse();
|
|
20
|
+
//# sourceMappingURL=cli.js.map
|