Conversation
- Add spec_stop_guard.py hook to prevent early stopping during /spec workflow - Hook blocks stopping unless AskUserQuestion was used or no active plan exists - Rename .claude/plugin/ to .claude/ccp/ for consistency - Add tests for spec_stop_guard hook
… after updates - Add /learn command for extracting reusable knowledge into skills - Add learn_reminder hook that prompts for knowledge extraction on stop - Add learn.md rule for automatic invocation after significant tasks - Improve updater to restart CCP automatically after updates via --restart-ccp flag - Show minimal progress in quiet mode during updates (step indicators) - Suppress verbose output (extension lists, warnings) in quiet mode - Clean up standards skills naming
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Claude finished @maxritter's task in 1m 50s —— View job Code Review Complete
SummaryThis PR adds an online learning system with Review Findings✅ Strengths
|
WalkthroughRefactors plugin layout from Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
installer/steps/claude_files.py (1)
204-213: Update file path pattern to match.claude/ccpdirectory structure.Line 204 still checks for
"/plugin/"in file paths, but the directory has been renamed from.claude/plugin/to.claude/ccp/. Files under.claude/ccp/will not match this pattern and will incorrectly fall through to the "other" category. Change the check to"/ccp/"to properly categorize plugin files.Current code (lines 204-205)
elif "/plugin/" in file_path: categories["plugin"].append(file_info)
🤖 Fix all issues with AI agents
In @.claude/ccp/hooks/learn_reminder.py:
- Around line 14-31: The STATE_FILE is hardcoded to /tmp which risks clobbering
and symlink attacks; change initialization of STATE_FILE in this module to use a
per-user runtime/cache directory (e.g., compute base =
platformdirs.user_runtime_dir or platformdirs.user_cache_dir or fallback to
Path.home()/".cache"/"claude") and set STATE_FILE = Path(base) /
"claude-online-learning-reminder"; ensure the directory is created
(mkdir(parents=True, exist_ok=True)) before any read/write in main(), keep
COOLDOWN_SECONDS and main() logic the same but wrap read_text/write_text with
the existing exception handling to tolerate permission errors.
In @.claude/ccp/scripts/worker-wrapper.cjs:
- Around line 1-2: The file contains a duplicated shebang ("#!/usr/bin/env bun")
causing a parse error because only the very first line may be a shebang; remove
the redundant second shebang so there is only a single "#!/usr/bin/env bun" at
the top of the file, leaving the rest of the JS unchanged to ensure the file
parses correctly.
In @.claude/ccp/skills/standards-accessibility/SKILL.md:
- Line 2: The YAML key "name: standards-accessability" is misspelled; update the
value to "name: standards-accessibility" so the slug matches the directory and
correct spelling in SKILL.md (replace the existing "standards-accessability"
token with "standards-accessibility").
In @.claude/ccp/skills/standards-css/SKILL.md:
- Line 2: The skill metadata uses an inconsistent name value; replace the
current name field value "standards-cc" with "standards-css" in the SKILL.md so
the frontmatter/name matches the folder path and the project's naming convention
(look for the line containing name: standards-cc and update it to name:
standards-css).
In @.claude/rules/standard/workflow-enforcement.md:
- Around line 30-38: The fenced code blocks in the workflow-enforcement markdown
lack language tags (causing MD040); update each triple-backtick block shown (the
three task listing blocks and the example task blocks referenced) to include a
language identifier like ```text or ```markdown so every fenced code block has a
language tag; ensure you replace each opening ``` with ```text (or ```markdown)
for the blocks containing plain lists and task examples (the blocks containing
"1. User makes request..." and the subsequent task lists and examples) so
markdownlint MD040 is satisfied.
In `@installer/steps/dependencies.py`:
- Line 142: Remove the unsupported "lspRecommendationDisabled" key from the
configuration being built in installer/steps/dependencies.py (delete the line
containing "lspRecommendationDisabled": True inside the settings/configuration
dict) and instead control LSP behavior via environment variables (e.g., set
ENABLE_LSP_TOOL in the env block) if LSP toggling is required.
🧹 Nitpick comments (4)
.claude/ccp/scripts/worker-service.cjs (1)
14-20: Consider maintaining the source file separately from the minified bundle.This
.cjsfile appears to be a minified/bundled output, making code review difficult. If this is generated from source files, consider:
- Adding the source files to version control for reviewability
- Including a source map or build configuration reference
- Documenting the build process in the repository
This would improve maintainability and allow proper code review of future changes.
.claude/ccp/hooks/spec_stop_guard.py (2)
22-28: Anchor plan discovery to project root if hooks don’t run from it.If Stop hooks run with a different working directory,
docs/planswon’t be found and the guard won’t trigger. Consider resolving from a project root provided in hook input (if available) or document that hooks run from the project directory.
128-128: Remove unused f-string prefix.💡 Suggested change
- print(f"Continue the workflow or use AskUserQuestion if user input is needed.", file=sys.stderr) + print("Continue the workflow or use AskUserQuestion if user input is needed.", file=sys.stderr).claude/commands/spec.md (1)
994-1008: Fix numbering gaps in the CRITICAL RULES SUMMARY.The list skips numbers (e.g., 6→8, 10→12). Consider renumbering or switching to bullets to avoid confusion.
.claude/ccp/hooks/learn_reminder.py
Outdated
| STATE_FILE = Path("/tmp/claude-online-learning-reminder") | ||
| COOLDOWN_SECONDS = 120 | ||
|
|
||
|
|
||
| def main() -> int: | ||
| """Output online learning reminder with cooldown.""" | ||
| now = time.time() | ||
|
|
||
| if STATE_FILE.exists(): | ||
| try: | ||
| last_reminder = float(STATE_FILE.read_text().strip()) | ||
| if now - last_reminder < COOLDOWN_SECONDS: | ||
| return 0 | ||
| except (ValueError, OSError): | ||
| pass | ||
|
|
||
| STATE_FILE.write_text(str(now)) | ||
| print("🧠 EVALUATE: Did you learn something extractable? → Invoke Skill(learn)", file=sys.stderr) |
There was a problem hiding this comment.
Avoid a fixed /tmp state file (symlink/clobber risk).
Use a per-user runtime/cache directory to prevent unintended overwrites.
🔧 Proposed fix
+import os
from pathlib import Path
-STATE_FILE = Path("/tmp/claude-online-learning-reminder")
+def _get_state_file() -> Path:
+ runtime_dir = Path(
+ os.environ.get("XDG_RUNTIME_DIR", Path.home() / ".cache" / "claude-codepro")
+ )
+ runtime_dir.mkdir(parents=True, exist_ok=True)
+ return runtime_dir / "online-learning-reminder"
+
COOLDOWN_SECONDS = 120
@@
- if STATE_FILE.exists():
+ state_file = _get_state_file()
+ if state_file.exists():
try:
- last_reminder = float(STATE_FILE.read_text().strip())
+ last_reminder = float(state_file.read_text().strip())
if now - last_reminder < COOLDOWN_SECONDS:
return 0
except (ValueError, OSError):
pass
- STATE_FILE.write_text(str(now))
+ state_file.write_text(str(now))🧰 Tools
🪛 Ruff (0.14.14)
14-14: Probable insecure usage of temporary file or directory: "/tmp/claude-online-learning-reminder"
(S108)
🤖 Prompt for AI Agents
In @.claude/ccp/hooks/learn_reminder.py around lines 14 - 31, The STATE_FILE is
hardcoded to /tmp which risks clobbering and symlink attacks; change
initialization of STATE_FILE in this module to use a per-user runtime/cache
directory (e.g., compute base = platformdirs.user_runtime_dir or
platformdirs.user_cache_dir or fallback to Path.home()/".cache"/"claude") and
set STATE_FILE = Path(base) / "claude-online-learning-reminder"; ensure the
directory is created (mkdir(parents=True, exist_ok=True)) before any read/write
in main(), keep COOLDOWN_SECONDS and main() logic the same but wrap
read_text/write_text with the existing exception handling to tolerate permission
errors.
| ``` | ||
| 1. User makes request | ||
| 2. IMMEDIATELY create tasks (before any other work) | ||
| 3. Set up dependencies with addBlockedBy | ||
| 4. Mark task in_progress when starting | ||
| 5. Mark task completed when done | ||
| 6. Check TaskList for next task | ||
| 7. Repeat until all tasks completed | ||
| ``` |
There was a problem hiding this comment.
Add fenced code block languages for markdownlint compliance.
These new blocks lack a language tag. Use text or markdown to satisfy MD040 and improve readability.
✅ Suggested fix
-```
+```text
1. User makes request
2. IMMEDIATELY create tasks (before any other work)
3. Set up dependencies with addBlockedBy
4. Mark task in_progress when starting
5. Mark task completed when done
6. Check TaskList for next task
7. Repeat until all tasks completed
-```
+```
-```
+```text
Task 1: Research existing code
Task 2: Implement feature [blockedBy: 1]
Task 3: Write tests [blockedBy: 2]
Task 4: Update documentation [blockedBy: 2]
-```
+```
-```
+```text
1. TaskCreate: "Fix login bug"
2. TaskCreate: "Add password reset feature"
3. TaskCreate: "Test both features" [blockedBy: 1, 2]
4. Start task 1, mark in_progress
5. Complete task 1, mark completed
6. TaskList → see task 2 is ready
7. Continue...
-```
+```Also applies to: 44-49, 55-63
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
30-30: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In @.claude/rules/standard/workflow-enforcement.md around lines 30 - 38, The
fenced code blocks in the workflow-enforcement markdown lack language tags
(causing MD040); update each triple-backtick block shown (the three task listing
blocks and the example task blocks referenced) to include a language identifier
like ```text or ```markdown so every fenced code block has a language tag;
ensure you replace each opening ``` with ```text (or ```markdown) for the blocks
containing plain lists and task examples (the blocks containing "1. User makes
request..." and the subsequent task lists and examples) so markdownlint MD040 is
satisfied.
| "respectGitignore": False, | ||
| "autoUpdates": False, | ||
| "claudeInChromeDefaultEnabled": False, | ||
| "lspRecommendationDisabled": True, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Claude Code "lspRecommendationDisabled" configuration option
💡 Result:
There’s no publicly documented Claude Code setting named lspRecommendationDisabled.
In Anthropic’s official settings.json documentation, the supported top-level keys are listed (e.g., env, model, permissions, hooks, enabledPlugins, etc.), and lspRecommendationDisabled is not among them—so it’s not a supported/official configuration option you can rely on. [1]
If your goal is to control LSP behavior, the documented approach is to enable/disable LSP via environment variables (which you can also set through settings.json using the env block). For example, LSP is commonly toggled with ENABLE_LSP_TOOL=1. [1][2]
Sources: [1] [2]
🏁 Script executed:
# Search the codebase for references to "lspRecommendationDisabled"
rg "lspRecommendationDisabled" -iRepository: maxritter/claude-codepro
Length of output: 146
🏁 Script executed:
# Check if there's any documentation or schema for Claude Code config in the repo
find . -type f \( -name "*.md" -o -name "*.json" -o -name "*.yml" -o -name "*.yaml" \) | head -20 | xargs grep -l "lsp\|config\|schema" 2>/dev/null | head -10Repository: maxritter/claude-codepro
Length of output: 469
🏁 Script executed:
# Examine the dependencies.py file more closely to understand context
cat -n installer/steps/dependencies.py | sed -n '130,155p'Repository: maxritter/claude-codepro
Length of output: 1112
Remove lspRecommendationDisabled—it's not a supported Claude Code configuration option.
Web search confirms this setting is not documented in Anthropic's official settings.json schema and will be silently ignored. To control LSP behavior, use environment variables instead (e.g., set ENABLE_LSP_TOOL in the env block if LSP control is needed).
🤖 Prompt for AI Agents
In `@installer/steps/dependencies.py` at line 142, Remove the unsupported
"lspRecommendationDisabled" key from the configuration being built in
installer/steps/dependencies.py (delete the line containing
"lspRecommendationDisabled": True inside the settings/configuration dict) and
instead control LSP behavior via environment variables (e.g., set
ENABLE_LSP_TOOL in the env block) if LSP toggling is required.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.claude/commands/sync.md (1)
302-353: Fix Phase/Step numbering mismatch.Phase 8 uses Step 7.x and Phase 9 uses Step 8.x, which makes the workflow confusing and harder to follow. Please align step numbers to the phase they belong to.
Also applies to: 391-439
.github/workflows/claude.yml (2)
31-35: Restrict@claudetriggers to trusted actors.
Any commenter can invoke the workflow and consume the OAuth token (Line 31-35). Gate by author association (OWNER/MEMBER/COLLABORATOR) to prevent untrusted triggers.🔒 Example guard (apply same pattern per event type)
- claude-mention: - if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + claude-mention: + if: | + ( + github.event_name == 'issue_comment' && + contains(github.event.comment.body, '@claude') && + contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) + ) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))As per coding guidelines, tighten workflow security gates.
46-52: Pin GitHub Actions to immutable SHAs.
Using moving tags (@v4,@v1) creates a supply-chain risk. Pin to commit SHAs instead (lines 46, 52, 70, 76). As per coding guidelines, pin actions for security.🔐 Example pinning
- - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@<COMMIT_SHA> - - name: Run Claude Code - uses: anthropics/claude-code-action@v1 + - name: Run Claude Code + uses: anthropics/claude-code-action@<COMMIT_SHA>
🤖 Fix all issues with AI agents
In @.github/workflows/claude.yml:
- Around line 60-61: The job-level if condition in the workflow
(.github/workflows/claude.yml) needs a fork guard so PRs from forks (which don't
have access to CLAUDE_CODE_OAUTH_TOKEN) are skipped; update the job's if
(currently "github.event_name == 'pull_request' || github.event_name ==
'workflow_dispatch'") to only allow pull_request runs when the PR head repo
matches the target repo by adding a check like
github.event.pull_request.head.repo.full_name == github.repository (while still
allowing workflow_dispatch), so the job runs for same-repo PRs and
workflow_dispatch but not for forked PRs.
🧹 Nitpick comments (1)
.claude/commands/sync.md (1)
65-70: Add language identifiers to fenced code blocks (MD040).These fences are missing a language specifier; markdownlint will fail.
Proposed fix
- ``` + ```text Documented rules: [list from reading files] Documented skills: [list skill names and purposes] Potential gaps to investigate: [areas not covered] Possibly outdated: [rules/skills with old content or changed workflows] ```- ``` + ```text Question: "These skills need updates. Which should I update?" Header: "Skill Updates" multiSelect: true Options: - "[skill-name]" - [What changed and why] - "[skill-name]" - [What changed and why] - "None" - Skip skill updates ```- ``` + ```text Question: "Here's the updated [skill-name]. Apply changes?" Header: "Confirm Update" Options: - "Yes, update it" - "Edit first" - "Skip this one" ```- ``` + ```text Question: "[skill-name] appears obsolete. Remove it?" Header: "Remove Skill" Options: - "Yes, remove it" - "Keep it" - Still useful - "Update instead" - Workflow changed but still needed ```-``` +```text Skill(skill="learn")</details> Also applies to: 260-268, 277-285, 291-299, 425-427 </blockquote></details> </blockquote></details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | ||
| runs-on: ubuntu-latest |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
wc -l .github/workflows/claude.ymlRepository: maxritter/claude-codepro
Length of output: 99
🏁 Script executed:
cat -n .github/workflows/claude.ymlRepository: maxritter/claude-codepro
Length of output: 3169
Skip auto-review for forked PRs (or handle missing secrets).
Pull requests from forks won't receive CLAUDE_CODE_OAUTH_TOKEN due to GitHub's security model restricting secret access to untrusted sources. The job will fail when attempting to use the token. Add a fork guard to only run for PRs from the same repository:
✅ Suggested guard
- claude-review:
- if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
+ claude-review:
+ if: |
+ github.event_name == 'workflow_dispatch' ||
+ (github.event_name == 'pull_request' &&
+ github.event.pull_request.head.repo.full_name == github.repository)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository) | |
| runs-on: ubuntu-latest |
🤖 Prompt for AI Agents
In @.github/workflows/claude.yml around lines 60 - 61, The job-level if
condition in the workflow (.github/workflows/claude.yml) needs a fork guard so
PRs from forks (which don't have access to CLAUDE_CODE_OAUTH_TOKEN) are skipped;
update the job's if (currently "github.event_name == 'pull_request' ||
github.event_name == 'workflow_dispatch'") to only allow pull_request runs when
the PR head repo matches the target repo by adding a check like
github.event.pull_request.head.repo.full_name == github.repository (while still
allowing workflow_dispatch), so the job runs for same-repo PRs and
workflow_dispatch but not for forked PRs.
- Add "repeatable workflow" trigger to /learn system - Fix skill name typos (accessability, standards-cc) - Update /plugin/ path check to /ccp/ in installer - Remove flaky ANSI test in statusline formatter
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
installer/steps/claude_files.py (1)
25-40: Add space-prefixed replacement for.claude/ccpto match bin path handling.Line 37 handles space-prefixed
BIN_PATH_PATTERN, but line 39 only handles quotedPLUGIN_PATH_PATTERN. If a command embeds the plugin path after a space (e.g.,"exec .claude/ccp script"), it won't be patched to the absolute path and may break when hooks run outside the project root. Installer code should handle both prefixes consistently for robustness.🐛 Proposed fix
content = content.replace(" " + BIN_PATH_PATTERN, " " + abs_bin_path) content = content.replace('"' + BIN_PATH_PATTERN, '"' + abs_bin_path) +content = content.replace(" " + PLUGIN_PATH_PATTERN, " " + abs_plugin_path) content = content.replace('"' + PLUGIN_PATH_PATTERN, '"' + abs_plugin_path)
🤖 Fix all issues with AI agents
In @.claude/ccp/hooks/learn_reminder.py:
- Around line 30-35: STATE_FILE.write_text(...) can raise OSError and isn’t
currently caught; wrap the write in a try/except around the
STATE_FILE.write_text(str(now)) call (inside the same function containing the
read handling) to catch OSError (or Exception) and log a warning to stderr or
the existing logger, then continue to return 2 so the hook doesn't crash when
persistence fails; reference STATE_FILE and the write_text call when locating
where to add the try/except.
🧹 Nitpick comments (1)
installer/tests/unit/steps/test_claude_files.py (1)
33-64: Consider covering space‑prefixed.claude/ccpstrings in patch tests.
Current cases verify quoted prefixes only; if you add the space-prefixed replacement, add a test like"node .claude/ccp/scripts/..."to prevent regressions.
.claude/ccp/hooks/learn_reminder.py
Outdated
| STATE_FILE.write_text(str(now)) | ||
| print( | ||
| "🧠 EVALUATE: Non-obvious solution OR repeatable workflow? → Invoke Skill(learn)", | ||
| file=sys.stderr, | ||
| ) | ||
| return 2 |
There was a problem hiding this comment.
Unhandled write failure could crash the hook.
The read operation correctly handles OSError, but write_text() on line 30 can also raise OSError (permission denied, disk full, etc.), causing an unhandled exception and traceback. Consider wrapping the write in a try/except to gracefully continue even if state persistence fails.
🔧 Proposed fix
- STATE_FILE.write_text(str(now))
+ try:
+ STATE_FILE.write_text(str(now))
+ except OSError:
+ pass # Best-effort state persistence; reminder still shows
print(
"🧠 EVALUATE: Non-obvious solution OR repeatable workflow? → Invoke Skill(learn)",
file=sys.stderr,
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| STATE_FILE.write_text(str(now)) | |
| print( | |
| "🧠 EVALUATE: Non-obvious solution OR repeatable workflow? → Invoke Skill(learn)", | |
| file=sys.stderr, | |
| ) | |
| return 2 | |
| try: | |
| STATE_FILE.write_text(str(now)) | |
| except OSError: | |
| pass # Best-effort state persistence; reminder still shows | |
| print( | |
| "🧠 EVALUATE: Non-obvious solution OR repeatable workflow? → Invoke Skill(learn)", | |
| file=sys.stderr, | |
| ) | |
| return 2 |
🤖 Prompt for AI Agents
In @.claude/ccp/hooks/learn_reminder.py around lines 30 - 35,
STATE_FILE.write_text(...) can raise OSError and isn’t currently caught; wrap
the write in a try/except around the STATE_FILE.write_text(str(now)) call
(inside the same function containing the read handling) to catch OSError (or
Exception) and log a warning to stderr or the existing logger, then continue to
return 2 so the hook doesn't crash when persistence fails; reference STATE_FILE
and the write_text call when locating where to add the try/except.
- Add 60s cooldown escape hatch to spec_stop_guard hook - Only show shell reload prompt when config actually changed - Skip vtsls install if already installed globally - Skip vexor local model download if already cached
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
installer/steps/shell_config.py (1)
291-296: Alias updates don't trigger reload prompt despite function body changes.In the commit "Only show shell reload prompt when config actually changed,"
needs_reloadis set toTrueonly for new aliases (line 296), not for updated ones. However, the alias function was modified in this PR to add devcontainer support (searching/workspacesfor CCP projects). Existing users who run the installer again will see "Updated alias" but won't be prompted to reload, causing them to continue using the old function definition.Either set
needs_reload = Truewhen updating an alias, or add a note to the "Updated alias" message suggesting a manual reload.
🧹 Nitpick comments (3)
.claude/ccp/hooks/spec_stop_guard.py (2)
23-24: Consider usingtempfile.gettempdir()for portability.While hardcoding
/tmpworks on Linux/macOS, usingtempfile.gettempdir()ensures cross-platform compatibility (e.g., Windows uses%TEMP%).♻️ Suggested improvement
+import tempfile + -STATE_FILE = Path("/tmp/claude-spec-stop-guard") +STATE_FILE = Path(tempfile.gettempdir()) / "claude-spec-stop-guard"
152-152: Remove unnecessary f-string prefix.This string has no placeholders, so the
fprefix is extraneous.♻️ Fix
- print(f"Continue the workflow or use AskUserQuestion if user input is needed.", file=sys.stderr) + print("Continue the workflow or use AskUserQuestion if user input is needed.", file=sys.stderr)installer/steps/dependencies.py (1)
401-412: Harden vtsls detection for missing npm and narrower exceptions
Add a fastcommand_exists("npm")guard (handles Windowsnpm.cmd) and avoid catchingException.♻️ Proposed refactor
def _is_vtsls_installed() -> bool: """Check if vtsls is already installed globally.""" + if not command_exists("npm"): + return False try: result = subprocess.run( ["npm", "list", "-g", "@vtsls/language-server"], capture_output=True, text=True, ) return result.returncode == 0 and "@vtsls/language-server" in result.stdout - except Exception: + except (FileNotFoundError, OSError): return FalseAs per coding guidelines, please ensure cross‑platform compatibility.
- Hook now instructs Claude to output nothing if no learning needed - Updated learn.md rule with clear decision tree - Added Online Learning feature to README and website - Simplified hook message for clarity
- Removed learn_reminder.py stop hook (was blocking and forcing responses) - Added /learn check to context_monitor at 80%+ threshold - Updated learn.md rule to reflect context warning trigger - Removed learn_reminder tests (no longer needed)
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.claude/ccp/hooks/hooks.json:
- Around line 103-106: The Stop hook entry that runs "uv run python
\"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"" is missing a timeout and can
hang; update the hook object for spec_stop_guard.py to include the same timeout
property/value used by adjacent Stop hooks (add a "timeout" field to this
command entry) so the hook will be bounded like the others.
In @.claude/rules/standard/learn.md:
- Line 36: The fenced code block in the markdown currently has no language
identifier (a bare ``` fence); update that fence to include a language specifier
by changing the opening triple backticks to use "text" (i.e., replace the
existing ``` with ```text) so the block complies with MD040 and remains
semantically neutral.
| { | ||
| "type": "command", | ||
| "command": "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"" | ||
| }, |
There was a problem hiding this comment.
Add a timeout to prevent Stop hook hangs.
The new command lacks a timeout while adjacent Stop hooks enforce timeouts. If spec_stop_guard.py stalls, Stop can block indefinitely. Consider adding a timeout consistent with other hooks.
💡 Proposed fix
{
"type": "command",
- "command": "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\""
+ "command": "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"",
+ "timeout": 60
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| "type": "command", | |
| "command": "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"" | |
| }, | |
| { | |
| "type": "command", | |
| "command": "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"", | |
| "timeout": 60 | |
| }, |
🤖 Prompt for AI Agents
In @.claude/ccp/hooks/hooks.json around lines 103 - 106, The Stop hook entry
that runs "uv run python \"${CLAUDE_PLUGIN_ROOT}/hooks/spec_stop_guard.py\"" is
missing a timeout and can hang; update the hook object for spec_stop_guard.py to
include the same timeout property/value used by adjacent Stop hooks (add a
"timeout" field to this command entry) so the hook will be bounded like the
others.
|
|
||
| ### Quick Decision Tree | ||
|
|
||
| ``` |
There was a problem hiding this comment.
Add a language to the fenced code block.
MD040 requires a language identifier. Use text to keep semantics neutral.
✅ Suggested fix
-```
+```text🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
36-36: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
In @.claude/rules/standard/learn.md at line 36, The fenced code block in the
markdown currently has no language identifier (a bare ``` fence); update that
fence to include a language specifier by changing the opening triple backticks
to use "text" (i.e., replace the existing ``` with ```text) so the block
complies with MD040 and remains semantically neutral.
|
🎉 This PR is included in version 5.4.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
/learncommand for extracting reusable knowledge into skillslearn_reminderhook that prompts for knowledge extraction on stoplearn.mdrule for automatic invocation after significant tasks--restart-ccpflagTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.