mustard-claude 3.0.11 → 3.0.12

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/README.md CHANGED
@@ -26,10 +26,10 @@
26
26
 
27
27
  Mustard sets up a `.claude/` folder that turns Claude Code into a structured development pipeline:
28
28
 
29
- - **14 pipeline skills** — feature, bugfix, scan, resume, approve, complete, git, maint, task, knowledge, skill, status, scan-format, agent-prompt template
30
- - **9 enforcement hooks** — bash safety, file guard, registry validation, guard verification, auto-format, pre-compact, session cleanup, subagent tracking, RTK rewrite
29
+ - **15 pipeline skills** — feature, bugfix, scan, resume, approve, complete, git, maint, task, knowledge, skill, status, scan-format, agent-prompt template, stats
30
+ - **12 enforcement hooks** — bash safety, file guard, registry validation, guard verification, auto-format, pre-compact, session cleanup, subagent tracking, RTK rewrite, session memory, review gate, metrics tracker
31
31
  - **6 bundled skills** — design-craft, react-best-practices, senior-architect, skill-creator, commit-workflow, pipeline-execution
32
- - **3 sync scripts** — subproject detection, entity registry sync, statusline
32
+ - **8 utility scripts** — subproject detection, entity registry sync, statusline, memory persistence, diff context, knowledge base, metrics collection
33
33
  - **Token economy** — auto-installs [RTK](https://github.com/rtk-ai/rtk) to reduce token consumption by 60-90% on CLI outputs
34
34
  - **Monorepo + single repo** — works with any project structure
35
35
 
@@ -101,6 +101,8 @@ The CLI is a **one-time setup tool**. All intelligence lives in the skills and h
101
101
  | `mustard init` | Copy `.claude/` structure into current project |
102
102
  | `mustard update` | Update core files (preserves user customizations) |
103
103
  | `mustard auto-update` | Check npm for newer version and install |
104
+ | `mustard add <template>` | Install a community template |
105
+ | `mustard review --pr <N>` | Review a pull request (local or CI mode) |
104
106
  | `mustard --version` | Show installed version |
105
107
  | `mustard --help` | Show help |
106
108
 
@@ -144,6 +146,40 @@ The CLI is a **one-time setup tool**. All intelligence lives in the skills and h
144
146
  | `--check-only` | Only check for updates, do not install |
145
147
  | `-y, --yes` | Skip confirmation prompts |
146
148
 
149
+ ### `mustard add`
150
+
151
+ | Option | Description |
152
+ |--------|-------------|
153
+ | `-f, --force` | Overwrite existing files |
154
+
155
+ **Sources:**
156
+ - GitHub: `github.com/mustard-templates/{name}`
157
+ - npm: `mustard-template-{name}`
158
+
159
+ **Usage:**
160
+ ```bash
161
+ mustard add template:dotnet-clean-arch
162
+ mustard add template:nextjs-app-router
163
+ ```
164
+
165
+ ### `mustard review`
166
+
167
+ | Option | Description |
168
+ |--------|-------------|
169
+ | `--pr <number>` | PR number to review (required) |
170
+ | `--ci` | CI mode: post as PR comment, exit 1 on critical issues |
171
+
172
+ **Requirements:** `gh` (GitHub CLI) and `claude` CLI must be installed.
173
+
174
+ **Usage:**
175
+ ```bash
176
+ # Interactive review
177
+ mustard review --pr 42
178
+
179
+ # CI mode (for GitHub Actions)
180
+ mustard review --ci --pr 42
181
+ ```
182
+
147
183
  ## What Gets Installed
148
184
 
149
185
  ```
@@ -166,6 +202,7 @@ The CLI is a **one-time setup tool**. All intelligence lives in the skills and h
166
202
  │ ├── knowledge/SKILL.md # /knowledge — notes, audit, reports
167
203
  │ ├── skill/SKILL.md # /skill — manage skills
168
204
  │ ├── status/SKILL.md # /status — project status
205
+ │ ├── stats/SKILL.md # /stats — pipeline metrics
169
206
  │ └── templates/agent-prompt/SKILL.md # Agent prompt template
170
207
  ├── hooks/ # Enforcement hooks
171
208
  │ ├── rtk-rewrite.js # Rewrites Bash commands through RTK
@@ -177,11 +214,24 @@ The CLI is a **one-time setup tool**. All intelligence lives in the skills and h
177
214
  │ ├── pre-compact.js # Saves state before compaction
178
215
  │ ├── session-cleanup.js # Cleans up on session end
179
216
  │ ├── subagent-tracker.js # Tracks agent lifecycle
217
+ │ ├── session-memory.js # Injects persistent memory on session start
218
+ │ ├── review-gate.js # Pre-commit validation (fail-open)
219
+ │ ├── metrics-tracker.js # Tracks pipeline API calls and retries
180
220
  │ └── __tests__/hooks.test.js # Hook tests
181
221
  ├── scripts/
182
222
  │ ├── sync-detect.js # Detects subprojects + roles
183
223
  │ ├── sync-registry.js # Generates entity-registry.json
184
- └── statusline.js # Claude Code statusline
224
+ ├── statusline.js # Claude Code statusline
225
+ │ ├── memory-persist.js # Persists decisions/lessons across sessions
226
+ │ ├── memory-write.js # Writes agent memory entries
227
+ │ ├── diff-context.js # Generates git diff summary for agents
228
+ │ ├── knowledge-update.js # Updates project knowledge base
229
+ │ └── metrics-collect.js # Collects and displays pipeline metrics
230
+ ├── memory/ # Persistent memory (auto-created)
231
+ │ ├── decisions.json # Decisions across pipelines
232
+ │ └── lessons.json # Lessons learned
233
+ ├── knowledge.json # Evolutionary knowledge base
234
+ ├── metrics/ # Pipeline metrics archive
185
235
  └── skills/ # Bundled skills
186
236
  ├── design-craft/ # UI design methodology
187
237
  ├── react-best-practices/ # React/Next.js optimization (40+ rules)
@@ -203,6 +253,7 @@ The CLI is a **one-time setup tool**. All intelligence lives in the skills and h
203
253
  | `/approve` | Approve spec for implementation |
204
254
  | `/resume` | Resume interrupted pipeline |
205
255
  | `/complete` | Finalize or cancel pipeline |
256
+ | `/stats` | Show pipeline metrics and token savings |
206
257
 
207
258
  ### Operations
208
259
 
@@ -269,7 +320,7 @@ After `/scan`, the pipeline commands (`/feature`, `/bugfix`) have full context t
269
320
  PLAN — create spec with tasks per agent (Light: inline, Full: /approve)
270
321
 
271
322
 
272
- EXECUTE — dispatch agents per wave (DB+Backend ∥, Frontend after)
323
+ EXECUTE — dispatch agents per wave (DB+Backend ∥, Frontend after or parallel if safe)
273
324
 
274
325
 
275
326
  REVIEW — mandatory review per subproject (SOLID, patterns, i18n, ...)
@@ -301,6 +352,38 @@ Mustard integrates [RTK (Rust Token Killer)](https://github.com/rtk-ai/rtk) as c
301
352
 
302
353
  RTK only applies to Bash tool calls. Claude Code's built-in tools (Read, Grep, Glob) are already optimized and bypass the hook.
303
354
 
355
+ ## Persistent Memory
356
+
357
+ Mustard maintains lightweight persistent memory across sessions:
358
+
359
+ - **Decisions** — architectural and implementation decisions are saved to `.claude/memory/decisions.json`
360
+ - **Lessons** — what went wrong and the correction applied, saved to `.claude/memory/lessons.json`
361
+ - **Knowledge base** — patterns, conventions, and entities discovered across pipelines, saved to `.claude/knowledge.json`
362
+
363
+ Memory is automatically:
364
+ - **Injected** into each new session and every dispatched agent
365
+ - **Capped** at 50 entries (memory) / 200 entries (knowledge) — oldest pruned
366
+ - **Never cleaned** by session cleanup — persists until manually removed
367
+
368
+ This gives 80% of the benefit of a database-backed system with zero infrastructure.
369
+
370
+ ## CI Integration
371
+
372
+ Review PRs automatically in your CI pipeline:
373
+
374
+ ```bash
375
+ # In GitHub Actions
376
+ mustard review --ci --pr ${{ github.event.pull_request.number }}
377
+ ```
378
+
379
+ CI mode:
380
+ - Fetches PR diff via `gh pr diff`
381
+ - Runs Claude review with project guards and rules
382
+ - Posts review as PR comment
383
+ - Exits with code 1 if CRITICAL issues found (fails the build)
384
+
385
+ Requires `gh` and `claude` CLI in the CI environment.
386
+
304
387
  ## Supported Projects
305
388
 
306
389
  Mustard is **framework-agnostic**. The CLI just copies templates. `/scan` handles detection:
package/dist/cli.js CHANGED
@@ -3,6 +3,8 @@ import { createRequire } from 'node:module';
3
3
  import { initCommand } from './commands/init.js';
4
4
  import { updateCommand } from './commands/update.js';
5
5
  import { autoUpdateCommand } from './commands/auto-update.js';
6
+ import { addCommand } from './commands/add.js';
7
+ import { reviewCommand } from './commands/review.js';
6
8
  const require = createRequire(import.meta.url);
7
9
  const { version } = require('../package.json');
8
10
  export function run() {
@@ -28,6 +30,17 @@ export function run() {
28
30
  .option('--check-only', 'Only check for updates, do not install')
29
31
  .option('-y, --yes', 'Skip confirmation prompts')
30
32
  .action(autoUpdateCommand);
33
+ program
34
+ .command('add <template>')
35
+ .description('Install a community template (e.g., mustard add template:dotnet-clean-arch)')
36
+ .option('-f, --force', 'Overwrite existing files')
37
+ .action(addCommand);
38
+ program
39
+ .command('review')
40
+ .description('Review a pull request (local or CI mode)')
41
+ .option('--ci', 'CI mode: post review as PR comment, exit 1 on critical issues')
42
+ .option('--pr <number>', 'PR number to review')
43
+ .action(reviewCommand);
31
44
  program.parse();
32
45
  }
33
46
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,MAAM,UAAU,GAAG;IACjB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,SAAS,CAAC;SACf,WAAW,CAAC,sDAAsD,CAAC;SACnE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,aAAa,EAAE,sDAAsD,CAAC;SAC7E,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,WAAW,CAAC,CAAC;IAEvB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,2DAA2D,CAAC;SACxE,MAAM,CAAC,aAAa,EAAE,8BAA8B,CAAC;SACrD,MAAM,CAAC,aAAa,CAAC,CAAC;IAEzB,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,cAAc,EAAE,wCAAwC,CAAC;SAChE,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE7B,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,MAAM,UAAU,GAAG;IACjB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,SAAS,CAAC;SACf,WAAW,CAAC,sDAAsD,CAAC;SACnE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,aAAa,EAAE,sDAAsD,CAAC;SAC7E,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,WAAW,CAAC,CAAC;IAEvB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,2DAA2D,CAAC;SACxE,MAAM,CAAC,aAAa,EAAE,8BAA8B,CAAC;SACrD,MAAM,CAAC,aAAa,CAAC,CAAC;IAEzB,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,cAAc,EAAE,wCAAwC,CAAC;SAChE,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE7B,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,6EAA6E,CAAC;SAC1F,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CAAC,UAAU,CAAC,CAAC;IAEtB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,MAAM,EAAE,+DAA+D,CAAC;SAC/E,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;SAC9C,MAAM,CAAC,aAAa,CAAC,CAAC;IAEzB,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface AddOptions {
2
+ force?: boolean;
3
+ }
4
+ /**
5
+ * Add command - installs a community template into the current project's .claude/ directory.
6
+ * Sources: GitHub (mustard-templates/{name}) or npm (mustard-template-{name}).
7
+ */
8
+ export declare function addCommand(templateSpec: string, options: AddOptions): Promise<void>;
@@ -0,0 +1,191 @@
1
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { join, basename, relative, dirname } from 'node:path';
3
+ import { execSync } from 'node:child_process';
4
+ import { tmpdir } from 'node:os';
5
+ /**
6
+ * Add command - installs a community template into the current project's .claude/ directory.
7
+ * Sources: GitHub (mustard-templates/{name}) or npm (mustard-template-{name}).
8
+ */
9
+ export async function addCommand(templateSpec, options) {
10
+ // Parse template spec: "template:name" or just "name"
11
+ const name = templateSpec.replace(/^template:/, '');
12
+ if (!name || name.includes('..') || /[^a-zA-Z0-9_-]/.test(name)) {
13
+ console.error(`❌ Invalid template name: "${name}". Use alphanumeric, hyphens, underscores only.`);
14
+ process.exit(1);
15
+ }
16
+ const cwd = process.cwd();
17
+ const claudeDir = join(cwd, '.claude');
18
+ if (!existsSync(claudeDir)) {
19
+ console.error('❌ No .claude/ directory found. Run `mustard init` first.');
20
+ process.exit(1);
21
+ }
22
+ console.log(`📦 Installing template: ${name}`);
23
+ const tmpDir = join(tmpdir(), `mustard-template-${name}-${Date.now()}`);
24
+ try {
25
+ // Attempt 1: clone from GitHub
26
+ const repoUrl = `https://github.com/mustard-templates/${name}.git`;
27
+ console.log(`📥 Fetching from ${repoUrl}...`);
28
+ let fetchedDir = tmpDir;
29
+ try {
30
+ execSync(`git clone --depth 1 "${repoUrl}" "${tmpDir}"`, {
31
+ stdio: ['pipe', 'pipe', 'pipe'],
32
+ timeout: 30000,
33
+ });
34
+ }
35
+ catch {
36
+ // Attempt 2: npm package
37
+ console.log(` GitHub repo not found. Trying npm: mustard-template-${name}...`);
38
+ try {
39
+ mkdirSync(tmpDir, { recursive: true });
40
+ execSync(`npm pack mustard-template-${name} --pack-destination "${tmpDir}"`, {
41
+ stdio: ['pipe', 'pipe', 'pipe'],
42
+ timeout: 30000,
43
+ });
44
+ const tgz = readdirSync(tmpDir).find(f => f.endsWith('.tgz'));
45
+ if (tgz) {
46
+ execSync(`tar -xzf "${join(tmpDir, tgz)}" -C "${tmpDir}"`, {
47
+ stdio: ['pipe', 'pipe', 'pipe'],
48
+ });
49
+ // npm pack extracts to a "package" subdirectory
50
+ const packageDir = join(tmpDir, 'package');
51
+ if (existsSync(packageDir)) {
52
+ fetchedDir = packageDir;
53
+ }
54
+ }
55
+ }
56
+ catch {
57
+ console.error(`❌ Template "${name}" not found on GitHub or npm.`);
58
+ console.log('\nAvailable sources:');
59
+ console.log(` GitHub: github.com/mustard-templates/${name}`);
60
+ console.log(` npm: mustard-template-${name}`);
61
+ process.exit(1);
62
+ }
63
+ }
64
+ // Read manifest
65
+ const manifestPath = join(fetchedDir, 'mustard-template.json');
66
+ let manifest;
67
+ if (existsSync(manifestPath)) {
68
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
69
+ }
70
+ else {
71
+ // Auto-detect known .claude/ subdirectories
72
+ manifest = {
73
+ name,
74
+ version: '0.0.0',
75
+ files: detectFiles(fetchedDir),
76
+ };
77
+ }
78
+ console.log(`📋 Template: ${manifest.name} v${manifest.version}`);
79
+ if (manifest.description)
80
+ console.log(` ${manifest.description}`);
81
+ // Copy files
82
+ let copied = 0;
83
+ let skipped = 0;
84
+ for (const filePattern of manifest.files) {
85
+ const src = join(fetchedDir, filePattern);
86
+ if (!existsSync(src))
87
+ continue;
88
+ const destBase = join(claudeDir, filePattern);
89
+ if (statSync(src).isDirectory()) {
90
+ const files = walkDir(src);
91
+ for (const file of files) {
92
+ const rel = relative(src, file);
93
+ const dest = join(destBase, rel);
94
+ if (existsSync(dest) && !options.force) {
95
+ console.log(` Skipping existing: ${join(filePattern, rel)}`);
96
+ skipped++;
97
+ continue;
98
+ }
99
+ mkdirSync(dirname(dest), { recursive: true });
100
+ writeFileSync(dest, readFileSync(file));
101
+ console.log(` Copied: ${join(filePattern, rel)}`);
102
+ copied++;
103
+ }
104
+ }
105
+ else {
106
+ if (existsSync(destBase) && !options.force) {
107
+ console.log(` Skipping existing: ${filePattern}`);
108
+ skipped++;
109
+ continue;
110
+ }
111
+ mkdirSync(dirname(destBase), { recursive: true });
112
+ writeFileSync(destBase, readFileSync(src));
113
+ console.log(` Copied: ${filePattern}`);
114
+ copied++;
115
+ }
116
+ }
117
+ // Merge hook additions into settings.json
118
+ if (manifest.hooks_additions && manifest.hooks_additions.length > 0) {
119
+ const settingsPath = join(claudeDir, 'settings.json');
120
+ if (existsSync(settingsPath)) {
121
+ try {
122
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
123
+ const hooks = (settings.hooks ?? {});
124
+ settings.hooks = hooks;
125
+ for (const hook of manifest.hooks_additions) {
126
+ const event = hook.event;
127
+ if (!hooks[event])
128
+ hooks[event] = [];
129
+ // Skip if hook command already registered
130
+ const alreadyExists = hooks[event].some(h => h.hooks?.some(hh => hh.command === hook.command));
131
+ if (!alreadyExists) {
132
+ hooks[event].push({
133
+ matcher: hook.matcher,
134
+ hooks: [
135
+ {
136
+ type: 'command',
137
+ command: hook.command,
138
+ timeout: hook.timeout ?? 5,
139
+ },
140
+ ],
141
+ });
142
+ console.log(` Registered hook: ${event} -> ${basename(hook.command)}`);
143
+ }
144
+ }
145
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
146
+ }
147
+ catch (err) {
148
+ process.stderr.write(` Could not merge hooks into settings.json: ${err.message}\n`);
149
+ }
150
+ }
151
+ }
152
+ console.log(`\nTemplate installed: ${copied} file(s) copied, ${skipped} skipped.`);
153
+ if (skipped > 0)
154
+ console.log('Use --force to overwrite existing files.');
155
+ }
156
+ finally {
157
+ // Cleanup tmp directory
158
+ try {
159
+ execSync(`rm -rf "${tmpDir}"`, { stdio: ['pipe', 'pipe', 'pipe'] });
160
+ }
161
+ catch {
162
+ try {
163
+ execSync(`rmdir /s /q "${tmpDir}"`, { stdio: ['pipe', 'pipe', 'pipe'] });
164
+ }
165
+ catch {
166
+ // Best-effort cleanup — ignore failure
167
+ }
168
+ }
169
+ }
170
+ }
171
+ function detectFiles(dir) {
172
+ const knownSubdirs = ['commands', 'skills', 'hooks', 'context', 'scripts'];
173
+ return knownSubdirs.filter(p => existsSync(join(dir, p)));
174
+ }
175
+ function walkDir(dir) {
176
+ const results = [];
177
+ const entries = readdirSync(dir, { withFileTypes: true });
178
+ for (const entry of entries) {
179
+ const full = join(dir, entry.name);
180
+ if (entry.isDirectory()) {
181
+ if (entry.name === '.git' || entry.name === 'node_modules')
182
+ continue;
183
+ results.push(...walkDir(full));
184
+ }
185
+ else {
186
+ results.push(full);
187
+ }
188
+ }
189
+ return results;
190
+ }
191
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface ReviewOptions {
2
+ ci?: boolean;
3
+ pr?: string;
4
+ }
5
+ export declare function reviewCommand(options: ReviewOptions): Promise<void>;
6
+ export {};
@@ -0,0 +1,143 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ export async function reviewCommand(options) {
5
+ const prNumber = options.pr;
6
+ if (!prNumber) {
7
+ console.error('Error: PR number required. Usage: mustard review --pr <number>');
8
+ process.exit(1);
9
+ }
10
+ // Verify gh CLI is available
11
+ try {
12
+ execSync('gh --version', { stdio: 'ignore' });
13
+ }
14
+ catch {
15
+ console.error('Error: GitHub CLI (gh) is required. Install from https://cli.github.com/');
16
+ process.exit(1);
17
+ }
18
+ // Verify claude CLI is available
19
+ try {
20
+ execSync('claude --version', { stdio: 'ignore' });
21
+ }
22
+ catch {
23
+ console.error('Error: Claude CLI is required. Install from https://docs.anthropic.com/');
24
+ process.exit(1);
25
+ }
26
+ console.log(`Reviewing PR #${prNumber}${options.ci ? ' (CI mode)' : ''}...`);
27
+ try {
28
+ // Fetch PR info
29
+ const prInfo = execSync(`gh pr view ${prNumber} --json title,body,additions,deletions,changedFiles,baseRefName,headRefName`, {
30
+ encoding: 'utf8',
31
+ timeout: 15000,
32
+ stdio: ['pipe', 'pipe', 'pipe'],
33
+ windowsHide: true,
34
+ });
35
+ const pr = JSON.parse(prInfo);
36
+ // Fetch PR diff
37
+ const diff = execSync(`gh pr diff ${prNumber}`, {
38
+ encoding: 'utf8',
39
+ timeout: 30000,
40
+ stdio: ['pipe', 'pipe', 'pipe'],
41
+ windowsHide: true,
42
+ });
43
+ // Truncate diff if too large (max ~50k chars for Claude context)
44
+ const maxDiffChars = 50000;
45
+ let truncatedDiff = diff;
46
+ if (diff.length > maxDiffChars) {
47
+ truncatedDiff = diff.slice(0, maxDiffChars) + '\n\n... (diff truncated, showing first 50k chars)';
48
+ }
49
+ // Load guards if available
50
+ let guards = '';
51
+ const cwd = process.cwd();
52
+ const guardsPath = join(cwd, '.claude', 'commands', 'guards.md');
53
+ if (existsSync(guardsPath)) {
54
+ try {
55
+ guards = readFileSync(guardsPath, 'utf8').slice(0, 3000);
56
+ }
57
+ catch { /* non-critical — proceed without guards */ }
58
+ }
59
+ // Load CLAUDE.md for project rules
60
+ let projectRules = '';
61
+ const claudeMdPath = join(cwd, 'CLAUDE.md');
62
+ if (existsSync(claudeMdPath)) {
63
+ try {
64
+ projectRules = readFileSync(claudeMdPath, 'utf8').slice(0, 2000);
65
+ }
66
+ catch { /* non-critical — proceed without project rules */ }
67
+ }
68
+ // Build review prompt
69
+ const prompt = buildReviewPrompt(pr, truncatedDiff, guards, projectRules);
70
+ // Run Claude for review (both modes use --print for non-interactive output)
71
+ const reviewResult = execSync(`claude --print "${escapeForShell(prompt)}"`, {
72
+ encoding: 'utf8',
73
+ timeout: 120000,
74
+ maxBuffer: 10 * 1024 * 1024,
75
+ stdio: ['pipe', 'pipe', 'pipe'],
76
+ windowsHide: true,
77
+ });
78
+ console.log('\nReview Result:\n');
79
+ console.log(reviewResult);
80
+ // In CI mode, post review as PR comment
81
+ if (options.ci && reviewResult.trim()) {
82
+ try {
83
+ const commentBody = `## Automated Review (Mustard)\n\n${reviewResult}`;
84
+ execSync(`gh pr comment ${prNumber} --body "${escapeForShell(commentBody)}"`, {
85
+ stdio: ['pipe', 'pipe', 'pipe'],
86
+ timeout: 15000,
87
+ windowsHide: true,
88
+ });
89
+ console.log(`\nReview posted as comment on PR #${prNumber}`);
90
+ }
91
+ catch (err) {
92
+ process.stderr.write(`Warning: Could not post review comment: ${err.message}\n`);
93
+ }
94
+ // Exit with code based on review severity
95
+ if (/\bCRITICAL\b/i.test(reviewResult)) {
96
+ console.log('Critical issues found.');
97
+ process.exit(1);
98
+ }
99
+ }
100
+ console.log('Review complete.');
101
+ }
102
+ catch (err) {
103
+ console.error(`Error: Review failed: ${err.message}`);
104
+ process.exit(1);
105
+ }
106
+ }
107
+ function buildReviewPrompt(pr, diff, guards, projectRules) {
108
+ const additions = pr.additions;
109
+ const deletions = pr.deletions;
110
+ const changedFiles = pr.changedFiles;
111
+ const title = pr.title;
112
+ const body = pr.body;
113
+ const baseRefName = pr.baseRefName;
114
+ const headRefName = pr.headRefName;
115
+ const parts = [
116
+ 'Review this pull request for code quality, security, and correctness.',
117
+ '',
118
+ `## PR: ${title}`,
119
+ `Base: ${baseRefName} <- Head: ${headRefName}`,
120
+ `Changes: +${additions} -${deletions} (${changedFiles} files)`,
121
+ '',
122
+ ];
123
+ if (body) {
124
+ parts.push('## Description', body, '');
125
+ }
126
+ if (projectRules) {
127
+ parts.push('## Project Rules', projectRules, '');
128
+ }
129
+ if (guards) {
130
+ parts.push("## Guards (DO/DON'T rules)", guards, '');
131
+ }
132
+ parts.push('## Review Checklist', '- [ ] No security vulnerabilities (injection, XSS, secrets)', '- [ ] Code follows project conventions', '- [ ] No unnecessary complexity', '- [ ] Error handling is appropriate', '- [ ] No breaking changes without migration', '', '## Diff', '```diff', diff, '```', '', 'Provide a structured review with:', '1. **Summary**: What this PR does (1-2 sentences)', '2. **Issues**: List of issues found (CRITICAL / WARNING / INFO)', '3. **Suggestions**: Improvements (optional)', '4. **Verdict**: APPROVE / REQUEST_CHANGES / COMMENT');
133
+ return parts.join('\n');
134
+ }
135
+ function escapeForShell(str) {
136
+ // Escape for double-quoted shell string
137
+ return str
138
+ .replace(/\\/g, '\\\\')
139
+ .replace(/"/g, '\\"')
140
+ .replace(/\$/g, '\\$')
141
+ .replace(/`/g, '\\`');
142
+ }
143
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mustard-claude",
3
- "version": "3.0.11",
3
+ "version": "3.0.12",
4
4
  "description": "Framework-agnostic CLI for Claude Code project setup",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,10 @@ Autonomous pipeline to diagnose and fix bugs. Zero context-switch — never ask
15
15
  ### ANALYZE (diagnose + assess)
16
16
 
17
17
  1. **AUTO-SYNC:** `node .claude/scripts/sync-registry.js`
18
+
19
+ ### Diff Context (automatic)
20
+ Run `node .claude/scripts/diff-context.js` to capture the current git state. Include the output in the agent prompt as `{diff_context}` so agents know what has already changed.
21
+
18
22
  2. **DIAGNOSE:** Dispatch Explore agent:
19
23
  - Scoped Grep searches with specific path + pattern for the error/symptom
20
24
  - Trace callers/callees via Grep in relevant directories
@@ -33,10 +33,35 @@ If ANY gate fails: do NOT mark complete → report what failed + suggest fix. If
33
33
  6. **Pipeline State — cleanup:**
34
34
  - Extract `spec-name` from the spec directory (e.g. `2026-02-26-linked-services-card`)
35
35
  - **Delete** `.claude/.pipeline-states/{spec-name}.json` (removes from statusline)
36
- 6b. **Token Economy — RTK report (if available):**
36
+ 6b. **Knowledge Capture:**
37
+ - Review patterns discovered during this pipeline
38
+ - For each significant pattern/convention/entity discovered:
39
+ ```bash
40
+ echo '{"type":"pattern","name":"...","description":"...","source":"{spec-name}"}' | node .claude/scripts/knowledge-update.js
41
+ ```
42
+ - Focus on: naming conventions used, architectural decisions, integration patterns
43
+ - Skip trivial or already-known patterns
44
+
45
+ 6c. **Token Economy — RTK report (if available):**
37
46
  - Run `rtk gain --all --format json` via Bash
38
47
  - If RTK available: extract `saved_tokens` and `savings_pct`
39
48
  - Include in output block below
49
+ 6d. **Metrics Archive:**
50
+ - Read metrics from `.claude/.pipeline-states/{spec-name}.json`
51
+ - If metrics exist, ensure `.claude/metrics/` directory exists
52
+ - Save to `.claude/metrics/{spec-name}.json`:
53
+ ```json
54
+ {
55
+ "name": "{spec-name}",
56
+ "completedAt": "{ISO timestamp}",
57
+ "durationMs": "{calculated from startedAt to now}",
58
+ "apiCalls": "{from metrics}",
59
+ "retries": "{from metrics}",
60
+ "toolBreakdown": "{from metrics}",
61
+ "rtkSavings": { "saved": N, "pct": N }
62
+ }
63
+ ```
64
+ - If no metrics in state file, skip silently
40
65
  7. **Output — visual feedback:**
41
66
 
42
67
  ```
@@ -15,6 +15,10 @@ Starts the pipeline to implement a feature or enhancement. Self-contained: ANALY
15
15
  ### ANALYZE Phase
16
16
 
17
17
  **Auto-sync (silent):** `node .claude/scripts/sync-registry.js`
18
+
19
+ ### Diff Context (automatic)
20
+ Run `node .claude/scripts/diff-context.js` to capture the current git state. Include the output in the agent prompt as `{diff_context}` so agents know what has already changed.
21
+
18
22
  1. Read `pipeline-config.md` — agents, wave transitions, model selection
19
23
  2. Read `entity-registry.json` via Grep for the specific entity name (e.g. `"Contract":`) — NEVER read the full JSON. Entity found? infer layers. Not found? all layers.
20
24
  3. Determine layers from signals:
@@ -65,6 +69,9 @@ Record scope for PLAN phase branching.
65
69
  - Summary, Entity Info, Files, Tasks, Dependencies
66
70
  - Tasks organized by `### {Agent} Agent (Wave {N})`
67
71
  - 3-8 checkboxed steps per agent, decomposed by operation type (NOT by file)
72
+ - If a frontend task has NO dependency on new backend endpoints or types, mark it as `(parallel-safe)` in the spec header:
73
+ `### Frontend Agent (Wave 1, parallel-safe)`
74
+ This allows the orchestrator to dispatch it alongside backend in Wave 1.
68
75
  2. Add checkpoint fields: `Status: draft`, `Phase: PLAN`, `Scope: full`, `Checkpoint: {now}`
69
76
  3. Create `.claude/.pipeline-states/{spec-name}.json`: `specName`, `status: "active"`, `phase: 2`, `phaseName: "PLAN"`, `scope: "full"`
70
77
  4. Elegance Check: 3+ files or complex logic → "Is there a more elegant approach?"
@@ -103,7 +110,7 @@ When user chooses "Approve and implement now":
103
110
  3. Read `pipeline-config.md` for agent config. For `entity-registry.json`: Grep for specific entity block only
104
111
  4. Match recipes by title via Grep on `{subproject}/.claude/commands/recipes.md` — do NOT read full file. Extract recipe number + pattern refs
105
112
  5. Identify relevant skills for `{recommended_skills}`: list skill names most relevant to the task (e.g., `api-endpoint-wiring, api-dto-validation`). Agents use these as hints — Claude natively decides which to load based on descriptions
106
- 6. Dispatch agents (wave rules: DB+Backend parallel, Frontend after Backend). Agent prompt includes `{recommended_skills}` as skill hints — agents read SKILL.md of relevant skills before implementing
113
+ 6. Dispatch agents (wave rules: DB+Backend parallel, Frontend after Backend UNLESS spec marks task as `(parallel-safe)` — see `pipeline-config.md` Parallel Rules). Agent prompt includes `{recommended_skills}` as skill hints — agents read SKILL.md of relevant skills before implementing
107
114
  7. Wave transitions between waves (from `pipeline-config.md`)
108
115
  8. On return: validate (build/type-check), update spec `[ ]` → `[x]` (line-by-line edits, NEVER copy entire spec blocks as old_string)
109
116
  8b. **Agent Memory:** After agents return and spec is updated, write agent memory: `echo '{"agent_type":"{type}","wave":{N},"pipeline":"{spec-name}","summary":"{what agent did}","details":{...}}' | node .claude/scripts/memory-write.js` — one per agent. Skip if single-wave pipeline (no downstream agents to benefit).