clud-bug 0.7.0-rc.15 → 0.7.0-rc.18
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/dist/cli/hooks.d.ts +27 -19
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +77 -56
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +135 -47
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/skills.d.ts +7 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +37 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/update.js +2 -2
- package/dist/cli/update.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
- package/src/cli/hooks.ts +77 -56
- package/src/cli/main.ts +131 -49
- package/src/cli/skills.ts +38 -1
- package/src/cli/update.ts +2 -2
- package/src/core/version.ts +1 -1
- package/templates/workflow-py.yml.tmpl +14 -1
- package/templates/workflow-ts.yml.tmpl +14 -1
- package/templates/workflow.yml.tmpl +14 -1
package/dist/cli/hooks.d.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
/** Stable marker embedded in our hook
|
|
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 `
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
|
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
|
|
28
|
-
* `type:
|
|
29
|
-
* (`asyncRewake`),
|
|
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(
|
|
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
|
|
35
|
-
* duplicating) and **non-clobbering** (preserves
|
|
36
|
-
* every other event, and
|
|
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,
|
|
47
|
+
export declare function mergeLocalReviewHook(existing: unknown, command: string): ClaudeSettings;
|
|
40
48
|
//# sourceMappingURL=hooks.d.ts.map
|
package/dist/cli/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"
|
|
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:
|
|
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
|
|
5
|
-
//
|
|
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
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// `type: agent`
|
|
13
|
-
//
|
|
14
|
-
|
|
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 `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `
|
|
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
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
49
|
-
* `type:
|
|
50
|
-
* (`asyncRewake`),
|
|
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(
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
|
76
|
-
* duplicating) and **non-clobbering** (preserves
|
|
77
|
-
* every other event, and
|
|
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,
|
|
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(
|
|
108
|
+
const ours = buildLocalReviewHook(command);
|
|
88
109
|
const otherEntries = [];
|
|
89
110
|
const coLocatedUserHooks = [];
|
|
90
111
|
for (const entry of priorPost) {
|
package/dist/cli/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/cli/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAuQA,iBAAe,IAAI,kBA6BlB;AAigED,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,16 @@ 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,
|
|
69
|
+
// rc.18: `clud-bug init --local-only` installs MAX MODE (skills + slash
|
|
70
|
+
// command + commit hook), but SKIPS the GitHub Action workflows (which run
|
|
71
|
+
// claude-code-action with ANTHROPIC_API_KEY). For repos that review on a
|
|
72
|
+
// Claude subscription via the in-session hook, not a billed CI Action.
|
|
73
|
+
// Implies --with-local-review + --with-hooks.
|
|
74
|
+
localOnly: false,
|
|
64
75
|
// v0.7.0-rc.4: `clud-bug configure-github` flags.
|
|
65
76
|
// --dry-run prints the diff but skips PATCH; --branch overrides "main".
|
|
66
77
|
dryRun: false,
|
|
@@ -110,6 +121,10 @@ function parseArgs(argv) {
|
|
|
110
121
|
args.withLocalReview = true;
|
|
111
122
|
else if (a === '--with-hooks')
|
|
112
123
|
args.withHooks = true;
|
|
124
|
+
else if (a === '--with-design')
|
|
125
|
+
args.withDesign = true;
|
|
126
|
+
else if (a === '--local-only')
|
|
127
|
+
args.localOnly = true;
|
|
113
128
|
else if (a === '--dry-run')
|
|
114
129
|
args.dryRun = true;
|
|
115
130
|
else if (a === '--branch')
|
|
@@ -222,11 +237,18 @@ Options:
|
|
|
222
237
|
\`/clud-bug-review\` works in a Claude Code session —
|
|
223
238
|
reviews the current branch's PR using that session's
|
|
224
239
|
own tokens (no hosted App, no extra auth).
|
|
225
|
-
--with-hooks (init)
|
|
240
|
+
--with-hooks (init) Scaffold a native Claude Code \`type: command\`
|
|
226
241
|
commit-review hook into .claude/settings.json — on every
|
|
227
|
-
\`git commit\`
|
|
228
|
-
|
|
229
|
-
Implies --with-local-review. Off by default.
|
|
242
|
+
\`git commit\` / \`logmind log\`, it fetches a review recipe and
|
|
243
|
+
surfaces it to the agent (on this session's subscription)
|
|
244
|
+
via asyncRewake. Implies --with-local-review. Off by default.
|
|
245
|
+
--with-design (init) Install the design-critic kit (3 \`kind: design\`
|
|
246
|
+
skills) and enable the off-by-default visual review
|
|
247
|
+
lens — renders changed UI and critiques it. Off by default.
|
|
248
|
+
--local-only (init) MAX MODE: install the slash command + commit hook
|
|
249
|
+
(implies --with-local-review + --with-hooks) but SKIP the
|
|
250
|
+
GitHub Action workflows. Reviews run in your Claude Code
|
|
251
|
+
session on your subscription — no API key, no per-review bill.
|
|
230
252
|
--quiet,-q Token-frugal mode for agent invocations. Suppresses
|
|
231
253
|
progress chatter; emits exactly one final
|
|
232
254
|
\`ok <key-value>\` summary line per command. Errors
|
|
@@ -1141,27 +1163,37 @@ async function runInit(args) {
|
|
|
1141
1163
|
language: templateLanguage(tmplName),
|
|
1142
1164
|
}),
|
|
1143
1165
|
});
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
//
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1166
|
+
// --local-only (max mode): SKIP the GitHub Action workflows entirely. The
|
|
1167
|
+
// review + audit workflows run `claude-code-action` with ANTHROPIC_API_KEY
|
|
1168
|
+
// (per-token cost); max mode reviews on the session's own subscription, so a
|
|
1169
|
+
// local-only install must never add a token-billing Action. (self-update is
|
|
1170
|
+
// benign but skipped too — local-only means no clud-bug CI workflows at all.)
|
|
1171
|
+
if (args.localOnly) {
|
|
1172
|
+
log(' skipped GitHub Action workflows (--local-only: max mode runs on the session subscription, no API key)');
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
const workflowPath = join(cwd, '.github', 'workflows', 'clud-bug-review.yml');
|
|
1176
|
+
await mkdir(dirname(workflowPath), { recursive: true });
|
|
1177
|
+
await writeFile(workflowPath, workflow);
|
|
1178
|
+
log(` wrote ${rel(cwd, workflowPath)}`);
|
|
1179
|
+
// Install the audit workflow alongside the per-PR review one.
|
|
1180
|
+
// Manual-trigger by default; users opt into the cron by uncommenting.
|
|
1181
|
+
// Routed through renderFile so {{CCA_VERSION}} substitution pins
|
|
1182
|
+
// claude-code-action consistently with the review workflow.
|
|
1183
|
+
const auditTmpl = await renderFile(join(TEMPLATES, 'audit.yml.tmpl'), {});
|
|
1184
|
+
const auditPath = join(cwd, '.github', 'workflows', 'clud-bug-audit.yml');
|
|
1185
|
+
await writeFile(auditPath, auditTmpl);
|
|
1186
|
+
log(` wrote ${rel(cwd, auditPath)}`);
|
|
1187
|
+
// Install the self-update workflow. Cron weekly Mondays 12:00 UTC; opens
|
|
1188
|
+
// a PR if a newer clud-bug version is published. Disable by deleting the
|
|
1189
|
+
// file or pinning via .claude/skills/.clud-bug.json.
|
|
1190
|
+
// Routed through renderFile for parity (no CCA ref today but future
|
|
1191
|
+
// tokens should propagate uniformly).
|
|
1192
|
+
const selfUpdateTmpl = await renderFile(join(TEMPLATES, 'self-update.yml.tmpl'), {});
|
|
1193
|
+
const selfUpdatePath = join(cwd, '.github', 'workflows', 'clud-bug-self-update.yml');
|
|
1194
|
+
await writeFile(selfUpdatePath, selfUpdateTmpl);
|
|
1195
|
+
log(` wrote ${rel(cwd, selfUpdatePath)}`);
|
|
1196
|
+
}
|
|
1165
1197
|
// v0.7.0 (Wave 6b): optional local-review slash command. Scaffolds
|
|
1166
1198
|
// `.claude/commands/clud-bug-review.md` so `/clud-bug-review` works inside a
|
|
1167
1199
|
// Claude Code session — the agent reviews the current branch's open PR using
|
|
@@ -1170,6 +1202,12 @@ async function runInit(args) {
|
|
|
1170
1202
|
// `--with-hooks` implies `--with-local-review` — the auto hook and the manual
|
|
1171
1203
|
// `/clud-bug-review` command are complementary (the hook auto-runs the engine
|
|
1172
1204
|
// recipe on each commit; the command runs it on demand against the PR).
|
|
1205
|
+
// --local-only IS the max-mode install: the slash command + the commit hook,
|
|
1206
|
+
// minus the GitHub Action workflows (gated above).
|
|
1207
|
+
if (args.localOnly) {
|
|
1208
|
+
args.withLocalReview = true;
|
|
1209
|
+
args.withHooks = true;
|
|
1210
|
+
}
|
|
1173
1211
|
if (args.withHooks)
|
|
1174
1212
|
args.withLocalReview = true;
|
|
1175
1213
|
if (args.withLocalReview) {
|
|
@@ -1179,14 +1217,16 @@ async function runInit(args) {
|
|
|
1179
1217
|
await writeFile(commandPath, commandContent);
|
|
1180
1218
|
log(` wrote ${rel(cwd, commandPath)}`);
|
|
1181
1219
|
}
|
|
1182
|
-
// v0.7.0 (Wave 6b): optional native commit-review hook. Merges a
|
|
1183
|
-
// `type:
|
|
1184
|
-
// existing settings + hooks) that, on every `git commit
|
|
1185
|
-
//
|
|
1186
|
-
//
|
|
1220
|
+
// v0.7.0 (Wave 6b; rc.17 fix): optional native commit-review hook. Merges a
|
|
1221
|
+
// Claude Code `type: command` PostToolUse hook into `.claude/settings.json`
|
|
1222
|
+
// (preserving any existing settings + hooks) that, on every `git commit`, runs
|
|
1223
|
+
// `clud-bug review-prompt` and surfaces the recipe back to the session so the
|
|
1224
|
+
// agent reviews the commit on the session's subscription, in the background.
|
|
1225
|
+
// (`type: command`, not `type: agent` — agent hooks get no Bash, so they could
|
|
1226
|
+
// never run the CLI; see hooks.ts.)
|
|
1187
1227
|
if (args.withHooks) {
|
|
1188
|
-
const { mergeLocalReviewHook,
|
|
1189
|
-
const
|
|
1228
|
+
const { mergeLocalReviewHook, buildCommitReviewCommand } = await import('./hooks.js');
|
|
1229
|
+
const hookCommand = buildCommitReviewCommand(await readPkgVersion());
|
|
1190
1230
|
const settingsPath = join(cwd, '.claude', 'settings.json');
|
|
1191
1231
|
await mkdir(dirname(settingsPath), { recursive: true });
|
|
1192
1232
|
// Read-then-parse so we can tell "no file yet" (fresh merge) from "file
|
|
@@ -1210,11 +1250,26 @@ async function runInit(args) {
|
|
|
1210
1250
|
}
|
|
1211
1251
|
}
|
|
1212
1252
|
if (proceed) {
|
|
1213
|
-
const merged = mergeLocalReviewHook(existing,
|
|
1253
|
+
const merged = mergeLocalReviewHook(existing, hookCommand);
|
|
1214
1254
|
await writeFile(settingsPath, JSON.stringify(merged, null, 2) + '\n');
|
|
1215
1255
|
log(` wrote ${rel(cwd, settingsPath)} (commit-review hook)`);
|
|
1216
1256
|
}
|
|
1217
1257
|
}
|
|
1258
|
+
// rc.16: --with-design installs the bundled design-critic kit (3 `kind:
|
|
1259
|
+
// design` skills) and enables the off-by-default design lens. writeSkills
|
|
1260
|
+
// writes the SKILL.md files + merges the manifest entries; the `design` block
|
|
1261
|
+
// is flipped on the manifest read below so the local recipe + hosted bot both
|
|
1262
|
+
// run the visual pass. Idempotent — re-runs replace the skills in place.
|
|
1263
|
+
if (args.withDesign) {
|
|
1264
|
+
const designKit = await loadDesignKit(DESIGN_DIR);
|
|
1265
|
+
if (designKit.length > 0) {
|
|
1266
|
+
await writeSkills(join(cwd, '.claude', 'skills'), designKit, client);
|
|
1267
|
+
log(` pinned ${designKit.length} design specimens (visual review lens enabled)`);
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
warn('No design-kit skills found to install (templates/skills/design/ empty?).');
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1218
1273
|
// Stamp the manifest. Sets strictMode: true ONLY on fresh installs —
|
|
1219
1274
|
// a manifest that's never been touched by clud-bug init/update has no
|
|
1220
1275
|
// lastUpdate field. Existing v0.3.x advisory installs (where strictMode
|
|
@@ -1223,6 +1278,12 @@ async function runInit(args) {
|
|
|
1223
1278
|
// fresh inits. Users opt out by setting strictMode: false.
|
|
1224
1279
|
const skillsDirPath = join(cwd, '.claude', 'skills');
|
|
1225
1280
|
const manifest = await readManifest(skillsDirPath);
|
|
1281
|
+
if (args.withDesign) {
|
|
1282
|
+
// Flip the off-by-default design lens on; preserve any existing knobs
|
|
1283
|
+
// (gate / themes / viewports) the user already set.
|
|
1284
|
+
const prior = manifest.design ?? {};
|
|
1285
|
+
manifest.design = { ...prior, enabled: true };
|
|
1286
|
+
}
|
|
1226
1287
|
const isFreshInstall = manifest.lastUpdate === undefined;
|
|
1227
1288
|
manifest.lastUpdateVersion = await readPkgVersion();
|
|
1228
1289
|
manifest.lastUpdate = new Date().toISOString();
|
|
@@ -1252,9 +1313,14 @@ async function runInit(args) {
|
|
|
1252
1313
|
log(' committing...');
|
|
1253
1314
|
const toAdd = [
|
|
1254
1315
|
'.claude',
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1316
|
+
// No GitHub Action workflows under --local-only (none were written).
|
|
1317
|
+
...(args.localOnly
|
|
1318
|
+
? []
|
|
1319
|
+
: [
|
|
1320
|
+
'.github/workflows/clud-bug-review.yml',
|
|
1321
|
+
'.github/workflows/clud-bug-audit.yml',
|
|
1322
|
+
'.github/workflows/clud-bug-self-update.yml',
|
|
1323
|
+
]),
|
|
1258
1324
|
...agentDocs.created,
|
|
1259
1325
|
...agentDocs.touched,
|
|
1260
1326
|
];
|
|
@@ -1269,22 +1335,44 @@ async function runInit(args) {
|
|
|
1269
1335
|
await runInitBranchProtection(args);
|
|
1270
1336
|
log('');
|
|
1271
1337
|
log('Field kit assembled. Next:');
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
log('
|
|
1276
|
-
|
|
1338
|
+
if (args.localOnly) {
|
|
1339
|
+
log(' Max mode — reviews run inside your Claude Code session on your own');
|
|
1340
|
+
log(' subscription. No API key, no GitHub Action, no per-review bill. On every');
|
|
1341
|
+
log(' commit the hook surfaces a review recipe; or run /clud-bug-review on demand.');
|
|
1342
|
+
if (!args.commit) {
|
|
1343
|
+
log(' → git add .claude && git commit && git push');
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
log(' → git push.');
|
|
1347
|
+
}
|
|
1277
1348
|
}
|
|
1278
1349
|
else {
|
|
1279
|
-
log('
|
|
1350
|
+
log(' 1. Set ANTHROPIC_API_KEY in your repo secrets:');
|
|
1351
|
+
log(' Settings → Secrets and variables → Actions → New repository secret');
|
|
1352
|
+
if (!args.commit) {
|
|
1353
|
+
log(' 2. git add .claude .github/workflows/clud-bug-*.yml && git commit && git push');
|
|
1354
|
+
log(' 3. Open a PR — the naturalist arrives within ~2 minutes.');
|
|
1355
|
+
}
|
|
1356
|
+
else {
|
|
1357
|
+
log(' 2. git push, then open a PR — the naturalist arrives within ~2 minutes.');
|
|
1358
|
+
}
|
|
1280
1359
|
}
|
|
1281
1360
|
log('');
|
|
1282
1361
|
log('Drop your own .claude/skills/<name>/SKILL.md files anytime — they get pinned automatically.');
|
|
1283
|
-
|
|
1284
|
-
|
|
1362
|
+
// These reference the GitHub Action workflows, which --local-only does not write.
|
|
1363
|
+
if (!args.localOnly) {
|
|
1364
|
+
log('For a whole-repo walk: Actions tab → Clud Bug 🐛 Audit → Run workflow.');
|
|
1365
|
+
log('Self-update is on (weekly Mondays 12:00 UTC). Pin via "pinVersion" in .claude/skills/.clud-bug.json.');
|
|
1366
|
+
}
|
|
1285
1367
|
log('');
|
|
1286
|
-
|
|
1287
|
-
|
|
1368
|
+
if (args.localOnly) {
|
|
1369
|
+
log('Strict mode + branch-protection enforcement apply to the GitHub Action path; max mode is');
|
|
1370
|
+
log('advisory by design — findings surface in your session for you to act on.');
|
|
1371
|
+
}
|
|
1372
|
+
else {
|
|
1373
|
+
log('Strict mode is ON by default (clud-bug-review fails the check on critical findings).');
|
|
1374
|
+
log(' • Add `clud-bug-review` to your branch protection required checks for full enforcement.');
|
|
1375
|
+
}
|
|
1288
1376
|
log(' • Opt out by setting "strictMode": false in .claude/skills/.clud-bug.json.');
|
|
1289
1377
|
// v0.6.33 — opt-in unified install (mirror of logmind v0.6.8). When
|
|
1290
1378
|
// --with-skdd is passed, subprocess to `pip install logmind` + `logmind init`
|