clud-bug 0.7.0-rc.14 → 0.7.0-rc.17

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.
Files changed (47) hide show
  1. package/dist/cli/hooks.d.ts +27 -19
  2. package/dist/cli/hooks.d.ts.map +1 -1
  3. package/dist/cli/hooks.js +77 -56
  4. package/dist/cli/hooks.js.map +1 -1
  5. package/dist/cli/main.d.ts.map +1 -1
  6. package/dist/cli/main.js +46 -13
  7. package/dist/cli/main.js.map +1 -1
  8. package/dist/cli/review-prompt.d.ts +10 -1
  9. package/dist/cli/review-prompt.d.ts.map +1 -1
  10. package/dist/cli/review-prompt.js +38 -5
  11. package/dist/cli/review-prompt.js.map +1 -1
  12. package/dist/cli/skills.d.ts +7 -0
  13. package/dist/cli/skills.d.ts.map +1 -1
  14. package/dist/cli/skills.js +42 -2
  15. package/dist/cli/skills.js.map +1 -1
  16. package/dist/cli/update.js +2 -2
  17. package/dist/cli/update.js.map +1 -1
  18. package/dist/core/design.d.ts +37 -0
  19. package/dist/core/design.d.ts.map +1 -0
  20. package/dist/core/design.js +47 -0
  21. package/dist/core/design.js.map +1 -0
  22. package/dist/core/index.d.ts +1 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/core/index.js +1 -0
  25. package/dist/core/index.js.map +1 -1
  26. package/dist/core/skills.d.ts +1 -1
  27. package/dist/core/skills.d.ts.map +1 -1
  28. package/dist/core/skills.js +7 -1
  29. package/dist/core/skills.js.map +1 -1
  30. package/dist/core/version.d.ts +1 -1
  31. package/dist/core/version.js +1 -1
  32. package/package.json +1 -1
  33. package/src/cli/hooks.ts +77 -56
  34. package/src/cli/main.ts +45 -13
  35. package/src/cli/review-prompt.ts +57 -5
  36. package/src/cli/skills.ts +42 -2
  37. package/src/cli/update.ts +2 -2
  38. package/src/core/design.ts +73 -0
  39. package/src/core/index.ts +7 -0
  40. package/src/core/skills.ts +8 -2
  41. package/src/core/version.ts +1 -1
  42. package/templates/skills/design/design-system-consistency.md +41 -0
  43. package/templates/skills/design/frontend-a11y.md +41 -0
  44. package/templates/skills/design/visual-polish.md +41 -0
  45. package/templates/workflow-py.yml.tmpl +14 -1
  46. package/templates/workflow-ts.yml.tmpl +14 -1
  47. package/templates/workflow.yml.tmpl +14 -1
@@ -1,18 +1,26 @@
1
- /** Stable marker embedded in our hook's prompt so re-runs replace it in place. */
1
+ /** Stable marker embedded in our hook so re-runs and upgrades from the old,
2
+ * broken `type: agent` hook — replace it in place. */
2
3
  export declare const CLUD_BUG_HOOK_MARKER = "clud-bug-local-review";
3
4
  /**
4
- * Build the `prompt` of the Claude Code `type: agent` commit-review hook,
5
- * pinned to the clud-bug VERSION that scaffolded it. Pinning matters: a bare
6
- * `npx clud-bug` resolves to the `latest` dist-tag, which can predate the
7
- * `review-prompt` verb (e.g. while v0.7 is prerelease on `next`); `@${version}`
8
- * guarantees the verb exists. `clud-bug update` refreshes the pin in place.
5
+ * Build the shell `command` of the commit-review hook, pinned to the clud-bug
6
+ * VERSION that scaffolded it (a bare `npx clud-bug` resolves to the `latest`
7
+ * dist-tag, which can predate the `review-prompt` verb; `@${version}` guarantees
8
+ * it). `clud-bug update` refreshes the pin in place.
9
9
  *
10
- * Rather than baking a static recipe (which would drift from the repo's
11
- * skills/config), it tells the subagent to run `clud-bug review-prompt` the
12
- * engine-driven verb that emits a recipe tailored to THIS repo's resolved plan
13
- * — and follow it. The recipe is generated fresh at commit time, always current.
10
+ * The command, in order:
11
+ * 1. Idempotency skip if this exact HEAD was already surfaced (avoids a
12
+ * re-review on an amend-with-no-change or a double-fire). The reviewed SHA
13
+ * is recorded under `.git/` (untracked), reusing the "last-reviewed-sha"
14
+ * idea the hosted bot uses on PR comments.
15
+ * 2. Fetch a fresh recipe tailored to THIS repo: `review-prompt --trigger
16
+ * commit` (an instruction recipe — `git show HEAD` + the skills + the
17
+ * report format — NOT raw data; it is meant to be FOLLOWED by an agent).
18
+ * 3. Surface it to the session by printing it and `exit 2`, so `asyncRewake`
19
+ * shows it to the main agent as a system reminder. The agent then reviews
20
+ * the commit on the session subscription.
21
+ * 4. Any failure or empty output → `exit 0` (quiet; the commit is never blocked).
14
22
  */
15
- export declare function buildCommitReviewPrompt(version: string): string;
23
+ export declare function buildCommitReviewCommand(version: string): string;
16
24
  /** One Claude Code hook entry: a tool matcher plus its hook list. */
17
25
  export interface HookMatcherEntry {
18
26
  matcher?: string;
@@ -24,17 +32,17 @@ export interface ClaudeSettings {
24
32
  [key: string]: unknown;
25
33
  }
26
34
  /**
27
- * Builds the PostToolUse entry that spawns the commit-review subagent: a native
28
- * `type: agent` hook that is backgrounded (`async`), surfaces findings
29
- * (`asyncRewake`), and fires only on `git commit` (`if`).
35
+ * Builds the PostToolUse entry that runs the commit-review command: a native
36
+ * `type: command` hook, backgrounded (`async`), surfacing the recipe back to the
37
+ * session (`asyncRewake` + exit 2), firing only on `git commit` (`if`).
30
38
  */
31
- export declare function buildLocalReviewHook(recipe: string): HookMatcherEntry;
39
+ export declare function buildLocalReviewHook(command: string): HookMatcherEntry;
32
40
  /**
33
41
  * Merges the clud-bug commit-review hook into an existing `.claude/settings.json`
34
- * object. **Idempotent** (replaces any prior clud-bug entry rather than
35
- * duplicating) and **non-clobbering** (preserves every other top-level key,
36
- * every other event, and every other hook). Tolerates a missing/malformed
42
+ * object. **Idempotent** (replaces any prior clud-bug entry including the old
43
+ * `type: agent` one — rather than duplicating) and **non-clobbering** (preserves
44
+ * every other top-level key, event, and hook). Tolerates a missing/malformed
37
45
  * `existing` value.
38
46
  */
39
- export declare function mergeLocalReviewHook(existing: unknown, recipe: string): ClaudeSettings;
47
+ export declare function mergeLocalReviewHook(existing: unknown, command: string): ClaudeSettings;
40
48
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"AAcA,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkB/D;AAED,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvC;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAcrE;AAUD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAwBtF"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"AAkBA;sDACsD;AACtD,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAuBhE;AAED,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvC;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CActE;AAcD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAwBvF"}
package/dist/cli/hooks.js CHANGED
@@ -1,90 +1,111 @@
1
- // Wave 6b — Claude Code `type: agent` commit-review hook scaffolding.
1
+ // Wave 6b (rc.17 fix) — Claude Code `type: command` commit-review hook scaffolding.
2
2
  //
3
3
  // `clud-bug init --with-hooks` writes a native Claude Code hook that, on every
4
- // `git commit` the agent makes, spawns a clud-bug review SUBAGENT in the same
5
- // session — so it runs on the session's subscription (no API key), in the
6
- // background (the commit never blocks), and surfaces findings back to the agent.
4
+ // `git commit`, runs clud-bug's review recipe ON THIS SESSION'S SUBSCRIPTION
5
+ // (no API key), in the background (the commit never blocks).
7
6
  //
8
- // The model (see the Wave 6b plan): clud-bug supplies the *recipe* (the
9
- // agent-hook `prompt`); Claude Code runs it as a subagent. This is the dynamic,
10
- // always-on counterpart to the `/clud-bug-review` slash command.
11
- //
12
- // `type: agent` hooks are documented as experimental; the same outcome is
13
- // reachable via a `type: command` hook + `additionalContext` if the API shifts.
14
- /** Stable marker embedded in our hook's prompt so re-runs replace it in place. */
7
+ // WHY `type: command`, NOT `type: agent`: a Claude Code `type: agent` hook
8
+ // spawns a subagent restricted to Read/Grep/Glob — it has NO Bash and the tool
9
+ // set is not configurable (see code.claude.com/docs/en/hooks: "spawn a subagent
10
+ // that can use tools like Read, Grep, and Glob"). The original Wave 6b hook used
11
+ // `type: agent` and told the subagent to run `npx clud-bug review-prompt` — a
12
+ // Bash CLI call an agent hook can never make — so the review NEVER ran for
13
+ // anyone. A `type: command` hook CAN run the CLI: it fetches the engine's recipe
14
+ // and surfaces it to the session via exit-2 (`asyncRewake`), so the MAIN agent —
15
+ // which has Bash, git, gh, and the subscription — performs the review. The hook
16
+ // exits 0 on any failure, so a review that can't run is a quiet no-op and the
17
+ // commit is NEVER blocked.
18
+ /** Stable marker embedded in our hook so re-runs — and upgrades from the old,
19
+ * broken `type: agent` hook — replace it in place. */
15
20
  export const CLUD_BUG_HOOK_MARKER = 'clud-bug-local-review';
16
21
  /**
17
- * Build the `prompt` of the Claude Code `type: agent` commit-review hook,
18
- * pinned to the clud-bug VERSION that scaffolded it. Pinning matters: a bare
19
- * `npx clud-bug` resolves to the `latest` dist-tag, which can predate the
20
- * `review-prompt` verb (e.g. while v0.7 is prerelease on `next`); `@${version}`
21
- * guarantees the verb exists. `clud-bug update` refreshes the pin in place.
22
+ * Build the shell `command` of the commit-review hook, pinned to the clud-bug
23
+ * VERSION that scaffolded it (a bare `npx clud-bug` resolves to the `latest`
24
+ * dist-tag, which can predate the `review-prompt` verb; `@${version}` guarantees
25
+ * it). `clud-bug update` refreshes the pin in place.
22
26
  *
23
- * Rather than baking a static recipe (which would drift from the repo's
24
- * skills/config), it tells the subagent to run `clud-bug review-prompt` the
25
- * engine-driven verb that emits a recipe tailored to THIS repo's resolved plan
26
- * — and follow it. The recipe is generated fresh at commit time, always current.
27
+ * The command, in order:
28
+ * 1. Idempotency skip if this exact HEAD was already surfaced (avoids a
29
+ * re-review on an amend-with-no-change or a double-fire). The reviewed SHA
30
+ * is recorded under `.git/` (untracked), reusing the "last-reviewed-sha"
31
+ * idea the hosted bot uses on PR comments.
32
+ * 2. Fetch a fresh recipe tailored to THIS repo: `review-prompt --trigger
33
+ * commit` (an instruction recipe — `git show HEAD` + the skills + the
34
+ * report format — NOT raw data; it is meant to be FOLLOWED by an agent).
35
+ * 3. Surface it to the session by printing it and `exit 2`, so `asyncRewake`
36
+ * shows it to the main agent as a system reminder. The agent then reviews
37
+ * the commit on the session subscription.
38
+ * 4. Any failure or empty output → `exit 0` (quiet; the commit is never blocked).
27
39
  */
28
- export function buildCommitReviewPrompt(version) {
29
- return `<!-- ${CLUD_BUG_HOOK_MARKER} v1 -->
30
- You are clud-bug's local commit review, running as a background subagent on this
31
- session's own subscription (no extra auth you have git, gh, and file access).
32
-
33
- Step 1get your review recipe from clud-bug's engine:
34
-
35
- npx clud-bug@${version} review-prompt --trigger commit
36
-
37
- That prints a structured review recipe tailored to THIS repo's skills + config (a
38
- fast single pass for a commit). If that command isn't available, run the repo's
39
- installed clud-bug CLI's \`review-prompt --trigger commit\` instead.
40
-
41
- Step 2 follow that recipe exactly: review the commit that was just made against
42
- the skills it names, and surface any findings back into the session so they can be
43
- fixed. A clean commit needs only a one-line note.
44
-
45
- Keep it tight this is the commit-time safety net; the deeper review runs at PR time.`;
40
+ export function buildCommitReviewCommand(version) {
41
+ return [
42
+ // Marker as a `#` comment (NOT a `:` no-op) so its free text can never break
43
+ // `sh` a paren / quote / `$` in the marker line would be a syntax error
44
+ // under `: ...`. The dogfood caught this. `isOurHook` finds the marker here.
45
+ `# ${CLUD_BUG_HOOK_MARKER} v2 clud-bug commit review on the session subscription`,
46
+ // Belt-and-suspenders gate. The `if: Bash(git commit *)` / `Bash(logmind log *)`
47
+ // field filters at the platform on Claude Code >= 2.1.85; OLDER CC ignores
48
+ // `if` and would fire this on EVERY Bash call (a review recipe after every
49
+ // command). Command hooks get the event JSON on stdin re-check it here. If
50
+ // stdin is empty (a CC that doesn't pipe it), fall through and trust `if`.
51
+ `ev=$(cat 2>/dev/null)`,
52
+ `if [ -n "$ev" ]; then case "$ev" in *'git commit'*|*'logmind log'*) ;; *) exit 0 ;; esac; fi`,
53
+ `sha=$(git rev-parse HEAD 2>/dev/null) || exit 0`,
54
+ `gitdir=$(git rev-parse --git-dir 2>/dev/null) || exit 0`,
55
+ `marker="$gitdir/clud-bug-last-commit-review"`,
56
+ `[ "$(cat "$marker" 2>/dev/null)" = "$sha" ] && exit 0`,
57
+ `recipe=$(npx clud-bug@${version} review-prompt --trigger commit 2>/dev/null) || exit 0`,
58
+ `[ -n "$recipe" ] || exit 0`,
59
+ `printf '%s' "$sha" > "$marker" 2>/dev/null || true`,
60
+ `printf '%s\\n\\n%s\\n' "clud-bug commit review (max mode — on this session's subscription): a commit was just made. Follow this recipe now — review that commit against the skills it names and surface any findings." "$recipe"`,
61
+ `exit 2`,
62
+ ].join('\n');
46
63
  }
47
64
  /**
48
- * Builds the PostToolUse entry that spawns the commit-review subagent: a native
49
- * `type: agent` hook that is backgrounded (`async`), surfaces findings
50
- * (`asyncRewake`), and fires only on `git commit` (`if`).
65
+ * Builds the PostToolUse entry that runs the commit-review command: a native
66
+ * `type: command` hook, backgrounded (`async`), surfacing the recipe back to the
67
+ * session (`asyncRewake` + exit 2), firing only on `git commit` (`if`).
51
68
  */
52
- export function buildLocalReviewHook(recipe) {
69
+ export function buildLocalReviewHook(command) {
70
+ const base = { type: 'command', async: true, asyncRewake: true, timeout: 180, command };
53
71
  return {
54
72
  matcher: 'Bash',
55
73
  hooks: [
56
- {
57
- type: 'agent',
58
- if: 'Bash(git commit *)',
59
- async: true,
60
- asyncRewake: true,
61
- timeout: 180,
62
- prompt: recipe,
63
- },
74
+ { ...base, if: 'Bash(git commit *)' },
75
+ // thrillmade repos (and any logmind user) commit via `logmind log`, which
76
+ // wraps `git commit` inside its own binary — so the Bash tool call is
77
+ // `logmind log ...`, which `Bash(git commit *)` never matches. Fire on it
78
+ // too, or max mode never triggers in a logmind repo. The idempotency
79
+ // SHA-marker means whichever path runs, a commit is reviewed exactly once.
80
+ { ...base, if: 'Bash(logmind log *)' },
64
81
  ],
65
82
  };
66
83
  }
67
84
  function isOurHook(h) {
68
- return typeof h?.['prompt'] === 'string' && h['prompt'].includes(CLUD_BUG_HOOK_MARKER);
85
+ // Match our marker in `command` (current `type: command` hook) OR `prompt`
86
+ // (the old, broken `type: agent` hook) so a re-install / `clud-bug update`
87
+ // replaces either in place.
88
+ const field = h?.['command'] ?? h?.['prompt'];
89
+ return typeof field === 'string' && field.includes(CLUD_BUG_HOOK_MARKER);
69
90
  }
70
91
  function isCludBugReviewEntry(entry) {
71
92
  return !!entry && Array.isArray(entry.hooks) && entry.hooks.some(isOurHook);
72
93
  }
73
94
  /**
74
95
  * Merges the clud-bug commit-review hook into an existing `.claude/settings.json`
75
- * object. **Idempotent** (replaces any prior clud-bug entry rather than
76
- * duplicating) and **non-clobbering** (preserves every other top-level key,
77
- * every other event, and every other hook). Tolerates a missing/malformed
96
+ * object. **Idempotent** (replaces any prior clud-bug entry including the old
97
+ * `type: agent` one — rather than duplicating) and **non-clobbering** (preserves
98
+ * every other top-level key, event, and hook). Tolerates a missing/malformed
78
99
  * `existing` value.
79
100
  */
80
- export function mergeLocalReviewHook(existing, recipe) {
101
+ export function mergeLocalReviewHook(existing, command) {
81
102
  const base = existing && typeof existing === 'object' ? { ...existing } : {};
82
103
  const hooks = { ...(base.hooks ?? {}) };
83
104
  const priorPost = Array.isArray(hooks.PostToolUse) ? hooks.PostToolUse : [];
84
105
  // Preserve every non-clud-bug hook — including any the user co-located INSIDE
85
106
  // our own matcher entry: drop only the hook(s) carrying our marker, never the
86
107
  // whole entry.
87
- const ours = buildLocalReviewHook(recipe);
108
+ const ours = buildLocalReviewHook(command);
88
109
  const otherEntries = [];
89
110
  const coLocatedUserHooks = [];
90
111
  for (const entry of priorPost) {
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,0EAA0E;AAC1E,iFAAiF;AACjF,EAAE;AACF,wEAAwE;AACxE,gFAAgF;AAChF,iEAAiE;AACjE,EAAE;AACF,0EAA0E;AAC1E,gFAAgF;AAEhF,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,QAAQ,oBAAoB;;;;;;mBAMlB,OAAO;;;;;;;;;;uFAU6D,CAAC;AACxF,CAAC;AAcD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO;QACL,OAAO,EAAE,MAAM;QACf,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,OAAO;gBACb,EAAE,EAAE,oBAAoB;gBACxB,KAAK,EAAE,IAAI;gBACX,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,GAAG;gBACZ,MAAM,EAAE,MAAM;aACf;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,CAAsC;IACvD,OAAO,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,QAAQ,IAAK,CAAC,CAAC,QAAQ,CAAY,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AACrG,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmC;IAC/D,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAiB,EAAE,MAAc;IACpE,MAAM,IAAI,GACR,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAI,QAA2B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,MAAM,KAAK,GAAuC,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;IAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5E,8EAA8E;IAC9E,8EAA8E;IAC9E,eAAe;IACf,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAuB,EAAE,CAAC;IAC5C,MAAM,kBAAkB,GAAmC,EAAE,CAAC;IAC9D,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK;gBAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;oBAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7E,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GACZ,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,kBAAkB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpG,KAAK,CAAC,WAAW,GAAG,CAAC,GAAG,YAAY,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAmPA,iBAAe,IAAI,kBA6BlB;AAm8DD,OAAO,EAAE,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AA4PA,iBAAe,IAAI,kBA6BlB;AA09DD,OAAO,EAAE,IAAI,EAAE,CAAC"}
package/dist/cli/main.js CHANGED
@@ -22,7 +22,7 @@ import { detect, buildDescriptionLine } from '../core/detect.js';
22
22
  import { renderFile, pickTemplate, templateLanguage } from '../core/render.js';
23
23
  import { reviewPrompt } from '../core/prompts.js';
24
24
  import { SkillsClient, rankAndCap } from '../core/skills.js';
25
- import { writeSkills, writeSkill, loadBaseline, readManifest, writeManifest, removeSkill, listInstalled, diffManifest, } from './skills.js';
25
+ import { writeSkills, writeSkill, loadBaseline, loadDesignKit, readManifest, writeManifest, removeSkill, listInstalled, diffManifest, } from './skills.js';
26
26
  import { computeAuditFileSet } from './audit.js';
27
27
  import { renderAuditHeader } from '../core/audit.js';
28
28
  import { runUpdate } from './update.js';
@@ -38,6 +38,7 @@ import { computeReviewCost, costPerLOC, cacheHitRate, extractTokensFromLog, roll
38
38
  const PKG_ROOT = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
39
39
  const TEMPLATES = join(PKG_ROOT, 'templates');
40
40
  const BASELINE_DIR = join(TEMPLATES, 'skills', 'baseline');
41
+ const DESIGN_DIR = join(TEMPLATES, 'skills', 'design');
41
42
  function parseArgs(argv) {
42
43
  const args = {
43
44
  _: [], offline: false, acceptAll: false, commit: false, help: false, version: false,
@@ -61,6 +62,10 @@ function parseArgs(argv) {
61
62
  // Claude Code session (reviews the current PR with the session's tokens).
62
63
  withLocalReview: false,
63
64
  withHooks: false,
65
+ // rc.16: `clud-bug init --with-design` installs the design-critic kit
66
+ // (3 `kind: design` skills) and flips the off-by-default `design` block to
67
+ // enabled so the visual review lens runs (local recipe + hosted bot).
68
+ withDesign: false,
64
69
  // v0.7.0-rc.4: `clud-bug configure-github` flags.
65
70
  // --dry-run prints the diff but skips PATCH; --branch overrides "main".
66
71
  dryRun: false,
@@ -110,6 +115,8 @@ function parseArgs(argv) {
110
115
  args.withLocalReview = true;
111
116
  else if (a === '--with-hooks')
112
117
  args.withHooks = true;
118
+ else if (a === '--with-design')
119
+ args.withDesign = true;
113
120
  else if (a === '--dry-run')
114
121
  args.dryRun = true;
115
122
  else if (a === '--branch')
@@ -222,11 +229,14 @@ Options:
222
229
  \`/clud-bug-review\` works in a Claude Code session —
223
230
  reviews the current branch's PR using that session's
224
231
  own tokens (no hosted App, no extra auth).
225
- --with-hooks (init) Also scaffold a native Claude Code \`type: agent\`
232
+ --with-hooks (init) Scaffold a native Claude Code \`type: command\`
226
233
  commit-review hook into .claude/settings.json — on every
227
- \`git commit\` the agent makes, a backgrounded clud-bug
228
- review subagent runs on the session's subscription.
229
- Implies --with-local-review. Off by default.
234
+ \`git commit\` / \`logmind log\`, it fetches a review recipe and
235
+ surfaces it to the agent (on this session's subscription)
236
+ via asyncRewake. Implies --with-local-review. Off by default.
237
+ --with-design (init) Install the design-critic kit (3 \`kind: design\`
238
+ skills) and enable the off-by-default visual review
239
+ lens — renders changed UI and critiques it. Off by default.
230
240
  --quiet,-q Token-frugal mode for agent invocations. Suppresses
231
241
  progress chatter; emits exactly one final
232
242
  \`ok <key-value>\` summary line per command. Errors
@@ -1179,14 +1189,16 @@ async function runInit(args) {
1179
1189
  await writeFile(commandPath, commandContent);
1180
1190
  log(` wrote ${rel(cwd, commandPath)}`);
1181
1191
  }
1182
- // v0.7.0 (Wave 6b): optional native commit-review hook. Merges a Claude Code
1183
- // `type: agent` PostToolUse hook into `.claude/settings.json` (preserving any
1184
- // existing settings + hooks) that, on every `git commit` the agent makes,
1185
- // spawns a clud-bug review subagent on the session's subscription, in the
1186
- // background the hook's prompt runs `clud-bug review-prompt` and follows it.
1192
+ // v0.7.0 (Wave 6b; rc.17 fix): optional native commit-review hook. Merges a
1193
+ // Claude Code `type: command` PostToolUse hook into `.claude/settings.json`
1194
+ // (preserving any existing settings + hooks) that, on every `git commit`, runs
1195
+ // `clud-bug review-prompt` and surfaces the recipe back to the session so the
1196
+ // agent reviews the commit on the session's subscription, in the background.
1197
+ // (`type: command`, not `type: agent` — agent hooks get no Bash, so they could
1198
+ // never run the CLI; see hooks.ts.)
1187
1199
  if (args.withHooks) {
1188
- const { mergeLocalReviewHook, buildCommitReviewPrompt } = await import('./hooks.js');
1189
- const hookPrompt = buildCommitReviewPrompt(await readPkgVersion());
1200
+ const { mergeLocalReviewHook, buildCommitReviewCommand } = await import('./hooks.js');
1201
+ const hookCommand = buildCommitReviewCommand(await readPkgVersion());
1190
1202
  const settingsPath = join(cwd, '.claude', 'settings.json');
1191
1203
  await mkdir(dirname(settingsPath), { recursive: true });
1192
1204
  // Read-then-parse so we can tell "no file yet" (fresh merge) from "file
@@ -1210,11 +1222,26 @@ async function runInit(args) {
1210
1222
  }
1211
1223
  }
1212
1224
  if (proceed) {
1213
- const merged = mergeLocalReviewHook(existing, hookPrompt);
1225
+ const merged = mergeLocalReviewHook(existing, hookCommand);
1214
1226
  await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n');
1215
1227
  log(` wrote ${rel(cwd, settingsPath)} (commit-review hook)`);
1216
1228
  }
1217
1229
  }
1230
+ // rc.16: --with-design installs the bundled design-critic kit (3 `kind:
1231
+ // design` skills) and enables the off-by-default design lens. writeSkills
1232
+ // writes the SKILL.md files + merges the manifest entries; the `design` block
1233
+ // is flipped on the manifest read below so the local recipe + hosted bot both
1234
+ // run the visual pass. Idempotent — re-runs replace the skills in place.
1235
+ if (args.withDesign) {
1236
+ const designKit = await loadDesignKit(DESIGN_DIR);
1237
+ if (designKit.length > 0) {
1238
+ await writeSkills(join(cwd, '.claude', 'skills'), designKit, client);
1239
+ log(` pinned ${designKit.length} design specimens (visual review lens enabled)`);
1240
+ }
1241
+ else {
1242
+ warn('No design-kit skills found to install (templates/skills/design/ empty?).');
1243
+ }
1244
+ }
1218
1245
  // Stamp the manifest. Sets strictMode: true ONLY on fresh installs —
1219
1246
  // a manifest that's never been touched by clud-bug init/update has no
1220
1247
  // lastUpdate field. Existing v0.3.x advisory installs (where strictMode
@@ -1223,6 +1250,12 @@ async function runInit(args) {
1223
1250
  // fresh inits. Users opt out by setting strictMode: false.
1224
1251
  const skillsDirPath = join(cwd, '.claude', 'skills');
1225
1252
  const manifest = await readManifest(skillsDirPath);
1253
+ if (args.withDesign) {
1254
+ // Flip the off-by-default design lens on; preserve any existing knobs
1255
+ // (gate / themes / viewports) the user already set.
1256
+ const prior = manifest.design ?? {};
1257
+ manifest.design = { ...prior, enabled: true };
1258
+ }
1226
1259
  const isFreshInstall = manifest.lastUpdate === undefined;
1227
1260
  manifest.lastUpdateVersion = await readPkgVersion();
1228
1261
  manifest.lastUpdate = new Date().toISOString();