Files
holocron/plugins/kyberforge/.apm/skills/instructions-author/scripts/new-instructions.sh
T
Defame1297andClaude Code c52e351954 feat(kyberforge): add instructions-author skill for .apm/instructions files
Scaffolds and revises apm instructions files, with a throwaway-package
verification recipe because `apm compile --validate` always exits 0 and
Claude Code drops `description`. Routed from forge and linked from
apm-workflow's compile reference. Bumps kyberforge to 2.1.0 and the catalog
to 0.5.2.

Fixes #148

Co-Authored-By: Claude Code <[email protected]>
Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
2026-10-01 06:46:39 +00:00

117 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATE="$SKILL_DIR/../assets/templates/instructions.md"
usage() {
cat <<USAGE
Usage: new-instructions.sh <name> <root>
Scaffold an apm instructions file from the bundled template.
Arguments:
name Kebab-case stem. Becomes <name>.instructions.md and, after install,
the deployed rule's filename.
root Existing path at or below the target package. The script walks up for
the nearest apm.yml with a top-level type: field (instructions, skill,
hybrid or prompts); an apm.yml without type: is a marketplace-only
manifest and is skipped. Creates
<package-root>/.apm/instructions/<name>.instructions.md
Exit codes:
0 File created, or already existed (no-op)
1 Invalid arguments, missing root, no package found, or template not found
USAGE
}
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
usage
exit 0
fi
if [[ $# -lt 2 ]]; then
echo "Error: name and root are required." >&2
echo "" >&2
usage >&2
exit 1
fi
NAME="$1"
ROOT="${2/#\~/$HOME}"
if ! grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$' <<< "$NAME"; then
echo "Error: name must use lowercase letters, numbers, and hyphens only." >&2
echo " No leading, trailing, or consecutive hyphens." >&2
echo " Received: '$NAME'" >&2
exit 1
fi
if [[ ! -f "$TEMPLATE" ]]; then
echo "Error: template not found at '$TEMPLATE'." >&2
echo " Run this script from its original location inside the instructions-author skill." >&2
exit 1
fi
if [[ ! -d "$ROOT" ]]; then
echo "Error: root directory '$ROOT' does not exist." >&2
exit 1
fi
ROOT="$(cd "$ROOT" && pwd)"
# Same marker as agent-author's new-agent.sh: a top-level type: naming one of
# the four package types, with matching quotes if quoted.
is_apm_package_manifest() {
local apm_yml="$1" line
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^type:[[:space:]]*(instructions|skill|hybrid|prompts)([[:space:]]|$) ]]; then
return 0
fi
if [[ "$line" =~ ^type:[[:space:]]*([\"\'])(instructions|skill|hybrid|prompts)([\"\'])([[:space:]]|$) ]] \
&& [[ "${BASH_REMATCH[1]}" == "${BASH_REMATCH[3]}" ]]; then
return 0
fi
done < "$apm_yml"
return 1
}
PACKAGE_ROOT=""
current="$ROOT"
while true; do
if [[ -f "$current/apm.yml" ]] && is_apm_package_manifest "$current/apm.yml"; then
PACKAGE_ROOT="$current"
break
fi
if [[ -e "$current/.git" ]]; then
break
fi
parent="$(dirname "$current")"
[[ "$parent" == "$current" ]] && break
current="$parent"
done
if [[ -z "$PACKAGE_ROOT" ]]; then
echo "Error: no apm package found at or above '$ROOT'." >&2
echo " Instructions only deploy from a package's .apm/instructions/. Run" >&2
echo " /apm-workflow configure (apm plugin init) there first, then retry." >&2
exit 1
fi
DEST_DIR="$PACKAGE_ROOT/.apm/instructions"
DEST="$DEST_DIR/$NAME.instructions.md"
if [[ -f "$DEST" ]]; then
echo "Skipping '$DEST' — already exists." >&2
exit 0
fi
mkdir -p "$DEST_DIR"
cp "$TEMPLATE" "$DEST"
echo "Created: $DEST" >&2
echo "" >&2
echo "Next steps:" >&2
echo " 1. Fill in $DEST — replace every FILL IN: placeholder and delete the comments." >&2
echo " 2. Check '$NAME' does not collide with a hand-authored rule: install overwrites" >&2
echo " <target>/rules/$NAME.* on most targets without warning." >&2
echo " 3. Verify with a real compile, not --validate: apm compile --dry-run --target <target>" >&2