Files
everything-claude-code/.opencode/tools/run-tests.ts
Affaan Mustafa 6c2e0eace8 fix: update opencode-ecc plugin for SDK v1.1.53 and refresh README stats
- Fix PluginContext → PluginInput type rename in @opencode-ai/plugin
- Import tool from @opencode-ai/plugin/tool subpath (fixes broken barrel export)
- Update client.app.log() calls to use new options-object API signature
- Stringify tool execute return values (SDK now requires Promise<string>)
- Add .js extensions to relative imports for NodeNext module resolution
- Update README star count (42K+) and contributor count (24)
2026-02-09 01:32:22 -08:00

140 lines
3.4 KiB
TypeScript

/**
* Run Tests Tool
*
* Custom OpenCode tool to run test suites with various options.
* Automatically detects the package manager and test framework.
*/
import { tool } from "@opencode-ai/plugin/tool"
import * as path from "path"
import * as fs from "fs"
export default tool({
description:
"Run the test suite with optional coverage, watch mode, or specific test patterns. Automatically detects package manager (npm, pnpm, yarn, bun) and test framework.",
args: {
pattern: tool.schema
.string()
.optional()
.describe("Test file pattern or specific test name to run"),
coverage: tool.schema
.boolean()
.optional()
.describe("Run with coverage reporting (default: false)"),
watch: tool.schema
.boolean()
.optional()
.describe("Run in watch mode for continuous testing (default: false)"),
updateSnapshots: tool.schema
.boolean()
.optional()
.describe("Update Jest/Vitest snapshots (default: false)"),
},
async execute(args, context) {
const { pattern, coverage, watch, updateSnapshots } = args
const cwd = context.worktree || context.directory
// Detect package manager
const packageManager = await detectPackageManager(cwd)
// Detect test framework
const testFramework = await detectTestFramework(cwd)
// Build command
let cmd: string[] = [packageManager]
if (packageManager === "npm") {
cmd.push("run", "test")
} else {
cmd.push("test")
}
// Add options based on framework
const testArgs: string[] = []
if (coverage) {
testArgs.push("--coverage")
}
if (watch) {
testArgs.push("--watch")
}
if (updateSnapshots) {
testArgs.push("-u")
}
if (pattern) {
if (testFramework === "jest" || testFramework === "vitest") {
testArgs.push("--testPathPattern", pattern)
} else {
testArgs.push(pattern)
}
}
// Add -- separator for npm
if (testArgs.length > 0) {
if (packageManager === "npm") {
cmd.push("--")
}
cmd.push(...testArgs)
}
const command = cmd.join(" ")
return JSON.stringify({
command,
packageManager,
testFramework,
options: {
pattern: pattern || "all tests",
coverage: coverage || false,
watch: watch || false,
updateSnapshots: updateSnapshots || false,
},
instructions: `Run this command to execute tests:\n\n${command}`,
})
},
})
async function detectPackageManager(cwd: string): Promise<string> {
const lockFiles: Record<string, string> = {
"bun.lockb": "bun",
"pnpm-lock.yaml": "pnpm",
"yarn.lock": "yarn",
"package-lock.json": "npm",
}
for (const [lockFile, pm] of Object.entries(lockFiles)) {
if (fs.existsSync(path.join(cwd, lockFile))) {
return pm
}
}
return "npm"
}
async function detectTestFramework(cwd: string): Promise<string> {
const packageJsonPath = path.join(cwd, "package.json")
if (fs.existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"))
const deps = {
...packageJson.dependencies,
...packageJson.devDependencies,
}
if (deps.vitest) return "vitest"
if (deps.jest) return "jest"
if (deps.mocha) return "mocha"
if (deps.ava) return "ava"
if (deps.tap) return "tap"
} catch {
// Ignore parse errors
}
}
return "unknown"
}