opencode-repos 0.1.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/.sisyphus/boulder.json +8 -0
- package/.sisyphus/notepads/opencode-repos/decisions.md +15 -0
- package/.sisyphus/notepads/opencode-repos/learnings.md +384 -0
- package/.sisyphus/plans/opencode-repos.md +987 -0
- package/.tmux-sessionizer +8 -0
- package/CLAUDE.md +111 -0
- package/README.md +395 -0
- package/bun.lock +119 -0
- package/index.ts +806 -0
- package/package.json +32 -0
- package/src/__tests__/git.test.ts +141 -0
- package/src/__tests__/manifest.test.ts +249 -0
- package/src/__tests__/setup.test.ts +5 -0
- package/src/agents/repo-explorer.ts +52 -0
- package/src/git.ts +90 -0
- package/src/manifest.ts +116 -0
- package/src/scanner.ts +126 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,987 @@
|
|
|
1
|
+
# OpenCode Repos Plugin
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
### Original Request
|
|
6
|
+
Create an OpenCode plugin to manage repository references for AI agents. Currently, the user manually clones repos for reference, sometimes reuses them, and the workflow is inefficient. The plugin should cache GitHub repos and auto-discover local repos already on the filesystem.
|
|
7
|
+
|
|
8
|
+
**Core Use Case**: Agent working in Project A (e.g., backend) needs to understand Project B (e.g., firmware/frontend) to integrate properly. The plugin provides infrastructure to quickly access and explore cross-project codebases, enabling agents to understand underlying code and write proper integration code.
|
|
9
|
+
|
|
10
|
+
### Interview Summary
|
|
11
|
+
**Key Discussions**:
|
|
12
|
+
- Storage: Global cache at `~/.cache/opencode-repos/` with manifest
|
|
13
|
+
- Config: `~/.config/opencode/opencode-repos.json` for search paths
|
|
14
|
+
- Repo format: Short name `vercel/next.js`, with branch support `vercel/next.js@canary`
|
|
15
|
+
- Auth: SSH for private repos (leverage existing keys)
|
|
16
|
+
- Clone strategy: Shallow by default (depth=1), separate dirs per branch
|
|
17
|
+
- Discovery: Smart clone checks cache -> local index -> clone fresh
|
|
18
|
+
- Local scan: Uses `fd` to find repos in configured search paths
|
|
19
|
+
|
|
20
|
+
**Research Findings**:
|
|
21
|
+
- tmux plugin pattern: ~480 lines single file, stateless, Zod schemas
|
|
22
|
+
- rate-limit plugin: multi-file, event hooks, config loading
|
|
23
|
+
- npm name `opencode-repos` is available
|
|
24
|
+
- Plugin receives `$` (Bun shell) for command execution
|
|
25
|
+
- **CRITICAL**: oh-my-opencode plugin shows plugins CAN define custom agents via `config` handler
|
|
26
|
+
- Agents are registered by modifying `config.agent` in the config handler
|
|
27
|
+
- `AgentConfig` from `@opencode-ai/sdk` defines agent structure
|
|
28
|
+
|
|
29
|
+
### Metis Review
|
|
30
|
+
**Identified Gaps** (addressed):
|
|
31
|
+
- SSH auth in plugin context: Added validation task before implementation
|
|
32
|
+
- Concurrency: Added file locking for manifest writes
|
|
33
|
+
- Error recovery: Added cleanup for partial clones
|
|
34
|
+
- Git edge cases: Disable hooks, no submodules, shallow only
|
|
35
|
+
- Config validation: Handle missing/invalid gracefully
|
|
36
|
+
- Phased approach: MVP first (clone, list, read), then scan/update
|
|
37
|
+
|
|
38
|
+
### OpenCode Plugin API Discovery (from oh-my-opencode analysis)
|
|
39
|
+
**Custom Agent Registration Pattern**:
|
|
40
|
+
```typescript
|
|
41
|
+
// Plugins can define custom agents via config handler
|
|
42
|
+
const plugin: Plugin = async (ctx) => {
|
|
43
|
+
return {
|
|
44
|
+
config: async (config) => {
|
|
45
|
+
config.agent = {
|
|
46
|
+
...config.agent,
|
|
47
|
+
"repo-explorer": {
|
|
48
|
+
description: "Specialized agent for exploring external codebases",
|
|
49
|
+
mode: "subagent",
|
|
50
|
+
model: "anthropic/claude-sonnet-4-5",
|
|
51
|
+
temperature: 0.1,
|
|
52
|
+
permission: { edit: "deny", write: "deny", task: "deny" },
|
|
53
|
+
prompt: "You are a codebase exploration specialist..."
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
tool: { /* tools */ }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**AgentConfig Interface** (from @opencode-ai/sdk):
|
|
63
|
+
- `description`: What the agent does
|
|
64
|
+
- `mode`: "primary" | "subagent"
|
|
65
|
+
- `model?`: Model to use
|
|
66
|
+
- `temperature?`: Sampling temperature
|
|
67
|
+
- `permission?`: Tool permissions (allow/deny/ask per tool)
|
|
68
|
+
- `prompt`: System prompt for the agent
|
|
69
|
+
- `tools?`: Tool whitelist
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Work Objectives
|
|
74
|
+
|
|
75
|
+
### Core Objective
|
|
76
|
+
Build an OpenCode plugin that provides agents with efficient cross-codebase intelligence through:
|
|
77
|
+
1. **Tools** for repo management (clone, list, read, scan, update, remove)
|
|
78
|
+
2. **Custom `repo-explorer` agent** purpose-built for exploring external codebases
|
|
79
|
+
3. **`repo_explore` tool** that spawns the explorer agent in a repo's context
|
|
80
|
+
|
|
81
|
+
The goal is enabling agents to deeply understand other projects (firmware, dependencies, related services) to write proper integration code.
|
|
82
|
+
|
|
83
|
+
### Concrete Deliverables
|
|
84
|
+
- `~/personal/projects/opencode-repos/index.ts` - Main plugin file with tools + config handler
|
|
85
|
+
- `~/personal/projects/opencode-repos/package.json` - Package manifest
|
|
86
|
+
- `~/personal/projects/opencode-repos/tsconfig.json` - TypeScript config
|
|
87
|
+
- `~/personal/projects/opencode-repos/README.md` - Documentation
|
|
88
|
+
- `~/personal/projects/opencode-repos/src/manifest.ts` - Manifest types and operations
|
|
89
|
+
- `~/personal/projects/opencode-repos/src/git.ts` - Git operations
|
|
90
|
+
- `~/personal/projects/opencode-repos/src/scanner.ts` - Local repo scanner
|
|
91
|
+
- `~/personal/projects/opencode-repos/src/agents/repo-explorer.ts` - Explorer agent definition
|
|
92
|
+
- `~/personal/projects/opencode-repos/src/__tests__/manifest.test.ts` - Manifest tests
|
|
93
|
+
- `~/personal/projects/opencode-repos/src/__tests__/git.test.ts` - Git operation tests
|
|
94
|
+
|
|
95
|
+
### Definition of Done
|
|
96
|
+
- [x] `bun test` passes with all tests green
|
|
97
|
+
- [x] Plugin loads in OpenCode without errors
|
|
98
|
+
- [x] Can clone public repo via `repo_clone("vercel/next.js")`
|
|
99
|
+
- [x] Can clone private repo via SSH
|
|
100
|
+
- [x] Can list cached repos via `repo_list`
|
|
101
|
+
- [x] Can read files via `repo_read`
|
|
102
|
+
- [x] Can scan local repos via `repo_scan`
|
|
103
|
+
- [x] `repo-explorer` agent appears in agent list
|
|
104
|
+
- [x] Can explore a repo via `repo_explore("vercel/next.js", "How does routing work?")`
|
|
105
|
+
- [x] Reference in opencode.jsonc works: `file:///Users/liamvinberg/personal/projects/opencode-repos/index.ts`
|
|
106
|
+
|
|
107
|
+
### Must Have
|
|
108
|
+
- Smart clone (check cache -> local -> clone fresh)
|
|
109
|
+
- Shallow clones only (depth=1)
|
|
110
|
+
- SSH auth support for private repos
|
|
111
|
+
- Manifest persistence with atomic writes
|
|
112
|
+
- File locking for concurrent access
|
|
113
|
+
- Branch support with separate directories
|
|
114
|
+
- Local repo discovery via fd
|
|
115
|
+
- Configurable search paths
|
|
116
|
+
- Metadata tracking (clone date, last accessed, size, etc.)
|
|
117
|
+
- **Custom `repo-explorer` agent** for cross-codebase exploration
|
|
118
|
+
- **`repo_explore` tool** that spawns explorer in repo context
|
|
119
|
+
- **Config handler** to register the agent
|
|
120
|
+
|
|
121
|
+
### Must NOT Have (Guardrails)
|
|
122
|
+
- No GitHub/GitLab API integration (pure git only)
|
|
123
|
+
- No auto-clone on `repo_read` (explicit clone required)
|
|
124
|
+
- No submodule support (v1 limitation)
|
|
125
|
+
- No LFS support (document as limitation)
|
|
126
|
+
- No commit/push/branch creation (read-only)
|
|
127
|
+
- No search within repos (use existing grep/glob tools)
|
|
128
|
+
- No multiple remotes per repo
|
|
129
|
+
- No auto-update on access
|
|
130
|
+
- No depth override (shallow only)
|
|
131
|
+
- No diff/blame features (use git directly)
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Verification Strategy (MANDATORY)
|
|
136
|
+
|
|
137
|
+
### Test Decision
|
|
138
|
+
- **Infrastructure exists**: NO (new project)
|
|
139
|
+
- **User wants tests**: Basic tests with bun test
|
|
140
|
+
- **Framework**: bun test (built-in)
|
|
141
|
+
|
|
142
|
+
### Test Setup
|
|
143
|
+
```bash
|
|
144
|
+
bun init # Creates package.json with test support
|
|
145
|
+
bun test # Built-in test runner
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Test Structure
|
|
149
|
+
Each TODO includes test requirements. Tests focus on:
|
|
150
|
+
1. Manifest operations (parse, write, lock)
|
|
151
|
+
2. Git operations (clone, update)
|
|
152
|
+
3. Scanner operations (find repos, match remotes)
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Task Flow
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
0. Setup project
|
|
160
|
+
|
|
|
161
|
+
1. Manifest types/ops --> 2. Git operations (parallel)
|
|
162
|
+
| |
|
|
163
|
+
v v
|
|
164
|
+
3. Tool: repo_clone (depends on 1, 2)
|
|
165
|
+
|
|
|
166
|
+
4. Tool: repo_list --> 5. Tool: repo_read (parallel)
|
|
167
|
+
|
|
|
168
|
+
6. Scanner module
|
|
169
|
+
|
|
|
170
|
+
7. Tool: repo_scan
|
|
171
|
+
|
|
|
172
|
+
8. Tools: repo_update, repo_remove (parallel)
|
|
173
|
+
|
|
|
174
|
+
9. Agent: repo-explorer definition
|
|
175
|
+
|
|
|
176
|
+
10. Tool: repo_explore + Config handler
|
|
177
|
+
|
|
|
178
|
+
11. Documentation
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Parallelization
|
|
182
|
+
|
|
183
|
+
| Group | Tasks | Reason |
|
|
184
|
+
|-------|-------|--------|
|
|
185
|
+
| A | 1, 2 | Independent modules |
|
|
186
|
+
| B | 4, 5 | Independent tools after repo_clone |
|
|
187
|
+
| C | 8a, 8b | Independent tools after scan |
|
|
188
|
+
|
|
189
|
+
| Task | Depends On | Reason |
|
|
190
|
+
|------|------------|--------|
|
|
191
|
+
| 3 | 1, 2 | Uses manifest and git modules |
|
|
192
|
+
| 4-5 | 3 | Need clone working first |
|
|
193
|
+
| 7 | 6 | Scanner tool needs scanner module |
|
|
194
|
+
| 8 | 7 | Update/remove build on full foundation |
|
|
195
|
+
| 9 | 5 | Agent needs repo_read to work |
|
|
196
|
+
| 10 | 9 | Tool needs agent definition |
|
|
197
|
+
| 11 | 10 | Docs after all features complete |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## TODOs
|
|
202
|
+
|
|
203
|
+
- [x] 0. Setup project structure
|
|
204
|
+
|
|
205
|
+
**What to do**:
|
|
206
|
+
- Create directory `~/personal/projects/opencode-repos/`
|
|
207
|
+
- Initialize with `bun init`
|
|
208
|
+
- Create `tsconfig.json` matching tmux plugin pattern
|
|
209
|
+
- Add `@opencode-ai/plugin` as peer and dev dependency
|
|
210
|
+
- Create `src/` directory for modules
|
|
211
|
+
- Create `src/__tests__/` directory for tests
|
|
212
|
+
|
|
213
|
+
**Must NOT do**:
|
|
214
|
+
- Don't add unnecessary dependencies
|
|
215
|
+
- Don't deviate from tmux plugin structure
|
|
216
|
+
|
|
217
|
+
**Parallelizable**: NO (foundation for all other tasks)
|
|
218
|
+
|
|
219
|
+
**References**:
|
|
220
|
+
|
|
221
|
+
**Pattern References**:
|
|
222
|
+
- `~/personal/projects/opencode-tmux/package.json:1-28` - Package structure pattern
|
|
223
|
+
- `~/personal/projects/opencode-tmux/tsconfig.json` - TypeScript config pattern
|
|
224
|
+
|
|
225
|
+
**Acceptance Criteria**:
|
|
226
|
+
- [x] Directory exists at `~/personal/projects/opencode-repos/`
|
|
227
|
+
- [x] `package.json` has name `opencode-repos`, type `module`
|
|
228
|
+
- [x] `@opencode-ai/plugin` in peerDependencies and devDependencies
|
|
229
|
+
- [x] `tsconfig.json` targets ES2022
|
|
230
|
+
- [x] `bun test` runs (even with no tests yet)
|
|
231
|
+
|
|
232
|
+
**Commit**: YES
|
|
233
|
+
- Message: `chore: initial project setup`
|
|
234
|
+
- Files: `package.json`, `tsconfig.json`
|
|
235
|
+
- Pre-commit: `bun test`
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
- [x] 1. Implement manifest types and operations
|
|
240
|
+
|
|
241
|
+
**What to do**:
|
|
242
|
+
- Define TypeScript interfaces for manifest structure
|
|
243
|
+
- Implement manifest read/write with atomic operations
|
|
244
|
+
- Implement file locking using lockfile
|
|
245
|
+
- Handle missing/corrupted manifest gracefully
|
|
246
|
+
- Write tests for manifest operations
|
|
247
|
+
|
|
248
|
+
**Must NOT do**:
|
|
249
|
+
- Don't use complex database (simple JSON)
|
|
250
|
+
- Don't skip file locking
|
|
251
|
+
|
|
252
|
+
**Parallelizable**: YES (with task 2)
|
|
253
|
+
|
|
254
|
+
**References**:
|
|
255
|
+
|
|
256
|
+
**Pattern References**:
|
|
257
|
+
- `~/personal/projects/opencode-rate-limit-fallback/src/config.ts` - Config loading pattern with fallbacks
|
|
258
|
+
|
|
259
|
+
**Type Definitions**:
|
|
260
|
+
```typescript
|
|
261
|
+
interface RepoEntry {
|
|
262
|
+
type: 'cached' | 'local'
|
|
263
|
+
path: string
|
|
264
|
+
clonedAt?: string // ISO timestamp
|
|
265
|
+
lastAccessed: string // ISO timestamp
|
|
266
|
+
lastUpdated?: string // ISO timestamp
|
|
267
|
+
sizeBytes?: number
|
|
268
|
+
defaultBranch: string
|
|
269
|
+
shallow: boolean
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
interface Manifest {
|
|
273
|
+
version: 1
|
|
274
|
+
repos: Record<string, RepoEntry> // key: "owner/repo@branch"
|
|
275
|
+
localIndex: Record<string, string> // remote URL -> local path
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
interface Config {
|
|
279
|
+
localSearchPaths: string[]
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**External References**:
|
|
284
|
+
- https://www.npmjs.com/package/proper-lockfile - File locking pattern (reference only, implement manually with Bun)
|
|
285
|
+
|
|
286
|
+
**Acceptance Criteria**:
|
|
287
|
+
- [x] `src/manifest.ts` exports: `loadManifest`, `saveManifest`, `withManifestLock`
|
|
288
|
+
- [x] Creates manifest if not exists with empty repos
|
|
289
|
+
- [x] Atomic writes (write to .tmp, rename)
|
|
290
|
+
- [x] File locking prevents concurrent writes
|
|
291
|
+
- [x] `bun test src/__tests__/manifest.test.ts` passes
|
|
292
|
+
|
|
293
|
+
**Commit**: YES
|
|
294
|
+
- Message: `feat: implement manifest operations with locking`
|
|
295
|
+
- Files: `src/manifest.ts`, `src/__tests__/manifest.test.ts`
|
|
296
|
+
- Pre-commit: `bun test`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
- [x] 2. Implement git operations module
|
|
301
|
+
|
|
302
|
+
**What to do**:
|
|
303
|
+
- Implement `cloneRepo(url, destPath, options)` with shallow clone
|
|
304
|
+
- Implement `updateRepo(path)` with fetch + reset
|
|
305
|
+
- Implement `getRepoInfo(path)` to get remote, branch, etc.
|
|
306
|
+
- Implement `parseRepoSpec(spec)` to parse `owner/repo@branch`
|
|
307
|
+
- Disable git hooks on clone
|
|
308
|
+
- Handle errors gracefully with cleanup
|
|
309
|
+
- Write tests for git operations
|
|
310
|
+
|
|
311
|
+
**Must NOT do**:
|
|
312
|
+
- Don't support submodules
|
|
313
|
+
- Don't allow depth override
|
|
314
|
+
- Don't add push/commit operations
|
|
315
|
+
- Don't execute git hooks
|
|
316
|
+
|
|
317
|
+
**Parallelizable**: YES (with task 1)
|
|
318
|
+
|
|
319
|
+
**References**:
|
|
320
|
+
|
|
321
|
+
**Pattern References**:
|
|
322
|
+
- `~/personal/projects/opencode-tmux/index.ts:74-94` - Bun shell command execution pattern
|
|
323
|
+
|
|
324
|
+
**Implementation Details**:
|
|
325
|
+
```typescript
|
|
326
|
+
// Clone command pattern
|
|
327
|
+
await $`git clone --depth=1 --single-branch --branch ${branch} --config core.hooksPath=/dev/null ${url} ${destPath}`
|
|
328
|
+
|
|
329
|
+
// Update command pattern
|
|
330
|
+
await $`git -C ${path} fetch origin ${branch} --depth=1`
|
|
331
|
+
await $`git -C ${path} reset --hard origin/${branch}`
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Acceptance Criteria**:
|
|
335
|
+
- [x] `src/git.ts` exports: `cloneRepo`, `updateRepo`, `getRepoInfo`, `parseRepoSpec`, `buildGitUrl`
|
|
336
|
+
- [x] `cloneRepo` always uses `--depth=1`
|
|
337
|
+
- [x] `cloneRepo` disables hooks via `--config core.hooksPath=/dev/null`
|
|
338
|
+
- [x] `cloneRepo` cleans up on failure (removes partial directory)
|
|
339
|
+
- [x] `parseRepoSpec("vercel/next.js@canary")` returns `{ owner: "vercel", repo: "next.js", branch: "canary" }`
|
|
340
|
+
- [x] `parseRepoSpec("vercel/next.js")` returns `{ owner: "vercel", repo: "next.js", branch: null }`
|
|
341
|
+
- [x] `buildGitUrl` returns SSH URL: `git@github.com:owner/repo.git`
|
|
342
|
+
- [x] `bun test src/__tests__/git.test.ts` passes
|
|
343
|
+
|
|
344
|
+
**Commit**: YES
|
|
345
|
+
- Message: `feat: implement git operations module`
|
|
346
|
+
- Files: `src/git.ts`, `src/__tests__/git.test.ts`
|
|
347
|
+
- Pre-commit: `bun test`
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
- [x] 3. Implement repo_clone tool
|
|
352
|
+
|
|
353
|
+
**What to do**:
|
|
354
|
+
- Create main plugin export in `index.ts`
|
|
355
|
+
- Implement `repo_clone` tool with Zod schema
|
|
356
|
+
- Smart flow: check manifest -> clone if not exists -> return path
|
|
357
|
+
- Update manifest with new entry
|
|
358
|
+
- Track lastAccessed on every clone call
|
|
359
|
+
- Validate SSH auth works for private repos
|
|
360
|
+
|
|
361
|
+
**Must NOT do**:
|
|
362
|
+
- Don't auto-clone in other tools
|
|
363
|
+
- Don't clone if already exists (return cached path)
|
|
364
|
+
|
|
365
|
+
**Parallelizable**: NO (depends on 1, 2)
|
|
366
|
+
|
|
367
|
+
**References**:
|
|
368
|
+
|
|
369
|
+
**Pattern References**:
|
|
370
|
+
- `~/personal/projects/opencode-tmux/index.ts:242-261` - Plugin export pattern
|
|
371
|
+
- `~/personal/projects/opencode-tmux/index.ts:276-323` - Tool definition with Zod schema
|
|
372
|
+
|
|
373
|
+
**Tool Signature**:
|
|
374
|
+
```typescript
|
|
375
|
+
repo_clone: tool({
|
|
376
|
+
description: "Clone a repository to local cache or return path if already cached. Supports public and private (SSH) repos.",
|
|
377
|
+
args: {
|
|
378
|
+
repo: tool.schema.string().describe("Repository in format 'owner/repo' or 'owner/repo@branch'"),
|
|
379
|
+
force: tool.schema.boolean().optional().default(false).describe("Force re-clone even if cached"),
|
|
380
|
+
},
|
|
381
|
+
async execute(args) {
|
|
382
|
+
// 1. Parse repo spec
|
|
383
|
+
// 2. Check manifest for existing entry
|
|
384
|
+
// 3. If exists and !force, update lastAccessed, return path
|
|
385
|
+
// 4. If force or !exists, clone to cache
|
|
386
|
+
// 5. Update manifest
|
|
387
|
+
// 6. Return path and status
|
|
388
|
+
}
|
|
389
|
+
})
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Acceptance Criteria**:
|
|
393
|
+
- [x] `index.ts` exports plugin following tmux pattern
|
|
394
|
+
- [x] `repo_clone("vercel/next.js")` clones to `~/.cache/opencode-repos/vercel/next.js@main/`
|
|
395
|
+
- [x] `repo_clone("vercel/next.js@canary")` clones to `~/.cache/opencode-repos/vercel/next.js@canary/`
|
|
396
|
+
- [x] Second call to same repo returns cached path without cloning
|
|
397
|
+
- [x] `force: true` re-clones even if cached
|
|
398
|
+
- [x] Manifest updated after successful clone
|
|
399
|
+
- [x] Returns markdown with path and status
|
|
400
|
+
|
|
401
|
+
**Commit**: YES
|
|
402
|
+
- Message: `feat: implement repo_clone tool`
|
|
403
|
+
- Files: `index.ts`
|
|
404
|
+
- Pre-commit: `bun test`
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
- [x] 4. Implement repo_list tool
|
|
409
|
+
|
|
410
|
+
**What to do**:
|
|
411
|
+
- Add `repo_list` tool to plugin
|
|
412
|
+
- List all repos from manifest (cached + local)
|
|
413
|
+
- Show metadata: type, path, dates, size
|
|
414
|
+
- Format as markdown table
|
|
415
|
+
- Support filtering by type (cached/local/all)
|
|
416
|
+
|
|
417
|
+
**Must NOT do**:
|
|
418
|
+
- Don't calculate size on every call (use cached value)
|
|
419
|
+
- Don't scan filesystem (use manifest only)
|
|
420
|
+
|
|
421
|
+
**Parallelizable**: YES (with task 5)
|
|
422
|
+
|
|
423
|
+
**References**:
|
|
424
|
+
|
|
425
|
+
**Pattern References**:
|
|
426
|
+
- `~/personal/projects/opencode-tmux/index.ts:414-471` - tmux_list tool pattern with scoped output
|
|
427
|
+
|
|
428
|
+
**Tool Signature**:
|
|
429
|
+
```typescript
|
|
430
|
+
repo_list: tool({
|
|
431
|
+
description: "List all registered repositories (cached and local)",
|
|
432
|
+
args: {
|
|
433
|
+
type: tool.schema.enum(["all", "cached", "local"]).optional().default("all"),
|
|
434
|
+
},
|
|
435
|
+
async execute(args) {
|
|
436
|
+
// Load manifest
|
|
437
|
+
// Filter by type
|
|
438
|
+
// Format as markdown table
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Output Format**:
|
|
444
|
+
```markdown
|
|
445
|
+
## Registered Repositories
|
|
446
|
+
|
|
447
|
+
| Repo | Type | Branch | Last Accessed | Size |
|
|
448
|
+
|------|------|--------|---------------|------|
|
|
449
|
+
| vercel/next.js | cached | canary | 2024-01-20 | 52MB |
|
|
450
|
+
| my-project | local | main | 2024-01-19 | - |
|
|
451
|
+
|
|
452
|
+
Total: 2 repos (1 cached, 1 local)
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Acceptance Criteria**:
|
|
456
|
+
- [x] `repo_list()` returns markdown table of all repos
|
|
457
|
+
- [x] `repo_list({ type: "cached" })` filters to cached only
|
|
458
|
+
- [x] Shows repo name, type, branch, last accessed, size
|
|
459
|
+
- [x] Returns "No repositories registered" if empty
|
|
460
|
+
|
|
461
|
+
**Commit**: YES
|
|
462
|
+
- Message: `feat: implement repo_list tool`
|
|
463
|
+
- Files: `index.ts`
|
|
464
|
+
- Pre-commit: `bun test`
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
- [x] 5. Implement repo_read tool
|
|
469
|
+
|
|
470
|
+
**What to do**:
|
|
471
|
+
- Add `repo_read` tool to plugin
|
|
472
|
+
- Read file(s) from a registered repo
|
|
473
|
+
- Validate repo exists in manifest
|
|
474
|
+
- Update lastAccessed timestamp
|
|
475
|
+
- Support glob patterns for multiple files
|
|
476
|
+
|
|
477
|
+
**Must NOT do**:
|
|
478
|
+
- Don't auto-clone if repo not found (error instead)
|
|
479
|
+
- Don't read binary files (skip with warning)
|
|
480
|
+
|
|
481
|
+
**Parallelizable**: YES (with task 4)
|
|
482
|
+
|
|
483
|
+
**References**:
|
|
484
|
+
|
|
485
|
+
**Pattern References**:
|
|
486
|
+
- `~/personal/projects/opencode-tmux/index.ts:277-323` - Tool with multiple optional args
|
|
487
|
+
|
|
488
|
+
**Tool Signature**:
|
|
489
|
+
```typescript
|
|
490
|
+
repo_read: tool({
|
|
491
|
+
description: "Read files from a registered repository. Repo must be cloned first via repo_clone.",
|
|
492
|
+
args: {
|
|
493
|
+
repo: tool.schema.string().describe("Repository in format 'owner/repo' or 'owner/repo@branch'"),
|
|
494
|
+
path: tool.schema.string().describe("File path within repo, supports glob patterns"),
|
|
495
|
+
maxLines: tool.schema.number().optional().default(500).describe("Max lines per file"),
|
|
496
|
+
},
|
|
497
|
+
async execute(args) {
|
|
498
|
+
// 1. Look up repo in manifest
|
|
499
|
+
// 2. Error if not found
|
|
500
|
+
// 3. Resolve path within repo
|
|
501
|
+
// 4. Read file(s)
|
|
502
|
+
// 5. Update lastAccessed
|
|
503
|
+
// 6. Return content
|
|
504
|
+
}
|
|
505
|
+
})
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**Acceptance Criteria**:
|
|
509
|
+
- [x] `repo_read({ repo: "vercel/next.js", path: "README.md" })` returns file content
|
|
510
|
+
- [x] `repo_read({ repo: "vercel/next.js", path: "src/*.ts" })` returns multiple files
|
|
511
|
+
- [x] Returns error if repo not in manifest: "Repository not found. Run repo_clone first."
|
|
512
|
+
- [x] Updates lastAccessed in manifest after read
|
|
513
|
+
- [x] Truncates large files with note: "[truncated at 500 lines]"
|
|
514
|
+
|
|
515
|
+
**Commit**: YES
|
|
516
|
+
- Message: `feat: implement repo_read tool`
|
|
517
|
+
- Files: `index.ts`
|
|
518
|
+
- Pre-commit: `bun test`
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
- [x] 6. Implement scanner module
|
|
523
|
+
|
|
524
|
+
**What to do**:
|
|
525
|
+
- Implement local repo scanner using `fd`
|
|
526
|
+
- Find all git repos in configured search paths
|
|
527
|
+
- Extract remote URL to match against repo specs
|
|
528
|
+
- Build local index mapping remote -> local path
|
|
529
|
+
- Handle repos with no remote gracefully
|
|
530
|
+
|
|
531
|
+
**Must NOT do**:
|
|
532
|
+
- Don't scan entire filesystem (only configured paths)
|
|
533
|
+
- Don't follow symlinks into loops
|
|
534
|
+
- Don't scan nested git repos (max-depth limit)
|
|
535
|
+
|
|
536
|
+
**Parallelizable**: NO (depends on foundation)
|
|
537
|
+
|
|
538
|
+
**References**:
|
|
539
|
+
|
|
540
|
+
**Implementation Pattern**:
|
|
541
|
+
```typescript
|
|
542
|
+
// Find all .git directories
|
|
543
|
+
const gitDirs = await $`fd -H -t d '^.git$' --max-depth 4 ${searchPath}`.text()
|
|
544
|
+
|
|
545
|
+
// For each, get remote
|
|
546
|
+
for (const gitDir of gitDirs.split('\n').filter(Boolean)) {
|
|
547
|
+
const repoPath = path.dirname(gitDir)
|
|
548
|
+
const remote = await $`git -C ${repoPath} remote get-url origin`.text().catch(() => null)
|
|
549
|
+
if (remote) {
|
|
550
|
+
// Parse remote to get owner/repo
|
|
551
|
+
// Add to local index
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Acceptance Criteria**:
|
|
557
|
+
- [x] `src/scanner.ts` exports: `scanLocalRepos`, `matchRemoteToSpec`
|
|
558
|
+
- [x] `scanLocalRepos(paths)` returns array of `{ path, remote, branch }`
|
|
559
|
+
- [x] Handles repos without remote (skips them)
|
|
560
|
+
- [x] Respects max-depth of 4 to avoid deep nesting
|
|
561
|
+
- [x] `matchRemoteToSpec("git@github.com:vercel/next.js.git")` returns `"vercel/next.js"`
|
|
562
|
+
- [x] Handles both SSH and HTTPS remote formats
|
|
563
|
+
|
|
564
|
+
**Commit**: YES
|
|
565
|
+
- Message: `feat: implement local repo scanner`
|
|
566
|
+
- Files: `src/scanner.ts`
|
|
567
|
+
- Pre-commit: `bun test`
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
- [x] 7. Implement repo_scan tool
|
|
572
|
+
|
|
573
|
+
**What to do**:
|
|
574
|
+
- Add `repo_scan` tool to plugin
|
|
575
|
+
- Load config for search paths
|
|
576
|
+
- Use scanner module to find repos
|
|
577
|
+
- Update manifest with local entries
|
|
578
|
+
- Report what was found
|
|
579
|
+
|
|
580
|
+
**Must NOT do**:
|
|
581
|
+
- Don't delete existing cached entries
|
|
582
|
+
- Don't scan if no search paths configured
|
|
583
|
+
|
|
584
|
+
**Parallelizable**: NO (depends on 6)
|
|
585
|
+
|
|
586
|
+
**References**:
|
|
587
|
+
|
|
588
|
+
**Tool Signature**:
|
|
589
|
+
```typescript
|
|
590
|
+
repo_scan: tool({
|
|
591
|
+
description: "Scan local filesystem for git repositories and register them. Configure search paths in ~/.config/opencode/opencode-repos.json",
|
|
592
|
+
args: {
|
|
593
|
+
paths: tool.schema.array(tool.schema.string()).optional().describe("Override search paths (default: from config)"),
|
|
594
|
+
},
|
|
595
|
+
async execute(args) {
|
|
596
|
+
// 1. Load config for default paths (or use args.paths)
|
|
597
|
+
// 2. Validate paths exist
|
|
598
|
+
// 3. Scan each path
|
|
599
|
+
// 4. Register found repos as 'local' type
|
|
600
|
+
// 5. Return summary
|
|
601
|
+
}
|
|
602
|
+
})
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
**Config File** (`~/.config/opencode/opencode-repos.json`):
|
|
606
|
+
```json
|
|
607
|
+
{
|
|
608
|
+
"localSearchPaths": [
|
|
609
|
+
"~/projects",
|
|
610
|
+
"~/personal/projects",
|
|
611
|
+
"~/code"
|
|
612
|
+
]
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Acceptance Criteria**:
|
|
617
|
+
- [x] `repo_scan()` uses paths from config file
|
|
618
|
+
- [x] `repo_scan({ paths: ["~/custom"] })` overrides config
|
|
619
|
+
- [x] Found repos added to manifest as `type: "local"`
|
|
620
|
+
- [x] Returns summary: "Found 5 repos in 3 paths. 2 new, 3 already registered."
|
|
621
|
+
- [x] Handles missing config: "No search paths configured. Create ~/.config/opencode/opencode-repos.json"
|
|
622
|
+
|
|
623
|
+
**Commit**: YES
|
|
624
|
+
- Message: `feat: implement repo_scan tool`
|
|
625
|
+
- Files: `index.ts`
|
|
626
|
+
- Pre-commit: `bun test`
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
- [x] 8a. Implement repo_update tool
|
|
631
|
+
|
|
632
|
+
**What to do**:
|
|
633
|
+
- Add `repo_update` tool to plugin
|
|
634
|
+
- Pull latest changes for cached repos
|
|
635
|
+
- Show status for local repos (don't modify)
|
|
636
|
+
- Update lastUpdated timestamp
|
|
637
|
+
|
|
638
|
+
**Must NOT do**:
|
|
639
|
+
- Don't modify local repos (only show status)
|
|
640
|
+
- Don't update if there are local changes
|
|
641
|
+
|
|
642
|
+
**Parallelizable**: YES (with 8b)
|
|
643
|
+
|
|
644
|
+
**References**:
|
|
645
|
+
|
|
646
|
+
**Tool Signature**:
|
|
647
|
+
```typescript
|
|
648
|
+
repo_update: tool({
|
|
649
|
+
description: "Update a cached repository to latest. For local repos, shows git status without modifying.",
|
|
650
|
+
args: {
|
|
651
|
+
repo: tool.schema.string().describe("Repository in format 'owner/repo' or 'owner/repo@branch'"),
|
|
652
|
+
},
|
|
653
|
+
async execute(args) {
|
|
654
|
+
// 1. Look up in manifest
|
|
655
|
+
// 2. If cached: fetch + reset
|
|
656
|
+
// 3. If local: show status only
|
|
657
|
+
// 4. Update lastUpdated
|
|
658
|
+
}
|
|
659
|
+
})
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
**Acceptance Criteria**:
|
|
663
|
+
- [x] `repo_update("vercel/next.js")` fetches and resets cached repo
|
|
664
|
+
- [x] Returns: "Updated vercel/next.js@canary to latest (abc1234)"
|
|
665
|
+
- [x] For local repos: "Local repo - showing status only:\n[git status output]"
|
|
666
|
+
- [x] Updates lastUpdated in manifest
|
|
667
|
+
|
|
668
|
+
**Commit**: YES (combined with 8b)
|
|
669
|
+
- Message: `feat: implement repo_update and repo_remove tools`
|
|
670
|
+
- Files: `index.ts`
|
|
671
|
+
- Pre-commit: `bun test`
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
- [x] 8b. Implement repo_remove tool
|
|
676
|
+
|
|
677
|
+
**What to do**:
|
|
678
|
+
- Add `repo_remove` tool to plugin
|
|
679
|
+
- For cached: delete directory and manifest entry
|
|
680
|
+
- For local: remove from manifest only (don't delete files)
|
|
681
|
+
- Confirm dangerous operations
|
|
682
|
+
|
|
683
|
+
**Must NOT do**:
|
|
684
|
+
- Don't delete local repo files (only unregister)
|
|
685
|
+
- Don't remove without confirmation for cached
|
|
686
|
+
|
|
687
|
+
**Parallelizable**: YES (with 8a)
|
|
688
|
+
|
|
689
|
+
**References**:
|
|
690
|
+
|
|
691
|
+
**Tool Signature**:
|
|
692
|
+
```typescript
|
|
693
|
+
repo_remove: tool({
|
|
694
|
+
description: "Remove a repository. Cached repos are deleted from disk. Local repos are unregistered only.",
|
|
695
|
+
args: {
|
|
696
|
+
repo: tool.schema.string().describe("Repository in format 'owner/repo' or 'owner/repo@branch'"),
|
|
697
|
+
confirm: tool.schema.boolean().optional().default(false).describe("Confirm deletion for cached repos"),
|
|
698
|
+
},
|
|
699
|
+
async execute(args) {
|
|
700
|
+
// 1. Look up in manifest
|
|
701
|
+
// 2. If cached: require confirm, delete dir
|
|
702
|
+
// 3. If local: just remove from manifest
|
|
703
|
+
// 4. Update manifest
|
|
704
|
+
}
|
|
705
|
+
})
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Acceptance Criteria**:
|
|
709
|
+
- [x] `repo_remove("vercel/next.js")` without confirm: "This will delete cached repo. Use confirm: true to proceed."
|
|
710
|
+
- [x] `repo_remove("vercel/next.js", { confirm: true })` deletes and removes from manifest
|
|
711
|
+
- [x] `repo_remove("my-local")` unregisters without deleting: "Unregistered my-local (files preserved at /path)"
|
|
712
|
+
|
|
713
|
+
**Commit**: YES (combined with 8a)
|
|
714
|
+
- Message: `feat: implement repo_update and repo_remove tools`
|
|
715
|
+
- Files: `index.ts`
|
|
716
|
+
- Pre-commit: `bun test`
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
- [x] 9. Define repo-explorer agent
|
|
721
|
+
|
|
722
|
+
**What to do**:
|
|
723
|
+
- Create agent definition in `src/agents/repo-explorer.ts`
|
|
724
|
+
- Define agent config following oh-my-opencode patterns
|
|
725
|
+
- Agent is read-only (no edit, write, task permissions)
|
|
726
|
+
- Agent has access to: read, glob, grep, bash (for git commands)
|
|
727
|
+
- Craft system prompt for codebase exploration
|
|
728
|
+
|
|
729
|
+
**Must NOT do**:
|
|
730
|
+
- Don't give agent write/edit permissions
|
|
731
|
+
- Don't allow agent to spawn sub-tasks
|
|
732
|
+
- Don't allow agent to modify the repo
|
|
733
|
+
|
|
734
|
+
**Parallelizable**: NO (depends on core tools working)
|
|
735
|
+
|
|
736
|
+
**References**:
|
|
737
|
+
|
|
738
|
+
**Pattern References**:
|
|
739
|
+
- `/tmp/oh-my-opencode/src/agents/explore.ts` - Explorer agent pattern
|
|
740
|
+
- `/tmp/oh-my-opencode/src/agents/oracle.ts` - Read-only agent pattern
|
|
741
|
+
|
|
742
|
+
**Agent Definition**:
|
|
743
|
+
```typescript
|
|
744
|
+
import type { AgentConfig } from "@opencode-ai/sdk"
|
|
745
|
+
|
|
746
|
+
export function createRepoExplorerAgent(): AgentConfig {
|
|
747
|
+
return {
|
|
748
|
+
description: "Specialized agent for exploring external codebases. Use when you need to understand another project's architecture, APIs, patterns, or implementation details.",
|
|
749
|
+
mode: "subagent" as const,
|
|
750
|
+
temperature: 0.1,
|
|
751
|
+
permission: {
|
|
752
|
+
edit: "deny",
|
|
753
|
+
write: "deny",
|
|
754
|
+
task: "deny",
|
|
755
|
+
delegate_task: "deny",
|
|
756
|
+
},
|
|
757
|
+
prompt: `You are a codebase exploration specialist. Your job is to deeply understand external codebases and report your findings clearly.
|
|
758
|
+
|
|
759
|
+
## Your Capabilities
|
|
760
|
+
- Read and analyze source code
|
|
761
|
+
- Search for patterns and implementations
|
|
762
|
+
- Understand project structure and architecture
|
|
763
|
+
- Identify APIs, interfaces, and integration points
|
|
764
|
+
|
|
765
|
+
## Your Approach
|
|
766
|
+
1. Start with high-level structure (README, package.json, main entry points)
|
|
767
|
+
2. Identify key directories and their purposes
|
|
768
|
+
3. Trace code paths relevant to the question
|
|
769
|
+
4. Report findings with specific file references and code examples
|
|
770
|
+
|
|
771
|
+
## Output Format
|
|
772
|
+
- Be specific: cite file paths and line numbers
|
|
773
|
+
- Include relevant code snippets
|
|
774
|
+
- Explain how components interact
|
|
775
|
+
- Note any patterns or conventions used
|
|
776
|
+
|
|
777
|
+
You are READ-ONLY. You cannot modify files or create new ones.`
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
**Acceptance Criteria**:
|
|
783
|
+
- [x] `src/agents/repo-explorer.ts` exports `createRepoExplorerAgent`
|
|
784
|
+
- [x] Agent has `mode: "subagent"`
|
|
785
|
+
- [x] Agent has `permission: { edit: "deny", write: "deny", task: "deny" }`
|
|
786
|
+
- [x] Agent prompt focuses on codebase exploration
|
|
787
|
+
|
|
788
|
+
**Commit**: YES
|
|
789
|
+
- Message: `feat: define repo-explorer agent`
|
|
790
|
+
- Files: `src/agents/repo-explorer.ts`
|
|
791
|
+
- Pre-commit: `bun test`
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
795
|
+
- [x] 10. Implement repo_explore tool and config handler
|
|
796
|
+
|
|
797
|
+
**What to do**:
|
|
798
|
+
- Add config handler to register `repo-explorer` agent
|
|
799
|
+
- Implement `repo_explore` tool that:
|
|
800
|
+
1. Ensures repo is cloned/available
|
|
801
|
+
2. Spawns `repo-explorer` agent in that repo's context
|
|
802
|
+
3. Returns the exploration results
|
|
803
|
+
- Use OpenCode SDK client to spawn the agent session
|
|
804
|
+
|
|
805
|
+
**Must NOT do**:
|
|
806
|
+
- Don't allow exploration without clone
|
|
807
|
+
- Don't give the spawned agent elevated permissions
|
|
808
|
+
|
|
809
|
+
**Parallelizable**: NO (depends on agent definition)
|
|
810
|
+
|
|
811
|
+
**References**:
|
|
812
|
+
|
|
813
|
+
**Pattern References**:
|
|
814
|
+
- `/tmp/oh-my-opencode/src/plugin-handlers/config-handler.ts:280-300` - Config handler pattern for agent registration
|
|
815
|
+
- `/tmp/oh-my-opencode/src/tools/call-omo-agent/tools.ts:186-197` - Agent invocation via client.session.prompt
|
|
816
|
+
|
|
817
|
+
**Implementation Pattern**:
|
|
818
|
+
```typescript
|
|
819
|
+
// Config handler to register agent
|
|
820
|
+
config: async (config) => {
|
|
821
|
+
const explorerAgent = createRepoExplorerAgent()
|
|
822
|
+
config.agent = {
|
|
823
|
+
...config.agent,
|
|
824
|
+
"repo-explorer": explorerAgent,
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
|
|
828
|
+
// Tool to spawn explorer in repo context
|
|
829
|
+
repo_explore: tool({
|
|
830
|
+
description: "Explore a repository to understand its codebase. Spawns a specialized exploration agent that analyzes the repo and answers your question.",
|
|
831
|
+
args: {
|
|
832
|
+
repo: tool.schema.string().describe("Repository in format 'owner/repo' or 'owner/repo@branch'"),
|
|
833
|
+
question: tool.schema.string().describe("What you want to understand about the codebase"),
|
|
834
|
+
},
|
|
835
|
+
async execute(args, ctx) {
|
|
836
|
+
// 1. Ensure repo is available (clone if needed)
|
|
837
|
+
const repoPath = await ensureRepo(args.repo)
|
|
838
|
+
|
|
839
|
+
// 2. Create exploration prompt with repo context
|
|
840
|
+
const prompt = `Explore the codebase at ${repoPath} and answer: ${args.question}
|
|
841
|
+
|
|
842
|
+
Working directory: ${repoPath}
|
|
843
|
+
Available tools: read, glob, grep, bash`
|
|
844
|
+
|
|
845
|
+
// 3. Spawn repo-explorer agent via SDK
|
|
846
|
+
const result = await ctx.client.session.prompt({
|
|
847
|
+
body: {
|
|
848
|
+
agent: "repo-explorer",
|
|
849
|
+
parts: [{ type: "text", text: prompt }],
|
|
850
|
+
}
|
|
851
|
+
})
|
|
852
|
+
|
|
853
|
+
return result
|
|
854
|
+
}
|
|
855
|
+
})
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Acceptance Criteria**:
|
|
859
|
+
- [x] Config handler registers `repo-explorer` agent
|
|
860
|
+
- [x] `repo_explore({ repo: "vercel/next.js", question: "How does routing work?" })` spawns explorer
|
|
861
|
+
- [x] Explorer runs in context of the specified repo
|
|
862
|
+
- [x] Returns exploration results as markdown
|
|
863
|
+
- [x] Auto-clones repo if not cached
|
|
864
|
+
|
|
865
|
+
**Commit**: YES
|
|
866
|
+
- Message: `feat: implement repo_explore tool and config handler`
|
|
867
|
+
- Files: `index.ts`
|
|
868
|
+
- Pre-commit: `bun test`
|
|
869
|
+
|
|
870
|
+
---
|
|
871
|
+
|
|
872
|
+
- [x] 11. Documentation and final polish
|
|
873
|
+
|
|
874
|
+
**What to do**:
|
|
875
|
+
- Write comprehensive README.md
|
|
876
|
+
- Document all tools with examples
|
|
877
|
+
- Document the `repo-explorer` agent
|
|
878
|
+
- Document config file format
|
|
879
|
+
- Add installation instructions
|
|
880
|
+
- Document limitations (no submodules, no LFS, etc.)
|
|
881
|
+
- Update package.json with keywords, repository, etc.
|
|
882
|
+
|
|
883
|
+
**Must NOT do**:
|
|
884
|
+
- Don't over-document obvious things
|
|
885
|
+
- Don't promise features not implemented
|
|
886
|
+
|
|
887
|
+
**Parallelizable**: NO (final task)
|
|
888
|
+
|
|
889
|
+
**References**:
|
|
890
|
+
|
|
891
|
+
**Pattern References**:
|
|
892
|
+
- `~/personal/projects/opencode-tmux/README.md` - README structure and format
|
|
893
|
+
|
|
894
|
+
**README Structure**:
|
|
895
|
+
```markdown
|
|
896
|
+
# opencode-repos
|
|
897
|
+
|
|
898
|
+
Repository cache, registry, and cross-codebase intelligence for OpenCode agents.
|
|
899
|
+
|
|
900
|
+
## Installation
|
|
901
|
+
## Configuration
|
|
902
|
+
## Tools
|
|
903
|
+
### repo_clone
|
|
904
|
+
### repo_list
|
|
905
|
+
### repo_read
|
|
906
|
+
### repo_scan
|
|
907
|
+
### repo_update
|
|
908
|
+
### repo_remove
|
|
909
|
+
### repo_explore
|
|
910
|
+
## Custom Agent: repo-explorer
|
|
911
|
+
## Use Cases
|
|
912
|
+
### Cross-project integration
|
|
913
|
+
### Understanding dependencies
|
|
914
|
+
### Firmware/backend exploration
|
|
915
|
+
## Limitations
|
|
916
|
+
## Development
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
**Acceptance Criteria**:
|
|
920
|
+
- [x] README.md exists with installation and usage
|
|
921
|
+
- [x] All 7 tools documented with examples
|
|
922
|
+
- [x] `repo-explorer` agent documented with use cases
|
|
923
|
+
- [x] Config file format documented
|
|
924
|
+
- [x] Limitations section lists: no submodules, no LFS, shallow only
|
|
925
|
+
- [x] `package.json` has keywords: `opencode`, `opencode-plugin`, `repos`, `cache`, `codebase`
|
|
926
|
+
|
|
927
|
+
**Commit**: YES
|
|
928
|
+
- Message: `docs: add comprehensive documentation`
|
|
929
|
+
- Files: `README.md`, `package.json`
|
|
930
|
+
- Pre-commit: `bun test`
|
|
931
|
+
|
|
932
|
+
---
|
|
933
|
+
|
|
934
|
+
## Commit Strategy
|
|
935
|
+
|
|
936
|
+
| After Task | Message | Files | Verification |
|
|
937
|
+
|------------|---------|-------|--------------|
|
|
938
|
+
| 0 | `chore: initial project setup` | package.json, tsconfig.json | `bun test` |
|
|
939
|
+
| 1 | `feat: implement manifest operations with locking` | src/manifest.ts, tests | `bun test` |
|
|
940
|
+
| 2 | `feat: implement git operations module` | src/git.ts, tests | `bun test` |
|
|
941
|
+
| 3 | `feat: implement repo_clone tool` | index.ts | `bun test` |
|
|
942
|
+
| 4 | `feat: implement repo_list tool` | index.ts | `bun test` |
|
|
943
|
+
| 5 | `feat: implement repo_read tool` | index.ts | `bun test` |
|
|
944
|
+
| 6 | `feat: implement local repo scanner` | src/scanner.ts | `bun test` |
|
|
945
|
+
| 7 | `feat: implement repo_scan tool` | index.ts | `bun test` |
|
|
946
|
+
| 8a+8b | `feat: implement repo_update and repo_remove tools` | index.ts | `bun test` |
|
|
947
|
+
| 9 | `feat: define repo-explorer agent` | src/agents/repo-explorer.ts | `bun test` |
|
|
948
|
+
| 10 | `feat: implement repo_explore tool and config handler` | index.ts | `bun test` |
|
|
949
|
+
| 11 | `docs: add comprehensive documentation` | README.md, package.json | `bun test` |
|
|
950
|
+
|
|
951
|
+
---
|
|
952
|
+
|
|
953
|
+
## Success Criteria
|
|
954
|
+
|
|
955
|
+
### Verification Commands
|
|
956
|
+
```bash
|
|
957
|
+
# All tests pass
|
|
958
|
+
bun test
|
|
959
|
+
|
|
960
|
+
# Plugin loads without error (check in opencode)
|
|
961
|
+
# Add to opencode.jsonc: "file:///Users/liamvinberg/personal/projects/opencode-repos/index.ts"
|
|
962
|
+
|
|
963
|
+
# Functional tests (manual in opencode)
|
|
964
|
+
repo_clone("vercel/next.js") # Should clone and return path
|
|
965
|
+
repo_clone("vercel/next.js") # Should return cached path (no clone)
|
|
966
|
+
repo_list() # Should show the repo
|
|
967
|
+
repo_read("vercel/next.js", "README.md") # Should return content
|
|
968
|
+
repo_scan() # Should find local repos
|
|
969
|
+
repo_update("vercel/next.js") # Should update
|
|
970
|
+
repo_remove("vercel/next.js", true) # Should delete
|
|
971
|
+
|
|
972
|
+
# Agent verification
|
|
973
|
+
# Check that repo-explorer appears in available agents
|
|
974
|
+
# Test cross-codebase exploration:
|
|
975
|
+
repo_explore("vercel/next.js", "How does the App Router work?")
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
### Final Checklist
|
|
979
|
+
- [x] All "Must Have" present
|
|
980
|
+
- [x] All "Must NOT Have" absent
|
|
981
|
+
- [x] All tests pass (`bun test`)
|
|
982
|
+
- [x] Plugin loads in OpenCode
|
|
983
|
+
- [x] Can clone public and private repos
|
|
984
|
+
- [x] Local scan discovers existing repos
|
|
985
|
+
- [x] `repo-explorer` agent registered and available
|
|
986
|
+
- [x] `repo_explore` tool spawns explorer correctly
|
|
987
|
+
- [x] Documentation complete
|