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)
This commit is contained in:
Affaan Mustafa
2026-02-09 01:32:22 -08:00
parent 77bb669dc5
commit 6c2e0eace8
6 changed files with 37 additions and 34 deletions

View File

@@ -13,18 +13,21 @@
* - SessionEnd → session.deleted
*/
import type { PluginContext } from "@opencode-ai/plugin"
import type { PluginInput } from "@opencode-ai/plugin"
export const ECCHooksPlugin = async ({
project,
client,
$,
directory,
worktree,
}: PluginContext) => {
}: PluginInput) => {
// Track files edited in current session for console.log audit
const editedFiles = new Set<string>()
// Helper to call the SDK's log API with correct signature
const log = (level: "debug" | "info" | "warn" | "error", message: string) =>
client.app.log({ body: { service: "ecc", level, message } })
return {
/**
* Prettier Auto-Format Hook
@@ -41,7 +44,7 @@ export const ECCHooksPlugin = async ({
if (event.path.match(/\.(ts|tsx|js|jsx)$/)) {
try {
await $`prettier --write ${event.path} 2>/dev/null`
client.app.log("info", `[ECC] Formatted: ${event.path}`)
log("info", `[ECC] Formatted: ${event.path}`)
} catch {
// Prettier not installed or failed - silently continue
}
@@ -53,7 +56,7 @@ export const ECCHooksPlugin = async ({
const result = await $`grep -n "console\\.log" ${event.path} 2>/dev/null`.text()
if (result.trim()) {
const lines = result.trim().split("\n").length
client.app.log(
log(
"warn",
`[ECC] console.log found in ${event.path} (${lines} occurrence${lines > 1 ? "s" : ""})`
)
@@ -82,21 +85,21 @@ export const ECCHooksPlugin = async ({
) {
try {
await $`npx tsc --noEmit 2>&1`
client.app.log("info", "[ECC] TypeScript check passed")
log("info", "[ECC] TypeScript check passed")
} catch (error: unknown) {
const err = error as { stdout?: string }
client.app.log("warn", "[ECC] TypeScript errors detected:")
log("warn", "[ECC] TypeScript errors detected:")
if (err.stdout) {
// Log first few errors
const errors = err.stdout.split("\n").slice(0, 5)
errors.forEach((line: string) => client.app.log("warn", ` ${line}`))
errors.forEach((line: string) => log("warn", ` ${line}`))
}
}
}
// PR creation logging
if (input.tool === "bash" && input.args?.toString().includes("gh pr create")) {
client.app.log("info", "[ECC] PR created - check GitHub Actions status")
log("info", "[ECC] PR created - check GitHub Actions status")
}
},
@@ -115,7 +118,7 @@ export const ECCHooksPlugin = async ({
input.tool === "bash" &&
input.args?.toString().includes("git push")
) {
client.app.log(
log(
"info",
"[ECC] Remember to review changes before pushing: git diff origin/main...HEAD"
)
@@ -135,7 +138,7 @@ export const ECCHooksPlugin = async ({
!filePath.includes("LICENSE") &&
!filePath.includes("CONTRIBUTING")
) {
client.app.log(
log(
"warn",
`[ECC] Creating ${filePath} - consider if this documentation is necessary`
)
@@ -150,7 +153,7 @@ export const ECCHooksPlugin = async ({
cmd.match(/^cargo\s+(build|test|run)/) ||
cmd.match(/^go\s+(build|test|run)/)
) {
client.app.log(
log(
"info",
"[ECC] Long-running command detected - consider using background execution"
)
@@ -166,13 +169,13 @@ export const ECCHooksPlugin = async ({
* Action: Loads context and displays welcome message
*/
"session.created": async () => {
client.app.log("info", "[ECC] Session started - Everything Claude Code hooks active")
log("info", "[ECC] Session started - Everything Claude Code hooks active")
// Check for project-specific context files
try {
const hasClaudeMd = await $`test -f ${worktree}/CLAUDE.md && echo "yes"`.text()
if (hasClaudeMd.trim() === "yes") {
client.app.log("info", "[ECC] Found CLAUDE.md - loading project context")
log("info", "[ECC] Found CLAUDE.md - loading project context")
}
} catch {
// No CLAUDE.md found
@@ -189,7 +192,7 @@ export const ECCHooksPlugin = async ({
"session.idle": async () => {
if (editedFiles.size === 0) return
client.app.log("info", "[ECC] Session idle - running console.log audit")
log("info", "[ECC] Session idle - running console.log audit")
let totalConsoleLogCount = 0
const filesWithConsoleLogs: string[] = []
@@ -210,16 +213,16 @@ export const ECCHooksPlugin = async ({
}
if (totalConsoleLogCount > 0) {
client.app.log(
log(
"warn",
`[ECC] Audit: ${totalConsoleLogCount} console.log statement(s) in ${filesWithConsoleLogs.length} file(s)`
)
filesWithConsoleLogs.forEach((f) =>
client.app.log("warn", ` - ${f}`)
log("warn", ` - ${f}`)
)
client.app.log("warn", "[ECC] Remove console.log statements before committing")
log("warn", "[ECC] Remove console.log statements before committing")
} else {
client.app.log("info", "[ECC] Audit passed: No console.log statements found")
log("info", "[ECC] Audit passed: No console.log statements found")
}
// Desktop notification (macOS)
@@ -241,7 +244,7 @@ export const ECCHooksPlugin = async ({
* Action: Final cleanup and state saving
*/
"session.deleted": async () => {
client.app.log("info", "[ECC] Session ended - cleaning up")
log("info", "[ECC] Session ended - cleaning up")
editedFiles.clear()
},
@@ -266,7 +269,7 @@ export const ECCHooksPlugin = async ({
* Action: Logs for audit trail
*/
"permission.asked": async (event: { tool: string; args: unknown }) => {
client.app.log("info", `[ECC] Permission requested for: ${event.tool}`)
log("info", `[ECC] Permission requested for: ${event.tool}`)
},
/**
@@ -280,7 +283,7 @@ export const ECCHooksPlugin = async ({
const completed = event.todos.filter((t) => t.done).length
const total = event.todos.length
if (total > 0) {
client.app.log("info", `[ECC] Progress: ${completed}/${total} tasks completed`)
log("info", `[ECC] Progress: ${completed}/${total} tasks completed`)
}
},
}

View File

@@ -6,7 +6,7 @@
* while taking advantage of OpenCode's more sophisticated 20+ event types.
*/
export { ECCHooksPlugin, default } from "./ecc-hooks"
export { ECCHooksPlugin, default } from "./ecc-hooks.js"
// Re-export for named imports
export * from "./ecc-hooks"
export * from "./ecc-hooks.js"