mirror of
https://github.com/Heretek-AI/.github.git
synced 2026-11-07 10:45:57 -10:00
30 files changed
+1284
-86
No files matched your search
@@ -0,0 +1,48 @@
|
||||
name: Audit Finding
|
||||
description: Independent verification gap or adversarial audit finding backed by runnable proof.
|
||||
title: "[Audit]: "
|
||||
type: Bug
|
||||
labels: ["audit"]
|
||||
body:
|
||||
- type: dropdown
|
||||
id: priority
|
||||
attributes:
|
||||
label: Priority
|
||||
description: Severity classification per Heretek-AI adversarial audit standards.
|
||||
options:
|
||||
- "P0 — Broken against real host/upstream, security boundary bypass, or missing pinned artifact"
|
||||
- "P1 — Deprecated/EOL version, fail-open error handling, untested [S] invariant, or upstream drift"
|
||||
- "P2 — Non-fatal version lag, doc/behavior mismatch, or missing CI coverage"
|
||||
- "P3 — Minor cleanup, dead code, or naming consistency"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: location
|
||||
attributes:
|
||||
label: File and line location
|
||||
description: Repo-relative path and line range (`path/to/file.ts:123`).
|
||||
placeholder: src/index.ts:42
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: claim
|
||||
attributes:
|
||||
label: Claim under audit
|
||||
description: What the README, AGENTS.md, spec, or test suite claims works.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proof
|
||||
attributes:
|
||||
label: Runnable proof command and verbatim output
|
||||
description: Exact command runnable from the repository root and its trimmed raw output.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: remediation
|
||||
attributes:
|
||||
label: Fail-closed remediation and verification check
|
||||
description: Exact diff or fix strategy and the command that turns from red to green.
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,5 +1,7 @@
|
||||
name: Bug
|
||||
description: Something behaves differently from what the docs or tests say.
|
||||
title: "[Bug]: "
|
||||
type: Bug
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: textarea
|
||||
@@ -7,23 +9,35 @@ body:
|
||||
attributes:
|
||||
label: What happened
|
||||
description: The observed behavior, with exact error text or command output.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What you expected
|
||||
description: The behavior promised by the docs, contract, or test suite.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: The smallest sequence that shows it.
|
||||
description: The smallest runnable command sequence that demonstrates the failure from a clean checkout.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version or commit
|
||||
placeholder: v1.2.3 or a commit SHA
|
||||
description: Exact git commit SHA (`git rev-parse HEAD`) or package version.
|
||||
placeholder: v1.2.3 or 8eb83340a487b1150af00701b94f01af97e4b4d6
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: environment
|
||||
attributes:
|
||||
label: Runtime and OS
|
||||
description: Runtime version (Bun, Node, Python/uv, OpenCode) and OS/arch.
|
||||
placeholder: "Bun 1.3.x / OpenCode 2.0.26 on Linux x86_64"
|
||||
@@ -1 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security Vulnerability Report
|
||||
url: https://github.com/Heretek-AI/.github/blob/main/SECURITY.md
|
||||
about: Report vulnerabilities privately via GitHub Private Vulnerability Reporting, never in a public issue.
|
||||
- name: Organization Governance & Cross-Repo Standards
|
||||
url: https://github.com/Heretek-AI/.github/blob/main/docs/organization-governance.md
|
||||
about: Review rulesets, shared CI secrets/variables, and fleet-wide conventions.
|
||||
@@ -1,5 +1,7 @@
|
||||
name: Epic
|
||||
description: A tracking issue that groups child issues toward one outcome.
|
||||
title: "[Epic]: "
|
||||
type: Epic
|
||||
labels: ["epic"]
|
||||
body:
|
||||
- type: textarea
|
||||
@@ -23,6 +25,8 @@ body:
|
||||
attributes:
|
||||
label: Exit criteria
|
||||
description: Checkable conditions beyond "all children closed".
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: human
|
||||
attributes:
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
name: Task
|
||||
description: A unit of work with a checkable finish line.
|
||||
title: "[Task]: "
|
||||
type: Task
|
||||
labels: ["task"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: goal
|
||||
@@ -12,15 +15,22 @@ body:
|
||||
id: done
|
||||
attributes:
|
||||
label: Done when
|
||||
description: Conditions someone else can check, one per line.
|
||||
description: Binary, runnable conditions someone else (or an agent) can verify, one per line.
|
||||
value: |
|
||||
- [ ]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: verify
|
||||
attributes:
|
||||
label: Verification commands
|
||||
description: Exact commands that must exit 0 to prove completion.
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: scope
|
||||
attributes:
|
||||
label: Out of scope
|
||||
description: Explicit refusal boundaries so implementation does not drift.
|
||||
- type: textarea
|
||||
id: links
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# actionlint configuration for Heretek-AI repositories
|
||||
self-hosted-runner:
|
||||
labels: []
|
||||
|
||||
config-variables:
|
||||
- OPENCODE_MODEL
|
||||
- OCR_LLM_URL
|
||||
- OCR_LLM_MODEL
|
||||
- OCR_LLM_USE_ANTHROPIC
|
||||
@@ -2,6 +2,16 @@
|
||||
|
||||
## Evidence
|
||||
|
||||
<!-- Commands run and what they printed. Name anything that was not run. -->
|
||||
<!-- Exact commands run and verbatim output. Explicitly name anything that was not run. -->
|
||||
|
||||
```text
|
||||
```
|
||||
|
||||
## Pre-merge checklist
|
||||
|
||||
- [ ] No machine-local paths (`file://` or `/home/` / `/Users/`) in tracked files
|
||||
- [ ] Local hooks passed (`lefthook run pre-commit`)
|
||||
- [ ] Every changed invariant has a test that fails when sabotaged
|
||||
|
||||
## Linked issues
|
||||
|
||||
@@ -10,7 +10,9 @@ permissions:
|
||||
|
||||
jobs:
|
||||
hygiene:
|
||||
uses: ./.github/workflows/hygiene.yml
|
||||
uses: $/.github/workflows/hygiene.yml
|
||||
with:
|
||||
audit_workflows: true
|
||||
|
||||
lint:
|
||||
name: Labels and scripts
|
||||
@@ -19,8 +21,17 @@ jobs:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: labels.json is a list of name, color, description
|
||||
|
||||
- name: Validate labels.json schema
|
||||
run: |
|
||||
jq -e 'type == "array" and all(.[]; (.name | type == "string") and (.color | test("^[0-9a-f]{6}$")) and (.description | type == "string"))' labels.json
|
||||
- name: shellcheck
|
||||
|
||||
- name: Validate fleet-manifest.json schema
|
||||
run: |
|
||||
jq -e '.schema_version == 1 and (.profiles | type == "object") and (.repositories | type == "array") and all(.repositories[]; (.name | type == "string") and (.profile | type == "string"))' fleet-manifest.json
|
||||
|
||||
- name: Validate Agent Skills (SKILL.md)
|
||||
run: bash scripts/validate-skills.sh
|
||||
|
||||
- name: ShellCheck scripts
|
||||
run: shellcheck scripts/*.sh
|
||||
@@ -0,0 +1,70 @@
|
||||
name: Fleet Standardization Sync
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "fleet-manifest.json"
|
||||
- "labels.json"
|
||||
- "lefthook.yml"
|
||||
- "templates/**"
|
||||
- "skills/**"
|
||||
- "scripts/**"
|
||||
- ".github/actionlint.yaml"
|
||||
- ".github/workflows/hygiene.yml"
|
||||
- ".github/workflows/ocr-review.yml"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Preview changes without pushing branches or opening PRs"
|
||||
type: boolean
|
||||
default: true
|
||||
target_repo:
|
||||
description: "Optional single repository name (e.g. IUMBTEMS) to sync; leave blank for all"
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: fleet-sync-main
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
sync-fleet:
|
||||
name: Open standardization PRs across Heretek-AI
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check for ORG_SYNC_TOKEN
|
||||
id: check-token
|
||||
env:
|
||||
SYNC_TOKEN: ${{ secrets.ORG_SYNC_TOKEN }}
|
||||
run: |
|
||||
if [ -z "$SYNC_TOKEN" ]; then
|
||||
echo "::notice::ORG_SYNC_TOKEN organization secret is not set; running fleet-sync in dry-run mode."
|
||||
echo "dry_run=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "dry_run=${{ inputs.dry_run || 'false' }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Propagate standards across fleet
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.ORG_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
DRY_RUN: ${{ steps.check-token.outputs.dry_run }}
|
||||
TARGET_REPO: ${{ inputs.target_repo }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
args=()
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
args+=(--dry-run)
|
||||
fi
|
||||
if [ -n "$TARGET_REPO" ]; then
|
||||
args+=(--repo "$TARGET_REPO")
|
||||
fi
|
||||
bash scripts/sync-fleet.sh "${args[@]}"
|
||||
@@ -1,8 +1,7 @@
|
||||
name: Hygiene
|
||||
|
||||
# Reusable check: tracked files must not contain machine-local paths.
|
||||
# A file:// URI or an absolute path into someone's home directory describes
|
||||
# one machine, breaks for every other reader and leaks the directory layout.
|
||||
# Reusable check: tracked files must not contain machine-local paths, and
|
||||
# workflows must pass static syntax/security checks when enabled.
|
||||
#
|
||||
# Call it from a repository:
|
||||
#
|
||||
@@ -20,6 +19,10 @@ on:
|
||||
description: Newline-separated paths left out of the scan, relative to the repo root.
|
||||
type: string
|
||||
default: ""
|
||||
audit_workflows:
|
||||
description: Run actionlint and zizmor against .github/workflows/ in a companion job.
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -54,3 +57,20 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
echo "No machine-local paths in tracked files."
|
||||
|
||||
workflow-security:
|
||||
name: Workflow syntax and security
|
||||
if: inputs.audit_workflows
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
|
||||
- name: Audit workflows with zizmor
|
||||
run: uvx "[email protected]" --format=github .
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -7,7 +7,8 @@ name: OpenCodeReview
|
||||
# jobs:
|
||||
# review:
|
||||
# uses: Heretek-AI/.github/.github/workflows/ocr-review.yml@<commit sha> # main
|
||||
# secrets: inherit
|
||||
# secrets:
|
||||
# OCR_LLM_TOKEN: ${{ secrets.OCR_LLM_TOKEN }}
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
@@ -36,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
if: |
|
||||
github.event_name == 'pull_request_target'
|
||||
github.event_name == 'pull_request'
|
||||
|| (
|
||||
github.event_name == 'issue_comment'
|
||||
&& github.event.issue.pull_request
|
||||
|
||||
@@ -4,7 +4,7 @@ concurrency:
|
||||
group: >-
|
||||
${{
|
||||
(
|
||||
github.event_name == 'pull_request_target'
|
||||
github.event_name == 'pull_request'
|
||||
|| (
|
||||
github.event_name == 'issue_comment'
|
||||
&& github.event.issue.pull_request
|
||||
@@ -26,7 +26,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
@@ -37,5 +37,6 @@ permissions:
|
||||
|
||||
jobs:
|
||||
review:
|
||||
uses: ./.github/workflows/ocr-review.yml
|
||||
secrets: inherit
|
||||
uses: $/.github/workflows/ocr-review.yml
|
||||
secrets:
|
||||
OCR_LLM_TOKEN: ${{ secrets.OCR_LLM_TOKEN }}
|
||||
@@ -1,75 +1,55 @@
|
||||
# Heretek-AI/.github
|
||||
|
||||
Organization-wide defaults, and the shared conventions of the agent-tooling repositories.
|
||||
Organization-wide defaults, shared Agent Skills, polyglot Lefthook v2 configurations, and automated fleet PR synchronization for `Heretek-AI`.
|
||||
|
||||
## Applies to every repository in the organization
|
||||
## 1. Inherited Automatically Across Every Repository (Zero Copy)
|
||||
|
||||
GitHub uses these files for any Heretek-AI repository that lacks its own copy:
|
||||
GitHub automatically applies these files to any `Heretek-AI` repository that does not commit its own override at the same path:
|
||||
|
||||
- `SECURITY.md` and `CONTRIBUTING.md`
|
||||
- `.github/ISSUE_TEMPLATE/` (bug, task, epic)
|
||||
- `.github/ISSUE_TEMPLATE/` (`bug.yml`, `task.yml`, `epic.yml`, `audit.yml`, and `config.yml`)
|
||||
- `.github/pull_request_template.md`
|
||||
|
||||
A repository opts out of one by committing its own file at the same path. Any file in a repository's own `.github/ISSUE_TEMPLATE/` replaces the whole default set of issue forms.
|
||||
> **Important:** Do not copy `.github/ISSUE_TEMPLATE/*` into child repositories unless a repository needs to replace the entire default set of issue forms.
|
||||
|
||||
## Used by the agent-tooling repositories
|
||||
## 2. Automated Fleet PR Synchronization (`fleet-sync.yml`)
|
||||
|
||||
| Path | Purpose |
|
||||
Every push to `main` that modifies `fleet-manifest.json`, `labels.json`, `skills/**`, `templates/**`, `.github/actionlint.yaml`, or reusable workflows triggers [`.github/workflows/fleet-sync.yml`](.github/workflows/fleet-sync.yml) (`scripts/sync-fleet.sh`), which:
|
||||
|
||||
1. Syncs `labels.json` across all 32 downstream repositories via `scripts/sync-labels.sh --update`.
|
||||
2. Copies the repository's stack-matched Lefthook v2 config (`templates/lefthook/<profile>.yml` -> `lefthook.yml`).
|
||||
3. Syncs the four canonical Agent Skills (`skills/*` -> `.agents/skills/*`) with cross-harness symlinks for OpenCode v2 (`.opencode/skills`), Claude Code (`.claude/skills`), and GitHub Copilot (`.github/skills`).
|
||||
4. Rewrites `Heretek-AI/.github/.github/workflows/<name>.yml@<sha>` references in downstream `.github/workflows/*.yml` files to the new `Heretek-AI/.github` commit SHA.
|
||||
5. Opens or updates a single idempotent, DCO-signed pull request (`chore/sync-org-standards`) per repository.
|
||||
|
||||
### Stack Profiles (`fleet-manifest.json`)
|
||||
|
||||
| Profile | Target Repositories | Pre-Commit & Pre-Push Gates |
|
||||
| --- | --- | --- |
|
||||
| `bun-biome` | `IUMBTEMS`, `claude-4-opencode`, `Agent-Builder`, `Token-Max`, `heretek-context-router`, `epistemic-factory`, `agency-control-plane`, `opencode-harness`, `opencode-v2-plugin-teser`, `opencode-rea`, `opencode-searxng-plugin` | Local-path check, `gitleaks`, `biome check --write`, `shellcheck`, `actionlint`, `zizmor`, `bun test` |
|
||||
| `python-uv` | `scraper-swarm` | Local-path check, `gitleaks`, `ruff check --fix`, `ruff format`, `taplo`, `shellcheck`, `actionlint`, `zizmor`, `uv lock --check`, `ty check` |
|
||||
| `node-zerodep` | `opencode-4-openclaude`, `GDevelop-Unlocked` | Local-path check, `gitleaks`, `node --check`, `jq`, `shellcheck`, `actionlint`, `zizmor`, `node --test` |
|
||||
| `universal` | `awesome-opencode`, `heretek-skills`, and 16 other active repositories | Local-path check, `gitleaks`, `jq`, `shellcheck`, `actionlint`, `zizmor` |
|
||||
|
||||
## 3. Shared Agent Skills (`skills/`)
|
||||
|
||||
Conforms to the [Agent Skills Open Specification](https://agentskills.io/specification) and [OpenCode v2 Agent Skills](https://opencode.ai/docs/skills/):
|
||||
|
||||
| Skill | Trigger & Purpose |
|
||||
| --- | --- |
|
||||
| [`docs/agent-tooling-family.md`](docs/agent-tooling-family.md) | The five repositories and what connects them |
|
||||
| [`docs/organization-governance.md`](docs/organization-governance.md) | Organization hardening, rulesets, secrets/variables, and repository inventory |
|
||||
| [`docs/adr/`](docs/adr/) | Decisions that span repositories |
|
||||
| [`templates/AGENTS.md`](templates/AGENTS.md) | Starting point for a new repository's agent guide |
|
||||
| `labels.json`, `scripts/sync-labels.sh` | Shared label set |
|
||||
| `.github/workflows/hygiene.yml` | Reusable check for machine-local paths |
|
||||
| `.github/workflows/ocr-review.yml` | Reusable OpenCodeReview PR review workflow |
|
||||
| [`skills/evidence-pr/SKILL.md`](skills/evidence-pr/SKILL.md) | Runs `lefthook run pre-commit`, captures verbatim command evidence for PR descriptions, and watches status checks |
|
||||
| [`skills/hygiene-and-workflow-audit/SKILL.md`](skills/hygiene-and-workflow-audit/SKILL.md) | Scans tracked files for machine-local paths and audits `.github/workflows/` with `actionlint` and `zizmor` |
|
||||
| [`skills/cross-repo-contract-check/SKILL.md`](skills/cross-repo-contract-check/SKILL.md) | Enforces ADR 0001 protocol-only boundaries and golden fixture verification across `scraper-swarm` and `IUMBTEMS` |
|
||||
| [`skills/adversarial-claim-check/SKILL.md`](skills/adversarial-claim-check/SKILL.md) | Runs pre-release artifact checks and invariant sabotage tests inside a disposable `git worktree` |
|
||||
|
||||
### Hygiene check
|
||||
|
||||
Fails when a tracked file contains a `file://` URI or an absolute path into a home directory.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
hygiene:
|
||||
uses: Heretek-AI/.github/.github/workflows/hygiene.yml@<commit sha> # main
|
||||
with:
|
||||
exclude: |
|
||||
path/to/recorded-evidence
|
||||
```
|
||||
|
||||
Pin the workflow to a commit of this repository; code scanning flags a branch reference. `exclude` is optional: one repo-relative path per line, for files that must stay byte-identical, such as recorded evidence.
|
||||
|
||||
### OpenCodeReview (`ocr-review.yml`)
|
||||
|
||||
Runs [`Heretek-AI/open-code-review`](https://github.com/Heretek-AI/open-code-review) on pull requests (`pull_request`) and `@ocr` maintainer comments (`issue_comment`) across all 29 active workflow-enabled repositories using organization-level variables (`OCR_LLM_URL`, `OCR_LLM_MODEL`, `OCR_LLM_USE_ANTHROPIC`) and the `OCR_LLM_TOKEN` organization secret:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
ocr:
|
||||
uses: Heretek-AI/.github/.github/workflows/ocr-review.yml@main
|
||||
with:
|
||||
llm_url: ${{ vars.OCR_LLM_URL || 'https://token-plan-sgp.xiaomimimo.com/v1' }}
|
||||
llm_model: ${{ vars.OCR_LLM_MODEL || 'mimo-v2.6-flash' }}
|
||||
use_anthropic: ${{ vars.OCR_LLM_USE_ANTHROPIC == 'true' }}
|
||||
secrets:
|
||||
OCR_LLM_TOKEN: ${{ secrets.OCR_LLM_TOKEN }}
|
||||
```
|
||||
|
||||
### Standardized Organization Secrets & Variables
|
||||
## 4. Standardized Organization Secrets & Variables
|
||||
|
||||
| Name | Kind | Visibility | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| `ORG_SYNC_TOKEN` | Org Secret | `selected` (`.github`) | Fine-grained token or GitHub App installation token (`Contents: write`, `Pull requests: write`, `Issues: write`, `Workflows: write`) used by `fleet-sync.yml` |
|
||||
| `OPENCODE_MODEL` | Org Variable | `all` | Default model for OpenCode live evals and AI review (`opencode/muse-spark-1.3-contributor`) |
|
||||
| `OPENCODE_API_KEY` | Org Secret | `selected` | OpenCode API key for live evals and AI review (`IUMBTEMS`, `claude-4-opencode`, `awesome-opencode`, `Agent-Builder`) |
|
||||
| `OCR_LLM_URL` | Org Variable | `all` | OpenCodeReview LLM endpoint (`https://token-plan-sgp.xiaomimimo.com/v1`) |
|
||||
| `OCR_LLM_MODEL` | Org Variable | `all` | OpenCodeReview model (`mimo-v2.6-flash`) |
|
||||
| `OCR_LLM_USE_ANTHROPIC` | Org Variable | `all` | OpenCodeReview protocol toggle (`false` for OpenAI-compatible) |
|
||||
| `OCR_LLM_TOKEN` | Org Secret | `all` | OpenCodeReview API token |
|
||||
|
||||
### Labels
|
||||
|
||||
```sh
|
||||
scripts/sync-labels.sh Heretek-AI/<repo> [Heretek-AI/<repo>...]
|
||||
```
|
||||
|
||||
Creates each label in `labels.json` that the repository lacks. Existing labels keep their color and description, and nothing is deleted.
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"organization": "Heretek-AI",
|
||||
"sync_branch": "chore/sync-org-standards",
|
||||
"profiles": {
|
||||
"bun-biome": {
|
||||
"description": "Bun workspaces/projects with Biome v2.5 and TypeScript",
|
||||
"lefthook_template": "templates/lefthook/bun-biome.yml",
|
||||
"sync_skills": true,
|
||||
"sync_actionlint_config": true
|
||||
},
|
||||
"python-uv": {
|
||||
"description": "Python 3.12+ with uv, Ruff v0.17, ty, and pnpm/Docker",
|
||||
"lefthook_template": "templates/lefthook/python-uv.yml",
|
||||
"sync_skills": true,
|
||||
"sync_actionlint_config": true
|
||||
},
|
||||
"node-zerodep": {
|
||||
"description": "Zero-dependency Node.js repositories using built-in node:test",
|
||||
"lefthook_template": "templates/lefthook/node-zerodep.yml",
|
||||
"sync_skills": true,
|
||||
"sync_actionlint_config": true
|
||||
},
|
||||
"universal": {
|
||||
"description": "Universal hygiene, shellcheck, JSON, and workflow security hooks",
|
||||
"lefthook_template": "templates/lefthook/universal.yml",
|
||||
"sync_skills": true,
|
||||
"sync_actionlint_config": true
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"name": "IUMBTEMS",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "claude-4-opencode",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "scraper-swarm",
|
||||
"profile": "python-uv",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "opencode-4-openclaude",
|
||||
"profile": "node-zerodep",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "GDevelop-Unlocked",
|
||||
"profile": "node-zerodep",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "awesome-opencode",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": true
|
||||
},
|
||||
{
|
||||
"name": "Agent-Builder",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "awesome-harness",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "Token-Max",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "heretek-rigs",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "Heretek-Crew",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "heretek-context-router",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "epistemic-factory",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "agency-control-plane",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "The-Agency",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "SwarmOS",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "heretek-devcontainers",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "oh-mine-pi",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "arcane-repo",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "Game-Studio",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "opencode-harness",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "opencode-v2-plugin-teser",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "opencode-rea",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "opencode-searxng-plugin",
|
||||
"profile": "bun-biome",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "godot-opencode",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "unity.gamedev.kit",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "homebrew-tap",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "ompweb-docker",
|
||||
"profile": "universal",
|
||||
"actions_enabled": true,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "heretek-skills",
|
||||
"profile": "universal",
|
||||
"actions_enabled": false,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "virt-box",
|
||||
"profile": "universal",
|
||||
"actions_enabled": false,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "optimized-prompts",
|
||||
"profile": "universal",
|
||||
"actions_enabled": false,
|
||||
"protected_ruleset": false
|
||||
},
|
||||
{
|
||||
"name": "free-git",
|
||||
"profile": "universal",
|
||||
"actions_enabled": false,
|
||||
"protected_ruleset": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+55
-8
@@ -1,10 +1,57 @@
|
||||
[
|
||||
{ "name": "epic", "color": "5319e7", "description": "Tracking issue: goals, order, exit criteria" },
|
||||
{ "name": "security", "color": "b60205", "description": "Security or isolation gap" },
|
||||
{ "name": "human-only", "color": "b60205", "description": "Only a human can do this step" },
|
||||
{ "name": "audit", "color": "ededed", "description": "Independent verification of shipped work" },
|
||||
{ "name": "release", "color": "0e8a16", "description": "Release, tagging or publishing" },
|
||||
{ "name": "cross-repo", "color": "c5def5", "description": "Depends on or affects another Heretek-AI repo" },
|
||||
{ "name": "upstream", "color": "fbca04", "description": "Driven by a change in an upstream project" },
|
||||
{ "name": "dependencies", "color": "0366d6", "description": "Pull requests that update a dependency file" }
|
||||
{
|
||||
"name": "bug",
|
||||
"color": "d73a4a",
|
||||
"description": "Something behaves differently from what the docs or tests say"
|
||||
},
|
||||
{
|
||||
"name": "task",
|
||||
"color": "0075ca",
|
||||
"description": "A unit of work with a checkable finish line"
|
||||
},
|
||||
{
|
||||
"name": "epic",
|
||||
"color": "5319e7",
|
||||
"description": "Tracking issue: goals, order, exit criteria"
|
||||
},
|
||||
{
|
||||
"name": "security",
|
||||
"color": "b60205",
|
||||
"description": "Security or isolation gap"
|
||||
},
|
||||
{
|
||||
"name": "human-only",
|
||||
"color": "b60205",
|
||||
"description": "Only a human can do this step"
|
||||
},
|
||||
{
|
||||
"name": "audit",
|
||||
"color": "ededed",
|
||||
"description": "Independent verification of shipped work"
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"color": "0e8a16",
|
||||
"description": "Release, tagging or publishing"
|
||||
},
|
||||
{
|
||||
"name": "cross-repo",
|
||||
"color": "c5def5",
|
||||
"description": "Depends on or affects another Heretek-AI repo"
|
||||
},
|
||||
{
|
||||
"name": "upstream",
|
||||
"color": "fbca04",
|
||||
"description": "Driven by a change in an upstream project"
|
||||
},
|
||||
{
|
||||
"name": "dependencies",
|
||||
"color": "0366d6",
|
||||
"description": "Pull requests that update a dependency file"
|
||||
},
|
||||
{
|
||||
"name": "org-sync",
|
||||
"color": "1d76db",
|
||||
"description": "Automated standardization PR from Heretek-AI/.github"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,68 @@
|
||||
# Lefthook v2 configuration for Heretek-AI/.github
|
||||
# Spec: https://lefthook.dev/configuration/jobs/ (Lefthook >= 2.2.2)
|
||||
min_version: 1.10.0
|
||||
|
||||
pre-commit:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: no-local-paths
|
||||
run: |
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
if git grep -nIE "$PATTERN" -- {staged_files}; then
|
||||
echo "ERROR: Machine-local paths found in staged files. Use repo-relative paths or owner/name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: gitleaks
|
||||
run: |
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
gitleaks protect --staged --redact --no-banner
|
||||
fi
|
||||
|
||||
- name: json-schema
|
||||
glob: "*.json"
|
||||
run: |
|
||||
jq empty {staged_files}
|
||||
if [ -f labels.json ]; then
|
||||
jq -e 'type == "array" and all(.[]; (.name | type == "string") and (.color | test("^[0-9a-f]{6}$")) and (.description | type == "string"))' labels.json >/dev/null
|
||||
fi
|
||||
if [ -f fleet-manifest.json ]; then
|
||||
jq -e '.schema_version == 1 and (.profiles | type == "object") and (.repositories | type == "array")' fleet-manifest.json >/dev/null
|
||||
fi
|
||||
|
||||
- name: shell-format
|
||||
glob: "*.sh"
|
||||
stage_fixed: true
|
||||
run: |
|
||||
if command -v shfmt >/dev/null 2>&1; then
|
||||
shfmt -i 2 -ci -w {staged_files}
|
||||
fi
|
||||
|
||||
- name: shellcheck
|
||||
glob: "*.sh"
|
||||
run: |
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
shellcheck {staged_files}
|
||||
else
|
||||
bash -n {staged_files}
|
||||
fi
|
||||
|
||||
- name: skills-validate
|
||||
glob: "{skills,.agents/skills}/*/SKILL.md"
|
||||
run: bash scripts/validate-skills.sh
|
||||
|
||||
- name: workflow-actionlint
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v actionlint >/dev/null 2>&1; then
|
||||
actionlint {staged_files}
|
||||
fi
|
||||
|
||||
- name: workflow-zizmor
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v zizmor >/dev/null 2>&1; then
|
||||
zizmor --format=plain {staged_files}
|
||||
elif command -v uvx >/dev/null 2>&1; then
|
||||
uvx [email protected] --format=plain {staged_files}
|
||||
fi
|
||||
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env bash
|
||||
# Propagate standardized Agent Skills, Lefthook configs, workflow SHA pins,
|
||||
# and labels from Heretek-AI/.github to target repositories via idempotent PRs.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/sync-fleet.sh [--dry-run] [--repo <repo-name>]
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
manifest="$root/fleet-manifest.json"
|
||||
dry_run=false
|
||||
filter_repo=""
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--dry-run)
|
||||
dry_run=true
|
||||
shift
|
||||
;;
|
||||
--repo)
|
||||
filter_repo="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [--dry-run] [--repo <repo-name>]" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
org="$(jq -r '.organization' "$manifest")"
|
||||
sync_branch="$(jq -r '.sync_branch' "$manifest")"
|
||||
source_sha="$(git -C "$root" rev-parse HEAD)"
|
||||
short_sha="$(git -C "$root" rev-parse --short HEAD)"
|
||||
work_tmp="$(mktemp -d -t heretek-fleet-sync-XXXXXX)"
|
||||
trap 'rm -rf "$work_tmp"' EXIT
|
||||
|
||||
echo "=== Heretek-AI Fleet Sync (@$short_sha, dry_run=$dry_run) ==="
|
||||
|
||||
while IFS=$' ' read -r repo_name profile actions_enabled; do
|
||||
if [ -n "$filter_repo" ] && [ "$repo_name" != "$filter_repo" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
full_repo="$org/$repo_name"
|
||||
echo "--- Processing $full_repo (profile=$profile, actions_enabled=$actions_enabled) ---"
|
||||
|
||||
# 1. Sync organization labels
|
||||
if [ "$dry_run" = false ]; then
|
||||
"$root/scripts/sync-labels.sh" --update "$full_repo" || echo "::warning::Label sync skipped for $full_repo"
|
||||
else
|
||||
echo "[dry-run] Would sync labels.json to $full_repo"
|
||||
fi
|
||||
|
||||
# 2. Clone target repository default branch
|
||||
clone_dir="$work_tmp/$repo_name"
|
||||
if ! gh repo clone "$full_repo" "$clone_dir" -- --depth=1 2>/dev/null; then
|
||||
echo "::warning::Could not clone $full_repo; skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
default_branch="$(git -C "$clone_dir" rev-parse --abbrev-ref HEAD)"
|
||||
git -C "$clone_dir" checkout -B "$sync_branch"
|
||||
|
||||
# 3. Copy stack-specific lefthook.yml
|
||||
lefthook_tpl="$(jq -r --arg p "$profile" '.profiles[$p].lefthook_template' "$manifest")"
|
||||
cp "$root/$lefthook_tpl" "$clone_dir/lefthook.yml"
|
||||
|
||||
# 4. Sync canonical Agent Skills into .agents/skills/ and harness symlinks
|
||||
mkdir -p "$clone_dir/.agents/skills"
|
||||
for skill_dir in "$root"/skills/*/; do
|
||||
[ -d "$skill_dir" ] || continue
|
||||
skill_name="$(basename "$skill_dir")"
|
||||
rm -rf "$clone_dir/.agents/skills/$skill_name"
|
||||
cp -R "$skill_dir" "$clone_dir/.agents/skills/$skill_name"
|
||||
done
|
||||
|
||||
# Ensure cross-agent discovery symlinks (.opencode/skills, .claude/skills, .github/skills)
|
||||
for harness_dir in .opencode .claude .github; do
|
||||
mkdir -p "$clone_dir/$harness_dir"
|
||||
if [ ! -e "$clone_dir/$harness_dir/skills" ] && [ ! -L "$clone_dir/$harness_dir/skills" ]; then
|
||||
ln -s ../.agents/skills "$clone_dir/$harness_dir/skills"
|
||||
fi
|
||||
done
|
||||
|
||||
# 5. For workflow-enabled repos, sync .github/actionlint.yaml and bump reusable workflow SHAs
|
||||
if [ "$actions_enabled" = "true" ]; then
|
||||
mkdir -p "$clone_dir/.github/workflows"
|
||||
cp "$root/.github/actionlint.yaml" "$clone_dir/.github/actionlint.yaml"
|
||||
|
||||
# Rewrite Heretek-AI/.github/.github/workflows/<wf>.yml@<40-hex-or-main> to @$source_sha # main
|
||||
for wf in "$clone_dir"/.github/workflows/*.{yml,yaml}; do
|
||||
[ -f "$wf" ] || continue
|
||||
sed -i -E "s|(Heretek-AI/\.github/\.github/workflows/[A-Za-z0-9_.-]+\.ya?ml)@[0-9a-f]{40}([[:space:]]*#.*)?|\1@${source_sha} # main|g" "$wf"
|
||||
done
|
||||
fi
|
||||
|
||||
# 6. Check if anything changed
|
||||
if [ -z "$(git -C "$clone_dir" status --porcelain)" ]; then
|
||||
echo "$full_repo: already up to date with @$short_sha"
|
||||
continue
|
||||
fi
|
||||
|
||||
git -C "$clone_dir" status --short
|
||||
|
||||
if [ "$dry_run" = true ]; then
|
||||
echo "[dry-run] Would commit and open/update PR on $full_repo ($sync_branch -> $default_branch)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# 7. Commit with DCO sign-off (web_commit_signoff_required: true) and open/update PR
|
||||
git -C "$clone_dir" config user.name "heretek-fleet-sync[bot]"
|
||||
git -C "$clone_dir" config user.email "heretek-fleet-sync[bot]@users.noreply.github.com"
|
||||
git -C "$clone_dir" add -A
|
||||
git -C "$clone_dir" commit --signoff -m "chore(org-sync): propagate Heretek-AI/.github@$short_sha standards"
|
||||
git -C "$clone_dir" push --force-with-lease origin "$sync_branch"
|
||||
|
||||
pr_title="chore(org-sync): sync Heretek-AI/.github@$short_sha standards ($profile)"
|
||||
pr_body="$(cat <<EOF
|
||||
## What and why
|
||||
|
||||
Automated organization standardization sync from \`Heretek-AI/.github@${source_sha}\` (profile: \`${profile}\`).
|
||||
|
||||
- Updates \`lefthook.yml\` to the \`${profile}\` Lefthook v2 job profile
|
||||
- Syncs shared Agent Skills under \`.agents/skills/\` (with \`.opencode/skills\`, \`.claude/skills\`, and \`.github/skills\` discovery paths)
|
||||
- Bumps reusable workflow pins (\`Heretek-AI/.github/.github/workflows/*\`) to \`${source_sha}\`
|
||||
|
||||
## Evidence
|
||||
|
||||
\`\`\`text
|
||||
Source commit: Heretek-AI/.github@${source_sha}
|
||||
Target profile: ${profile}
|
||||
Validated by: Heretek-AI/.github CI (hygiene, actionlint, zizmor, validate-skills.sh, shellcheck)
|
||||
\`\`\`
|
||||
|
||||
## Linked issues
|
||||
|
||||
Tracked by \`Heretek-AI/.github\` organization standardization.
|
||||
EOF
|
||||
)"
|
||||
|
||||
existing_pr="$(gh pr list --repo "$full_repo" --head "$sync_branch" --base "$default_branch" --json number --jq '.[0].number // empty')"
|
||||
if [ -n "$existing_pr" ]; then
|
||||
gh pr edit "$existing_pr" --repo "$full_repo" --title "$pr_title" --body "$pr_body" >/dev/null
|
||||
echo "$full_repo: updated PR #$existing_pr"
|
||||
else
|
||||
pr_url="$(gh pr create --repo "$full_repo" --head "$sync_branch" --base "$default_branch" --title "$pr_title" --body "$pr_body" --label "org-sync")"
|
||||
echo "$full_repo: created $pr_url"
|
||||
fi
|
||||
done < <(jq -r '.repositories[] | [.name, .profile, (.actions_enabled | tostring)] | @tsv' "$manifest")
|
||||
+16
-5
@@ -1,20 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create each label in labels.json that a repository lacks.
|
||||
# Existing labels keep their color and description; nothing is deleted.
|
||||
# Create or update each label in labels.json across one or more repositories.
|
||||
# Usage: scripts/sync-labels.sh [--update] owner/repo [owner/repo...]
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
force_flag=()
|
||||
|
||||
if [ "${1:-}" = "--update" ]; then
|
||||
force_flag=(--force)
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "usage: $0 owner/repo [owner/repo...]" >&2
|
||||
echo "usage: $0 [--update] owner/repo [owner/repo...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
for repo in "$@"; do
|
||||
existing="$(gh label list --repo "$repo" --limit 500 --json name --jq '.[].name')"
|
||||
while IFS=$'\t' read -r name color description; do
|
||||
while IFS=$' ' read -r name color description; do
|
||||
if grep -Fxq -- "$name" <<<"$existing"; then
|
||||
echo "$repo: $name exists"
|
||||
if [ "${#force_flag[@]}" -gt 0 ]; then
|
||||
gh label create "$name" --repo "$repo" --color "$color" --description "$description" --force >/dev/null
|
||||
echo "$repo: $name updated"
|
||||
else
|
||||
echo "$repo: $name exists"
|
||||
fi
|
||||
else
|
||||
gh label create "$name" --repo "$repo" --color "$color" --description "$description" >/dev/null
|
||||
echo "$repo: $name created"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# Validate SKILL.md files against the Agent Skills Open Specification (agentskills.io)
|
||||
# and OpenCode v2 skill constraints.
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
skills_dir="${1:-$root/skills}"
|
||||
|
||||
if [ ! -d "$skills_dir" ]; then
|
||||
echo "No skills directory at $skills_dir; skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
status=0
|
||||
found=0
|
||||
|
||||
for skill_md in "$skills_dir"/*/SKILL.md; do
|
||||
[ -e "$skill_md" ] || continue
|
||||
found=$((found + 1))
|
||||
dir_name="$(basename "$(dirname "$skill_md")")"
|
||||
|
||||
# 1. Line budget (< 500 lines)
|
||||
lines="$(wc -l <"$skill_md" | tr -d '[:space:]')"
|
||||
if [ "$lines" -ge 500 ]; then
|
||||
echo "::error file=$skill_md::SKILL.md has $lines lines (must be < 500 lines)"
|
||||
status=1
|
||||
fi
|
||||
|
||||
# 2. Extract YAML frontmatter between first two '---' lines
|
||||
if [ "$(head -n 1 "$skill_md")" != "---" ]; then
|
||||
echo "::error file=$skill_md::Missing opening YAML frontmatter delimiter (---)"
|
||||
status=1
|
||||
continue
|
||||
fi
|
||||
|
||||
frontmatter="$(awk 'NR==1 && $0=="---" {in_fm=1; next} in_fm && $0=="---" {exit} in_fm {print}' "$skill_md")"
|
||||
name_val="$(printf '%s
|
||||
' "$frontmatter" | sed -n 's/^name:[[:space:]]*//p' | tr -d '"' | tr -d "'")"
|
||||
desc_val="$(printf '%s
|
||||
' "$frontmatter" | sed -n 's/^description:[[:space:]]*//p')"
|
||||
|
||||
# 3. Validate name matches directory and spec regex ^[a-z0-9]+(-[a-z0-9]+)*$ (1-64 chars)
|
||||
if [ -z "$name_val" ]; then
|
||||
echo "::error file=$skill_md::Missing required 'name' field in frontmatter"
|
||||
status=1
|
||||
elif [ "$name_val" != "$dir_name" ]; then
|
||||
echo "::error file=$skill_md::Frontmatter name '$name_val' does not match directory '$dir_name'"
|
||||
status=1
|
||||
elif ! printf '%s' "$name_val" | grep -Eq '^[a-z0-9]+(-[a-z0-9]+)*$' || [ "${#name_val}" -gt 64 ]; then
|
||||
echo "::error file=$skill_md::Invalid skill name '$name_val' (must be 1-64 lowercase alphanumeric/hyphen chars)"
|
||||
status=1
|
||||
fi
|
||||
|
||||
# 4. Validate description (1-1024 chars)
|
||||
if [ -z "$desc_val" ]; then
|
||||
echo "::error file=$skill_md::Missing required 'description' field in frontmatter"
|
||||
status=1
|
||||
elif [ "${#desc_val}" -gt 1024 ]; then
|
||||
echo "::error file=$skill_md::Description exceeds 1024 characters (${#desc_val})"
|
||||
status=1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Validated $found skill(s) in $skills_dir."
|
||||
exit "$status"
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: adversarial-claim-check
|
||||
description: Stress-test repository claims, version pins, packaging artifacts, and security invariants in a disposable git worktree before release or audit sign-off. Use when cutting a release, auditing shipped work, or proving an [S] invariant is guarded by tests.
|
||||
license: MIT
|
||||
compatibility: opencode claude codex copilot
|
||||
metadata:
|
||||
audience: maintainers-and-agents
|
||||
workflow: audit-verification
|
||||
opencode/slash: "true"
|
||||
---
|
||||
|
||||
# Adversarial Claim & Release Verification
|
||||
|
||||
Proves that a repository's claims, dependency pins, and security invariants hold against real tools and sabotage testing in an isolated worktree without dirtying the working checkout.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Verifying a repository before cutting a tagged release or publishing to npm/GHCR
|
||||
- Auditing an issue labeled `audit` or `security`
|
||||
- Confirming that a new test genuinely catches a broken invariant (sabotage check)
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Create an isolated disposable worktree.** Never mutate the primary checkout for destructive or sabotage experiments:
|
||||
|
||||
```bash
|
||||
AUDIT_TMP="$(mktemp -d -t heretek-check-XXXXXX)"
|
||||
git worktree add --detach "$AUDIT_TMP/wt" HEAD
|
||||
trap 'git worktree remove --force "$AUDIT_TMP/wt" && rm -rf "$AUDIT_TMP"' EXIT
|
||||
```
|
||||
|
||||
2. **Verify package & lockfile truth.**
|
||||
- **Bun / Node**: Run `npm pack --dry-run` (or `bun pm pack --dry-run`) inside `"$AUDIT_TMP/wt"` and confirm every entry point (`main`, `exports`, `bin`, `files`) resolves to a built file that exists.
|
||||
- **Python (`uv`)**: Run `uv lock --check` and confirm `[tool.uv] exclude-newer = "7 days"` is respected.
|
||||
- **GitHub Actions**: Confirm every `uses:` pin resolves to a 40-char commit SHA.
|
||||
|
||||
3. **Sabotage critical invariants.** For each security or correctness invariant changed in the PR:
|
||||
- Introduce a 1-line break in `"$AUDIT_TMP/wt"`.
|
||||
- Run the test suite in `"$AUDIT_TMP/wt"` and confirm it exits non-zero.
|
||||
- Restore the file with `git -C "$AUDIT_TMP/wt" checkout -- .`.
|
||||
|
||||
4. **Confirm clean working tree.** Verify `git status --porcelain` on the main checkout is empty after cleanup.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- A test that passes when the production guard is commented out is a lie; fix the test before merging.
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: cross-repo-contract-check
|
||||
description: Verify protocol contracts and version pins across Heretek-AI agent-tooling repositories without sharing runtime source code. Use when updating MCP gateway contracts, OpenCode v2 plugin APIs, or vendored golden fixtures.
|
||||
license: MIT
|
||||
compatibility: opencode claude codex copilot
|
||||
metadata:
|
||||
audience: maintainers-and-agents
|
||||
workflow: cross-repo
|
||||
opencode/slash: "true"
|
||||
---
|
||||
|
||||
# Cross-Repository Contract Verification
|
||||
|
||||
Per `Heretek-AI/.github` ADR 0001, repositories in the agent-tooling family (`IUMBTEMS`, `claude-4-opencode`, `scraper-swarm`, `opencode-4-openclaude`, `GDevelop-Unlocked`) never import each other's source code and integrate strictly over versioned protocols and golden fixtures.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Modifying `/mcp` request/response schemas or `contract/v1/fixtures/` in `Heretek-AI/scraper-swarm`
|
||||
- Updating the vendored `scraper-swarm` client in `Heretek-AI/IUMBTEMS`
|
||||
- Bumping `@opencode/plugin` v2 across `Heretek-AI/IUMBTEMS` or `Heretek-AI/claude-4-opencode`
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Check the governing boundary in `AGENTS.md`.** Confirm that no relative cross-repo filesystem imports or unpublished workspace links are introduced.
|
||||
2. **Validate golden fixtures against real schemas.**
|
||||
- When working in the producer (`Heretek-AI/scraper-swarm`), regenerate or validate `contract/v1/fixtures/` and record the producer commit SHA.
|
||||
- When working in the consumer (`Heretek-AI/IUMBTEMS`), vendor the exact fixture files at the recorded commit SHA and run the consumer contract test suite against them.
|
||||
3. **Apply lockstep or independent release rules.**
|
||||
- `IUMBTEMS` packages (`@heretek-ai/epistemic-swarm`, `es-core`, `es-cli`) release in lockstep at identical version numbers.
|
||||
- `@opencode/plugin` v2 pins move independently per repository (`package.json` is the source of truth).
|
||||
4. **Label cross-repo pull requests.** Apply the `cross-repo` label and reference the companion issue or commit in `Heretek-AI/<repo>#<number>` format.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Breaking changes to an existing contract path (`contract/v1/`) are forbidden; introduce a new contract version directory (`contract/v2/`) and open a tracking issue on the consumer repository.
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: evidence-pr
|
||||
description: Prepare and verify an evidence-backed pull request following Heretek-AI conventions. Use whenever staging changes, running pre-PR verification, writing a pull request body, or checking CI status after a push.
|
||||
license: MIT
|
||||
compatibility: opencode claude codex copilot
|
||||
metadata:
|
||||
audience: maintainers-and-agents
|
||||
workflow: github-pr
|
||||
opencode/slash: "true"
|
||||
---
|
||||
|
||||
# Evidence-Backed Pull Request Workflow
|
||||
|
||||
Every pull request in a `Heretek-AI` repository must prove its claims with executed command output and explicitly state what was not run.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Preparing a branch to open or update a pull request
|
||||
- Writing or updating a pull request description
|
||||
- Verifying that a push passes all required status checks
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Work on a topic branch.** Confirm you are not on `main`:
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
2. **Stage explicit repo-relative paths.** Never run `git add .` or `git add -A`. Verify staged files contain no machine-local paths or untracked scratch files:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
3. **Run local pre-commit and test gates.** Execute Lefthook and the repository's canonical test command, capturing the exact output:
|
||||
|
||||
```bash
|
||||
lefthook run pre-commit
|
||||
```
|
||||
|
||||
4. **Draft the PR body using executed evidence.** Populate all three required sections from `.github/pull_request_template.md`:
|
||||
- `## What and why`: Concise summary of the behavior change and motivation.
|
||||
- `## Evidence`: Exact commands executed and their trimmed verbatim stdout/stderr. Explicitly list any check or integration that was **not** run and why.
|
||||
- `## Linked issues`: Closing or tracking references (`Closes #123` or `Part of Heretek-AI/<repo>#45`).
|
||||
|
||||
5. **Sign off commits and verify CI after push.** Organization governance requires commit sign-off (`git commit --signoff`). After pushing, inspect every triggered workflow run:
|
||||
|
||||
```bash
|
||||
gh pr checks --watch
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Never claim a test passed without executing it in the current working tree.
|
||||
- Never reference another repository by local filesystem path (`../other-repo` or `/Users/...`); always use `Heretek-AI/<repo>`.
|
||||
- Merging to `main` and cutting releases are human maintainer actions unless explicitly delegated.
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
name: hygiene-and-workflow-audit
|
||||
description: Audit tracked files and GitHub Actions workflows for machine-local path leaks, unpinned actions, template injection, excessive permissions, and invalid SKILL.md frontmatter. Use when editing .github/workflows, adding skills, or debugging hygiene CI failures.
|
||||
license: MIT
|
||||
compatibility: opencode claude codex copilot
|
||||
metadata:
|
||||
audience: maintainers-and-agents
|
||||
workflow: security-hygiene
|
||||
opencode/slash: "true"
|
||||
---
|
||||
|
||||
# Hygiene and Workflow Security Audit
|
||||
|
||||
Enforces `Heretek-AI` repository hygiene and GitHub Actions supply-chain hardening locally before changes reach CI.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Creating or modifying `.github/workflows/*.yml`
|
||||
- Creating or updating `.agents/skills/*/SKILL.md`
|
||||
- Diagnosing a failure in the `hygiene / No machine-local paths` status check
|
||||
- Preparing a repository for zero-bypass ruleset enforcement
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Scan tracked files for machine-local paths.** Run the exact regex enforced by `Heretek-AI/.github/.github/workflows/hygiene.yml`:
|
||||
|
||||
```bash
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
! git grep -nIE "$PATTERN" -- .
|
||||
```
|
||||
|
||||
2. **Enforce GitHub Actions security invariants.** Every workflow under `.github/workflows/` must satisfy:
|
||||
- Top-level `permissions: contents: read` (or `permissions: {}` with job-level least-privilege grants).
|
||||
- Every third-party or official `uses:` step pinned to a full 40-character commit SHA with a `# vX.Y.Z` version comment.
|
||||
- `persist-credentials: false` on every `actions/checkout` step unless the job explicitly pushes git changes.
|
||||
- No untrusted context (`github.event.pull_request.title`, `github.event.issue.body`, `github.event.comment.body`, `github.head_ref`) interpolated directly inside `run:` blocks; always bind untrusted values to `env:` variables first.
|
||||
|
||||
3. **Run static workflow analyzers (`actionlint` and `zizmor`).**
|
||||
|
||||
```bash
|
||||
actionlint
|
||||
uvx [email protected] --format=plain .
|
||||
```
|
||||
|
||||
4. **Validate Agent Skills (`SKILL.md`).** If the repository contains `.agents/skills/` or `skills/`, run the validator:
|
||||
|
||||
```bash
|
||||
bash scripts/validate-skills.sh
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `actionlint` skips input validation on SHA-pinned actions; verify action input names against upstream `action.yml` when pinning.
|
||||
- Never add `pull_request_target` workflows that check out or execute untrusted PR head code.
|
||||
+12
-2
@@ -12,6 +12,15 @@ Delete these comments, and any section with nothing to say.
|
||||
Back every claim about behavior with something executed or read: test output,
|
||||
command output, a file and line. State what was not run.
|
||||
|
||||
## Agent Skills & Local Hooks
|
||||
|
||||
- Shared organization skills live in `.agents/skills/` (symlinked to `.opencode/skills/`, `.claude/skills/`, and `.github/skills/`):
|
||||
- `evidence-pr`: pre-PR verification and evidence formatting
|
||||
- `hygiene-and-workflow-audit`: machine-local path scan, `actionlint`, `zizmor`, and `SKILL.md` validation
|
||||
- `cross-repo-contract-check`: protocol and fixture verification across repositories
|
||||
- `adversarial-claim-check`: disposable worktree verification and invariant sabotage testing
|
||||
- Run `lefthook install` after cloning and `lefthook run pre-commit` before committing.
|
||||
|
||||
## Canonical surfaces
|
||||
|
||||
<!--
|
||||
@@ -32,10 +41,11 @@ one that spends money, the one that needs a secret.
|
||||
|
||||
| Invariant | Where |
|
||||
| --- | --- |
|
||||
| No machine-local paths in tracked files | `lefthook.yml` (`no-local-paths`), `.github/workflows/hygiene.yml` |
|
||||
|
||||
## Workflow
|
||||
|
||||
- Work on a topic branch and open a pull request. A maintainer merges and cuts releases.
|
||||
- Stage explicit paths.
|
||||
- After a push, check every workflow run.
|
||||
- Stage explicit paths and commit with `--signoff` (`git commit -s`).
|
||||
- After a push, check every workflow run (`gh pr checks --watch`).
|
||||
- Write repo-relative paths in tracked files, and `owner/name` for another repository.
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.5.15/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 100
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"correctness": {
|
||||
"noUnusedVariables": "error",
|
||||
"noUnusedImports": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "warn"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Ruff v0.17+ configuration for Heretek-AI Python repositories
|
||||
target-version = "py312"
|
||||
line-length = 100
|
||||
|
||||
[lint]
|
||||
select = ["E", "F", "I", "B", "UP", "S", "SIM", "RUF"]
|
||||
ignore = ["S101"]
|
||||
|
||||
[format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
@@ -0,0 +1,46 @@
|
||||
# Standardized Lefthook v2 configuration — Profile: bun-biome (Bun + Biome v2.5 + TypeScript)
|
||||
# Managed by Heretek-AI/.github fleet-sync. Local overrides belong in lefthook-local.yml.
|
||||
min_version: 1.10.0
|
||||
|
||||
pre-commit:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: no-local-paths
|
||||
run: |
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
if git grep -nIE "$PATTERN" -- {staged_files}; then
|
||||
echo "ERROR: Machine-local paths found in staged files. Use repo-relative paths or owner/name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: gitleaks
|
||||
run: |
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
gitleaks protect --staged --redact --no-banner
|
||||
fi
|
||||
|
||||
- name: biome-check
|
||||
glob: "*.{js,ts,jsx,tsx,mjs,cjs,json,jsonc}"
|
||||
stage_fixed: true
|
||||
run: bunx --bun @biomejs/biome check --write --no-errors-on-unmatched {staged_files}
|
||||
|
||||
- name: shellcheck
|
||||
glob: "*.sh"
|
||||
run: |
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
shellcheck {staged_files}
|
||||
else
|
||||
bash -n {staged_files}
|
||||
fi
|
||||
|
||||
- name: workflow-audit
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v actionlint >/dev/null 2>&1; then actionlint {staged_files}; fi
|
||||
if command -v zizmor >/dev/null 2>&1; then zizmor --format=plain {staged_files}; fi
|
||||
|
||||
pre-push:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: typecheck-and-test
|
||||
run: bun test
|
||||
@@ -0,0 +1,52 @@
|
||||
# Standardized Lefthook v2 configuration — Profile: node-zerodep (Node.js zero-dependency + node:test)
|
||||
# Managed by Heretek-AI/.github fleet-sync. Local overrides belong in lefthook-local.yml.
|
||||
min_version: 1.10.0
|
||||
|
||||
pre-commit:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: no-local-paths
|
||||
run: |
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
if git grep -nIE "$PATTERN" -- {staged_files}; then
|
||||
echo "ERROR: Machine-local paths found in staged files. Use repo-relative paths or owner/name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: gitleaks
|
||||
run: |
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
gitleaks protect --staged --redact --no-banner
|
||||
fi
|
||||
|
||||
- name: node-syntax-check
|
||||
glob: "*.{js,mjs,cjs}"
|
||||
run: |
|
||||
for f in {staged_files}; do
|
||||
node --check "$f"
|
||||
done
|
||||
|
||||
- name: json-validate
|
||||
glob: "*.json"
|
||||
run: jq empty {staged_files}
|
||||
|
||||
- name: shellcheck
|
||||
glob: "*.sh"
|
||||
run: |
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
shellcheck {staged_files}
|
||||
else
|
||||
bash -n {staged_files}
|
||||
fi
|
||||
|
||||
- name: workflow-audit
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v actionlint >/dev/null 2>&1; then actionlint {staged_files}; fi
|
||||
if command -v zizmor >/dev/null 2>&1; then zizmor --format=plain {staged_files}; fi
|
||||
|
||||
pre-push:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: node-test
|
||||
run: node --test
|
||||
@@ -0,0 +1,66 @@
|
||||
# Standardized Lefthook v2 configuration — Profile: python-uv (Python 3.12 + uv + Ruff v0.17 + ty + pnpm)
|
||||
# Managed by Heretek-AI/.github fleet-sync. Local overrides belong in lefthook-local.yml.
|
||||
min_version: 1.10.0
|
||||
|
||||
pre-commit:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: no-local-paths
|
||||
run: |
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
if git grep -nIE "$PATTERN" -- {staged_files}; then
|
||||
echo "ERROR: Machine-local paths found in staged files. Use repo-relative paths or owner/name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: gitleaks
|
||||
run: |
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
gitleaks protect --staged --redact --no-banner
|
||||
fi
|
||||
|
||||
- name: python-ruff
|
||||
glob: "*.{py,pyi}"
|
||||
group:
|
||||
piped: true
|
||||
jobs:
|
||||
- name: ruff-lint
|
||||
stage_fixed: true
|
||||
run: uv run ruff check --fix {staged_files}
|
||||
- name: ruff-format
|
||||
stage_fixed: true
|
||||
run: uv run ruff format {staged_files}
|
||||
|
||||
- name: toml-taplo
|
||||
glob: "*.toml"
|
||||
stage_fixed: true
|
||||
run: |
|
||||
if command -v taplo >/dev/null 2>&1; then
|
||||
taplo fmt {staged_files}
|
||||
fi
|
||||
|
||||
- name: shellcheck
|
||||
glob: "*.sh"
|
||||
run: |
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
shellcheck {staged_files}
|
||||
else
|
||||
bash -n {staged_files}
|
||||
fi
|
||||
|
||||
- name: workflow-audit
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v actionlint >/dev/null 2>&1; then actionlint {staged_files}; fi
|
||||
if command -v zizmor >/dev/null 2>&1; then zizmor --format=plain {staged_files}; fi
|
||||
|
||||
pre-push:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: uv-lock-check
|
||||
run: uv lock --check
|
||||
- name: python-typecheck
|
||||
run: |
|
||||
if uv run ty --version >/dev/null 2>&1; then
|
||||
uv run ty check
|
||||
fi
|
||||
@@ -0,0 +1,39 @@
|
||||
# Standardized Lefthook v2 configuration — Profile: universal (Docs, Skills, Docker, Config repos)
|
||||
# Managed by Heretek-AI/.github fleet-sync. Local overrides belong in lefthook-local.yml.
|
||||
min_version: 1.10.0
|
||||
|
||||
pre-commit:
|
||||
parallel: true
|
||||
jobs:
|
||||
- name: no-local-paths
|
||||
run: |
|
||||
PATTERN='file:///(home|Users|root)/|/(home|Users)/[^/[:space:]"'"'"'`<>]+/(Projects|Documents|Desktop|Downloads|\.gemini|\.claude|\.codex|\.cursor)(/|[^A-Za-z0-9_-]|$)'
|
||||
if git grep -nIE "$PATTERN" -- {staged_files}; then
|
||||
echo "ERROR: Machine-local paths found in staged files. Use repo-relative paths or owner/name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: gitleaks
|
||||
run: |
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
gitleaks protect --staged --redact --no-banner
|
||||
fi
|
||||
|
||||
- name: json-validate
|
||||
glob: "*.json"
|
||||
run: jq empty {staged_files}
|
||||
|
||||
- name: shellcheck
|
||||
glob: "*.sh"
|
||||
run: |
|
||||
if command -v shellcheck >/dev/null 2>&1; then
|
||||
shellcheck {staged_files}
|
||||
else
|
||||
bash -n {staged_files}
|
||||
fi
|
||||
|
||||
- name: workflow-audit
|
||||
glob: ".github/workflows/*.{yml,yaml}"
|
||||
run: |
|
||||
if command -v actionlint >/dev/null 2>&1; then actionlint {staged_files}; fi
|
||||
if command -v zizmor >/dev/null 2>&1; then zizmor --format=plain {staged_files}; fi
|
||||
Reference in new issue
Block a user