summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--js/OpenCode.md27
-rw-r--r--js/src/tool/grep.ts54
-rw-r--r--js/src/tool/ls.ts5
3 files changed, 56 insertions, 30 deletions
diff --git a/js/OpenCode.md b/js/OpenCode.md
new file mode 100644
index 000000000..7def6f8c7
--- /dev/null
+++ b/js/OpenCode.md
@@ -0,0 +1,27 @@
+# OpenCode Context
+
+## Build/Test Commands
+
+- `bun install` - Install dependencies
+- `bun run index.ts` - Run the application
+- `bun build src/index.ts --compile --outfile ./dist/opencode` - Build executable
+- `bun test` - Run all tests
+- `bun test <pattern>` - Run specific test files
+- `bun test --test-name-pattern <regex>` - Run tests matching pattern
+
+## Code Style & Conventions
+
+- TypeScript with Bun runtime
+- ES modules (`"type": "module"`)
+- Namespace-based organization (e.g., `Tool.define`, `App.provide`)
+- Zod for schema validation and type safety
+- Async/await patterns throughout
+- Structured logging with service-based loggers (`Log.create({ service: "name" })`)
+- Tool pattern: define tools with `Tool.define()` wrapper for metadata/timing
+- Context pattern: use `Context.create()` for dependency injection
+- Import style: Node.js built-ins with `node:` prefix, relative imports with explicit extensions
+- Error handling: try/catch with structured logging
+- File organization: group by feature in `src/` with index files for exports
+- Test files: co-located in `test/` directory, use Bun's built-in test runner
+- Naming: camelCase for variables/functions, PascalCase for namespaces/types
+- **Variable declarations: Prefer `const` over `let` unless reassignment is necessary** \ No newline at end of file
diff --git a/js/src/tool/grep.ts b/js/src/tool/grep.ts
index b67a4790e..21f242244 100644
--- a/js/src/tool/grep.ts
+++ b/js/src/tool/grep.ts
@@ -81,7 +81,7 @@ function globToRegex(glob: string): string {
regexPattern = regexPattern.replaceAll("?", ".");
// Handle {a,b,c} patterns
- regexPattern = regexPattern.replace(/\{([^}]+)\}/g, (match, inner) => {
+ regexPattern = regexPattern.replace(/\{([^}]+)\}/g, (_, inner) => {
return "(" + inner.replace(/,/g, "|") + ")";
});
@@ -301,36 +301,36 @@ export const grep = Tool.define({
100,
);
- let output: string;
if (matches.length === 0) {
- output = "No files found";
- } else {
- const lines = [`Found ${matches.length} matches`];
-
- let currentFile = "";
- for (const match of matches) {
- if (currentFile !== match.path) {
- if (currentFile !== "") {
- lines.push("");
- }
- currentFile = match.path;
- lines.push(`${match.path}:`);
- }
- if (match.lineNum > 0) {
- lines.push(` Line ${match.lineNum}: ${match.lineText}`);
- } else {
- lines.push(` ${match.path}`);
+ return {
+ metadata: { matches: 0, truncated },
+ output: "No files found"
+ };
+ }
+
+ const lines = [`Found ${matches.length} matches`];
+
+ let currentFile = "";
+ for (const match of matches) {
+ if (currentFile !== match.path) {
+ if (currentFile !== "") {
+ lines.push("");
}
+ currentFile = match.path;
+ lines.push(`${match.path}:`);
}
-
- if (truncated) {
- lines.push("");
- lines.push(
- "(Results are truncated. Consider using a more specific path or pattern.)",
- );
+ if (match.lineNum > 0) {
+ lines.push(` Line ${match.lineNum}: ${match.lineText}`);
+ } else {
+ lines.push(` ${match.path}`);
}
+ }
- output = lines.join("\n");
+ if (truncated) {
+ lines.push("");
+ lines.push(
+ "(Results are truncated. Consider using a more specific path or pattern.)",
+ );
}
return {
@@ -338,7 +338,7 @@ export const grep = Tool.define({
matches: matches.length,
truncated,
},
- output,
+ output: lines.join("\n"),
};
},
});
diff --git a/js/src/tool/ls.ts b/js/src/tool/ls.ts
index 286ac30a2..c481b4d8d 100644
--- a/js/src/tool/ls.ts
+++ b/js/src/tool/ls.ts
@@ -125,12 +125,11 @@ async function listDirectory(
results.push(fullPath + path.sep);
}
- if (results.length < limit) {
- await walk(fullPath);
- } else {
+ if (results.length >= limit) {
truncated = true;
return;
}
+ await walk(fullPath);
} else if (entry.isFile()) {
if (fullPath !== initialPath) {
results.push(fullPath);