diff --git a/plugins/agentic-advisor/.claude-plugin/plugin.json b/plugins/agentic-advisor/.claude-plugin/plugin.json index 9628e90..6825b01 100644 --- a/plugins/agentic-advisor/.claude-plugin/plugin.json +++ b/plugins/agentic-advisor/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "agentic-advisor", - "version": "1.4.2", + "version": "1.4.3", "description": "Before writing code, grades how fragile the target is from LinearB health signals + local git history (rework, incidents, fix/revert density, code ownership) and holds the agent to a matching effort level (LOW/MEDIUM/HIGH) — lean on calm repos, defensive on fragile ones. Auto-triggers via a bundled hook and can report each effort decision to your LinearB org as usage telemetry.", "author": { "name": "LinearB", diff --git a/plugins/agentic-advisor/CHANGELOG.md b/plugins/agentic-advisor/CHANGELOG.md index afed5d9..34bfe8c 100644 --- a/plugins/agentic-advisor/CHANGELOG.md +++ b/plugins/agentic-advisor/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.4.3] - 2026-10-15 + +### Fixed + +- No more false prompt nudges: "auto-fix" / "auto fix" / "autofix" no longer counts as a code task, and a repo that was already graded and worked on isn't nudged again (another repo in the same session still is). + ## [1.4.2] - 2026-10-15 ### Fixed diff --git a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh index c424221..2b2197a 100755 --- a/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh +++ b/plugins/agentic-advisor/hooks/agentic-advisor-trigger.sh @@ -133,7 +133,7 @@ case "$event" in if [ -n "$ticket" ]; then # Tier 1: Jira ticket (primary). msg="This looks like the start of a repo-scoped code task (Jira ticket ${ticket} referenced). ${guidance}" - elif printf '%s' "$prompt" | grep -qiE '\b(fix|fixes|fixing|fixed|implement|implementing|refactor|refactoring|hotfix|bug ?fix|debug|patch|endpoint|migration)\b'; then + elif printf '%s' "$prompt" | sed -E 's/[Aa][Uu][Tt][Oo][- ]?[Ff][Ii][Xx]//g' | grep -qiE '\b(fix|fixes|fixing|fixed|implement|implementing|refactor|refactoring|hotfix|bug ?fix|debug|patch|endpoint|migration)\b'; then # Tier 2: code-task keywords (fallback for ad-hoc work). msg="This looks like a code-writing task. ${guidance}" fi @@ -196,8 +196,16 @@ case "$event" in # (missing file path, non-git, missing transcript, or marker write failure). git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0 - # Skill already ran this session -> allow the edit. - skill_ran && exit 0 + # Skill already ran this session -> allow the edit. If a verdict names this repo, mark it handled so later prompts here aren't nudged. + if skill_ran; then + set_marker "$dir" + # The verdict uses the repo's name: check the remote's name and the folder's (clones and worktrees can differ). + url="$(git -C "$dir" config --get remote.origin.url 2>/dev/null)"; url="${url%.git}" + for name in "${url##*[/:]}" "$(basename "$(git -C "$dir" rev-parse --show-toplevel 2>/dev/null)")"; do + [ -n "$name" ] && grep -qF "LinearB: $name " "$transcript" 2>/dev/null && { : > "$marker" 2>/dev/null || true; break; } + done + exit 0 + fi # Can't read the transcript -> can't confirm skill status -> fail open (allow). [ -n "$transcript" ] && [ -f "$transcript" ] || exit 0 diff --git a/tests/agentic-advisor/hooks_test.sh b/tests/agentic-advisor/hooks_test.sh index 99f251c..ccf61de 100755 --- a/tests/agentic-advisor/hooks_test.sh +++ b/tests/agentic-advisor/hooks_test.sh @@ -53,6 +53,7 @@ reminded() { [ "$rc" -eq 0 ] && jq -e '(.hookSpecificOutput.permissionDecision = denied() { [ "$rc" -eq 0 ] && jq -e '.hookSpecificOutput.permissionDecision == "deny"' <<<"$out" >/dev/null; } add_skill() { printf '%s\n' '{"timestamp":"2026-01-01T00:00:00Z","message":{"role":"assistant","model":"m","usage":{"output_tokens":10},"content":[{"type":"tool_use","name":"Skill","input":{"skill":"agentic-advisor:agentic-advisor"}}]}}' >> "$TRANSCRIPT"; } add_verdict() { printf '%s\n' '{"timestamp":"2026-01-01T00:00:05Z","message":{"role":"assistant","model":"m","usage":{"output_tokens":20},"content":[{"type":"text","text":"> LinearB: widgets — MEDIUM effort (rework 6.5%) — focused diff."}]}}' >> "$TRANSCRIPT"; } +add_verdict_for() { printf '{"message":{"role":"assistant","content":[{"type":"text","text":"> LinearB: %s — MEDIUM effort (x) — y."}]}}\n' "$1" >> "$TRANSCRIPT"; } # Reporter posts from a detached subshell; wait briefly for the stub to record calls. ncalls() { find "$T/curl" -type f | wc -l | tr -d ' '; } await_calls() { local _; for _ in 1 2 3 4 5 6 7 8 9 10; do [ "$(ncalls)" -ge "$1" ] && return; sleep 0.2; done; } @@ -74,6 +75,36 @@ teardown setup run "$TRIGGER" UserPromptSubmit "$(prompt 'what time is it?')" check "trigger: non-code prompt is silent" silent +run "$TRIGGER" UserPromptSubmit "$(prompt 'turn on Auto-fix for the PR')" +check "trigger: 'auto-fix' is not a code task" silent +run "$TRIGGER" UserPromptSubmit "$(prompt 'turn on auto fix')" +check "trigger: 'auto fix' is not a code task" silent +run "$TRIGGER" UserPromptSubmit "$(prompt 'turn on autofix and fix the login bug')" +check "trigger: a real fix next to autofix still nudges" nudged +teardown + +setup +add_skill; add_verdict_for other-repo +run "$TRIGGER" PreToolUse "$(tool Edit app.js)" +run "$TRIGGER" UserPromptSubmit "$(prompt 'fix the login bug')" +check "trigger: an edit in a repo the verdict didn't name doesn't mark it handled" nudged +teardown + +setup +add_skill; add_verdict_for widgets +run "$TRIGGER" PreToolUse "$(tool Edit app.js)" +run "$TRIGGER" UserPromptSubmit "$(prompt 'fix the login bug')" +check "trigger: a verdict naming the remote repo (folder named differently) marks it handled" silent +teardown + +setup +add_skill; add_verdict_for repo +run "$TRIGGER" PreToolUse "$(tool Edit app.js)" +run "$TRIGGER" UserPromptSubmit "$(prompt 'fix the login bug')" +check "trigger: no nudge in a repo already graded and worked on" silent +REPO2="$T/repo2"; git init -q "$REPO2" +out="$(printf '{"hook_event_name":"UserPromptSubmit","session_id":"s1","cwd":"%s","transcript_path":"%s","prompt":"fix the login bug"}' "$REPO2" "$TRANSCRIPT" | "$TRIGGER")"; rc=$? +check "trigger: a second repo still nudges after the skill ran" nudged teardown for v in 0 false OFF no; do