Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Pre-commit

on:
pull_request:
push:
branches:
- main

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable

- name: Install gitleaks
run: |
go install github.com/zricethezav/gitleaks/v8@latest
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

- name: Install pre-commit
run: python -m pip install pre-commit

- name: Run pre-commit
run: pre-commit run --all-files
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
repos:
- repo: local
hooks:
- id: repo-hygiene
name: repo hygiene checks
entry: bash tools/pre_commit_checks.sh
language: system
pass_filenames: false
- id: public-readiness
name: public readiness audit
entry: bash tools/audit_public.sh
language: system
pass_filenames: false
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New plugin with two skills for browser testing against any URL
- `cmux-browser` skill: interactive browser testing via `cmux browser` (visible split pane)
- `playwright-testing` skill: headless browser testing via `playwright-cli`
- URL-agnostic: works with local dev servers, staging, and production sites (e.g. `https://mon.eurekabuilder.xyz`)
- Migrated from project-local skills in `trader-dashboard/.claude/skills/`
- URL-agnostic: works with local dev servers, staging, and production sites (e.g. `https://staging.example.com`)
- Migrated from project-local `.claude/skills/` content

### Technical Details
- Marketplace: 1.10.0 -> 1.11.0
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ Follow [Semantic Versioning](https://semver.org/). Users update via `/plugin upd

### Testing
```bash
/plugin marketplace add /Users/amit/src/amitkot/claude-code-tools
/plugin marketplace add .
/plugin install plugin-name@amitkot
```
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ Extracted documentation optimized for AI context:

2. **GitButler CLI** (for GitButler skill) - Install from [gitbutlerapp/gitbutler](https://github.com/gitbutlerapp/gitbutler)

## Public Readiness

Before changing repository visibility or publishing a release, run the local audit:

```bash
pre-commit run --all-files
just audit-public
gitleaks detect --source . --redact --no-banner
git status --short --ignored
```

The public-readiness gate targets the current tree and future commits. Repository history is not rewritten.

### Installing Plugins

#### Option 1: Via Plugin Marketplace (Recommended)
Expand Down
20 changes: 10 additions & 10 deletions ai_docs/claude-code/plugins-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1322,7 +1322,7 @@ const customServer = createSdkMcpServer({
`https://api.weather.com/v1/current?q=${args.location}&units=${args.units}`
);
const data = await response.json();

return {
content: [{
type: "text",
Expand Down Expand Up @@ -1440,7 +1440,7 @@ tool(
// args is fully typed based on the schema
// TypeScript knows: args.data.name is string, args.data.age is number, etc.
console.log(`Processing ${args.data.name}'s data as ${args.format}`);

// Your processing logic here
return {
content: [{
Expand All @@ -1464,7 +1464,7 @@ tool(
async (args) => {
try {
const response = await fetch(args.endpoint);

if (!response.ok) {
return {
content: [{
Expand All @@ -1473,7 +1473,7 @@ tool(
}]
};
}

const data = await response.json();
return {
content: [{
Expand Down Expand Up @@ -1547,20 +1547,20 @@ const apiGatewayServer = createSdkMcpServer({
openai: { baseUrl: "https://api.openai.com/v1", key: process.env.OPENAI_KEY },
slack: { baseUrl: "https://slack.com/api", key: process.env.SLACK_TOKEN }
};

const { baseUrl, key } = config[args.service];
const url = new URL(`${baseUrl}${args.endpoint}`);

if (args.query) {
Object.entries(args.query).forEach(([k, v]) => url.searchParams.set(k, v));
}

const response = await fetch(url, {
method: args.method,
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: args.body ? JSON.stringify(args.body) : undefined
});

const data = await response.json();
return {
content: [{
Expand Down Expand Up @@ -1593,7 +1593,7 @@ const calculatorServer = createSdkMcpServer({
// Use a safe math evaluation library in production
const result = eval(args.expression); // Example only!
const formatted = Number(result).toFixed(args.precision);

return {
content: [{
type: "text",
Expand Down Expand Up @@ -1622,7 +1622,7 @@ const calculatorServer = createSdkMcpServer({
async (args) => {
const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);
const interest = amount - args.principal;

return {
content: [{
type: "text",
Expand Down
2 changes: 1 addition & 1 deletion beads-orchestration/skills/execute-beads-plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ Execution complete.
Results:
- Tasks completed: N
- Verification passed: N
-
-
Implementation plan: [path]
Source plan: [path]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
When Task Agents complete work, they leave breadcrumbs:

```markdown
**Notes:** Implemented validation in `src/api/validate.rs:15-45`.
**Notes:** Implemented validation in `src/api/validate.rs:15-45`.
Added ValidationError enum in `src/errors.rs:20-30`.
Uses existing `EmailValidator` from `src/utils/validators.rs`.
```
Expand Down Expand Up @@ -68,7 +68,7 @@ To run agents in parallel, use single message with multiple Task tool calls:

<task_tool>
subagent_type: general-purpose
model: sonnet
model: sonnet
prompt: [Task Agent prompt for br-105]
</task_tool>

Expand Down
2 changes: 1 addition & 1 deletion beads-orchestration/skills/plans-to-beads/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Analyze the plan deeply before creating any beads:
```bash
br dep add <dependent-task> <dependency-task>
```

4. **Link tasks to epic**:
```bash
br dep add <task> <epic> -t parent-child
Expand Down
4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
# Run session recovery TUI
session-recover *ARGS:
cd session_recovery && uv run --with textual --with typer python __main__.py {{ARGS}}

# Run public-readiness checks used by pre-commit and CI
audit-public:
bash tools/audit_public.sh
2 changes: 1 addition & 1 deletion marketplace-author/skills/marketplace-author/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Authoring skills in the [`amitkot/claude-code-tools`](https://github.com/amitkot

## CRITICAL: Repo path

The marketplace repo is at `/Users/amit/src/amitkot/claude-code-tools/`. Run all commands from there. If a different machine path is needed, ask once before guessing.
Run all commands from the repository root. If the current working directory is unclear, ask once before guessing.

## Workflow

Expand Down
38 changes: 38 additions & 0 deletions tools/audit_public.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail

if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
echo "audit-public: must run inside a git repository" >&2
exit 1
fi

cd "$(git rev-parse --show-toplevel)"

status=0

check_pattern() {
local label="$1"
local pattern="$2"

if git grep -n -I -E "$pattern" -- . \
':(exclude).git' \
':(exclude)tools/audit_public.sh' \
':(exclude).pre-commit-config.yaml' >/tmp/audit-public-matches.txt; then
echo "Blocked public-readiness pattern: ${label}" >&2
cat /tmp/audit-public-matches.txt >&2
status=1
fi
}

check_pattern "internal project/domain references" "eurekabuilder|mon\\.eurekabuilder\\.xyz|trader-dashboard"
check_pattern "absolute local repo path" "/Users/amit/src/amitkot/claude-code-tools"

rm -f /tmp/audit-public-matches.txt

if command -v gitleaks >/dev/null 2>&1; then
gitleaks detect --source . --redact --no-banner
else
echo "gitleaks not found; install it and run: gitleaks detect --source . --redact --no-banner" >&2
fi

exit "$status"
70 changes: 70 additions & 0 deletions tools/pre_commit_checks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail

if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
echo "pre-commit checks: must run inside a git repository" >&2
exit 1
fi

cd "$(git rev-parse --show-toplevel)"

status=0
max_bytes=$((1024 * 1024))

files=()
while IFS= read -r -d '' file; do
files+=("$file")
done < <(git ls-files -z)

for file in "${files[@]}"; do
[[ -f "$file" ]] || continue

size=$(wc -c <"$file" | tr -d ' ')
if [[ "$size" -gt "$max_bytes" ]]; then
echo "Large tracked file exceeds 1 MiB: $file (${size} bytes)" >&2
status=1
fi

if LC_ALL=C grep -Iq . "$file"; then
if LC_ALL=C grep -n '[[:blank:]]$' "$file" >/tmp/pre-commit-trailing.txt; then
echo "Trailing whitespace in $file:" >&2
cat /tmp/pre-commit-trailing.txt >&2
status=1
fi

if [[ -s "$file" ]] && [[ "$(tail -c 1 "$file")" != "" ]]; then
echo "Missing final newline: $file" >&2
status=1
fi

if LC_ALL=C grep -n -E -e '-----BEGIN (RSA |DSA |EC |OPENSSH |PGP )?PRIVATE KEY-----' "$file" >/tmp/pre-commit-private-key.txt; then
echo "Private key material detected in $file:" >&2
cat /tmp/pre-commit-private-key.txt >&2
status=1
fi
fi

case "$file" in
*.json)
if ! python3 -m json.tool "$file" >/dev/null; then
echo "Invalid JSON: $file" >&2
status=1
fi
;;
*.yaml|*.yml)
if command -v ruby >/dev/null 2>&1; then
if ! ruby -e 'require "yaml"; YAML.load_file(ARGV.fetch(0))' "$file"; then
echo "Invalid YAML: $file" >&2
status=1
fi
else
echo "ruby not found; cannot validate YAML file: $file" >&2
status=1
fi
;;
esac
done

rm -f /tmp/pre-commit-trailing.txt /tmp/pre-commit-private-key.txt

exit "$status"
Loading