diff --git a/plugin/skills/ase-code-analyze/SKILL.md b/plugin/skills/ase-code-analyze/SKILL.md index 32d49270..745e600d 100644 --- a/plugin/skills/ase-code-analyze/SKILL.md +++ b/plugin/skills/ase-code-analyze/SKILL.md @@ -1,6 +1,6 @@ --- name: ase-code-analyze -argument-hint: "[--help|-h] [--performance|-p] [--security|-s] [--severity|-S=(LOW|MEDIUM|HIGH)] " +argument-hint: "[--help|-h] [--performance|-p] [--security|-s] [--severity|-S=(LOW|MEDIUM|HIGH)] [--quick|-Q] " description: > Analyze the source code for problems in either the logic and semantics and its related control flow, performance and efficiency, @@ -10,6 +10,7 @@ disable-model-invocation: false effort: high allowed-tools: - "Agent" + - "Bash" - "Glob" --- @@ -23,7 +24,7 @@ Analyze Source Code + arg2="--performance|-p --security|-s --severity|-S=(LOW|MEDIUM|HIGH) --quick|-Q"> $ARGUMENTS @@ -204,6 +205,164 @@ problems in *performance* and *efficiency*, or problems in *security*. followed by one `{ command: "set", key: "ase-issue-P", val: ": <description/>" }` entry per reported problem. + <if condition="<getopt-option-quick/> is equal `true` and at least one problem survived the severity floor"> + + The `--quick`/`-Q` flag turns this analysis into a *one-shot* + `analyze → resolve → implement → verify` pipeline that resolves + the surviving problems fully autonomously, *without any user + interaction*. Problems whose `severity` is `ACCEPTED` are + *excluded* from auto-resolution: they document deliberately + accepted trade-offs, so "fixing" them would undo reviewed + decisions -- they stay reported and persisted only. Let <count/> + be the number of surviving *non-ACCEPTED* problems and + <accepted-count/> the number of surviving `ACCEPTED` problems, + and keep the surviving <problems/> entries (each with its `file`, + `title`, and `description` field) available for the sub-steps + below. If <count/> is `0`, *skip* this entire one-shot block and + continue with the final hint <template/> below. + + First, announce the one-shot phase with the following <template/>: + + <template> + <ase-tpl-bullet-secondary/> **ONE-SHOT RESOLUTION** (<count/> problem(s), <accepted-count/> ACCEPTED skipped) + </template> + + Then perform the following sub-steps and finally *STOP* the entire + flow (do *not* emit the final hint <template/> below): + + 1. *Guard and snapshot*: with the `Bash` tool, run + `git rev-parse --is-inside-work-tree` to check whether the + target is a Git working tree. If it fails (no Git repository), + worktree isolation is impossible, so *skip* sub-steps 3-6 and + instead resolve each cluster of sub-step 2 *sequentially* -- + one non-isolated `Agent` invocation at a time, in ascending + order, each with the sub-step 3 prompt but *without* the + `isolation` parameter, the seeding instruction, and the diff + return (the fixes land in the live tree directly); for each + problem, record its <outcome/> as `resolved` and its changed + files <files/> (from `git diff --name-only` taken immediately + before and after its cluster's `Agent`) -- then continue with + sub-step 7. Otherwise, capture the repository root + `git rev-parse --show-toplevel` as <live-root/> and + `git worktree list --porcelain` as <worktrees-before/> for the + cleanup in sub-step 6. + + 2. *Cluster by file*: group the <count/> problems by their `file` + field -- problems sharing the same file form *one* cluster + (resolving same-file problems in separate parallel worktrees + would guarantee merge conflicts). Order the clusters by their + lowest contained `P<n/>` and let <cluster-count/> be the number + of clusters, <cluster-index/> the 1-based cluster number, and + <cluster-problems/> the ascending, comma-separated `P<n/>` list + of a cluster. + + 3. *Resolve in parallel (background)*: for *every* cluster, invoke + the following tool once, emitting *all* invocations *in one + single message* so they run in *parallel*, each in its *own* + isolated Git worktree: + + ```text + Agent( + description: "Resolve <cluster-problems/> (<cluster-index/>/<cluster-count/>)", + subagent_type: "general-purpose", + isolation: "worktree", + run_in_background: true, + prompt: "First seed this worktree with the live working tree's uncommitted state: run `git -C \"<live-root/>\" diff HEAD | git apply --whitespace=nowarn` (skip when that diff is empty), then `git add -A && git commit -m seed` (skip the commit when nothing is staged). Then, for each of <cluster-problems/> in ascending order, call the tool Skill(skill: \"ase:ase-code-resolve\", args: \"-Q P<n/>\") to fully resolve AND implement that issue in this worktree. When finished, run `git add -A` followed by `git diff --cached`, and return ONLY that complete unified diff as your final message (an empty string if nothing changed)." + ) + ``` + + The background execution keeps the long fan-out interruptible + and observable: *each time* one of these `Agent` invocations + completes, immediately output one progress line with the + following <template/>, then keep waiting until *all* clusters + have returned. Collect each returned unified diff, keyed by its + cluster. + + <template> + <ase-tpl-bullet-secondary/> **RESOLVED** (<cluster-index/>/<cluster-count/>): <cluster-problems/> + </template> + + 4. *Reconcile sequentially -- always merge, never prompt*: with the + `Bash` tool, process the collected cluster diffs in ascending + cluster order. For each *non-empty* diff, write it to a + temporary file and apply it with `git apply --whitespace=nowarn + <patch-file/>` -- deliberately *without* `--index`: staging + remains with the user. On success, record each contained + problem's <outcome/> as `merged` and its changed files <files/> + (the `+++ b/<path>` headers of its diff). On failure, retry + with `git apply --3way --whitespace=nowarn <patch-file/>`. If + the three-way attempt also fails or leaves Git conflict markers + in any touched file, or the diff is empty, or its `Agent` + returned nothing, do *not* stop -- instead add the cluster's + problems to a *retry set* (a possibly marker-littered file is + repaired there). + + 5. *Retry conflicts sequentially*: for each `P<n/>` in the retry + set, in ascending order and strictly *one at a time*, set + <title/> and <description/> to that problem's `title` and + `description` fields (from <problems/>) and invoke a + *non-isolated* `Agent` against the now-updated live working + tree: + + ```text + Agent( + description: "Re-resolve P<n/> (sequential)", + subagent_type: "general-purpose", + run_in_background: false, + prompt: "Call the tool Skill(skill: \"ase:ase-code-resolve\", args: \"-Q <title/> — <description/>\") to fully resolve AND implement that problem directly in the current working tree. The affected files may still contain Git conflict markers from a failed three-way merge -- remove any such markers as part of the resolution." + ) + ``` + + Because each such `Agent` edits the live tree directly and + sequentially, its change always integrates cleanly, so *all* + <count/> problems end up merged. Record that problem's + <outcome/> as `re-resolved` and its changed files <files/> + (from `git diff --name-only` taken immediately before and after + that single `Agent`). + + 6. *Remove the worktrees*: with the `Bash` tool, compare the current + `git worktree list --porcelain` against <worktrees-before/>; for + *each* newly added worktree, run `git worktree remove --force + <path/>`, then run `git worktree prune` to drop any remaining + administrative references. + + 7. *Verify and repair*: the per-worktree resolutions ran in `dry` + mode (no verification), so the *merged result* MUST now be + verified centrally. Determine the project's canonical + *formatter*, *build*, and *test* commands from its build + configuration (e.g. npm `package.json` scripts, `Makefile`, + Gradle `spotlessApply`/`build`/`test`, Cargo, etc). With the + `Bash` tool run, in this order: the formatter (if any), the + build, and the test suite. If any of them fails, hand the + *complete* failure output to one *non-isolated* + `Agent(subagent_type: "general-purpose", run_in_background: + false)` with the prompt to repair exactly those failures in the + current working tree without touching unrelated user changes, + then re-run the failed commands. Perform at most *two* such + repair rounds. Set <verify/> to `green` when everything passes, + or to a short failure summary when failures remain. Do *not* + stage or commit anything -- staging remains with the user. + + 8. *Report the per-problem results*: for *every* auto-resolved + problem `P<n/>`, in ascending order, output the following + <template/>, where <marker/> is `✓` when its <outcome/> is + `merged` or `resolved` and `↻` when its <outcome/> is + `re-resolved`, and <files/> is the comma-separated list of its + changed files (or `no changes` when empty): + + <template> + <ase-tpl-bullet-signal/> **P<n/>** <marker/> *<outcome/>*: <files/> + </template> + + 9. Finally, output the following summary <template/> and then *STOP* + the entire flow (do *not* emit the final hint <template/> below): + + <template> + ⧉ **ASE**: ↪ hint: **one-shot `-Q`: auto-resolved <count/> problem(s) (<accepted-count/> ACCEPTED skipped), verification: <verify/> -- staging remains with you.** + </template> + + </if> + Finally, give a final hint by expanding the following (which, depending on the configured <ase-guidance-level/>, may expand into nothing and hence emit no output at all): diff --git a/plugin/skills/ase-code-analyze/help.md b/plugin/skills/ase-code-analyze/help.md index 9789317f..6fe1545a 100644 --- a/plugin/skills/ase-code-analyze/help.md +++ b/plugin/skills/ase-code-analyze/help.md @@ -10,6 +10,7 @@ [`--performance`|`-p`] [`--security`|`-s`] [`--severity`|`-S`=(`LOW`|`MEDIUM`|`HIGH`)] + [`--quick`|`-Q`] *source-reference* ## DESCRIPTION @@ -38,6 +39,26 @@ severity* order `HIGH`, `MEDIUM`, `LOW`, `ACCEPTED` - keeping the `file`/`line` order within the same severity - and are renumbered contiguously as `P<n>`, so `P1` is the most severe problem. +The `--quick`|`-Q` option turns the analysis into a fully autonomous +one-shot `analyze → resolve → implement → verify` pipeline: after +reporting, it groups the surviving problems into *per-file clusters* +(same-file problems are never resolved in parallel), dispatches one +worktree-isolated `ase-code-resolve -Q` sub-agent per cluster in +parallel (in the background, with a progress line per returning +cluster; each worktree is first *seeded* with the live tree's +uncommitted state so its diff applies cleanly), then reconciles all +resulting diffs into the working tree (plain `git apply`, `--3way` as +fallback, and a conflicting cluster is re-resolved sequentially so that +*all* problems are merged), removes the temporary worktrees again, and +finally runs the project's formatter, build, and test suite centrally +on the merged result, with up to two autonomous repair rounds for any +failures. `ACCEPTED` problems document deliberately accepted trade-offs +and are *excluded* from auto-resolution. Nothing is staged or +committed -- staging remains with the user. It composes with +`--severity` (only surviving findings are resolved) and requires a Git +repository (otherwise the clusters are resolved sequentially without +worktree isolation). + The skill investigates the code base silently, reports each detected problem as a `PROBLEM` entry with severity (`LOW`, `MEDIUM`, `HIGH`) and inline file/line references (in the performance lens, each entry @@ -83,6 +104,13 @@ Analyze a directory, reporting only `MEDIUM` and `HIGH` problems: ❯ /ase-code-analyze -S MEDIUM src/handlers/ ``` +Analyze a directory and, in one non-interactive shot, auto-resolve and +implement every `HIGH` finding: + +```text +❯ /ase-code-analyze -Q -S HIGH src/handlers/ +``` + ## SEE ALSO [`ase-code-resolve`](../ase-code-resolve/help.md), [`ase-code-refactor`](../ase-code-refactor/help.md), [`ase-code-lint`](../ase-code-lint/help.md),