@winspan/claude-forge 8.53.2 → 8.54.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 (390) hide show
  1. package/DEVELOPMENT.md +290 -221
  2. package/README.md +50 -8
  3. package/dist/cli/commands/skills.d.ts.map +1 -1
  4. package/dist/cli/commands/skills.js +7 -3
  5. package/dist/cli/commands/skills.js.map +1 -1
  6. package/dist/cli/init/hook-manager.d.ts +1 -1
  7. package/dist/cli/init/hook-manager.d.ts.map +1 -1
  8. package/dist/cli/init/hook-manager.js +1 -0
  9. package/dist/cli/init/hook-manager.js.map +1 -1
  10. package/dist/core/storage/events.d.ts.map +1 -1
  11. package/dist/core/storage/events.js +0 -1
  12. package/dist/core/storage/events.js.map +1 -1
  13. package/dist/core/storage/maintenance.d.ts +25 -3
  14. package/dist/core/storage/maintenance.d.ts.map +1 -1
  15. package/dist/core/storage/maintenance.js +33 -4
  16. package/dist/core/storage/maintenance.js.map +1 -1
  17. package/dist/core/storage/routing.d.ts +4 -0
  18. package/dist/core/storage/routing.d.ts.map +1 -1
  19. package/dist/core/storage/routing.js +10 -4
  20. package/dist/core/storage/routing.js.map +1 -1
  21. package/dist/core/storage/sessions.d.ts +17 -0
  22. package/dist/core/storage/sessions.d.ts.map +1 -1
  23. package/dist/core/storage/sessions.js +64 -0
  24. package/dist/core/storage/sessions.js.map +1 -1
  25. package/dist/core/storage/skills.d.ts +4 -0
  26. package/dist/core/storage/skills.d.ts.map +1 -1
  27. package/dist/core/storage/skills.js +10 -2
  28. package/dist/core/storage/skills.js.map +1 -1
  29. package/dist/core/storage/sqlite.d.ts +5 -0
  30. package/dist/core/storage/sqlite.d.ts.map +1 -1
  31. package/dist/core/storage/sqlite.js +6 -0
  32. package/dist/core/storage/sqlite.js.map +1 -1
  33. package/dist/core/storage/tasks.d.ts.map +1 -1
  34. package/dist/core/storage/tasks.js +2 -0
  35. package/dist/core/storage/tasks.js.map +1 -1
  36. package/dist/core/types.d.ts +7 -0
  37. package/dist/core/types.d.ts.map +1 -1
  38. package/dist/daemon/index.d.ts.map +1 -1
  39. package/dist/daemon/index.js +19 -4
  40. package/dist/daemon/index.js.map +1 -1
  41. package/dist/skills/registry.d.ts.map +1 -1
  42. package/dist/skills/registry.js +13 -2
  43. package/dist/skills/registry.js.map +1 -1
  44. package/dist/skills/semantic-matcher.d.ts +2 -2
  45. package/dist/skills/semantic-matcher.d.ts.map +1 -1
  46. package/dist/skills/semantic-matcher.js +14 -19
  47. package/dist/skills/semantic-matcher.js.map +1 -1
  48. package/dist/skills/upgrade-engine.d.ts +3 -1
  49. package/dist/skills/upgrade-engine.d.ts.map +1 -1
  50. package/dist/skills/upgrade-engine.js +25 -14
  51. package/dist/skills/upgrade-engine.js.map +1 -1
  52. package/dist/web/analytics/weekly-report.d.ts.map +1 -1
  53. package/dist/web/analytics/weekly-report.js +21 -29
  54. package/dist/web/analytics/weekly-report.js.map +1 -1
  55. package/dist/web/routes/patch.d.ts.map +1 -1
  56. package/dist/web/routes/patch.js +32 -2
  57. package/dist/web/routes/patch.js.map +1 -1
  58. package/dist/web/routes/sessions.d.ts.map +1 -1
  59. package/dist/web/routes/sessions.js +9 -7
  60. package/dist/web/routes/sessions.js.map +1 -1
  61. package/dist/web/routes/trace.d.ts.map +1 -1
  62. package/dist/web/routes/trace.js +2 -3
  63. package/dist/web/routes/trace.js.map +1 -1
  64. package/dist/web/server.d.ts.map +1 -1
  65. package/dist/web/server.js +3 -2
  66. package/dist/web/server.js.map +1 -1
  67. package/package.json +12 -2
  68. package/scripts/postinstall.cjs +21 -0
  69. package/.claude/CLAUDE.md +0 -17
  70. package/.eslintrc.js +0 -23
  71. package/.prettierrc +0 -8
  72. package/ARCHITECTURE_ISSUES.md +0 -249
  73. package/CLAUDE.md +0 -265
  74. package/CLAUDE.md.backup +0 -488
  75. package/docs/concurrent-agents.md +0 -129
  76. package/docs/design/architecture-review-20260516.md +0 -232
  77. package/docs/design/fix-skills-data-and-set-leak-spec-20260516-1300.md +0 -219
  78. package/docs/design/h1-storage-aggregation-spec-20260518-1121.md +0 -299
  79. package/docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md +0 -191
  80. package/docs/design/h3-fallback-removal-spec-20260518-1245.md +0 -76
  81. package/docs/design/h4-index-dedup-spec-20260518-1230.md +0 -109
  82. package/docs/design/h6-services-migration-spec-20260518-1355.md +0 -82
  83. package/docs/design/hook-failure-queue-spec-20260516-1530.md +0 -204
  84. package/docs/design/l1-swarm-protocol-extract-spec-20260518-1605.md +0 -106
  85. package/docs/design/m10-forge-paths-spec-20260518-1320.md +0 -121
  86. package/docs/design/m2-m3-tool-input-spec-20260518-1425.md +0 -131
  87. package/docs/design/m7-routing-event-association-spec-20260518-1545.md +0 -103
  88. package/docs/design/project-path-gitroot-spec-20260518-1715.md +0 -134
  89. package/docs/design/refactor-phase1-spec-20260515-1600.md +0 -543
  90. package/docs/design/refactor-phase2-spec-20260515-1700.md +0 -424
  91. package/docs/design/skill-ai-upgrade-spec-20260518-1930.md +0 -297
  92. package/docs/design/task-active-gc-spec-20260518-1745.md +0 -146
  93. package/docs/design/tasks-list-filter-pagination-spec-20260518-0930.md +0 -208
  94. package/docs/implementation/daemon-skill-sync-changelog-20260518-2000.md +0 -22
  95. package/docs/implementation/fix-skills-data-and-set-leak-changelog-20260516-1300.md +0 -104
  96. package/docs/implementation/h1-storage-aggregation-changelog-20260518-1121.md +0 -82
  97. package/docs/implementation/h2-final-changelog-20260518-1530.md +0 -61
  98. package/docs/implementation/h2-phase1-safety-net-changelog-20260518-1450.md +0 -70
  99. package/docs/implementation/h2-phase2-operations-changelog-20260518-1450.md +0 -120
  100. package/docs/implementation/h2-phase3-callsites-changelog-20260518-1450.md +0 -71
  101. package/docs/implementation/h3-fallback-removal-changelog-20260518-1245.md +0 -71
  102. package/docs/implementation/h4-index-dedup-changelog-20260518-1230.md +0 -60
  103. package/docs/implementation/h6-services-migration-changelog-20260518-1355.md +0 -46
  104. package/docs/implementation/h7-m9-defaults-changelog-20260518-1300.md +0 -46
  105. package/docs/implementation/hook-failure-queue-changelog-20260516-1530.md +0 -196
  106. package/docs/implementation/hotfix-daemon-event-reject-20260516-1430.md +0 -56
  107. package/docs/implementation/l1-swarm-protocol-extract-changelog-20260518-1605.md +0 -45
  108. package/docs/implementation/l3-l4-daemon-perf-changelog-20260518-1410.md +0 -63
  109. package/docs/implementation/l6-l8-final-cleanup-changelog-20260518-1640.md +0 -38
  110. package/docs/implementation/m1-m4-m5-l7-cleanup-changelog-20260518-1310.md +0 -58
  111. package/docs/implementation/m10-forge-paths-changelog-20260518-1320.md +0 -60
  112. package/docs/implementation/m2-m3-tool-input-changelog-20260518-1425.md +0 -43
  113. package/docs/implementation/m6-m8-naming-shutdown-changelog-20260518-1340.md +0 -56
  114. package/docs/implementation/m7-routing-association-changelog-20260518-1545.md +0 -69
  115. package/docs/implementation/project-path-gitroot-changelog-20260518-1715.md +0 -63
  116. package/docs/implementation/refactor-phase1-changelog-20260515-1630.md +0 -354
  117. package/docs/implementation/refactor-phase2-changelog-20260515-1705.md +0 -421
  118. package/docs/implementation/skill-ai-upgrade-changelog-20260518-1930.md +0 -49
  119. package/docs/implementation/task-active-gc-changelog-20260518-1745.md +0 -35
  120. package/docs/implementation/task-title-summary-changelog-20260518-1130.md +0 -39
  121. package/docs/implementation/tasks-detail-back-loses-filters-changelog-20260518-1100.md +0 -22
  122. package/docs/implementation/tasks-list-filter-pagination-changelog-20260518-0930.md +0 -72
  123. package/docs/implementation/tasks-page-white-screen-hotfix-changelog-20260518-1015.md +0 -56
  124. package/docs/reviews/claudemd-template-sync.md +0 -54
  125. package/docs/reviews/task-title-summary.md +0 -92
  126. package/docs/reviews/tasks-detail-back-loses-filters.md +0 -58
  127. package/docs/reviews/tasks-filter-pagination.md +0 -80
  128. package/docs/reviews/tasks-page-white-screen-hotfix.md +0 -126
  129. package/docs/ruflo-learning-strategy.md +0 -322
  130. package/docs/skills-deduplication-analysis.md +0 -83
  131. package/docs/skills-multiformat-support.md +0 -177
  132. package/docs/skills-third-party.md +0 -183
  133. package/docs/testing/tasks-filter-pagination-test-report.md +0 -86
  134. package/forge +0 -321
  135. package/playwright.config.ts +0 -40
  136. package/scripts/demo-v2.ts +0 -91
  137. package/scripts/dev-daemon.sh +0 -232
  138. package/scripts/dev-web.ts +0 -109
  139. package/scripts/e2e-mcp-link.ts +0 -423
  140. package/scripts/e2e-methodology-quality.ts +0 -253
  141. package/scripts/e2e-routing.ts +0 -456
  142. package/scripts/e2e-user-methodology.ts +0 -326
  143. package/scripts/e2e-web-workflows.ts +0 -299
  144. package/scripts/migrate-legacy-to-dynamic.sql +0 -108
  145. package/scripts/regenerate-execution-docs.ts +0 -116
  146. package/scripts/sync-agent-skills.ts +0 -193
  147. package/scripts/test-hook.sh +0 -71
  148. package/scripts/verify-skill-loading.ts +0 -62
  149. package/src/claudemd/claudemd-generator.ts +0 -568
  150. package/src/claudemd/convention-extractor.ts +0 -69
  151. package/src/claudemd/index.ts +0 -35
  152. package/src/claudemd/persona-manager.ts +0 -88
  153. package/src/claudemd/resume-manager.ts +0 -236
  154. package/src/claudemd/tech-detector.ts +0 -220
  155. package/src/claudemd/templates/swarm-protocol.md +0 -222
  156. package/src/cli/commands/claudemd.ts +0 -84
  157. package/src/cli/commands/config.ts +0 -46
  158. package/src/cli/commands/daemon.ts +0 -310
  159. package/src/cli/commands/executions.ts +0 -115
  160. package/src/cli/commands/init.ts +0 -204
  161. package/src/cli/commands/logs.ts +0 -181
  162. package/src/cli/commands/mcp.ts +0 -242
  163. package/src/cli/commands/menu.ts +0 -357
  164. package/src/cli/commands/skills.ts +0 -328
  165. package/src/cli/commands/stats.ts +0 -73
  166. package/src/cli/commands/status.ts +0 -69
  167. package/src/cli/commands/template.ts +0 -77
  168. package/src/cli/commands/trace.ts +0 -148
  169. package/src/cli/index.ts +0 -42
  170. package/src/cli/init/hook-manager.ts +0 -132
  171. package/src/core/ai/provider.ts +0 -308
  172. package/src/core/ai/types.ts +0 -51
  173. package/src/core/config.ts +0 -124
  174. package/src/core/constants.ts +0 -67
  175. package/src/core/event-fields.ts +0 -32
  176. package/src/core/queue/index.ts +0 -192
  177. package/src/core/storage/base.ts +0 -302
  178. package/src/core/storage/events.ts +0 -434
  179. package/src/core/storage/injections.ts +0 -78
  180. package/src/core/storage/maintenance.ts +0 -59
  181. package/src/core/storage/migrations/002_add_skill_tracking.sql +0 -6
  182. package/src/core/storage/migrations/003_add_skill_invocations.sql +0 -23
  183. package/src/core/storage/performance-indexes.sql +0 -23
  184. package/src/core/storage/routing.ts +0 -322
  185. package/src/core/storage/rows.ts +0 -112
  186. package/src/core/storage/schema.sql +0 -224
  187. package/src/core/storage/sessions.ts +0 -168
  188. package/src/core/storage/skills.ts +0 -233
  189. package/src/core/storage/sqlite.ts +0 -293
  190. package/src/core/storage/tasks.ts +0 -318
  191. package/src/core/storage/token-usage.ts +0 -93
  192. package/src/core/types.ts +0 -181
  193. package/src/core/utils/error-handler.ts +0 -257
  194. package/src/core/utils/forge-resume-block.ts +0 -74
  195. package/src/core/utils/format.ts +0 -69
  196. package/src/core/utils/git.ts +0 -23
  197. package/src/core/utils/logger.ts +0 -134
  198. package/src/core/utils/lru-cache.ts +0 -54
  199. package/src/core/utils/path.ts +0 -19
  200. package/src/core/utils/session.ts +0 -26
  201. package/src/core/utils/time.ts +0 -37
  202. package/src/core/utils/token-tracker.ts +0 -97
  203. package/src/daemon/event-parser.ts +0 -36
  204. package/src/daemon/handlers/history-exporter.ts +0 -117
  205. package/src/daemon/handlers/post-tool-use.ts +0 -54
  206. package/src/daemon/handlers/stop.ts +0 -208
  207. package/src/daemon/handlers/user-prompt.ts +0 -178
  208. package/src/daemon/hook-sync.ts +0 -91
  209. package/src/daemon/index.ts +0 -312
  210. package/src/daemon/launchd/com.claude-forge.daemon.plist.template +0 -47
  211. package/src/daemon/launchd-installer.ts +0 -260
  212. package/src/daemon/lifecycle.ts +0 -128
  213. package/src/daemon/router.ts +0 -40
  214. package/src/daemon/server.ts +0 -196
  215. package/src/daemon/services/task-segmenter.ts +0 -112
  216. package/src/daemon/skill-sync.ts +0 -88
  217. package/src/hooks/hook-lib.sh +0 -118
  218. package/src/hooks/notification.sh +0 -35
  219. package/src/hooks/post-tool-use.sh +0 -61
  220. package/src/hooks/pre-tool-use.sh +0 -63
  221. package/src/hooks/stop.sh +0 -43
  222. package/src/hooks/user-prompt-submit.sh +0 -69
  223. package/src/mcp/server.ts +0 -322
  224. package/src/skills/index.ts +0 -2
  225. package/src/skills/invocation-guard.ts +0 -177
  226. package/src/skills/matcher.ts +0 -148
  227. package/src/skills/official/code-simplifier.md +0 -52
  228. package/src/skills/official/find-skills.md +0 -142
  229. package/src/skills/official/official-api-design.md +0 -30
  230. package/src/skills/official/official-architecture-decision.md +0 -41
  231. package/src/skills/official/official-bmad.md +0 -118
  232. package/src/skills/official/official-db-schema-design.md +0 -34
  233. package/src/skills/official/official-debug.md +0 -25
  234. package/src/skills/official/official-doc-driven.md +0 -31
  235. package/src/skills/official/official-harness-engineering.md +0 -108
  236. package/src/skills/official/official-performance-optimization.md +0 -30
  237. package/src/skills/official/official-pr-review.md +0 -35
  238. package/src/skills/official/official-release-checklist.md +0 -30
  239. package/src/skills/official/official-security-hardening.md +0 -32
  240. package/src/skills/official/official-spec-driven-design.md +0 -31
  241. package/src/skills/official/planning-with-files.md +0 -241
  242. package/src/skills/official/ui-ux-pro-max.md +0 -105
  243. package/src/skills/official/webapp-testing.md +0 -96
  244. package/src/skills/official-skills.ts +0 -89
  245. package/src/skills/registry.ts +0 -355
  246. package/src/skills/semantic-matcher.ts +0 -234
  247. package/src/skills/tools/pipeline-suggest.ts +0 -226
  248. package/src/skills/tools/skill-invoke.ts +0 -168
  249. package/src/skills/tools/skill-list.ts +0 -59
  250. package/src/skills/upgrade-engine.ts +0 -541
  251. package/src/skills/upgrade-prompt.ts +0 -84
  252. package/src/templates/go.yaml +0 -53
  253. package/src/templates/python.yaml +0 -59
  254. package/src/templates/react.yaml +0 -55
  255. package/src/templates/template-manager.ts +0 -170
  256. package/src/web/analytics/anti-pattern-detector.ts +0 -367
  257. package/src/web/analytics/drift-detector.ts +0 -219
  258. package/src/web/analytics/weekly-report.ts +0 -431
  259. package/src/web/auth-middleware.ts +0 -54
  260. package/src/web/routes/_helpers.ts +0 -34
  261. package/src/web/routes/ai.ts +0 -204
  262. package/src/web/routes/auth.ts +0 -22
  263. package/src/web/routes/drift.ts +0 -25
  264. package/src/web/routes/error-handler.ts +0 -120
  265. package/src/web/routes/events.ts +0 -47
  266. package/src/web/routes/insights.ts +0 -43
  267. package/src/web/routes/patch.ts +0 -117
  268. package/src/web/routes/reports.ts +0 -34
  269. package/src/web/routes/rules.ts +0 -76
  270. package/src/web/routes/sessions.ts +0 -250
  271. package/src/web/routes/skill-stats.ts +0 -92
  272. package/src/web/routes/skills.ts +0 -350
  273. package/src/web/routes/static.ts +0 -67
  274. package/src/web/routes/stats.ts +0 -50
  275. package/src/web/routes/status.ts +0 -30
  276. package/src/web/routes/tasks.ts +0 -193
  277. package/src/web/routes/token-usage.ts +0 -20
  278. package/src/web/routes/trace.ts +0 -126
  279. package/src/web/routes/types.ts +0 -57
  280. package/src/web/server.ts +0 -134
  281. package/src/web/ssrf-guard.ts +0 -112
  282. package/src/web/static/index.html +0 -3251
  283. package/src/web/static/vendor/chart.umd.min.js +0 -20
  284. package/tests/e2e/dashboard.spec.ts +0 -205
  285. package/tests/e2e/routing-skill-e2e.test.ts +0 -39
  286. package/tests/helpers/mock-ai.ts +0 -92
  287. package/tests/helpers/mock-storage.ts +0 -159
  288. package/tests/integration/claudemd-generator.test.ts +0 -90
  289. package/tests/integration/queue-replay.integration.test.ts +0 -193
  290. package/tests/integration/tasks-filter.integration.test.ts +0 -154
  291. package/tests/integration/web-analytics.integration.test.ts +0 -133
  292. package/tests/integration/web-stats.integration.test.ts +0 -135
  293. package/tests/integration/web-trace.integration.test.ts +0 -175
  294. package/tests/performance/database.benchmark.ts +0 -161
  295. package/tests/semantic-matcher.test.ts +0 -99
  296. package/tests/skill-matcher.test.ts +0 -110
  297. package/tests/unit/ai-provider-retry.test.ts +0 -194
  298. package/tests/unit/ai-provider-vision.test.ts +0 -224
  299. package/tests/unit/claudemd-generator.test.ts +0 -68
  300. package/tests/unit/cli-mcp.test.ts +0 -141
  301. package/tests/unit/core/forge-paths.test.ts +0 -99
  302. package/tests/unit/daemon/hook-sync.test.ts +0 -71
  303. package/tests/unit/daemon/post-tool-use.test.ts +0 -121
  304. package/tests/unit/daemon/skill-sync.test.ts +0 -75
  305. package/tests/unit/daemon/stop-handler-behavior-summary.test.ts +0 -202
  306. package/tests/unit/daemon/task-segmenter-recover.test.ts +0 -84
  307. package/tests/unit/event-fields.test.ts +0 -88
  308. package/tests/unit/event-parser.test.ts +0 -55
  309. package/tests/unit/handlers.test.ts +0 -171
  310. package/tests/unit/hooks/resolve-project-path.test.ts +0 -122
  311. package/tests/unit/invocation-guard.test.ts +0 -125
  312. package/tests/unit/queue.test.ts +0 -272
  313. package/tests/unit/router.test.ts +0 -138
  314. package/tests/unit/security.test.ts +0 -128
  315. package/tests/unit/skill-invocations-workflow.test.ts +0 -495
  316. package/tests/unit/skill-registry.test.ts +0 -94
  317. package/tests/unit/skills/invocation-guard-ttl.test.ts +0 -211
  318. package/tests/unit/skills/official-skills-loader.test.ts +0 -126
  319. package/tests/unit/skills/registry-multiformat.test.ts +0 -92
  320. package/tests/unit/skills/upgrade-engine-parse.test.ts +0 -138
  321. package/tests/unit/skills/upgrade-engine.test.ts +0 -401
  322. package/tests/unit/skills/upgrade-prompt.test.ts +0 -89
  323. package/tests/unit/socket-server.test.ts +0 -183
  324. package/tests/unit/storage/event-operations-aggregates.test.ts +0 -342
  325. package/tests/unit/storage/migration-idempotent.test.ts +0 -304
  326. package/tests/unit/storage/routing-aggregates.test.ts +0 -276
  327. package/tests/unit/storage/routing.test.ts +0 -117
  328. package/tests/unit/storage/schema-missing.test.ts +0 -81
  329. package/tests/unit/storage/session-operations-aggregates.test.ts +0 -120
  330. package/tests/unit/storage/sessions-aggregate.test.ts +0 -435
  331. package/tests/unit/storage/skill-operations-counts.test.ts +0 -106
  332. package/tests/unit/storage/skills-aggregates.test.ts +0 -104
  333. package/tests/unit/storage/sqlite-refactor-harness.test.ts +0 -314
  334. package/tests/unit/storage/task-operations-counts.test.ts +0 -46
  335. package/tests/unit/storage/tasks-getById.test.ts +0 -343
  336. package/tests/unit/storage/tasks-stale-gc.test.ts +0 -86
  337. package/tests/unit/storage.test.ts +0 -172
  338. package/tests/unit/token-usage.test.ts +0 -144
  339. package/tests/unit/type-guards.test.ts +0 -201
  340. package/tests/unit/utils/format.test.ts +0 -189
  341. package/tests/unit/utils/session.test.ts +0 -89
  342. package/tests/unit/utils/time.test.ts +0 -112
  343. package/tests/unit/web/navigation-back-contract.test.ts +0 -134
  344. package/tests/unit/web/routes-auth.test.ts +0 -93
  345. package/tests/unit/web/routes-events.test.ts +0 -101
  346. package/tests/unit/web/routes-rules.test.ts +0 -182
  347. package/tests/unit/web/routes-sessions.test.ts +0 -181
  348. package/tests/unit/web/routes-skill-stats.test.ts +0 -179
  349. package/tests/unit/web/routes-stats.test.ts +0 -92
  350. package/tests/unit/web/routes-tasks.test.ts +0 -385
  351. package/tests/unit/web/task-title-contract.test.ts +0 -210
  352. package/tests/unit/web/tasks-component-contract.test.ts +0 -179
  353. package/tsconfig.json +0 -22
  354. package/vitest.config.ts +0 -21
  355. package/vitest.integration.config.ts +0 -16
  356. package/web/CLAUDE.md +0 -20
  357. package/web/index.html +0 -13
  358. package/web/package-lock.json +0 -4854
  359. package/web/package.json +0 -35
  360. package/web/postcss.config.js +0 -6
  361. package/web/src/App.tsx +0 -110
  362. package/web/src/components/CodeBlock.tsx +0 -31
  363. package/web/src/components/Confirm.tsx +0 -96
  364. package/web/src/components/Drawer.tsx +0 -60
  365. package/web/src/components/Layout.tsx +0 -145
  366. package/web/src/components/MarkdownRenderer.tsx +0 -77
  367. package/web/src/components/SearchInput.tsx +0 -31
  368. package/web/src/components/SessionDetailContent.tsx +0 -157
  369. package/web/src/components/Toast.tsx +0 -92
  370. package/web/src/index.css +0 -19
  371. package/web/src/main.tsx +0 -31
  372. package/web/src/pages/AIConfig.tsx +0 -233
  373. package/web/src/pages/Dashboard.tsx +0 -572
  374. package/web/src/pages/Events.tsx +0 -271
  375. package/web/src/pages/Reports.tsx +0 -428
  376. package/web/src/pages/SessionDetail.tsx +0 -162
  377. package/web/src/pages/Sessions.tsx +0 -205
  378. package/web/src/pages/Skills.tsx +0 -180
  379. package/web/src/pages/TaskDetail.tsx +0 -515
  380. package/web/src/pages/Tasks.tsx +0 -415
  381. package/web/src/utils/auth.ts +0 -59
  382. package/web/src/utils/export.ts +0 -54
  383. package/web/src/utils/navigation.ts +0 -25
  384. package/web/src/utils/task-title.ts +0 -49
  385. package/web/src/utils/time.ts +0 -13
  386. package/web/tailwind.config.js +0 -11
  387. package/web/tsconfig.json +0 -21
  388. package/web/tsconfig.node.json +0 -10
  389. package/web/vite.config.ts +0 -76
  390. package/winspan-claude-forge-8.43.0.tgz +0 -0
@@ -1,112 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import type { SQLiteStorage } from '../../core/storage/sqlite.js';
3
- import { logger } from '../../core/utils/logger.js';
4
- import { normalizeTimestamp, timestampToMs } from '../../core/utils/time.js';
5
- import { truncateSessionId } from '../../core/utils/session.js';
6
- import { truncateString } from '../../core/utils/format.js';
7
-
8
- const NEW_TASK_KEYWORDS = [
9
- '帮我', '实现', '修复', '添加', '重构', '优化', '创建', '删除',
10
- '升级', '迁移', '部署', '配置', '设计', '提交', '推送',
11
- 'fix', 'add', 'implement', 'refactor', 'create', 'delete', 'deploy',
12
- ];
13
-
14
- const CONTINUE_KEYWORDS = [
15
- '继续', '然后', '还有', '另外', '这个', '那个', '它',
16
- '对', '好的', '可以', '是的', '不是', '不对', '改一下',
17
- ];
18
-
19
- const TASK_SWITCH_MINUTES = 10;
20
-
21
- export class TaskSegmenter {
22
- private currentTasks = new Map<string, { id: string; lastTime: number }>();
23
-
24
- constructor(private storage: SQLiteStorage) {}
25
-
26
- processPrompt(sessionId: string, prompt: string, timestamp: string, eventId?: string): string {
27
- const key = sessionId;
28
- const current = this.currentTasks.get(key) ?? this.recoverActiveTask(key);
29
- const now = timestampToMs(timestamp);
30
-
31
- if (!current || this.shouldStartNewTask(prompt, now, current)) {
32
- if (current) {
33
- this.storage.updateTask(current.id, { status: 'completed', end_time: timestamp });
34
- }
35
- const taskId = this.createTask(sessionId, prompt, timestamp);
36
- this.currentTasks.set(key, { id: taskId, lastTime: now });
37
- if (eventId) this.storage.linkEventToTask(taskId, eventId);
38
- return taskId;
39
- }
40
-
41
- current.lastTime = now;
42
- if (eventId) this.storage.linkEventToTask(current.id, eventId);
43
- return current.id;
44
- }
45
-
46
- linkEvent(sessionId: string, eventId: string): void {
47
- const current = this.currentTasks.get(sessionId) ?? this.recoverActiveTask(sessionId);
48
- if (current) {
49
- this.storage.linkEventToTask(current.id, eventId);
50
- }
51
- }
52
-
53
- /**
54
- * 从数据库恢复 session 的 active 任务到内存 Map。
55
- * 用于 daemon 重启后内存丢失场景的 lazy 恢复。
56
- * 找不到 active 任务时返回 null(不报错)。
57
- */
58
- private recoverActiveTask(sessionId: string): { id: string; lastTime: number } | null {
59
- const tasks = this.storage.queryTasks({ session_id: sessionId, limit: 5 });
60
- const activeTask = tasks.find(t => t.status === 'active');
61
- if (!activeTask) return null;
62
-
63
- const anchor = activeTask.end_time ?? activeTask.start_time;
64
- const lastTime = timestampToMs(anchor);
65
- const entry = { id: activeTask.id, lastTime };
66
- this.currentTasks.set(sessionId, entry);
67
- logger.info(
68
- `[TaskSegmenter] Recovered active task ${truncateString(activeTask.id, 8)} for session ${truncateSessionId(sessionId)} from DB`,
69
- );
70
- return entry;
71
- }
72
-
73
- getCurrentTaskId(sessionId: string): string | null {
74
- return this.currentTasks.get(sessionId)?.id ?? null;
75
- }
76
-
77
- completeCurrentTask(sessionId: string, timestamp: string): void {
78
- const current = this.currentTasks.get(sessionId) ?? this.recoverActiveTask(sessionId);
79
- if (!current) return;
80
- this.storage.updateTask(current.id, {
81
- status: 'completed',
82
- end_time: timestamp,
83
- });
84
- this.currentTasks.delete(sessionId);
85
- }
86
-
87
- private shouldStartNewTask(prompt: string, now: number, current: { lastTime: number }): boolean {
88
- const minutesDiff = (now - current.lastTime) / 60000;
89
- if (minutesDiff > TASK_SWITCH_MINUTES) return true;
90
-
91
- const hasContinue = CONTINUE_KEYWORDS.some(kw => prompt.includes(kw));
92
- if (hasContinue) return false;
93
-
94
- const hasNewTask = NEW_TASK_KEYWORDS.some(kw => prompt.includes(kw));
95
- return hasNewTask;
96
- }
97
-
98
- private createTask(sessionId: string, prompt: string, timestamp: string): string {
99
- const taskId = randomUUID();
100
- const title = this.extractTitle(prompt);
101
- this.storage.writeTask({ id: taskId, session_id: sessionId, title, start_time: timestamp });
102
- logger.info(`[TaskSegmenter] New task: "${title}" (${truncateString(taskId, 8)})`);
103
- return taskId;
104
- }
105
-
106
- private extractTitle(prompt: string): string {
107
- const cleaned = prompt.replace(/\[Image #\d+\]/g, '').trim();
108
- const firstLine = cleaned.split('\n')[0].trim();
109
- if (firstLine.length <= 60) return firstLine || '(无标题)';
110
- return truncateString(firstLine, 60);
111
- }
112
- }
@@ -1,88 +0,0 @@
1
- import { existsSync, readFileSync, copyFileSync, mkdirSync, readdirSync } from 'node:fs';
2
- import { createHash } from 'node:crypto';
3
- import { join, dirname } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { homedir } from 'node:os';
6
- import { logger } from '../core/utils/logger.js';
7
-
8
- const USER_SKILLS_DIR = join(homedir(), '.claude', 'skills');
9
-
10
- function sha256(content: Buffer): string {
11
- return createHash('sha256').update(content).digest('hex');
12
- }
13
-
14
- function getSourceSkillsDir(): string {
15
- // Compiled: dist/daemon/skill-sync.js → dist/skills/official
16
- // Dev (vitest): src/daemon/skill-sync.ts → src/skills/official
17
- return join(dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'official');
18
- }
19
-
20
- export interface SkillSyncResult {
21
- copied: number;
22
- checked: number;
23
- skipped_userOwned: number; // user skills not in source list — untouched
24
- }
25
-
26
- /**
27
- * Sync official skills from dist/skills/official to ~/.claude/skills/.
28
- *
29
- * Strategy:
30
- * - Only files present in the source dir (dist/skills/official) are candidates
31
- * - sha256 identical → skip; different → overwrite
32
- * - User-only skills (not in source list) are never touched
33
- * - Target dir is created if absent (first install)
34
- *
35
- * Failures are logged as warnings and never thrown — daemon startup must not be blocked.
36
- */
37
- export function syncSkills(opts?: { sourceDir?: string; targetDir?: string }): SkillSyncResult {
38
- const result: SkillSyncResult = { copied: 0, checked: 0, skipped_userOwned: 0 };
39
- const sourceDir = opts?.sourceDir ?? getSourceSkillsDir();
40
- const targetDir = opts?.targetDir ?? USER_SKILLS_DIR;
41
-
42
- if (!existsSync(sourceDir)) {
43
- logger.warn(`[SkillSync] source dir not found at ${sourceDir}, skipping`);
44
- return result;
45
- }
46
-
47
- // Ensure target dir exists (first install may not have ~/.claude/skills/)
48
- try {
49
- mkdirSync(targetDir, { recursive: true });
50
- } catch {
51
- /* ignore — if it already exists mkdirSync is a no-op */
52
- }
53
-
54
- let sourceFiles: string[];
55
- try {
56
- sourceFiles = readdirSync(sourceDir).filter((f) => f.endsWith('.md'));
57
- } catch (err) {
58
- logger.warn(`[SkillSync] failed to list ${sourceDir}: ${err}`);
59
- return result;
60
- }
61
-
62
- for (const file of sourceFiles) {
63
- result.checked++;
64
- const src = join(sourceDir, file);
65
- const dest = join(targetDir, file);
66
-
67
- try {
68
- const srcContent = readFileSync(src);
69
- if (existsSync(dest)) {
70
- const destContent = readFileSync(dest);
71
- if (sha256(srcContent) === sha256(destContent)) {
72
- continue; // identical — no copy needed
73
- }
74
- }
75
-
76
- copyFileSync(src, dest);
77
- result.copied++;
78
- logger.info(`[SkillSync] updated ${file}`);
79
- } catch (err) {
80
- logger.warn(`[SkillSync] failed to sync ${file}: ${err instanceof Error ? err.message : String(err)}`);
81
- }
82
- }
83
-
84
- if (result.copied > 0) {
85
- logger.info(`[SkillSync] synced ${result.copied}/${result.checked} skill files`);
86
- }
87
- return result;
88
- }
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - Hook shared library
3
- # Source this file at the top of each hook script:
4
- # source "$(dirname "$0")/hook-lib.sh"
5
- #
6
- # Provides:
7
- # - SOCKET_PATH, QUEUE_DIR shared variables
8
- # - send_event_or_enqueue() function
9
-
10
- SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
11
- QUEUE_DIR="$HOME/.claude-forge/queue"
12
-
13
- # resolve_project_path <input_cwd>
14
- #
15
- # Walk up the directory tree from <input_cwd> to find the nearest ancestor that
16
- # contains a `.git` entry (directory for normal clones, file for worktrees /
17
- # submodules). Print the resolved git-root path on stdout.
18
- #
19
- # Fallback rules:
20
- # - Empty input → start from $PWD
21
- # - Relative input → prefixed with $PWD to absolutise
22
- # - No .git found within 64 levels → print original input unchanged
23
- #
24
- # POSIX-only: uses `dirname` and `case`; does NOT depend on `realpath` or any
25
- # GNU coreutils extensions, so it works on macOS BSD and Linux alike.
26
- resolve_project_path() {
27
- local input="${1:-}"
28
- local dir="${input:-$PWD}"
29
-
30
- # Absolutise: prefix relative paths with $PWD (no realpath dependency)
31
- case "$dir" in
32
- /*) ;;
33
- *) dir="$PWD/$dir" ;;
34
- esac
35
-
36
- local guard=0
37
- while [ "$dir" != "/" ] && [ "$dir" != "." ] && [ $guard -lt 64 ]; do
38
- if [ -d "$dir/.git" ] || [ -f "$dir/.git" ]; then
39
- printf '%s' "$dir"
40
- return 0
41
- fi
42
- dir=$(dirname "$dir")
43
- guard=$((guard + 1))
44
- done
45
-
46
- # No git ancestor found → fall back to the caller's original cwd
47
- printf '%s' "${input:-$PWD}"
48
- }
49
-
50
- # send_event_or_enqueue <event_json> [timeout_seconds]
51
- #
52
- # 1. If socket file does not exist → enqueue in background → return empty string
53
- # 2. If socket exists → send via nc with timeout
54
- # - nc exit code != 0 → enqueue in background → return empty string
55
- # - nc exit code == 0 → return daemon response on stdout
56
- #
57
- # The caller reads REPLY_RESPONSE after calling this function:
58
- # send_event_or_enqueue "$EVENT" 10
59
- # RESPONSE="$HOOK_RESPONSE"
60
- #
61
- # macOS BSD nc notes:
62
- # - `nc -U` opens a Unix domain socket connection
63
- # - `-w N` sets idle timeout (seconds); on macOS this is the "connection timeout"
64
- # for UDP but for TCP/Unix it's inactivity timeout after connection
65
- # - Exit code: 0 = success (data sent + connection closed by remote), 1 = error
66
- # - An empty response (daemon returns nothing) still exits 0 if the connection
67
- # was established and closed cleanly → we check exit code, NOT response content
68
-
69
- HOOK_RESPONSE=""
70
-
71
- send_event_or_enqueue() {
72
- local event_json="$1"
73
- local timeout_secs="${2:-10}"
74
-
75
- HOOK_RESPONSE=""
76
-
77
- # Fast path: no socket file → daemon is not running
78
- if [ ! -S "$SOCKET_PATH" ]; then
79
- _enqueue_event_bg "$event_json"
80
- return 0
81
- fi
82
-
83
- # Socket exists: try to send; capture exit code separately from stdout
84
- local tmp_response
85
- tmp_response=$(echo "$event_json" | nc -U -w "$timeout_secs" "$SOCKET_PATH" 2>/dev/null)
86
- local nc_exit=$?
87
-
88
- if [ $nc_exit -ne 0 ]; then
89
- # nc failed (connection refused, socket disappeared between check and send, etc.)
90
- _enqueue_event_bg "$event_json"
91
- return 0
92
- fi
93
-
94
- # Success: pass response back to caller
95
- HOOK_RESPONSE="$tmp_response"
96
- }
97
-
98
- # _enqueue_event_bg <event_json>
99
- # Forks a background subshell to write the event JSON to the queue directory.
100
- # The main hook process is never blocked by this operation.
101
- _enqueue_event_bg() {
102
- local event_json="$1"
103
- (
104
- mkdir -p "$QUEUE_DIR"
105
- # Timestamp with second precision (BSD date has no %N nanoseconds)
106
- local ts
107
- ts=$(date -u +"%Y%m%dT%H%M%S")
108
- # UUID: prefer uuidgen (macOS), fall back to /proc on Linux
109
- local uuid
110
- uuid=$(uuidgen 2>/dev/null \
111
- || cat /proc/sys/kernel/random/uuid 2>/dev/null \
112
- || printf '%s-%s' "$$" "$RANDOM")
113
- local filename="${ts}-${uuid}.json"
114
- # Atomic write: write to temp file, then rename
115
- local tmp_file="$QUEUE_DIR/.tmp-${filename}"
116
- printf '%s' "$event_json" > "$tmp_file" && mv "$tmp_file" "$QUEUE_DIR/${filename}"
117
- ) &
118
- }
@@ -1,35 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - Notification Hook
3
-
4
- # shellcheck source=./hook-lib.sh
5
- source "$(dirname "$0")/hook-lib.sh"
6
-
7
- AUTH_TOKEN=$(cat "$HOME/.claude-forge/daemon.token" 2>/dev/null || echo '')
8
-
9
- # 读取 stdin
10
- INPUT=$(cat)
11
-
12
- # 提取 cwd(jq 替代 python3)
13
- RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
14
- PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
15
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // .sessionId // ""')
16
- SESSION_ID="${SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-cli}}"
17
-
18
- # 构造事件 JSON(原始 INPUT 作为 tool_input,保留完整通知内容)
19
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
20
- TOOL_INPUT=$(echo "$INPUT" | jq -c '.')
21
- EVENT=$(jq -nc \
22
- --arg hook_type "Notification" \
23
- --arg timestamp "$TIMESTAMP" \
24
- --arg session_id "$SESSION_ID" \
25
- --arg project_path "$PROJECT_PATH" \
26
- --argjson tool_input "$TOOL_INPUT" \
27
- --arg auth "$AUTH_TOKEN" \
28
- '{hook_type: $hook_type, timestamp: $timestamp, session_id: $session_id,
29
- project_path: $project_path, tool_name: "notification",
30
- tool_input: $tool_input, _auth: $auth}')
31
-
32
- # 发送到 daemon(1 秒超时;失败时入队)
33
- send_event_or_enqueue "$EVENT" 1
34
-
35
- exit 0
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - PostToolUse Hook
3
-
4
- # shellcheck source=./hook-lib.sh
5
- source "$(dirname "$0")/hook-lib.sh"
6
-
7
- AUTH_TOKEN=$(cat "$HOME/.claude-forge/daemon.token" 2>/dev/null || echo '')
8
-
9
- # 读取 stdin
10
- INPUT=$(cat)
11
-
12
- # 提取字段(单次 jq 调用,替代 4 个 python3 进程)
13
- # tool_response 是 Claude Code 的字段名
14
- TOOL_NAME="${CLAUDE_TOOL_NAME:-$(echo "$INPUT" | jq -r '.tool_name // ""')}"
15
- TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // {}')
16
- TOOL_OUTPUT=$(echo "$INPUT" | jq -c '.tool_response // {}')
17
- RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
18
- PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
19
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // .sessionId // ""')
20
- SESSION_ID="${SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-cli}}"
21
-
22
- # 构造事件 JSON
23
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
24
- EVENT=$(jq -nc \
25
- --arg hook_type "PostToolUse" \
26
- --arg timestamp "$TIMESTAMP" \
27
- --arg session_id "$SESSION_ID" \
28
- --arg project_path "$PROJECT_PATH" \
29
- --arg tool_name "$TOOL_NAME" \
30
- --argjson tool_input "$TOOL_INPUT" \
31
- --argjson tool_output "$TOOL_OUTPUT" \
32
- --arg auth "$AUTH_TOKEN" \
33
- '{hook_type: $hook_type, timestamp: $timestamp, session_id: $session_id,
34
- project_path: $project_path, tool_name: $tool_name, tool_input: $tool_input,
35
- tool_output: $tool_output, _auth: $auth}')
36
-
37
- # 发送到 daemon(PostToolUse 也需要等待响应以支持通知注入;失败时入队)
38
- send_event_or_enqueue "$EVENT" 5
39
- RESPONSE="$HOOK_RESPONSE"
40
-
41
- if [ -n "$RESPONSE" ]; then
42
- # 硬阻断:优先使用 hookSpecificOutput(Claude Code 官方格式)
43
- ALLOW=$(echo "$RESPONSE" | jq -r '.allow // true')
44
- if [ "$ALLOW" = "false" ]; then
45
- HAS_HOOK_OUTPUT=$(echo "$RESPONSE" | jq -r 'if .hookSpecificOutput then "yes" else "no" end')
46
- if [ "$HAS_HOOK_OUTPUT" = "yes" ]; then
47
- echo "$RESPONSE" | jq '{hookSpecificOutput: .hookSpecificOutput}'
48
- exit 0
49
- else
50
- REASON=$(echo "$RESPONSE" | jq -r '.reason // "Pipeline 已阻断"')
51
- echo "$REASON" >&2
52
- exit 2
53
- fi
54
- fi
55
-
56
- HAS_CONTEXT=$(echo "$RESPONSE" | jq -r 'if .additionalContext and (.additionalContext != "") then "yes" else "no" end')
57
- if [ "$HAS_CONTEXT" = "yes" ]; then
58
- echo "$RESPONSE"
59
- fi
60
- fi
61
- exit 0
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - PreToolUse Hook(双向通信)
3
-
4
- # shellcheck source=./hook-lib.sh
5
- source "$(dirname "$0")/hook-lib.sh"
6
-
7
- AUTH_TOKEN=$(cat "$HOME/.claude-forge/daemon.token" 2>/dev/null || echo '')
8
-
9
- # 读取 stdin(Claude Code 传入的 JSON)
10
- INPUT=$(cat)
11
-
12
- # 提取字段(单次 jq 调用,替代 3 个 python3 进程)
13
- TOOL_NAME="${CLAUDE_TOOL_NAME:-$(echo "$INPUT" | jq -r '.tool_name // ""')}"
14
- TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // {}')
15
- RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
16
- PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
17
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // .sessionId // ""')
18
- SESSION_ID="${SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-cli}}"
19
-
20
- # 构造事件 JSON(jq -n 替代 python3 heredoc)
21
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
22
- EVENT=$(jq -nc \
23
- --arg hook_type "PreToolUse" \
24
- --arg timestamp "$TIMESTAMP" \
25
- --arg session_id "$SESSION_ID" \
26
- --arg project_path "$PROJECT_PATH" \
27
- --arg tool_name "$TOOL_NAME" \
28
- --argjson tool_input "$TOOL_INPUT" \
29
- --arg auth "$AUTH_TOKEN" \
30
- '{hook_type: $hook_type, timestamp: $timestamp, session_id: $session_id,
31
- project_path: $project_path, tool_name: $tool_name, tool_input: $tool_input,
32
- _auth: $auth}')
33
-
34
- # 发送事件(5 秒超时;失败时入队)
35
- send_event_or_enqueue "$EVENT" 5
36
- RESPONSE="$HOOK_RESPONSE"
37
-
38
- if [ -n "$RESPONSE" ]; then
39
- ALLOW=$(echo "$RESPONSE" | jq -r '.allow // true')
40
-
41
- if [ "$ALLOW" = "false" ]; then
42
- # 优先使用 hookSpecificOutput(Claude Code 官方格式),否则降级到 stderr + exit 2
43
- HAS_HOOK_OUTPUT=$(echo "$RESPONSE" | jq -r 'if .hookSpecificOutput then "yes" else "no" end')
44
- if [ "$HAS_HOOK_OUTPUT" = "yes" ]; then
45
- # 输出 hookSpecificOutput 格式到 stdout,但必须 exit 非0 才能真正阻止工具执行
46
- echo "$RESPONSE" | jq '{hookSpecificOutput: .hookSpecificOutput}'
47
- exit 1
48
- else
49
- # 降级:输出原因到 stderr,exit 2 强制阻断
50
- REASON=$(echo "$RESPONSE" | jq -r '.reason // "操作被 Forge 阻断"')
51
- echo "$REASON" >&2
52
- exit 2
53
- fi
54
- fi
55
-
56
- # 有 additionalContext 时输出
57
- HAS_CONTEXT=$(echo "$RESPONSE" | jq -r 'if .additionalContext and (.additionalContext != "") then "yes" else "no" end')
58
- if [ "$HAS_CONTEXT" = "yes" ]; then
59
- echo "$RESPONSE"
60
- fi
61
- fi
62
-
63
- exit 0
package/src/hooks/stop.sh DELETED
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - Stop Hook
3
-
4
- # shellcheck source=./hook-lib.sh
5
- source "$(dirname "$0")/hook-lib.sh"
6
-
7
- AUTH_TOKEN=$(cat "$HOME/.claude-forge/daemon.token" 2>/dev/null || echo '')
8
-
9
- # 读取 stdin
10
- INPUT=$(cat 2>/dev/null || echo '{}')
11
-
12
- # 提取 cwd,上溯 git root
13
- RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
14
- PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
15
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // .sessionId // ""')
16
- SESSION_ID="${SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-cli}}"
17
-
18
- # 构造事件 JSON
19
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
20
- EVENT=$(jq -nc \
21
- --arg hook_type "Stop" \
22
- --arg timestamp "$TIMESTAMP" \
23
- --arg session_id "$SESSION_ID" \
24
- --arg project_path "$PROJECT_PATH" \
25
- --arg auth "$AUTH_TOKEN" \
26
- '{hook_type: $hook_type, timestamp: $timestamp, session_id: $session_id,
27
- project_path: $project_path, tool_name: "stop", tool_input: {}, _auth: $auth}')
28
-
29
- # 发送事件并读取响应(失败时入队)
30
- send_event_or_enqueue "$EVENT" 5
31
- RESPONSE="$HOOK_RESPONSE"
32
-
33
- # 解析响应:allow=false 时输出 reason 并以 exit 2 阻断
34
- if [ -n "$RESPONSE" ]; then
35
- ALLOW=$(echo "$RESPONSE" | jq -r '.allow // true' 2>/dev/null)
36
- if [ "$ALLOW" = "false" ]; then
37
- REASON=$(echo "$RESPONSE" | jq -r '.reason // "质量门禁阻断"' 2>/dev/null)
38
- echo "$REASON"
39
- exit 2
40
- fi
41
- fi
42
-
43
- exit 0
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Claude Forge - UserPromptSubmit Hook
3
- # 拦截用户输入,触发意图分析和自动 Pipeline 编排
4
-
5
- # shellcheck source=./hook-lib.sh
6
- source "$(dirname "$0")/hook-lib.sh"
7
-
8
- AUTH_TOKEN=$(cat "$HOME/.claude-forge/daemon.token" 2>/dev/null || echo '')
9
-
10
- # 读取 stdin(Claude Code 传入的 JSON)
11
- INPUT=$(cat)
12
-
13
- # 提取字段(jq 替代 python3)
14
- USER_PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""')
15
- RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
16
- PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
17
- SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // .sessionId // ""')
18
- SESSION_ID="${SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-cli}}"
19
-
20
- # 空 prompt 跳过
21
- if [ -z "$USER_PROMPT" ]; then
22
- exit 0
23
- fi
24
-
25
- # 构造事件 JSON(jq -n 替代 python3 heredoc)
26
- TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
27
- EVENT=$(jq -nc \
28
- --arg hook_type "UserPromptSubmit" \
29
- --arg timestamp "$TIMESTAMP" \
30
- --arg session_id "$SESSION_ID" \
31
- --arg project_path "$PROJECT_PATH" \
32
- --arg user_prompt "$USER_PROMPT" \
33
- --arg auth "$AUTH_TOKEN" \
34
- '{hook_type: $hook_type, timestamp: $timestamp, session_id: $session_id,
35
- project_path: $project_path, tool_name: "UserPrompt",
36
- user_prompt: $user_prompt, tool_input: {user_prompt: $user_prompt}, _auth: $auth}')
37
-
38
- if [ -z "$EVENT" ]; then
39
- exit 0
40
- fi
41
-
42
- # 发送事件(10 秒超时,AI 分析可能需要更多时间)
43
- # 失败时自动入队(daemon 停机期间事件不丢失)
44
- send_event_or_enqueue "$EVENT" 10
45
- RESPONSE="$HOOK_RESPONSE"
46
-
47
- if [ -n "$RESPONSE" ]; then
48
- HAS_SYSTEM=$(echo "$RESPONSE" | jq -r 'if .systemMessage and (.systemMessage != "") then "yes" else "no" end')
49
- HAS_CONTEXT=$(echo "$RESPONSE" | jq -r 'if .additionalContext and (.additionalContext != "") then "yes" else "no" end')
50
-
51
- if [ "$HAS_SYSTEM" = "yes" ] || [ "$HAS_CONTEXT" = "yes" ]; then
52
- # stderr 输出摘要到终端
53
- if [ "$HAS_SYSTEM" = "yes" ]; then
54
- SM_LEN=$(echo "$RESPONSE" | jq -r '.systemMessage | length')
55
- printf '\033[36m💉 [Forge] 注入 systemMessage (%s chars)\033[0m\n' "$SM_LEN" >&2
56
- fi
57
- if [ "$HAS_CONTEXT" = "yes" ]; then
58
- CONTEXT=$(echo "$RESPONSE" | jq -r '.additionalContext // ""')
59
- DISPLAY_LINES=$(printf '%s' "$CONTEXT" | head -3)
60
- if [ -n "$DISPLAY_LINES" ]; then
61
- printf '\033[36m💉 [Forge] %s\033[0m\n' "$DISPLAY_LINES" >&2
62
- fi
63
- fi
64
- # stdout 返回给 Claude Code
65
- echo "$RESPONSE"
66
- fi
67
- fi
68
-
69
- exit 0