22 Commits

Author SHA1 Message Date
dd934d3b07 fix(tests): exclude .claude/worktrees/ from test-file discovery
find-based discovery in run-bats.sh and run-tests.sh picked up test
files nested inside on-disk git worktree checkouts under
.claude/worktrees/ (untracked, created by background agent isolation),
whose submodule-based test_helper isn't initialized there — causing
spurious pre-push failures unrelated to any real change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 11:29:20 +00:00
2102c8c917 feat(gitea): add gitea-orchestrate agent-facing dispatcher
Adds the deterministic, agent-facing counterpart to gitea-workflow per
docs/adr/0011-gitea-skill-deep-modules.md, mirroring git-orchestrate's
shape: structured request/response JSON, safety gates on destructive
ops (delete-branch/release/tag/label/milestone/file, merge-pr), and
routing across the six gitea domain skills without conversational
disambiguation. Authored via kyberforge:agent-author directly (not
forge) since the artifact type was already known, and validated clean
via kyberforge:agent-audit (structure, provenance, and qualitative
checks all pass). Bumps plugin version 1.2.0 -> 1.3.0 in both manifests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:24:30 +00:00
bc42a99ad2 feat(gitea): add gitea-workflow human-facing router skill
# Conflicts:
#	plugins/gitea/skills/gitea-workflow/README.md
#	plugins/gitea/skills/gitea-workflow/SKILL.md
#	plugins/gitea/skills/gitea-workflow/references/sources.md
2026-07-05 11:16:59 +00:00
0f138f27db feat(gitea): add gitea-workflow skill (human-facing dispatcher)
Adds the human-facing entry point and dispatcher for the Gitea
integration per docs/adr/0011-gitea-skill-deep-modules.md. Preserves
the retired flat skill's default no-args status view (open issues +
open PRs, composed via list_issues/list_pull_requests) and extends
its dispatch table to route ambiguous requests across all 6 domain
skills (issues, labels/milestones, prs, branches, files, releases) —
the old table only covered 4 of these. The skill only calls
gitea-mcp tools directly for the composed status view; every other
operation is a routed handoff to the owning sibling skill, keeping
execution logic (call signatures, gotchas, confirmation gates) owned
in one place.

Bumps plugins/gitea version 1.1.0 -> 1.2.0 in both manifests for the
new skill. Passed structural validation, provenance validation, and
an independent clean-context skill-audit recheck (one finding fixed:
allowed-tools was missing the Skill tool needed for routing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:16:31 +00:00
c47436d6d3 feat(gitea): add gitea-workflow human-facing router skill
Adds the human-facing entry point and router for the Gitea integration,
replacing the old flat /gitea skill per ADR 0011. It composes the six
domain skills (gitea-issues, gitea-labels-milestones, gitea-prs,
gitea-branches, gitea-files, gitea-releases) rather than calling any
Gitea MCP tool directly, mirroring git-workflow's router shape.

Preserves the old flat skill's default no-args status view (open
issues + open PRs, two sections) and adds deterministic ambiguous
issue-vs-PR number resolution via issue_read's is_pull field, since
issues and PRs share one number space in Gitea.

Authored via kyberforge:forge -> skill-author, with an independent
clean-context skill-audit re-run confirming no findings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:15:56 +00:00
bc094819a5 fix(gitea-prs): document inline-comment field-name asymmetry
An independent clean-context audit of the newly-authored gitea-prs skill
flagged that old_line_num/new_line_num (write path, pull_request_review_write
create) and position/old_position (read path, get_review_comments) name the
same concept differently — the same class of write/read field mismatch that
produced the review_scomments typo elsewhere in this domain. Adds one
clarifying sentence to references/reviews.md so an agent skimming only one
side doesn't assume symmetric field names.
2026-07-05 11:05:51 +00:00
21b052b353 feat(gitea): add gitea-issues skill 2026-07-05 11:03:32 +00:00
98980d3d1f feat(gitea): add gitea-issues skill
Covers list_issues, issue_read, issue_write, and search_issues, closing out
all four enrichments deferred from issue #6 comment #848: label inference
(delegated to gitea-labels-milestones), milestone assignment on create,
an assignee workaround for the blocked get_me/read:user scope, and the
"Depends on #N" dependency-linking convention validated by Gitea's
automatic cross-reference rendering.

Call signatures were re-verified live via ToolSearch against the deployed
gitea-mcp server rather than copied from api-reference.md, per ADR 0011 --
this caught that list_issues has no `type` or `milestones` parameter on the
live schema, despite the research doc documenting both (the exact drift
that caused issue #6 comment #849).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:02:46 +00:00
e455c68fe4 feat(gitea): add gitea-prs skill
Covers list_pull_requests, pull_request_read, pull_request_write, and
pull_request_review_write, split out of the flat plugins/bin/skills/gitea
PR-dispatch logic per ADR 0011. Composes gitea-labels-milestones for
label/milestone ID resolution instead of duplicating that lookup.

Tool signatures were cross-checked live via ToolSearch against the deployed
gitea-mcp server rather than copied from api-reference.md, per the ADR's
schema-drift mitigation process.
2026-07-05 11:00:51 +00:00
22d15cf734 docs(gitea): recover signed-commit/reverse-proxy gotchas from orphaned commit
Commit 7ad9fb6 (an orphaned parallel gitea-files authoring run, superseded
by 0c7dd04 during a worktree merge race) backfilled two real gotchas into
troubleshooting.md that the winning version didn't carry: protected-branch
signed-commit rejection and reverse-proxy 413 on large file writes, both
sourced from context7:/websites/gitea. Recovering them since they're
genuine findings, not duplicated elsewhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 10:49:51 +00:00
14369ae103 fix(gitea): fill provenance gap in gitea-branches sources.md
The gitea-branches skill was authored before the context7 research
backfill (workflow-conventions.md) landed on this branch, so its
sources.md was missing context7-websites-gitea and
context7-gitea-tea-cli — both present with status `extracted` in the
upstream research doc, which validate-provenance.sh requires every
consuming skill to account for. Adds context7-websites-gitea (credited
for the protected-branch gotcha) and context7-gitea-tea-cli (marked
`(none)` — its release/tag content is out of scope for branches/commits).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 10:42:24 +00:00
696079cf3e feat(gitea): add gitea-releases skill 2026-07-05 10:40:17 +00:00
a17f65db22 feat(gitea): add gitea-releases skill
Covers releases and tags (list/get/create/delete) — all verified
working with the current write:issue/write:repository token scope.
2026-07-05 10:40:05 +00:00
7d30c454ca feat(gitea): add gitea-files skill 2026-07-05 10:39:00 +00:00
0c7dd04a46 feat(gitea): add gitea-files skill
Covers get_file_contents, get_dir_contents, get_repository_tree,
create_or_update_file, delete_file — all verified working with the
current write:issue/write:repository token scope.
2026-07-05 10:38:52 +00:00
3de8ff5d15 feat(gitea): add gitea-labels-milestones skill 2026-07-05 10:38:22 +00:00
fd837b87d9 feat(gitea): add gitea-branches skill (branches + commits) 2026-07-05 10:38:22 +00:00
a3853f78b1 feat(gitea): add gitea-labels-milestones skill
Cross-cutting skill for label and milestone operations, composed by
gitea-issues and gitea-prs. Includes the label inference guide deferred
from issue #6 comment #848.
2026-07-05 10:38:09 +00:00
5854961c1f feat(gitea): add gitea-branches skill (branches + commits)
Adds plugins/gitea/skills/gitea-branches/ per ADR 0011, covering
list_branches/create_branch/delete_branch (migrated from the flat
plugins/bin/skills/gitea/ dispatch) plus list_commits/get_commit (new
read-only commit-history domain). Call signatures were re-verified live
via ToolSearch against the deployed gitea-mcp server rather than copied
from api-reference.md, per issue #6 comment #849's root-cause fix.

Bumps the gitea plugin to 1.1.0 in both manifests for the new skill.
2026-07-05 10:35:12 +00:00
4e98df7445 docs(gitea): backfill external workflow-convention research via context7
Merge research backfill for issue #6: adds external/best-practice
content (label taxonomy, PR review conventions, milestone semantics,
issue/PR cross-linking, release semver conventions) sourced from
context7, closing the gap left by the original docs.gitea.com timeout.
2026-07-05 10:23:35 +00:00
0d2a6cd839 docs(adr): record gitea plugin deep-module redesign decision
Captures the grill-with-docs session for issue #6: relocate gitea
skill from plugins/bin/ to plugins/gitea/, split into 6 domain skills
plus a workflow orchestrator and orchestrate agent, expand scope to
3 token-verified new domains, and resolve the schema-verification
question from comment #849.
2026-07-05 10:23:34 +00:00
12f60f42b7 docs(gitea): backfill external workflow-convention research via context7
Existing gitea research docs were 100% code-derived from gitea-mcp
source with zero external content (the original docs.gitea.com fetch
timed out and was never retried). Adds workflow-conventions.md sourced
from context7 /websites/gitea and /git_gitea_com/gitea_tea: scoped/
exclusive label conventions, PR review/branch-protection rules,
release/tag semver conventions, and automatic issue/PR cross-reference
linking (validates the dependency-linking convention for issue #6).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 10:23:11 +00:00
12 changed files with 16 additions and 81 deletions

View File

@@ -24,10 +24,3 @@ Read these on demand:
## Working context
This repo is built by a junior developer as a homelab tool intended to scale to professional environments. Challenge ideas and reference industry standards rather than validate assumptions. Explain the why behind decisions — assume the user is learning, not just executing. Flag significant actions before taking them.
## Subagent orchestration
- **Forks stop when their assigned task is done.** A `fork` inherits the coordinator's full context, including visibility into any shared TaskList. That visibility is not license to keep going: once a fork's assigned task is reported complete, it must stop rather than autonomously picking up further items from the list. Forks that keep pulling work race against the coordinator's own orchestration and can duplicate or conflict with tasks the coordinator has separately delegated.
- **Don't hand a fork a TaskList that includes governance-gated actions** (push, publish, merge) unless you are prepared for it to act on those items without a fresh confirmation round. A fork acting on its own initiative is not party to any pending human confirmation the coordinator is mid-flow on, so it can bypass a gate that was meant to hold.
- **`TaskGet`/`TaskUpdate`/`TaskList` only work for forks.** Fresh (non-fork) subagents cannot discover or call these tools. When delegating to a fresh subagent, the coordinator owns all task-list bookkeeping itself — claim and complete the entry on the agent's behalf — rather than instructing the fresh agent to self-claim or self-complete.
- **Worktree/branch cleanup is part of closing out the PR, not a separate step.** When a coordinator creates a worktree (`Agent(isolation: "worktree")` or `git worktree add` directly) to land a PR, merging that PR is not the end of the task. Immediately after verifying the merge: run `git worktree remove --force --force <path>` (the double `-f` is required whenever the worktree initialized submodules to run tests — assume it did, this repo has several), then `git branch -d` both the feature branch and any `worktree-agent-<id>` isolation branch the `Agent` tool auto-created for that worktree — `git worktree remove` deletes neither branch on its own. Do this without waiting for the user to notice stale branches/worktrees and ask.

View File

@@ -126,14 +126,6 @@ Two forks independently fixed `references/sources.md` with different approaches
When briefing an agent to implement a new skill, the instinct is to tell it to write the SKILL.md and supporting files directly. This bypasses Step 5 of the skill-author process (provenance), which requires reading all research `sources.md` files and recording every `extracted` slug in META.md. The `validate-provenance.sh` script catches the gap — but only after the commit, requiring a fix round. This pattern recurred twice in one session (plugin-author and marketplace-author initial implementation, then again in the first round of fix agents). Fix: briefs for implementation agents must explicitly say "invoke `/skill-author` (read and follow `plugins/kyberforge/skills/skill-author/SKILL.md`)" — not "write the skill files." Invoking the skill is the only reliable way to ensure all process gates, including provenance, run.
## 2026-07-05 — Repo root is a bare checkout; work happens in worktrees only
`/root/ai-development/.git` has `core.bare = true` — the root directory itself has no working tree. Running plain `git status`, `git commit`, or editing tracked files at the root fails (`fatal: this operation must be run in a work tree`) or silently produces edits git can never see or commit — not discoverable until the error is hit, or worse, missed entirely. All real work — including one-line docs fixes — requires `git worktree add <path> -b <branch> origin/main` first. Fresh worktrees also don't have submodules (`tests/bats`, `docs/wiki`, etc.) initialized, so the `run-tests` pre-push hook fails until `git submodule update --init --recursive` is run. Fix: before any edit/commit in this repo, confirm a working tree exists (`git rev-parse --is-inside-work-tree`); if not, create a worktree first, and initialize submodules before attempting to push.
## 2026-07-05 — Local remote-tracking refs go stale; verify against the Gitea API before asking
After a PR merge (with Gitea's default auto-delete-branch behavior), `git branch -a` still showed the remote feature branch — the local `remotes/origin/*` ref hadn't been pruned. This led to asking the user for confirmation to delete a branch that was already gone server-side, which they correctly pushed back on. Fix: before asking the user to confirm a git/PR cleanup action, check the authoritative remote state directly (e.g. `mcp__gitea__list_branches`, or `git fetch --prune` first) rather than trusting local remote-tracking refs, which are not automatically kept in sync.
## 2026-05-18 — Planning meta-commentary does not belong in deployed artifacts
During write-skill refactor, an "open thread" note (about a deferred research step) was written directly into the SKILL.md Process section. The user caught it. The rule it violated: a deployed artifact (SKILL.md, a runtime file loaded by agents) must not contain planning meta-commentary — deferred items, open threads, and implementation notes belong in the issue file, which is the planning artifact. The skill body should contain only content relevant to runtime execution. If a decision is deferred, record it in the issue and leave no trace in the skill. The distinction: issue = planning record; skill = executable instruction.

View File

@@ -1,4 +1,5 @@
{
"agents": "agents/",
"author": {
"email": "defame1297@rkdr.net",
"name": "Defame1297"

View File

@@ -1,4 +1,5 @@
{
"agents": "agents/",
"author": {
"email": "defame1297@rkdr.net",
"name": "Defame1297"
@@ -15,5 +16,8 @@
"license": "MIT",
"mcpServers": ".mcp.json",
"name": "core",
"skills": [
"skills/"
],
"version": "1.0.0"
}

View File

@@ -1,4 +1,5 @@
{
"agents": "agents/",
"author": {
"email": "defame1297@rkdr.net",
"name": "Defame1297"

View File

@@ -8,5 +8,5 @@
"keywords": [],
"license": "MIT",
"name": "kyberforge",
"version": "1.2.3"
"version": "1.2.2"
}

View File

@@ -13,5 +13,5 @@
"skills": [
"skills/"
],
"version": "1.2.3"
"version": "1.2.2"
}

View File

@@ -57,7 +57,7 @@ Before touching the filesystem, confirm you have:
- [ ] Agent purpose — one sentence describing the task this agent handles
- [ ] Trigger condition — when should the runtime delegate to this agent?
If any are missing, stop and ask before proceeding. Then capture `git log --oneline -1` before touching the filesystem — Step 5 needs it to verify a real commit landed.
If any are missing, stop and ask before proceeding.
Verify `kyberforge:agent-audit` is available — it ships with the kyberforge plugin and is co-installed with this skill. If unavailable, stop and tell the user to install the kyberforge plugin before continuing.
@@ -180,23 +180,19 @@ Run this checklist before invoking the audit:
- [ ] If plugin scope: no `hooks`, `mcpServers`, or `permissionMode` (silently ignored at plugin scope)
- [ ] System prompt body present and non-empty
- [ ] No `FILL IN:` placeholders remain
- [ ] No `<!-- -->` template comments remain in frontmatter
**Copilot CLI file (`<name>.agent.md`):**
- [ ] File extension is `.agent.md` (not `.md`)
- [ ] `name` field matches the filename stem (e.g. `name: my-agent` in `my-agent.agent.md`)
- [ ] `description` field present
- [ ] No Claude Code-only fields (`maxTurns`, `isolation`, `memory`, `permissionMode`, `effort`, `hooks`, `mcpServers`)
- [ ] No Claude Code-only fields (`maxTurns`, `isolation`, `memory`, `permissionMode`, `effort`)
- [ ] System prompt body present and non-empty
- [ ] Body does not exceed 30,000 characters
- [ ] No `<!-- -->` template comments remain in frontmatter
If the destination is inside a plugin directory, apply a **minor bump** to the `version` field in both `plugin.json` and `.claude-plugin/plugin.json` at the plugin root in the same edit pass (e.g. `1.0.4` → `1.1.0`).
Invoke the `kyberforge:agent-audit` skill directly on the created files to confirm the pair is valid before closing.
**Commit verification.** Capture `git log --oneline -1` before Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the new agent files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the agent as done once the hash has actually changed.
## Improving an existing agent
### Step 1 — Verify inputs
@@ -205,10 +201,6 @@ Confirm the agent files exist and at least one improvement signal is present in
If no signals: "This skill applies existing signals to an agent. For a blind review, examine the files manually or run a grill session first."
Verify `kyberforge:agent-audit` is available — it ships with the kyberforge plugin and is co-installed with this skill. If unavailable, stop and tell the user to install the kyberforge plugin before continuing.
Capture `git log --oneline -1` now, before making any edits — Step 5 needs it to verify a real commit landed.
**Partial state** — if one provider file exists but the other does not, scaffold the missing file first (run `bash scripts/new-agent.sh <name> <root>` — the file-by-file no-op means only the missing file is created), then continue with the improve flow on both files.
### Step 2 — Gather and group signals
@@ -232,8 +224,6 @@ Before editing, state which root causes were identified, what evidence supports
Edit any file the signals point to. Generalize the fix — find the underlying gap, not the specific example that failed. For every sentence you add, ask: "Would the agent get this wrong without it?" A shorter, focused definition consistently outperforms an exhaustive one. For Copilot files, verify no Claude Code-only fields are introduced.
If the edit adds or removes research-sourced content, update `source_keys` in the edited file(s) and the corresponding entry in `sources.md` per Create flow's Step 4.
### Step 5 — Validate and close
Re-run the validation checklist from the create flow's Step 5 on any edited file.
@@ -241,5 +231,3 @@ Re-run the validation checklist from the create flow's Step 5 on any edited file
If the agent lives inside a plugin directory, apply a **patch bump** to the `version` field in both `plugin.json` and `.claude-plugin/plugin.json` at the plugin root in the same edit pass (e.g. `1.0.4` → `1.0.5`).
Invoke the `kyberforge:agent-audit` skill directly on the edited files to confirm no regressions before closing.
**Commit verification.** Capture `git log --oneline -1` at the start of Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the changed files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the improvement as done once the hash has actually changed.

View File

@@ -26,7 +26,6 @@ metadata:
- Patching per symptom is the default failure mode. Three eval failures may all trace to one missing instruction — always identify the root cause before editing.
- Do not create new scripts unless a signal explicitly calls for it. Writing scripts from scratch requires transcript analysis that is out of scope here; flag the opportunity as a suggestion instead.
- Never spawn a subagent to audit or recheck your own work during an authoring pass. Run `/skill-audit` yourself, inline, in the same context as the edits you just made. A *separate* independent recheck via a clean-context subagent is the `/forge` skill's outer-loop responsibility exclusively — delegating it inward here duplicates that layer and introduces a race: a stray self-spawned subagent can have its worktree torn down by concurrent cleanup, destroying an uncommitted draft before it was ever safe.
## Route
@@ -51,7 +50,6 @@ Design for one coherent user intent — skills too narrow force multiple loads p
- [ ] A clear purpose — what specific task will this skill handle?
- [ ] Trigger scenarios — when should an agent activate it, including indirect cases?
- [ ] Skill name (kebab-case) and destination path
- [ ] Capture `git log --oneline -1` now, before touching the filesystem — Step 6 needs it to verify a real commit landed
If any are missing, stop and ask the user before proceeding.
@@ -224,8 +222,6 @@ All FAIL findings must be resolved before the skill is considered done.
If the skill is versioned (`metadata.version`), set it to the next **minor** version (e.g. `0.2.0` → `0.3.0`). New skills without a prior version start at `0.1.0`.
**Commit verification.** Capture `git log --oneline -1` before Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the new skill files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the skill as done once the hash has actually changed.
## Improving an existing skill
### Step 1 — Verify inputs
@@ -234,8 +230,6 @@ Confirm the skill directory path exists and that at least one improvement signal
If the skill dir is missing, ask for it. If no signals are present, stop: "This skill applies existing signals to a skill. For a blind review without signals, use `/skill-audit` instead."
Capture `git log --oneline -1` now, before making any edits — Step 5 needs it to verify a real commit landed.
Signals can come from anywhere in the conversation or referenced files:
- Grill session output (most common predecessor in the factory sequence)
- `/skill-audit` findings (PASS/FAIL/SUGGESTION punch list)
@@ -278,6 +272,8 @@ Edit any file in the skill directory that the signals point to: SKILL.md, script
If a signal points to a script or reference file, edit that file directly rather than adding a workaround in SKILL.md.
**On scripts**: Fix and edit existing scripts freely when signals point to them.
### Step 5 — Validate and close
Before running the audit, confirm:
@@ -288,5 +284,3 @@ Before running the audit, confirm:
Run `/skill-audit` on the skill directory. Resolve any FAIL findings before considering the improvement complete.
If the skill is versioned (`metadata.version`), bump the **patch** version (e.g. `0.1.0` → `0.1.1`).
**Commit verification.** Capture `git log --oneline -1` at the start of Step 1 and keep it. Once the audit is clean, run `git add` and `git commit` for the changed files — do not stop at staging. Then run `git log --oneline -1` again and confirm the hash changed from the one you captured at the start. A non-empty `git diff --stat` is not sufficient proof of completion: staged-but-uncommitted work isn't part of any commit and can be silently lost if the working tree is cleaned up before a commit lands. Only report the improvement as done once the hash has actually changed.

View File

@@ -30,16 +30,10 @@ done
# Install git hooks into the current repo checkout
HOOKS_SRC="$REPO_ROOT/scripts/git-hooks"
if [[ -d "$HOOKS_SRC" ]]; then
# Unset inherited GIT_DIR/GIT_WORK_TREE — set by git when this script runs as
# a hook (e.g. pre-push), they override -C's directory-based discovery and
# would resolve against the invoking repo instead of $REPO_ROOT.
GIT_HOOKS_DIR="$(env -u GIT_DIR -u GIT_WORK_TREE git -C "$REPO_ROOT" rev-parse --git-path hooks)"
[[ "$GIT_HOOKS_DIR" = /* ]] || GIT_HOOKS_DIR="$REPO_ROOT/$GIT_HOOKS_DIR"
mkdir -p "$GIT_HOOKS_DIR"
for hook_file in "$HOOKS_SRC"/*; do
[[ -f "$hook_file" ]] || continue
hook_name="$(basename "$hook_file")"
dest_hook="$GIT_HOOKS_DIR/$hook_name"
dest_hook="$REPO_ROOT/.git/hooks/$hook_name"
cp "$hook_file" "$dest_hook"
chmod +x "$dest_hook"
done

View File

@@ -7,12 +7,8 @@ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BATS="$REPO_ROOT/tests/bats/bin/bats"
if [[ ! -x "$BATS" ]]; then
echo "bats not found at $BATS — initializing submodules..." >&2
git -C "$REPO_ROOT" submodule update --init --recursive
fi
if [[ ! -x "$BATS" ]]; then
echo "Error: bats still not found at $BATS after submodule init" >&2
echo "Error: bats not found at $BATS" >&2
echo " Run: git submodule update --init --recursive" >&2
exit 1
fi

View File

@@ -3,12 +3,6 @@
# Runs install.sh from a temp repo to avoid touching the real .git/hooks/.
set -euo pipefail
# This script may itself run inside a git hook (e.g. pre-push), which sets
# GIT_DIR/GIT_EXEC_PATH/etc. in the environment. `git init`/`git -C` below
# would silently re-target the inherited GIT_DIR instead of creating an
# isolated repo in $TEMP_REPO, so start from a clean slate.
for var in $(compgen -v | grep '^GIT_'); do unset "$var"; done
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PASS=0
FAIL=0
@@ -28,7 +22,7 @@ TEMP_HOME="$(mktemp -d)"
trap 'rm -rf "$TEMP_REPO" "$TEMP_HOME"' EXIT
mkdir -p "$TEMP_REPO/scripts"
git -C "$TEMP_REPO" init -q
mkdir -p "$TEMP_REPO/.git/hooks"
# Minimal deploy-manifest.sh — empty deploy lists so install.sh reaches the
# hook-copy block without attempting to copy files that don't exist in the
@@ -96,28 +90,6 @@ else
fi
rmdir "$HOOKS_SRC/not-a-hook"
# ---------------------------------------------------------------------------
echo ""
echo "--- hook install: resolves correctly when GIT_DIR is inherited (hook context) ---"
# ---------------------------------------------------------------------------
# Git sets GIT_DIR/GIT_WORK_TREE for child processes when this script itself
# runs as a hook (e.g. pre-push). Simulate that and confirm install.sh still
# resolves hooks against $TEMP_REPO, not the inherited GIT_DIR.
OTHER_REPO="$(mktemp -d)"
git -C "$OTHER_REPO" init -q
if HOME="$TEMP_HOME" GIT_DIR="$OTHER_REPO/.git" GIT_WORK_TREE="$OTHER_REPO" \
bash "$TEMP_REPO/scripts/install.sh" > /dev/null 2>&1; then
if [[ -f "$TEMP_REPO/.git/hooks/post-push" ]]; then
pass "resolves \$TEMP_REPO/.git/hooks/ even with inherited GIT_DIR"
else
fail "installed into inherited GIT_DIR instead of \$TEMP_REPO"
fi
else
fail "install.sh failed when GIT_DIR/GIT_WORK_TREE were inherited"
fi
rm -rf "$OTHER_REPO"
# ---------------------------------------------------------------------------
echo ""
echo "--- hook install: idempotent ---"