@wooojin/forgen 0.4.0 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/.claude-plugin/plugin.json +5 -5
  2. package/CHANGELOG.md +194 -15
  3. package/CONTRIBUTING.md +2 -2
  4. package/README.ja.md +74 -9
  5. package/README.ko.md +77 -12
  6. package/README.md +127 -25
  7. package/README.zh.md +43 -9
  8. package/assets/README.md +86 -0
  9. package/assets/architecture.svg +100 -0
  10. package/assets/banner.png +0 -0
  11. package/assets/banner.svg +53 -0
  12. package/assets/demo/01-install.gif +0 -0
  13. package/assets/demo/01-install.tape +54 -0
  14. package/assets/demo/02-compound-learning.gif +0 -0
  15. package/assets/demo/02-compound-learning.tape +50 -0
  16. package/assets/demo/03-forge-personalization.gif +0 -0
  17. package/assets/demo/03-forge-personalization.tape +64 -0
  18. package/assets/demo/before-after.gif +0 -0
  19. package/assets/demo/before-after.tape +98 -0
  20. package/assets/demo-preview.svg +96 -0
  21. package/assets/icon.png +0 -0
  22. package/{hooks → assets/shared}/hook-registry.json +2 -1
  23. package/dist/checks/conclusion-verification-ratio.d.ts +37 -0
  24. package/dist/checks/conclusion-verification-ratio.js +86 -0
  25. package/dist/checks/fact-vs-agreement.d.ts +47 -0
  26. package/dist/checks/fact-vs-agreement.js +92 -0
  27. package/dist/checks/self-score-deflation.d.ts +38 -0
  28. package/dist/checks/self-score-deflation.js +108 -0
  29. package/dist/cli.js +98 -6
  30. package/dist/core/auto-compound-runner.js +137 -49
  31. package/dist/core/behavior-classifier.d.ts +28 -0
  32. package/dist/core/behavior-classifier.js +46 -0
  33. package/dist/core/dashboard.d.ts +7 -0
  34. package/dist/core/dashboard.js +41 -2
  35. package/dist/core/doctor.js +118 -5
  36. package/dist/core/extraction-notice.d.ts +18 -0
  37. package/dist/core/extraction-notice.js +64 -0
  38. package/dist/core/git-stats.d.ts +36 -0
  39. package/dist/core/git-stats.js +79 -0
  40. package/dist/core/harness.d.ts +1 -1
  41. package/dist/core/harness.js +27 -20
  42. package/dist/core/host-detect.d.ts +42 -0
  43. package/dist/core/host-detect.js +68 -0
  44. package/dist/core/init-cli.d.ts +26 -0
  45. package/dist/core/init-cli.js +104 -0
  46. package/dist/core/init.js +17 -0
  47. package/dist/core/inspect-cli.js +1 -2
  48. package/dist/core/installer.js +2 -2
  49. package/dist/core/migrate-cli.d.ts +11 -0
  50. package/dist/core/migrate-cli.js +53 -0
  51. package/dist/core/migrate-evidence-host.d.ts +36 -0
  52. package/dist/core/migrate-evidence-host.js +49 -0
  53. package/dist/core/paths.d.ts +8 -1
  54. package/dist/core/paths.js +11 -2
  55. package/dist/core/recall-cli.d.ts +26 -0
  56. package/dist/core/recall-cli.js +125 -0
  57. package/dist/core/recall-reference-detector.d.ts +43 -0
  58. package/dist/core/recall-reference-detector.js +65 -0
  59. package/dist/core/settings-injector.js +4 -2
  60. package/dist/core/spawn.d.ts +1 -1
  61. package/dist/core/spawn.js +4 -11
  62. package/dist/core/stats-cli.d.ts +21 -0
  63. package/dist/core/stats-cli.js +133 -10
  64. package/dist/core/trust-layer-intent.d.ts +35 -0
  65. package/dist/core/trust-layer-intent.js +30 -0
  66. package/dist/core/types.d.ts +1 -1
  67. package/dist/core/uninstall.js +2 -1
  68. package/dist/engine/compound-cli.js +1 -0
  69. package/dist/engine/compound-export.js +8 -3
  70. package/dist/engine/compound-extractor.js +7 -9
  71. package/dist/engine/learn-cli.js +5 -6
  72. package/dist/engine/lifecycle/bypass-detector.d.ts +6 -1
  73. package/dist/engine/lifecycle/bypass-detector.js +57 -5
  74. package/dist/engine/lifecycle/lifecycle-cli.js +4 -4
  75. package/dist/engine/lifecycle/meta-reclassifier.js +3 -3
  76. package/dist/engine/lifecycle/orchestrator.js +2 -2
  77. package/dist/engine/lifecycle/signals.js +6 -6
  78. package/dist/engine/meta-learning/session-quality-scorer.d.ts +1 -6
  79. package/dist/engine/meta-learning/session-quality-scorer.js +2 -21
  80. package/dist/engine/skill-promoter.js +3 -6
  81. package/dist/fgx.js +2 -1
  82. package/dist/forge/evidence-processor.js +12 -0
  83. package/dist/forge/onboarding.d.ts +3 -2
  84. package/dist/forge/onboarding.js +3 -2
  85. package/dist/hooks/context-guard.js +1 -1
  86. package/dist/hooks/dangerous-patterns.json +3 -3
  87. package/dist/hooks/db-guard.js +21 -5
  88. package/dist/hooks/forge-loop-progress.d.ts +9 -0
  89. package/dist/hooks/forge-loop-progress.js +38 -0
  90. package/dist/hooks/hook-registry.js +1 -1
  91. package/dist/hooks/hooks-generator.d.ts +15 -1
  92. package/dist/hooks/hooks-generator.js +18 -16
  93. package/dist/hooks/intent-classifier.js +1 -1
  94. package/dist/hooks/keyword-detector.js +2 -2
  95. package/dist/hooks/notepad-injector.js +1 -1
  96. package/dist/hooks/permission-handler.js +1 -1
  97. package/dist/hooks/post-tool-failure.js +1 -1
  98. package/dist/hooks/post-tool-use.d.ts +7 -1
  99. package/dist/hooks/post-tool-use.js +50 -23
  100. package/dist/hooks/pre-compact.js +2 -2
  101. package/dist/hooks/pre-tool-use.d.ts +7 -0
  102. package/dist/hooks/pre-tool-use.js +28 -10
  103. package/dist/hooks/rate-limiter.js +3 -3
  104. package/dist/hooks/secret-filter.js +1 -1
  105. package/dist/hooks/session-recovery.js +12 -1
  106. package/dist/hooks/shared/blocking-allowlist.d.ts +28 -0
  107. package/dist/hooks/shared/blocking-allowlist.js +38 -0
  108. package/dist/hooks/shared/command-parser.d.ts +44 -0
  109. package/dist/hooks/shared/command-parser.js +50 -0
  110. package/dist/hooks/shared/forge-loop-state.d.ts +36 -0
  111. package/dist/hooks/shared/forge-loop-state.js +116 -0
  112. package/dist/hooks/shared/hook-response.d.ts +30 -2
  113. package/dist/hooks/shared/hook-response.js +61 -3
  114. package/dist/hooks/skill-injector.js +2 -2
  115. package/dist/hooks/slop-detector.js +2 -2
  116. package/dist/hooks/solution-injector.d.ts +9 -0
  117. package/dist/hooks/solution-injector.js +48 -5
  118. package/dist/hooks/stop-guard.js +152 -13
  119. package/dist/hooks/subagent-tracker.js +1 -1
  120. package/dist/host/capabilities-claude.d.ts +8 -0
  121. package/dist/host/capabilities-claude.js +46 -0
  122. package/dist/host/capabilities-codex.d.ts +11 -0
  123. package/dist/host/capabilities-codex.js +50 -0
  124. package/dist/host/capabilities-registry.d.ts +11 -0
  125. package/dist/host/capabilities-registry.js +30 -0
  126. package/dist/host/codex-adapter.d.ts +8 -5
  127. package/dist/host/codex-adapter.js +10 -82
  128. package/dist/host/codex-output-parser.d.ts +39 -0
  129. package/dist/host/codex-output-parser.js +75 -0
  130. package/dist/host/exec-host.d.ts +54 -0
  131. package/dist/host/exec-host.js +92 -0
  132. package/dist/host/host-runtime.d.ts +37 -0
  133. package/dist/host/host-runtime.js +51 -0
  134. package/dist/host/install-claude.d.ts +35 -0
  135. package/dist/host/install-claude.js +238 -0
  136. package/dist/host/install-codex.d.ts +44 -0
  137. package/dist/host/install-codex.js +276 -0
  138. package/dist/host/install-orchestrator.d.ts +34 -0
  139. package/dist/host/install-orchestrator.js +126 -0
  140. package/dist/host/invoke-agent.d.ts +27 -0
  141. package/dist/host/invoke-agent.js +115 -0
  142. package/dist/host/parity-harness.d.ts +62 -0
  143. package/dist/host/parity-harness.js +283 -0
  144. package/dist/host/projection.d.ts +35 -0
  145. package/dist/host/projection.js +126 -0
  146. package/dist/i18n/index.js +3 -5
  147. package/dist/mcp/server.js +11 -0
  148. package/dist/mcp/tools.js +47 -0
  149. package/dist/services/session.d.ts +6 -3
  150. package/dist/services/session.js +33 -4
  151. package/dist/store/evidence-store.d.ts +1 -0
  152. package/dist/store/evidence-store.js +45 -3
  153. package/dist/store/host-mismatch.d.ts +42 -0
  154. package/dist/store/host-mismatch.js +65 -0
  155. package/dist/store/implicit-feedback-store.d.ts +59 -0
  156. package/dist/store/implicit-feedback-store.js +153 -0
  157. package/dist/store/profile-store.d.ts +29 -0
  158. package/dist/store/profile-store.js +53 -0
  159. package/dist/store/rule-store.js +8 -0
  160. package/dist/store/types.d.ts +13 -0
  161. package/hooks/hooks.json +6 -1
  162. package/package.json +7 -5
  163. package/plugin.json +4 -4
  164. package/scripts/postinstall.js +100 -25
  165. /package/{agents → assets/claude/agents}/analyst.md +0 -0
  166. /package/{agents → assets/claude/agents}/architect.md +0 -0
  167. /package/{agents → assets/claude/agents}/code-reviewer.md +0 -0
  168. /package/{agents → assets/claude/agents}/critic.md +0 -0
  169. /package/{agents → assets/claude/agents}/debugger.md +0 -0
  170. /package/{agents → assets/claude/agents}/designer.md +0 -0
  171. /package/{agents → assets/claude/agents}/executor.md +0 -0
  172. /package/{agents → assets/claude/agents}/explore.md +0 -0
  173. /package/{agents → assets/claude/agents}/git-master.md +0 -0
  174. /package/{agents → assets/claude/agents}/planner.md +0 -0
  175. /package/{agents → assets/claude/agents}/solution-evolver.md +0 -0
  176. /package/{agents → assets/claude/agents}/test-engineer.md +0 -0
  177. /package/{agents → assets/claude/agents}/verifier.md +0 -0
  178. /package/{commands → assets/claude/commands}/architecture-decision.md +0 -0
  179. /package/{commands → assets/claude/commands}/calibrate.md +0 -0
  180. /package/{commands → assets/claude/commands}/code-review.md +0 -0
  181. /package/{commands → assets/claude/commands}/compound.md +0 -0
  182. /package/{commands → assets/claude/commands}/deep-interview.md +0 -0
  183. /package/{commands → assets/claude/commands}/docker.md +0 -0
  184. /package/{commands → assets/claude/commands}/forge-loop.md +0 -0
  185. /package/{commands → assets/claude/commands}/learn.md +0 -0
  186. /package/{commands → assets/claude/commands}/retro.md +0 -0
  187. /package/{commands → assets/claude/commands}/ship.md +0 -0
@@ -0,0 +1,50 @@
1
+ # forgen — Compound Learning Demo
2
+ # Shows: Claude using accumulated knowledge → auto-compound extracting patterns
3
+
4
+ Output assets/demo/02-compound-learning.gif
5
+
6
+ Set Shell "zsh"
7
+ Set FontFamily "JetBrains Mono"
8
+ Set FontSize 15
9
+ Set Width 1200
10
+ Set Height 700
11
+ Set Padding 20
12
+ Set Theme "Catppuccin Mocha"
13
+ Set TypingSpeed 35ms
14
+ Set WindowBar Colorful
15
+ Set BorderRadius 10
16
+ Set Margin 20
17
+ Set MarginFill "#1e1e2e"
18
+
19
+ Hide
20
+ Type "cd /tmp/forgen-demo && clear"
21
+ Enter
22
+ Sleep 1s
23
+ Show
24
+
25
+ # Step 1: Ask Claude about TDD — compound should inject knowledge
26
+ Type "claude -p 'tdd 방식으로 isPrime 함수 만들어줘' --allowedTools Bash,Write,Edit"
27
+ Sleep 500ms
28
+ Enter
29
+ Sleep 15s
30
+
31
+ # Step 2: Show compound solutions matched
32
+ Type "# Compound matched starter-tdd-red-green-refactor"
33
+ Enter
34
+ Sleep 2s
35
+
36
+ # Step 3: Search compound knowledge via MCP
37
+ Type "claude -p 'compound-search MCP 도구로 typescript를 검색해줘'"
38
+ Sleep 500ms
39
+ Enter
40
+ Sleep 10s
41
+
42
+ # Step 4: Show accumulated solutions
43
+ Type "ls ~/.compound/me/solutions/ | wc -l"
44
+ Sleep 500ms
45
+ Enter
46
+ Sleep 1s
47
+
48
+ Type "# Knowledge grows with every session"
49
+ Enter
50
+ Sleep 3s
@@ -0,0 +1,64 @@
1
+ # forgen — Forge Personalization Demo
2
+ # Shows: forge interview → profile generated → personalized config
3
+
4
+ Output assets/demo/03-forge-personalization.gif
5
+
6
+ Set Shell "zsh"
7
+ Set FontFamily "JetBrains Mono"
8
+ Set FontSize 15
9
+ Set Width 1200
10
+ Set Height 700
11
+ Set Padding 20
12
+ Set Theme "Catppuccin Mocha"
13
+ Set TypingSpeed 35ms
14
+ Set WindowBar Colorful
15
+ Set BorderRadius 10
16
+ Set Margin 20
17
+ Set MarginFill "#1e1e2e"
18
+
19
+ Hide
20
+ Type "cd /tmp/forgen-demo && clear"
21
+ Enter
22
+ Sleep 1s
23
+ Show
24
+
25
+ # Step 1: Start forge
26
+ Type "forgen forge"
27
+ Sleep 500ms
28
+ Enter
29
+ Sleep 3s
30
+
31
+ # Answer questions (simulated — quality-focused developer)
32
+ Type "2"
33
+ Enter
34
+ Sleep 2s
35
+
36
+ Type "1"
37
+ Enter
38
+ Sleep 2s
39
+
40
+ Type "2"
41
+ Enter
42
+ Sleep 2s
43
+
44
+ Type "1"
45
+ Enter
46
+ Sleep 2s
47
+
48
+ Type "2"
49
+ Enter
50
+ Sleep 2s
51
+
52
+ # Wait for profile generation
53
+ Sleep 5s
54
+
55
+ # Step 2: Show generated rules
56
+ Type "cat .claude/rules/forge-quality.md | head -15"
57
+ Sleep 500ms
58
+ Enter
59
+ Sleep 3s
60
+
61
+ # Step 3: Show that Claude behavior is now personalized
62
+ Type "# Claude is now tuned to YOUR coding style"
63
+ Enter
64
+ Sleep 3s
Binary file
@@ -0,0 +1,98 @@
1
+ # forgen — Same Tool, Different Developer
2
+ # Shows how forge adapts Claude to YOUR coding style
3
+
4
+ Output assets/demo/before-after.gif
5
+
6
+ Set Shell "zsh"
7
+ Set FontFamily "JetBrains Mono"
8
+ Set FontSize 14
9
+ Set Width 1200
10
+ Set Height 750
11
+ Set Padding 20
12
+ Set Theme "Catppuccin Mocha"
13
+ Set TypingSpeed 25ms
14
+ Set WindowBar Colorful
15
+ Set BorderRadius 10
16
+ Set Margin 20
17
+ Set MarginFill "#1e1e2e"
18
+
19
+ # ═══════════════════════════════════════
20
+ # Developer A: Senior — wants terse, severity-only
21
+ # ═══════════════════════════════════════
22
+
23
+ Hide
24
+ Type `TMPDIR=$(mktemp -d) && cd "$TMPDIR" && git init -q && git config user.email "t@t" && git config user.name "T" && mkdir -p .claude/rules && cat > .claude/rules/forge-communication.md << 'EOF'`
25
+ Enter
26
+ Type "# Forgen Forge — Communication Style (terse profile)"
27
+ Enter
28
+ Type "- Keep responses under 3 sentences unless showing code"
29
+ Enter
30
+ Type "- No preamble or trailing summary"
31
+ Enter
32
+ Type "- For code review: use [SEVERITY] format only"
33
+ Enter
34
+ Type "EOF"
35
+ Enter
36
+ Type "clear"
37
+ Enter
38
+ Sleep 1s
39
+ Show
40
+
41
+ Type "echo ' Developer A: Senior engineer — prefers terse, severity-only'"
42
+ Enter
43
+ Sleep 2s
44
+
45
+ Type "cat .claude/rules/forge-communication.md"
46
+ Enter
47
+ Sleep 3s
48
+
49
+ Type@20ms `claude -p "이 코드를 리뷰해줘: function add(a, b) { let result = a + b; return result; } 파일은 만들지 마."`
50
+ Sleep 500ms
51
+ Enter
52
+ Sleep 20s
53
+
54
+ Sleep 5s
55
+
56
+ # ═══════════════════════════════════════
57
+ # Developer B: Junior — wants explanations & examples
58
+ # ═══════════════════════════════════════
59
+
60
+ Hide
61
+ Type `TMPDIR2=$(mktemp -d) && cd "$TMPDIR2" && git init -q && git config user.email "t@t" && git config user.name "T" && mkdir -p .claude/rules && cat > .claude/rules/forge-communication.md << 'EOF'`
62
+ Enter
63
+ Type "# Forgen Forge — Communication Style (educational profile)"
64
+ Enter
65
+ Type "- Explain reasoning and trade-offs for every suggestion"
66
+ Enter
67
+ Type "- Include examples showing what could go wrong"
68
+ Enter
69
+ Type "- Teach concepts — explain the why not just the what"
70
+ Enter
71
+ Type "EOF"
72
+ Enter
73
+ Type "clear"
74
+ Enter
75
+ Sleep 1s
76
+ Show
77
+
78
+ Type ""
79
+ Enter
80
+ Type "echo ' Developer B: Junior engineer — wants explanations & examples'"
81
+ Enter
82
+ Sleep 2s
83
+
84
+ Type "cat .claude/rules/forge-communication.md"
85
+ Enter
86
+ Sleep 3s
87
+
88
+ Type@20ms `claude -p "이 코드를 리뷰해줘: function add(a, b) { let result = a + b; return result; } 파일은 만들지 마."`
89
+ Sleep 500ms
90
+ Enter
91
+ Sleep 25s
92
+
93
+ Sleep 3s
94
+ Type ""
95
+ Enter
96
+ Type "echo ' Same question. Same tool. Different developer. ⚡'"
97
+ Enter
98
+ Sleep 5s
@@ -0,0 +1,96 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="340" viewBox="0 0 800 340">
2
+ <style>
3
+ .term { font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', monospace; font-size: 13px; }
4
+ .prompt { fill: #a6e3a1; }
5
+ .cmd { fill: #cdd6f4; }
6
+ .tag { fill: #89b4fa; }
7
+ .haiku { fill: #f9e2af; }
8
+ .sonnet { fill: #a6e3a1; }
9
+ .opus { fill: #cba6f7; }
10
+ .dim { fill: #6c7086; }
11
+ .box { fill: #a6e3a1; }
12
+ @keyframes typeIn { from { opacity: 0; } to { opacity: 1; } }
13
+ @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } }
14
+ @keyframes blink { 0%, 100% { opacity: 0.8; } 50% { opacity: 0; } }
15
+ .line1 { animation: typeIn 0.1s 0.3s both; }
16
+ .line2 { animation: fadeIn 0.2s 0.8s both; }
17
+ .line3 { animation: fadeIn 0.2s 1.1s both; }
18
+ .line4 { animation: fadeIn 0.2s 1.4s both; }
19
+ .line5 { animation: fadeIn 0.2s 1.7s both; }
20
+ .line6 { animation: fadeIn 0.2s 2.0s both; }
21
+ .line7 { animation: fadeIn 0.3s 2.5s both; }
22
+ .cursor { animation: blink 1s 2.8s infinite; }
23
+ </style>
24
+
25
+ <!-- Terminal window -->
26
+ <rect width="800" height="340" rx="10" ry="10" fill="#1e1e2e"/>
27
+ <rect width="800" height="36" rx="10" ry="10" fill="#313244"/>
28
+ <rect y="26" width="800" height="10" fill="#313244"/>
29
+
30
+ <!-- Traffic lights -->
31
+ <circle cx="20" cy="18" r="6" fill="#f38ba8"/>
32
+ <circle cx="40" cy="18" r="6" fill="#f9e2af"/>
33
+ <circle cx="60" cy="18" r="6" fill="#a6e3a1"/>
34
+ <text x="400" y="23" text-anchor="middle" class="term" font-size="12" fill="#6c7086">forgen — terminal</text>
35
+
36
+ <!-- Line 1: command -->
37
+ <g class="line1">
38
+ <text x="24" y="68" class="term prompt">$</text>
39
+ <text x="40" y="68" class="term cmd">forgen</text>
40
+ </g>
41
+
42
+ <!-- Line 2: philosophy -->
43
+ <g class="line2">
44
+ <text x="24" y="96" class="term tag">[forgen]</text>
45
+ <text x="96" y="96" class="term cmd">Philosophy: </text>
46
+ <text x="194" y="96" class="term" fill="#f9e2af">my-engineering</text>
47
+ <text x="310" y="96" class="term dim"> (global)</text>
48
+ </g>
49
+
50
+ <!-- Line 3: scope -->
51
+ <g class="line3">
52
+ <text x="24" y="120" class="term tag">[forgen]</text>
53
+ <text x="96" y="120" class="term cmd">Scope: Me(5) │ 3 rules, 2 solutions</text>
54
+ </g>
55
+
56
+ <!-- Line 4: routing -->
57
+ <g class="line4">
58
+ <text x="24" y="144" class="term tag">[forgen]</text>
59
+ <text x="96" y="144" class="term cmd">Routing: </text>
60
+ <text x="172" y="144" class="term haiku">haiku:3</text>
61
+ <text x="232" y="144" class="term dim"> │ </text>
62
+ <text x="256" y="144" class="term sonnet">sonnet:5</text>
63
+ <text x="324" y="144" class="term dim"> │ </text>
64
+ <text x="348" y="144" class="term opus">opus:4</text>
65
+ </g>
66
+
67
+ <!-- Line 5: pack -->
68
+ <g class="line5">
69
+ <text x="24" y="168" class="term tag">[forgen]</text>
70
+ <text x="96" y="168" class="term cmd">Pack: backend v1.0.0 (5 rules, 3 solutions)</text>
71
+ </g>
72
+
73
+ <!-- Line 6: launching -->
74
+ <g class="line6">
75
+ <text x="24" y="192" class="term tag">[forgen]</text>
76
+ <text x="96" y="192" class="term cmd">Starting Claude Code...</text>
77
+ </g>
78
+
79
+ <!-- Separator -->
80
+ <g class="line7">
81
+ <line x1="24" y1="212" x2="776" y2="212" stroke="#313244" stroke-width="1"/>
82
+
83
+ <!-- Claude Code box -->
84
+ <text x="24" y="236" class="term dim">╭──────────────────────────────────────────────────╮</text>
85
+ <text x="24" y="256" class="term dim">│</text>
86
+ <text x="40" y="256" class="term box"> ✓ Claude Code (philosophy-driven mode)</text>
87
+ <text x="430" y="256" class="term dim">│</text>
88
+ <text x="24" y="276" class="term dim">│</text>
89
+ <text x="40" y="276" class="term" fill="#cdd6f4"> 19 agents │ 19 skills │ 18 hooks loaded</text>
90
+ <text x="430" y="276" class="term dim">│</text>
91
+ <text x="24" y="296" class="term dim">╰──────────────────────────────────────────────────╯</text>
92
+
93
+ <!-- Blinking cursor -->
94
+ <rect x="24" y="310" width="8" height="16" fill="#cdd6f4" class="cursor"/>
95
+ </g>
96
+ </svg>
Binary file
@@ -18,5 +18,6 @@
18
18
  { "name": "subagent-tracker-stop", "tier": "workflow", "event": "SubagentStop", "matcher": "*", "script": "hooks/subagent-tracker.js stop", "timeout": 2, "compoundCritical": false },
19
19
  { "name": "post-tool-failure", "tier": "workflow", "event": "PostToolUseFailure", "matcher": "*", "script": "hooks/post-tool-failure.js", "timeout": 3, "compoundCritical": false },
20
20
  { "name": "solution-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/solution-injector.js", "timeout": 5, "compoundCritical": true },
21
- { "name": "skill-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/skill-injector.js", "timeout": 5, "compoundCritical": true }
21
+ { "name": "skill-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/skill-injector.js", "timeout": 5, "compoundCritical": true },
22
+ { "name": "forge-loop-progress", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/forge-loop-progress.js", "timeout": 2, "compoundCritical": false }
22
23
  ]
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Forgen v0.4.1 — TEST-3: 결론 vs 검증 비율 가드
3
+ *
4
+ * Claude 응답 텍스트에서 **결론 키워드** 와 **검증 키워드** 빈도 비율을 측정.
5
+ * 결론 / 검증 > 3 이면 "결론을 쏟아내지만 검증이 부족한" 합의-기반 완료 선언
6
+ * 패턴 — stop-guard 에서 block.
7
+ *
8
+ * 배경 (RC3): v0.4.0 self-interview 에서 "통과했다 / 완료됐다" 같은 결론이
9
+ * 한 응답에 5~8회 반복되지만 "테스트 실행했나 / 증거가 뭔가" 관련 표현은
10
+ * 0회인 케이스 반복 관찰. TEST-1 이 "측정 도구 호출 0건" 을 봤다면, TEST-3
11
+ * 은 같은 문제를 **텍스트-내부** 비율로 잡는다 (도구 호출이 있어도 서술이
12
+ * 결론-편향이면 감지).
13
+ *
14
+ * 순수 함수 — Stop hook 이 `block_message` 로 주입할 수 있도록 reason 문자열을
15
+ * 직접 반환.
16
+ */
17
+ export interface RatioCheckInput {
18
+ text: string;
19
+ /** 비율 임계값. 기본 3 (결론이 검증의 3배 넘으면 block). */
20
+ threshold?: number;
21
+ /**
22
+ * 결론/검증 둘 다 합쳐 이 개수 미만이면 판정 보류 (sparse text).
23
+ * 기본 4 — 짧은 1-2줄 응답에 오탐 방지.
24
+ */
25
+ minTotal?: number;
26
+ }
27
+ export interface RatioCheckResult {
28
+ /** true = 결론 편향 감지 — block 후보. */
29
+ block: boolean;
30
+ conclusionCount: number;
31
+ verificationCount: number;
32
+ /** 검증이 0이면 Infinity, 아니면 결론/검증. */
33
+ ratio: number;
34
+ /** block 시 stop-guard block_message 로 주입할 사람-읽기 문장. */
35
+ reason: string;
36
+ }
37
+ export declare function checkConclusionVerificationRatio(input: RatioCheckInput): RatioCheckResult;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Forgen v0.4.1 — TEST-3: 결론 vs 검증 비율 가드
3
+ *
4
+ * Claude 응답 텍스트에서 **결론 키워드** 와 **검증 키워드** 빈도 비율을 측정.
5
+ * 결론 / 검증 > 3 이면 "결론을 쏟아내지만 검증이 부족한" 합의-기반 완료 선언
6
+ * 패턴 — stop-guard 에서 block.
7
+ *
8
+ * 배경 (RC3): v0.4.0 self-interview 에서 "통과했다 / 완료됐다" 같은 결론이
9
+ * 한 응답에 5~8회 반복되지만 "테스트 실행했나 / 증거가 뭔가" 관련 표현은
10
+ * 0회인 케이스 반복 관찰. TEST-1 이 "측정 도구 호출 0건" 을 봤다면, TEST-3
11
+ * 은 같은 문제를 **텍스트-내부** 비율로 잡는다 (도구 호출이 있어도 서술이
12
+ * 결론-편향이면 감지).
13
+ *
14
+ * 순수 함수 — Stop hook 이 `block_message` 로 주입할 수 있도록 reason 문자열을
15
+ * 직접 반환.
16
+ */
17
+ /** 결론 키워드 — 상태를 단정적으로 선언하는 어휘. */
18
+ const CONCLUSION_PATTERNS = [
19
+ /\b(pass(es|ed)?|passing)\b/gi,
20
+ /\b(done|ready|shipped|finished|complete)\b/gi,
21
+ /\bLGTM\b/g,
22
+ /\bconfirmed\b/gi,
23
+ /\bverified\b/gi,
24
+ /\bvalidated\b/gi,
25
+ /(통과(했|됐|함|합니다))/g,
26
+ /(완료(했|됐|됨|됐습니다))/g,
27
+ /(성공(했|했습니다|적))/g,
28
+ /(동작(합니다|함|한다))/g,
29
+ ];
30
+ /** 검증 키워드 — 측정/확인/실행 행위를 서술하는 어휘. */
31
+ const VERIFICATION_PATTERNS = [
32
+ /\b(test(s|ed|ing)?|tested)\b/gi,
33
+ /\b(verify|verifying|verification)\b/gi,
34
+ /\b(check(ed|ing)?)\b/gi,
35
+ /\b(run|ran|running)\b/gi,
36
+ /\b(measure(d|ment)?)\b/gi,
37
+ /\bevidence\b/gi,
38
+ /증거/g,
39
+ /테스트/g,
40
+ /확인/g,
41
+ /검증/g,
42
+ /실행/g,
43
+ /측정/g,
44
+ ];
45
+ function countMatches(text, patterns) {
46
+ let n = 0;
47
+ for (const p of patterns) {
48
+ const m = text.match(p);
49
+ if (m)
50
+ n += m.length;
51
+ }
52
+ return n;
53
+ }
54
+ export function checkConclusionVerificationRatio(input) {
55
+ const threshold = input.threshold ?? 3;
56
+ const minTotal = input.minTotal ?? 4;
57
+ const conclusionCount = countMatches(input.text, CONCLUSION_PATTERNS);
58
+ const verificationCount = countMatches(input.text, VERIFICATION_PATTERNS);
59
+ const total = conclusionCount + verificationCount;
60
+ const ratio = verificationCount === 0
61
+ ? (conclusionCount === 0 ? 0 : Infinity)
62
+ : conclusionCount / verificationCount;
63
+ // sparse text → 판정 보류
64
+ if (total < minTotal) {
65
+ return {
66
+ block: false,
67
+ conclusionCount,
68
+ verificationCount,
69
+ ratio,
70
+ reason: '',
71
+ };
72
+ }
73
+ // 결론이 전혀 없으면 비율 자체가 의미 없음
74
+ if (conclusionCount === 0) {
75
+ return { block: false, conclusionCount, verificationCount, ratio, reason: '' };
76
+ }
77
+ const block = ratio > threshold;
78
+ let reason = '';
79
+ if (block) {
80
+ reason =
81
+ verificationCount === 0
82
+ ? `결론 ${conclusionCount}건 vs 검증 0건. 완료 선언 전에 실제 실행/측정 증거 (npm test, curl, Read 결과 등) 를 턴에 포함시켜 재응답.`
83
+ : `결론/검증 비율 ${ratio.toFixed(1)} (${conclusionCount}/${verificationCount}) > ${threshold}. 결론에 비해 검증 서술이 적음 — 증거(실행 결과/측정값) 를 추가하여 재응답.`;
84
+ }
85
+ return { block, conclusionCount, verificationCount, ratio, reason };
86
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Forgen v0.4.1 — TEST-1: 사실 vs 합의 가드
3
+ *
4
+ * 목적: Claude 가 "동작합니다 / 통과했습니다 / 검증됐습니다" 같은 **사실 주장**을
5
+ * 내놓을 때, 그 턴(또는 최근 N턴)에 실제 측정/검증을 수행한 도구 호출이 있었는가?
6
+ * 측정 없이 합의(agreement)만으로 사실로 변환된다면 alert.
7
+ *
8
+ * 배경 (RC1): v0.4.0 릴리즈 직전 self-assessment 에서 점수가 조금씩 올라가는데
9
+ * 측정 도구 호출은 0건인 케이스가 반복. 메타 점수 인플레이션 (TEST-2 / US-13)
10
+ * 의 직전 단계. 여기서는 alert 레벨까지만 — block 은 TEST-2 에서.
11
+ *
12
+ * 순수 함수 설계: I/O 없이 텍스트 + 측정 신호 메타데이터만 받아 판정.
13
+ * Stop hook / session scorer / CLI 어느 쪽에서도 호출 가능.
14
+ */
15
+ /** TEST-1 판정 입력. */
16
+ export interface FactCheckInput {
17
+ /** Claude 의 최근 턴 응답 텍스트. */
18
+ text: string;
19
+ /**
20
+ * 최근 N 턴에서 실행된 도구 이름 목록 (중복 OK). 없으면 빈 배열.
21
+ * 호출지가 0턴/전체 세션 등 윈도우를 결정한다.
22
+ */
23
+ recentTools: string[];
24
+ /**
25
+ * optional: 측정으로 간주할 최소 tool count. 기본 1.
26
+ * 빌드/테스트같은 확정 측정 1회면 충분하다고 간주.
27
+ */
28
+ minMeasurements?: number;
29
+ }
30
+ export interface FactCheckResult {
31
+ /** true = 측정 없는 사실-주장 감지, alert 필요. */
32
+ alert: boolean;
33
+ /** 매칭된 사실-주장 키워드 (최대 3개). */
34
+ factAssertions: string[];
35
+ /** 감지된 합의/추측 신호 (최대 3개). */
36
+ agreementSofteners: string[];
37
+ /** 관찰된 측정성 도구 호출 수. */
38
+ measurementCount: number;
39
+ /** 호출지가 surface 하기 좋은 사람-읽기 이유. */
40
+ reason: string;
41
+ }
42
+ /**
43
+ * 핵심 판정 — 텍스트에 사실-주장이 있고 측정 도구가 없으면 alert.
44
+ * 측정이 있거나 사실-주장이 없으면 alert=false.
45
+ * 합의 softener 는 참고용 — softener 많을수록 reason 에 경고 추가.
46
+ */
47
+ export declare function checkFactVsAgreement(input: FactCheckInput): FactCheckResult;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Forgen v0.4.1 — TEST-1: 사실 vs 합의 가드
3
+ *
4
+ * 목적: Claude 가 "동작합니다 / 통과했습니다 / 검증됐습니다" 같은 **사실 주장**을
5
+ * 내놓을 때, 그 턴(또는 최근 N턴)에 실제 측정/검증을 수행한 도구 호출이 있었는가?
6
+ * 측정 없이 합의(agreement)만으로 사실로 변환된다면 alert.
7
+ *
8
+ * 배경 (RC1): v0.4.0 릴리즈 직전 self-assessment 에서 점수가 조금씩 올라가는데
9
+ * 측정 도구 호출은 0건인 케이스가 반복. 메타 점수 인플레이션 (TEST-2 / US-13)
10
+ * 의 직전 단계. 여기서는 alert 레벨까지만 — block 은 TEST-2 에서.
11
+ *
12
+ * 순수 함수 설계: I/O 없이 텍스트 + 측정 신호 메타데이터만 받아 판정.
13
+ * Stop hook / session scorer / CLI 어느 쪽에서도 호출 가능.
14
+ */
15
+ /**
16
+ * 측정성 도구 — 실행 결과가 사실 주장을 뒷받침할 수 있는 카테고리.
17
+ *
18
+ * v0.4.1 coverage fix: TEST-2 와 같은 논리로, Read/Edit/Write/Grep/Glob 은 파일
19
+ * 내용 확인/수정이지 "통과/검증/완료" 같은 실 실행 주장을 뒷받침 못 함. 오직
20
+ * Bash (실 실행) + NotebookEdit (실행 결과) 만 strong measurement.
21
+ *
22
+ * 이전 넓은 집합은 신규 사용자 시나리오 (buyer-day1 R4) 에서 Claude 가 Read
23
+ * 한 번만 해도 alert 회피 → TEST-1 본 의도 훼손.
24
+ */
25
+ const MEASUREMENT_TOOL_CATEGORIES = new Set([
26
+ 'Bash',
27
+ 'NotebookEdit',
28
+ ]);
29
+ /** 사실-주장 키워드 — "측정됐다/검증됐다" 류 강한 확정 언어. */
30
+ const FACT_ASSERTION_PATTERNS = [
31
+ /\b(pass(es|ed)?|passing)\b/i,
32
+ /\bverified\b/i,
33
+ /\bconfirmed\b/i,
34
+ /\bvalidated\b/i,
35
+ /\ball tests? pass/i,
36
+ /(통과(했|됐|함|합니다))/,
37
+ /(검증(됐|했|됨|완료))/,
38
+ /(동작(합니다|함|한다))/,
39
+ /(성공(했|했습니다|적))/,
40
+ /(완료(했|됐|됨|됐습니다))/,
41
+ ];
42
+ /** 합의/추측 표현 — 측정 없이 확언으로 가는 다리. 이 패턴이 많으면 합의→사실 전환 위험. */
43
+ const AGREEMENT_SOFTENERS = [
44
+ /\b(should|would|might)\s+(work|pass)/i,
45
+ /\blikely\b/i,
46
+ /\bprobably\b/i,
47
+ /(생각합니다|생각함|생각해|봅니다|예상(합니다|돼))/,
48
+ /(그럴\s*것\s*같|맞을\s*것\s*같)/,
49
+ ];
50
+ function findMatches(text, patterns, max = 3) {
51
+ const out = [];
52
+ for (const p of patterns) {
53
+ if (out.length >= max)
54
+ break;
55
+ const m = text.match(p);
56
+ if (m)
57
+ out.push(m[0]);
58
+ }
59
+ return out;
60
+ }
61
+ /**
62
+ * 핵심 판정 — 텍스트에 사실-주장이 있고 측정 도구가 없으면 alert.
63
+ * 측정이 있거나 사실-주장이 없으면 alert=false.
64
+ * 합의 softener 는 참고용 — softener 많을수록 reason 에 경고 추가.
65
+ */
66
+ export function checkFactVsAgreement(input) {
67
+ const { text, recentTools } = input;
68
+ const minMeasurements = input.minMeasurements ?? 1;
69
+ const factAssertions = findMatches(text, FACT_ASSERTION_PATTERNS);
70
+ const agreementSofteners = findMatches(text, AGREEMENT_SOFTENERS);
71
+ const measurementCount = recentTools.filter((t) => MEASUREMENT_TOOL_CATEGORIES.has(t)).length;
72
+ const hasFactAssertion = factAssertions.length > 0;
73
+ const measurementMissing = measurementCount < minMeasurements;
74
+ const alert = hasFactAssertion && measurementMissing;
75
+ let reason = '';
76
+ if (alert) {
77
+ const parts = [];
78
+ parts.push(`사실-주장 키워드 ${factAssertions.length}건 감지 ("${factAssertions.join('", "')}")`);
79
+ parts.push(`그러나 최근 측정 도구 호출 ${measurementCount}회 (< ${minMeasurements})`);
80
+ if (agreementSofteners.length > 0) {
81
+ parts.push(`합의성 표현 ${agreementSofteners.length}건 (${agreementSofteners.join(', ')})`);
82
+ }
83
+ reason = parts.join('. ');
84
+ }
85
+ return {
86
+ alert,
87
+ factAssertions,
88
+ agreementSofteners,
89
+ measurementCount,
90
+ reason,
91
+ };
92
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Forgen v0.4.1 — TEST-2: 자가 점수 인플레이션 가드
3
+ *
4
+ * Claude 가 자신의 작업 품질/확신도/완성도를 **숫자**로 상향 선언하면서 해당
5
+ * 턴(또는 세션)에 측정 도구 호출이 0 건이면 block. TEST-1 (사실 vs 합의) 보다
6
+ * 강한 신호 — 구체적 숫자 인플레이션은 합의-기반 자기-아부(sycophancy)의
7
+ * 가장 또렷한 표식.
8
+ *
9
+ * 배경 (RC2): v0.4.0 self-interview 에서 "8/10", "신뢰도 90%", "0.85 → 0.95"
10
+ * 같은 자가 점수가 턴마다 올라갔지만 `npm test` / `curl` / `Read` 등 실제
11
+ * 측정 호출은 0건. TEST-1 이 서술체 사실 주장을 잡았다면, TEST-2 는 **숫자**
12
+ * 점수의 인플레이션에 초점을 맞춘다.
13
+ *
14
+ * 순수 함수 — Stop hook block 경로에 붙는다.
15
+ */
16
+ export interface SelfScoreCheckInput {
17
+ text: string;
18
+ /** 이번 턴(또는 윈도우) 내 실행된 도구 이름 목록. */
19
+ recentTools: string[];
20
+ /** score delta 임계 — 이 이상의 증가를 인플레이션으로 간주. 기본 0 (모든 상승). */
21
+ minDelta?: number;
22
+ /** 측정 도구 최소 호출 수 — 기본 1. */
23
+ minMeasurements?: number;
24
+ }
25
+ export interface SelfScoreCheckResult {
26
+ /** true = 자가 점수 인플레이션 감지 (측정 없이 숫자 증가 선언). block 대상. */
27
+ block: boolean;
28
+ /** 매칭된 점수 표현 raw 스트링 (최대 3개). */
29
+ scoreSignals: string[];
30
+ /** 감지된 positive delta 목록 (from → to). */
31
+ deltas: Array<{
32
+ from: number;
33
+ to: number;
34
+ }>;
35
+ measurementCount: number;
36
+ reason: string;
37
+ }
38
+ export declare function checkSelfScoreInflation(input: SelfScoreCheckInput): SelfScoreCheckResult;