chore: import upstream snapshot with attribution
CI / Test (ubuntu-latest, Node 18.x, bun) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, npm) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, pnpm) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, yarn) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 20.x, bun) (push) Failing after 17m13s
CI / Test (ubuntu-latest, Node 20.x, npm) (push) Failing after 18m42s
CI / Test (ubuntu-latest, Node 20.x, pnpm) (push) Failing after 15m0s
CI / Test (ubuntu-latest, Node 20.x, yarn) (push) Failing after 49m44s
CI / Test (ubuntu-latest, Node 22.x, bun) (push) Failing after 51m55s
CI / Test (ubuntu-latest, Node 22.x, pnpm) (push) Failing after 21m57s
CI / Test (ubuntu-latest, Node 22.x, npm) (push) Failing after 37m39s
CI / Test (ubuntu-latest, Node 22.x, yarn) (push) Failing after 34m7s
CI / Validate Components (push) Failing after 37m15s
CI / Python Tests (push) Failing after 10m1s
CI / Security Scan (push) Failing after 10m1s
CI / Lint (push) Failing after 17m12s
CI / Coverage (push) Failing after 20m19s
CI / Test (macos-latest, Node 18.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, yarn) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, yarn) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, yarn) (push) Has been cancelled
CI / Test (ubuntu-latest, Node 18.x, bun) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, npm) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, pnpm) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 18.x, yarn) (push) Failing after 15m1s
CI / Test (ubuntu-latest, Node 20.x, bun) (push) Failing after 17m13s
CI / Test (ubuntu-latest, Node 20.x, npm) (push) Failing after 18m42s
CI / Test (ubuntu-latest, Node 20.x, pnpm) (push) Failing after 15m0s
CI / Test (ubuntu-latest, Node 20.x, yarn) (push) Failing after 49m44s
CI / Test (ubuntu-latest, Node 22.x, bun) (push) Failing after 51m55s
CI / Test (ubuntu-latest, Node 22.x, pnpm) (push) Failing after 21m57s
CI / Test (ubuntu-latest, Node 22.x, npm) (push) Failing after 37m39s
CI / Test (ubuntu-latest, Node 22.x, yarn) (push) Failing after 34m7s
CI / Validate Components (push) Failing after 37m15s
CI / Python Tests (push) Failing after 10m1s
CI / Security Scan (push) Failing after 10m1s
CI / Lint (push) Failing after 17m12s
CI / Coverage (push) Failing after 20m19s
CI / Test (macos-latest, Node 18.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 18.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 18.x, yarn) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 20.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 20.x, yarn) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, bun) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, npm) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, pnpm) (push) Has been cancelled
CI / Test (macos-latest, Node 22.x, yarn) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, npm) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, pnpm) (push) Has been cancelled
CI / Test (windows-latest, Node 22.x, yarn) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* ECC Custom Tool: Git Summary
|
||||
*
|
||||
* Returns branch/status/log/diff details for the active repository.
|
||||
*/
|
||||
|
||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||
import { execFileSync } from "child_process"
|
||||
|
||||
// Conservative subset of git's allowed ref-name characters. Rejects shell
|
||||
// metacharacters and option-like leading `-` so a model-supplied baseBranch
|
||||
// cannot inject into the shell command line built below.
|
||||
const SAFE_GIT_REF = /^[A-Za-z0-9._/-]+$/
|
||||
|
||||
function isSafeRef(ref: string): boolean {
|
||||
if (typeof ref !== "string" || ref.length === 0 || ref.length > 200) return false
|
||||
if (!SAFE_GIT_REF.test(ref)) return false
|
||||
if (ref.startsWith("-") || ref.startsWith(".") || ref.startsWith("/")) return false
|
||||
if (ref.includes("..") || ref.includes("//")) return false
|
||||
return true
|
||||
}
|
||||
|
||||
function isSafeDepth(value: unknown): value is number {
|
||||
return typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 1000
|
||||
}
|
||||
|
||||
const gitSummaryTool: ToolDefinition = tool({
|
||||
description:
|
||||
"Generate git summary with branch, status, recent commits, and optional diff stats.",
|
||||
args: {
|
||||
depth: tool.schema
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Number of recent commits to include (default: 5)"),
|
||||
includeDiff: tool.schema
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Include diff stats against base branch (default: true)"),
|
||||
baseBranch: tool.schema
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Base branch for diff comparison (default: main)"),
|
||||
},
|
||||
async execute(args, context) {
|
||||
const cwd = context.worktree || context.directory
|
||||
const depth = isSafeDepth(args.depth) ? args.depth : 5
|
||||
const includeDiff = args.includeDiff ?? true
|
||||
const baseBranch = args.baseBranch ?? "main"
|
||||
|
||||
const result: Record<string, string> = {
|
||||
branch: runArgs(["branch", "--show-current"], cwd) || "unknown",
|
||||
status: runArgs(["status", "--short"], cwd) || "clean",
|
||||
log: runArgs(["log", "--oneline", `-${depth}`], cwd) || "no commits found",
|
||||
}
|
||||
|
||||
if (includeDiff) {
|
||||
result.stagedDiff = runArgs(["diff", "--cached", "--stat"], cwd) || ""
|
||||
result.branchDiff = isSafeRef(baseBranch)
|
||||
? runArgs(["diff", `${baseBranch}...HEAD`, "--stat"], cwd) ||
|
||||
`unable to diff against ${baseBranch}`
|
||||
: `unable to diff against ${baseBranch} (invalid ref)`
|
||||
}
|
||||
|
||||
return JSON.stringify(result)
|
||||
},
|
||||
})
|
||||
|
||||
export default gitSummaryTool
|
||||
|
||||
function runArgs(args: string[], cwd: string): string {
|
||||
try {
|
||||
return execFileSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).trim()
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user