mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
feat(skill): make bare /impeccable context-aware (re: #159)
Reshape of the "/impeccable suggest" proposal in #159. Instead of adding a 24th command (menu pollution + the command-add tax + its own discoverability problem), upgrade the path users already hit: bare `/impeccable` with no argument. - New skill/scripts/context-signals.mjs gathers cheap, deterministic signals (setup gaps, register, latest cached critique score, git change scope, a dev-server port probe, and a `scan.detectTarget` for the detector) and emits JSON. It does NOT score or rank, and it does NOT run the detector itself (the engine isn't importable in an installed skill, and shelling npx+jsdom would risk a hang) — the agent reasons over the raw signals. - SKILL.md routing rule 1 now leads with the 2-3 highest-value next commands, each with a reason from the signals, then the full menu. Never auto-runs; always confirms. Reuses init's "Recommend starting points" vocabulary. When a project has never been critiqued it offers critique; when scan.detectTarget is set it runs `npx impeccable detect --fast --json` and folds the hits in. - Export extractRegister from context.mjs for reuse. Stays 23 commands; no metadata/pin/site-data changes. Unit-tested, including a regression guard for porcelain leading-space path parsing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
06eabc144a
commit
772aa73aa3
@@ -144,11 +144,14 @@ Plus two management commands: `pin <command>` and `unpin <command>`, detailed be
|
||||
|
||||
Reason over the signals; there is no score to obey:
|
||||
- `setup.hasDesign` false while `setup.hasCode` true → `document` (capture the visual system).
|
||||
- `critique.latest` is `null` → the project has never been critiqued; for a set-up project with a real surface, offering `/impeccable critique <surface>` is a strong default.
|
||||
- `critique.latest` with a low `score` or non-zero `p0` / `p1` → `polish` (it reads that snapshot as its backlog), or re-run `critique` if the snapshot looks stale.
|
||||
- `git.changedFiles` pointing at one surface → scope `audit` or `polish` to those files specifically, naming them.
|
||||
- `devServer.running` true → `live` is available for in-browser iteration; if false, don't lead with `live`.
|
||||
- Otherwise group by intent exactly as init's "Recommend starting points" step does (build new / improve what's there / iterate visually), tailored to `setup.register`.
|
||||
|
||||
**If `scan.detectTarget` is set, run `node .github/skills/impeccable/scripts/detect.mjs --json <scan.detectTarget>` once** (the bundled detector: no network, no npx, full coverage) and fold the hits into your picks: many quality / contrast hits → `audit` or `polish`; a specific slop family → the matching command (gradient text or eyebrows → `quieter` / `typeset`, flat or gray palette → `colorize`, and so on). It's a real, current signal that beats guessing. If detect errors, skip it and recommend the user run `audit` themselves; never block the suggestion on it.
|
||||
|
||||
Keep it to 2-3 pointed picks with the exact command to type. The menu stays the fallback; the recommendation is the lede.
|
||||
2. **First word matches a command**: load its reference file and follow its instructions. Everything after the command name is the target.
|
||||
3. **First word doesn't match, but the intent clearly maps to one command** (e.g. "fix the spacing" → `layout`, "rewrite this error message" → `clarify`, "the colors feel flat" → `colorize`): load that command's reference and proceed as if invoked. If two commands could fit, ask once which.
|
||||
|
||||
@@ -150,8 +150,35 @@ async function devServerSignals() {
|
||||
return { running: open.length > 0, ports: open };
|
||||
}
|
||||
|
||||
/**
|
||||
* What the agent could point the bundled detector (`detect.mjs`) at. The
|
||||
* detector is HTML/CSS oriented, so a rendered page (dev server) or a static
|
||||
* HTML entry is a far better target than a raw source tree. This script does
|
||||
* NOT run the detector itself — it just surfaces the target so the agent can
|
||||
* run `node <scripts>/detect.mjs --json <target>` (bundled, dep-free, fast)
|
||||
* and fold the hits into its recommendation.
|
||||
*/
|
||||
function scanTarget(cwd, devServer) {
|
||||
if (devServer.running && devServer.ports.length) {
|
||||
return { detectTarget: `http://localhost:${devServer.ports[0]}`, via: 'dev-server' };
|
||||
}
|
||||
for (const c of ['index.html', 'public/index.html', 'dist/index.html', 'build/index.html']) {
|
||||
if (fs.existsSync(path.join(cwd, c))) return { detectTarget: c, via: 'html' };
|
||||
}
|
||||
for (const dir of ['.', 'public', 'dist', 'build']) {
|
||||
try {
|
||||
const abs = path.join(cwd, dir);
|
||||
if (!fs.existsSync(abs)) continue;
|
||||
const html = fs.readdirSync(abs).find((f) => f.endsWith('.html'));
|
||||
if (html) return { detectTarget: path.join(dir, html), via: 'html' };
|
||||
} catch { /* ignore unreadable dir */ }
|
||||
}
|
||||
return { detectTarget: null, via: null };
|
||||
}
|
||||
|
||||
export async function gatherSignals(cwd = process.cwd()) {
|
||||
const ctx = loadContext(cwd);
|
||||
const devServer = await devServerSignals();
|
||||
return {
|
||||
setup: {
|
||||
hasProduct: ctx.hasProduct,
|
||||
@@ -163,7 +190,8 @@ export async function gatherSignals(cwd = process.cwd()) {
|
||||
},
|
||||
critique: { latest: latestCritique(cwd) },
|
||||
git: gitSignals(cwd),
|
||||
devServer: await devServerSignals(),
|
||||
devServer,
|
||||
scan: scanTarget(cwd, devServer),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user