@boshu2/vibe-check 1.8.0 → 2.0.0
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/.claude/settings.local.json +1 -1
- package/CHANGELOG.md +10 -0
- package/CLAUDE.md +58 -0
- package/Makefile +43 -6
- package/README.md +80 -27
- package/bin/vibe-check.js +1 -1
- package/claude-progress.json +18 -0
- package/dist/analysis/cross-session-analysis.d.ts +1 -1
- package/dist/analysis/cross-session-analysis.d.ts.map +1 -1
- package/dist/analysis/cross-session-analysis.js +9 -18
- package/dist/analysis/cross-session-analysis.js.map +1 -1
- package/dist/analysis/index.d.ts +1 -1
- package/dist/analysis/index.d.ts.map +1 -1
- package/dist/analysis/index.js +1 -11
- package/dist/analysis/index.js.map +1 -1
- package/dist/analyzers/audit.d.ts +28 -0
- package/dist/analyzers/audit.d.ts.map +1 -0
- package/dist/analyzers/audit.js +86 -0
- package/dist/analyzers/audit.js.map +1 -0
- package/dist/analyzers/patterns.d.ts +1 -1
- package/dist/analyzers/patterns.d.ts.map +1 -1
- package/dist/analyzers/patterns.js +4 -10
- package/dist/analyzers/patterns.js.map +1 -1
- package/dist/analyzers/quality.d.ts +1 -1
- package/dist/analyzers/quality.d.ts.map +1 -1
- package/dist/analyzers/quality.js +5 -12
- package/dist/analyzers/quality.js.map +1 -1
- package/dist/analyzers/sessions.d.ts +1 -1
- package/dist/analyzers/sessions.d.ts.map +1 -1
- package/dist/analyzers/sessions.js +1 -4
- package/dist/analyzers/sessions.js.map +1 -1
- package/dist/cli.js +20 -20
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +114 -149
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/audit.d.ts +3 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +77 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/cache.js +31 -70
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +22 -58
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/forensics.d.ts +2 -2
- package/dist/commands/forensics.d.ts.map +1 -1
- package/dist/commands/forensics.js +41 -48
- package/dist/commands/forensics.js.map +1 -1
- package/dist/commands/index.d.ts +14 -13
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +14 -33
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init-hook.js +26 -32
- package/dist/commands/init-hook.js.map +1 -1
- package/dist/commands/insights.js +39 -45
- package/dist/commands/insights.js.map +1 -1
- package/dist/commands/pipeline.js +39 -78
- package/dist/commands/pipeline.js.map +1 -1
- package/dist/commands/profile.js +68 -74
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/session.d.ts +9 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +134 -118
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/sessions.d.ts +1 -1
- package/dist/commands/sessions.d.ts.map +1 -1
- package/dist/commands/sessions.js +42 -49
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/start.js +22 -67
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/timeline.js +74 -81
- package/dist/commands/timeline.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +117 -47
- package/dist/commands/watch.js.map +1 -1
- package/dist/gamification/achievements.d.ts +1 -1
- package/dist/gamification/achievements.d.ts.map +1 -1
- package/dist/gamification/achievements.js +7 -13
- package/dist/gamification/achievements.js.map +1 -1
- package/dist/gamification/index.d.ts +8 -8
- package/dist/gamification/index.d.ts.map +1 -1
- package/dist/gamification/index.js +8 -28
- package/dist/gamification/index.js.map +1 -1
- package/dist/gamification/profile.d.ts +2 -2
- package/dist/gamification/profile.d.ts.map +1 -1
- package/dist/gamification/profile.js +21 -64
- package/dist/gamification/profile.js.map +1 -1
- package/dist/gamification/stats.d.ts +1 -1
- package/dist/gamification/stats.d.ts.map +1 -1
- package/dist/gamification/stats.js +4 -10
- package/dist/gamification/stats.js.map +1 -1
- package/dist/gamification/streaks.d.ts +1 -1
- package/dist/gamification/streaks.d.ts.map +1 -1
- package/dist/gamification/streaks.js +8 -18
- package/dist/gamification/streaks.js.map +1 -1
- package/dist/gamification/types.js +3 -6
- package/dist/gamification/types.js.map +1 -1
- package/dist/gamification/xp.d.ts +1 -1
- package/dist/gamification/xp.d.ts.map +1 -1
- package/dist/gamification/xp.js +29 -38
- package/dist/gamification/xp.js.map +1 -1
- package/dist/git.d.ts +1 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +15 -27
- package/dist/git.js.map +1 -1
- package/dist/inner-loop/context-amnesia.d.ts +20 -0
- package/dist/inner-loop/context-amnesia.d.ts.map +1 -0
- package/dist/inner-loop/context-amnesia.js +246 -0
- package/dist/inner-loop/context-amnesia.js.map +1 -0
- package/dist/inner-loop/index.d.ts +39 -0
- package/dist/inner-loop/index.d.ts.map +1 -0
- package/dist/inner-loop/index.js +181 -0
- package/dist/inner-loop/index.js.map +1 -0
- package/dist/inner-loop/instruction-drift.d.ts +28 -0
- package/dist/inner-loop/instruction-drift.d.ts.map +1 -0
- package/dist/inner-loop/instruction-drift.js +255 -0
- package/dist/inner-loop/instruction-drift.js.map +1 -0
- package/dist/inner-loop/logging-only.d.ts +30 -0
- package/dist/inner-loop/logging-only.d.ts.map +1 -0
- package/dist/inner-loop/logging-only.js +256 -0
- package/dist/inner-loop/logging-only.js.map +1 -0
- package/dist/inner-loop/tests-passing-lie.d.ts +34 -0
- package/dist/inner-loop/tests-passing-lie.d.ts.map +1 -0
- package/dist/inner-loop/tests-passing-lie.js +208 -0
- package/dist/inner-loop/tests-passing-lie.js.map +1 -0
- package/dist/inner-loop/types.d.ts +111 -0
- package/dist/inner-loop/types.d.ts.map +1 -0
- package/dist/inner-loop/types.js +26 -0
- package/dist/inner-loop/types.js.map +1 -0
- package/dist/insights/generators.d.ts +4 -4
- package/dist/insights/generators.d.ts.map +1 -1
- package/dist/insights/generators.js +9 -20
- package/dist/insights/generators.js.map +1 -1
- package/dist/insights/index.d.ts +4 -4
- package/dist/insights/index.d.ts.map +1 -1
- package/dist/insights/index.js +23 -27
- package/dist/insights/index.js.map +1 -1
- package/dist/insights/types.js +1 -2
- package/dist/insights/types.js.map +1 -1
- package/dist/metrics/code-stability.d.ts +1 -1
- package/dist/metrics/code-stability.d.ts.map +1 -1
- package/dist/metrics/code-stability.js +1 -4
- package/dist/metrics/code-stability.js.map +1 -1
- package/dist/metrics/file-churn.d.ts +1 -1
- package/dist/metrics/file-churn.d.ts.map +1 -1
- package/dist/metrics/file-churn.js +1 -4
- package/dist/metrics/file-churn.js.map +1 -1
- package/dist/metrics/flow.d.ts +1 -1
- package/dist/metrics/flow.d.ts.map +1 -1
- package/dist/metrics/flow.js +1 -4
- package/dist/metrics/flow.js.map +1 -1
- package/dist/metrics/index.d.ts +2 -2
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +15 -20
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/rework.d.ts +1 -1
- package/dist/metrics/rework.d.ts.map +1 -1
- package/dist/metrics/rework.js +1 -4
- package/dist/metrics/rework.js.map +1 -1
- package/dist/metrics/spirals.d.ts +1 -1
- package/dist/metrics/spirals.d.ts.map +1 -1
- package/dist/metrics/spirals.js +5 -10
- package/dist/metrics/spirals.js.map +1 -1
- package/dist/metrics/time-spiral.d.ts +1 -1
- package/dist/metrics/time-spiral.d.ts.map +1 -1
- package/dist/metrics/time-spiral.js +1 -4
- package/dist/metrics/time-spiral.js.map +1 -1
- package/dist/metrics/trust.d.ts +1 -1
- package/dist/metrics/trust.d.ts.map +1 -1
- package/dist/metrics/trust.js +3 -6
- package/dist/metrics/trust.js.map +1 -1
- package/dist/metrics/velocity-anomaly.d.ts +1 -1
- package/dist/metrics/velocity-anomaly.d.ts.map +1 -1
- package/dist/metrics/velocity-anomaly.js +3 -6
- package/dist/metrics/velocity-anomaly.js.map +1 -1
- package/dist/metrics/velocity.d.ts +1 -1
- package/dist/metrics/velocity.d.ts.map +1 -1
- package/dist/metrics/velocity.js +6 -10
- package/dist/metrics/velocity.js.map +1 -1
- package/dist/output/index.d.ts +4 -4
- package/dist/output/index.d.ts.map +1 -1
- package/dist/output/index.js +10 -18
- package/dist/output/index.js.map +1 -1
- package/dist/output/json.d.ts +1 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/json.js +1 -4
- package/dist/output/json.js.map +1 -1
- package/dist/output/markdown.d.ts +1 -1
- package/dist/output/markdown.d.ts.map +1 -1
- package/dist/output/markdown.js +5 -8
- package/dist/output/markdown.js.map +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +55 -62
- package/dist/output/terminal.js.map +1 -1
- package/dist/output/timeline-html.d.ts +1 -1
- package/dist/output/timeline-html.d.ts.map +1 -1
- package/dist/output/timeline-html.js +5 -8
- package/dist/output/timeline-html.js.map +1 -1
- package/dist/output/timeline-markdown.d.ts +1 -1
- package/dist/output/timeline-markdown.d.ts.map +1 -1
- package/dist/output/timeline-markdown.js +5 -8
- package/dist/output/timeline-markdown.js.map +1 -1
- package/dist/output/timeline.d.ts +1 -1
- package/dist/output/timeline.d.ts.map +1 -1
- package/dist/output/timeline.js +46 -52
- package/dist/output/timeline.js.map +1 -1
- package/dist/patterns/detour.d.ts +1 -1
- package/dist/patterns/detour.d.ts.map +1 -1
- package/dist/patterns/detour.js +1 -4
- package/dist/patterns/detour.js.map +1 -1
- package/dist/patterns/flow-state.d.ts +1 -1
- package/dist/patterns/flow-state.d.ts.map +1 -1
- package/dist/patterns/flow-state.js +1 -4
- package/dist/patterns/flow-state.js.map +1 -1
- package/dist/patterns/index.d.ts +7 -7
- package/dist/patterns/index.d.ts.map +1 -1
- package/dist/patterns/index.js +7 -21
- package/dist/patterns/index.js.map +1 -1
- package/dist/patterns/intervention-effectiveness.d.ts +1 -1
- package/dist/patterns/intervention-effectiveness.d.ts.map +1 -1
- package/dist/patterns/intervention-effectiveness.js +3 -8
- package/dist/patterns/intervention-effectiveness.js.map +1 -1
- package/dist/patterns/late-night.d.ts +1 -1
- package/dist/patterns/late-night.d.ts.map +1 -1
- package/dist/patterns/late-night.js +1 -4
- package/dist/patterns/late-night.js.map +1 -1
- package/dist/patterns/post-delete-sprint.d.ts +1 -1
- package/dist/patterns/post-delete-sprint.d.ts.map +1 -1
- package/dist/patterns/post-delete-sprint.js +1 -4
- package/dist/patterns/post-delete-sprint.js.map +1 -1
- package/dist/patterns/spiral-regression.d.ts +1 -1
- package/dist/patterns/spiral-regression.d.ts.map +1 -1
- package/dist/patterns/spiral-regression.js +3 -8
- package/dist/patterns/spiral-regression.js.map +1 -1
- package/dist/patterns/thrashing.d.ts +1 -1
- package/dist/patterns/thrashing.d.ts.map +1 -1
- package/dist/patterns/thrashing.js +3 -6
- package/dist/patterns/thrashing.js.map +1 -1
- package/dist/score/index.d.ts +3 -3
- package/dist/score/index.d.ts.map +1 -1
- package/dist/score/index.js +4 -10
- package/dist/score/index.js.map +1 -1
- package/dist/score/weights.js +2 -6
- package/dist/score/weights.js.map +1 -1
- package/dist/sessions/index.js +9 -51
- package/dist/sessions/index.js.map +1 -1
- package/dist/storage/atomic.js +10 -51
- package/dist/storage/atomic.js.map +1 -1
- package/dist/storage/commit-log.d.ts +1 -1
- package/dist/storage/commit-log.d.ts.map +1 -1
- package/dist/storage/commit-log.js +11 -51
- package/dist/storage/commit-log.js.map +1 -1
- package/dist/storage/index.d.ts +5 -5
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +5 -37
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/schema.js +4 -9
- package/dist/storage/schema.js.map +1 -1
- package/dist/storage/spiral-history.js +14 -57
- package/dist/storage/spiral-history.js.map +1 -1
- package/dist/storage/timeline-store.d.ts +2 -2
- package/dist/storage/timeline-store.d.ts.map +1 -1
- package/dist/storage/timeline-store.js +17 -61
- package/dist/storage/timeline-store.js.map +1 -1
- package/dist/types.js +1 -2
- package/docs/ENHANCEMENT-PLAN.md +361 -0
- package/docs/FEATURES.md +340 -0
- package/feature-list.json +6 -0
- package/package.json +8 -7
- package/dist/calibration/ece.d.ts +0 -26
- package/dist/calibration/ece.d.ts.map +0 -1
- package/dist/calibration/ece.js +0 -93
- package/dist/calibration/ece.js.map +0 -1
- package/dist/calibration/index.d.ts +0 -3
- package/dist/calibration/index.d.ts.map +0 -1
- package/dist/calibration/index.js +0 -15
- package/dist/calibration/index.js.map +0 -1
- package/dist/calibration/storage.d.ts +0 -34
- package/dist/calibration/storage.d.ts.map +0 -1
- package/dist/calibration/storage.js +0 -188
- package/dist/calibration/storage.js.map +0 -1
- package/dist/commands/intervene.d.ts +0 -15
- package/dist/commands/intervene.d.ts.map +0 -1
- package/dist/commands/intervene.js +0 -183
- package/dist/commands/intervene.js.map +0 -1
- package/dist/commands/learn.d.ts +0 -3
- package/dist/commands/learn.d.ts.map +0 -1
- package/dist/commands/learn.js +0 -161
- package/dist/commands/learn.js.map +0 -1
- package/dist/commands/lesson.d.ts +0 -8
- package/dist/commands/lesson.d.ts.map +0 -1
- package/dist/commands/lesson.js +0 -206
- package/dist/commands/lesson.js.map +0 -1
- package/dist/commands/level.d.ts +0 -3
- package/dist/commands/level.d.ts.map +0 -1
- package/dist/commands/level.js +0 -277
- package/dist/commands/level.js.map +0 -1
- package/dist/gamification/badges.d.ts +0 -29
- package/dist/gamification/badges.d.ts.map +0 -1
- package/dist/gamification/badges.js +0 -114
- package/dist/gamification/badges.js.map +0 -1
- package/dist/gamification/challenges.d.ts +0 -42
- package/dist/gamification/challenges.d.ts.map +0 -1
- package/dist/gamification/challenges.js +0 -184
- package/dist/gamification/challenges.js.map +0 -1
- package/dist/gamification/hall-of-fame.d.ts +0 -17
- package/dist/gamification/hall-of-fame.d.ts.map +0 -1
- package/dist/gamification/hall-of-fame.js +0 -64
- package/dist/gamification/hall-of-fame.js.map +0 -1
- package/dist/gamification/intervention-memory.d.ts +0 -61
- package/dist/gamification/intervention-memory.d.ts.map +0 -1
- package/dist/gamification/intervention-memory.js +0 -229
- package/dist/gamification/intervention-memory.js.map +0 -1
- package/dist/gamification/leaderboards.d.ts +0 -49
- package/dist/gamification/leaderboards.d.ts.map +0 -1
- package/dist/gamification/leaderboards.js +0 -179
- package/dist/gamification/leaderboards.js.map +0 -1
- package/dist/gamification/pattern-memory.d.ts +0 -45
- package/dist/gamification/pattern-memory.d.ts.map +0 -1
- package/dist/gamification/pattern-memory.js +0 -188
- package/dist/gamification/pattern-memory.js.map +0 -1
- package/dist/gamification/share.d.ts +0 -29
- package/dist/gamification/share.d.ts.map +0 -1
- package/dist/gamification/share.js +0 -57
- package/dist/gamification/share.js.map +0 -1
- package/dist/learning/cadence.d.ts +0 -15
- package/dist/learning/cadence.d.ts.map +0 -1
- package/dist/learning/cadence.js +0 -130
- package/dist/learning/cadence.js.map +0 -1
- package/dist/learning/index.d.ts +0 -19
- package/dist/learning/index.d.ts.map +0 -1
- package/dist/learning/index.js +0 -35
- package/dist/learning/index.js.map +0 -1
- package/dist/learning/lessons-storage.d.ts +0 -48
- package/dist/learning/lessons-storage.d.ts.map +0 -1
- package/dist/learning/lessons-storage.js +0 -266
- package/dist/learning/lessons-storage.js.map +0 -1
- package/dist/learning/lessons-types.d.ts +0 -83
- package/dist/learning/lessons-types.d.ts.map +0 -1
- package/dist/learning/lessons-types.js +0 -15
- package/dist/learning/lessons-types.js.map +0 -1
- package/dist/learning/nudges.d.ts +0 -20
- package/dist/learning/nudges.d.ts.map +0 -1
- package/dist/learning/nudges.js +0 -68
- package/dist/learning/nudges.js.map +0 -1
- package/dist/learning/retrospective.d.ts +0 -27
- package/dist/learning/retrospective.d.ts.map +0 -1
- package/dist/learning/retrospective.js +0 -184
- package/dist/learning/retrospective.js.map +0 -1
- package/dist/learning/storage.d.ts +0 -44
- package/dist/learning/storage.d.ts.map +0 -1
- package/dist/learning/storage.js +0 -194
- package/dist/learning/storage.js.map +0 -1
- package/dist/learning/surfacing.d.ts +0 -36
- package/dist/learning/surfacing.d.ts.map +0 -1
- package/dist/learning/surfacing.js +0 -255
- package/dist/learning/surfacing.js.map +0 -1
- package/dist/learning/synthesis.d.ts +0 -17
- package/dist/learning/synthesis.d.ts.map +0 -1
- package/dist/learning/synthesis.js +0 -293
- package/dist/learning/synthesis.js.map +0 -1
- package/dist/learning/types.d.ts +0 -60
- package/dist/learning/types.d.ts.map +0 -1
- package/dist/learning/types.js +0 -17
- package/dist/learning/types.js.map +0 -1
- package/dist/recommend/index.d.ts +0 -3
- package/dist/recommend/index.d.ts.map +0 -1
- package/dist/recommend/index.js +0 -14
- package/dist/recommend/index.js.map +0 -1
- package/dist/recommend/ordered-logistic.d.ts +0 -49
- package/dist/recommend/ordered-logistic.d.ts.map +0 -1
- package/dist/recommend/ordered-logistic.js +0 -153
- package/dist/recommend/ordered-logistic.js.map +0 -1
- package/dist/recommend/questions.d.ts +0 -19
- package/dist/recommend/questions.d.ts.map +0 -1
- package/dist/recommend/questions.js +0 -73
- package/dist/recommend/questions.js.map +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instruction Drift Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects when AI starts "improving" things that weren't asked for:
|
|
5
|
+
* - Changes files outside the stated scope
|
|
6
|
+
* - Unrequested refactors
|
|
7
|
+
* - Style changes to unrelated code
|
|
8
|
+
* - "Cleanup" of code that was working fine
|
|
9
|
+
*
|
|
10
|
+
* This is a key "Inner Loop Disaster" in vibe coding.
|
|
11
|
+
*/
|
|
12
|
+
import { TimelineEvent } from '../types.js';
|
|
13
|
+
import { InstructionDriftResult, SessionScope, InnerLoopConfig } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Detect instruction drift in commit history.
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectInstructionDrift(events: TimelineEvent[], filesPerCommit: Map<string, string[]>, config?: Partial<InnerLoopConfig>): InstructionDriftResult;
|
|
18
|
+
/**
|
|
19
|
+
* Set session scope for drift detection.
|
|
20
|
+
* Call this at session start to declare intended working files.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createSessionScope(intendedFiles: string[], intendedDirs: string[], taskDescription?: string): SessionScope;
|
|
23
|
+
/**
|
|
24
|
+
* Infer session scope from first N commits.
|
|
25
|
+
* Use this if no explicit scope was declared.
|
|
26
|
+
*/
|
|
27
|
+
export declare function inferSessionScope(events: TimelineEvent[], filesPerCommit: Map<string, string[]>, commitCount?: number): SessionScope;
|
|
28
|
+
//# sourceMappingURL=instruction-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instruction-drift.d.ts","sourceRoot":"","sources":["../../src/inner-loop/instruction-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,sBAAsB,EAEtB,YAAY,EACZ,eAAe,EAEhB,MAAM,YAAY,CAAC;AA6CpB;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,EAAE,EACvB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,sBAAsB,CA8CxB;AAsKD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EAAE,EACvB,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,CAAC,EAAE,MAAM,GACvB,YAAY,CAOd;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,EAAE,EACvB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,WAAW,GAAE,MAAU,GACtB,YAAY,CAsBd"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instruction Drift Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects when AI starts "improving" things that weren't asked for:
|
|
5
|
+
* - Changes files outside the stated scope
|
|
6
|
+
* - Unrequested refactors
|
|
7
|
+
* - Style changes to unrelated code
|
|
8
|
+
* - "Cleanup" of code that was working fine
|
|
9
|
+
*
|
|
10
|
+
* This is a key "Inner Loop Disaster" in vibe coding.
|
|
11
|
+
*/
|
|
12
|
+
import { DEFAULT_INNER_LOOP_CONFIG, } from './types.js';
|
|
13
|
+
// Patterns that indicate unrequested changes
|
|
14
|
+
const DRIFT_PATTERNS = {
|
|
15
|
+
unrequested_refactor: [
|
|
16
|
+
/\brefactor/i,
|
|
17
|
+
/\bcleanup\b/i,
|
|
18
|
+
/\bclean\s*up\b/i,
|
|
19
|
+
/\breorganize/i,
|
|
20
|
+
/\brestructure/i,
|
|
21
|
+
/\bsimplify/i,
|
|
22
|
+
/\bimprove\s+code/i,
|
|
23
|
+
],
|
|
24
|
+
unrequested_improvement: [
|
|
25
|
+
/\bimprove/i,
|
|
26
|
+
/\benhance/i,
|
|
27
|
+
/\boptimize/i,
|
|
28
|
+
/\bbetter/i,
|
|
29
|
+
/\bupgrade/i,
|
|
30
|
+
/\bmodernize/i,
|
|
31
|
+
],
|
|
32
|
+
style_change: [
|
|
33
|
+
/\bformat/i,
|
|
34
|
+
/\blint/i,
|
|
35
|
+
/\bstyle\b/i,
|
|
36
|
+
/\bprettier/i,
|
|
37
|
+
/\bindent/i,
|
|
38
|
+
/\bwhitespace/i,
|
|
39
|
+
/\bspacing/i,
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
// Files that are often legitimately touched as side effects
|
|
43
|
+
const ALLOWED_SIDE_EFFECT_FILES = [
|
|
44
|
+
/package\.json$/,
|
|
45
|
+
/package-lock\.json$/,
|
|
46
|
+
/yarn\.lock$/,
|
|
47
|
+
/pnpm-lock\.yaml$/,
|
|
48
|
+
/tsconfig\.json$/,
|
|
49
|
+
/\.gitignore$/,
|
|
50
|
+
/\.env\.example$/,
|
|
51
|
+
/Cargo\.lock$/,
|
|
52
|
+
/go\.sum$/,
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* Detect instruction drift in commit history.
|
|
56
|
+
*/
|
|
57
|
+
export function detectInstructionDrift(events, filesPerCommit, config = {}) {
|
|
58
|
+
const cfg = { ...DEFAULT_INNER_LOOP_CONFIG, ...config };
|
|
59
|
+
const drifts = [];
|
|
60
|
+
if (events.length === 0) {
|
|
61
|
+
return {
|
|
62
|
+
detected: false,
|
|
63
|
+
drifts: [],
|
|
64
|
+
totalDriftCommits: 0,
|
|
65
|
+
totalUnauthorizedFiles: 0,
|
|
66
|
+
message: 'No commits to analyze',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// If we have explicit session scope, use it
|
|
70
|
+
if (cfg.sessionScope) {
|
|
71
|
+
const scopeDrifts = detectScopeCreep(events, filesPerCommit, cfg.sessionScope, cfg);
|
|
72
|
+
drifts.push(...scopeDrifts);
|
|
73
|
+
}
|
|
74
|
+
// Always check for unrequested refactors/improvements
|
|
75
|
+
const refactorDrifts = detectUnrequestedRefactors(events, filesPerCommit, cfg);
|
|
76
|
+
drifts.push(...refactorDrifts);
|
|
77
|
+
// Detect sudden file scope explosion
|
|
78
|
+
const explosionDrifts = detectScopeExplosion(events, filesPerCommit, cfg);
|
|
79
|
+
drifts.push(...explosionDrifts);
|
|
80
|
+
// Calculate totals
|
|
81
|
+
const totalDriftCommits = new Set(drifts.map((d) => d.commitHash)).size;
|
|
82
|
+
const totalUnauthorizedFiles = new Set(drifts.flatMap((d) => d.unauthorizedFiles)).size;
|
|
83
|
+
const detected = drifts.length > 0;
|
|
84
|
+
let message = '';
|
|
85
|
+
if (detected) {
|
|
86
|
+
const driftTypes = new Set(drifts.map((d) => d.driftType));
|
|
87
|
+
message = `🎯 Instruction drift detected: ${totalDriftCommits} commit${totalDriftCommits > 1 ? 's' : ''} went outside scope (${Array.from(driftTypes).join(', ')})`;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
detected,
|
|
91
|
+
drifts: drifts.slice(0, 10),
|
|
92
|
+
totalDriftCommits,
|
|
93
|
+
totalUnauthorizedFiles,
|
|
94
|
+
message,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Detect commits that touch files outside the declared session scope.
|
|
99
|
+
*/
|
|
100
|
+
function detectScopeCreep(events, filesPerCommit, scope, config) {
|
|
101
|
+
const drifts = [];
|
|
102
|
+
// Build set of authorized files/patterns
|
|
103
|
+
const authorizedFiles = new Set(scope.intendedFiles);
|
|
104
|
+
const authorizedDirs = scope.intendedDirs;
|
|
105
|
+
for (const event of events) {
|
|
106
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
107
|
+
const unauthorizedFiles = [];
|
|
108
|
+
for (const file of files) {
|
|
109
|
+
// Skip allowed side-effect files
|
|
110
|
+
if (isAllowedSideEffect(file, config))
|
|
111
|
+
continue;
|
|
112
|
+
// Check if file is authorized
|
|
113
|
+
const isAuthorized = authorizedFiles.has(file) ||
|
|
114
|
+
authorizedDirs.some((dir) => file.startsWith(dir + '/') || file === dir);
|
|
115
|
+
if (!isAuthorized) {
|
|
116
|
+
unauthorizedFiles.push(file);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (unauthorizedFiles.length > 0) {
|
|
120
|
+
drifts.push({
|
|
121
|
+
commitHash: event.hash,
|
|
122
|
+
commitMessage: event.subject,
|
|
123
|
+
timestamp: event.timestamp,
|
|
124
|
+
driftType: 'scope_creep',
|
|
125
|
+
unauthorizedFiles,
|
|
126
|
+
authorizedScope: [...scope.intendedFiles, ...scope.intendedDirs],
|
|
127
|
+
description: `Changed ${unauthorizedFiles.length} file${unauthorizedFiles.length > 1 ? 's' : ''} outside declared scope`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return drifts;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Detect commits that do unrequested refactoring/improvements.
|
|
135
|
+
*/
|
|
136
|
+
function detectUnrequestedRefactors(events, filesPerCommit, config) {
|
|
137
|
+
const drifts = [];
|
|
138
|
+
// Build "normal" working set from first few commits
|
|
139
|
+
const workingSet = new Set();
|
|
140
|
+
const firstCommitCount = Math.min(3, events.length);
|
|
141
|
+
for (let i = 0; i < firstCommitCount; i++) {
|
|
142
|
+
const files = filesPerCommit.get(events[i].hash) || [];
|
|
143
|
+
files.forEach((f) => workingSet.add(f));
|
|
144
|
+
}
|
|
145
|
+
for (const event of events) {
|
|
146
|
+
const message = event.subject;
|
|
147
|
+
// Check for refactor/improvement patterns
|
|
148
|
+
for (const [driftType, patterns] of Object.entries(DRIFT_PATTERNS)) {
|
|
149
|
+
const matchesPattern = patterns.some((p) => p.test(message));
|
|
150
|
+
if (matchesPattern) {
|
|
151
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
152
|
+
// Check if this touches files outside the working set
|
|
153
|
+
const outsideFiles = files.filter((f) => !workingSet.has(f) && !isAllowedSideEffect(f, config));
|
|
154
|
+
if (outsideFiles.length > 0 || files.length > 5) {
|
|
155
|
+
drifts.push({
|
|
156
|
+
commitHash: event.hash,
|
|
157
|
+
commitMessage: message,
|
|
158
|
+
timestamp: event.timestamp,
|
|
159
|
+
driftType: driftType,
|
|
160
|
+
unauthorizedFiles: outsideFiles,
|
|
161
|
+
authorizedScope: Array.from(workingSet),
|
|
162
|
+
description: `${driftType.replace(/_/g, ' ')}: ${message.substring(0, 50)}`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return drifts;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Detect sudden explosion in file scope (touching many more files than normal).
|
|
172
|
+
*/
|
|
173
|
+
function detectScopeExplosion(events, filesPerCommit, config) {
|
|
174
|
+
const drifts = [];
|
|
175
|
+
if (events.length < 3)
|
|
176
|
+
return drifts;
|
|
177
|
+
// Calculate average files per commit
|
|
178
|
+
let totalFiles = 0;
|
|
179
|
+
const fileCounts = [];
|
|
180
|
+
for (const event of events) {
|
|
181
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
182
|
+
const nonSideEffectFiles = files.filter((f) => !isAllowedSideEffect(f, config));
|
|
183
|
+
fileCounts.push(nonSideEffectFiles.length);
|
|
184
|
+
totalFiles += nonSideEffectFiles.length;
|
|
185
|
+
}
|
|
186
|
+
const avgFiles = totalFiles / events.length;
|
|
187
|
+
const threshold = Math.max(avgFiles * 3, 10); // 3x average or at least 10
|
|
188
|
+
// Find commits that touch way more files than average
|
|
189
|
+
for (let i = 0; i < events.length; i++) {
|
|
190
|
+
const event = events[i];
|
|
191
|
+
const fileCount = fileCounts[i];
|
|
192
|
+
if (fileCount > threshold) {
|
|
193
|
+
const files = filesPerCommit.get(event.hash) || [];
|
|
194
|
+
const nonSideEffectFiles = files.filter((f) => !isAllowedSideEffect(f, config));
|
|
195
|
+
drifts.push({
|
|
196
|
+
commitHash: event.hash,
|
|
197
|
+
commitMessage: event.subject,
|
|
198
|
+
timestamp: event.timestamp,
|
|
199
|
+
driftType: 'scope_creep',
|
|
200
|
+
unauthorizedFiles: nonSideEffectFiles,
|
|
201
|
+
authorizedScope: [],
|
|
202
|
+
description: `Touched ${fileCount} files (avg: ${Math.round(avgFiles)}) - possible scope explosion`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return drifts;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check if a file is an allowed side-effect (like package.json).
|
|
210
|
+
*/
|
|
211
|
+
function isAllowedSideEffect(file, config) {
|
|
212
|
+
// Check config allowed files
|
|
213
|
+
if (config.allowedDriftFiles.some((f) => file.endsWith(f))) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
// Check default patterns
|
|
217
|
+
return ALLOWED_SIDE_EFFECT_FILES.some((p) => p.test(file));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Set session scope for drift detection.
|
|
221
|
+
* Call this at session start to declare intended working files.
|
|
222
|
+
*/
|
|
223
|
+
export function createSessionScope(intendedFiles, intendedDirs, taskDescription) {
|
|
224
|
+
return {
|
|
225
|
+
intendedFiles,
|
|
226
|
+
intendedDirs,
|
|
227
|
+
taskDescription,
|
|
228
|
+
startTime: new Date(),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Infer session scope from first N commits.
|
|
233
|
+
* Use this if no explicit scope was declared.
|
|
234
|
+
*/
|
|
235
|
+
export function inferSessionScope(events, filesPerCommit, commitCount = 3) {
|
|
236
|
+
const files = new Set();
|
|
237
|
+
const dirs = new Set();
|
|
238
|
+
const eventsToUse = events.slice(0, commitCount);
|
|
239
|
+
for (const event of eventsToUse) {
|
|
240
|
+
const commitFiles = filesPerCommit.get(event.hash) || [];
|
|
241
|
+
for (const file of commitFiles) {
|
|
242
|
+
files.add(file);
|
|
243
|
+
// Extract directory
|
|
244
|
+
const dir = file.split('/').slice(0, -1).join('/');
|
|
245
|
+
if (dir)
|
|
246
|
+
dirs.add(dir);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
intendedFiles: Array.from(files),
|
|
251
|
+
intendedDirs: Array.from(dirs),
|
|
252
|
+
startTime: events[0]?.timestamp || new Date(),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=instruction-drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instruction-drift.js","sourceRoot":"","sources":["../../src/inner-loop/instruction-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging-Only Commit Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects "Debug Loop Spiral" pattern where AI adds logging/print statements
|
|
5
|
+
* instead of actually fixing the root cause. Signs of this:
|
|
6
|
+
*
|
|
7
|
+
* - Commits that only add console.log/print statements
|
|
8
|
+
* - Multiple consecutive debugging commits without substantive changes
|
|
9
|
+
* - Increasing logging density without resolution
|
|
10
|
+
*
|
|
11
|
+
* This is a key "Inner Loop Disaster" in vibe coding.
|
|
12
|
+
*/
|
|
13
|
+
import { TimelineEvent } from '../types.js';
|
|
14
|
+
import { LoggingOnlyResult, LoggingOnlyCommit, InnerLoopConfig } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Detect logging-only commits from timeline events.
|
|
17
|
+
* This is a lightweight version that infers from commit messages.
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectLoggingOnlyCommits(events: TimelineEvent[], config?: Partial<InnerLoopConfig>): LoggingOnlyResult;
|
|
20
|
+
/**
|
|
21
|
+
* Analyze a commit diff to count logging statements.
|
|
22
|
+
* This is the more accurate version that actually looks at the diff.
|
|
23
|
+
*/
|
|
24
|
+
export declare function analyzeCommitForLogging(repoPath: string, commitHash: string, config?: Partial<InnerLoopConfig>): Promise<LoggingOnlyCommit | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Analyze multiple commits for logging patterns.
|
|
27
|
+
* Returns detailed analysis with diff inspection.
|
|
28
|
+
*/
|
|
29
|
+
export declare function analyzeCommitsForLogging(repoPath: string, events: TimelineEvent[], config?: Partial<InnerLoopConfig>): Promise<LoggingOnlyResult>;
|
|
30
|
+
//# sourceMappingURL=logging-only.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-only.d.ts","sourceRoot":"","sources":["../../src/inner-loop/logging-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAmEpB;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,aAAa,EAAE,EACvB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,iBAAiB,CAgFnB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAmDnC;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,EAAE,EACvB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAoD5B"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging-Only Commit Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects "Debug Loop Spiral" pattern where AI adds logging/print statements
|
|
5
|
+
* instead of actually fixing the root cause. Signs of this:
|
|
6
|
+
*
|
|
7
|
+
* - Commits that only add console.log/print statements
|
|
8
|
+
* - Multiple consecutive debugging commits without substantive changes
|
|
9
|
+
* - Increasing logging density without resolution
|
|
10
|
+
*
|
|
11
|
+
* This is a key "Inner Loop Disaster" in vibe coding.
|
|
12
|
+
*/
|
|
13
|
+
import { simpleGit } from 'simple-git';
|
|
14
|
+
import { DEFAULT_INNER_LOOP_CONFIG, } from './types.js';
|
|
15
|
+
// Patterns that indicate logging statements by language
|
|
16
|
+
const LOGGING_PATTERNS = {
|
|
17
|
+
javascript: [
|
|
18
|
+
/console\.(log|error|warn|debug|info|trace|dir|table)\s*\(/,
|
|
19
|
+
/console\.(time|timeEnd|timeLog|group|groupEnd)\s*\(/,
|
|
20
|
+
/debugger;/,
|
|
21
|
+
],
|
|
22
|
+
typescript: [
|
|
23
|
+
/console\.(log|error|warn|debug|info|trace|dir|table)\s*\(/,
|
|
24
|
+
/console\.(time|timeEnd|timeLog|group|groupEnd)\s*\(/,
|
|
25
|
+
/debugger;/,
|
|
26
|
+
],
|
|
27
|
+
python: [
|
|
28
|
+
/print\s*\(/,
|
|
29
|
+
/logging\.(debug|info|warning|error|critical)\s*\(/,
|
|
30
|
+
/logger\.(debug|info|warning|error|critical)\s*\(/,
|
|
31
|
+
/pprint\s*\(/,
|
|
32
|
+
/breakpoint\s*\(/,
|
|
33
|
+
/import\s+pdb/,
|
|
34
|
+
/pdb\.set_trace\s*\(/,
|
|
35
|
+
],
|
|
36
|
+
java: [
|
|
37
|
+
/System\.out\.print(ln)?\s*\(/,
|
|
38
|
+
/System\.err\.print(ln)?\s*\(/,
|
|
39
|
+
/logger\.(debug|info|warn|error|trace)\s*\(/,
|
|
40
|
+
/log\.(debug|info|warn|error|trace)\s*\(/,
|
|
41
|
+
/LOG\.(debug|info|warn|error|trace)\s*\(/,
|
|
42
|
+
],
|
|
43
|
+
go: [
|
|
44
|
+
/fmt\.Print(ln|f)?\s*\(/,
|
|
45
|
+
/log\.Print(ln|f)?\s*\(/,
|
|
46
|
+
/log\.(Debug|Info|Warn|Error|Fatal)(f|ln)?\s*\(/,
|
|
47
|
+
],
|
|
48
|
+
rust: [
|
|
49
|
+
/println!\s*\(/,
|
|
50
|
+
/eprintln!\s*\(/,
|
|
51
|
+
/dbg!\s*\(/,
|
|
52
|
+
/debug!\s*\(/,
|
|
53
|
+
/info!\s*\(/,
|
|
54
|
+
/warn!\s*\(/,
|
|
55
|
+
/error!\s*\(/,
|
|
56
|
+
/trace!\s*\(/,
|
|
57
|
+
],
|
|
58
|
+
ruby: [
|
|
59
|
+
/puts\s+/,
|
|
60
|
+
/p\s+/,
|
|
61
|
+
/pp\s+/,
|
|
62
|
+
/Rails\.logger\.(debug|info|warn|error)\s*\(/,
|
|
63
|
+
/logger\.(debug|info|warn|error)\s*\(/,
|
|
64
|
+
/binding\.pry/,
|
|
65
|
+
/byebug/,
|
|
66
|
+
],
|
|
67
|
+
php: [
|
|
68
|
+
/var_dump\s*\(/,
|
|
69
|
+
/print_r\s*\(/,
|
|
70
|
+
/echo\s+/,
|
|
71
|
+
/error_log\s*\(/,
|
|
72
|
+
/dd\s*\(/,
|
|
73
|
+
/dump\s*\(/,
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
// Aggregate all patterns for quick detection
|
|
77
|
+
const ALL_LOGGING_PATTERNS = Object.values(LOGGING_PATTERNS).flat();
|
|
78
|
+
/**
|
|
79
|
+
* Detect logging-only commits from timeline events.
|
|
80
|
+
* This is a lightweight version that infers from commit messages.
|
|
81
|
+
*/
|
|
82
|
+
export function detectLoggingOnlyCommits(events, config = {}) {
|
|
83
|
+
const cfg = { ...DEFAULT_INNER_LOOP_CONFIG, ...config };
|
|
84
|
+
const loggingCommits = [];
|
|
85
|
+
if (events.length === 0) {
|
|
86
|
+
return {
|
|
87
|
+
detected: false,
|
|
88
|
+
loggingCommits: [],
|
|
89
|
+
consecutiveLoggingCount: 0,
|
|
90
|
+
totalLoggingCommits: 0,
|
|
91
|
+
message: 'No commits to analyze',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Sort by timestamp
|
|
95
|
+
const sorted = [...events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
96
|
+
// Patterns that suggest logging/debugging activity
|
|
97
|
+
const debuggingPatterns = [
|
|
98
|
+
/\badd(ed|ing)?\s+(log|debug|print)/i,
|
|
99
|
+
/\blog(ging)?\b/i,
|
|
100
|
+
/\bdebug(ging)?\b/i,
|
|
101
|
+
/\bprint\s+statement/i,
|
|
102
|
+
/\btrace\b/i,
|
|
103
|
+
/\bconsole\b/i,
|
|
104
|
+
/\btemporary\b/i,
|
|
105
|
+
/\btemp\b/i,
|
|
106
|
+
/\bwip\b/i,
|
|
107
|
+
/\binvestigat/i,
|
|
108
|
+
/\bdiagnos/i,
|
|
109
|
+
];
|
|
110
|
+
for (const event of sorted) {
|
|
111
|
+
const message = event.subject.toLowerCase();
|
|
112
|
+
const isDebugging = debuggingPatterns.some((p) => p.test(message));
|
|
113
|
+
// Infer if this is a logging-only commit
|
|
114
|
+
// True if message suggests debugging AND it's a small change
|
|
115
|
+
if (isDebugging) {
|
|
116
|
+
loggingCommits.push({
|
|
117
|
+
hash: event.hash,
|
|
118
|
+
message: event.subject,
|
|
119
|
+
timestamp: event.timestamp,
|
|
120
|
+
loggingStatements: 0, // Will be updated if we analyze diff
|
|
121
|
+
actualFixes: 0,
|
|
122
|
+
isLoggingOnly: true, // Inferred
|
|
123
|
+
loggingPatterns: [],
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Find longest consecutive run
|
|
128
|
+
let maxConsecutive = 0;
|
|
129
|
+
let currentConsecutive = 0;
|
|
130
|
+
for (const event of sorted) {
|
|
131
|
+
const isLogging = loggingCommits.some((lc) => lc.hash === event.hash);
|
|
132
|
+
if (isLogging) {
|
|
133
|
+
currentConsecutive++;
|
|
134
|
+
maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
currentConsecutive = 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const detected = maxConsecutive >= cfg.maxConsecutiveLoggingCommits;
|
|
141
|
+
let message = '';
|
|
142
|
+
if (detected) {
|
|
143
|
+
message = `🔍 Debug loop detected: ${maxConsecutive} consecutive logging/debug commits. Consider stepping back to understand the root cause.`;
|
|
144
|
+
}
|
|
145
|
+
else if (loggingCommits.length > 0) {
|
|
146
|
+
message = `${loggingCommits.length} debug/logging commit${loggingCommits.length > 1 ? 's' : ''} found`;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
detected,
|
|
150
|
+
loggingCommits: loggingCommits.slice(0, 10),
|
|
151
|
+
consecutiveLoggingCount: maxConsecutive,
|
|
152
|
+
totalLoggingCommits: loggingCommits.length,
|
|
153
|
+
message,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Analyze a commit diff to count logging statements.
|
|
158
|
+
* This is the more accurate version that actually looks at the diff.
|
|
159
|
+
*/
|
|
160
|
+
export async function analyzeCommitForLogging(repoPath, commitHash, config = {}) {
|
|
161
|
+
const cfg = { ...DEFAULT_INNER_LOOP_CONFIG, ...config };
|
|
162
|
+
const git = simpleGit(repoPath);
|
|
163
|
+
try {
|
|
164
|
+
// Get the commit diff
|
|
165
|
+
const diff = await git.show([commitHash, '--format=', '--unified=0']);
|
|
166
|
+
const commitLog = await git.log(['-1', '--format=%s', commitHash]);
|
|
167
|
+
const message = commitLog.latest?.message || '';
|
|
168
|
+
// Count logging statements added (lines starting with +)
|
|
169
|
+
const addedLines = diff
|
|
170
|
+
.split('\n')
|
|
171
|
+
.filter((line) => line.startsWith('+') && !line.startsWith('+++'));
|
|
172
|
+
let loggingStatements = 0;
|
|
173
|
+
const foundPatterns = [];
|
|
174
|
+
for (const line of addedLines) {
|
|
175
|
+
for (const pattern of ALL_LOGGING_PATTERNS) {
|
|
176
|
+
if (pattern.test(line)) {
|
|
177
|
+
loggingStatements++;
|
|
178
|
+
// Extract pattern name for reporting
|
|
179
|
+
const patternStr = pattern.toString();
|
|
180
|
+
if (!foundPatterns.includes(patternStr)) {
|
|
181
|
+
foundPatterns.push(patternStr);
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Count non-logging changes
|
|
188
|
+
const actualFixes = addedLines.length - loggingStatements;
|
|
189
|
+
// Determine if this is logging-only
|
|
190
|
+
const isLoggingOnly = loggingStatements > 0 && (actualFixes === 0 || loggingStatements / addedLines.length > 0.8);
|
|
191
|
+
return {
|
|
192
|
+
hash: commitHash,
|
|
193
|
+
message,
|
|
194
|
+
timestamp: new Date(), // Would need to get from git log
|
|
195
|
+
loggingStatements,
|
|
196
|
+
actualFixes,
|
|
197
|
+
isLoggingOnly,
|
|
198
|
+
loggingPatterns: foundPatterns,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Analyze multiple commits for logging patterns.
|
|
207
|
+
* Returns detailed analysis with diff inspection.
|
|
208
|
+
*/
|
|
209
|
+
export async function analyzeCommitsForLogging(repoPath, events, config = {}) {
|
|
210
|
+
const cfg = { ...DEFAULT_INNER_LOOP_CONFIG, ...config };
|
|
211
|
+
const loggingCommits = [];
|
|
212
|
+
// Analyze each commit
|
|
213
|
+
for (const event of events) {
|
|
214
|
+
const result = await analyzeCommitForLogging(repoPath, event.hash, config);
|
|
215
|
+
if (result) {
|
|
216
|
+
result.timestamp = event.timestamp;
|
|
217
|
+
if (result.loggingStatements > 0) {
|
|
218
|
+
loggingCommits.push(result);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Sort by timestamp
|
|
223
|
+
loggingCommits.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
224
|
+
// Find consecutive logging-only commits
|
|
225
|
+
let maxConsecutive = 0;
|
|
226
|
+
let currentConsecutive = 0;
|
|
227
|
+
const sorted = [...events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
228
|
+
for (const event of sorted) {
|
|
229
|
+
const loggingCommit = loggingCommits.find((lc) => lc.hash === event.hash);
|
|
230
|
+
if (loggingCommit?.isLoggingOnly) {
|
|
231
|
+
currentConsecutive++;
|
|
232
|
+
maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
currentConsecutive = 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const detected = maxConsecutive >= cfg.maxConsecutiveLoggingCommits;
|
|
239
|
+
// Generate message
|
|
240
|
+
let message = '';
|
|
241
|
+
if (detected) {
|
|
242
|
+
const totalLogging = loggingCommits.reduce((sum, c) => sum + c.loggingStatements, 0);
|
|
243
|
+
message = `🔍 Debug loop spiral: ${maxConsecutive} consecutive logging commits (${totalLogging} log statements added). Stop and think about the root cause.`;
|
|
244
|
+
}
|
|
245
|
+
else if (loggingCommits.length > 0) {
|
|
246
|
+
message = `${loggingCommits.filter((c) => c.isLoggingOnly).length} logging-only commit${loggingCommits.length > 1 ? 's' : ''} detected`;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
detected,
|
|
250
|
+
loggingCommits,
|
|
251
|
+
consecutiveLoggingCount: maxConsecutive,
|
|
252
|
+
totalLoggingCommits: loggingCommits.length,
|
|
253
|
+
message,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=logging-only.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-only.js","sourceRoot":"","sources":["../../src/inner-loop/logging-only.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Tests Passing" Lie Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects when AI claims "all tests passing" or "working" but the code
|
|
5
|
+
* actually doesn't work. This is detected through:
|
|
6
|
+
*
|
|
7
|
+
* 1. Inferred: Commit claims success but is immediately followed by fixes
|
|
8
|
+
* 2. Verified: Actually run tests/build and compare to commit claims
|
|
9
|
+
*
|
|
10
|
+
* This is a key "Inner Loop Disaster" in vibe coding.
|
|
11
|
+
*/
|
|
12
|
+
import { TimelineEvent } from '../types.js';
|
|
13
|
+
import { TestsPassingLieResult, InnerLoopConfig } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Detect "tests passing" lies through pattern analysis.
|
|
16
|
+
* This is the inferred method that works without running actual tests.
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectTestsPassingLie(events: TimelineEvent[], filesPerCommit: Map<string, string[]>, config?: Partial<InnerLoopConfig>): TestsPassingLieResult;
|
|
19
|
+
/**
|
|
20
|
+
* Verify a specific commit by actually running tests.
|
|
21
|
+
* This requires the repo to be at that commit state.
|
|
22
|
+
*/
|
|
23
|
+
export declare function verifyCommit(repoPath: string, commitHash: string, config?: Partial<InnerLoopConfig>): Promise<{
|
|
24
|
+
passed: boolean;
|
|
25
|
+
output: string;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Verify build passes for a commit.
|
|
29
|
+
*/
|
|
30
|
+
export declare function verifyBuild(repoPath: string, config?: Partial<InnerLoopConfig>): Promise<{
|
|
31
|
+
passed: boolean;
|
|
32
|
+
output: string;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=tests-passing-lie.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tests-passing-lie.d.ts","sourceRoot":"","sources":["../../src/inner-loop/tests-passing-lie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,qBAAqB,EAErB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAiCpB;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EAAE,EACvB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,qBAAqB,CAqEvB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsB9C;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM,GACpC,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB9C"}
|