ryansch

ryansch / plannotator-update

Last active 1 month ago

Like 0

ryansch revised this gist 1 month ago · 0e89b03

1 file changed

plannotator-update renamed to plannotator-update.sh

File renamed without changes

ryansch revised this gist 1 month ago · b576ff8

1 file changed, 99 insertions

plannotator-update (file created)
@@ -0,0 +1,99 @@
1 + #!/usr/bin/env bash
2 + #
3 + # plannotator-update — update Plannotator, then re-apply the local --gate --json
4 + # patch that the installer overwrites.
5 + #
6 + # The upstream `plannotator-annotate` skill invokes the binary with no flags.
7 + # Ryan runs `permissions.defaultMode: auto`, so the plugin's plan-review hook
8 + # never fires and `/plannotator-annotate` is the only path to an Approve button.
9 + # `--gate` adds that button; `--json` makes Close emit {"decision":"dismissed"}
10 + # instead of empty stdout and lets approve-with-notes survive. Flags go *before*
11 + # $ARGUMENTS so nothing the user types can swallow them as a value
12 + # (--result-file is the only value-taking flag).
13 + #
14 + # Usage:
15 + # plannotator-update # install latest, then patch
16 + # plannotator-update --patch-only # skip the download, just re-apply the patch
17 + # plannotator-update --check # report patch state, change nothing
18 +
19 + set -euo pipefail
20 +
21 + INSTALL_URL="https://plannotator.ai/install.sh"
22 + SKILL="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/plannotator-annotate/SKILL.md"
23 +
24 + UNPATCHED='!`plannotator annotate $ARGUMENTS`'
25 + PATCHED='!`plannotator annotate --gate --json $ARGUMENTS`'
26 +
27 + MODE=install
28 + case "${1-}" in
29 + --patch-only) MODE=patch ;;
30 + --check) MODE=check ;;
31 + -h|--help) awk 'NR==1{next} /^#/{sub(/^# ?/,""); print; next} {exit}' "$0" ; exit 0 ;;
32 + "") ;;
33 + *) echo "plannotator-update: unknown option '$1'" >&2 ; exit 2 ;;
34 + esac
35 +
36 + version() { command -v plannotator >/dev/null 2>&1 && plannotator --version 2>/dev/null || echo "(not installed)"; }
37 +
38 + # --- update ---------------------------------------------------------------
39 + if [ "$MODE" = install ]; then
40 + before=$(version)
41 + echo "==> Updating Plannotator (currently: $before)"
42 + # --yes keeps it unattended; the installer still honours the saved answers
43 + # in ~/.plannotator/install-prefs (extras=no, model_invocable=none).
44 + curl -fsSL "$INSTALL_URL" | bash -s -- --yes
45 + after=$(version)
46 + if [ "$before" = "$after" ]; then
47 + echo "==> Version unchanged: $after"
48 + else
49 + echo "==> Updated: $before -> $after"
50 + fi
51 + fi
52 +
53 + # --- patch ----------------------------------------------------------------
54 + if [ ! -f "$SKILL" ]; then
55 + echo "plannotator-update: skill not found at $SKILL" >&2
56 + echo " The installer should have written it. Nothing patched." >&2
57 + exit 1
58 + fi
59 +
60 + if grep -qxF "$PATCHED" "$SKILL"; then
61 + echo "==> Skill already patched (--gate --json present)"
62 + exit 0
63 + fi
64 +
65 + if [ "$MODE" = check ]; then
66 + echo "==> Skill is NOT patched. Invocation line(s) found:"
67 + grep -nF 'plannotator annotate' "$SKILL" >&2 || echo " (none)" >&2
68 + exit 1
69 + fi
70 +
71 + if ! grep -qxF "$UNPATCHED" "$SKILL"; then
72 + # Upstream changed the invocation line. Refuse to guess — a wrong patch here
73 + # fails silently as a missing Approve button, which is exactly the bug this
74 + # script exists to prevent.
75 + echo "plannotator-update: cannot patch — expected invocation line not found." >&2
76 + echo " expected: $UNPATCHED" >&2
77 + echo " found in $SKILL:" >&2
78 + grep -nF 'plannotator annotate' "$SKILL" >&2 || echo " (no 'plannotator annotate' line at all)" >&2
79 + echo " Upstream likely reshaped the skill. Re-apply --gate --json by hand" >&2
80 + echo " and update the OLD/NEW strings in $0." >&2
81 + exit 1
82 + fi
83 +
84 + tmp=$(mktemp)
85 + trap 'rm -f "$tmp"' EXIT
86 + # Exact whole-line match, so no regex metacharacter can misfire on $ARGUMENTS.
87 + awk -v old="$UNPATCHED" -v new="$PATCHED" '
88 + $0 == old { $0 = new; n++ }
89 + { print }
90 + END { exit(n ? 0 : 1) }
91 + ' "$SKILL" > "$tmp"
92 + cat "$tmp" > "$SKILL"
93 +
94 + grep -qxF "$PATCHED" "$SKILL" || { echo "plannotator-update: patch verification failed" >&2; exit 1; }
95 + echo "==> Patched $SKILL"
96 + echo " $PATCHED"
97 +
98 + # Note: ~/.agents/skills/plannotator-annotate is the "core" skill flavour — it has
99 + # no inline-bash $ARGUMENTS line and is deliberately left alone.