opencodekit 0.13.2 ā 0.14.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/dist/index.js +16 -4
- package/dist/template/.opencode/AGENTS.md +13 -4
- package/dist/template/.opencode/README.md +98 -2
- package/dist/template/.opencode/command/brainstorm.md +25 -2
- package/dist/template/.opencode/command/finish.md +21 -4
- package/dist/template/.opencode/command/handoff.md +17 -0
- package/dist/template/.opencode/command/implement.md +38 -0
- package/dist/template/.opencode/command/plan.md +32 -0
- package/dist/template/.opencode/command/research.md +61 -5
- package/dist/template/.opencode/command/resume.md +31 -0
- package/dist/template/.opencode/command/start.md +31 -0
- package/dist/template/.opencode/command/triage.md +16 -1
- package/dist/template/.opencode/memory/observations/.gitkeep +0 -0
- package/dist/template/.opencode/memory/project/conventions.md +31 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/_transactions/0-8d00d272-cb80-463b-9774-7120a1c994e7.txn +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/_transactions/1-a3bea825-dad3-47dd-a6d6-ff41b76ff7b0.txn +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/_versions/1.manifest +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/_versions/2.manifest +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/data/001010101000000101110001f998d04b63936ff83f9a34152d.lance +0 -0
- package/dist/template/.opencode/memory/vector_db/memories.lance/data/010000101010000000010010701b3840d38c2b5f275da99978.lance +0 -0
- package/dist/template/.opencode/opencode.json +587 -523
- package/dist/template/.opencode/package.json +3 -1
- package/dist/template/.opencode/plugin/memory.ts +610 -0
- package/dist/template/.opencode/tool/memory-embed.ts +183 -0
- package/dist/template/.opencode/tool/memory-index.ts +769 -0
- package/dist/template/.opencode/tool/memory-search.ts +358 -66
- package/dist/template/.opencode/tool/observation.ts +301 -12
- package/dist/template/.opencode/tool/repo-map.ts +451 -0
- package/package.json +16 -4
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { tool } from "@opencode-ai/plugin";
|
|
6
|
+
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
|
|
9
|
+
interface CodeSymbol {
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
line: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface FileNode {
|
|
16
|
+
name: string;
|
|
17
|
+
path: string;
|
|
18
|
+
symbols: CodeSymbol[];
|
|
19
|
+
children: Map<string, FileNode>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// AST-grep patterns for quick symbol extraction
|
|
23
|
+
const QUICK_PATTERNS: Record<string, { lang: string; pattern: string }[]> = {
|
|
24
|
+
ts: [
|
|
25
|
+
{ lang: "typescript", pattern: "function $NAME($$$)" },
|
|
26
|
+
{ lang: "typescript", pattern: "const $NAME = ($$$) =>" },
|
|
27
|
+
{ lang: "typescript", pattern: "class $NAME" },
|
|
28
|
+
{ lang: "typescript", pattern: "interface $NAME" },
|
|
29
|
+
{ lang: "typescript", pattern: "type $NAME =" },
|
|
30
|
+
{ lang: "typescript", pattern: "export function $NAME($$$)" },
|
|
31
|
+
{ lang: "typescript", pattern: "export const $NAME" },
|
|
32
|
+
],
|
|
33
|
+
tsx: [
|
|
34
|
+
{ lang: "tsx", pattern: "function $NAME($$$)" },
|
|
35
|
+
{ lang: "tsx", pattern: "export function $NAME($$$)" },
|
|
36
|
+
],
|
|
37
|
+
js: [
|
|
38
|
+
{ lang: "javascript", pattern: "function $NAME($$$)" },
|
|
39
|
+
{ lang: "javascript", pattern: "const $NAME = ($$$) =>" },
|
|
40
|
+
{ lang: "javascript", pattern: "class $NAME" },
|
|
41
|
+
],
|
|
42
|
+
jsx: [
|
|
43
|
+
{ lang: "javascript", pattern: "function $NAME($$$)" },
|
|
44
|
+
{ lang: "javascript", pattern: "export function $NAME($$$)" },
|
|
45
|
+
],
|
|
46
|
+
py: [
|
|
47
|
+
{ lang: "python", pattern: "def $NAME($$$):" },
|
|
48
|
+
{ lang: "python", pattern: "class $NAME:" },
|
|
49
|
+
{ lang: "python", pattern: "class $NAME($$$):" },
|
|
50
|
+
],
|
|
51
|
+
go: [
|
|
52
|
+
{ lang: "go", pattern: "func $NAME($$$)" },
|
|
53
|
+
{ lang: "go", pattern: "type $NAME struct" },
|
|
54
|
+
{ lang: "go", pattern: "type $NAME interface" },
|
|
55
|
+
],
|
|
56
|
+
rs: [
|
|
57
|
+
{ lang: "rust", pattern: "fn $NAME($$$)" },
|
|
58
|
+
{ lang: "rust", pattern: "struct $NAME" },
|
|
59
|
+
{ lang: "rust", pattern: "enum $NAME" },
|
|
60
|
+
{ lang: "rust", pattern: "trait $NAME" },
|
|
61
|
+
{ lang: "rust", pattern: "impl $NAME" },
|
|
62
|
+
],
|
|
63
|
+
rb: [
|
|
64
|
+
{ lang: "ruby", pattern: "def $NAME" },
|
|
65
|
+
{ lang: "ruby", pattern: "class $NAME" },
|
|
66
|
+
{ lang: "ruby", pattern: "module $NAME" },
|
|
67
|
+
],
|
|
68
|
+
ex: [
|
|
69
|
+
{ lang: "elixir", pattern: "def $NAME($$$) do" },
|
|
70
|
+
{ lang: "elixir", pattern: "defmodule $NAME do" },
|
|
71
|
+
],
|
|
72
|
+
java: [
|
|
73
|
+
{ lang: "java", pattern: "class $NAME" },
|
|
74
|
+
{ lang: "java", pattern: "interface $NAME" },
|
|
75
|
+
],
|
|
76
|
+
kt: [
|
|
77
|
+
{ lang: "kotlin", pattern: "fun $NAME($$$)" },
|
|
78
|
+
{ lang: "kotlin", pattern: "class $NAME" },
|
|
79
|
+
],
|
|
80
|
+
swift: [
|
|
81
|
+
{ lang: "swift", pattern: "func $NAME($$$)" },
|
|
82
|
+
{ lang: "swift", pattern: "class $NAME" },
|
|
83
|
+
{ lang: "swift", pattern: "struct $NAME" },
|
|
84
|
+
],
|
|
85
|
+
php: [
|
|
86
|
+
{ lang: "php", pattern: "function $NAME($$$)" },
|
|
87
|
+
{ lang: "php", pattern: "class $NAME" },
|
|
88
|
+
],
|
|
89
|
+
c: [{ lang: "c", pattern: "struct $NAME" }],
|
|
90
|
+
cpp: [
|
|
91
|
+
{ lang: "cpp", pattern: "class $NAME" },
|
|
92
|
+
{ lang: "cpp", pattern: "struct $NAME" },
|
|
93
|
+
],
|
|
94
|
+
cs: [
|
|
95
|
+
{ lang: "csharp", pattern: "class $NAME" },
|
|
96
|
+
{ lang: "csharp", pattern: "interface $NAME" },
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
async function extractSymbols(
|
|
101
|
+
filePath: string,
|
|
102
|
+
): Promise<{ symbols: CodeSymbol[]; error?: string }> {
|
|
103
|
+
const symbols: CodeSymbol[] = [];
|
|
104
|
+
|
|
105
|
+
const ext = path.extname(filePath).slice(1);
|
|
106
|
+
const patterns = QUICK_PATTERNS[ext];
|
|
107
|
+
|
|
108
|
+
if (!patterns) {
|
|
109
|
+
return { symbols };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const { lang, pattern } of patterns) {
|
|
113
|
+
try {
|
|
114
|
+
const { stdout } = await execAsync(
|
|
115
|
+
`sg --pattern '${pattern}' --lang ${lang} --json "${filePath}"`,
|
|
116
|
+
{ maxBuffer: 5 * 1024 * 1024 },
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (!stdout.trim()) continue;
|
|
120
|
+
|
|
121
|
+
const matches = JSON.parse(stdout) as Array<{
|
|
122
|
+
range: { start: { line: number } };
|
|
123
|
+
metaVariables?: { single?: { NAME?: { text: string } } };
|
|
124
|
+
}>;
|
|
125
|
+
|
|
126
|
+
for (const match of matches) {
|
|
127
|
+
const name = match.metaVariables?.single?.NAME?.text;
|
|
128
|
+
if (name && !symbols.some((s) => s.name === name)) {
|
|
129
|
+
symbols.push({
|
|
130
|
+
name,
|
|
131
|
+
type: getSymbolType(pattern),
|
|
132
|
+
line: match.range.start.line,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// Pattern didn't match, continue
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Sort by line number
|
|
142
|
+
symbols.sort((a, b) => a.line - b.line);
|
|
143
|
+
|
|
144
|
+
return { symbols };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getSymbolType(pattern: string): string {
|
|
148
|
+
if (pattern.includes("class")) return "class";
|
|
149
|
+
if (pattern.includes("interface")) return "interface";
|
|
150
|
+
if (pattern.includes("struct")) return "struct";
|
|
151
|
+
if (pattern.includes("enum")) return "enum";
|
|
152
|
+
if (pattern.includes("trait")) return "trait";
|
|
153
|
+
if (pattern.includes("module")) return "module";
|
|
154
|
+
if (pattern.includes("type")) return "type";
|
|
155
|
+
if (pattern.includes("const")) return "const";
|
|
156
|
+
if (pattern.includes("def ")) return "fn";
|
|
157
|
+
if (pattern.includes("func ")) return "fn";
|
|
158
|
+
if (pattern.includes("fn ")) return "fn";
|
|
159
|
+
if (pattern.includes("function")) return "fn";
|
|
160
|
+
return "symbol";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function findSourceFiles(dir: string, maxDepth = 5): Promise<string[]> {
|
|
164
|
+
const files: string[] = [];
|
|
165
|
+
const extensions = Object.keys(QUICK_PATTERNS);
|
|
166
|
+
|
|
167
|
+
async function walk(currentDir: string, depth: number) {
|
|
168
|
+
if (depth > maxDepth) return;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
172
|
+
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
175
|
+
|
|
176
|
+
// Skip common non-source directories
|
|
177
|
+
if (entry.isDirectory()) {
|
|
178
|
+
if (
|
|
179
|
+
entry.name === "node_modules" ||
|
|
180
|
+
entry.name === ".git" ||
|
|
181
|
+
entry.name === "dist" ||
|
|
182
|
+
entry.name === "build" ||
|
|
183
|
+
entry.name === ".next" ||
|
|
184
|
+
entry.name === "__pycache__" ||
|
|
185
|
+
entry.name === "target" ||
|
|
186
|
+
entry.name === "vendor" ||
|
|
187
|
+
entry.name.startsWith(".")
|
|
188
|
+
) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
await walk(fullPath, depth + 1);
|
|
192
|
+
} else {
|
|
193
|
+
const ext = path.extname(entry.name).slice(1);
|
|
194
|
+
if (extensions.includes(ext)) {
|
|
195
|
+
files.push(fullPath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch {
|
|
200
|
+
// Directory not readable
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
await walk(dir, 0);
|
|
205
|
+
return files;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function buildTree(
|
|
209
|
+
files: Array<{ path: string; symbols: CodeSymbol[] }>,
|
|
210
|
+
baseDir: string,
|
|
211
|
+
): FileNode {
|
|
212
|
+
const root: FileNode = {
|
|
213
|
+
name: path.basename(baseDir),
|
|
214
|
+
path: baseDir,
|
|
215
|
+
symbols: [],
|
|
216
|
+
children: new Map(),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
for (const file of files) {
|
|
220
|
+
const relativePath = path.relative(baseDir, file.path);
|
|
221
|
+
const parts = relativePath.split(path.sep);
|
|
222
|
+
|
|
223
|
+
let current = root;
|
|
224
|
+
for (let i = 0; i < parts.length; i++) {
|
|
225
|
+
const part = parts[i];
|
|
226
|
+
const isFile = i === parts.length - 1;
|
|
227
|
+
|
|
228
|
+
if (!current.children.has(part)) {
|
|
229
|
+
current.children.set(part, {
|
|
230
|
+
name: part,
|
|
231
|
+
path: path.join(baseDir, ...parts.slice(0, i + 1)),
|
|
232
|
+
symbols: isFile ? file.symbols : [],
|
|
233
|
+
children: new Map(),
|
|
234
|
+
});
|
|
235
|
+
} else if (isFile) {
|
|
236
|
+
const node = current.children.get(part);
|
|
237
|
+
if (node) {
|
|
238
|
+
node.symbols = file.symbols;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const next = current.children.get(part);
|
|
243
|
+
if (next) {
|
|
244
|
+
current = next;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return root;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function renderTree(
|
|
253
|
+
node: FileNode,
|
|
254
|
+
prefix = "",
|
|
255
|
+
isLast = true,
|
|
256
|
+
isRoot = true,
|
|
257
|
+
): string {
|
|
258
|
+
const lines: string[] = [];
|
|
259
|
+
|
|
260
|
+
if (!isRoot) {
|
|
261
|
+
const connector = isLast ? "āāā " : "āāā ";
|
|
262
|
+
const symbolList =
|
|
263
|
+
node.symbols.length > 0
|
|
264
|
+
? ` (${node.symbols.map((s) => s.name).join(", ")})`
|
|
265
|
+
: "";
|
|
266
|
+
lines.push(`${prefix}${connector}${node.name}${symbolList}`);
|
|
267
|
+
} else {
|
|
268
|
+
lines.push(`${node.name}/`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const children = Array.from(node.children.values());
|
|
272
|
+
// Sort: directories first, then files
|
|
273
|
+
children.sort((a, b) => {
|
|
274
|
+
const aIsDir = a.children.size > 0;
|
|
275
|
+
const bIsDir = b.children.size > 0;
|
|
276
|
+
if (aIsDir && !bIsDir) return -1;
|
|
277
|
+
if (!aIsDir && bIsDir) return 1;
|
|
278
|
+
return a.name.localeCompare(b.name);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
for (let i = 0; i < children.length; i++) {
|
|
282
|
+
const child = children[i];
|
|
283
|
+
const childIsLast = i === children.length - 1;
|
|
284
|
+
const newPrefix = isRoot ? "" : prefix + (isLast ? " " : "ā ");
|
|
285
|
+
lines.push(renderTree(child, newPrefix, childIsLast, false));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return lines.join("\n");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function renderCompact(
|
|
292
|
+
files: Array<{ path: string; symbols: CodeSymbol[] }>,
|
|
293
|
+
baseDir: string,
|
|
294
|
+
): string {
|
|
295
|
+
const lines: string[] = [];
|
|
296
|
+
|
|
297
|
+
// Group by directory
|
|
298
|
+
const byDir = new Map<string, Array<{ name: string; symbols: string[] }>>();
|
|
299
|
+
|
|
300
|
+
for (const file of files) {
|
|
301
|
+
const relativePath = path.relative(baseDir, file.path);
|
|
302
|
+
const dir = path.dirname(relativePath);
|
|
303
|
+
const fileName = path.basename(relativePath);
|
|
304
|
+
|
|
305
|
+
if (!byDir.has(dir)) {
|
|
306
|
+
byDir.set(dir, []);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const dirFiles = byDir.get(dir);
|
|
310
|
+
if (dirFiles) {
|
|
311
|
+
dirFiles.push({
|
|
312
|
+
name: fileName,
|
|
313
|
+
symbols: file.symbols.map((s) => s.name),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Sort directories
|
|
319
|
+
const sortedDirs = Array.from(byDir.keys()).sort();
|
|
320
|
+
|
|
321
|
+
for (const dir of sortedDirs) {
|
|
322
|
+
const files = byDir.get(dir);
|
|
323
|
+
if (!files) continue;
|
|
324
|
+
|
|
325
|
+
lines.push(dir === "." ? "" : `${dir}/`);
|
|
326
|
+
|
|
327
|
+
for (const file of files) {
|
|
328
|
+
const symbolStr =
|
|
329
|
+
file.symbols.length > 0 ? ` ā ${file.symbols.join(", ")}` : "";
|
|
330
|
+
lines.push(` ${file.name}${symbolStr}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return lines.join("\n");
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export default tool({
|
|
338
|
+
description:
|
|
339
|
+
"Generate a compact repository map showing file structure with key symbols (functions, classes, etc). Inspired by Aider's repo-map. Great for understanding codebase structure.",
|
|
340
|
+
args: {
|
|
341
|
+
path: tool.schema
|
|
342
|
+
.string()
|
|
343
|
+
.optional()
|
|
344
|
+
.describe("Directory to map. Defaults to 'src' or current directory."),
|
|
345
|
+
format: tool.schema
|
|
346
|
+
.string()
|
|
347
|
+
.optional()
|
|
348
|
+
.describe(
|
|
349
|
+
"Output format: 'tree' (visual tree), 'compact' (grouped by dir), 'symbols-only' (just symbols). Default: tree",
|
|
350
|
+
),
|
|
351
|
+
maxDepth: tool.schema
|
|
352
|
+
.number()
|
|
353
|
+
.optional()
|
|
354
|
+
.describe("Maximum directory depth to traverse. Default: 5"),
|
|
355
|
+
includeSymbols: tool.schema
|
|
356
|
+
.boolean()
|
|
357
|
+
.optional()
|
|
358
|
+
.describe(
|
|
359
|
+
"Include symbol names in output. Default: true. Set false for structure only.",
|
|
360
|
+
),
|
|
361
|
+
},
|
|
362
|
+
async execute(args, _context) {
|
|
363
|
+
const { path: inputPath, format, maxDepth, includeSymbols } = args;
|
|
364
|
+
const targetDir = (inputPath as string) || (await getDefaultDir());
|
|
365
|
+
const depth = (maxDepth as number) ?? 5;
|
|
366
|
+
const showSymbols = includeSymbols !== false;
|
|
367
|
+
const outputFormat = (format as string) || "tree";
|
|
368
|
+
|
|
369
|
+
// Check if ast-grep is available
|
|
370
|
+
try {
|
|
371
|
+
await execAsync("sg --version");
|
|
372
|
+
} catch {
|
|
373
|
+
return "Error: ast-grep (sg) not installed. Run: npm install -g @ast-grep/cli";
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Find source files
|
|
377
|
+
const absPath = path.isAbsolute(targetDir)
|
|
378
|
+
? targetDir
|
|
379
|
+
: path.join(process.cwd(), targetDir);
|
|
380
|
+
|
|
381
|
+
try {
|
|
382
|
+
await fs.access(absPath);
|
|
383
|
+
} catch {
|
|
384
|
+
return `Error: Directory not found: ${targetDir}`;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const sourceFiles = await findSourceFiles(absPath, depth);
|
|
388
|
+
|
|
389
|
+
if (sourceFiles.length === 0) {
|
|
390
|
+
return `No source files found in ${targetDir}`;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Extract symbols if needed
|
|
394
|
+
const filesWithSymbols: Array<{ path: string; symbols: CodeSymbol[] }> = [];
|
|
395
|
+
|
|
396
|
+
for (const file of sourceFiles) {
|
|
397
|
+
if (showSymbols) {
|
|
398
|
+
const { symbols } = await extractSymbols(file);
|
|
399
|
+
filesWithSymbols.push({ path: file, symbols });
|
|
400
|
+
} else {
|
|
401
|
+
filesWithSymbols.push({ path: file, symbols: [] });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Sort by path
|
|
406
|
+
filesWithSymbols.sort((a, b) => a.path.localeCompare(b.path));
|
|
407
|
+
|
|
408
|
+
// Generate output
|
|
409
|
+
let output: string;
|
|
410
|
+
|
|
411
|
+
switch (outputFormat) {
|
|
412
|
+
case "compact":
|
|
413
|
+
output = renderCompact(filesWithSymbols, absPath);
|
|
414
|
+
break;
|
|
415
|
+
case "symbols-only": {
|
|
416
|
+
const symbolLines = filesWithSymbols
|
|
417
|
+
.filter((f) => f.symbols.length > 0)
|
|
418
|
+
.map((f) => {
|
|
419
|
+
const rel = path.relative(absPath, f.path);
|
|
420
|
+
return `${rel}: ${f.symbols.map((s) => s.name).join(", ")}`;
|
|
421
|
+
});
|
|
422
|
+
output = symbolLines.join("\n");
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
default: {
|
|
426
|
+
const tree = buildTree(filesWithSymbols, absPath);
|
|
427
|
+
output = renderTree(tree);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const stats = {
|
|
432
|
+
files: sourceFiles.length,
|
|
433
|
+
symbols: filesWithSymbols.reduce((sum, f) => sum + f.symbols.length, 0),
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
return `# Repository Map: ${path.basename(absPath)}\n\n${output}\n\n---\nš ${stats.files} files | š£ ${stats.symbols} symbols`;
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
async function getDefaultDir(): Promise<string> {
|
|
441
|
+
// Try common source directories
|
|
442
|
+
for (const dir of ["src", "lib", "app", "."]) {
|
|
443
|
+
try {
|
|
444
|
+
await fs.access(path.join(process.cwd(), dir));
|
|
445
|
+
return dir;
|
|
446
|
+
} catch {
|
|
447
|
+
// Continue to next
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return ".";
|
|
451
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencodekit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"bin": {
|
|
15
15
|
"ock": "dist/index.js"
|
|
16
16
|
},
|
|
17
|
-
"files": [
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
18
21
|
"scripts": {
|
|
19
22
|
"dev": "bun run src/index.ts",
|
|
20
23
|
"build": "bun run build.ts && mkdir -p dist/template && rsync -av --exclude=node_modules --exclude=dist --exclude=.git --exclude=coverage --exclude=.next --exclude=.turbo --exclude=logs --exclude=package-lock.json .opencode/ dist/template/.opencode/",
|
|
@@ -26,7 +29,14 @@
|
|
|
26
29
|
"lint": "biome check .",
|
|
27
30
|
"lint:fix": "biome check --fix ."
|
|
28
31
|
},
|
|
29
|
-
"keywords": [
|
|
32
|
+
"keywords": [
|
|
33
|
+
"cli",
|
|
34
|
+
"opencodekit",
|
|
35
|
+
"template",
|
|
36
|
+
"agents",
|
|
37
|
+
"mcp",
|
|
38
|
+
"opencode"
|
|
39
|
+
],
|
|
30
40
|
"author": "OpenCodeKit",
|
|
31
41
|
"license": "MIT",
|
|
32
42
|
"engines": {
|
|
@@ -52,5 +62,7 @@
|
|
|
52
62
|
"@types/node": "^22.10.1",
|
|
53
63
|
"typescript": "^5.7.2"
|
|
54
64
|
},
|
|
55
|
-
"trustedDependencies": [
|
|
65
|
+
"trustedDependencies": [
|
|
66
|
+
"@beads/bd"
|
|
67
|
+
]
|
|
56
68
|
}
|