@winspan/claude-forge 8.50.6 → 8.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +7 -7
- package/dist/claudemd/claudemd-generator.d.ts.map +1 -1
- package/dist/claudemd/claudemd-generator.js +27 -237
- package/dist/claudemd/claudemd-generator.js.map +1 -1
- package/dist/claudemd/resume-manager.js +1 -1
- package/dist/claudemd/resume-manager.js.map +1 -1
- package/dist/claudemd/templates/swarm-protocol.md +222 -0
- package/dist/cli/commands/daemon.js +6 -6
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/executions.d.ts.map +1 -1
- package/dist/cli/commands/executions.js +4 -3
- package/dist/cli/commands/executions.js.map +1 -1
- package/dist/cli/commands/init.js +2 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/logs.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +3 -5
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/menu.d.ts.map +1 -1
- package/dist/cli/commands/menu.js +4 -3
- package/dist/cli/commands/menu.js.map +1 -1
- package/dist/cli/commands/stats.d.ts.map +1 -1
- package/dist/cli/commands/stats.js +2 -3
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/status.js +2 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/trace.d.ts.map +1 -1
- package/dist/cli/commands/trace.js +11 -23
- package/dist/cli/commands/trace.js.map +1 -1
- package/dist/cli/init/hook-manager.d.ts.map +1 -1
- package/dist/cli/init/hook-manager.js +2 -2
- package/dist/cli/init/hook-manager.js.map +1 -1
- package/dist/core/ai/provider.js +2 -2
- package/dist/core/ai/provider.js.map +1 -1
- package/dist/core/constants.d.ts +12 -1
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +15 -1
- package/dist/core/constants.js.map +1 -1
- package/dist/core/event-fields.d.ts +16 -0
- package/dist/core/event-fields.d.ts.map +1 -0
- package/dist/core/event-fields.js +19 -0
- package/dist/core/event-fields.js.map +1 -0
- package/dist/core/queue/index.d.ts.map +1 -1
- package/dist/core/queue/index.js +3 -4
- package/dist/core/queue/index.js.map +1 -1
- package/dist/core/storage/base.d.ts +36 -3
- package/dist/core/storage/base.d.ts.map +1 -1
- package/dist/core/storage/base.js +101 -58
- package/dist/core/storage/base.js.map +1 -1
- package/dist/core/storage/events.d.ts +92 -3
- package/dist/core/storage/events.d.ts.map +1 -1
- package/dist/core/storage/events.js +147 -0
- package/dist/core/storage/events.js.map +1 -1
- package/dist/core/storage/routing.d.ts +54 -1
- package/dist/core/storage/routing.d.ts.map +1 -1
- package/dist/core/storage/routing.js +99 -1
- package/dist/core/storage/routing.js.map +1 -1
- package/dist/core/storage/schema.sql +12 -2
- package/dist/core/storage/sessions.d.ts +20 -0
- package/dist/core/storage/sessions.d.ts.map +1 -1
- package/dist/core/storage/sessions.js +59 -0
- package/dist/core/storage/sessions.js.map +1 -1
- package/dist/core/storage/skills.d.ts +23 -0
- package/dist/core/storage/skills.d.ts.map +1 -1
- package/dist/core/storage/skills.js +47 -0
- package/dist/core/storage/skills.js.map +1 -1
- package/dist/core/storage/sqlite.d.ts +35 -2
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +93 -4
- package/dist/core/storage/sqlite.js.map +1 -1
- package/dist/core/storage/tasks.d.ts +49 -0
- package/dist/core/storage/tasks.d.ts.map +1 -1
- package/dist/core/storage/tasks.js +143 -1
- package/dist/core/storage/tasks.js.map +1 -1
- package/dist/core/storage/token-usage.d.ts +1 -1
- package/dist/core/storage/token-usage.d.ts.map +1 -1
- package/dist/core/storage/token-usage.js +1 -1
- package/dist/core/storage/token-usage.js.map +1 -1
- package/dist/core/types.d.ts +24 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/error-handler.d.ts.map +1 -1
- package/dist/core/utils/error-handler.js +3 -2
- package/dist/core/utils/error-handler.js.map +1 -1
- package/dist/core/utils/git.d.ts +10 -0
- package/dist/core/utils/git.d.ts.map +1 -0
- package/dist/core/utils/git.js +24 -0
- package/dist/core/utils/git.js.map +1 -0
- package/dist/core/utils/logger.d.ts.map +1 -1
- package/dist/core/utils/logger.js +15 -1
- package/dist/core/utils/logger.js.map +1 -1
- package/dist/core/utils/lru-cache.d.ts +1 -0
- package/dist/core/utils/lru-cache.d.ts.map +1 -1
- package/dist/core/utils/lru-cache.js +3 -0
- package/dist/core/utils/lru-cache.js.map +1 -1
- package/dist/core/utils/token-tracker.js +1 -1
- package/dist/core/utils/token-tracker.js.map +1 -1
- package/dist/daemon/event-parser.d.ts.map +1 -1
- package/dist/daemon/event-parser.js +2 -1
- package/dist/daemon/event-parser.js.map +1 -1
- package/dist/daemon/handlers/history-exporter.js.map +1 -1
- package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
- package/dist/daemon/handlers/post-tool-use.js +7 -3
- package/dist/daemon/handlers/post-tool-use.js.map +1 -1
- package/dist/daemon/handlers/stop.d.ts +4 -0
- package/dist/daemon/handlers/stop.d.ts.map +1 -1
- package/dist/daemon/handlers/stop.js +23 -35
- package/dist/daemon/handlers/stop.js.map +1 -1
- package/dist/daemon/handlers/user-prompt.d.ts +3 -3
- package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
- package/dist/daemon/handlers/user-prompt.js +12 -22
- package/dist/daemon/handlers/user-prompt.js.map +1 -1
- package/dist/daemon/hook-sync.d.ts +17 -0
- package/dist/daemon/hook-sync.d.ts.map +1 -0
- package/dist/daemon/hook-sync.js +74 -0
- package/dist/daemon/hook-sync.js.map +1 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +33 -9
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/lifecycle.js +3 -4
- package/dist/daemon/lifecycle.js.map +1 -1
- package/dist/daemon/server.d.ts +6 -4
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +76 -85
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/services/task-segmenter.js +1 -1
- package/dist/daemon/services/task-segmenter.js.map +1 -1
- package/dist/hooks/hook-lib.sh +37 -0
- package/dist/hooks/notification.sh +2 -2
- package/dist/hooks/post-tool-use.sh +2 -2
- package/dist/hooks/pre-tool-use.sh +2 -2
- package/dist/hooks/stop.sh +9 -6
- package/dist/hooks/user-prompt-submit.sh +2 -2
- package/dist/{daemon/services → web/analytics}/anti-pattern-detector.d.ts +3 -4
- package/dist/web/analytics/anti-pattern-detector.d.ts.map +1 -0
- package/dist/{daemon/services → web/analytics}/anti-pattern-detector.js +7 -46
- package/dist/{daemon/services → web/analytics}/anti-pattern-detector.js.map +1 -1
- package/dist/web/analytics/drift-detector.d.ts.map +1 -0
- package/dist/{daemon/services → web/analytics}/drift-detector.js +10 -13
- package/dist/web/analytics/drift-detector.js.map +1 -0
- package/dist/web/analytics/weekly-report.d.ts.map +1 -0
- package/dist/{daemon/services → web/analytics}/weekly-report.js +51 -50
- package/dist/web/analytics/weekly-report.js.map +1 -0
- package/dist/web/auth-middleware.d.ts.map +1 -1
- package/dist/web/auth-middleware.js +1 -2
- package/dist/web/auth-middleware.js.map +1 -1
- package/dist/web/routes/_helpers.d.ts +16 -0
- package/dist/web/routes/_helpers.d.ts.map +1 -0
- package/dist/web/routes/_helpers.js +32 -0
- package/dist/web/routes/_helpers.js.map +1 -0
- package/dist/web/routes/drift.js +1 -1
- package/dist/web/routes/drift.js.map +1 -1
- package/dist/web/routes/insights.js +1 -1
- package/dist/web/routes/insights.js.map +1 -1
- package/dist/web/routes/reports.js +1 -1
- package/dist/web/routes/reports.js.map +1 -1
- package/dist/web/routes/rules.d.ts +3 -0
- package/dist/web/routes/rules.d.ts.map +1 -1
- package/dist/web/routes/rules.js +28 -52
- package/dist/web/routes/rules.js.map +1 -1
- package/dist/web/routes/sessions.d.ts.map +1 -1
- package/dist/web/routes/sessions.js +16 -30
- package/dist/web/routes/sessions.js.map +1 -1
- package/dist/web/routes/skill-stats.d.ts +2 -0
- package/dist/web/routes/skill-stats.d.ts.map +1 -1
- package/dist/web/routes/skill-stats.js +28 -64
- package/dist/web/routes/skill-stats.js.map +1 -1
- package/dist/web/routes/skills.d.ts.map +1 -1
- package/dist/web/routes/skills.js +5 -4
- package/dist/web/routes/skills.js.map +1 -1
- package/dist/web/routes/stats.d.ts +4 -0
- package/dist/web/routes/stats.d.ts.map +1 -1
- package/dist/web/routes/stats.js +19 -21
- package/dist/web/routes/stats.js.map +1 -1
- package/dist/web/routes/tasks.d.ts.map +1 -1
- package/dist/web/routes/tasks.js +17 -42
- package/dist/web/routes/tasks.js.map +1 -1
- package/dist/web/routes/trace.d.ts.map +1 -1
- package/dist/web/routes/trace.js +7 -17
- package/dist/web/routes/trace.js.map +1 -1
- package/dist/web/routes/types.d.ts.map +1 -1
- package/dist/web/routes/types.js +4 -3
- package/dist/web/routes/types.js.map +1 -1
- package/dist/web/static/assets/{AIConfig-BQCAQE9D.js → AIConfig-CdDWzJyO.js} +2 -2
- package/dist/web/static/assets/{AIConfig-BQCAQE9D.js.map → AIConfig-CdDWzJyO.js.map} +1 -1
- package/dist/web/static/assets/{Dashboard-D7Bo6Kan.js → Dashboard-CoEmmIDt.js} +2 -2
- package/dist/web/static/assets/{Dashboard-D7Bo6Kan.js.map → Dashboard-CoEmmIDt.js.map} +1 -1
- package/dist/web/static/assets/{Drawer-BeHRQxUS.js → Drawer-DdRTzlLB.js} +2 -2
- package/dist/web/static/assets/{Drawer-BeHRQxUS.js.map → Drawer-DdRTzlLB.js.map} +1 -1
- package/dist/web/static/assets/{Events-K_tCY2ti.js → Events-DrIq1SUS.js} +2 -2
- package/dist/web/static/assets/{Events-K_tCY2ti.js.map → Events-DrIq1SUS.js.map} +1 -1
- package/dist/web/static/assets/{Reports-BJCmBnc_.js → Reports-DFBM3MDK.js} +2 -2
- package/dist/web/static/assets/{Reports-BJCmBnc_.js.map → Reports-DFBM3MDK.js.map} +1 -1
- package/dist/web/static/assets/{SearchInput-BX2KhMkw.js → SearchInput-qCj_jAcf.js} +2 -2
- package/dist/web/static/assets/{SearchInput-BX2KhMkw.js.map → SearchInput-qCj_jAcf.js.map} +1 -1
- package/dist/web/static/assets/{SessionDetail-Bkr-kC7V.js → SessionDetail-CCzwdoT7.js} +2 -2
- package/dist/web/static/assets/{SessionDetail-Bkr-kC7V.js.map → SessionDetail-CCzwdoT7.js.map} +1 -1
- package/dist/web/static/assets/{Sessions-Chx9OCLH.js → Sessions-FfLYkAw9.js} +2 -2
- package/dist/web/static/assets/{Sessions-Chx9OCLH.js.map → Sessions-FfLYkAw9.js.map} +1 -1
- package/dist/web/static/assets/{Skills-O0GT1i7m.js → Skills-C8Gvs3Qa.js} +2 -2
- package/dist/web/static/assets/{Skills-O0GT1i7m.js.map → Skills-C8Gvs3Qa.js.map} +1 -1
- package/dist/web/static/assets/TaskDetail-BS8pYhaR.js +2 -0
- package/dist/web/static/assets/TaskDetail-BS8pYhaR.js.map +1 -0
- package/dist/web/static/assets/Tasks-CyuhizG8.js +2 -0
- package/dist/web/static/assets/Tasks-CyuhizG8.js.map +1 -0
- package/dist/web/static/assets/index-CBX47X8l.js +3 -0
- package/dist/web/static/assets/{index-DxIbmNmr.js.map → index-CBX47X8l.js.map} +1 -1
- package/dist/web/static/assets/index-DjIoMdoR.css +1 -0
- package/dist/web/static/assets/{lucide-fJlPI3H7.js → lucide-Bs_edTLa.js} +44 -39
- package/dist/web/static/assets/lucide-Bs_edTLa.js.map +1 -0
- package/dist/web/static/assets/react-router-r79dBVy4.js +20 -0
- package/dist/web/static/assets/{react-router-I-HqunH7.js.map → react-router-r79dBVy4.js.map} +1 -1
- package/dist/web/static/assets/task-title-BhOcemuR.js +2 -0
- package/dist/web/static/assets/task-title-BhOcemuR.js.map +1 -0
- package/dist/web/static/index.html +4 -4
- package/docs/design/h1-storage-aggregation-spec-20260518-1121.md +299 -0
- package/docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md +191 -0
- package/docs/design/h3-fallback-removal-spec-20260518-1245.md +76 -0
- package/docs/design/h4-index-dedup-spec-20260518-1230.md +109 -0
- package/docs/design/h6-services-migration-spec-20260518-1355.md +82 -0
- package/docs/design/l1-swarm-protocol-extract-spec-20260518-1605.md +106 -0
- package/docs/design/m10-forge-paths-spec-20260518-1320.md +121 -0
- package/docs/design/m2-m3-tool-input-spec-20260518-1425.md +131 -0
- package/docs/design/m7-routing-event-association-spec-20260518-1545.md +103 -0
- package/docs/design/project-path-gitroot-spec-20260518-1715.md +134 -0
- package/docs/design/task-active-gc-spec-20260518-1745.md +146 -0
- package/docs/implementation/h1-storage-aggregation-changelog-20260518-1121.md +82 -0
- package/docs/implementation/h2-final-changelog-20260518-1530.md +61 -0
- package/docs/implementation/h2-phase1-safety-net-changelog-20260518-1450.md +70 -0
- package/docs/implementation/h2-phase2-operations-changelog-20260518-1450.md +120 -0
- package/docs/implementation/h2-phase3-callsites-changelog-20260518-1450.md +71 -0
- package/docs/implementation/h3-fallback-removal-changelog-20260518-1245.md +71 -0
- package/docs/implementation/h4-index-dedup-changelog-20260518-1230.md +60 -0
- package/docs/implementation/h6-services-migration-changelog-20260518-1355.md +46 -0
- package/docs/implementation/h7-m9-defaults-changelog-20260518-1300.md +46 -0
- package/docs/implementation/l1-swarm-protocol-extract-changelog-20260518-1605.md +45 -0
- package/docs/implementation/l3-l4-daemon-perf-changelog-20260518-1410.md +63 -0
- package/docs/implementation/l6-l8-final-cleanup-changelog-20260518-1640.md +38 -0
- package/docs/implementation/m1-m4-m5-l7-cleanup-changelog-20260518-1310.md +58 -0
- package/docs/implementation/m10-forge-paths-changelog-20260518-1320.md +60 -0
- package/docs/implementation/m2-m3-tool-input-changelog-20260518-1425.md +43 -0
- package/docs/implementation/m6-m8-naming-shutdown-changelog-20260518-1340.md +56 -0
- package/docs/implementation/m7-routing-association-changelog-20260518-1545.md +69 -0
- package/docs/implementation/project-path-gitroot-changelog-20260518-1715.md +63 -0
- package/docs/implementation/task-active-gc-changelog-20260518-1745.md +35 -0
- package/docs/implementation/task-title-summary-changelog-20260518-1130.md +39 -0
- package/docs/implementation/tasks-detail-back-loses-filters-changelog-20260518-1100.md +22 -0
- package/docs/implementation/tasks-page-white-screen-hotfix-changelog-20260518-1015.md +56 -0
- package/docs/reviews/task-title-summary.md +92 -0
- package/docs/reviews/tasks-detail-back-loses-filters.md +58 -0
- package/docs/reviews/tasks-page-white-screen-hotfix.md +126 -0
- package/package.json +2 -2
- package/src/claudemd/claudemd-generator.ts +29 -238
- package/src/claudemd/resume-manager.ts +1 -1
- package/src/claudemd/templates/swarm-protocol.md +222 -0
- package/src/cli/commands/daemon.ts +6 -6
- package/src/cli/commands/executions.ts +4 -3
- package/src/cli/commands/init.ts +2 -2
- package/src/cli/commands/logs.ts +1 -1
- package/src/cli/commands/mcp.ts +3 -5
- package/src/cli/commands/menu.ts +4 -3
- package/src/cli/commands/stats.ts +2 -3
- package/src/cli/commands/status.ts +2 -2
- package/src/cli/commands/trace.ts +10 -26
- package/src/cli/init/hook-manager.ts +2 -2
- package/src/core/ai/provider.ts +2 -2
- package/src/core/constants.ts +18 -1
- package/src/core/event-fields.ts +32 -0
- package/src/core/queue/index.ts +3 -4
- package/src/core/storage/base.ts +132 -56
- package/src/core/storage/events.ts +183 -4
- package/src/core/storage/routing.ts +129 -1
- package/src/core/storage/schema.sql +12 -2
- package/src/core/storage/sessions.ts +64 -0
- package/src/core/storage/skills.ts +69 -0
- package/src/core/storage/sqlite.ts +103 -4
- package/src/core/storage/tasks.ts +149 -1
- package/src/core/storage/token-usage.ts +1 -1
- package/src/core/types.ts +30 -3
- package/src/core/utils/error-handler.ts +3 -2
- package/src/core/utils/git.ts +23 -0
- package/src/core/utils/logger.ts +16 -1
- package/src/core/utils/lru-cache.ts +4 -0
- package/src/core/utils/token-tracker.ts +1 -1
- package/src/daemon/event-parser.ts +4 -3
- package/src/daemon/handlers/history-exporter.ts +1 -1
- package/src/daemon/handlers/post-tool-use.ts +7 -3
- package/src/daemon/handlers/stop.ts +32 -39
- package/src/daemon/handlers/user-prompt.ts +12 -22
- package/src/daemon/hook-sync.ts +91 -0
- package/src/daemon/index.ts +34 -10
- package/src/daemon/lifecycle.ts +3 -3
- package/src/daemon/server.ts +76 -89
- package/src/daemon/services/task-segmenter.ts +1 -1
- package/src/hooks/hook-lib.sh +37 -0
- package/src/hooks/notification.sh +2 -2
- package/src/hooks/post-tool-use.sh +2 -2
- package/src/hooks/pre-tool-use.sh +2 -2
- package/src/hooks/stop.sh +9 -6
- package/src/hooks/user-prompt-submit.sh +2 -2
- package/src/{daemon/services → web/analytics}/anti-pattern-detector.ts +9 -54
- package/src/{daemon/services → web/analytics}/drift-detector.ts +10 -23
- package/src/{daemon/services → web/analytics}/weekly-report.ts +52 -75
- package/src/web/auth-middleware.ts +1 -2
- package/src/web/routes/_helpers.ts +34 -0
- package/src/web/routes/drift.ts +1 -1
- package/src/web/routes/insights.ts +1 -1
- package/src/web/routes/reports.ts +1 -1
- package/src/web/routes/rules.ts +31 -56
- package/src/web/routes/sessions.ts +18 -30
- package/src/web/routes/skill-stats.ts +29 -69
- package/src/web/routes/skills.ts +5 -4
- package/src/web/routes/stats.ts +19 -29
- package/src/web/routes/tasks.ts +17 -42
- package/src/web/routes/trace.ts +7 -19
- package/src/web/routes/types.ts +4 -3
- package/tests/integration/claudemd-generator.test.ts +90 -0
- package/tests/integration/web-analytics.integration.test.ts +133 -0
- package/tests/integration/web-stats.integration.test.ts +135 -0
- package/tests/integration/web-trace.integration.test.ts +175 -0
- package/tests/unit/core/forge-paths.test.ts +99 -0
- package/tests/unit/daemon/hook-sync.test.ts +71 -0
- package/tests/unit/daemon/post-tool-use.test.ts +121 -0
- package/tests/unit/daemon/stop-handler-behavior-summary.test.ts +202 -0
- package/tests/unit/daemon/task-segmenter-recover.test.ts +84 -0
- package/tests/unit/event-fields.test.ts +88 -0
- package/tests/unit/event-parser.test.ts +55 -0
- package/tests/unit/hooks/resolve-project-path.test.ts +122 -0
- package/tests/unit/socket-server.test.ts +183 -0
- package/tests/unit/storage/event-operations-aggregates.test.ts +342 -0
- package/tests/unit/storage/migration-idempotent.test.ts +304 -0
- package/tests/unit/storage/routing-aggregates.test.ts +276 -0
- package/tests/unit/storage/routing.test.ts +117 -0
- package/tests/unit/storage/schema-missing.test.ts +81 -0
- package/tests/unit/storage/session-operations-aggregates.test.ts +120 -0
- package/tests/unit/storage/skill-operations-counts.test.ts +106 -0
- package/tests/unit/storage/skills-aggregates.test.ts +104 -0
- package/tests/unit/storage/sqlite-refactor-harness.test.ts +3 -3
- package/tests/unit/storage/task-operations-counts.test.ts +46 -0
- package/tests/unit/storage/tasks-getById.test.ts +343 -0
- package/tests/unit/storage/tasks-stale-gc.test.ts +86 -0
- package/tests/unit/token-usage.test.ts +6 -6
- package/tests/unit/web/navigation-back-contract.test.ts +134 -0
- package/tests/unit/web/routes-rules.test.ts +182 -0
- package/tests/unit/web/routes-tasks.test.ts +34 -0
- package/tests/unit/web/task-title-contract.test.ts +210 -0
- package/tests/unit/web/tasks-component-contract.test.ts +179 -0
- package/vitest.config.ts +1 -1
- package/web/src/pages/TaskDetail.tsx +9 -5
- package/web/src/pages/Tasks.tsx +315 -50
- package/web/src/utils/navigation.ts +25 -0
- package/web/src/utils/task-title.ts +49 -0
- package/dist/daemon/services/anti-pattern-detector.d.ts.map +0 -1
- package/dist/daemon/services/drift-detector.d.ts.map +0 -1
- package/dist/daemon/services/drift-detector.js.map +0 -1
- package/dist/daemon/services/weekly-report.d.ts.map +0 -1
- package/dist/daemon/services/weekly-report.js.map +0 -1
- package/dist/web/static/assets/TaskDetail-5SR8zGzv.js +0 -2
- package/dist/web/static/assets/TaskDetail-5SR8zGzv.js.map +0 -1
- package/dist/web/static/assets/Tasks-DCgDqvOZ.js +0 -2
- package/dist/web/static/assets/Tasks-DCgDqvOZ.js.map +0 -1
- package/dist/web/static/assets/index-D8AKj26b.css +0 -1
- package/dist/web/static/assets/index-DxIbmNmr.js +0 -3
- package/dist/web/static/assets/lucide-fJlPI3H7.js.map +0 -1
- package/dist/web/static/assets/react-router-I-HqunH7.js +0 -20
- /package/dist/{daemon/services → web/analytics}/drift-detector.d.ts +0 -0
- /package/dist/{daemon/services → web/analytics}/weekly-report.d.ts +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# project-path git root 修复 Spec
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
让 5 个 hook 在 IDE 调用时把 `cwd`(可能是任意子目录)上溯为 git 仓库根目录后再发给 daemon,从根上阻止子目录被生成 `.claude-forge/`。
|
|
5
|
+
|
|
6
|
+
## 调研结果
|
|
7
|
+
|
|
8
|
+
| 位置 | 现状 | 改造需求 |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `src/hooks/pre-tool-use.sh:15-16` | `PROJECT_PATH=$(jq -r '.cwd'); fallback $PWD` | 套上 `resolve_project_path` |
|
|
11
|
+
| `src/hooks/post-tool-use.sh:17-18` | 同上 | 同上 |
|
|
12
|
+
| `src/hooks/user-prompt-submit.sh:15-16` | 同上 | 同上 |
|
|
13
|
+
| `src/hooks/stop.sh:11-12` | 同上 + 未引用 hook-lib.sh | 先 source hook-lib.sh 再用函数 |
|
|
14
|
+
| `src/hooks/notification.sh:13-14` | 同上 | 同上 |
|
|
15
|
+
| `src/hooks/hook-lib.sh` | 已有 `send_event_or_enqueue` 公共函数 | **新增 `resolve_project_path`** |
|
|
16
|
+
| `src/daemon/handlers/history-exporter.ts:24` | `path.join(project_path,'.claude-forge','history')` | 不动(hook 端已传 git root) |
|
|
17
|
+
| `src/cli/commands/executions.ts:16,53,85` | `process.cwd()` 拼 `.claude-forge` | 新增 `resolveGitRoot()` helper |
|
|
18
|
+
| `src/templates/template-manager.ts:82,89` | `initProject(_, projectPath)` 由调用方传入 | 调用方传 git root 即可(init CLI 自身改) |
|
|
19
|
+
|
|
20
|
+
观察:`hook-lib.sh` 已存在公共函数集,`stop.sh` 是唯一未 source 它的 hook(手写 nc + socket),改造时顺手补齐一致性。
|
|
21
|
+
|
|
22
|
+
## 方案选择
|
|
23
|
+
|
|
24
|
+
| | A. Hook 端解析 git root | B. Daemon 端解析 | C. 完全消除目录 | D. 混合 hash |
|
|
25
|
+
|---|---|---|---|---|
|
|
26
|
+
| 改动面 | 5 hook + lib + CLI | 1 处 | 涉及多模块迁移 | A+ 存储改造 |
|
|
27
|
+
| 性能 | bash 上溯(O(深度),无子进程)| 每次 spawn `git` | 同 A | 同 A |
|
|
28
|
+
| 下游受益 | 全部 | 仅 history-exporter | 全部但破坏可见性 | 全部 |
|
|
29
|
+
| 老数据 | 兼容(新数据用新值)| 兼容 | 需迁移 | 需迁移 |
|
|
30
|
+
| 风险 | 0 测试 hook 改动 | 子进程开销 | discoverability 破坏 | 引入新维度 |
|
|
31
|
+
|
|
32
|
+
**推荐 A**:根因解决 + 保留用户在项目根 `ls` 即可看到 history 的可见性 + 不引入子进程开销。bash `while` 上溯零依赖,daemon / CLI 自动受益。
|
|
33
|
+
|
|
34
|
+
## 改造范围(约 70 行)
|
|
35
|
+
|
|
36
|
+
| 文件 | 行数 | 说明 |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `src/hooks/hook-lib.sh` | +25 | 新增 `resolve_project_path` |
|
|
39
|
+
| `src/hooks/pre-tool-use.sh` | -2 +1 | 替换两行 |
|
|
40
|
+
| `src/hooks/post-tool-use.sh` | -2 +1 | 同上 |
|
|
41
|
+
| `src/hooks/user-prompt-submit.sh` | -2 +1 | 同上 |
|
|
42
|
+
| `src/hooks/stop.sh` | -2 +2 | 先 source hook-lib.sh,再用函数 |
|
|
43
|
+
| `src/hooks/notification.sh` | -2 +1 | 同上 |
|
|
44
|
+
| `src/cli/commands/executions.ts` | +8 | 新增 `resolveGitRoot()` 替换 3 处 `process.cwd()` |
|
|
45
|
+
| `src/cli/commands/init.ts`(调用 template-manager 处,需 grep 确认)| +2 | 把传给 `initProject` 的 `projectPath` 改成 git root |
|
|
46
|
+
| 新增 `tests/unit/hooks/resolve-project-path.test.sh`(或 vitest 调 bash)| ~40 | safety-net |
|
|
47
|
+
| 新增 `tests/integration/hook-gitroot.integration.test.ts` | ~50 | 端到端 |
|
|
48
|
+
|
|
49
|
+
## hook-lib.sh 公共函数设计
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# resolve_project_path <input_cwd>
|
|
53
|
+
# 从 input_cwd 上溯查找最近的 .git 目录,输出 git root。
|
|
54
|
+
# 非 git 项目 / 上溯到根 / 输入为空 → 回退到 input_cwd(再回退到 $PWD)。
|
|
55
|
+
# 防御:最多上溯 64 层,避免符号链接环。
|
|
56
|
+
resolve_project_path() {
|
|
57
|
+
local dir="${1:-$PWD}"
|
|
58
|
+
[ -z "$dir" ] && dir="$PWD"
|
|
59
|
+
|
|
60
|
+
# 规整为绝对路径(不依赖 realpath)
|
|
61
|
+
case "$dir" in
|
|
62
|
+
/*) ;;
|
|
63
|
+
*) dir="$PWD/$dir" ;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
local guard=0
|
|
67
|
+
while [ "$dir" != "/" ] && [ "$dir" != "." ] && [ $guard -lt 64 ]; do
|
|
68
|
+
if [ -d "$dir/.git" ] || [ -f "$dir/.git" ]; then # 后者兼容 git worktree
|
|
69
|
+
printf '%s' "$dir"
|
|
70
|
+
return 0
|
|
71
|
+
fi
|
|
72
|
+
dir=$(dirname "$dir")
|
|
73
|
+
guard=$((guard + 1))
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
# 未找到 → 回退到原 cwd
|
|
77
|
+
printf '%s' "${1:-$PWD}"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
调用方一行替换:
|
|
82
|
+
```bash
|
|
83
|
+
RAW_CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
|
|
84
|
+
PROJECT_PATH=$(resolve_project_path "${RAW_CWD:-$PWD}")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## CLI / daemon 端兼容
|
|
88
|
+
|
|
89
|
+
**daemon 端**:不改。`history-exporter.ts:24` 信任传入的 `event.project_path`(hook 端已是 git root)。
|
|
90
|
+
|
|
91
|
+
**CLI 端 `executions.ts`**:新增 helper(放 `src/core/utils/git.ts`):
|
|
92
|
+
```typescript
|
|
93
|
+
export function resolveGitRoot(start = process.cwd()): string {
|
|
94
|
+
try {
|
|
95
|
+
return execSync('git rev-parse --show-toplevel', { cwd: start, stdio: ['ignore', 'pipe', 'ignore'] })
|
|
96
|
+
.toString().trim() || start;
|
|
97
|
+
} catch { return start; }
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
三处 `path.join(process.cwd(), '.claude-forge', ...)` → `path.join(resolveGitRoot(), '.claude-forge', ...)`。
|
|
101
|
+
|
|
102
|
+
**template-manager.ts**:函数本身签名不变(接收 `projectPath`),改 init 命令调用侧。
|
|
103
|
+
|
|
104
|
+
## 测试策略
|
|
105
|
+
|
|
106
|
+
- **safety-net (单测 bash 函数)**:构造 fixture `/tmp/forge-test/repo/.git/`,对 `resolve_project_path /tmp/forge-test/repo/a/b/c` 断言返回 git root;非 git 目录断言回退;空输入断言回退到 `$PWD`。
|
|
107
|
+
- **集成**:vitest 起一个 daemon,构造 `cwd=fixture/sub/dir` 的 INPUT,跑 `pre-tool-use.sh`,从 daemon storage queryEvents 断言 `project_path === fixture` 而非子目录。
|
|
108
|
+
- **回归**:现有 daemon 集成测试不需要改(hook 端透明改造)。
|
|
109
|
+
- **CLI 端**:单测 `resolveGitRoot()` 在 git 仓 / 非 git 仓两种 cwd 下的返回值。
|
|
110
|
+
|
|
111
|
+
## 风险与回滚
|
|
112
|
+
|
|
113
|
+
- **`.git` 是文件(worktree)场景**:`[ -f "$dir/.git" ]` 已兼容。
|
|
114
|
+
- **非 git 项目**:fallback 原 cwd,行为不变。
|
|
115
|
+
- **monorepo 子模块各自 .git**:返回最近的 git root,符合预期。
|
|
116
|
+
- **历史数据**:旧 sessions.project_path 仍是子目录路径,不做迁移;可选清单:列出 sessions 表去重 project_path,提供 `cf admin remap-project-path` 工具(非本次范围)。
|
|
117
|
+
- **bash on Linux/macOS 差异**:用 POSIX 内建(`dirname` / `case`),不依赖 `realpath`。
|
|
118
|
+
- **回滚**:还原 6 个文件即可,无 schema 变更。
|
|
119
|
+
|
|
120
|
+
## 实施顺序(refactor-safe)
|
|
121
|
+
|
|
122
|
+
1. **safety-net 阶段**:先写 `tests/unit/hooks/resolve-project-path.test.sh`(或 vitest 用 `child_process.execSync('bash -c "source hook-lib.sh && resolve_project_path ..."')`)和 `tests/integration/hook-gitroot.integration.test.ts`(先红)
|
|
123
|
+
2. **lib 阶段**:在 `hook-lib.sh` 新增 `resolve_project_path` → 单测转绿
|
|
124
|
+
3. **hook 改造**:5 个 hook 替换两行;`stop.sh` 同时改为 `source hook-lib.sh`(顺手补一致性)→ 集成测试转绿
|
|
125
|
+
4. **CLI 阶段**:新增 `src/core/utils/git.ts::resolveGitRoot`,改 `executions.ts` 3 处 + `init` 调用侧
|
|
126
|
+
5. **验证**:`npx tsc --noEmit` + `npm test` + 手工到 fixture 子目录跑 `cf executions list` 确认走 git root
|
|
127
|
+
6. **release**:bump patch 版本,changelog 注明"hooks 解析 git root,不再在子目录生成 .claude-forge"
|
|
128
|
+
|
|
129
|
+
## 命名遵循
|
|
130
|
+
|
|
131
|
+
- bash 函数:`resolve_project_path`(snake_case,与 hook-lib 现有 `send_event_or_enqueue` / `_enqueue_event_bg` 一致)
|
|
132
|
+
- TS 工具函数:`resolveGitRoot`(camelCase,`get` 前缀不适用因为这是计算非查询)
|
|
133
|
+
- 新文件:`src/core/utils/git.ts`(kebab 化已为单词,遵循现有 `time.ts` / `session.ts`)
|
|
134
|
+
- 测试文件:`tests/unit/hooks/resolve-project-path.test.sh` 或 `.test.ts`、`tests/integration/hook-gitroot.integration.test.ts`
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# task active GC 修复 Spec
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
|
|
5
|
+
通过周期 GC + completeCurrentTask recover fallback,消除因 ESC 中断、Stop hook 未触发、daemon 重启等场景导致的 task 永久滞留 `active` 状态。
|
|
6
|
+
|
|
7
|
+
## Bug 复现路径
|
|
8
|
+
|
|
9
|
+
| 场景 | 触发条件 | 为何漏掉 |
|
|
10
|
+
|------|---------|---------|
|
|
11
|
+
| A | 用户 ESC 中断 Claude Code,Stop hook 不触发 | completeCurrentTask 永远不被调用 |
|
|
12
|
+
| B | daemon 重启后用户 ESC,Stop hook 触发但 `currentTasks` Map 为空 | completeCurrentTask 第 78 行:`const current = this.currentTasks.get(sessionId)` — Map 空直接 return |
|
|
13
|
+
| C | 用户切到别的 session 后永不再 prompt 旧 session | shouldStartNewTask 从不被触发,task 无人收尾 |
|
|
14
|
+
|
|
15
|
+
## 方案对比
|
|
16
|
+
|
|
17
|
+
| 方案 | 修复场景 | 改动文件数 | 风险 |
|
|
18
|
+
|------|---------|-----------|------|
|
|
19
|
+
| A:周期 GC | A / C(idle 超阈值后兜底) | 3 | idle 阈值设太短可能误杀长任务 |
|
|
20
|
+
| B:completeCurrentTask recover fallback | B | 1 | 仅修场景 B,A/C 仍漏 |
|
|
21
|
+
| C:A + B 组合 | A / B / C 全覆盖 | 3 | 最全面,改动仍可控 |
|
|
22
|
+
| D:新增 `auto_closed` 状态 | A / B / C + UI 语义区分 | 5+ | 改动大,可作后续优化 |
|
|
23
|
+
|
|
24
|
+
**推荐:方案 C**。
|
|
25
|
+
|
|
26
|
+
## 详细设计
|
|
27
|
+
|
|
28
|
+
### 1. storage 新方法:`completeStaleActiveTasks`
|
|
29
|
+
|
|
30
|
+
**位置**:`src/core/storage/tasks.ts`(TaskOperations 类内)
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
/**
|
|
34
|
+
* 将 idle 超过阈值的 active task 批量转为 completed。
|
|
35
|
+
* 条件:status='active' AND end_time IS NOT NULL
|
|
36
|
+
* AND (now - end_time) > idleMinutes 分钟。
|
|
37
|
+
* 返回:受影响行数。
|
|
38
|
+
*/
|
|
39
|
+
completeStaleActiveTasks(idleMinutes: number): number {
|
|
40
|
+
const result = this.db.prepare(`
|
|
41
|
+
UPDATE tasks
|
|
42
|
+
SET status = 'completed'
|
|
43
|
+
WHERE status = 'active'
|
|
44
|
+
AND end_time IS NOT NULL
|
|
45
|
+
AND (julianday('now') - julianday(end_time)) * 24 * 60 > ?
|
|
46
|
+
`).run(idleMinutes);
|
|
47
|
+
return result.changes;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
同步在 `SQLiteStorage` facade(`sqlite.ts`)暴露同名代理方法。
|
|
52
|
+
|
|
53
|
+
注意:`end_time` 由 `linkEventToTask` 持续更新,作为 idle 判定基准合理。没有 `end_time` 的 task(从未 link 过事件)不纳入 GC,避免误杀刚创建的 task。
|
|
54
|
+
|
|
55
|
+
### 2. TaskSegmenter.completeCurrentTask 加 recover fallback
|
|
56
|
+
|
|
57
|
+
**位置**:`src/daemon/services/task-segmenter.ts:77`
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
completeCurrentTask(sessionId: string, timestamp: string): void {
|
|
61
|
+
const current = this.currentTasks.get(sessionId) ?? this.recoverActiveTask(sessionId);
|
|
62
|
+
if (!current) return;
|
|
63
|
+
...
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
一行改动,与 `processPrompt` / `linkEvent` 模式一致。
|
|
68
|
+
|
|
69
|
+
### 3. maintenanceInterval 加 GC 调度
|
|
70
|
+
|
|
71
|
+
**位置**:`src/daemon/index.ts:105-116`
|
|
72
|
+
|
|
73
|
+
现有 `maintenanceInterval` 是 **24 小时**,仅清理旧 events。需新增独立的**短周期 GC interval**:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// ── 5.6. Stale task GC (every 5 minutes) ──────────────────────────
|
|
77
|
+
const STALE_TASK_GC_INTERVAL = 5 * 60 * 1000; // 5 分钟
|
|
78
|
+
const STALE_TASK_IDLE_MINUTES = 10; // idle 超 10 分钟视为滞留
|
|
79
|
+
|
|
80
|
+
const staleTaskGcInterval = setInterval(() => {
|
|
81
|
+
try {
|
|
82
|
+
const closed = storage.completeStaleActiveTasks(STALE_TASK_IDLE_MINUTES);
|
|
83
|
+
if (closed > 0) {
|
|
84
|
+
logger.info(`[Maintenance] Auto-completed ${closed} stale active task(s)`);
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
logger.error(`[Maintenance] Stale task GC failed: ${err}`);
|
|
88
|
+
}
|
|
89
|
+
}, STALE_TASK_GC_INTERVAL);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
关闭时需调用 `clearInterval(staleTaskGcInterval)`(在现有 graceful shutdown 段追加)。
|
|
93
|
+
|
|
94
|
+
## 改造范围
|
|
95
|
+
|
|
96
|
+
| 文件 | 改动内容 | 估算行数 |
|
|
97
|
+
|------|---------|---------|
|
|
98
|
+
| `src/core/storage/tasks.ts` | 新增 `completeStaleActiveTasks` 方法 | +12 |
|
|
99
|
+
| `src/core/storage/sqlite.ts` | facade 代理方法 | +3 |
|
|
100
|
+
| `src/daemon/services/task-segmenter.ts` | completeCurrentTask recover fallback(1 行) | +1 |
|
|
101
|
+
| `src/daemon/index.ts` | 新增 GC interval + clearInterval | +12 |
|
|
102
|
+
|
|
103
|
+
共 4 文件,约 28 行净增。
|
|
104
|
+
|
|
105
|
+
## 配置
|
|
106
|
+
|
|
107
|
+
| 参数 | 值 | 说明 |
|
|
108
|
+
|------|----|------|
|
|
109
|
+
| `STALE_TASK_IDLE_MINUTES` | 10 | idle 超 10 分钟视为放弃,不可配置(硬编码常量) |
|
|
110
|
+
| `STALE_TASK_GC_INTERVAL` | 5 分钟 | GC 轮询间隔,独立于 24h 维护周期 |
|
|
111
|
+
|
|
112
|
+
如未来需要可迁移到 `config.yaml` 的 `tasks.stale_gc_minutes` 字段。
|
|
113
|
+
|
|
114
|
+
## 测试策略
|
|
115
|
+
|
|
116
|
+
| 测试类型 | 测试用例 | 文件位置 |
|
|
117
|
+
|---------|---------|---------|
|
|
118
|
+
| 单测:`completeStaleActiveTasks` | 空表返回 0 | 新增 `tests/unit/storage/tasks-stale-gc.test.ts` |
|
|
119
|
+
| | 1 idle 超阈值 + 1 未超:只关超的 | 同上 |
|
|
120
|
+
| | `status='completed'` 的 task 不被改动 | 同上 |
|
|
121
|
+
| | `end_time IS NULL` 的 task 不被纳入 | 同上 |
|
|
122
|
+
| 单测:recover fallback | Map 为空时仍能 complete DB 中 active task | 扩展现有 task-segmenter 测试 |
|
|
123
|
+
|
|
124
|
+
## 风险与回滚
|
|
125
|
+
|
|
126
|
+
| 风险 | 概率 | 缓解措施 |
|
|
127
|
+
|------|------|---------|
|
|
128
|
+
| 误杀正在进行的长任务 | 低(idle 阈值 10 分钟,linkEvent 持续刷新 end_time) | 阈值可调大;日志可审计 |
|
|
129
|
+
| 旧库一次性批量 GC | 必然发生,且是预期行为 | 无需回滚,这正是修 bug 的目的 |
|
|
130
|
+
| GC interval 异常退出 | 极低(try-catch 包裹) | 日志记录,不影响主流程 |
|
|
131
|
+
|
|
132
|
+
**回滚**:删除 daemon/index.ts 中的 `staleTaskGcInterval` 代码块即可完全禁用 GC,其他改动无副作用。
|
|
133
|
+
|
|
134
|
+
## 实施顺序
|
|
135
|
+
|
|
136
|
+
1. `tasks.ts` — 新增 `completeStaleActiveTasks` + 单测
|
|
137
|
+
2. `sqlite.ts` — facade 代理方法
|
|
138
|
+
3. `task-segmenter.ts` — recover fallback 单行 + 单测
|
|
139
|
+
4. `daemon/index.ts` — GC interval 注册 + clearInterval
|
|
140
|
+
5. 全量测试 `npm test`
|
|
141
|
+
|
|
142
|
+
## 命名遵循
|
|
143
|
+
|
|
144
|
+
- `completeStaleActiveTasks`:`complete` 前缀(语义清晰,优于 `write`)
|
|
145
|
+
- `STALE_TASK_GC_INTERVAL` / `STALE_TASK_IDLE_MINUTES`:全大写常量
|
|
146
|
+
- `staleTaskGcInterval`:camelCase 变量,与 `maintenanceInterval` 风格一致
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# H1 实施 Changelog
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-05-18 11:21
|
|
4
|
+
**Spec**: `docs/design/h1-storage-aggregation-spec-20260518-1121.md`
|
|
5
|
+
**Status**: 完成
|
|
6
|
+
|
|
7
|
+
## 完成清单
|
|
8
|
+
|
|
9
|
+
- [x] Storage 新方法(7 个):
|
|
10
|
+
- `aggregateRoutingStats({ since_ts, project_path? })` → `RoutingOperations`
|
|
11
|
+
- `aggregateRoutingTrendByDay({ since_ts })` → `RoutingOperations`
|
|
12
|
+
- `aggregateSkillInvocationsBySkill({ since, limit? })` → `SkillOperations`
|
|
13
|
+
- `getTask(taskId)` → `TaskOperations`
|
|
14
|
+
- `queryEventsByTaskId(taskId, opts?)` → `TaskOperations`
|
|
15
|
+
- `queryInjectionsByTaskId(taskId)` → `TaskOperations`
|
|
16
|
+
- `querySkillInvocationsByTaskWindow(taskId, now_ms?)` → `TaskOperations`
|
|
17
|
+
- [x] sqlite.ts facade 转发已加(7 个方法)
|
|
18
|
+
- [x] 索引新增:`idx_routing_events_type_ts` (schema.sql + base.ts runMigrations 同步)
|
|
19
|
+
- [x] Storage 单元测试(3 文件):
|
|
20
|
+
- `tests/unit/storage/routing-aggregates.test.ts`
|
|
21
|
+
- `tests/unit/storage/skills-aggregates.test.ts`
|
|
22
|
+
- `tests/unit/storage/tasks-getById-aggregates.test.ts`
|
|
23
|
+
- [x] Routes 改造(3 文件):
|
|
24
|
+
- `src/web/routes/rules.ts` — hit-rate 改用 `aggregateRoutingStats` + `aggregateSkillInvocationsBySkill`
|
|
25
|
+
- `src/web/routes/skill-stats.ts` — 5 个 endpoint 全部下沉到 SQL 聚合
|
|
26
|
+
- `src/web/routes/tasks.ts` — `/:taskId` PK 直查 + JOIN
|
|
27
|
+
- [x] 路由测试新增:`tests/unit/web/routes-rules.test.ts`(之前缺口)
|
|
28
|
+
|
|
29
|
+
## 关键代码定位
|
|
30
|
+
|
|
31
|
+
### Storage 新方法
|
|
32
|
+
- `src/core/storage/routing.ts` — `aggregateRoutingStats`、`aggregateRoutingTrendByDay`(4 条独立 prepared statement 走索引;trend 用 `strftime('%Y-%m-%d', ts/1000, 'unixepoch')`)
|
|
33
|
+
- `src/core/storage/skills.ts` — `aggregateSkillInvocationsBySkill`(按 `total DESC`)
|
|
34
|
+
- `src/core/storage/tasks.ts` — `getTask` / `queryEventsByTaskId` / `queryInjectionsByTaskId` / `querySkillInvocationsByTaskWindow`(后者用 `task_events` JOIN + `tasks.start_time/end_time` 转 ms 做窗口过滤)
|
|
35
|
+
- `src/core/storage/sqlite.ts` — facade 转发 7 个方法
|
|
36
|
+
- `src/core/storage/schema.sql` 末尾 + `src/core/storage/base.ts` runMigrations — `idx_routing_events_type_ts ON routing_events(routed_to_type, ts DESC)`
|
|
37
|
+
|
|
38
|
+
### Route 改造点
|
|
39
|
+
- `src/web/routes/rules.ts` — `queryRoutingEvents{limit:100000}` + `querySkillInvocations{limit:100000}` JS reduce → `aggregateRoutingStats` + `aggregateSkillInvocationsBySkill`
|
|
40
|
+
- `src/web/routes/skill-stats.ts:16` — `/distribution`:`agg.by_type` + 三桶兜底
|
|
41
|
+
- `src/web/routes/skill-stats.ts:33` — `/frequency`:`agg.by_skill_routed.map(...)`
|
|
42
|
+
- `src/web/routes/skill-stats.ts:43` — `/trend`:`aggregateRoutingTrendByDay` + JS skillRate 计算
|
|
43
|
+
- `src/web/routes/skill-stats.ts:59` — `/invocations`:`aggregateSkillInvocationsBySkill`,`total` 改为 sum 行 total
|
|
44
|
+
- `src/web/routes/skill-stats.ts:76` — `/api/routing/stats`:`agg.obeyed/total/by_agent`
|
|
45
|
+
- `src/web/routes/tasks.ts:59` — `/:taskId`:`getTask` + `queryEventsByTaskId` + `queryInjectionsByTaskId` + `querySkillInvocationsByTaskWindow` 取代旧四段全表扫
|
|
46
|
+
|
|
47
|
+
## 测试结果
|
|
48
|
+
|
|
49
|
+
| 维度 | 数值 |
|
|
50
|
+
|------|------|
|
|
51
|
+
| storage + web unit | 171 通过 / 1 失败(pre-existing) |
|
|
52
|
+
| 全量 `npm test` | **417 通过 / 1 失败 / 418 总** |
|
|
53
|
+
| `npx tsc --noEmit` | **0 errors** |
|
|
54
|
+
|
|
55
|
+
### Pre-existing failure(与 H1 无关,main 分支既有)
|
|
56
|
+
- `tests/unit/storage/sqlite-refactor-harness.test.ts > Task Operations > linkEventToTask associates events with tasks`
|
|
57
|
+
- 报错:`Invalid event data: ... event_id Invalid uuid`
|
|
58
|
+
- 原因:测试中传入的 `event_id` 不是 UUID 格式,与 `events.ts:73` 的 zod 校验不兼容
|
|
59
|
+
- 在 main 分支同样 fail,**未在本次任务范围**,未修
|
|
60
|
+
|
|
61
|
+
## 超出 spec 的改动
|
|
62
|
+
|
|
63
|
+
无。所有改动均严格按 spec 第 3 节执行。响应字段结构未变更(前端 React 组件契约保持):
|
|
64
|
+
- `/distribution` → `{ windowHours, distribution: [{type, count}] }` ✓
|
|
65
|
+
- `/frequency` → `{ windowHours, frequency: [{name, count}] }` ✓
|
|
66
|
+
- `/trend` → `{ windowHours, trend: [{day, skillRate}] }` ✓
|
|
67
|
+
- `/invocations` → `{ days, total, invocations: [{skill_id, total, success, failed}] }` ✓
|
|
68
|
+
- `/api/routing/stats` → `{ days, total, agentCalls, noAgent, agentRate, byAgent }` ✓
|
|
69
|
+
- `/api/tasks/:taskId` → `{ task, userPrompts, injections, timeline, skillInvocations, artifacts }` ✓
|
|
70
|
+
|
|
71
|
+
注:`/invocations` 的 `total` 字段语义不变(旧实现是 `invocations.length` = 原始记录数;新实现是 `sum(rows.total)` = 同样的原始记录数,因 GROUP BY skill_id 后各 group total 之和等于总行数)。
|
|
72
|
+
|
|
73
|
+
## 已知问题
|
|
74
|
+
|
|
75
|
+
- **Pre-existing**:`sqlite-refactor-harness.test.ts > linkEventToTask` — 与 H1 无关,main 分支同样失败。
|
|
76
|
+
- 无其它已知问题。
|
|
77
|
+
|
|
78
|
+
## 回滚提示
|
|
79
|
+
|
|
80
|
+
纯增量改动。如需回滚:
|
|
81
|
+
- revert `src/web/routes/{rules,skill-stats,tasks}.ts` 即可恢复旧行为
|
|
82
|
+
- storage 新方法和索引保留无害(无人调用即无副作用)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# H2 完整实施 Changelog
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-05-18
|
|
4
|
+
**Spec**: `docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md`
|
|
5
|
+
**Status**: 全 4 Phase 完成
|
|
6
|
+
**Workflow**: refactor-safe(safety-net → 新方法 → 替换 → 收尾)
|
|
7
|
+
|
|
8
|
+
## 四阶段 commit 索引
|
|
9
|
+
|
|
10
|
+
| Phase | Commit | 内容 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| 1 | `0b494ed` | safety-net 17 test cases(web-stats / web-trace / stop-handler / web-analytics 增强) |
|
|
13
|
+
| 2 | (上一 commit) | 20 个 Operations 新方法 + 44 个单测 + facade 转发 |
|
|
14
|
+
| 3 | `bf3eb39` | 7 个调用方文件替换 db.prepare() → facade |
|
|
15
|
+
| 4 | (本 commit) | getDatabase jsdoc 警告 + 总 changelog |
|
|
16
|
+
|
|
17
|
+
## 累计影响
|
|
18
|
+
|
|
19
|
+
- **改动 13 个 src 文件,新增 12 个测试文件**
|
|
20
|
+
- **消除 27 处越权 SQL 直写**(spec 调研时 25 处 + 主线程封闭性扫描补 cli/commands/trace.ts 3 处)
|
|
21
|
+
- **新增 20 个 Operations 方法**:EventOperations × 11 + SessionOperations × 4 + TaskOperations × 1 + SkillOperations × 4
|
|
22
|
+
- **新增 61 个测试用例**:safety-net 17 + Operations 单测 44
|
|
23
|
+
|
|
24
|
+
## 命名固化(H1 → H2 一致)
|
|
25
|
+
|
|
26
|
+
- `aggregate*` 聚合(GROUP BY 类)
|
|
27
|
+
- `count*` 计数
|
|
28
|
+
- `query*` 列表查询
|
|
29
|
+
- `get*` 单条查询
|
|
30
|
+
|
|
31
|
+
## 关键决策
|
|
32
|
+
|
|
33
|
+
1. **getDatabase 保留 public**(不改 protected):架构非继承关系,protected 收益小风险大;改用 jsdoc `@internal` 标注 + CLAUDE.md 工作流提醒
|
|
34
|
+
2. **SQL 行为零变更**:所有 SQL 直接搬入 Operations,不做"优化",保证 safety-net 测试零回归
|
|
35
|
+
3. **`LIKE '%error%'` 失败检测保留原 3 个 OR 条件**:与生产匹配
|
|
36
|
+
4. **Phase 2 偏差**:`aggregateToolUsage` 缺 `until` 参数 → Phase 3 改用 `queryEventsByTimeRange + 内存聚合` 兜底,保留 `[since, until)` 语义
|
|
37
|
+
|
|
38
|
+
## 测试结果(最终)
|
|
39
|
+
|
|
40
|
+
- safety-net 集成测试:17/17 ✓
|
|
41
|
+
- Operations 单测:44/44 ✓
|
|
42
|
+
- 现有回归:541/542 通过
|
|
43
|
+
- **唯一失败**:pre-existing `linkEventToTask` (Zod UUID 校验,与 H2 无关)
|
|
44
|
+
- `npx tsc --noEmit`: 0 errors
|
|
45
|
+
|
|
46
|
+
## 残留 `db.prepare` 检查
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
$ grep -rn "db\.prepare" src/web/ src/cli/commands/trace.ts src/daemon/handlers/ --include="*.ts" | grep -v ".test."
|
|
50
|
+
src/web/routes/stats.ts:7: * H2 Phase 3: 替换原 db.prepare 直写 SQL 为 SQLiteStorage facade 聚合方法。
|
|
51
|
+
src/web/routes/trace.ts:95: // H2 Phase 3: 改用 facade 聚合方法,消除 db.prepare 直写。
|
|
52
|
+
src/daemon/handlers/stop.ts:151: // H2 Phase 3: 改用 facade 聚合方法,消除 db.prepare 直写。
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**3 处均为注释**,无 SQL 直写。
|
|
56
|
+
|
|
57
|
+
## 后续 follow-up
|
|
58
|
+
|
|
59
|
+
- **可选**:补完 `aggregateToolUsage` 的 `until` 参数支持,weekly-report 改回单条 SQL
|
|
60
|
+
- **可选**:ESLint 规则禁止 `web/routes/` `web/analytics/` `daemon/handlers/` import storage 后调用 `getDatabase()`
|
|
61
|
+
- **不建议**:把 `getDatabase` 改 protected(架构非继承)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# H2 Phase 1 safety-net Changelog
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-05-18 14:50
|
|
4
|
+
**Spec**: docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md
|
|
5
|
+
**Status**: Phase 1 完成(Phase 2-4 待后续)
|
|
6
|
+
|
|
7
|
+
## 完成清单
|
|
8
|
+
|
|
9
|
+
- [x] web-stats 集成测试 (`tests/integration/web-stats.integration.test.ts`, 4 cases)
|
|
10
|
+
- [x] web-trace 集成测试 (`tests/integration/web-trace.integration.test.ts`, 6 cases — 全分支覆盖)
|
|
11
|
+
- [x] stop-handler-behavior-summary 单测 (`tests/unit/daemon/stop-handler-behavior-summary.test.ts`, 5 cases)
|
|
12
|
+
- [x] web-analytics 集成测试增强 (+2 value-level cases)
|
|
13
|
+
|
|
14
|
+
## 关键代码定位
|
|
15
|
+
|
|
16
|
+
| 测试文件 | 行号 | 内容 |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| `tests/integration/web-stats.integration.test.ts:38` | empty database 200 shape |
|
|
19
|
+
| `tests/integration/web-stats.integration.test.ts:60` | totalEvents/totalSessions/toolUsage 聚合 |
|
|
20
|
+
| `tests/integration/web-stats.integration.test.ts:83` | dailyActivity 字段形状 |
|
|
21
|
+
| `tests/integration/web-stats.integration.test.ts:103` | skillInvocations 计数 |
|
|
22
|
+
| `tests/integration/web-trace.integration.test.ts:84-118` | 4 个 4xx 错误分支 |
|
|
23
|
+
| `tests/integration/web-trace.integration.test.ts:120-130` | 200 + 空 sessions[](无 git note)|
|
|
24
|
+
| `tests/integration/web-trace.integration.test.ts:132-167` | 200 + 完整 session 详情(含 event_breakdown)|
|
|
25
|
+
| `tests/unit/daemon/stop-handler-behavior-summary.test.ts:69` | 无事件时不附加 summary |
|
|
26
|
+
| `tests/unit/daemon/stop-handler-behavior-summary.test.ts:82` | tool-only summary |
|
|
27
|
+
| `tests/unit/daemon/stop-handler-behavior-summary.test.ts:110` | Agent 委托计数 + agent 名 |
|
|
28
|
+
| `tests/unit/daemon/stop-handler-behavior-summary.test.ts:141` | skill 调用计数 |
|
|
29
|
+
| `tests/unit/daemon/stop-handler-behavior-summary.test.ts:169` | session 隔离(不串扰)|
|
|
30
|
+
| `tests/integration/web-analytics.integration.test.ts:92` | weekly report value 断言 |
|
|
31
|
+
| `tests/integration/web-analytics.integration.test.ts:107` | insights summary.total = patterns.length |
|
|
32
|
+
|
|
33
|
+
## 测试结果
|
|
34
|
+
|
|
35
|
+
- **新增/增强 safety-net 测试**: 17 passed (4 stats + 6 trace + 5 stop + 2 analytics 增强)
|
|
36
|
+
- **跨 Phase 1 范围全量**:
|
|
37
|
+
- `tests/integration/` + `tests/unit/daemon/`: 33 / 33 passed
|
|
38
|
+
- **tsc**: 0 errors
|
|
39
|
+
- **npm test 全量**: 497 / 498 passed (1 failed = pre-existing `linkEventToTask`)
|
|
40
|
+
|
|
41
|
+
## 实施决策
|
|
42
|
+
|
|
43
|
+
1. **trace 测试覆盖方案**:采用方案 A(tmp git repo)。在 `os.tmpdir()` 用 `execFileSync('git', ...)` 创建真实仓库 + 两次 commit + `git notes add`,覆盖:
|
|
44
|
+
- 缺 `?project` query → 400
|
|
45
|
+
- 相对路径 → 400
|
|
46
|
+
- 非 git 目录 → 400
|
|
47
|
+
- commit 不存在 → 404
|
|
48
|
+
- HEAD 有 commit 但无 note → 200 + 空 sessions[]
|
|
49
|
+
- 有 forge-session note + storage 有对应 events → 200 + 完整 session 详情(event_breakdown 等)
|
|
50
|
+
- **覆盖度高于 spec 最低要求**(spec 只要求 commit 不存在 4xx + 无 note 空 sessions 两条),实际跑得快且稳定。
|
|
51
|
+
2. **stop-handler 测试路径调整**:spec 写 `src/tests/stop-handler-behavior-summary.test.ts`,但 `vitest.config.ts` 只包含 `tests/unit/**` 与 `tests/integration/**`。如放到 `src/tests/` 会被 collect 排除导致永远不跑。改放到 `tests/unit/daemon/stop-handler-behavior-summary.test.ts` 以确保实际生效,已在测试文件顶部 NOTE 注释中说明决策。
|
|
52
|
+
3. **`generateBehaviorSummary` 私有方法访问**:经由 `handle()` 入口 + mock `ResumeManager.save` 捕获最终 resume content 进行断言。比反射访问私有方法更接近生产实际路径,且更稳健。
|
|
53
|
+
4. **web-analytics 增强保守原则**:只加 2 个新 case(weekly value + insights consistency),不重写既有 shape 断言。所有原 case 仍保留并通过。
|
|
54
|
+
5. **fixture 时间戳策略**:weekly-report 按 ISO week 范围过滤事件,所以 fixture 用 `new Date().toISOString()`(当下时间)确保进入 `weekOffset: 0` 窗口;stats endpoint 用 `date('now', '-7 days')`,同样满足。
|
|
55
|
+
|
|
56
|
+
## 待 Phase 2 处理
|
|
57
|
+
|
|
58
|
+
下一步 Phase 2(新增 ~20 个 Operations 方法)的提示:
|
|
59
|
+
|
|
60
|
+
- Phase 2 应在 `src/core/storage/{events,sessions,tasks,skills}.ts` 加方法,**不删旧 SQL**,并行存在。
|
|
61
|
+
- Phase 2 同时增加 4 个新单测文件:`tests/unit/storage/{event,session,skill}-operations-aggregates.test.ts`(spec 表 116 行所列)。
|
|
62
|
+
- Phase 3 才会替换调用方(每文件 1 commit),届时本 Phase 1 的 safety-net 会兜底回归。
|
|
63
|
+
- Phase 4 给 `getDatabase()` 加 jsdoc `@internal` 警告。
|
|
64
|
+
- 改造涉及 `daemon/handlers/stop.ts` 时,本次新加的 `stop-handler-behavior-summary.test.ts` 5 个 case 是关键回归依据。
|
|
65
|
+
- trace 测试包含一次真实 `git init`,单测耗时 ~600ms,未来 Phase 2/3 增加新测试时不必再做 git 操作。
|
|
66
|
+
|
|
67
|
+
## 已知问题
|
|
68
|
+
|
|
69
|
+
- **pre-existing 失败**:`SQLiteStorage - Characterization Tests (Pre-Refactor) > Task Operations > linkEventToTask associates events with tasks` —— Zod uuid 校验失败,与本 Phase 1 改动无关,按纪律不修。
|
|
70
|
+
- **未覆盖**:`cli/commands/trace.ts` 3 段 SQL 暂无对应集成测试(spec 第 71 行已标注"可补")。Phase 2/3 替换 CLI trace 时可考虑加 CLI smoke test,或先依赖 web-trace 同模式断言间接保护。
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# H2 Phase 2 Operations 新方法 Changelog
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-05-18 14:50 (Phase 2)
|
|
4
|
+
**Spec**: docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md
|
|
5
|
+
**Status**: Phase 2 完成(Phase 3 待替换调用方)
|
|
6
|
+
|
|
7
|
+
## 完成清单
|
|
8
|
+
|
|
9
|
+
- [x] EventOperations 11 方法(events.ts)
|
|
10
|
+
- [x] SessionOperations 4 方法(sessions.ts)
|
|
11
|
+
- [x] TaskOperations 1 方法(tasks.ts)
|
|
12
|
+
- [x] SkillOperations 4 方法(skills.ts)
|
|
13
|
+
- [x] sqlite.ts facade 转发(20 个方法)
|
|
14
|
+
- [x] 4 文件单测(44 个 case 全过)
|
|
15
|
+
- [x] tsc 通过 0 errors
|
|
16
|
+
- [x] 旧 SQL 并行存在(Phase 3 才替换)
|
|
17
|
+
|
|
18
|
+
## 新增方法清单
|
|
19
|
+
|
|
20
|
+
### EventOperations(src/core/storage/events.ts:179-358)
|
|
21
|
+
|
|
22
|
+
| 方法 | SQL 来源 |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `countAllEvents()` | stats.ts:13 |
|
|
25
|
+
| `aggregateToolUsage({ since?, limit?, hook_type? })` | stats.ts:17-21 + weekly-report.ts:214-222 |
|
|
26
|
+
| `aggregateDailyEventCounts({ since, until? })` | stats.ts:28-33 |
|
|
27
|
+
| `aggregateHookTypeBySession(session_id)` | trace.ts:106-109 + cli/trace.ts:115 |
|
|
28
|
+
| `aggregateAgentTypeBySession(session_id)` | trace.ts:111-116 + cli/trace.ts:124 + stop.ts:163-168 |
|
|
29
|
+
| `aggregateToolUsageBySession(session_id)` | stop.ts:154-158 |
|
|
30
|
+
| `countActiveDays({ since, until? })` | drift-detector.ts:154-157 |
|
|
31
|
+
| `aggregateOverviewByRange({ since, until })` | weekly-report.ts:100-109 |
|
|
32
|
+
| `queryDistinctProjects({ since, until })` | weekly-report.ts:111-116 |
|
|
33
|
+
| `aggregateToolFailureRate({ since, until })` | weekly-report.ts:228-244(保留 3 OR LIKE 分支) |
|
|
34
|
+
| `queryFileEditInputs({ since, until, tool_names })` | weekly-report.ts:261-268(内部 IN 展开) |
|
|
35
|
+
| `queryEventsByTimeRange({ since, until? })` | anti-pattern-detector.ts:83-86 |
|
|
36
|
+
|
|
37
|
+
### SessionOperations(src/core/storage/sessions.ts:107-178)
|
|
38
|
+
|
|
39
|
+
| 方法 | SQL 来源 |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `countAllSessions()` | stats.ts:14 |
|
|
42
|
+
| `aggregateDailySessionCounts({ since, until? })` | stats.ts:35-40 |
|
|
43
|
+
| `querySessionsByTimeRange({ since, until? })` | anti-pattern-detector.ts:104-114 |
|
|
44
|
+
| `countSessionsByRange({ since, until? })` | drift-detector.ts:185-187 |
|
|
45
|
+
|
|
46
|
+
### TaskOperations(src/core/storage/tasks.ts:120-131)
|
|
47
|
+
|
|
48
|
+
| 方法 | SQL 来源 |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `countTasksByRange({ since, until? })` | drift-detector.ts:190-192 + weekly-report.ts:118-122 |
|
|
51
|
+
|
|
52
|
+
### SkillOperations(src/core/storage/skills.ts:203-232)
|
|
53
|
+
|
|
54
|
+
| 方法 | SQL 来源 |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `countAllSkillInvocations()` | stats.ts:50 |
|
|
57
|
+
| `countSkillInvocationsBySession(session_id)` | stop.ts:176-178 |
|
|
58
|
+
| `countDistinctSkillsSince(since_ms)` | drift-detector.ts:125-128 |
|
|
59
|
+
| `queryDistinctSkillIdsBySession(session_id)` | trace.ts:118-120 + cli/trace.ts:135 |
|
|
60
|
+
|
|
61
|
+
### sqlite.ts facade(src/core/storage/sqlite.ts:94-160)
|
|
62
|
+
|
|
63
|
+
20 个方法签名严格按 spec,全部 `delegate to this.events / this.sessions / this.tasks / this.skills`。
|
|
64
|
+
|
|
65
|
+
## 关键代码定位
|
|
66
|
+
|
|
67
|
+
- `src/core/storage/events.ts:179-358` — EventOperations 11 新方法
|
|
68
|
+
- `src/core/storage/sessions.ts:107-178` — SessionOperations 4 新方法
|
|
69
|
+
- `src/core/storage/tasks.ts:120-131` — TaskOperations countTasksByRange
|
|
70
|
+
- `src/core/storage/skills.ts:203-232` — SkillOperations 4 新方法
|
|
71
|
+
- `src/core/storage/sqlite.ts:94-160` — facade 转发段
|
|
72
|
+
|
|
73
|
+
## 测试结果
|
|
74
|
+
|
|
75
|
+
- 新增单测: **44 passed / 44**
|
|
76
|
+
- event-operations-aggregates.test.ts: 23 tests
|
|
77
|
+
- session-operations-aggregates.test.ts: 9 tests
|
|
78
|
+
- task-operations-counts.test.ts: 3 tests
|
|
79
|
+
- skill-operations-counts.test.ts: 9 tests
|
|
80
|
+
- 旧 storage 测试回归: 通过(除 pre-existing failure)
|
|
81
|
+
- tsc: **0 errors**
|
|
82
|
+
- npm test: **541 passed / 542**(仅 pre-existing `linkEventToTask` 失败)
|
|
83
|
+
|
|
84
|
+
## 实施决策
|
|
85
|
+
|
|
86
|
+
1. **LIKE '%error%' 失败检测保持原 SQL 三个 OR 分支**
|
|
87
|
+
- `tool_output LIKE '%"error"%' OR LIKE '%"is_error":true%' OR LIKE '%"isError":true%'`
|
|
88
|
+
- 测试覆盖三种 tool_output JSON 形态,确认全部命中
|
|
89
|
+
|
|
90
|
+
2. **时间区间统一 `[since, until)` 半开半闭语义**
|
|
91
|
+
- 调用方负责 ISO 字符串构造(`new Date(since).toISOString()`)
|
|
92
|
+
- until 一律 `<`(与 weekly-report.ts 原 `start_time < ?` 一致)
|
|
93
|
+
- 与 stats.ts 原 `date('now', '-7 days')` 语义不同:新方法不再隐含 now(),调用方计算
|
|
94
|
+
|
|
95
|
+
3. **`queryFileEditInputs` 内部展开 placeholders**
|
|
96
|
+
- tool_names 通过参数注入,避免外部拼 SQL
|
|
97
|
+
- 空 list 直接返回空数组(避免 `IN ()` SQL 错误)
|
|
98
|
+
|
|
99
|
+
4. **`aggregateToolUsage` 合并 stats / weekly-report 两个用例**
|
|
100
|
+
- 通过 `hook_type` 可选过滤 + `since` 可选过滤兼顾两种调用
|
|
101
|
+
- `tool_name IS NOT NULL AND tool_name != ''` 始终生效(stats.ts 原行为)
|
|
102
|
+
|
|
103
|
+
5. **`aggregateAgentTypeBySession` 与 `aggregateToolUsageBySession` 分离**
|
|
104
|
+
- 前者 `tool_name IN ('Agent','Task')` + json_extract subagent_type(stop.ts:163 / trace.ts:111)
|
|
105
|
+
- 后者纯 `tool_name IS NOT NULL`(stop.ts:154)
|
|
106
|
+
- 两段语义不同,分别封装
|
|
107
|
+
|
|
108
|
+
## 待 Phase 3 处理
|
|
109
|
+
|
|
110
|
+
- 替换 src/web/routes/stats.ts(5 段 SQL)
|
|
111
|
+
- 替换 src/web/routes/trace.ts(3 段 SQL)
|
|
112
|
+
- 替换 src/cli/commands/trace.ts(3 段 SQL)
|
|
113
|
+
- 替换 src/daemon/handlers/stop.ts:154-178(3 段 SQL)
|
|
114
|
+
- 替换 src/web/analytics/drift-detector.ts(4 段 SQL)
|
|
115
|
+
- 替换 src/web/analytics/weekly-report.ts(6 段 SQL)
|
|
116
|
+
- 替换 src/web/analytics/anti-pattern-detector.ts(2 段 SQL)
|
|
117
|
+
|
|
118
|
+
## 已知问题
|
|
119
|
+
|
|
120
|
+
- `tests/unit/storage/sqlite-refactor-harness.test.ts > linkEventToTask` pre-existing 失败(与 Phase 2 改动无关,event_id 未传 UUID 导致 zod schema 拒收)
|