@muggleai/works 5.9.0 → 5.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/{chunk-LVUJ4E62.js → chunk-MSPMXBO5.js} +638 -468
- package/dist/{chunk-5PYK7DWB.js → chunk-WUMAJOBT.js} +17 -6
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/README.md +19 -13
- package/dist/plugin/agents/test-prepare-runner.md +4 -1
- package/dist/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/dist/plugin/commands/mtest.md +1 -1
- package/dist/plugin/hooks/README.md +15 -3
- package/dist/plugin/hooks/hooks.json +79 -0
- package/dist/plugin/scripts/ensure-electron-app.sh +62 -47
- package/dist/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/dist/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/dist/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/dist/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/dist/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/dist/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/dist/plugin/scripts/guardrail-report-format.sh +9 -5
- package/dist/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/dist/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/dist/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/dist/plugin/scripts/guardrails.mjs +474 -80
- package/dist/plugin/scripts/pr-watch-events.sh +116 -0
- package/dist/plugin/scripts/pr-watch-guards.sh +8 -2
- package/dist/plugin/scripts/pr-watch-loop.sh +254 -0
- package/dist/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/dist/plugin/scripts/sign-body.sh +88 -0
- package/dist/plugin/skills/CLAUDE.md +16 -0
- package/dist/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/dist/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/dist/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/dist/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/dist/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/dist/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/dist/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/dist/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/dist/plugin/skills/do/open-prs/forward.md +2 -2
- package/dist/plugin/skills/do/per-comment-replies.md +2 -15
- package/dist/plugin/skills/muggle/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/dist/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/dist/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/dist/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/dist/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/dist/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/dist/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/dist/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/dist/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/dist/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/dist/plugin/skills/muggle-test/SKILL.md +23 -3
- package/dist/plugin/skills/muggle-test/execute-local.md +2 -0
- package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/dist/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/dist/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/dist/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/dist/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/dist/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/dist/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/dist/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/release-manifest.json +4 -4
- package/dist/src-B5OTAZKM.js +1 -0
- package/package.json +7 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/README.md +19 -13
- package/plugin/agents/test-prepare-runner.md +4 -1
- package/plugin/agents/visual-walkthrough-builder.md +12 -5
- package/plugin/commands/mtest.md +1 -1
- package/plugin/hooks/README.md +15 -3
- package/plugin/hooks/hooks.json +79 -0
- package/plugin/scripts/ensure-electron-app.sh +62 -47
- package/plugin/scripts/guardrail-classify-gate.sh +23 -0
- package/plugin/scripts/guardrail-debug-path-gate.sh +41 -0
- package/plugin/scripts/guardrail-pr-terminal.sh +6 -2
- package/plugin/scripts/guardrail-record-stage-read.sh +21 -0
- package/plugin/scripts/guardrail-record-stage-signals.sh +23 -0
- package/plugin/scripts/guardrail-record-tests.sh +11 -4
- package/plugin/scripts/guardrail-report-format.sh +9 -5
- package/plugin/scripts/guardrail-skill-stages.sh +35 -0
- package/plugin/scripts/guardrail-stage-gate.sh +43 -0
- package/plugin/scripts/guardrail-walkthrough-gate.sh +41 -0
- package/plugin/scripts/guardrails.mjs +474 -80
- package/plugin/scripts/pr-watch-events.sh +116 -0
- package/plugin/scripts/pr-watch-guards.sh +8 -2
- package/plugin/scripts/pr-watch-loop.sh +254 -0
- package/plugin/scripts/reconcile-stale-watchers.sh +66 -18
- package/plugin/scripts/sign-body.sh +88 -0
- package/plugin/skills/CLAUDE.md +16 -0
- package/plugin/skills/_shared/post-merge-cleanup.md +83 -3
- package/plugin/skills/_shared/pr-followup-helpers/loop-signature.md +6 -8
- package/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +10 -18
- package/plugin/skills/_shared/resolve-e2e-validation-context.md +1 -0
- package/plugin/skills/_shared/vcs/CLAUDE.md +1 -0
- package/plugin/skills/_shared/vcs/github/pr-edit.md +3 -2
- package/plugin/skills/_shared/vcs/github/reply-line-comment.md +3 -2
- package/plugin/skills/_shared/vcs/github/top-level-comment.md +3 -2
- package/plugin/skills/_shared/vcs/gitlab/mr-create.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-edit.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/mr-note.md +4 -1
- package/plugin/skills/_shared/vcs/gitlab/reply-discussion.md +4 -1
- package/plugin/skills/_shared/vcs/post-signature.md +23 -12
- package/plugin/skills/do/open-prs/forward.md +2 -2
- package/plugin/skills/do/per-comment-replies.md +2 -15
- package/plugin/skills/muggle/SKILL.md +1 -1
- package/plugin/skills/muggle-browser-task/SKILL.md +1 -1
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +2 -1
- package/plugin/skills/muggle-pr-followup/SKILL.md +6 -3
- package/plugin/skills/muggle-pr-followup/adopt.md +60 -0
- package/plugin/skills/muggle-pr-followup/arm-watcher.md +10 -14
- package/plugin/skills/muggle-pr-followup/auto-track.md +2 -0
- package/plugin/skills/muggle-pr-followup/evals/evals.json +63 -1
- package/plugin/skills/muggle-pr-followup/output-templates/help.md +11 -1
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +1 -7
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +1 -4
- package/plugin/skills/muggle-pr-followup/reconcile.md +32 -6
- package/plugin/skills/muggle-pr-followup/state-schemas.md +18 -0
- package/plugin/skills/muggle-preferences/SKILL.md +1 -1
- package/plugin/skills/muggle-preferences/evals/evals.json +45 -0
- package/plugin/skills/muggle-preferences/ops/change-one.md +1 -1
- package/plugin/skills/muggle-preferences/ops/configure.md +4 -5
- package/plugin/skills/muggle-preferences/ops/list.md +1 -1
- package/plugin/skills/muggle-preferences/ops/set.md +3 -4
- package/plugin/skills/muggle-preferences/preference-gates/README.md +3 -3
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +2 -2
- package/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/watcherLifetime.md +23 -0
- package/plugin/skills/muggle-test/SKILL.md +23 -3
- package/plugin/skills/muggle-test/execute-local.md +2 -0
- package/plugin/skills/muggle-test-feature-local/SKILL.md +6 -1
- package/plugin/skills/muggle-test-import/SKILL.md +1 -1
- package/plugin/skills/muggle-test-prepare/SKILL.md +28 -15
- package/plugin/skills/muggle-test-prepare/steps/check-running.md +1 -1
- package/plugin/skills/muggle-test-prepare/steps/confirm-recipe.md +56 -0
- package/plugin/skills/muggle-test-prepare/steps/derive-service-graph.md +51 -0
- package/plugin/skills/muggle-test-prepare/steps/e2e-instructions.md +111 -0
- package/plugin/skills/muggle-test-prepare/steps/identify-services.md +4 -2
- package/plugin/skills/muggle-test-prepare/steps/readiness-report.md +12 -5
- package/plugin/skills/muggle-test-prepare/steps/record-resolution.md +32 -0
- package/plugin/skills/muggle-test-prepare/steps/replay-or-learn.md +20 -0
- package/plugin/skills/muggle-test-prepare/steps/reuse-plan.md +9 -6
- package/plugin/skills/muggle-test-prepare/steps/smoke-test.md +5 -1
- package/plugin/skills/muggle-test-prepare/steps/start-services.md +3 -1
- package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +1 -1
- package/dist/src-FDK2KQSZ.js +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# stage-read observer (PostToolUse/Read). Records that a file in the skills tree
|
|
5
|
+
# was opened, which is how the Stop gate tells a mandatory stage that was read
|
|
6
|
+
# from one that was skipped. Emits no directive.
|
|
7
|
+
#
|
|
8
|
+
# Read fires constantly, so only a markdown file living under a `skills/`
|
|
9
|
+
# directory reaches Node — a mandatory stage can be any file in that tree, but
|
|
10
|
+
# never one outside it, so source reads and repo docs return {} in-shell. Both
|
|
11
|
+
# path separators are accepted: a Windows payload carries escaped backslashes.
|
|
12
|
+
# Degrades to {}.
|
|
13
|
+
payload="$(cat)"
|
|
14
|
+
|
|
15
|
+
if ! grep -Eiq '"file_path"[[:space:]]*:[[:space:]]*"[^"]*[/\\]+skills[/\\]+[^"]*\.md"' <<<"$payload"; then
|
|
16
|
+
printf '{}'
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
|
|
21
|
+
printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" record-stage-read 2>/dev/null || printf '{}'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# stage-signal observer (PostToolUse/Bash + muggle telemetry and feedback tools).
|
|
5
|
+
# Records the three things the stage gates settle from: a Step 6f
|
|
6
|
+
# pre-execution-classification emit, debug-path evidence for a failed run (a
|
|
7
|
+
# failure-classified emit or feedback naming it), and the skip markers each gate
|
|
8
|
+
# documents as its way out. Emits no directive — the gates read the state.
|
|
9
|
+
#
|
|
10
|
+
# The marker arm matches the MUGGLE_<GATE>_SKIP shape, never one token: a gate
|
|
11
|
+
# whose marker is missing from a hand-listed set instructs the user to run an
|
|
12
|
+
# echo that can never register, then blocks the turn anyway. Anchoring the
|
|
13
|
+
# marker to a leading `echo` stays in guardrails.mjs; over-matching here only
|
|
14
|
+
# costs a needless spawn. Degrades to {}.
|
|
15
|
+
payload="$(cat)"
|
|
16
|
+
|
|
17
|
+
if ! grep -Eiq 'MUGGLE_[A-Z0-9_]+_SKIP|muggle.*(telemetry-event-emit|user-feedback-create)' <<<"$payload"; then
|
|
18
|
+
printf '{}'
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
|
|
23
|
+
printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" record-stage-signals 2>/dev/null || printf '{}'
|
|
@@ -10,12 +10,19 @@ set -uo pipefail
|
|
|
10
10
|
# pre-filter for test runners and the muggle E2E tool names keeps Node off the
|
|
11
11
|
# hot path. Only a `test` command (npm/pnpm/yarn/jest/vitest/pytest/go/cargo),
|
|
12
12
|
# a muggle execute/replay/test-generation event, a muggle-test skill telemetry
|
|
13
|
-
# emit (registers a clean-SKIP verdict as an E2E run),
|
|
14
|
-
# reaches guardrails.mjs, which then
|
|
15
|
-
# updates state. Degrades to {}.
|
|
13
|
+
# emit (registers a clean-SKIP verdict as an E2E run), a skip marker, or a PR
|
|
14
|
+
# publish carrying a rendered walkthrough reaches guardrails.mjs, which then
|
|
15
|
+
# inspects the output for pass/fail and updates state. Degrades to {}.
|
|
16
|
+
#
|
|
17
|
+
# The marker arm matches the MUGGLE_<GATE>_SKIP shape, never one token: every
|
|
18
|
+
# Stop gate documents its own marker as the escape hatch, and a per-token list
|
|
19
|
+
# left the watcher and walkthrough markers unreachable — the gates instructed
|
|
20
|
+
# the user to run an echo that could never reach the recorder, then blocked the
|
|
21
|
+
# turn anyway. Anchoring the marker to a leading `echo` stays in guardrails.mjs;
|
|
22
|
+
# over-matching here only costs a needless spawn.
|
|
16
23
|
payload="$(cat)"
|
|
17
24
|
|
|
18
|
-
if ! grep -Eiq '(pnpm|npm|yarn)[[:space:]]+(run[[:space:]]+)?test|jest|vitest|pytest|go[[:space:]]+test|cargo[[:space:]]+test|muggle.*(execute|test-generation|replay)|muggle-local-telemetry-skill-emit|
|
|
25
|
+
if ! grep -Eiq '(pnpm|npm|yarn)[[:space:]]+(run[[:space:]]+)?test|jest|vitest|pytest|go[[:space:]]+test|cargo[[:space:]]+test|muggle.*(execute|test-generation|replay)|muggle-local-telemetry-skill-emit|MUGGLE_[A-Z0-9_]+_SKIP|gh[[:space:]]+pr[[:space:]]+(comment|create|edit)|issues/comments/[0-9]' <<<"$payload"; then
|
|
19
26
|
printf '{}'
|
|
20
27
|
exit 0
|
|
21
28
|
fi
|
|
@@ -7,14 +7,18 @@ set -uo pipefail
|
|
|
7
7
|
# deterministic renderer.
|
|
8
8
|
#
|
|
9
9
|
# This must stay synchronous (only a sync PreToolUse hook can deny), and it fires
|
|
10
|
-
# before every Bash call. A keyword pre-filter for the
|
|
10
|
+
# before every Bash call. A keyword pre-filter for the PR-publishing commands
|
|
11
11
|
# keeps Node off the hot path: a plain `ls`/`git status`/build command returns {}
|
|
12
|
-
# in-shell and never pays cold-start. Only a `gh pr comment|create|edit`
|
|
13
|
-
# guardrails.mjs, which reads the body (incl.
|
|
14
|
-
#
|
|
12
|
+
# in-shell and never pays cold-start. Only a `gh pr comment|create|edit` or a
|
|
13
|
+
# `gh api` comment edit reaches guardrails.mjs, which reads the body (incl.
|
|
14
|
+
# --body-file) and decides. The comment-edit arm matters as much as the post
|
|
15
|
+
# arm: guardrails.mjs gates that path precisely so a sanctioned walkthrough
|
|
16
|
+
# can't be overwritten with hand-written markdown afterwards, and a pre-filter
|
|
17
|
+
# on `gh pr` alone left that bypass wide open. Degrades to {} so it never blocks
|
|
18
|
+
# an unrelated command.
|
|
15
19
|
payload="$(cat)"
|
|
16
20
|
|
|
17
|
-
if ! grep -Eiq 'gh[[:space:]]+pr[[:space:]]+(comment|create|edit)' <<<"$payload"; then
|
|
21
|
+
if ! grep -Eiq 'gh[[:space:]]+pr[[:space:]]+(comment|create|edit)|issues/comments/[0-9]' <<<"$payload"; then
|
|
18
22
|
printf '{}'
|
|
19
23
|
exit 0
|
|
20
24
|
fi
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# mandatory-stage recorder (PostToolUse/Skill). Records which skill is running
|
|
5
|
+
# and, when its SKILL.md declares `mandatoryStages`, returns those files as
|
|
6
|
+
# required reading at the moment of use. The Stop gate
|
|
7
|
+
# (guardrail-stage-gate.sh) blocks the turn end while any of them is unread.
|
|
8
|
+
#
|
|
9
|
+
# Skill calls are rare, so the pre-filter is a file test rather than a keyword
|
|
10
|
+
# scan: the invoked name is pulled out of the payload and Node runs only when it
|
|
11
|
+
# resolves to a skill this plugin actually ships. Another plugin's skill, or an
|
|
12
|
+
# input with no skill name, returns {} in-shell. Every key the resolver reads is
|
|
13
|
+
# accepted here — a key matched in one and missed in the other makes the gate
|
|
14
|
+
# dead code on exactly the harness that names it that way. Degrades to {}.
|
|
15
|
+
payload="$(cat)"
|
|
16
|
+
|
|
17
|
+
root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
|
|
18
|
+
|
|
19
|
+
for candidate in $(printf '%s' "$payload" \
|
|
20
|
+
| grep -oE '"(skill|skillName|name|command)"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
21
|
+
| sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/'); do
|
|
22
|
+
# A namespaced invocation (`muggle:muggle-test`) and a slash command
|
|
23
|
+
# (`/muggle-test`) both name the same skill directory.
|
|
24
|
+
skill="${candidate##*:}"
|
|
25
|
+
skill="${skill#/}"
|
|
26
|
+
case "$skill" in
|
|
27
|
+
"" | *[!A-Za-z0-9._-]*) continue ;;
|
|
28
|
+
esac
|
|
29
|
+
if [ -f "$root/skills/$skill/SKILL.md" ]; then
|
|
30
|
+
printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" skill-stages 2>/dev/null || printf '{}'
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
printf '{}'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# mandatory-stage gate (Stop). When a skill invoked this session declared
|
|
5
|
+
# `mandatoryStages` in its SKILL.md and any of those files was never opened,
|
|
6
|
+
# block the turn end naming them (or the MUGGLE_STAGE_SKIP escape hatch). This
|
|
7
|
+
# is the root fix for a skill read as a single page: the SKILL.md links out to
|
|
8
|
+
# steps that are mandatory, nothing forced them open, and the steps were
|
|
9
|
+
# silently dropped.
|
|
10
|
+
#
|
|
11
|
+
# Mirrors guardrail-watch-gate.sh: synchronous (only a sync Stop hook can block
|
|
12
|
+
# the turn end), fires on EVERY turn end, and pre-filters in shell so Node spawns
|
|
13
|
+
# only when a stage is actually owed. On the overwhelming majority of turns no
|
|
14
|
+
# skill declared stages, so the state file is absent or mandatoryStages is empty
|
|
15
|
+
# and we return {} in-shell. The read-vs-declared comparison runs in
|
|
16
|
+
# guardrails.mjs. Degrades to {}.
|
|
17
|
+
payload="$(cat)"
|
|
18
|
+
|
|
19
|
+
raw_sid="$(printf '%s' "$payload" | grep -oE '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/')"
|
|
20
|
+
[ -n "$raw_sid" ] || raw_sid="unknown"
|
|
21
|
+
sid="$(printf '%s' "$raw_sid" | sed 's/[^A-Za-z0-9_-]/_/g')"
|
|
22
|
+
|
|
23
|
+
# Resolve the same home dir Node's os.homedir() uses. HOME is correct on
|
|
24
|
+
# macOS/Linux and on most Git Bash setups; fall back to converting USERPROFILE
|
|
25
|
+
# when HOME doesn't hold the state dir (some Windows shells point HOME elsewhere).
|
|
26
|
+
home="${HOME:-}"
|
|
27
|
+
if [ ! -d "$home/.muggle-ai" ] && command -v cygpath >/dev/null 2>&1 && [ -n "${USERPROFILE:-}" ]; then
|
|
28
|
+
home="$(cygpath -u "$USERPROFILE" 2>/dev/null || printf '%s' "$home")"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Empty array serializes as `"mandatoryStages": []` (one line); a non-empty array
|
|
32
|
+
# spans lines, so the empty match reliably tells them apart.
|
|
33
|
+
state_file="$home/.muggle-ai/guardrails/$sid.json"
|
|
34
|
+
if [ ! -f "$state_file" ] \
|
|
35
|
+
|| ! grep -q '"mandatoryStages"' "$state_file" \
|
|
36
|
+
|| grep -q '"mandatoryStages": \[\]' "$state_file" \
|
|
37
|
+
|| grep -q '"stageSkipped": true' "$state_file"; then
|
|
38
|
+
printf '{}'
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
|
|
43
|
+
printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" stage-gate 2>/dev/null || printf '{}'
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
# acceptance-run → walkthrough gate (Stop). When an E2E acceptance run happened
|
|
5
|
+
# this session and no visual walkthrough has reached the PR, block the turn end
|
|
6
|
+
# until it does or a skip is declared. Fires once per session per PR.
|
|
7
|
+
#
|
|
8
|
+
# This must stay synchronous (only a sync Stop hook can block the turn end), and
|
|
9
|
+
# it fires on EVERY turn end. There is no command payload to key off, so the
|
|
10
|
+
# pre-filter reads the same per-session state file guardrails.mjs uses and only
|
|
11
|
+
# spawns Node when the gate could actually fire — i.e. an acceptance run is
|
|
12
|
+
# recorded and the walkthrough is neither posted nor skipped. On the
|
|
13
|
+
# overwhelming majority of turns (no E2E this session) the state file is absent
|
|
14
|
+
# or e2eRun is unset, so we return {} in-shell and never pay Node cold-start —
|
|
15
|
+
# which also means the gate's `gh` lookups only ever run on turns that could
|
|
16
|
+
# genuinely owe a walkthrough. Degrades to {}.
|
|
17
|
+
payload="$(cat)"
|
|
18
|
+
|
|
19
|
+
raw_sid="$(printf '%s' "$payload" | grep -oE '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*:[[:space:]]*"([^"]*)".*/\1/')"
|
|
20
|
+
[ -n "$raw_sid" ] || raw_sid="unknown"
|
|
21
|
+
sid="$(printf '%s' "$raw_sid" | sed 's/[^A-Za-z0-9_-]/_/g')"
|
|
22
|
+
|
|
23
|
+
# Resolve the same home dir Node's os.homedir() uses. HOME is correct on
|
|
24
|
+
# macOS/Linux and on most Git Bash setups; fall back to converting USERPROFILE
|
|
25
|
+
# when HOME doesn't hold the state dir (some Windows shells point HOME elsewhere).
|
|
26
|
+
home="${HOME:-}"
|
|
27
|
+
if [ ! -d "$home/.muggle-ai" ] && command -v cygpath >/dev/null 2>&1 && [ -n "${USERPROFILE:-}" ]; then
|
|
28
|
+
home="$(cygpath -u "$USERPROFILE" 2>/dev/null || printf '%s' "$home")"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
state_file="$home/.muggle-ai/guardrails/$sid.json"
|
|
32
|
+
if [ ! -f "$state_file" ] \
|
|
33
|
+
|| ! grep -q '"e2eRun": true' "$state_file" \
|
|
34
|
+
|| grep -q '"walkthroughPosted": true' "$state_file" \
|
|
35
|
+
|| grep -q '"walkthroughSkipped": true' "$state_file"; then
|
|
36
|
+
printf '{}'
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
root="${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}"
|
|
41
|
+
printf '%s' "$payload" | node "${root}/scripts/guardrails.mjs" walkthrough-gate 2>/dev/null || printf '{}'
|