From e8ee1e239f5c417cb47252435ef1abc02635a98e Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 9 Mar 2026 21:36:29 -0400 Subject: [PATCH] sync --- .opencode/.gitignore | 3 +- .../plans/1771135996918-mighty-wizard.md | 209 ------------------ 2 files changed, 2 insertions(+), 210 deletions(-) delete mode 100644 .opencode/plans/1771135996918-mighty-wizard.md diff --git a/.opencode/.gitignore b/.opencode/.gitignore index b0f4a6a039..e7c46c0033 100644 --- a/.opencode/.gitignore +++ b/.opencode/.gitignore @@ -2,4 +2,5 @@ node_modules package.json bun.lock .gitignore -package-lock.json \ No newline at end of file +package-lock.json +plans diff --git a/.opencode/plans/1771135996918-mighty-wizard.md b/.opencode/plans/1771135996918-mighty-wizard.md deleted file mode 100644 index 36c1048ba3..0000000000 --- a/.opencode/plans/1771135996918-mighty-wizard.md +++ /dev/null @@ -1,209 +0,0 @@ -# Plan: Project References Feature - -Add support for referencing external git repositories in `opencode.json` that can be queried via a dedicated subagent. - -## Overview - -Users can specify references in config: - -```json -{ - "references": ["git@github.com:Effect-TS/effect.git", "git@github.com:foo/bar.git#v1.0.0", "/local/path/to/repo"] -} -``` - -These get cloned/cached to `~/.cache/opencode/references/` and a `reference` subagent can search across them. - ---- - -## Files to Create - -### `src/reference/index.ts` - -Core reference management module with: - -- `parse(url: string): Reference` - Parse git URL or local path, extract branch if present (`#branch` suffix) -- `cachePath(ref: Reference): string` - SHA-256 hash of URL for deterministic directory names -- `isStale(ref: Reference): Promise` - Check if `FETCH_HEAD` mtime > 1 hour old -- `fetch(ref: Reference): Promise` - Clone with `--depth 1` or `git fetch`, handle branch checkout -- `ensureFresh(ref: Reference): Promise` - Lazy fetch wrapper (skip if not stale) -- `list(): Promise` - Get references from config -- `directories(): Promise` - Get all cached reference paths for permissions - -Types: - -```ts -interface Reference { - url: string // Original URL/path - path: string // Cache directory (for git) or resolved path (for local) - branch?: string // Optional branch/tag from URL fragment - type: "git" | "local" -} -``` - -URL parsing supports: - -- `git@github.com:foo/bar.git` → git -- `git@github.com:foo/bar.git#main` → git with branch -- `https://github.com/foo/bar.git#v1.0.0` → git with tag -- `/absolute/path` → local -- `~/relative/path` → local (expanded) - -### `src/agent/prompt/reference.txt` - -Prompt for reference subagent: - -``` -You are a multi-project code search specialist. You search across referenced projects -to answer questions about external codebases. - -Available references: {references} - -Guidelines: -- Search across ALL referenced projects unless the user specifies one -- Report which project(s) contained relevant findings -- Use Glob for file patterns, Grep for content search, Read for specific files -- Return absolute paths so users can locate findings -- Do not modify any files or run destructive commands -``` - ---- - -## Files to Modify - -### `src/config/config.ts` - -Add `references` field to `Config.Info` schema (around line 1174): - -```ts -references: z.array(z.string()).optional().describe( - "Git repositories or local paths to reference from subagents" -), -``` - -### `src/global/index.ts` - -Add reference cache path and create directory: - -```ts -// Add to Path object: -reference: path.join(cache, "references"), - -// Add to mkdir promise array: -fs.mkdir(path.join(cache, "references"), { recursive: true }), -``` - -### `src/agent/agent.ts` - -Add `reference` agent to built-in agents (after `explore` around line 155): - -```ts -reference: { - name: "reference", - description: `Search across referenced projects configured in opencode.json under "references". Use this to query code in external repositories.`, - permission: PermissionNext.merge( - defaults, - PermissionNext.fromConfig({ - "*": "deny", - grep: "allow", - glob: "allow", - list: "allow", - bash: "allow", - webfetch: "allow", - websearch: "allow", - codesearch: "allow", - read: "allow", - lsp: "allow", - external_directory: { - [Truncate.GLOB]: "allow", - // Reference paths added dynamically via Reference.directories() - }, - }), - user, - ), - prompt: PROMPT_REFERENCE, - options: {}, - mode: "subagent", - native: true, -}, -``` - -Need to inject reference paths into `external_directory` permissions. This requires: - -1. Loading references via `Reference.list()` -2. Ensuring they're fresh via `Reference.ensureFresh()` -3. Adding their paths to `external_directory` permissions - -**Challenge**: The agent definition is loaded once at startup, but references may change. Solution: Inject reference paths dynamically in the Task tool when creating the subagent session. - -### `src/tool/task.ts` - -When creating session for `reference` subagent (around line 72): - -```ts -// Before Session.create: -let extraPermissions = [] -if (params.subagent_type === "reference") { - const refs = await Reference.list() - await Promise.all(refs.map((r) => Reference.ensureFresh(r))) - const paths = refs.map((r) => path.join(r.path, "*")) - extraPermissions = paths.map((p) => ({ - permission: "external_directory" as const, - pattern: p, - action: "allow" as const, - })) -} - -// Add extraPermissions to the permission array in Session.create -``` - -Also need to inject available references into the prompt. Modify `SessionPrompt.resolvePromptParts` or add a way to inject context. - -### `src/session/prompt.ts` (or similar) - -Inject reference list into reference agent's system prompt: - -```ts -// When agent.name === "reference", prepend reference info to prompt -const refs = await Reference.list() -const refList = refs.map((r) => `- ${r.url} at ${r.path}`).join("\n") -// Inject into prompt or parts -``` - ---- - -## Edge Cases - -1. **Clone failures**: Log warning, continue with other references. Don't block subagent. -2. **Network failures**: Use cached version if exists, even if stale. Only error if never cloned. -3. **Branch not found**: Log error, skip that reference. -4. **Local path missing**: Log warning, skip reference. -5. **Invalid URL format**: Log warning, skip reference. -6. **Shallow clone**: Use `--depth 1` for faster clones. For branch-specific URLs, use `--branch --depth 1`. - ---- - -## Verification - -1. Add to `opencode.json`: `{"references": ["git@github.com:effect-ts/effect.git"]}` -2. Invoke `@reference` with query like "show me the Effect schema module" -3. Verify repo cloned to `~/.cache/opencode/references//` -4. Verify subagent can search/read files in the cloned repo -5. Wait 1+ hour, invoke again, verify fetch happens -6. Test with local path: `{"references": ["/path/to/local/repo"]}` -7. Test with branch: `{"references": ["git@github.com:foo/bar.git#main"]}` -8. Verify error handling with invalid URL - ---- - -## Files Summary - -| File | Action | -| -------------------------------- | ------------------------------------------- | -| `src/reference/index.ts` | Create | -| `src/agent/prompt/reference.txt` | Create | -| `src/config/config.ts` | Add `references` to schema | -| `src/global/index.ts` | Add `reference` path | -| `src/agent/agent.ts` | Add `reference` agent | -| `src/tool/task.ts` | Inject ref permissions + paths into session | -| `src/session/prompt.ts` | Inject reference list into system prompt |