mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
238964fdd2
Workflows get the skills treatment (operator decision): canonical source in the product tree, installed by a product verb, Claude-only labeled as such. **What moves:** all seven Claude workflow scripts + README migrate from force-added exceptions inside the gitignored `.claude/` to a tracked top-level `workflows/` (sibling of `skills/`) — the four existing conveyors plus `audit-dimensions`, `verify-fixes`, `implement-wave`: three thin, args-parameterized orchestration conveyors extracted from this session's hand-rolled waves, contract-reviewed, and smoke-proven through the real Workflow runtime (the smoke caught two contract gaps static review could not: an `export default` wrapper the runtime never invokes, and args arriving as a JSON string — both fixed, string-args tolerance now built in). **New verb:** `ao workflows link` / `unlink` mirror `ao skills link` semantics — dry-run `--json`, refuse to replace real files or foreign links, unlink only checkout-owned links — targeting the project-local `.claude/workflows/` where Claude Code resolves named workflows (`--into` overrides). Checkout identity reuses the skillsapp marker discipline, fail-closed. Claude-only runtime adapter, same doctrine as the Codex-only `skills-codex/`. **Legacy surfaces repointed:** `install-workflows.sh` (user-global $HOME installer), `check-workflow-drift.sh` + gate comment, `check-bdd-foundry-markers.sh`; spine allowlist + YAML-probe excuse + go-cli.md spine region gain the workflows group; COMMANDS.md, cli-surface projections, and surface-count fixture regenerated; new tests carry per-command git-env scrubbing (test-isolation ratchet back at baseline). **Built BY the workflow being canonized** — `implement-wave` orchestrated its own canonization: two disjoint-ownership lanes plus a seam-checking verifier that ran the real binary's link → resolve → unlink cycle in the live tree (both lanes RESOLVED). The lanes correctly *refused* to self-approve their command into the spine invariants and handed integration three flagged edits instead. **Expected local gate note:** `workflow.install-drift` correctly FAILS on machines whose user-global `~/.claude/workflows` links still point at the old location — that is the transition it exists to catch. CI stays green (absent→skip). **Post-merge operator step:** `cd ~/dev/agentops && git pull && bash scripts/install-workflows.sh`. **Verified:** full suite 63/63 pkgs; golangci-lint clean; `gate check --full` over this range = 66/67 with only the documented install-drift environment finding; workflows smoke-run evidence in session logs.
68 lines
2.3 KiB
Bash
Executable File
68 lines
2.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install-workflows.sh — install repo-canonical Claude workflows (workflows/)
|
|
# into $HOME/.claude/workflows as symlinks (ag-wi9w1). Project-local installs
|
|
# use `ao workflows link` instead.
|
|
#
|
|
# Usage: bash scripts/install-workflows.sh [name.js ...]
|
|
# No args: install every repo-tracked workflows/*.js.
|
|
# With args: install only the named workflows (arg-scoped).
|
|
#
|
|
# Semantics (per the canonicalize-bdd-foundry-workflow spec, C2):
|
|
# - repo root resolved from cwd git; dest dir $HOME/.claude/workflows (mkdir -p)
|
|
# - dest is a symlink (incl. dangling) -> ln -sfn to the repo canonical (idempotent)
|
|
# - dest is a byte-equal regular file -> replace with the symlink
|
|
# - dest is a divergent regular file -> cp -p backup to
|
|
# <name>.pre-canonicalize-<UTC-ts> (path printed), then ln -sfn
|
|
# - dest absent -> ln -sfn
|
|
# Touches ONLY $HOME; never writes into the repo. Exits non-zero on any real failure.
|
|
set -euo pipefail
|
|
shopt -s lastpipe 2>/dev/null || true
|
|
umask 022
|
|
|
|
# shellcheck disable=SC1007,SC1091
|
|
. "$(CDPATH= cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/repo-root.sh"
|
|
repo_root="$(resolve_repo_root)"
|
|
src_dir="$repo_root/workflows"
|
|
dest_dir="$HOME/.claude/workflows"
|
|
mkdir -p "$dest_dir"
|
|
|
|
if [ "$#" -eq 0 ]; then
|
|
for f in "$src_dir"/*.js; do
|
|
[ -e "$f" ] || continue
|
|
set -- "$@" "$(basename "$f")"
|
|
done
|
|
fi
|
|
|
|
status=0
|
|
for name in "$@"; do
|
|
src="$src_dir/$name"
|
|
dest="$dest_dir/$name"
|
|
if [ ! -f "$src" ]; then
|
|
echo "ERROR: no such workflow in repo: $name ($src)" >&2
|
|
status=1
|
|
continue
|
|
fi
|
|
if [ -L "$dest" ]; then
|
|
ln -sfn "$src" "$dest"
|
|
echo "installed (symlink refreshed): $dest -> $src"
|
|
elif [ -f "$dest" ]; then
|
|
if cmp -s "$dest" "$src"; then
|
|
ln -sfn "$src" "$dest"
|
|
echo "installed (byte-equal copy replaced with symlink): $dest -> $src"
|
|
else
|
|
backup="$dest.pre-canonicalize-$(date -u +%Y%m%dT%H%M%SZ)"
|
|
cp -p "$dest" "$backup"
|
|
echo "backup of divergent local file: $backup"
|
|
ln -sfn "$src" "$dest"
|
|
echo "installed (divergent copy backed up, then symlinked): $dest -> $src"
|
|
fi
|
|
elif [ -e "$dest" ]; then
|
|
echo "ERROR: $dest exists and is neither a regular file nor a symlink; refusing" >&2
|
|
status=1
|
|
else
|
|
ln -sfn "$src" "$dest"
|
|
echo "installed (new symlink): $dest -> $src"
|
|
fi
|
|
done
|
|
exit "$status"
|