Compare commits
3 Commits
bbfcc366c2
...
80ff1f8b03
| Author | SHA1 | Date | |
|---|---|---|---|
| 80ff1f8b03 | |||
| 9b5069693a | |||
| 2cad84ff26 |
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
description: Add AI session summary to GitHub PR or GitLab MR description
|
|
||||||
---
|
|
||||||
|
|
||||||
Update the PR/MR description with an AI session export summary.
|
|
||||||
|
|
||||||
First, invoke the skill tool to load the session-export skill:
|
|
||||||
|
|
||||||
```
|
|
||||||
skill({ name: 'session-export' })
|
|
||||||
```
|
|
||||||
|
|
||||||
Then follow the skill instructions to export the session summary.
|
|
||||||
|
|
||||||
<user-request>
|
|
||||||
$ARGUMENTS
|
|
||||||
</user-request>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import type { Plugin } from "@opencode-ai/plugin";
|
|
||||||
|
|
||||||
export const DirenvPlugin: Plugin = async ({ $ }) => {
|
|
||||||
return {
|
|
||||||
"shell.env": async (input, output) => {
|
|
||||||
try {
|
|
||||||
const exported = await $`direnv export json`
|
|
||||||
.cwd(input.cwd)
|
|
||||||
.quiet()
|
|
||||||
.json();
|
|
||||||
|
|
||||||
Object.assign(output.env, exported);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("[direnv] failed to export env:", error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
---
|
|
||||||
name: librarian
|
|
||||||
description: Multi-repository codebase exploration. Research library internals, find code patterns, understand architecture, compare implementations across GitHub/npm/PyPI/crates. Use when needing deep understanding of how libraries work, finding implementations across open source, or exploring remote repository structure.
|
|
||||||
references:
|
|
||||||
- references/tool-routing.md
|
|
||||||
- references/opensrc-api.md
|
|
||||||
- references/opensrc-examples.md
|
|
||||||
- references/linking.md
|
|
||||||
- references/diagrams.md
|
|
||||||
---
|
|
||||||
|
|
||||||
# Librarian Skill
|
|
||||||
|
|
||||||
Deep codebase exploration across remote repositories.
|
|
||||||
|
|
||||||
## How to Use This Skill
|
|
||||||
|
|
||||||
### Reference Structure
|
|
||||||
|
|
||||||
| File | Purpose | When to Read |
|
|
||||||
|------|---------|--------------|
|
|
||||||
| `tool-routing.md` | Tool selection decision trees | **Always read first** |
|
|
||||||
| `opensrc-api.md` | API reference, types | Writing opensrc code |
|
|
||||||
| `opensrc-examples.md` | JavaScript patterns, workflows | Implementation examples |
|
|
||||||
| `linking.md` | GitHub URL patterns | Formatting responses |
|
|
||||||
| `diagrams.md` | Mermaid patterns | Visualizing architecture |
|
|
||||||
|
|
||||||
### Reading Order
|
|
||||||
|
|
||||||
1. **Start** with `tool-routing.md` → choose tool strategy
|
|
||||||
2. **If using opensrc:**
|
|
||||||
- Read `opensrc-api.md` for API details
|
|
||||||
- Read `opensrc-examples.md` for patterns
|
|
||||||
3. **Before responding:** `linking.md` + `diagrams.md` for output formatting
|
|
||||||
|
|
||||||
## Tool Arsenal
|
|
||||||
|
|
||||||
| Tool | Best For | Limitations |
|
|
||||||
|------|----------|-------------|
|
|
||||||
| **grep_app** | Find patterns across ALL public GitHub | Literal search only |
|
|
||||||
| **context7** | Library docs, API examples, usage | Known libraries only |
|
|
||||||
| **opensrc** | Fetch full source for deep exploration | Must fetch before read |
|
|
||||||
|
|
||||||
## Quick Decision Trees
|
|
||||||
|
|
||||||
### "How does X work?"
|
|
||||||
|
|
||||||
```
|
|
||||||
Known library?
|
|
||||||
├─ Yes → context7.resolve-library-id → context7.query-docs
|
|
||||||
│ └─ Need internals? → opensrc.fetch → read source
|
|
||||||
└─ No → grep_app search → opensrc.fetch top result
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Find pattern X"
|
|
||||||
|
|
||||||
```
|
|
||||||
Specific repo?
|
|
||||||
├─ Yes → opensrc.fetch → opensrc.grep → read matches
|
|
||||||
└─ No → grep_app (broad) → opensrc.fetch interesting repos
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Explore repo structure"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. opensrc.fetch(target)
|
|
||||||
2. opensrc.tree(source.name) → quick overview
|
|
||||||
3. opensrc.files(source.name, "**/*.ts") → detailed listing
|
|
||||||
4. Read: README, package.json, src/index.*
|
|
||||||
5. Create architecture diagram (see diagrams.md)
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Compare X vs Y"
|
|
||||||
|
|
||||||
```
|
|
||||||
1. opensrc.fetch(["X", "Y"])
|
|
||||||
2. Use source.name from results for subsequent calls
|
|
||||||
3. opensrc.grep(pattern, { sources: [nameX, nameY] })
|
|
||||||
4. Read comparable files, synthesize differences
|
|
||||||
```
|
|
||||||
|
|
||||||
## Critical: Source Naming Convention
|
|
||||||
|
|
||||||
**After fetching, always use `source.name` for subsequent calls:**
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const [{ source }] = await opensrc.fetch("vercel/ai");
|
|
||||||
const files = await opensrc.files(source.name, "**/*.ts");
|
|
||||||
```
|
|
||||||
|
|
||||||
| Type | Fetch Spec | Source Name |
|
|
||||||
|------|------------|-------------|
|
|
||||||
| npm | `"zod"` | `"zod"` |
|
|
||||||
| npm scoped | `"@tanstack/react-query"` | `"@tanstack/react-query"` |
|
|
||||||
| pypi | `"pypi:requests"` | `"requests"` |
|
|
||||||
| crates | `"crates:serde"` | `"serde"` |
|
|
||||||
| GitHub | `"vercel/ai"` | `"github.com/vercel/ai"` |
|
|
||||||
| GitLab | `"gitlab:org/repo"` | `"gitlab.com/org/repo"` |
|
|
||||||
|
|
||||||
## When NOT to Use opensrc
|
|
||||||
|
|
||||||
| Scenario | Use Instead |
|
|
||||||
|----------|-------------|
|
|
||||||
| Simple library API questions | context7 |
|
|
||||||
| Finding examples across many repos | grep_app |
|
|
||||||
| Very large monorepos (>10GB) | Clone locally |
|
|
||||||
| Private repositories | Direct access |
|
|
||||||
|
|
||||||
## Output Guidelines
|
|
||||||
|
|
||||||
1. **Comprehensive final message** - only last message returns to main agent
|
|
||||||
2. **Parallel tool calls** - maximize efficiency
|
|
||||||
3. **Link every file reference** - see `linking.md`
|
|
||||||
4. **Diagram complex relationships** - see `diagrams.md`
|
|
||||||
5. **Never mention tool names** - say "I'll search" not "I'll use opensrc"
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- [Tool Routing Decision Trees](references/tool-routing.md)
|
|
||||||
- [opensrc API Reference](references/opensrc-api.md)
|
|
||||||
- [opensrc Code Examples](references/opensrc-examples.md)
|
|
||||||
- [GitHub Linking Patterns](references/linking.md)
|
|
||||||
- [Mermaid Diagram Patterns](references/diagrams.md)
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
# Mermaid Diagram Patterns
|
|
||||||
|
|
||||||
Create diagrams for:
|
|
||||||
- Architecture (component relationships)
|
|
||||||
- Data flow (request → response)
|
|
||||||
- Dependencies (import graph)
|
|
||||||
- Sequences (step-by-step processes)
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[Client] --> B[API Gateway]
|
|
||||||
B --> C[Auth Service]
|
|
||||||
B --> D[Data Service]
|
|
||||||
D --> E[(Database)]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Flow
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
flowchart LR
|
|
||||||
Input --> Parse --> Validate --> Transform --> Output
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sequence
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
sequenceDiagram
|
|
||||||
Client->>+Server: Request
|
|
||||||
Server->>+DB: Query
|
|
||||||
DB-->>-Server: Result
|
|
||||||
Server-->>-Client: Response
|
|
||||||
```
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
|
|
||||||
| Type | Use For |
|
|
||||||
|------|---------|
|
|
||||||
| `graph TD` | Component hierarchy, dependencies |
|
|
||||||
| `flowchart LR` | Data transformation, pipelines |
|
|
||||||
| `sequenceDiagram` | Request/response, multi-party interaction |
|
|
||||||
| `classDiagram` | Type relationships, inheritance |
|
|
||||||
| `stateDiagram` | State machines, lifecycle |
|
|
||||||
|
|
||||||
## Tips
|
|
||||||
|
|
||||||
- Keep nodes short (3-4 words max)
|
|
||||||
- Use subgraphs for grouping related components
|
|
||||||
- Arrow labels for relationship types
|
|
||||||
- Prefer LR (left-right) for flows, TD (top-down) for hierarchies
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
# GitHub Linking Patterns
|
|
||||||
|
|
||||||
All file/dir/code refs → fluent markdown links. Never raw URLs.
|
|
||||||
|
|
||||||
## URL Formats
|
|
||||||
|
|
||||||
### File
|
|
||||||
```
|
|
||||||
https://github.com/{owner}/{repo}/blob/{ref}/{path}
|
|
||||||
```
|
|
||||||
|
|
||||||
### File + Lines
|
|
||||||
```
|
|
||||||
https://github.com/{owner}/{repo}/blob/{ref}/{path}#L{start}-L{end}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Directory
|
|
||||||
```
|
|
||||||
https://github.com/{owner}/{repo}/tree/{ref}/{path}
|
|
||||||
```
|
|
||||||
|
|
||||||
### GitLab (note `/-/blob/`)
|
|
||||||
```
|
|
||||||
https://gitlab.com/{owner}/{repo}/-/blob/{ref}/{path}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ref Resolution
|
|
||||||
|
|
||||||
| Source | Use as ref |
|
|
||||||
|--------|------------|
|
|
||||||
| Known version | `v{version}` |
|
|
||||||
| Default branch | `main` or `master` |
|
|
||||||
| opensrc fetch | ref from result |
|
|
||||||
| Specific commit | full SHA |
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Correct
|
|
||||||
```markdown
|
|
||||||
The [`parseAsync`](https://github.com/colinhacks/zod/blob/main/src/types.ts#L450-L480) method handles...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Wrong
|
|
||||||
```markdown
|
|
||||||
See https://github.com/colinhacks/zod/blob/main/src/types.ts#L100
|
|
||||||
The parseAsync method in src/types.ts handles...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Line Numbers
|
|
||||||
|
|
||||||
- Single: `#L42`
|
|
||||||
- Range: `#L42-L50`
|
|
||||||
- Prefer ranges for context (2-5 lines around key code)
|
|
||||||
|
|
||||||
## Registry → GitHub
|
|
||||||
|
|
||||||
| Registry | Find repo in |
|
|
||||||
|----------|--------------|
|
|
||||||
| npm | `package.json` → `repository` |
|
|
||||||
| PyPI | `pyproject.toml` or setup.py |
|
|
||||||
| crates | `Cargo.toml` |
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
# opensrc API Reference
|
|
||||||
|
|
||||||
## Tool
|
|
||||||
|
|
||||||
Use the **opensrc MCP server** via single tool:
|
|
||||||
|
|
||||||
| Tool | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `opensrc_execute` | All operations (fetch, read, grep, files, remove, etc.) |
|
|
||||||
|
|
||||||
Takes a `code` parameter: JavaScript async arrow function executed server-side. Source trees stay on server, only results return.
|
|
||||||
|
|
||||||
## API Surface
|
|
||||||
|
|
||||||
### Read Operations
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// List all fetched sources
|
|
||||||
opensrc.list(): Source[]
|
|
||||||
|
|
||||||
// Check if source exists
|
|
||||||
opensrc.has(name: string, version?: string): boolean
|
|
||||||
|
|
||||||
// Get source metadata
|
|
||||||
opensrc.get(name: string): Source | undefined
|
|
||||||
|
|
||||||
// List files with optional glob
|
|
||||||
opensrc.files(sourceName: string, glob?: string): Promise<FileEntry[]>
|
|
||||||
|
|
||||||
// Get directory tree structure (default depth: 3)
|
|
||||||
opensrc.tree(sourceName: string, options?: { depth?: number }): Promise<TreeNode>
|
|
||||||
|
|
||||||
// Regex search file contents
|
|
||||||
opensrc.grep(pattern: string, options?: GrepOptions): Promise<GrepResult[]>
|
|
||||||
|
|
||||||
// AST-based semantic code search
|
|
||||||
opensrc.astGrep(sourceName: string, pattern: string, options?: AstGrepOptions): Promise<AstGrepMatch[]>
|
|
||||||
|
|
||||||
// Read single file
|
|
||||||
opensrc.read(sourceName: string, filePath: string): Promise<string>
|
|
||||||
|
|
||||||
// Batch read multiple files (supports globs!)
|
|
||||||
opensrc.readMany(sourceName: string, paths: string[]): Promise<Record<string, string>>
|
|
||||||
|
|
||||||
// Parse fetch spec
|
|
||||||
opensrc.resolve(spec: string): Promise<ParsedSpec>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mutation Operations
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Fetch packages/repos
|
|
||||||
opensrc.fetch(specs: string | string[], options?: { modify?: boolean }): Promise<FetchedSource[]>
|
|
||||||
|
|
||||||
// Remove sources
|
|
||||||
opensrc.remove(names: string[]): Promise<RemoveResult>
|
|
||||||
|
|
||||||
// Clean by type
|
|
||||||
opensrc.clean(options?: CleanOptions): Promise<RemoveResult>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Types
|
|
||||||
|
|
||||||
### Source
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface Source {
|
|
||||||
type: "npm" | "pypi" | "crates" | "repo";
|
|
||||||
name: string; // Use this for all subsequent calls
|
|
||||||
version?: string;
|
|
||||||
ref?: string;
|
|
||||||
path: string;
|
|
||||||
fetchedAt: string;
|
|
||||||
repository: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### FetchedSource
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface FetchedSource {
|
|
||||||
source: Source; // IMPORTANT: use source.name for subsequent calls
|
|
||||||
alreadyExists: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### GrepOptions
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface GrepOptions {
|
|
||||||
sources?: string[]; // Filter to specific sources
|
|
||||||
include?: string; // File glob pattern (e.g., "*.ts")
|
|
||||||
maxResults?: number; // Limit results (default: 100)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### GrepResult
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface GrepResult {
|
|
||||||
source: string;
|
|
||||||
file: string;
|
|
||||||
line: number;
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AstGrepOptions
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface AstGrepOptions {
|
|
||||||
glob?: string; // File glob pattern (e.g., "**/*.ts")
|
|
||||||
lang?: string | string[]; // Language(s): "js", "ts", "tsx", "html", "css"
|
|
||||||
limit?: number; // Max results (default: 1000)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AstGrepMatch
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface AstGrepMatch {
|
|
||||||
file: string;
|
|
||||||
line: number;
|
|
||||||
column: number;
|
|
||||||
endLine: number;
|
|
||||||
endColumn: number;
|
|
||||||
text: string; // Matched code text
|
|
||||||
metavars: Record<string, string>; // Captured $VAR → text
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### AST Pattern Syntax
|
|
||||||
|
|
||||||
| Pattern | Matches |
|
|
||||||
|---------|---------|
|
|
||||||
| `$NAME` | Single node, captures to metavars |
|
|
||||||
| `$$$ARGS` | Zero or more nodes (variadic), captures |
|
|
||||||
| `$_` | Single node, no capture |
|
|
||||||
| `$$$` | Zero or more nodes, no capture |
|
|
||||||
|
|
||||||
### FileEntry
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface FileEntry {
|
|
||||||
path: string;
|
|
||||||
size: number;
|
|
||||||
isDirectory: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### TreeNode
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface TreeNode {
|
|
||||||
name: string;
|
|
||||||
type: "file" | "dir";
|
|
||||||
children?: TreeNode[]; // only for dirs
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### CleanOptions
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface CleanOptions {
|
|
||||||
packages?: boolean;
|
|
||||||
repos?: boolean;
|
|
||||||
npm?: boolean;
|
|
||||||
pypi?: boolean;
|
|
||||||
crates?: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### RemoveResult
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface RemoveResult {
|
|
||||||
success: boolean;
|
|
||||||
removed: string[];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
Operations throw on errors. Wrap in try/catch if needed:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
try {
|
|
||||||
const content = await opensrc.read("zod", "missing.ts");
|
|
||||||
return content;
|
|
||||||
} catch (e) {
|
|
||||||
return { error: e.message };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`readMany` returns errors as string values prefixed with `[Error:`:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const files = await opensrc.readMany("zod", ["exists.ts", "missing.ts"]);
|
|
||||||
// { "exists.ts": "content...", "missing.ts": "[Error: ENOENT...]" }
|
|
||||||
|
|
||||||
// Filter successful reads
|
|
||||||
const successful = Object.entries(files)
|
|
||||||
.filter(([_, content]) => !content.startsWith("[Error:"));
|
|
||||||
```
|
|
||||||
|
|
||||||
## Package Spec Formats
|
|
||||||
|
|
||||||
| Format | Example | Source Name After Fetch |
|
|
||||||
|--------|---------|------------------------|
|
|
||||||
| `<name>` | `"zod"` | `"zod"` |
|
|
||||||
| `<name>@<version>` | `"zod@3.22.0"` | `"zod"` |
|
|
||||||
| `pypi:<name>` | `"pypi:requests"` | `"requests"` |
|
|
||||||
| `crates:<name>` | `"crates:serde"` | `"serde"` |
|
|
||||||
| `owner/repo` | `"vercel/ai"` | `"github.com/vercel/ai"` |
|
|
||||||
| `owner/repo@ref` | `"vercel/ai@v1.0.0"` | `"github.com/vercel/ai"` |
|
|
||||||
| `gitlab:owner/repo` | `"gitlab:org/repo"` | `"gitlab.com/org/repo"` |
|
|
||||||
|
|
||||||
## Critical Pattern
|
|
||||||
|
|
||||||
**Always capture `source.name` from fetch results:**
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("vercel/ai");
|
|
||||||
|
|
||||||
// GitHub repos: "vercel/ai" → "github.com/vercel/ai"
|
|
||||||
const sourceName = source.name;
|
|
||||||
|
|
||||||
// Use sourceName for ALL subsequent calls
|
|
||||||
const files = await opensrc.files(sourceName, "src/**/*.ts");
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,336 +0,0 @@
|
|||||||
# opensrc Code Examples
|
|
||||||
|
|
||||||
## Workflow: Fetch → Explore
|
|
||||||
|
|
||||||
### Basic Fetch and Explore with tree()
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("vercel/ai");
|
|
||||||
// Get directory structure first
|
|
||||||
const tree = await opensrc.tree(source.name, { depth: 2 });
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fetch and Read Key Files
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("vercel/ai");
|
|
||||||
const sourceName = source.name; // "github.com/vercel/ai"
|
|
||||||
|
|
||||||
const files = await opensrc.readMany(sourceName, [
|
|
||||||
"package.json",
|
|
||||||
"README.md",
|
|
||||||
"src/index.ts"
|
|
||||||
]);
|
|
||||||
|
|
||||||
return { sourceName, files };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### readMany with Globs
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("zod");
|
|
||||||
// Read all package.json files in monorepo
|
|
||||||
const files = await opensrc.readMany(source.name, [
|
|
||||||
"packages/*/package.json" // globs supported!
|
|
||||||
]);
|
|
||||||
return Object.keys(files);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Batch Fetch Multiple Packages
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const results = await opensrc.fetch(["zod", "valibot", "yup"]);
|
|
||||||
const names = results.map(r => r.source.name);
|
|
||||||
|
|
||||||
// Compare how each handles string validation
|
|
||||||
const comparisons = {};
|
|
||||||
for (const name of names) {
|
|
||||||
const matches = await opensrc.grep("string.*validate|validateString", {
|
|
||||||
sources: [name],
|
|
||||||
include: "*.ts",
|
|
||||||
maxResults: 10
|
|
||||||
});
|
|
||||||
comparisons[name] = matches.map(m => `${m.file}:${m.line}`);
|
|
||||||
}
|
|
||||||
return comparisons;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Search Patterns
|
|
||||||
|
|
||||||
### Grep → Read Context
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const matches = await opensrc.grep("export function parse\\(", {
|
|
||||||
sources: ["zod"],
|
|
||||||
include: "*.ts"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (matches.length === 0) return "No matches";
|
|
||||||
|
|
||||||
const match = matches[0];
|
|
||||||
const content = await opensrc.read(match.source, match.file);
|
|
||||||
const lines = content.split("\n");
|
|
||||||
|
|
||||||
// Return 40 lines starting from match
|
|
||||||
return {
|
|
||||||
file: match.file,
|
|
||||||
code: lines.slice(match.line - 1, match.line + 39).join("\n")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Search Across All Fetched Sources
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const sources = opensrc.list();
|
|
||||||
const results = {};
|
|
||||||
|
|
||||||
for (const source of sources) {
|
|
||||||
const errorHandling = await opensrc.grep("throw new|catch \\(|\\.catch\\(", {
|
|
||||||
sources: [source.name],
|
|
||||||
include: "*.ts",
|
|
||||||
maxResults: 20
|
|
||||||
});
|
|
||||||
results[source.name] = {
|
|
||||||
type: source.type,
|
|
||||||
errorPatterns: errorHandling.length
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## AST-Based Search
|
|
||||||
|
|
||||||
Use `astGrep` for semantic code search with pattern matching.
|
|
||||||
|
|
||||||
### Find Function Declarations
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("lodash");
|
|
||||||
|
|
||||||
const fns = await opensrc.astGrep(source.name, "function $NAME($$$ARGS) { $$$BODY }", {
|
|
||||||
lang: "js",
|
|
||||||
limit: 20
|
|
||||||
});
|
|
||||||
|
|
||||||
return fns.map(m => ({
|
|
||||||
file: m.file,
|
|
||||||
line: m.line,
|
|
||||||
name: m.metavars.NAME
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Find React Hooks Usage
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("vercel/ai");
|
|
||||||
|
|
||||||
const stateHooks = await opensrc.astGrep(
|
|
||||||
source.name,
|
|
||||||
"const [$STATE, $SETTER] = useState($$$INIT)",
|
|
||||||
{ lang: ["ts", "tsx"], limit: 50 }
|
|
||||||
);
|
|
||||||
|
|
||||||
return stateHooks.map(m => ({
|
|
||||||
file: m.file,
|
|
||||||
state: m.metavars.STATE,
|
|
||||||
setter: m.metavars.SETTER
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Find Class Definitions with Context
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const [{ source }] = await opensrc.fetch("zod");
|
|
||||||
|
|
||||||
const classes = await opensrc.astGrep(source.name, "class $NAME", {
|
|
||||||
glob: "**/*.ts"
|
|
||||||
});
|
|
||||||
|
|
||||||
const details = [];
|
|
||||||
for (const cls of classes.slice(0, 5)) {
|
|
||||||
const content = await opensrc.read(source.name, cls.file);
|
|
||||||
const lines = content.split("\n");
|
|
||||||
details.push({
|
|
||||||
name: cls.metavars.NAME,
|
|
||||||
file: cls.file,
|
|
||||||
preview: lines.slice(cls.line - 1, cls.line + 9).join("\n")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compare Export Patterns Across Libraries
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const results = await opensrc.fetch(["zod", "valibot"]);
|
|
||||||
const names = results.map(r => r.source.name);
|
|
||||||
|
|
||||||
const exports = {};
|
|
||||||
for (const name of names) {
|
|
||||||
const matches = await opensrc.astGrep(name, "export const $NAME = $_", {
|
|
||||||
lang: "ts",
|
|
||||||
limit: 30
|
|
||||||
});
|
|
||||||
exports[name] = matches.map(m => m.metavars.NAME);
|
|
||||||
}
|
|
||||||
return exports;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### grep vs astGrep
|
|
||||||
|
|
||||||
| Use Case | Tool |
|
|
||||||
|----------|------|
|
|
||||||
| Text/regex pattern | `grep` |
|
|
||||||
| Function declarations | `astGrep`: `function $NAME($$$) { $$$ }` |
|
|
||||||
| Arrow functions | `astGrep`: `const $N = ($$$) => $_` |
|
|
||||||
| Class definitions | `astGrep`: `class $NAME extends $PARENT` |
|
|
||||||
| Import statements | `astGrep`: `import { $$$IMPORTS } from "$MOD"` |
|
|
||||||
| JSX components | `astGrep`: `<$COMP $$$PROPS />` |
|
|
||||||
|
|
||||||
## Repository Exploration
|
|
||||||
|
|
||||||
### Find Entry Points
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const name = "github.com/vercel/ai";
|
|
||||||
|
|
||||||
const allFiles = await opensrc.files(name, "**/*.{ts,js}");
|
|
||||||
const entryPoints = allFiles.filter(f =>
|
|
||||||
f.path.match(/^(src\/)?(index|main|mod)\.(ts|js)$/) ||
|
|
||||||
f.path.includes("/index.ts")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Read all entry points
|
|
||||||
const contents = {};
|
|
||||||
for (const ep of entryPoints.slice(0, 5)) {
|
|
||||||
contents[ep.path] = await opensrc.read(name, ep.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
totalFiles: allFiles.length,
|
|
||||||
entryPoints: entryPoints.map(f => f.path),
|
|
||||||
contents
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Explore Package Structure
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const name = "zod";
|
|
||||||
|
|
||||||
// Get all TypeScript files
|
|
||||||
const tsFiles = await opensrc.files(name, "**/*.ts");
|
|
||||||
|
|
||||||
// Group by directory
|
|
||||||
const byDir = {};
|
|
||||||
for (const f of tsFiles) {
|
|
||||||
const dir = f.path.split("/").slice(0, -1).join("/") || ".";
|
|
||||||
byDir[dir] = (byDir[dir] || 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read key files
|
|
||||||
const pkg = await opensrc.read(name, "package.json");
|
|
||||||
const readme = await opensrc.read(name, "README.md");
|
|
||||||
|
|
||||||
return {
|
|
||||||
structure: byDir,
|
|
||||||
package: JSON.parse(pkg),
|
|
||||||
readmePreview: readme.slice(0, 500)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Batch Operations
|
|
||||||
|
|
||||||
### Read Many with Error Handling
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const files = await opensrc.readMany("zod", [
|
|
||||||
"src/index.ts",
|
|
||||||
"src/types.ts",
|
|
||||||
"src/ZodError.ts",
|
|
||||||
"src/helpers/parseUtil.ts"
|
|
||||||
]);
|
|
||||||
|
|
||||||
// files is Record<string, string> - errors start with "[Error:"
|
|
||||||
const successful = Object.entries(files)
|
|
||||||
.filter(([_, content]) => !content.startsWith("[Error:"))
|
|
||||||
.map(([path, content]) => ({ path, lines: content.split("\n").length }));
|
|
||||||
|
|
||||||
return successful;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Parallel Grep Across Multiple Sources
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
async () => {
|
|
||||||
const targets = ["zod", "valibot"];
|
|
||||||
const pattern = "export (type|interface)";
|
|
||||||
|
|
||||||
const results = await Promise.all(
|
|
||||||
targets.map(async (name) => {
|
|
||||||
const matches = await opensrc.grep(pattern, {
|
|
||||||
sources: [name],
|
|
||||||
include: "*.ts",
|
|
||||||
maxResults: 50
|
|
||||||
});
|
|
||||||
return { name, count: matches.length, matches };
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Workflow Checklist
|
|
||||||
|
|
||||||
### Comprehensive Repository Analysis
|
|
||||||
|
|
||||||
```
|
|
||||||
Repository Analysis Progress:
|
|
||||||
- [ ] 1. Fetch repository
|
|
||||||
- [ ] 2. Read package.json + README
|
|
||||||
- [ ] 3. Identify entry points (src/index.*)
|
|
||||||
- [ ] 4. Read main entry file
|
|
||||||
- [ ] 5. Map exports and public API
|
|
||||||
- [ ] 6. Trace key functionality
|
|
||||||
- [ ] 7. Create architecture diagram
|
|
||||||
```
|
|
||||||
|
|
||||||
### Library Comparison
|
|
||||||
|
|
||||||
```
|
|
||||||
Comparison Progress:
|
|
||||||
- [ ] 1. Fetch all libraries
|
|
||||||
- [ ] 2. Grep for target pattern in each
|
|
||||||
- [ ] 3. Read matching implementations
|
|
||||||
- [ ] 4. Create comparison table
|
|
||||||
- [ ] 5. Synthesize findings
|
|
||||||
```
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
# Tool Routing
|
|
||||||
|
|
||||||
## Decision Flowchart
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
Q[User Query] --> T{Query Type?}
|
|
||||||
T -->|Understand/Explain| U[UNDERSTAND]
|
|
||||||
T -->|Find/Search| F[FIND]
|
|
||||||
T -->|Explore/Architecture| E[EXPLORE]
|
|
||||||
T -->|Compare| C[COMPARE]
|
|
||||||
|
|
||||||
U --> U1{Known library?}
|
|
||||||
U1 -->|Yes| U2[context7.resolve-library-id]
|
|
||||||
U2 --> U3[context7.query-docs]
|
|
||||||
U3 --> U4{Need source?}
|
|
||||||
U4 -->|Yes| U5[opensrc.fetch → read]
|
|
||||||
U1 -->|No| U6[grep_app → opensrc.fetch]
|
|
||||||
|
|
||||||
F --> F1{Specific repo?}
|
|
||||||
F1 -->|Yes| F2[opensrc.fetch → grep → read]
|
|
||||||
F1 -->|No| F3[grep_app broad search]
|
|
||||||
F3 --> F4[opensrc.fetch interesting repos]
|
|
||||||
|
|
||||||
E --> E1[opensrc.fetch]
|
|
||||||
E1 --> E2[opensrc.files]
|
|
||||||
E2 --> E3[Read entry points]
|
|
||||||
E3 --> E4[Create diagram]
|
|
||||||
|
|
||||||
C --> C1["opensrc.fetch([X, Y])"]
|
|
||||||
C1 --> C2[grep same pattern]
|
|
||||||
C2 --> C3[Read comparable files]
|
|
||||||
C3 --> C4[Synthesize comparison]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Query Type Detection
|
|
||||||
|
|
||||||
| Keywords | Query Type | Start With |
|
|
||||||
|----------|------------|------------|
|
|
||||||
| "how does", "why does", "explain", "purpose of" | UNDERSTAND | context7 |
|
|
||||||
| "find", "where is", "implementations of", "examples of" | FIND | grep_app |
|
|
||||||
| "explore", "walk through", "architecture", "structure" | EXPLORE | opensrc |
|
|
||||||
| "compare", "vs", "difference between" | COMPARE | opensrc |
|
|
||||||
|
|
||||||
## UNDERSTAND Queries
|
|
||||||
|
|
||||||
```
|
|
||||||
Known library? → context7.resolve-library-id → context7.query-docs
|
|
||||||
└─ Need source? → opensrc.fetch → read
|
|
||||||
|
|
||||||
Unknown? → grep_app search → opensrc.fetch top result → read
|
|
||||||
```
|
|
||||||
|
|
||||||
**When to transition context7 → opensrc:**
|
|
||||||
- Need implementation details (not just API docs)
|
|
||||||
- Question about internals/private methods
|
|
||||||
- Tracing code flow through library
|
|
||||||
|
|
||||||
## FIND Queries
|
|
||||||
|
|
||||||
```
|
|
||||||
Specific repo? → opensrc.fetch → opensrc.grep → read matches
|
|
||||||
|
|
||||||
Broad search? → grep_app → analyze → opensrc.fetch interesting repos
|
|
||||||
```
|
|
||||||
|
|
||||||
**grep_app query tips:**
|
|
||||||
- Use literal code patterns: `useState(` not "react hooks"
|
|
||||||
- Filter by language: `language: ["TypeScript"]`
|
|
||||||
- Narrow by repo: `repo: "vercel/"` for org
|
|
||||||
|
|
||||||
## EXPLORE Queries
|
|
||||||
|
|
||||||
```
|
|
||||||
1. opensrc.fetch(target)
|
|
||||||
2. opensrc.files → understand structure
|
|
||||||
3. Identify entry points: README, package.json, src/index.*
|
|
||||||
4. Read entry → internals
|
|
||||||
5. Create architecture diagram
|
|
||||||
```
|
|
||||||
|
|
||||||
## COMPARE Queries
|
|
||||||
|
|
||||||
```
|
|
||||||
1. opensrc.fetch([X, Y])
|
|
||||||
2. Extract source.name from each result
|
|
||||||
3. opensrc.grep same pattern in both
|
|
||||||
4. Read comparable files
|
|
||||||
5. Synthesize → comparison table
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tool Capabilities
|
|
||||||
|
|
||||||
| Tool | Best For | Not For |
|
|
||||||
|------|----------|---------|
|
|
||||||
| **grep_app** | Broad search, unknown scope, finding repos | Semantic queries |
|
|
||||||
| **context7** | Library APIs, best practices, common patterns | Library internals |
|
|
||||||
| **opensrc** | Deep exploration, reading internals, tracing flow | Initial discovery |
|
|
||||||
|
|
||||||
## Anti-patterns
|
|
||||||
|
|
||||||
| Don't | Do |
|
|
||||||
|-------|-----|
|
|
||||||
| grep_app for known library docs | context7 first |
|
|
||||||
| opensrc.fetch before knowing target | grep_app to discover |
|
|
||||||
| Multiple small reads | opensrc.readMany batch |
|
|
||||||
| Describe without linking | Link every file ref |
|
|
||||||
| Text for complex relationships | Mermaid diagram |
|
|
||||||
| Use tool names in responses | "I'll search..." not "I'll use opensrc" |
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
---
|
|
||||||
name: session-export
|
|
||||||
description: Update GitHub PR descriptions with AI session export summaries. Use when user asks to add session summary to PR/MR, document AI assistance in PR/MR, or export conversation summary to PR/MR description.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Session Export
|
|
||||||
|
|
||||||
Update PR/MR descriptions with a structured summary of the AI-assisted conversation.
|
|
||||||
|
|
||||||
## Output Format
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
> [!NOTE]
|
|
||||||
> This PR was written with AI assistance.
|
|
||||||
|
|
||||||
<details><summary>AI Session Export</summary>
|
|
||||||
<p>
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"info": {
|
|
||||||
"title": "<brief task description>",
|
|
||||||
"agent": "opencode",
|
|
||||||
"models": ["<model(s) used>"]
|
|
||||||
},
|
|
||||||
"summary": [
|
|
||||||
"<action 1>",
|
|
||||||
"<action 2>",
|
|
||||||
...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</details>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### 1. Export Session Data
|
|
||||||
|
|
||||||
Get session data using OpenCode CLI:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
opencode export [sessionID]
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns JSON with session info including models used. Use current session if no sessionID provided.
|
|
||||||
|
|
||||||
### 2. Generate Summary JSON
|
|
||||||
|
|
||||||
From exported data and conversation context, create summary:
|
|
||||||
|
|
||||||
- **title**: 2-5 word task description (lowercase)
|
|
||||||
- **agent**: always "opencode"
|
|
||||||
- **models**: array from export data
|
|
||||||
- **summary**: array of terse action statements
|
|
||||||
- Use past tense ("added", "fixed", "created")
|
|
||||||
- Start with "user requested..." or "user asked..."
|
|
||||||
- Chronological order
|
|
||||||
- Attempt to keep the summary to a max of 25 turns ("user requested", "agent did")
|
|
||||||
- **NEVER include sensitive data**: API keys, credentials, secrets, tokens, passwords, env vars
|
|
||||||
|
|
||||||
### 3. Update PR/MR Description
|
|
||||||
|
|
||||||
**GitHub:**
|
|
||||||
```bash
|
|
||||||
gh pr edit <PR_NUMBER> --body "$(cat <<'EOF'
|
|
||||||
<existing description>
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This PR was written with AI assistance.
|
|
||||||
|
|
||||||
<details><summary>AI Session Export</summary>
|
|
||||||
...
|
|
||||||
</details>
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Preserve Existing Content
|
|
||||||
|
|
||||||
Always fetch and preserve existing PR/MR description:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# GitHub
|
|
||||||
gh pr view <PR_NUMBER> --json body -q '.body'
|
|
||||||
|
|
||||||
Append session export after existing content with blank line separator.
|
|
||||||
|
|
||||||
## Example Summary
|
|
||||||
|
|
||||||
For a session where user asked to add dark mode:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"info": {
|
|
||||||
"title": "dark mode implementation",
|
|
||||||
"agent": "opencode",
|
|
||||||
"models": ["claude sonnet 4"]
|
|
||||||
},
|
|
||||||
"summary": [
|
|
||||||
"user requested dark mode toggle in settings",
|
|
||||||
"agent explored existing theme system",
|
|
||||||
"agent created ThemeContext for state management",
|
|
||||||
"agent added DarkModeToggle component",
|
|
||||||
"agent updated CSS variables for dark theme",
|
|
||||||
"agent ran tests and fixed 2 failures",
|
|
||||||
"agent committed changes"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security
|
|
||||||
|
|
||||||
**NEVER include in summary:**
|
|
||||||
- API keys, tokens, secrets
|
|
||||||
- Passwords, credentials
|
|
||||||
- Environment variable values
|
|
||||||
- Private URLs with auth tokens
|
|
||||||
- Personal identifiable information
|
|
||||||
- Internal hostnames/IPs
|
|
||||||
@@ -61,7 +61,7 @@ in {
|
|||||||
opensrc = {
|
opensrc = {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
type = "local";
|
type = "local";
|
||||||
command = ["opensrc-mcp"];
|
command = ["node" "/home/cschmatzler/.bun/bin/opensrc-mcp"];
|
||||||
};
|
};
|
||||||
context7 = {
|
context7 = {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user