@uniswap/ai-toolkit-nx-claude 0.5.29 → 0.5.30-next.1

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 (87) hide show
  1. package/dist/cli-generator.cjs +28 -59
  2. package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts +8 -10
  3. package/dist/packages/ai-toolkit-nx-claude/src/cli-generator.d.ts.map +1 -1
  4. package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts +0 -1
  5. package/dist/packages/ai-toolkit-nx-claude/src/index.d.ts.map +1 -1
  6. package/generators.json +0 -15
  7. package/package.json +4 -35
  8. package/dist/content/agents/agnostic/CLAUDE.md +0 -282
  9. package/dist/content/agents/agnostic/agent-capability-analyst.md +0 -575
  10. package/dist/content/agents/agnostic/agent-optimizer.md +0 -396
  11. package/dist/content/agents/agnostic/agent-orchestrator.md +0 -475
  12. package/dist/content/agents/agnostic/cicd-agent.md +0 -301
  13. package/dist/content/agents/agnostic/claude-agent-discovery.md +0 -304
  14. package/dist/content/agents/agnostic/claude-docs-fact-checker.md +0 -435
  15. package/dist/content/agents/agnostic/claude-docs-initializer.md +0 -782
  16. package/dist/content/agents/agnostic/claude-docs-manager.md +0 -595
  17. package/dist/content/agents/agnostic/code-explainer.md +0 -269
  18. package/dist/content/agents/agnostic/code-generator.md +0 -785
  19. package/dist/content/agents/agnostic/commit-message-generator.md +0 -101
  20. package/dist/content/agents/agnostic/context-loader.md +0 -432
  21. package/dist/content/agents/agnostic/debug-assistant.md +0 -321
  22. package/dist/content/agents/agnostic/doc-writer.md +0 -536
  23. package/dist/content/agents/agnostic/feedback-collector.md +0 -165
  24. package/dist/content/agents/agnostic/infrastructure-agent.md +0 -406
  25. package/dist/content/agents/agnostic/migration-assistant.md +0 -489
  26. package/dist/content/agents/agnostic/pattern-learner.md +0 -481
  27. package/dist/content/agents/agnostic/performance-analyzer.md +0 -528
  28. package/dist/content/agents/agnostic/plan-reviewer.md +0 -173
  29. package/dist/content/agents/agnostic/planner.md +0 -235
  30. package/dist/content/agents/agnostic/pr-creator.md +0 -498
  31. package/dist/content/agents/agnostic/pr-reviewer.md +0 -142
  32. package/dist/content/agents/agnostic/prompt-engineer.md +0 -541
  33. package/dist/content/agents/agnostic/refactorer.md +0 -311
  34. package/dist/content/agents/agnostic/researcher.md +0 -349
  35. package/dist/content/agents/agnostic/security-analyzer.md +0 -1087
  36. package/dist/content/agents/agnostic/stack-splitter.md +0 -642
  37. package/dist/content/agents/agnostic/style-enforcer.md +0 -568
  38. package/dist/content/agents/agnostic/test-runner.md +0 -481
  39. package/dist/content/agents/agnostic/test-writer.md +0 -292
  40. package/dist/content/commands/agnostic/CLAUDE.md +0 -207
  41. package/dist/content/commands/agnostic/address-pr-issues.md +0 -205
  42. package/dist/content/commands/agnostic/auto-spec.md +0 -386
  43. package/dist/content/commands/agnostic/claude-docs.md +0 -409
  44. package/dist/content/commands/agnostic/claude-init-plus.md +0 -439
  45. package/dist/content/commands/agnostic/create-pr.md +0 -79
  46. package/dist/content/commands/agnostic/daily-standup.md +0 -185
  47. package/dist/content/commands/agnostic/deploy.md +0 -441
  48. package/dist/content/commands/agnostic/execute-plan.md +0 -167
  49. package/dist/content/commands/agnostic/explain-file.md +0 -303
  50. package/dist/content/commands/agnostic/explore.md +0 -82
  51. package/dist/content/commands/agnostic/fix-bug.md +0 -273
  52. package/dist/content/commands/agnostic/gen-tests.md +0 -185
  53. package/dist/content/commands/agnostic/generate-commit-message.md +0 -92
  54. package/dist/content/commands/agnostic/git-worktree-orchestrator.md +0 -647
  55. package/dist/content/commands/agnostic/implement-spec.md +0 -270
  56. package/dist/content/commands/agnostic/monitor.md +0 -581
  57. package/dist/content/commands/agnostic/perf-analyze.md +0 -214
  58. package/dist/content/commands/agnostic/plan.md +0 -453
  59. package/dist/content/commands/agnostic/refactor.md +0 -315
  60. package/dist/content/commands/agnostic/refine-linear-task.md +0 -575
  61. package/dist/content/commands/agnostic/research.md +0 -49
  62. package/dist/content/commands/agnostic/review-code.md +0 -321
  63. package/dist/content/commands/agnostic/review-plan.md +0 -109
  64. package/dist/content/commands/agnostic/review-pr.md +0 -393
  65. package/dist/content/commands/agnostic/split-stack.md +0 -705
  66. package/dist/content/commands/agnostic/update-claude-md.md +0 -401
  67. package/dist/content/commands/agnostic/work-through-pr-comments.md +0 -873
  68. package/dist/generators/add-agent/CLAUDE.md +0 -130
  69. package/dist/generators/add-agent/files/__name__.md.template +0 -37
  70. package/dist/generators/add-agent/generator.cjs +0 -640
  71. package/dist/generators/add-agent/schema.json +0 -59
  72. package/dist/generators/add-command/CLAUDE.md +0 -131
  73. package/dist/generators/add-command/files/__name__.md.template +0 -46
  74. package/dist/generators/add-command/generator.cjs +0 -643
  75. package/dist/generators/add-command/schema.json +0 -50
  76. package/dist/generators/files/src/index.ts.template +0 -1
  77. package/dist/generators/init/CLAUDE.md +0 -520
  78. package/dist/generators/init/generator.cjs +0 -3304
  79. package/dist/generators/init/schema.json +0 -180
  80. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-agent/generator.d.ts +0 -5
  81. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-agent/generator.d.ts.map +0 -1
  82. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-command/generator.d.ts +0 -5
  83. package/dist/packages/ai-toolkit-nx-claude/src/generators/add-command/generator.d.ts.map +0 -1
  84. package/dist/packages/ai-toolkit-nx-claude/src/generators/init/generator.d.ts +0 -5
  85. package/dist/packages/ai-toolkit-nx-claude/src/generators/init/generator.d.ts.map +0 -1
  86. package/dist/packages/ai-toolkit-nx-claude/src/utils/auto-update-utils.d.ts +0 -30
  87. package/dist/packages/ai-toolkit-nx-claude/src/utils/auto-update-utils.d.ts.map +0 -1
@@ -1,873 +0,0 @@
1
- ---
2
- name: work-through-pr-comments
3
- description: Methodically work through GitHub pull request comments in a conversational workflow, analyzing each comment, presenting solution options, gathering your decisions, and implementing approved changes.
4
- argument-hint: <pr-number> OR <owner/repo> <pr-number>
5
- allowed-tools: Bash(*), Read(*), Write(*), Edit(*), Grep(*), Glob(*), AskUserQuestion(*), mcp__github__get_pull_request(*), mcp__github__get_pull_request_comments(*), mcp__github__get_pull_request_reviews(*)
6
- ---
7
-
8
- # Work Through PR Comments
9
-
10
- Methodically work through GitHub pull request comments in a conversational workflow, analyzing each comment, presenting solution options, gathering your decisions, and implementing approved changes.
11
-
12
- ## Usage
13
-
14
- ```bash
15
- /work-through-pr-comments <pr-number> # Work through comments on PR in current repo
16
- /work-through-pr-comments <owner/repo> <pr-number> # Work through comments on PR in specific repo
17
- ```
18
-
19
- ## Examples
20
-
21
- ```bash
22
- /work-through-pr-comments 154 # Work through comments on PR #154 in current repo
23
- /work-through-pr-comments Uniswap/ai-toolkit 154 # Work through comments on PR #154 in Uniswap/ai-toolkit
24
- ```
25
-
26
- ## Workflow Overview
27
-
28
- This command implements a **conversational, methodical workflow** for addressing PR comments:
29
-
30
- 1. **Fetch PR Details**: Get PR information, reviews, and inline comments
31
- 2. **Analyze Each Comment**: For each comment, provide context and analysis
32
- 3. **Present Options**: Suggest multiple solution approaches with pros/cons
33
- 4. **Gather Decisions**: Ask you which approach to take
34
- 5. **Implement Changes**: Make the approved changes
35
- 6. **Verify**: Test and validate the changes
36
- 7. **Repeat**: Move to next comment until all are addressed
37
- 8. **Commit**: Offer to create a single commit with all changes
38
-
39
- ## Input Parameters
40
-
41
- ### Required
42
-
43
- - **pr-number**: The pull request number (e.g., `154`)
44
-
45
- ### Optional
46
-
47
- - **owner/repo**: Repository in format `owner/repo` (defaults to current repo detected from git remote)
48
-
49
- ## Step-by-Step Implementation
50
-
51
- ### Step 1: Parse Input and Detect Repository
52
-
53
- ```typescript
54
- // Parse command arguments
55
- const args = userInput.trim().split(/\s+/);
56
-
57
- let owner: string;
58
- let repo: string;
59
- let prNumber: number;
60
-
61
- if (args.length === 1) {
62
- // Format: /work-through-pr-comments 154
63
- // Detect from current git remote
64
- const remoteUrl = await Bash('git config --get remote.origin.url');
65
- // Parse owner/repo from: git@github.com:Uniswap/ai-toolkit.git or https://github.com/Uniswap/ai-toolkit.git
66
- const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
67
- if (!match) {
68
- throw new Error(
69
- 'Could not detect repository from git remote. Use: /work-through-pr-comments <owner/repo> <pr-number>'
70
- );
71
- }
72
- [, owner, repo] = match;
73
- prNumber = parseInt(args[0]);
74
- } else if (args.length === 2) {
75
- // Format: /work-through-pr-comments Uniswap/ai-toolkit 154
76
- [owner, repo] = args[0].split('/');
77
- prNumber = parseInt(args[1]);
78
- } else {
79
- throw new Error(
80
- 'Usage: /work-through-pr-comments <pr-number> OR /work-through-pr-comments <owner/repo> <pr-number>'
81
- );
82
- }
83
-
84
- // Validate PR number
85
- if (isNaN(prNumber) || prNumber <= 0) {
86
- throw new Error(`Invalid PR number: ${args[args.length - 1]}`);
87
- }
88
-
89
- console.log(`📋 Analyzing PR #${prNumber} in ${owner}/${repo}...`);
90
- ```
91
-
92
- ### Step 2: Fetch PR Data
93
-
94
- Fetch all PR-related data in parallel for efficiency:
95
-
96
- ```typescript
97
- // Fetch PR details, comments, and reviews in parallel
98
- const [prDetails, prComments, prReviews] = await Promise.all([
99
- mcp__github__get_pull_request({ owner, repo, pull_number: prNumber }),
100
- mcp__github__get_pull_request_comments({ owner, repo, pull_number: prNumber }),
101
- mcp__github__get_pull_request_reviews({ owner, repo, pull_number: prNumber }),
102
- ]);
103
-
104
- console.log(`\n**PR Title**: ${prDetails.title}`);
105
- console.log(`**Author**: ${prDetails.user.login}`);
106
- console.log(`**State**: ${prDetails.state}`);
107
- console.log(`**URL**: ${prDetails.html_url}\n`);
108
- ```
109
-
110
- ### Step 3: Organize and Categorize Comments
111
-
112
- Organize comments into categories for clear presentation:
113
-
114
- ```typescript
115
- interface Comment {
116
- id: string;
117
- type: 'inline' | 'review';
118
- author: string;
119
- body: string;
120
- path?: string;
121
- line?: number;
122
- position?: number;
123
- created_at: string;
124
- html_url: string;
125
- }
126
-
127
- // Collect all comments
128
- const allComments: Comment[] = [];
129
-
130
- // Add inline comments (code review comments)
131
- prComments.forEach((comment) => {
132
- allComments.push({
133
- id: `comment-${comment.id}`,
134
- type: 'inline',
135
- author: comment.user.login,
136
- body: comment.body,
137
- path: comment.path,
138
- line: comment.line,
139
- position: comment.position,
140
- created_at: comment.created_at,
141
- html_url: comment.html_url,
142
- });
143
- });
144
-
145
- // Add review comments (from review body)
146
- prReviews.forEach((review) => {
147
- if (review.body && review.body.trim()) {
148
- allComments.push({
149
- id: `review-${review.id}`,
150
- type: 'review',
151
- author: review.user.login,
152
- body: review.body,
153
- created_at: review.submitted_at,
154
- html_url: review.html_url,
155
- });
156
- }
157
- });
158
-
159
- // Sort by creation date (oldest first)
160
- allComments.sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
161
-
162
- console.log(`Found ${allComments.length} comment(s) to address`);
163
-
164
- if (allComments.length === 0) {
165
- console.log('✅ No comments to address!');
166
- return;
167
- }
168
- ```
169
-
170
- ### Step 4: Process Each Comment Conversationally
171
-
172
- For each comment, follow the conversational workflow:
173
-
174
- ````typescript
175
- // Track decisions and changes
176
- const decisions = [];
177
- const filesToChange = new Set<string>();
178
-
179
- for (let i = 0; i < allComments.length; i++) {
180
- const comment = allComments[i];
181
- const commentNum = i + 1;
182
-
183
- console.log(`\n${'='.repeat(80)}`);
184
- console.log(`📝 Comment ${commentNum}/${allComments.length}`);
185
- console.log(`${'='.repeat(80)}\n`);
186
-
187
- // Display comment context
188
- console.log(`**Author**: ${comment.author}`);
189
- console.log(
190
- `**Type**: ${comment.type === 'inline' ? 'Inline code comment' : 'General review comment'}`
191
- );
192
- if (comment.path) {
193
- console.log(`**Location**: \`${comment.path}:${comment.line || comment.position}\``);
194
- }
195
- console.log(`**Comment**:\n> ${comment.body}\n`);
196
-
197
- // Read affected file if inline comment
198
- let fileContext = null;
199
- if (comment.type === 'inline' && comment.path) {
200
- try {
201
- const fullPath = `${process.cwd()}/${comment.path}`;
202
- fileContext = await Read(fullPath);
203
-
204
- // Show relevant section around the comment line
205
- const lines = fileContext.split('\n');
206
- const targetLine = comment.line || comment.position || 0;
207
- const startLine = Math.max(0, targetLine - 5);
208
- const endLine = Math.min(lines.length, targetLine + 5);
209
-
210
- console.log(`**Current Code Context** (\`${comment.path}\`):\n`);
211
- console.log('```');
212
- for (let i = startLine; i < endLine; i++) {
213
- const lineNum = i + 1;
214
- const prefix = lineNum === targetLine ? '→ ' : ' ';
215
- console.log(`${prefix}${String(lineNum).padStart(4)} ${lines[i]}`);
216
- }
217
- console.log('```\n');
218
-
219
- filesToChange.add(fullPath);
220
- } catch (error) {
221
- console.log(`⚠️ Could not read file: ${comment.path}\n`);
222
- }
223
- }
224
-
225
- // AI Analysis: Understand the comment and suggest solutions
226
- console.log('## 🤔 My Analysis\n');
227
-
228
- // This is where Claude should analyze the comment based on its content
229
- // The actual analysis will be done by Claude in real-time
230
- // Key things to analyze:
231
- // - What is the reviewer asking for?
232
- // - Why are they asking for it?
233
- // - What are the implications?
234
- // - What are possible approaches?
235
-
236
- console.log('## 💡 Suggested Solutions\n');
237
-
238
- // Present options (Claude should generate these based on the comment)
239
- // Example structure:
240
- console.log('**Option A**: [First approach]');
241
- console.log('- ✅ Pros: ...');
242
- console.log('- ❌ Cons: ...\n');
243
-
244
- console.log('**Option B**: [Second approach]');
245
- console.log('- ✅ Pros: ...');
246
- console.log('- ❌ Cons: ...\n');
247
-
248
- console.log('**💭 My Recommendation**: [Preferred option and reasoning]\n');
249
-
250
- // Ask user for decision using AskUserQuestion
251
- const userChoice = await AskUserQuestion({
252
- questions: [
253
- {
254
- question: `How would you like to address this comment from ${comment.author}?`,
255
- header: 'Approach',
256
- multiSelect: false,
257
- options: [
258
- {
259
- label: 'Option A',
260
- description: 'Implement the first suggested approach',
261
- },
262
- {
263
- label: 'Option B',
264
- description: 'Implement the second suggested approach',
265
- },
266
- {
267
- label: 'Custom',
268
- description: "I'll tell you what I want to do",
269
- },
270
- {
271
- label: 'Skip',
272
- description: 'Skip this comment for now',
273
- },
274
- ],
275
- },
276
- ],
277
- });
278
-
279
- const selectedOption = userChoice.answers['Approach'];
280
-
281
- if (selectedOption === 'Skip') {
282
- console.log('⏭️ Skipping this comment\n');
283
- decisions.push({
284
- comment: commentNum,
285
- author: comment.author,
286
- decision: 'skipped',
287
- reason: 'User chose to skip',
288
- });
289
- continue;
290
- }
291
-
292
- if (selectedOption === 'Custom') {
293
- console.log(
294
- "📝 Please describe what you'd like me to do for this comment, and I'll implement it.\n"
295
- );
296
- // Wait for user to provide instructions
297
- // Then implement based on their guidance
298
- continue;
299
- }
300
-
301
- // Implement the chosen solution
302
- console.log(`\n## 🔧 Implementing: ${selectedOption}\n`);
303
-
304
- // Make the necessary changes based on the chosen option
305
- // This will vary depending on the comment, but generally:
306
- // 1. Use Read tool to get current file content (if not already read)
307
- // 2. Use Edit tool to make changes
308
- // 3. Verify changes
309
- // 4. Track changed files
310
-
311
- decisions.push({
312
- comment: commentNum,
313
- author: comment.author,
314
- decision: selectedOption,
315
- files_changed: Array.from(filesToChange),
316
- });
317
-
318
- console.log('✅ Changes implemented\n');
319
- }
320
- ````
321
-
322
- ### Step 5: Summary and Commit
323
-
324
- After processing all comments, provide a summary and offer to commit:
325
-
326
- ````typescript
327
- console.log(`\n${'='.repeat(80)}`);
328
- console.log('📊 Summary of Changes');
329
- console.log(`${'='.repeat(80)}\n`);
330
-
331
- const addressedCount = decisions.filter((d) => d.decision !== 'skipped').length;
332
- const skippedCount = decisions.filter((d) => d.decision === 'skipped').length;
333
-
334
- console.log(`Total comments processed: ${allComments.length}`);
335
- console.log(`Comments addressed: ${addressedCount}`);
336
- console.log(`Comments skipped: ${skippedCount}`);
337
- console.log(`Files modified: ${filesToChange.size}\n`);
338
-
339
- // List all changed files
340
- if (filesToChange.size > 0) {
341
- console.log('**Files changed:**');
342
- filesToChange.forEach((file) => {
343
- console.log(` - ${file}`);
344
- });
345
- console.log('');
346
- }
347
-
348
- // Run formatting and linting
349
- console.log('🔍 Running code quality checks...\n');
350
-
351
- try {
352
- // Format code
353
- await Bash('npx nx format:write --uncommitted');
354
- console.log('✅ Code formatting complete');
355
-
356
- // Lint markdown if any .md files changed
357
- const hasMarkdownChanges = Array.from(filesToChange).some((f) => f.endsWith('.md'));
358
- if (hasMarkdownChanges) {
359
- await Bash('npm exec markdownlint-cli2 -- --fix "**/*.md"');
360
- console.log('✅ Markdown linting complete');
361
- }
362
- } catch (error) {
363
- console.log(`⚠️ Some quality checks failed: ${error.message}`);
364
- console.log('Continuing...\n');
365
- }
366
-
367
- // Show git status
368
- const gitStatus = await Bash('git status --short');
369
- console.log('\n**Git status:**');
370
- console.log('```');
371
- console.log(gitStatus);
372
- console.log('```\n');
373
-
374
- // Ask if user wants to commit
375
- const shouldCommit = await AskUserQuestion({
376
- questions: [
377
- {
378
- question: 'Would you like to commit these changes?',
379
- header: 'Commit',
380
- multiSelect: false,
381
- options: [
382
- {
383
- label: 'Yes',
384
- description: 'Stage all changes and create a commit',
385
- },
386
- {
387
- label: 'No',
388
- description: 'Leave changes unstaged for manual review',
389
- },
390
- ],
391
- },
392
- ],
393
- });
394
-
395
- if (shouldCommit.answers['Commit'] === 'Yes') {
396
- // Stage all changes
397
- await Bash('git add -A');
398
-
399
- // Create commit message
400
- const commitMessage = `fix: address PR #${prNumber} review comments
401
-
402
- Addressed ${addressedCount} review comment(s) from ${
403
- new Set(decisions.map((d) => d.author)).size
404
- } reviewer(s)
405
- Modified ${filesToChange.size} file(s)
406
-
407
- PR: ${prDetails.html_url}`;
408
-
409
- // Create commit using heredoc for proper formatting
410
- await Bash(`git commit -m "$(cat <<'EOF'
411
- ${commitMessage}
412
- EOF
413
- )"`);
414
-
415
- console.log('✅ Changes committed successfully!');
416
-
417
- // Show the commit
418
- await Bash('git log -1 --oneline');
419
- } else {
420
- console.log('ℹ️ Changes left unstaged. Review and commit when ready.');
421
- }
422
- ````
423
-
424
- ## Workflow Principles
425
-
426
- ### 1. Conversational Approach
427
-
428
- - **One comment at a time**: Don't overwhelm with all comments at once
429
- - **Clear context**: Always show the comment, location, and relevant code
430
- - **Ask questions**: Use AskUserQuestion tool to gather user preferences
431
- - **Wait for decisions**: Never assume what the user wants
432
- - **Support custom responses**: Allow user to provide their own solution
433
-
434
- ### 2. Methodical Analysis
435
-
436
- For each comment:
437
-
438
- 1. **Understand Intent**: What is the reviewer asking for?
439
- 2. **Identify Impact**: What files/code needs to change?
440
- 3. **Assess Complexity**: Is this simple or complex?
441
- 4. **Consider Tradeoffs**: What are the pros/cons of different approaches?
442
- 5. **Provide Recommendation**: Share your preferred option with reasoning
443
-
444
- ### 3. Present Options
445
-
446
- Always provide **2-3 options** with:
447
-
448
- - Clear, concise description
449
- - Pros and cons for each
450
- - Your recommendation (with reasoning)
451
- - "Custom" option for user-provided solutions
452
- - "Skip" option for comments the user wants to defer
453
-
454
- ### 4. Implement Cleanly
455
-
456
- - Read files before editing (required by Edit tool)
457
- - Make targeted changes (don't refactor unrelated code)
458
- - Verify changes work (run linting, type checking if applicable)
459
- - Track all modified files for the summary
460
- - Show progress and results after each implementation
461
-
462
- ### 5. Quality Checks
463
-
464
- Before offering to commit:
465
-
466
- - Run code formatting (`npx nx format:write --uncommitted`)
467
- - Run markdown linting (if .md files changed)
468
- - Run affected linting (if applicable)
469
- - Show git status for user review
470
- - Handle errors gracefully
471
-
472
- ### 6. Single Commit
473
-
474
- Create one well-formatted commit for all PR comment changes:
475
-
476
- - Clear commit message following conventional commits
477
- - Summarize what was addressed
478
- - Include PR URL for reference
479
- - List number of comments addressed and files changed
480
-
481
- ## Example Workflow
482
-
483
- ````
484
- /work-through-pr-comments 154
485
-
486
- 📋 Analyzing PR #154 in Uniswap/ai-toolkit...
487
-
488
- **PR Title**: feat(claude): add local claude code workflows...
489
- **Author**: wkoutre
490
- **State**: open
491
- **URL**: https://github.com/Uniswap/ai-toolkit/pull/154
492
-
493
- Found 3 comment(s) to address
494
-
495
- ================================================================================
496
- 📝 Comment 1/3
497
- ================================================================================
498
-
499
- **Author**: Melvillian
500
- **Type**: Inline code comment
501
- **Location**: `scripts/lefthook/lint-markdown.sh:14`
502
- **Comment**:
503
- > security-nit: pin to `npx markdownlint-cli2@v1.18.1 --fix`
504
-
505
- **Current Code Context** (`scripts/lefthook/lint-markdown.sh`):
506
-
507
- ```text
508
- 9 echo "ℹ️ No markdown files to lint"
509
- 10 exit 0
510
- 11 fi
511
- 12
512
- 13 # Lint and fix markdown files (uses .markdownlint-cli2.jsonc config)
513
- → 14 echo "$STAGED_MD_FILES" | xargs npx markdownlint-cli2 --fix
514
- 15 MD_EXIT_CODE=$?
515
- 16
516
- 17 # Re-stage any auto-fixed files
517
- 18 echo "$STAGED_MD_FILES" | xargs git add
518
- ````
519
-
520
- ## 🤔 My Analysis
521
-
522
- The reviewer is raising a security concern about using `npx` without version
523
- pinning. When `npx` fetches a package without a specified version, it could
524
- potentially fetch a compromised or incompatible version from npm.
525
-
526
- However, I notice the reviewer suggested version `v1.18.1`, but your package.json
527
- shows `markdownlint-cli2: ^0.18.1`. This appears to be a typo.
528
-
529
- The core concern is valid: unpinned npm package fetching can be a security risk.
530
-
531
- ## 💡 Suggested Solutions
532
-
533
- **Option A**: Pin to exact version in script (`@0.18.1`)
534
-
535
- - ✅ Pros: Clear version in script, reproducible builds
536
- - ✅ Pros: Matches your package.json version
537
- - ❌ Cons: Version duplication between package.json and script
538
- - ❌ Cons: Need to update in two places when upgrading
539
-
540
- **Option B**: Use locally installed version (`npm exec`)
541
-
542
- - ✅ Pros: Single source of truth (package.json)
543
- - ✅ Pros: More secure - uses locked version from package-lock.json
544
- - ✅ Pros: No version string duplication
545
- - ❌ Cons: Requires `npm install` to have been run first
546
-
547
- **Option C**: Clarify version with reviewer first
548
-
549
- - ✅ Pros: Ensures we understand their intent
550
- - ❌ Cons: Delays implementation
551
-
552
- **💭 My Recommendation**: Option B - Use `npm exec markdownlint-cli2` instead
553
- of `npx markdownlint-cli2`. This addresses the security concern while maintaining
554
- a single source of truth in package.json, and it's the most maintainable approach.
555
-
556
- How would you like to address this comment from Melvillian?
557
- ○ Option A
558
- ● Option B
559
- ○ Option C
560
- ○ Custom
561
- ○ Skip
562
-
563
- ## 🔧 Implementing: Option B
564
-
565
- Updating scripts/lefthook/lint-markdown.sh...
566
- ✅ Changes implemented
567
-
568
- [Continues with comments 2 and 3...]
569
-
570
- ## 📊 Summary of Changes
571
-
572
- Total comments processed: 3
573
- Comments addressed: 3
574
- Comments skipped: 0
575
- Files modified: 4
576
-
577
- **Files changed:**
578
-
579
- - scripts/lefthook/lint-markdown.sh
580
- - CLAUDE.md
581
- - packages/plugins/development-productivity/skills/prompt-improver/skill.md
582
- - src/utils/validation.ts
583
-
584
- 🔍 Running code quality checks...
585
- ✅ Code formatting complete
586
- ✅ Markdown linting complete
587
-
588
- **Git status:**
589
-
590
- ```
591
-
592
- M CLAUDE.md
593
- M packages/plugins/development-productivity/skills/prompt-improver/skill.md
594
- M scripts/lefthook/lint-markdown.sh
595
- M src/utils/validation.ts
596
-
597
- ```
598
-
599
- Would you like to commit these changes?
600
- ● Yes
601
- ○ No
602
-
603
- ✅ Changes committed successfully!
604
- c3b5993 fix: address PR #154 review comments
605
-
606
- ````
607
-
608
- ## Error Handling
609
-
610
- ### No Comments Found
611
-
612
- ```typescript
613
- if (allComments.length === 0) {
614
- console.log('✅ No comments to address! This PR has no review comments.');
615
- return;
616
- }
617
- ````
618
-
619
- ### Invalid PR Number
620
-
621
- ```typescript
622
- try {
623
- const prDetails = await mcp__github__get_pull_request({ owner, repo, pull_number: prNumber });
624
- } catch (error) {
625
- console.log(`❌ Could not find PR #${prNumber} in ${owner}/${repo}`);
626
- console.log(`Error: ${error.message}`);
627
- console.log('\nPlease verify:');
628
- console.log(' - The PR number is correct');
629
- console.log(' - You have access to this repository');
630
- console.log(' - The repository name is correct');
631
- return;
632
- }
633
- ```
634
-
635
- ### File Read Failures
636
-
637
- ```typescript
638
- try {
639
- const fullPath = `${process.cwd()}/${comment.path}`;
640
- fileContext = await Read(fullPath);
641
- } catch (error) {
642
- console.log(`⚠️ Could not read file: ${comment.path}`);
643
- console.log('Proceeding without file context...\n');
644
- // Continue - we can still analyze the comment without file context
645
- }
646
- ```
647
-
648
- ### Git Operation Failures
649
-
650
- ```typescript
651
- try {
652
- await Bash('git add -A');
653
- await Bash(`git commit -m "${commitMessage}"`);
654
- console.log('✅ Changes committed successfully!');
655
- } catch (error) {
656
- console.log('❌ Failed to create commit');
657
- console.log(`Error: ${error.message}`);
658
- console.log('\nYour changes have been made but not committed.');
659
- console.log('Please review the changes and commit manually with:');
660
- console.log(' git add -A');
661
- console.log(' git commit -m "fix: address PR review comments"');
662
- }
663
- ```
664
-
665
- ### Repository Detection Failures
666
-
667
- ```typescript
668
- try {
669
- const remoteUrl = await Bash('git config --get remote.origin.url');
670
- const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
671
- if (!match) throw new Error('Invalid GitHub URL format');
672
- [, owner, repo] = match;
673
- } catch (error) {
674
- console.log('❌ Could not detect repository from git remote');
675
- console.log('Please specify repository explicitly:');
676
- console.log(' /work-through-pr-comments <owner/repo> <pr-number>');
677
- console.log('\nExample:');
678
- console.log(' /work-through-pr-comments Uniswap/ai-toolkit 154');
679
- return;
680
- }
681
- ```
682
-
683
- ## Best Practices
684
-
685
- ### 1. Always Read Files Before Editing
686
-
687
- The Edit tool requires files to be read first:
688
-
689
- ```typescript
690
- // ✅ Correct
691
- const content = await Read(filePath);
692
- await Edit({ file_path: filePath, old_string: '...', new_string: '...' });
693
-
694
- // ❌ Wrong - will fail with error
695
- await Edit({ file_path: filePath, old_string: '...', new_string: '...' });
696
- ```
697
-
698
- ### 2. Track All Modified Files
699
-
700
- Maintain a Set to avoid duplicates:
701
-
702
- ```typescript
703
- const filesToChange = new Set<string>();
704
-
705
- // After each file modification
706
- filesToChange.add(fullPath);
707
-
708
- // Later, get count and list
709
- console.log(`Modified ${filesToChange.size} file(s)`);
710
- filesToChange.forEach((file) => console.log(` - ${file}`));
711
- ```
712
-
713
- ### 3. Show Progress Clearly
714
-
715
- Use clear visual separators and progress indicators:
716
-
717
- ```typescript
718
- console.log(`\n${'='.repeat(80)}`);
719
- console.log(`📝 Comment ${commentNum}/${allComments.length}`);
720
- console.log(`${'='.repeat(80)}\n`);
721
-
722
- // After implementation
723
- console.log('✅ Changes implemented\n');
724
- ```
725
-
726
- ### 4. Provide Rich Context
727
-
728
- Show the code being discussed:
729
-
730
- ```typescript
731
- // Highlight the specific line mentioned in the comment
732
- for (let i = startLine; i < endLine; i++) {
733
- const lineNum = i + 1;
734
- const prefix = lineNum === targetLine ? '→ ' : ' ';
735
- console.log(`${prefix}${String(lineNum).padStart(4)} ${lines[i]}`);
736
- }
737
- ```
738
-
739
- ### 5. Handle User's Custom Solutions
740
-
741
- Be ready to implement what the user describes:
742
-
743
- ```typescript
744
- if (selectedOption === 'Custom') {
745
- console.log("📝 Please describe what you'd like me to do for this comment.\n");
746
- // Wait for user instructions in next message
747
- // Then implement exactly what they ask for
748
- continue; // Will resume after user provides guidance
749
- }
750
- ```
751
-
752
- ### 6. Create Well-Formatted Commits
753
-
754
- Use heredoc for multi-line commit messages:
755
-
756
- ```typescript
757
- const commitMessage = `fix: address PR #${prNumber} review comments
758
-
759
- Addressed ${addressedCount} review comment(s)
760
- Modified ${filesToChange.size} file(s)
761
-
762
- PR: ${prDetails.html_url}`;
763
-
764
- await Bash(`git commit -m "$(cat <<'EOF'
765
- ${commitMessage}
766
- EOF
767
- )"`);
768
- ```
769
-
770
- ## Advanced Usage
771
-
772
- ### Working with Multiple Reviewers
773
-
774
- Track comments by reviewer:
775
-
776
- ```typescript
777
- const commentsByReviewer = allComments.reduce((acc, comment) => {
778
- if (!acc[comment.author]) acc[comment.author] = [];
779
- acc[comment.author].push(comment);
780
- return acc;
781
- }, {});
782
-
783
- console.log('\n**Comments by reviewer:**');
784
- Object.entries(commentsByReviewer).forEach(([author, comments]) => {
785
- console.log(` - ${author}: ${comments.length} comment(s)`);
786
- });
787
- ```
788
-
789
- ### Categorizing Comments
790
-
791
- Group by type or severity:
792
-
793
- ```typescript
794
- function categorizeComment(comment: Comment): string {
795
- const body = comment.body.toLowerCase();
796
-
797
- if (body.includes('security') || body.includes('vulnerability')) return 'security';
798
- if (body.includes('nit') || body.includes('nitpick')) return 'style';
799
- if (body.includes('blocker') || body.includes('must')) return 'blocker';
800
- if (body.includes('suggestion') || body.includes('consider')) return 'suggestion';
801
-
802
- return 'general';
803
- }
804
-
805
- const commentsByCategory = allComments.reduce((acc, comment) => {
806
- const category = categorizeComment(comment);
807
- if (!acc[category]) acc[category] = [];
808
- acc[category].push(comment);
809
- return acc;
810
- }, {});
811
- ```
812
-
813
- ### Batch Similar Changes
814
-
815
- If multiple comments ask for the same type of change:
816
-
817
- ```typescript
818
- // Group similar comments
819
- const similarComments = allComments.filter(
820
- (c) => c.body.toLowerCase().includes('pin version') || c.body.toLowerCase().includes('add type')
821
- );
822
-
823
- if (similarComments.length > 1) {
824
- console.log(`\n**Note**: Found ${similarComments.length} similar comments about [topic].`);
825
- console.log('Would you like to address them together?\n');
826
- }
827
- ```
828
-
829
- ## Integration with Other Tools
830
-
831
- ### Using GitHub CLI
832
-
833
- If `gh` CLI is available, use it for richer interactions:
834
-
835
- ```typescript
836
- const hasGH = await Bash('which gh')
837
- .then(() => true)
838
- .catch(() => false);
839
-
840
- if (hasGH) {
841
- // Can use gh for more features
842
- await Bash(`gh pr view ${prNumber}`);
843
- await Bash(`gh pr checks ${prNumber}`);
844
- }
845
- ```
846
-
847
- ### Running Project-Specific Checks
848
-
849
- After making changes, run project-specific validations:
850
-
851
- ```typescript
852
- // Run affected tests
853
- await Bash('npx nx affected --target=test --base=HEAD~1');
854
-
855
- // Run affected linting
856
- await Bash('npx nx affected --target=lint --base=HEAD~1');
857
-
858
- // Run type checking
859
- await Bash('npx nx affected --target=typecheck --base=HEAD~1');
860
- ```
861
-
862
- ## Notes
863
-
864
- - This command emphasizes **conversation and collaboration**
865
- - Always wait for user decisions before making changes
866
- - Provide clear, honest analysis with pros/cons
867
- - Support user's custom solutions
868
- - Track all changes for comprehensive summary
869
- - Run quality checks before offering to commit
870
- - Create a single, well-formatted commit
871
- - Handle errors gracefully and provide helpful guidance
872
- - The "Custom" option lets users direct you specifically
873
- - The "Skip" option allows deferring comments without blocking progress