oh-my-opencode 4.4.0 → 4.5.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.
- package/.agents/command/get-unpublished-changes.md +148 -0
- package/.agents/command/omomomo.md +37 -0
- package/.agents/command/publish.md +376 -0
- package/.agents/command/remove-deadcode.md +221 -0
- package/.agents/command/security-research.md +16 -0
- package/.agents/skills/get-unpublished-changes/SKILL.md +24 -0
- package/.agents/skills/github-triage/SKILL.md +587 -0
- package/.agents/skills/github-triage/scripts/gh_fetch.py +398 -0
- package/.agents/skills/hyperplan/SKILL.md +450 -0
- package/.agents/skills/omomomo/SKILL.md +36 -0
- package/.agents/skills/pre-publish-review/SKILL.md +407 -0
- package/.agents/skills/publish/SKILL.md +428 -0
- package/.agents/skills/remove-deadcode/SKILL.md +216 -0
- package/.agents/skills/security-research/SKILL.md +204 -0
- package/.agents/skills/work-with-pr/SKILL.md +360 -0
- package/.agents/skills/work-with-pr-workspace/evals/evals.json +76 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
- package/.agents/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
- package/.opencode/command/get-unpublished-changes.md +148 -0
- package/.opencode/command/omomomo.md +37 -0
- package/.opencode/command/publish.md +376 -0
- package/.opencode/command/remove-deadcode.md +221 -0
- package/.opencode/command/security-research.md +16 -0
- package/.opencode/skills/github-triage/SKILL.md +587 -0
- package/.opencode/skills/github-triage/scripts/gh_fetch.py +398 -0
- package/.opencode/skills/hyperplan/SKILL.md +450 -0
- package/.opencode/skills/pre-publish-review/SKILL.md +407 -0
- package/.opencode/skills/work-with-pr/SKILL.md +360 -0
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +76 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
- package/.opencode/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh-cn.md +1 -1
- package/dist/agents/atlas/agent.d.ts +6 -6
- package/dist/agents/prometheus/gemini.d.ts +0 -11
- package/dist/agents/prometheus/gpt.d.ts +0 -10
- package/dist/agents/prometheus/system-prompt.d.ts +2 -20
- package/dist/agents/types.d.ts +1 -16
- package/dist/cli/index.js +178 -129
- package/dist/config/schema/agent-names.d.ts +3 -3
- package/dist/config/schema/agent-overrides.d.ts +208 -208
- package/dist/config/schema/categories.d.ts +28 -28
- package/dist/config/schema/fallback-models.d.ts +20 -20
- package/dist/config/schema/oh-my-opencode-config.d.ts +208 -208
- package/dist/features/background-agent/parent-wake-notifier.d.ts +8 -1
- package/dist/help/schema/acp.d.ts +95 -0
- package/dist/help/schema/doctor.d.ts +147 -0
- package/dist/help/schema/sandbox.d.ts +74 -0
- package/dist/help/schema/status.d.ts +139 -0
- package/dist/hooks/keyword-detector/analyze/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/hyperplan/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/search/default.d.ts +1 -1
- package/dist/hooks/keyword-detector/team/default.d.ts +2 -7
- package/dist/hooks/keyword-detector/ultrawork/default.d.ts +1 -9
- package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +1 -16
- package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts +1 -10
- package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -5
- package/dist/hooks/ralph-loop/no-progress-turn-detector.d.ts +7 -0
- package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +1 -0
- package/dist/hooks/ralph-loop/types.d.ts +1 -0
- package/dist/hooks/runtime-fallback/error-classifier.d.ts +1 -0
- package/dist/index.js +52205 -50528
- package/dist/shared/prompt-async-gate/pending-tool-turn.d.ts +1 -0
- package/dist/shared/prompt-async-gate/types.d.ts +4 -3
- package/package.json +19 -13
- package/dist/agents/atlas/default-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/default.d.ts +0 -2
- package/dist/agents/atlas/gemini-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/gemini.d.ts +0 -2
- package/dist/agents/atlas/gpt-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/gpt.d.ts +0 -2
- package/dist/agents/atlas/kimi-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/kimi.d.ts +0 -2
- package/dist/agents/atlas/opus-4-7-prompt-sections.d.ts +0 -6
- package/dist/agents/atlas/opus-4-7.d.ts +0 -2
- package/dist/agents/atlas/shared-prompt.d.ts +0 -9
- package/dist/agents/prometheus/behavioral-summary.d.ts +0 -6
- package/dist/agents/prometheus/high-accuracy-mode.d.ts +0 -6
- package/dist/agents/prometheus/identity-constraints.d.ts +0 -7
- package/dist/agents/prometheus/interview-mode.d.ts +0 -7
- package/dist/agents/prometheus/plan-generation.d.ts +0 -7
- package/dist/agents/prometheus/plan-template.d.ts +0 -7
- package/dist/agents/prometheus/spec-driven-mode.d.ts +0 -7
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# PR: fix(comment-checker): relax regex to stop flagging legitimate Note: comments
|
|
2
|
+
|
|
3
|
+
**Title:** `fix(comment-checker): relax regex to stop flagging legitimate Note: comments`
|
|
4
|
+
**Base:** `dev`
|
|
5
|
+
**Branch:** `fix/comment-checker-note-false-positive`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
- Add `exclude_patterns` config to comment-checker schema, allowing users to whitelist comment prefixes (e.g. `["^Note:", "^TODO:"]`) that should not be flagged as AI slop
|
|
12
|
+
- Thread the exclude patterns through `cli-runner.ts` and `cli.ts` to the Go binary via `--exclude-pattern` flags
|
|
13
|
+
- Add test cases covering false positive scenarios: legitimate technical notes, RFC references, and AI memo detection with/without exclusions
|
|
14
|
+
|
|
15
|
+
## Context
|
|
16
|
+
|
|
17
|
+
The comment-checker Go binary (`go-claude-code-comment-checker` v0.4.1) contains the regex `(?i)^[\s#/*-]*note:\s*\w` which matches ALL comments starting with "Note:" followed by a word character. This produces false positives for legitimate technical comments:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Note: Thread-safe by design <- flagged as AI slop
|
|
21
|
+
# Note: See RFC 7231 for details <- flagged as AI slop
|
|
22
|
+
// Note: This edge case requires... <- flagged as AI slop
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
These are standard engineering comments, not AI agent memos.
|
|
26
|
+
|
|
27
|
+
## Changes
|
|
28
|
+
|
|
29
|
+
| File | Change |
|
|
30
|
+
|------|--------|
|
|
31
|
+
| `src/config/schema/comment-checker.ts` | Add `exclude_patterns: string[]` optional field |
|
|
32
|
+
| `src/hooks/comment-checker/cli.ts` | Pass `--exclude-pattern` flags to binary |
|
|
33
|
+
| `src/hooks/comment-checker/cli-runner.ts` | Thread `excludePatterns` through `processWithCli` and `processApplyPatchEditsWithCli` |
|
|
34
|
+
| `src/hooks/comment-checker/hook.ts` | Pass `config.exclude_patterns` to CLI runner calls |
|
|
35
|
+
| `src/hooks/comment-checker/cli.test.ts` | Add 6 new test cases for false positive scenarios |
|
|
36
|
+
| `src/hooks/comment-checker/hook.apply-patch.test.ts` | Add test verifying exclude_patterns config threading |
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```jsonc
|
|
41
|
+
// .opencode/oh-my-opencode.jsonc
|
|
42
|
+
{
|
|
43
|
+
"comment_checker": {
|
|
44
|
+
"exclude_patterns": ["^Note:", "^TODO:", "^FIXME:"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Related
|
|
50
|
+
|
|
51
|
+
- Go binary repo: `code-yeongyu/go-claude-code-comment-checker` (needs corresponding `--exclude-pattern` flag support)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Verification Strategy
|
|
2
|
+
|
|
3
|
+
## Gate A: CI (`ci.yml`)
|
|
4
|
+
|
|
5
|
+
### Pre-push local validation
|
|
6
|
+
```bash
|
|
7
|
+
bun run typecheck # Zero new type errors
|
|
8
|
+
bun test src/hooks/comment-checker/ # All comment-checker tests pass
|
|
9
|
+
bun test src/config/ # Config schema tests pass
|
|
10
|
+
bun run build # Build succeeds
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### CI pipeline expectations
|
|
14
|
+
| Step | Expected |
|
|
15
|
+
|------|----------|
|
|
16
|
+
| Tests (mock-heavy isolated) | Pass - comment-checker tests run in isolation |
|
|
17
|
+
| Tests (batch) | Pass - no regression in other hook tests |
|
|
18
|
+
| Typecheck (`tsc --noEmit`) | Pass - new `exclude_patterns` field is `z.array(z.string()).optional()` |
|
|
19
|
+
| Build | Pass - schema change is additive |
|
|
20
|
+
| Schema auto-commit | May trigger if schema JSON is auto-generated |
|
|
21
|
+
|
|
22
|
+
### Failure handling
|
|
23
|
+
- Type errors: Fix in worktree, new commit, push
|
|
24
|
+
- Test failures: Investigate, fix, new commit, push
|
|
25
|
+
- Schema auto-commit conflicts: Rebase on dev, resolve, force push
|
|
26
|
+
|
|
27
|
+
## Gate B: review-work (5-agent)
|
|
28
|
+
|
|
29
|
+
### Agent expectations
|
|
30
|
+
|
|
31
|
+
| Agent | Role | Focus Areas |
|
|
32
|
+
|-------|------|-------------|
|
|
33
|
+
| Oracle (goal) | Verify fix addresses false positive issue | Config schema matches PR description, exclude_patterns flows correctly |
|
|
34
|
+
| Oracle (code quality) | Code quality check | Factory pattern consistency, no catch-all files, <200 LOC |
|
|
35
|
+
| Oracle (security) | Security review | Regex patterns are user-supplied - verify no ReDoS risk from config |
|
|
36
|
+
| Hephaestus (QA) | Hands-on execution | Run tests, verify mock binary tests actually exercise the exclude flow |
|
|
37
|
+
| Hephaestus (context) | Context mining | Check git history for related changes, verify no conflicting PRs |
|
|
38
|
+
|
|
39
|
+
### Potential review-work flags
|
|
40
|
+
1. **ReDoS concern**: User-supplied regex patterns in `exclude_patterns` could theoretically cause ReDoS in the Go binary. Mitigation: the patterns are passed as CLI args, Go's `regexp` package is RE2-based (linear time guarantee).
|
|
41
|
+
2. **Breaking change check**: Adding optional field to config schema is non-breaking (Zod `z.optional()` fills default).
|
|
42
|
+
3. **Go binary dependency**: The `--exclude-pattern` flag must exist in the Go binary for this to work. If the binary doesn't support it yet, the patterns are silently ignored (binary treats unknown flags differently).
|
|
43
|
+
|
|
44
|
+
### Failure handling
|
|
45
|
+
- If any Oracle flags issues: address feedback, push new commit, re-run review-work
|
|
46
|
+
- If Hephaestus QA finds test gaps: add missing tests, push, re-verify
|
|
47
|
+
|
|
48
|
+
## Gate C: Cubic (`cubic-dev-ai[bot]`)
|
|
49
|
+
|
|
50
|
+
### Expected review focus
|
|
51
|
+
- Schema change additive and backward-compatible
|
|
52
|
+
- Parameter threading is mechanical and low-risk
|
|
53
|
+
- Tests use mock binaries (shell scripts) - standard project pattern per `cli.test.ts`
|
|
54
|
+
|
|
55
|
+
### Success criteria
|
|
56
|
+
- `cubic-dev-ai[bot]` comments "No issues found"
|
|
57
|
+
- No requested changes
|
|
58
|
+
|
|
59
|
+
### Failure handling
|
|
60
|
+
- If Cubic flags issues: read comment, address, push fix, re-request review via:
|
|
61
|
+
```bash
|
|
62
|
+
gh pr review --request-changes --body "Addressed Cubic feedback"
|
|
63
|
+
```
|
|
64
|
+
Then push fix and wait for re-review.
|
|
65
|
+
|
|
66
|
+
## Post-merge verification
|
|
67
|
+
|
|
68
|
+
1. Confirm squash merge landed on `dev`
|
|
69
|
+
2. Verify CI passes on `dev` branch post-merge
|
|
70
|
+
3. Clean up worktree:
|
|
71
|
+
```bash
|
|
72
|
+
git worktree remove ../omo-wt/fix/comment-checker-note-false-positive
|
|
73
|
+
git branch -d fix/comment-checker-note-false-positive
|
|
74
|
+
```
|
|
75
|
+
4. File issue on `code-yeongyu/go-claude-code-comment-checker` to add `--exclude-pattern` flag support and relax the `note:` regex upstream
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"total_tokens": null, "duration_ms": 570000, "total_duration_seconds": 570}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"run_id": "eval-5-without_skill",
|
|
3
|
+
"expectations": [
|
|
4
|
+
{"text": "Plan uses git worktree in a sibling directory", "passed": false, "evidence": "git checkout -b, no worktree"},
|
|
5
|
+
{"text": "References actual comment-checker hook files", "passed": true, "evidence": "Deep analysis of Go binary, tree-sitter, formatter.go, agent_memo.go with line numbers"},
|
|
6
|
+
{"text": "Adds test cases for Note: false positive scenarios", "passed": true, "evidence": "Detailed test cases distinguishing legit vs AI slop patterns"},
|
|
7
|
+
{"text": "Verification loop includes all 3 gates", "passed": false, "evidence": "Only bun test and typecheck. No review-work or Cubic."},
|
|
8
|
+
{"text": "Only modifies regex and adds tests — no unrelated changes", "passed": true, "evidence": "Adds allowed-prefix filter module — focused approach with config extension"}
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# Code Changes: comment-checker false positive fix
|
|
2
|
+
|
|
3
|
+
## Change 1: Extend config schema
|
|
4
|
+
|
|
5
|
+
**File: `src/config/schema/comment-checker.ts`**
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// BEFORE
|
|
9
|
+
import { z } from "zod"
|
|
10
|
+
|
|
11
|
+
export const CommentCheckerConfigSchema = z.object({
|
|
12
|
+
/** Custom prompt to replace the default warning message. Use {{comments}} placeholder for detected comments XML. */
|
|
13
|
+
custom_prompt: z.string().optional(),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type CommentCheckerConfig = z.infer<typeof CommentCheckerConfigSchema>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// AFTER
|
|
21
|
+
import { z } from "zod"
|
|
22
|
+
|
|
23
|
+
const DEFAULT_ALLOWED_COMMENT_PREFIXES = [
|
|
24
|
+
"note:",
|
|
25
|
+
"todo:",
|
|
26
|
+
"fixme:",
|
|
27
|
+
"hack:",
|
|
28
|
+
"xxx:",
|
|
29
|
+
"warning:",
|
|
30
|
+
"important:",
|
|
31
|
+
"bug:",
|
|
32
|
+
"optimize:",
|
|
33
|
+
"workaround:",
|
|
34
|
+
"safety:",
|
|
35
|
+
"security:",
|
|
36
|
+
"perf:",
|
|
37
|
+
"see:",
|
|
38
|
+
"ref:",
|
|
39
|
+
"cf.",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
export const CommentCheckerConfigSchema = z.object({
|
|
43
|
+
/** Custom prompt to replace the default warning message. Use {{comments}} placeholder for detected comments XML. */
|
|
44
|
+
custom_prompt: z.string().optional(),
|
|
45
|
+
/** Comment prefixes considered legitimate (not AI slop). Case-insensitive. Defaults include Note:, TODO:, FIXME:, etc. */
|
|
46
|
+
allowed_comment_prefixes: z.array(z.string()).optional().default(DEFAULT_ALLOWED_COMMENT_PREFIXES),
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
export type CommentCheckerConfig = z.infer<typeof CommentCheckerConfigSchema>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Change 2: Create allowed-prefix-filter module
|
|
53
|
+
|
|
54
|
+
**File: `src/hooks/comment-checker/allowed-prefix-filter.ts`** (NEW)
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const COMMENT_XML_REGEX = /<comment\s+line-number="\d+">([\s\S]*?)<\/comment>/g
|
|
58
|
+
const COMMENTS_BLOCK_REGEX = /<comments\s+file="[^"]*">\s*([\s\S]*?)\s*<\/comments>/g
|
|
59
|
+
const AGENT_MEMO_HEADER_REGEX = /🚨 AGENT MEMO COMMENT DETECTED.*?---\n\n/s
|
|
60
|
+
|
|
61
|
+
function stripCommentPrefix(text: string): string {
|
|
62
|
+
let stripped = text.trim()
|
|
63
|
+
for (const prefix of ["//", "#", "/*", "--", "*"]) {
|
|
64
|
+
if (stripped.startsWith(prefix)) {
|
|
65
|
+
stripped = stripped.slice(prefix.length).trim()
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return stripped
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isAllowedComment(commentText: string, allowedPrefixes: string[]): boolean {
|
|
73
|
+
const stripped = stripCommentPrefix(commentText).toLowerCase()
|
|
74
|
+
return allowedPrefixes.some((prefix) => stripped.startsWith(prefix.toLowerCase()))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function extractCommentTexts(xmlBlock: string): string[] {
|
|
78
|
+
const texts: string[] = []
|
|
79
|
+
let match: RegExpExecArray | null
|
|
80
|
+
const regex = new RegExp(COMMENT_XML_REGEX.source, COMMENT_XML_REGEX.flags)
|
|
81
|
+
while ((match = regex.exec(xmlBlock)) !== null) {
|
|
82
|
+
texts.push(match[1])
|
|
83
|
+
}
|
|
84
|
+
return texts
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function filterAllowedComments(
|
|
88
|
+
message: string,
|
|
89
|
+
allowedPrefixes: string[],
|
|
90
|
+
): { hasRemainingComments: boolean; filteredMessage: string } {
|
|
91
|
+
if (!message || allowedPrefixes.length === 0) {
|
|
92
|
+
return { hasRemainingComments: true, filteredMessage: message }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const commentTexts = extractCommentTexts(message)
|
|
96
|
+
|
|
97
|
+
if (commentTexts.length === 0) {
|
|
98
|
+
return { hasRemainingComments: true, filteredMessage: message }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const disallowedComments = commentTexts.filter(
|
|
102
|
+
(text) => !isAllowedComment(text, allowedPrefixes),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if (disallowedComments.length === 0) {
|
|
106
|
+
return { hasRemainingComments: false, filteredMessage: "" }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (disallowedComments.length === commentTexts.length) {
|
|
110
|
+
return { hasRemainingComments: true, filteredMessage: message }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let filteredMessage = message
|
|
114
|
+
for (const text of commentTexts) {
|
|
115
|
+
if (isAllowedComment(text, allowedPrefixes)) {
|
|
116
|
+
const escapedText = text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
117
|
+
const lineRegex = new RegExp(`\\s*<comment\\s+line-number="\\d+">${escapedText}</comment>\\n?`, "g")
|
|
118
|
+
filteredMessage = filteredMessage.replace(lineRegex, "")
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
filteredMessage = filteredMessage.replace(AGENT_MEMO_HEADER_REGEX, "")
|
|
123
|
+
|
|
124
|
+
return { hasRemainingComments: true, filteredMessage }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Change 3: Thread config through cli-runner.ts
|
|
129
|
+
|
|
130
|
+
**File: `src/hooks/comment-checker/cli-runner.ts`**
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// BEFORE (processWithCli signature and body)
|
|
134
|
+
export async function processWithCli(
|
|
135
|
+
input: { tool: string; sessionID: string; callID: string },
|
|
136
|
+
pendingCall: PendingCall,
|
|
137
|
+
output: { output: string },
|
|
138
|
+
cliPath: string,
|
|
139
|
+
customPrompt: string | undefined,
|
|
140
|
+
debugLog: (...args: unknown[]) => void,
|
|
141
|
+
): Promise<void> {
|
|
142
|
+
await withCommentCheckerLock(async () => {
|
|
143
|
+
// ...
|
|
144
|
+
const result = await runCommentChecker(hookInput, cliPath, customPrompt)
|
|
145
|
+
if (result.hasComments && result.message) {
|
|
146
|
+
debugLog("CLI detected comments, appending message")
|
|
147
|
+
output.output += `\n\n${result.message}`
|
|
148
|
+
} else {
|
|
149
|
+
debugLog("CLI: no comments detected")
|
|
150
|
+
}
|
|
151
|
+
}, undefined, debugLog)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// AFTER
|
|
157
|
+
import { filterAllowedComments } from "./allowed-prefix-filter"
|
|
158
|
+
|
|
159
|
+
export async function processWithCli(
|
|
160
|
+
input: { tool: string; sessionID: string; callID: string },
|
|
161
|
+
pendingCall: PendingCall,
|
|
162
|
+
output: { output: string },
|
|
163
|
+
cliPath: string,
|
|
164
|
+
customPrompt: string | undefined,
|
|
165
|
+
allowedPrefixes: string[],
|
|
166
|
+
debugLog: (...args: unknown[]) => void,
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
await withCommentCheckerLock(async () => {
|
|
169
|
+
void input
|
|
170
|
+
debugLog("using CLI mode with path:", cliPath)
|
|
171
|
+
|
|
172
|
+
const hookInput: HookInput = {
|
|
173
|
+
session_id: pendingCall.sessionID,
|
|
174
|
+
tool_name: pendingCall.tool.charAt(0).toUpperCase() + pendingCall.tool.slice(1),
|
|
175
|
+
transcript_path: "",
|
|
176
|
+
cwd: process.cwd(),
|
|
177
|
+
hook_event_name: "PostToolUse",
|
|
178
|
+
tool_input: {
|
|
179
|
+
file_path: pendingCall.filePath,
|
|
180
|
+
content: pendingCall.content,
|
|
181
|
+
old_string: pendingCall.oldString,
|
|
182
|
+
new_string: pendingCall.newString,
|
|
183
|
+
edits: pendingCall.edits,
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = await runCommentChecker(hookInput, cliPath, customPrompt)
|
|
188
|
+
|
|
189
|
+
if (result.hasComments && result.message) {
|
|
190
|
+
const { hasRemainingComments, filteredMessage } = filterAllowedComments(
|
|
191
|
+
result.message,
|
|
192
|
+
allowedPrefixes,
|
|
193
|
+
)
|
|
194
|
+
if (hasRemainingComments && filteredMessage) {
|
|
195
|
+
debugLog("CLI detected comments, appending filtered message")
|
|
196
|
+
output.output += `\n\n${filteredMessage}`
|
|
197
|
+
} else {
|
|
198
|
+
debugLog("CLI: all detected comments matched allowed prefixes, suppressing")
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
debugLog("CLI: no comments detected")
|
|
202
|
+
}
|
|
203
|
+
}, undefined, debugLog)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Same change applied to processApplyPatchEditsWithCli - add allowedPrefixes parameter
|
|
207
|
+
export async function processApplyPatchEditsWithCli(
|
|
208
|
+
sessionID: string,
|
|
209
|
+
edits: ApplyPatchEdit[],
|
|
210
|
+
output: { output: string },
|
|
211
|
+
cliPath: string,
|
|
212
|
+
customPrompt: string | undefined,
|
|
213
|
+
allowedPrefixes: string[],
|
|
214
|
+
debugLog: (...args: unknown[]) => void,
|
|
215
|
+
): Promise<void> {
|
|
216
|
+
debugLog("processing apply_patch edits:", edits.length)
|
|
217
|
+
|
|
218
|
+
for (const edit of edits) {
|
|
219
|
+
await withCommentCheckerLock(async () => {
|
|
220
|
+
const hookInput: HookInput = {
|
|
221
|
+
session_id: sessionID,
|
|
222
|
+
tool_name: "Edit",
|
|
223
|
+
transcript_path: "",
|
|
224
|
+
cwd: process.cwd(),
|
|
225
|
+
hook_event_name: "PostToolUse",
|
|
226
|
+
tool_input: {
|
|
227
|
+
file_path: edit.filePath,
|
|
228
|
+
old_string: edit.before,
|
|
229
|
+
new_string: edit.after,
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const result = await runCommentChecker(hookInput, cliPath, customPrompt)
|
|
234
|
+
|
|
235
|
+
if (result.hasComments && result.message) {
|
|
236
|
+
const { hasRemainingComments, filteredMessage } = filterAllowedComments(
|
|
237
|
+
result.message,
|
|
238
|
+
allowedPrefixes,
|
|
239
|
+
)
|
|
240
|
+
if (hasRemainingComments && filteredMessage) {
|
|
241
|
+
debugLog("CLI detected comments for apply_patch file:", edit.filePath)
|
|
242
|
+
output.output += `\n\n${filteredMessage}`
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}, undefined, debugLog)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Change 4: Update hook.ts to pass config
|
|
251
|
+
|
|
252
|
+
**File: `src/hooks/comment-checker/hook.ts`**
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// BEFORE (in tool.execute.after handler, around line 177)
|
|
256
|
+
await processWithCli(input, pendingCall, output, cliPath, config?.custom_prompt, debugLog)
|
|
257
|
+
|
|
258
|
+
// AFTER
|
|
259
|
+
const allowedPrefixes = config?.allowed_comment_prefixes ?? []
|
|
260
|
+
await processWithCli(input, pendingCall, output, cliPath, config?.custom_prompt, allowedPrefixes, debugLog)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// BEFORE (in apply_patch section, around line 147-154)
|
|
265
|
+
await processApplyPatchEditsWithCli(
|
|
266
|
+
input.sessionID,
|
|
267
|
+
edits,
|
|
268
|
+
output,
|
|
269
|
+
cliPath,
|
|
270
|
+
config?.custom_prompt,
|
|
271
|
+
debugLog,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
// AFTER
|
|
275
|
+
const allowedPrefixes = config?.allowed_comment_prefixes ?? []
|
|
276
|
+
await processApplyPatchEditsWithCli(
|
|
277
|
+
input.sessionID,
|
|
278
|
+
edits,
|
|
279
|
+
output,
|
|
280
|
+
cliPath,
|
|
281
|
+
config?.custom_prompt,
|
|
282
|
+
allowedPrefixes,
|
|
283
|
+
debugLog,
|
|
284
|
+
)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Change 5: Test file for allowed-prefix-filter
|
|
288
|
+
|
|
289
|
+
**File: `src/hooks/comment-checker/allowed-prefix-filter.test.ts`** (NEW)
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { describe, test, expect } from "bun:test"
|
|
293
|
+
|
|
294
|
+
import { filterAllowedComments } from "./allowed-prefix-filter"
|
|
295
|
+
|
|
296
|
+
const DEFAULT_PREFIXES = [
|
|
297
|
+
"note:", "todo:", "fixme:", "hack:", "xxx:", "warning:",
|
|
298
|
+
"important:", "bug:", "optimize:", "workaround:", "safety:",
|
|
299
|
+
"security:", "perf:", "see:", "ref:", "cf.",
|
|
300
|
+
]
|
|
301
|
+
|
|
302
|
+
function buildMessage(comments: { line: number; text: string }[], filePath = "/tmp/test.ts"): string {
|
|
303
|
+
const xml = comments
|
|
304
|
+
.map((c) => `\t<comment line-number="${c.line}">${c.text}</comment>`)
|
|
305
|
+
.join("\n")
|
|
306
|
+
return `COMMENT/DOCSTRING DETECTED - IMMEDIATE ACTION REQUIRED\n\n` +
|
|
307
|
+
`Your recent changes contain comments or docstrings, which triggered this hook.\n` +
|
|
308
|
+
`Detected comments/docstrings:\n` +
|
|
309
|
+
`<comments file="${filePath}">\n${xml}\n</comments>\n`
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
describe("allowed-prefix-filter", () => {
|
|
313
|
+
describe("#given default allowed prefixes", () => {
|
|
314
|
+
describe("#when message contains only Note: comments", () => {
|
|
315
|
+
test("#then should suppress the entire message", () => {
|
|
316
|
+
const message = buildMessage([
|
|
317
|
+
{ line: 5, text: "// Note: Thread-safe implementation" },
|
|
318
|
+
{ line: 12, text: "// NOTE: See RFC 7231 for details" },
|
|
319
|
+
])
|
|
320
|
+
|
|
321
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
322
|
+
|
|
323
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
324
|
+
expect(result.filteredMessage).toBe("")
|
|
325
|
+
})
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
describe("#when message contains only TODO/FIXME comments", () => {
|
|
329
|
+
test("#then should suppress the entire message", () => {
|
|
330
|
+
const message = buildMessage([
|
|
331
|
+
{ line: 3, text: "// TODO: implement caching" },
|
|
332
|
+
{ line: 7, text: "// FIXME: race condition here" },
|
|
333
|
+
{ line: 15, text: "# HACK: workaround for upstream bug" },
|
|
334
|
+
])
|
|
335
|
+
|
|
336
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
337
|
+
|
|
338
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
339
|
+
expect(result.filteredMessage).toBe("")
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
describe("#when message contains only AI slop comments", () => {
|
|
344
|
+
test("#then should keep the entire message", () => {
|
|
345
|
+
const message = buildMessage([
|
|
346
|
+
{ line: 2, text: "// Added new validation logic" },
|
|
347
|
+
{ line: 8, text: "// Refactored for better performance" },
|
|
348
|
+
])
|
|
349
|
+
|
|
350
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
351
|
+
|
|
352
|
+
expect(result.hasRemainingComments).toBe(true)
|
|
353
|
+
expect(result.filteredMessage).toBe(message)
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
describe("#when message contains mix of legitimate and slop comments", () => {
|
|
358
|
+
test("#then should keep message but remove allowed comment XML entries", () => {
|
|
359
|
+
const message = buildMessage([
|
|
360
|
+
{ line: 5, text: "// Note: Thread-safe implementation" },
|
|
361
|
+
{ line: 10, text: "// Changed from old API to new API" },
|
|
362
|
+
])
|
|
363
|
+
|
|
364
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
365
|
+
|
|
366
|
+
expect(result.hasRemainingComments).toBe(true)
|
|
367
|
+
expect(result.filteredMessage).not.toContain("Thread-safe implementation")
|
|
368
|
+
expect(result.filteredMessage).toContain("Changed from old API to new API")
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
describe("#when Note: comment has lowercase prefix", () => {
|
|
373
|
+
test("#then should still be treated as allowed (case-insensitive)", () => {
|
|
374
|
+
const message = buildMessage([
|
|
375
|
+
{ line: 1, text: "// note: this is case insensitive" },
|
|
376
|
+
])
|
|
377
|
+
|
|
378
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
379
|
+
|
|
380
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
381
|
+
})
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
describe("#when comment uses hash prefix", () => {
|
|
385
|
+
test("#then should strip prefix before matching", () => {
|
|
386
|
+
const message = buildMessage([
|
|
387
|
+
{ line: 1, text: "# Note: Python style comment" },
|
|
388
|
+
{ line: 5, text: "# TODO: something to do" },
|
|
389
|
+
])
|
|
390
|
+
|
|
391
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
392
|
+
|
|
393
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
394
|
+
})
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
describe("#when comment has Security: prefix", () => {
|
|
398
|
+
test("#then should be treated as allowed", () => {
|
|
399
|
+
const message = buildMessage([
|
|
400
|
+
{ line: 1, text: "// Security: validate input before processing" },
|
|
401
|
+
])
|
|
402
|
+
|
|
403
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
404
|
+
|
|
405
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
406
|
+
})
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
describe("#when comment has Warning: prefix", () => {
|
|
410
|
+
test("#then should be treated as allowed", () => {
|
|
411
|
+
const message = buildMessage([
|
|
412
|
+
{ line: 1, text: "// WARNING: This mutates the input array" },
|
|
413
|
+
])
|
|
414
|
+
|
|
415
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
416
|
+
|
|
417
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
418
|
+
})
|
|
419
|
+
})
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
describe("#given empty allowed prefixes", () => {
|
|
423
|
+
describe("#when any comments are detected", () => {
|
|
424
|
+
test("#then should pass through unfiltered", () => {
|
|
425
|
+
const message = buildMessage([
|
|
426
|
+
{ line: 1, text: "// Note: this should pass through" },
|
|
427
|
+
])
|
|
428
|
+
|
|
429
|
+
const result = filterAllowedComments(message, [])
|
|
430
|
+
|
|
431
|
+
expect(result.hasRemainingComments).toBe(true)
|
|
432
|
+
expect(result.filteredMessage).toBe(message)
|
|
433
|
+
})
|
|
434
|
+
})
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
describe("#given custom allowed prefixes", () => {
|
|
438
|
+
describe("#when comment matches custom prefix", () => {
|
|
439
|
+
test("#then should suppress it", () => {
|
|
440
|
+
const message = buildMessage([
|
|
441
|
+
{ line: 1, text: "// PERF: O(n log n) complexity" },
|
|
442
|
+
])
|
|
443
|
+
|
|
444
|
+
const result = filterAllowedComments(message, ["perf:"])
|
|
445
|
+
|
|
446
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
447
|
+
})
|
|
448
|
+
})
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
describe("#given empty message", () => {
|
|
452
|
+
describe("#when filterAllowedComments is called", () => {
|
|
453
|
+
test("#then should return hasRemainingComments true with empty string", () => {
|
|
454
|
+
const result = filterAllowedComments("", DEFAULT_PREFIXES)
|
|
455
|
+
|
|
456
|
+
expect(result.hasRemainingComments).toBe(true)
|
|
457
|
+
expect(result.filteredMessage).toBe("")
|
|
458
|
+
})
|
|
459
|
+
})
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
describe("#given message with agent memo header", () => {
|
|
463
|
+
describe("#when all flagged comments are legitimate Note: comments", () => {
|
|
464
|
+
test("#then should suppress agent memo header along with comments", () => {
|
|
465
|
+
const message =
|
|
466
|
+
"🚨 AGENT MEMO COMMENT DETECTED - CODE SMELL ALERT 🚨\n\n" +
|
|
467
|
+
"⚠️ AGENT MEMO COMMENTS DETECTED - THIS IS A CODE SMELL ⚠️\n\n" +
|
|
468
|
+
"You left \"memo-style\" comments...\n\n---\n\n" +
|
|
469
|
+
"Your recent changes contain comments...\n" +
|
|
470
|
+
"Detected comments/docstrings:\n" +
|
|
471
|
+
'<comments file="/tmp/test.ts">\n' +
|
|
472
|
+
'\t<comment line-number="5">// Note: Thread-safe</comment>\n' +
|
|
473
|
+
"</comments>\n"
|
|
474
|
+
|
|
475
|
+
const result = filterAllowedComments(message, DEFAULT_PREFIXES)
|
|
476
|
+
|
|
477
|
+
expect(result.hasRemainingComments).toBe(false)
|
|
478
|
+
expect(result.filteredMessage).toBe("")
|
|
479
|
+
})
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
})
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Change 6: Update existing test for new parameter
|
|
486
|
+
|
|
487
|
+
**File: `src/hooks/comment-checker/hook.apply-patch.test.ts`**
|
|
488
|
+
|
|
489
|
+
The `processApplyPatchEditsWithCli` mock needs to account for the new `allowedPrefixes` parameter:
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// BEFORE (line 58)
|
|
493
|
+
expect(processApplyPatchEditsWithCli).toHaveBeenCalledWith(
|
|
494
|
+
"ses_test",
|
|
495
|
+
[
|
|
496
|
+
{ filePath: "/repo/src/a.ts", before: "const a = 1\n", after: "// comment\nconst a = 1\n" },
|
|
497
|
+
{ filePath: "/repo/src/new.ts", before: "const b = 1\n", after: "// moved comment\nconst b = 1\n" },
|
|
498
|
+
],
|
|
499
|
+
expect.any(Object),
|
|
500
|
+
"/tmp/fake-comment-checker",
|
|
501
|
+
undefined,
|
|
502
|
+
expect.any(Function),
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
// AFTER - add allowed_comment_prefixes argument
|
|
506
|
+
expect(processApplyPatchEditsWithCli).toHaveBeenCalledWith(
|
|
507
|
+
"ses_test",
|
|
508
|
+
[
|
|
509
|
+
{ filePath: "/repo/src/a.ts", before: "const a = 1\n", after: "// comment\nconst a = 1\n" },
|
|
510
|
+
{ filePath: "/repo/src/new.ts", before: "const b = 1\n", after: "// moved comment\nconst b = 1\n" },
|
|
511
|
+
],
|
|
512
|
+
expect.any(Object),
|
|
513
|
+
"/tmp/fake-comment-checker",
|
|
514
|
+
undefined,
|
|
515
|
+
expect.any(Array),
|
|
516
|
+
expect.any(Function),
|
|
517
|
+
)
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## Summary of all touched files
|
|
521
|
+
|
|
522
|
+
| File | Action | Description |
|
|
523
|
+
|------|--------|-------------|
|
|
524
|
+
| `src/config/schema/comment-checker.ts` | Modified | Add `allowed_comment_prefixes` with defaults |
|
|
525
|
+
| `src/hooks/comment-checker/allowed-prefix-filter.ts` | **New** | Post-processing filter for legitimate comment prefixes |
|
|
526
|
+
| `src/hooks/comment-checker/allowed-prefix-filter.test.ts` | **New** | 11 test cases covering false positives and edge cases |
|
|
527
|
+
| `src/hooks/comment-checker/cli-runner.ts` | Modified | Thread `allowedPrefixes` param, apply filter after binary result |
|
|
528
|
+
| `src/hooks/comment-checker/hook.ts` | Modified | Pass `allowed_comment_prefixes` from config to CLI runner |
|
|
529
|
+
| `src/hooks/comment-checker/hook.apply-patch.test.ts` | Modified | Update mock assertions for new parameter |
|