@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.
- package/DEVELOPMENT.md +290 -221
- package/README.md +50 -8
- package/dist/cli/commands/skills.d.ts.map +1 -1
- package/dist/cli/commands/skills.js +7 -3
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/init/hook-manager.d.ts +1 -1
- package/dist/cli/init/hook-manager.d.ts.map +1 -1
- package/dist/cli/init/hook-manager.js +1 -0
- package/dist/cli/init/hook-manager.js.map +1 -1
- package/dist/core/storage/events.d.ts.map +1 -1
- package/dist/core/storage/events.js +0 -1
- package/dist/core/storage/events.js.map +1 -1
- package/dist/core/storage/maintenance.d.ts +25 -3
- package/dist/core/storage/maintenance.d.ts.map +1 -1
- package/dist/core/storage/maintenance.js +33 -4
- package/dist/core/storage/maintenance.js.map +1 -1
- package/dist/core/storage/routing.d.ts +4 -0
- package/dist/core/storage/routing.d.ts.map +1 -1
- package/dist/core/storage/routing.js +10 -4
- package/dist/core/storage/routing.js.map +1 -1
- package/dist/core/storage/sessions.d.ts +17 -0
- package/dist/core/storage/sessions.d.ts.map +1 -1
- package/dist/core/storage/sessions.js +64 -0
- package/dist/core/storage/sessions.js.map +1 -1
- package/dist/core/storage/skills.d.ts +4 -0
- package/dist/core/storage/skills.d.ts.map +1 -1
- package/dist/core/storage/skills.js +10 -2
- package/dist/core/storage/skills.js.map +1 -1
- package/dist/core/storage/sqlite.d.ts +5 -0
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +6 -0
- package/dist/core/storage/sqlite.js.map +1 -1
- package/dist/core/storage/tasks.d.ts.map +1 -1
- package/dist/core/storage/tasks.js +2 -0
- package/dist/core/storage/tasks.js.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +19 -4
- package/dist/daemon/index.js.map +1 -1
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +13 -2
- package/dist/skills/registry.js.map +1 -1
- package/dist/skills/semantic-matcher.d.ts +2 -2
- package/dist/skills/semantic-matcher.d.ts.map +1 -1
- package/dist/skills/semantic-matcher.js +14 -19
- package/dist/skills/semantic-matcher.js.map +1 -1
- package/dist/skills/upgrade-engine.d.ts +3 -1
- package/dist/skills/upgrade-engine.d.ts.map +1 -1
- package/dist/skills/upgrade-engine.js +25 -14
- package/dist/skills/upgrade-engine.js.map +1 -1
- package/dist/web/analytics/weekly-report.d.ts.map +1 -1
- package/dist/web/analytics/weekly-report.js +21 -29
- package/dist/web/analytics/weekly-report.js.map +1 -1
- package/dist/web/routes/patch.d.ts.map +1 -1
- package/dist/web/routes/patch.js +32 -2
- package/dist/web/routes/patch.js.map +1 -1
- package/dist/web/routes/sessions.d.ts.map +1 -1
- package/dist/web/routes/sessions.js +9 -7
- package/dist/web/routes/sessions.js.map +1 -1
- package/dist/web/routes/trace.d.ts.map +1 -1
- package/dist/web/routes/trace.js +2 -3
- package/dist/web/routes/trace.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +3 -2
- package/dist/web/server.js.map +1 -1
- package/package.json +12 -2
- package/scripts/postinstall.cjs +21 -0
- package/.claude/CLAUDE.md +0 -17
- package/.eslintrc.js +0 -23
- package/.prettierrc +0 -8
- package/ARCHITECTURE_ISSUES.md +0 -249
- package/CLAUDE.md +0 -265
- package/CLAUDE.md.backup +0 -488
- package/docs/concurrent-agents.md +0 -129
- package/docs/design/architecture-review-20260516.md +0 -232
- package/docs/design/fix-skills-data-and-set-leak-spec-20260516-1300.md +0 -219
- package/docs/design/h1-storage-aggregation-spec-20260518-1121.md +0 -299
- package/docs/design/h2-getdatabase-encapsulation-spec-20260518-1450.md +0 -191
- package/docs/design/h3-fallback-removal-spec-20260518-1245.md +0 -76
- package/docs/design/h4-index-dedup-spec-20260518-1230.md +0 -109
- package/docs/design/h6-services-migration-spec-20260518-1355.md +0 -82
- package/docs/design/hook-failure-queue-spec-20260516-1530.md +0 -204
- package/docs/design/l1-swarm-protocol-extract-spec-20260518-1605.md +0 -106
- package/docs/design/m10-forge-paths-spec-20260518-1320.md +0 -121
- package/docs/design/m2-m3-tool-input-spec-20260518-1425.md +0 -131
- package/docs/design/m7-routing-event-association-spec-20260518-1545.md +0 -103
- package/docs/design/project-path-gitroot-spec-20260518-1715.md +0 -134
- package/docs/design/refactor-phase1-spec-20260515-1600.md +0 -543
- package/docs/design/refactor-phase2-spec-20260515-1700.md +0 -424
- package/docs/design/skill-ai-upgrade-spec-20260518-1930.md +0 -297
- package/docs/design/task-active-gc-spec-20260518-1745.md +0 -146
- package/docs/design/tasks-list-filter-pagination-spec-20260518-0930.md +0 -208
- package/docs/implementation/daemon-skill-sync-changelog-20260518-2000.md +0 -22
- package/docs/implementation/fix-skills-data-and-set-leak-changelog-20260516-1300.md +0 -104
- package/docs/implementation/h1-storage-aggregation-changelog-20260518-1121.md +0 -82
- package/docs/implementation/h2-final-changelog-20260518-1530.md +0 -61
- package/docs/implementation/h2-phase1-safety-net-changelog-20260518-1450.md +0 -70
- package/docs/implementation/h2-phase2-operations-changelog-20260518-1450.md +0 -120
- package/docs/implementation/h2-phase3-callsites-changelog-20260518-1450.md +0 -71
- package/docs/implementation/h3-fallback-removal-changelog-20260518-1245.md +0 -71
- package/docs/implementation/h4-index-dedup-changelog-20260518-1230.md +0 -60
- package/docs/implementation/h6-services-migration-changelog-20260518-1355.md +0 -46
- package/docs/implementation/h7-m9-defaults-changelog-20260518-1300.md +0 -46
- package/docs/implementation/hook-failure-queue-changelog-20260516-1530.md +0 -196
- package/docs/implementation/hotfix-daemon-event-reject-20260516-1430.md +0 -56
- package/docs/implementation/l1-swarm-protocol-extract-changelog-20260518-1605.md +0 -45
- package/docs/implementation/l3-l4-daemon-perf-changelog-20260518-1410.md +0 -63
- package/docs/implementation/l6-l8-final-cleanup-changelog-20260518-1640.md +0 -38
- package/docs/implementation/m1-m4-m5-l7-cleanup-changelog-20260518-1310.md +0 -58
- package/docs/implementation/m10-forge-paths-changelog-20260518-1320.md +0 -60
- package/docs/implementation/m2-m3-tool-input-changelog-20260518-1425.md +0 -43
- package/docs/implementation/m6-m8-naming-shutdown-changelog-20260518-1340.md +0 -56
- package/docs/implementation/m7-routing-association-changelog-20260518-1545.md +0 -69
- package/docs/implementation/project-path-gitroot-changelog-20260518-1715.md +0 -63
- package/docs/implementation/refactor-phase1-changelog-20260515-1630.md +0 -354
- package/docs/implementation/refactor-phase2-changelog-20260515-1705.md +0 -421
- package/docs/implementation/skill-ai-upgrade-changelog-20260518-1930.md +0 -49
- package/docs/implementation/task-active-gc-changelog-20260518-1745.md +0 -35
- package/docs/implementation/task-title-summary-changelog-20260518-1130.md +0 -39
- package/docs/implementation/tasks-detail-back-loses-filters-changelog-20260518-1100.md +0 -22
- package/docs/implementation/tasks-list-filter-pagination-changelog-20260518-0930.md +0 -72
- package/docs/implementation/tasks-page-white-screen-hotfix-changelog-20260518-1015.md +0 -56
- package/docs/reviews/claudemd-template-sync.md +0 -54
- package/docs/reviews/task-title-summary.md +0 -92
- package/docs/reviews/tasks-detail-back-loses-filters.md +0 -58
- package/docs/reviews/tasks-filter-pagination.md +0 -80
- package/docs/reviews/tasks-page-white-screen-hotfix.md +0 -126
- package/docs/ruflo-learning-strategy.md +0 -322
- package/docs/skills-deduplication-analysis.md +0 -83
- package/docs/skills-multiformat-support.md +0 -177
- package/docs/skills-third-party.md +0 -183
- package/docs/testing/tasks-filter-pagination-test-report.md +0 -86
- package/forge +0 -321
- package/playwright.config.ts +0 -40
- package/scripts/demo-v2.ts +0 -91
- package/scripts/dev-daemon.sh +0 -232
- package/scripts/dev-web.ts +0 -109
- package/scripts/e2e-mcp-link.ts +0 -423
- package/scripts/e2e-methodology-quality.ts +0 -253
- package/scripts/e2e-routing.ts +0 -456
- package/scripts/e2e-user-methodology.ts +0 -326
- package/scripts/e2e-web-workflows.ts +0 -299
- package/scripts/migrate-legacy-to-dynamic.sql +0 -108
- package/scripts/regenerate-execution-docs.ts +0 -116
- package/scripts/sync-agent-skills.ts +0 -193
- package/scripts/test-hook.sh +0 -71
- package/scripts/verify-skill-loading.ts +0 -62
- package/src/claudemd/claudemd-generator.ts +0 -568
- package/src/claudemd/convention-extractor.ts +0 -69
- package/src/claudemd/index.ts +0 -35
- package/src/claudemd/persona-manager.ts +0 -88
- package/src/claudemd/resume-manager.ts +0 -236
- package/src/claudemd/tech-detector.ts +0 -220
- package/src/claudemd/templates/swarm-protocol.md +0 -222
- package/src/cli/commands/claudemd.ts +0 -84
- package/src/cli/commands/config.ts +0 -46
- package/src/cli/commands/daemon.ts +0 -310
- package/src/cli/commands/executions.ts +0 -115
- package/src/cli/commands/init.ts +0 -204
- package/src/cli/commands/logs.ts +0 -181
- package/src/cli/commands/mcp.ts +0 -242
- package/src/cli/commands/menu.ts +0 -357
- package/src/cli/commands/skills.ts +0 -328
- package/src/cli/commands/stats.ts +0 -73
- package/src/cli/commands/status.ts +0 -69
- package/src/cli/commands/template.ts +0 -77
- package/src/cli/commands/trace.ts +0 -148
- package/src/cli/index.ts +0 -42
- package/src/cli/init/hook-manager.ts +0 -132
- package/src/core/ai/provider.ts +0 -308
- package/src/core/ai/types.ts +0 -51
- package/src/core/config.ts +0 -124
- package/src/core/constants.ts +0 -67
- package/src/core/event-fields.ts +0 -32
- package/src/core/queue/index.ts +0 -192
- package/src/core/storage/base.ts +0 -302
- package/src/core/storage/events.ts +0 -434
- package/src/core/storage/injections.ts +0 -78
- package/src/core/storage/maintenance.ts +0 -59
- package/src/core/storage/migrations/002_add_skill_tracking.sql +0 -6
- package/src/core/storage/migrations/003_add_skill_invocations.sql +0 -23
- package/src/core/storage/performance-indexes.sql +0 -23
- package/src/core/storage/routing.ts +0 -322
- package/src/core/storage/rows.ts +0 -112
- package/src/core/storage/schema.sql +0 -224
- package/src/core/storage/sessions.ts +0 -168
- package/src/core/storage/skills.ts +0 -233
- package/src/core/storage/sqlite.ts +0 -293
- package/src/core/storage/tasks.ts +0 -318
- package/src/core/storage/token-usage.ts +0 -93
- package/src/core/types.ts +0 -181
- package/src/core/utils/error-handler.ts +0 -257
- package/src/core/utils/forge-resume-block.ts +0 -74
- package/src/core/utils/format.ts +0 -69
- package/src/core/utils/git.ts +0 -23
- package/src/core/utils/logger.ts +0 -134
- package/src/core/utils/lru-cache.ts +0 -54
- package/src/core/utils/path.ts +0 -19
- package/src/core/utils/session.ts +0 -26
- package/src/core/utils/time.ts +0 -37
- package/src/core/utils/token-tracker.ts +0 -97
- package/src/daemon/event-parser.ts +0 -36
- package/src/daemon/handlers/history-exporter.ts +0 -117
- package/src/daemon/handlers/post-tool-use.ts +0 -54
- package/src/daemon/handlers/stop.ts +0 -208
- package/src/daemon/handlers/user-prompt.ts +0 -178
- package/src/daemon/hook-sync.ts +0 -91
- package/src/daemon/index.ts +0 -312
- package/src/daemon/launchd/com.claude-forge.daemon.plist.template +0 -47
- package/src/daemon/launchd-installer.ts +0 -260
- package/src/daemon/lifecycle.ts +0 -128
- package/src/daemon/router.ts +0 -40
- package/src/daemon/server.ts +0 -196
- package/src/daemon/services/task-segmenter.ts +0 -112
- package/src/daemon/skill-sync.ts +0 -88
- package/src/hooks/hook-lib.sh +0 -118
- package/src/hooks/notification.sh +0 -35
- package/src/hooks/post-tool-use.sh +0 -61
- package/src/hooks/pre-tool-use.sh +0 -63
- package/src/hooks/stop.sh +0 -43
- package/src/hooks/user-prompt-submit.sh +0 -69
- package/src/mcp/server.ts +0 -322
- package/src/skills/index.ts +0 -2
- package/src/skills/invocation-guard.ts +0 -177
- package/src/skills/matcher.ts +0 -148
- package/src/skills/official/code-simplifier.md +0 -52
- package/src/skills/official/find-skills.md +0 -142
- package/src/skills/official/official-api-design.md +0 -30
- package/src/skills/official/official-architecture-decision.md +0 -41
- package/src/skills/official/official-bmad.md +0 -118
- package/src/skills/official/official-db-schema-design.md +0 -34
- package/src/skills/official/official-debug.md +0 -25
- package/src/skills/official/official-doc-driven.md +0 -31
- package/src/skills/official/official-harness-engineering.md +0 -108
- package/src/skills/official/official-performance-optimization.md +0 -30
- package/src/skills/official/official-pr-review.md +0 -35
- package/src/skills/official/official-release-checklist.md +0 -30
- package/src/skills/official/official-security-hardening.md +0 -32
- package/src/skills/official/official-spec-driven-design.md +0 -31
- package/src/skills/official/planning-with-files.md +0 -241
- package/src/skills/official/ui-ux-pro-max.md +0 -105
- package/src/skills/official/webapp-testing.md +0 -96
- package/src/skills/official-skills.ts +0 -89
- package/src/skills/registry.ts +0 -355
- package/src/skills/semantic-matcher.ts +0 -234
- package/src/skills/tools/pipeline-suggest.ts +0 -226
- package/src/skills/tools/skill-invoke.ts +0 -168
- package/src/skills/tools/skill-list.ts +0 -59
- package/src/skills/upgrade-engine.ts +0 -541
- package/src/skills/upgrade-prompt.ts +0 -84
- package/src/templates/go.yaml +0 -53
- package/src/templates/python.yaml +0 -59
- package/src/templates/react.yaml +0 -55
- package/src/templates/template-manager.ts +0 -170
- package/src/web/analytics/anti-pattern-detector.ts +0 -367
- package/src/web/analytics/drift-detector.ts +0 -219
- package/src/web/analytics/weekly-report.ts +0 -431
- package/src/web/auth-middleware.ts +0 -54
- package/src/web/routes/_helpers.ts +0 -34
- package/src/web/routes/ai.ts +0 -204
- package/src/web/routes/auth.ts +0 -22
- package/src/web/routes/drift.ts +0 -25
- package/src/web/routes/error-handler.ts +0 -120
- package/src/web/routes/events.ts +0 -47
- package/src/web/routes/insights.ts +0 -43
- package/src/web/routes/patch.ts +0 -117
- package/src/web/routes/reports.ts +0 -34
- package/src/web/routes/rules.ts +0 -76
- package/src/web/routes/sessions.ts +0 -250
- package/src/web/routes/skill-stats.ts +0 -92
- package/src/web/routes/skills.ts +0 -350
- package/src/web/routes/static.ts +0 -67
- package/src/web/routes/stats.ts +0 -50
- package/src/web/routes/status.ts +0 -30
- package/src/web/routes/tasks.ts +0 -193
- package/src/web/routes/token-usage.ts +0 -20
- package/src/web/routes/trace.ts +0 -126
- package/src/web/routes/types.ts +0 -57
- package/src/web/server.ts +0 -134
- package/src/web/ssrf-guard.ts +0 -112
- package/src/web/static/index.html +0 -3251
- package/src/web/static/vendor/chart.umd.min.js +0 -20
- package/tests/e2e/dashboard.spec.ts +0 -205
- package/tests/e2e/routing-skill-e2e.test.ts +0 -39
- package/tests/helpers/mock-ai.ts +0 -92
- package/tests/helpers/mock-storage.ts +0 -159
- package/tests/integration/claudemd-generator.test.ts +0 -90
- package/tests/integration/queue-replay.integration.test.ts +0 -193
- package/tests/integration/tasks-filter.integration.test.ts +0 -154
- package/tests/integration/web-analytics.integration.test.ts +0 -133
- package/tests/integration/web-stats.integration.test.ts +0 -135
- package/tests/integration/web-trace.integration.test.ts +0 -175
- package/tests/performance/database.benchmark.ts +0 -161
- package/tests/semantic-matcher.test.ts +0 -99
- package/tests/skill-matcher.test.ts +0 -110
- package/tests/unit/ai-provider-retry.test.ts +0 -194
- package/tests/unit/ai-provider-vision.test.ts +0 -224
- package/tests/unit/claudemd-generator.test.ts +0 -68
- package/tests/unit/cli-mcp.test.ts +0 -141
- package/tests/unit/core/forge-paths.test.ts +0 -99
- package/tests/unit/daemon/hook-sync.test.ts +0 -71
- package/tests/unit/daemon/post-tool-use.test.ts +0 -121
- package/tests/unit/daemon/skill-sync.test.ts +0 -75
- package/tests/unit/daemon/stop-handler-behavior-summary.test.ts +0 -202
- package/tests/unit/daemon/task-segmenter-recover.test.ts +0 -84
- package/tests/unit/event-fields.test.ts +0 -88
- package/tests/unit/event-parser.test.ts +0 -55
- package/tests/unit/handlers.test.ts +0 -171
- package/tests/unit/hooks/resolve-project-path.test.ts +0 -122
- package/tests/unit/invocation-guard.test.ts +0 -125
- package/tests/unit/queue.test.ts +0 -272
- package/tests/unit/router.test.ts +0 -138
- package/tests/unit/security.test.ts +0 -128
- package/tests/unit/skill-invocations-workflow.test.ts +0 -495
- package/tests/unit/skill-registry.test.ts +0 -94
- package/tests/unit/skills/invocation-guard-ttl.test.ts +0 -211
- package/tests/unit/skills/official-skills-loader.test.ts +0 -126
- package/tests/unit/skills/registry-multiformat.test.ts +0 -92
- package/tests/unit/skills/upgrade-engine-parse.test.ts +0 -138
- package/tests/unit/skills/upgrade-engine.test.ts +0 -401
- package/tests/unit/skills/upgrade-prompt.test.ts +0 -89
- package/tests/unit/socket-server.test.ts +0 -183
- package/tests/unit/storage/event-operations-aggregates.test.ts +0 -342
- package/tests/unit/storage/migration-idempotent.test.ts +0 -304
- package/tests/unit/storage/routing-aggregates.test.ts +0 -276
- package/tests/unit/storage/routing.test.ts +0 -117
- package/tests/unit/storage/schema-missing.test.ts +0 -81
- package/tests/unit/storage/session-operations-aggregates.test.ts +0 -120
- package/tests/unit/storage/sessions-aggregate.test.ts +0 -435
- package/tests/unit/storage/skill-operations-counts.test.ts +0 -106
- package/tests/unit/storage/skills-aggregates.test.ts +0 -104
- package/tests/unit/storage/sqlite-refactor-harness.test.ts +0 -314
- package/tests/unit/storage/task-operations-counts.test.ts +0 -46
- package/tests/unit/storage/tasks-getById.test.ts +0 -343
- package/tests/unit/storage/tasks-stale-gc.test.ts +0 -86
- package/tests/unit/storage.test.ts +0 -172
- package/tests/unit/token-usage.test.ts +0 -144
- package/tests/unit/type-guards.test.ts +0 -201
- package/tests/unit/utils/format.test.ts +0 -189
- package/tests/unit/utils/session.test.ts +0 -89
- package/tests/unit/utils/time.test.ts +0 -112
- package/tests/unit/web/navigation-back-contract.test.ts +0 -134
- package/tests/unit/web/routes-auth.test.ts +0 -93
- package/tests/unit/web/routes-events.test.ts +0 -101
- package/tests/unit/web/routes-rules.test.ts +0 -182
- package/tests/unit/web/routes-sessions.test.ts +0 -181
- package/tests/unit/web/routes-skill-stats.test.ts +0 -179
- package/tests/unit/web/routes-stats.test.ts +0 -92
- package/tests/unit/web/routes-tasks.test.ts +0 -385
- package/tests/unit/web/task-title-contract.test.ts +0 -210
- package/tests/unit/web/tasks-component-contract.test.ts +0 -179
- package/tsconfig.json +0 -22
- package/vitest.config.ts +0 -21
- package/vitest.integration.config.ts +0 -16
- package/web/CLAUDE.md +0 -20
- package/web/index.html +0 -13
- package/web/package-lock.json +0 -4854
- package/web/package.json +0 -35
- package/web/postcss.config.js +0 -6
- package/web/src/App.tsx +0 -110
- package/web/src/components/CodeBlock.tsx +0 -31
- package/web/src/components/Confirm.tsx +0 -96
- package/web/src/components/Drawer.tsx +0 -60
- package/web/src/components/Layout.tsx +0 -145
- package/web/src/components/MarkdownRenderer.tsx +0 -77
- package/web/src/components/SearchInput.tsx +0 -31
- package/web/src/components/SessionDetailContent.tsx +0 -157
- package/web/src/components/Toast.tsx +0 -92
- package/web/src/index.css +0 -19
- package/web/src/main.tsx +0 -31
- package/web/src/pages/AIConfig.tsx +0 -233
- package/web/src/pages/Dashboard.tsx +0 -572
- package/web/src/pages/Events.tsx +0 -271
- package/web/src/pages/Reports.tsx +0 -428
- package/web/src/pages/SessionDetail.tsx +0 -162
- package/web/src/pages/Sessions.tsx +0 -205
- package/web/src/pages/Skills.tsx +0 -180
- package/web/src/pages/TaskDetail.tsx +0 -515
- package/web/src/pages/Tasks.tsx +0 -415
- package/web/src/utils/auth.ts +0 -59
- package/web/src/utils/export.ts +0 -54
- package/web/src/utils/navigation.ts +0 -25
- package/web/src/utils/task-title.ts +0 -49
- package/web/src/utils/time.ts +0 -13
- package/web/tailwind.config.js +0 -11
- package/web/tsconfig.json +0 -21
- package/web/tsconfig.node.json +0 -10
- package/web/vite.config.ts +0 -76
- package/winspan-claude-forge-8.43.0.tgz +0 -0
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TaskOperations — tasks 表读写
|
|
3
|
-
*
|
|
4
|
-
* 拆分自 sqlite.ts。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type Database from 'better-sqlite3';
|
|
8
|
-
import type { ForgeEvent } from '../types.js';
|
|
9
|
-
import type { SkillInvocationRow } from './rows.js';
|
|
10
|
-
import type { Injection } from './injections.js';
|
|
11
|
-
|
|
12
|
-
export interface TaskRecord {
|
|
13
|
-
id: string;
|
|
14
|
-
session_id: string;
|
|
15
|
-
title: string;
|
|
16
|
-
description?: string;
|
|
17
|
-
start_time: string;
|
|
18
|
-
end_time?: string;
|
|
19
|
-
status: 'active' | 'completed' | 'abandoned';
|
|
20
|
-
event_count: number;
|
|
21
|
-
project_path?: string;
|
|
22
|
-
/** First UserPromptSubmit user_prompt text for this task's session window.
|
|
23
|
-
* Populated by queryTasksFiltered via correlated subquery on idx_events_session_hook. */
|
|
24
|
-
first_prompt?: string | null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface TaskFilter {
|
|
28
|
-
session_id?: string;
|
|
29
|
-
limit?: number;
|
|
30
|
-
offset?: number;
|
|
31
|
-
project?: string | string[];
|
|
32
|
-
from?: string;
|
|
33
|
-
to?: string;
|
|
34
|
-
search?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface TaskPage {
|
|
38
|
-
items: TaskRecord[];
|
|
39
|
-
total: number;
|
|
40
|
-
has_more: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export class TaskOperations {
|
|
44
|
-
constructor(private db: Database.Database) {}
|
|
45
|
-
|
|
46
|
-
writeTask(task: { id: string; session_id: string; title: string; start_time: string }): void {
|
|
47
|
-
this.db.prepare(`
|
|
48
|
-
INSERT INTO tasks (id, session_id, title, start_time) VALUES (?, ?, ?, ?)
|
|
49
|
-
`).run(task.id, task.session_id, task.title, task.start_time);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
updateTask(taskId: string, updates: { end_time?: string; status?: string; event_count?: number; title?: string }): void {
|
|
53
|
-
const sets: string[] = [];
|
|
54
|
-
const params: unknown[] = [];
|
|
55
|
-
if (updates.end_time !== undefined) { sets.push('end_time = ?'); params.push(updates.end_time); }
|
|
56
|
-
if (updates.status !== undefined) { sets.push('status = ?'); params.push(updates.status); }
|
|
57
|
-
if (updates.event_count !== undefined) { sets.push('event_count = ?'); params.push(updates.event_count); }
|
|
58
|
-
if (updates.title !== undefined) { sets.push('title = ?'); params.push(updates.title); }
|
|
59
|
-
if (sets.length === 0) return;
|
|
60
|
-
params.push(taskId);
|
|
61
|
-
this.db.prepare(`UPDATE tasks SET ${sets.join(', ')} WHERE id = ?`).run(...params);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
linkEventToTask(taskId: string, eventId: string): void {
|
|
65
|
-
this.db.prepare(`INSERT OR IGNORE INTO task_events (task_id, event_id) VALUES (?, ?)`).run(taskId, eventId);
|
|
66
|
-
this.db.prepare(`UPDATE tasks SET event_count = event_count + 1, end_time = (SELECT timestamp FROM events WHERE event_id = ?) WHERE id = ?`).run(eventId, taskId);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Legacy simple query — returns bare array (used by detail route internally) */
|
|
70
|
-
queryTasks(filter: { session_id?: string; limit?: number } = {}): TaskRecord[] {
|
|
71
|
-
const conditions: string[] = [];
|
|
72
|
-
const params: unknown[] = [];
|
|
73
|
-
if (filter.session_id) { conditions.push('session_id = ?'); params.push(filter.session_id); }
|
|
74
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
75
|
-
const limit = filter.limit ?? 50;
|
|
76
|
-
params.push(limit);
|
|
77
|
-
const rows = this.db.prepare(`SELECT * FROM tasks ${where} ORDER BY start_time DESC LIMIT ?`).all(...params) as Array<Record<string, unknown>>;
|
|
78
|
-
return rows.map(r => this.mapRow(r));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* queryTasksFiltered — paginated query with full filter support.
|
|
83
|
-
* JOINs sessions to expose project_path.
|
|
84
|
-
*/
|
|
85
|
-
queryTasksFiltered(filter: TaskFilter = {}): TaskPage {
|
|
86
|
-
const { conditions, params } = this.buildWhereConditions(filter);
|
|
87
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
88
|
-
|
|
89
|
-
const limit = Math.min(Math.max(filter.limit ?? 50, 1), 200);
|
|
90
|
-
const offset = Math.max(filter.offset ?? 0, 0);
|
|
91
|
-
|
|
92
|
-
// Count query
|
|
93
|
-
const countRow = this.db.prepare(
|
|
94
|
-
`SELECT COUNT(*) as cnt FROM tasks t JOIN sessions s ON t.session_id = s.session_id ${where}`
|
|
95
|
-
).get(...params) as { cnt: number };
|
|
96
|
-
const total = countRow?.cnt ?? 0;
|
|
97
|
-
|
|
98
|
-
// Data query
|
|
99
|
-
const dataParams = [...params, limit, offset];
|
|
100
|
-
const rows = this.db.prepare(
|
|
101
|
-
`SELECT t.*, s.project_path,
|
|
102
|
-
(SELECT e.user_prompt
|
|
103
|
-
FROM events e
|
|
104
|
-
WHERE e.session_id = t.session_id
|
|
105
|
-
AND e.hook_type = 'UserPromptSubmit'
|
|
106
|
-
AND e.timestamp >= t.start_time
|
|
107
|
-
AND (t.end_time IS NULL OR e.timestamp <= t.end_time)
|
|
108
|
-
ORDER BY e.timestamp ASC LIMIT 1) AS first_prompt
|
|
109
|
-
FROM tasks t
|
|
110
|
-
JOIN sessions s ON t.session_id = s.session_id
|
|
111
|
-
${where}
|
|
112
|
-
ORDER BY t.start_time DESC
|
|
113
|
-
LIMIT ? OFFSET ?`
|
|
114
|
-
).all(...dataParams) as Array<Record<string, unknown>>;
|
|
115
|
-
|
|
116
|
-
const items = rows.map(r => this.mapRow(r));
|
|
117
|
-
return { items, total, has_more: offset + items.length < total };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Count of tasks with start_time in [since, until?). */
|
|
121
|
-
countTasksByRange(opts: { since: string; until?: string }): number {
|
|
122
|
-
const conditions: string[] = ['start_time >= ?'];
|
|
123
|
-
const params: unknown[] = [opts.since];
|
|
124
|
-
if (opts.until !== undefined) {
|
|
125
|
-
conditions.push('start_time < ?');
|
|
126
|
-
params.push(opts.until);
|
|
127
|
-
}
|
|
128
|
-
const sql = `SELECT COUNT(*) as cnt FROM tasks WHERE ${conditions.join(' AND ')}`;
|
|
129
|
-
const row = this.db.prepare(sql).get(...params) as { cnt: number } | undefined;
|
|
130
|
-
return row?.cnt ?? 0;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Returns distinct project paths that have at least one task. */
|
|
134
|
-
queryTaskProjects(): string[] {
|
|
135
|
-
const rows = this.db.prepare(
|
|
136
|
-
`SELECT DISTINCT s.project_path
|
|
137
|
-
FROM sessions s
|
|
138
|
-
JOIN tasks t ON t.session_id = s.session_id
|
|
139
|
-
ORDER BY s.project_path`
|
|
140
|
-
).all() as Array<{ project_path: string }>;
|
|
141
|
-
return rows.map(r => r.project_path);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
getTaskEventIds(taskId: string): string[] {
|
|
145
|
-
const rows = this.db.prepare(`SELECT event_id FROM task_events WHERE task_id = ?`).all(taskId) as Array<{ event_id: string }>;
|
|
146
|
-
return rows.map(r => r.event_id);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 将 idle 超过阈值的 active task 批量转为 completed。
|
|
151
|
-
* 条件:status='active' AND end_time IS NOT NULL
|
|
152
|
-
* AND (now - end_time) > idleMinutes 分钟。
|
|
153
|
-
* 返回:受影响行数。
|
|
154
|
-
*/
|
|
155
|
-
completeStaleActiveTasks(idleMinutes: number): number {
|
|
156
|
-
const result = this.db.prepare(`
|
|
157
|
-
UPDATE tasks
|
|
158
|
-
SET status = 'completed'
|
|
159
|
-
WHERE status = 'active'
|
|
160
|
-
AND end_time IS NOT NULL
|
|
161
|
-
AND (julianday('now') - julianday(end_time)) * 24 * 60 > ?
|
|
162
|
-
`).run(idleMinutes);
|
|
163
|
-
return result.changes as number;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// ── H1: detail route 用的 PK 直查 / JOIN 接口 ──────────────────────
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 按 taskId 直查单个 task(LEFT JOIN sessions 取 project_path)。
|
|
170
|
-
* 替代旧 detail route 的「拉 5000 tasks 再 find(id)」。
|
|
171
|
-
*/
|
|
172
|
-
getTask(taskId: string): TaskRecord | null {
|
|
173
|
-
const row = this.db.prepare(`
|
|
174
|
-
SELECT t.*, s.project_path
|
|
175
|
-
FROM tasks t
|
|
176
|
-
LEFT JOIN sessions s ON s.session_id = t.session_id
|
|
177
|
-
WHERE t.id = ?
|
|
178
|
-
`).get(taskId) as Record<string, unknown> | undefined;
|
|
179
|
-
if (!row) return null;
|
|
180
|
-
return this.mapRow(row);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* 按 taskId JOIN task_events 拉关联事件,按 timestamp 升序。
|
|
185
|
-
* 默认 limit 5000(防御过大 task;前端不分页但要有上限)。
|
|
186
|
-
*/
|
|
187
|
-
queryEventsByTaskId(taskId: string, opts: { limit?: number } = {}): ForgeEvent[] {
|
|
188
|
-
const limit = opts.limit ?? 5000;
|
|
189
|
-
const rows = this.db.prepare(`
|
|
190
|
-
SELECT e.*
|
|
191
|
-
FROM events e
|
|
192
|
-
JOIN task_events te ON te.event_id = e.event_id
|
|
193
|
-
WHERE te.task_id = ?
|
|
194
|
-
ORDER BY e.timestamp ASC
|
|
195
|
-
LIMIT ?
|
|
196
|
-
`).all(taskId, limit) as Array<Record<string, unknown>>;
|
|
197
|
-
return rows.map(r => this.rowToEvent(r));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* 按 taskId JOIN task_events 拉关联 injections,按 timestamp 升序。
|
|
202
|
-
* 替代「拉 500 injections + JS Set.has 过滤」。
|
|
203
|
-
*/
|
|
204
|
-
queryInjectionsByTaskId(taskId: string): Injection[] {
|
|
205
|
-
const rows = this.db.prepare(`
|
|
206
|
-
SELECT i.*
|
|
207
|
-
FROM injections i
|
|
208
|
-
JOIN task_events te ON te.event_id = i.event_id
|
|
209
|
-
WHERE te.task_id = ?
|
|
210
|
-
ORDER BY i.timestamp ASC
|
|
211
|
-
`).all(taskId) as Array<Record<string, unknown>>;
|
|
212
|
-
return rows.map(r => ({
|
|
213
|
-
id: r.id as string,
|
|
214
|
-
event_id: (r.event_id as string) || undefined,
|
|
215
|
-
session_id: r.session_id as string,
|
|
216
|
-
timestamp: r.timestamp as string,
|
|
217
|
-
source_handler: r.source_handler as string,
|
|
218
|
-
injection_type: r.injection_type as Injection['injection_type'],
|
|
219
|
-
content: r.content as string,
|
|
220
|
-
}));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* 按 task 的时间窗口 + session_id 过滤 skill_invocations。
|
|
225
|
-
* 替代「拉 200 invocations + JS 时间比较」。
|
|
226
|
-
* `now_ms` 通过参数注入(end_time IS NULL 时取此值),便于测试时 mock。
|
|
227
|
-
*
|
|
228
|
-
* 时间转换:strftime('%s', ISO_TS) 返回 unix 秒(丢毫秒),× 1000 → ms。
|
|
229
|
-
* 与旧实现 `new Date(taskStart).getTime()` 相比可能损失最多 999ms,
|
|
230
|
-
* 但 task 时间窗口通常远大于秒级,对结果集影响可忽略。
|
|
231
|
-
*/
|
|
232
|
-
querySkillInvocationsByTaskWindow(taskId: string, opts: { now_ms?: number } = {}): SkillInvocationRow[] {
|
|
233
|
-
const nowMs = opts.now_ms ?? Date.now();
|
|
234
|
-
const rows = this.db.prepare(`
|
|
235
|
-
SELECT si.*
|
|
236
|
-
FROM skill_invocations si
|
|
237
|
-
JOIN tasks t ON t.session_id = si.session_id
|
|
238
|
-
WHERE t.id = ?
|
|
239
|
-
AND si.timestamp >= CAST(strftime('%s', t.start_time) AS INTEGER) * 1000
|
|
240
|
-
AND si.timestamp <= COALESCE(
|
|
241
|
-
CAST(strftime('%s', t.end_time) AS INTEGER) * 1000 + 999,
|
|
242
|
-
?
|
|
243
|
-
)
|
|
244
|
-
ORDER BY si.timestamp ASC
|
|
245
|
-
`).all(taskId, nowMs) as SkillInvocationRow[];
|
|
246
|
-
return rows;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/** Map a raw events row to ForgeEvent (parses JSON columns). */
|
|
250
|
-
private rowToEvent(row: Record<string, unknown>): ForgeEvent {
|
|
251
|
-
const parseJson = (val: unknown): unknown => {
|
|
252
|
-
if (val == null) return undefined;
|
|
253
|
-
if (typeof val !== 'string') return val;
|
|
254
|
-
try { return JSON.parse(val); } catch { return val; }
|
|
255
|
-
};
|
|
256
|
-
return {
|
|
257
|
-
event_id: row.event_id as string,
|
|
258
|
-
session_id: row.session_id as string,
|
|
259
|
-
project_path: row.project_path as string,
|
|
260
|
-
timestamp: row.timestamp as string,
|
|
261
|
-
hook_type: row.hook_type as ForgeEvent['hook_type'],
|
|
262
|
-
tool_name: (row.tool_name as string) || undefined,
|
|
263
|
-
tool_input: parseJson(row.tool_input) as ForgeEvent['tool_input'],
|
|
264
|
-
tool_output: parseJson(row.tool_output) as ForgeEvent['tool_output'],
|
|
265
|
-
user_prompt: (row.user_prompt as string) || undefined,
|
|
266
|
-
ai_response: (row.ai_response as string) || undefined,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
private buildWhereConditions(filter: TaskFilter): { conditions: string[]; params: unknown[] } {
|
|
271
|
-
const conditions: string[] = [];
|
|
272
|
-
const params: unknown[] = [];
|
|
273
|
-
|
|
274
|
-
if (filter.session_id) {
|
|
275
|
-
conditions.push('t.session_id = ?');
|
|
276
|
-
params.push(filter.session_id);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (filter.project) {
|
|
280
|
-
const projects = Array.isArray(filter.project) ? filter.project : [filter.project];
|
|
281
|
-
const placeholders = projects.map(() => '?').join(', ');
|
|
282
|
-
conditions.push(`s.project_path IN (${placeholders})`);
|
|
283
|
-
params.push(...projects);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (filter.from) {
|
|
287
|
-
conditions.push('t.start_time >= ?');
|
|
288
|
-
params.push(filter.from);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (filter.to) {
|
|
292
|
-
conditions.push('t.start_time <= ?');
|
|
293
|
-
params.push(filter.to);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (filter.search) {
|
|
297
|
-
conditions.push('t.title LIKE ?');
|
|
298
|
-
params.push(`%${filter.search}%`);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return { conditions, params };
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
private mapRow(r: Record<string, unknown>): TaskRecord {
|
|
305
|
-
return {
|
|
306
|
-
id: r.id as string,
|
|
307
|
-
session_id: r.session_id as string,
|
|
308
|
-
title: r.title as string,
|
|
309
|
-
description: (r.description as string) || undefined,
|
|
310
|
-
start_time: r.start_time as string,
|
|
311
|
-
end_time: (r.end_time as string) || undefined,
|
|
312
|
-
status: (r.status as TaskRecord['status']) || 'active',
|
|
313
|
-
event_count: (r.event_count as number) || 0,
|
|
314
|
-
project_path: (r.project_path as string) || undefined,
|
|
315
|
-
first_prompt: r.first_prompt !== undefined ? (r.first_prompt as string | null) : undefined,
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TokenUsageOperations — token_usage 表读写
|
|
3
|
-
*
|
|
4
|
-
* 拆分自 sqlite.ts。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type Database from 'better-sqlite3';
|
|
8
|
-
import { logger } from '../utils/logger.js';
|
|
9
|
-
|
|
10
|
-
export class TokenUsageOperations {
|
|
11
|
-
constructor(private db: Database.Database) {}
|
|
12
|
-
|
|
13
|
-
writeTokenUsage(params: {
|
|
14
|
-
session_id: string;
|
|
15
|
-
input_tokens: number;
|
|
16
|
-
output_tokens: number;
|
|
17
|
-
model?: string;
|
|
18
|
-
tool_name?: string;
|
|
19
|
-
}): void {
|
|
20
|
-
const total_tokens = params.input_tokens + params.output_tokens;
|
|
21
|
-
try {
|
|
22
|
-
this.db.prepare(`
|
|
23
|
-
INSERT INTO token_usage (session_id, timestamp,
|
|
24
|
-
input_tokens, output_tokens, total_tokens, model, tool_name)
|
|
25
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
26
|
-
`).run(
|
|
27
|
-
params.session_id,
|
|
28
|
-
Date.now(),
|
|
29
|
-
params.input_tokens,
|
|
30
|
-
params.output_tokens,
|
|
31
|
-
total_tokens,
|
|
32
|
-
params.model ?? null,
|
|
33
|
-
params.tool_name ?? null,
|
|
34
|
-
);
|
|
35
|
-
} catch (err) {
|
|
36
|
-
logger.debug(`[Storage] Failed to record token usage: ${err}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getTokenUsageBySession(session_id: string): {
|
|
41
|
-
total_tokens: number;
|
|
42
|
-
input_tokens: number;
|
|
43
|
-
output_tokens: number;
|
|
44
|
-
} {
|
|
45
|
-
const result = this.db.prepare(`
|
|
46
|
-
SELECT
|
|
47
|
-
COALESCE(SUM(input_tokens), 0) as input_tokens,
|
|
48
|
-
COALESCE(SUM(output_tokens), 0) as output_tokens,
|
|
49
|
-
COALESCE(SUM(total_tokens), 0) as total_tokens
|
|
50
|
-
FROM token_usage WHERE session_id = ?
|
|
51
|
-
`).get(session_id) as { input_tokens: number; output_tokens: number; total_tokens: number };
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
listTokenUsage(filter: {
|
|
56
|
-
session_id?: string;
|
|
57
|
-
limit?: number;
|
|
58
|
-
} = {}): Array<{
|
|
59
|
-
id: number;
|
|
60
|
-
session_id: string;
|
|
61
|
-
timestamp: number;
|
|
62
|
-
input_tokens: number;
|
|
63
|
-
output_tokens: number;
|
|
64
|
-
total_tokens: number;
|
|
65
|
-
model: string | null;
|
|
66
|
-
tool_name: string | null;
|
|
67
|
-
}> {
|
|
68
|
-
const conditions: string[] = [];
|
|
69
|
-
const params: unknown[] = [];
|
|
70
|
-
|
|
71
|
-
if (filter.session_id) {
|
|
72
|
-
conditions.push('session_id = ?');
|
|
73
|
-
params.push(filter.session_id);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
77
|
-
const limit = filter.limit ?? 100;
|
|
78
|
-
const sql = `SELECT * FROM token_usage ${where} ORDER BY timestamp DESC LIMIT ?`;
|
|
79
|
-
|
|
80
|
-
params.push(limit);
|
|
81
|
-
const rows = this.db.prepare(sql).all(...params) as Array<Record<string, unknown>>;
|
|
82
|
-
return rows.map(r => ({
|
|
83
|
-
id: r.id as number,
|
|
84
|
-
session_id: r.session_id as string,
|
|
85
|
-
timestamp: r.timestamp as number,
|
|
86
|
-
input_tokens: r.input_tokens as number,
|
|
87
|
-
output_tokens: r.output_tokens as number,
|
|
88
|
-
total_tokens: r.total_tokens as number,
|
|
89
|
-
model: (r.model as string) || null,
|
|
90
|
-
tool_name: (r.tool_name as string) || null,
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
}
|
package/src/core/types.ts
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core event types used by all Forge handlers.
|
|
3
|
-
*
|
|
4
|
-
* Two layers exposed:
|
|
5
|
-
*
|
|
6
|
-
* 1. **Wire shape** — `ForgeEvent`: a permissive interface that mirrors the
|
|
7
|
-
* raw Hook payload coming off the Unix socket. All optional fields are
|
|
8
|
-
* `?:` because the Hook envelope is the same regardless of `hook_type`.
|
|
9
|
-
* Storage / wire-level code (event-parser, sqlite rowToEvent, daemon
|
|
10
|
-
* router) keeps using this — it's still the source of truth on disk.
|
|
11
|
-
*
|
|
12
|
-
* 2. **Narrowed views** — `PreToolUseEvent` / `PostToolUseEvent` /
|
|
13
|
-
* `UserPromptSubmitEvent` / `NotificationEvent` / `StopEvent`: per-hook
|
|
14
|
-
* discriminated union with required fields filled in. Use these in
|
|
15
|
-
* handlers and downstream services where the hook type is already known.
|
|
16
|
-
*
|
|
17
|
-
* Convert with the type guards `isPreToolUse` / `isPostToolUse` / etc.
|
|
18
|
-
* They narrow correctly under TS control flow analysis.
|
|
19
|
-
*
|
|
20
|
-
* The split exists so we get compile-time guarantees inside handlers
|
|
21
|
-
* (no more `event.tool_name!`) without forcing every caller of the wire
|
|
22
|
-
* shape to do a 5-way switch.
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* Lenient bag of common tool_input fields across all Claude Code tools.
|
|
26
|
-
*
|
|
27
|
-
* Intentionally not a discriminated union — the tool set is open-ended and
|
|
28
|
-
* almost all access sites are defensive (`?.command ?? ''`). The index
|
|
29
|
-
* signature keeps forward compatibility with unknown tool kinds; prefer
|
|
30
|
-
* the typed getters in `core/event-fields.ts` over direct field access
|
|
31
|
-
* when the value is fed downstream as `string`.
|
|
32
|
-
*/
|
|
33
|
-
export interface ToolInputFields {
|
|
34
|
-
// Bash
|
|
35
|
-
command?: string;
|
|
36
|
-
description?: string;
|
|
37
|
-
// Edit / Write / Read / NotebookEdit
|
|
38
|
-
file_path?: string;
|
|
39
|
-
notebook_path?: string;
|
|
40
|
-
old_string?: string;
|
|
41
|
-
new_string?: string;
|
|
42
|
-
content?: string;
|
|
43
|
-
// Agent / Task
|
|
44
|
-
subagent_type?: string;
|
|
45
|
-
name?: string;
|
|
46
|
-
prompt?: string;
|
|
47
|
-
// UserPromptSubmit fallback envelope (some hook flows pack user_prompt here)
|
|
48
|
-
user_prompt?: string;
|
|
49
|
-
// Forward-compat for unknown tools / new Claude Code releases
|
|
50
|
-
[key: string]: unknown;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface ForgeEvent {
|
|
54
|
-
session_id: string;
|
|
55
|
-
project_path: string;
|
|
56
|
-
timestamp: string;
|
|
57
|
-
hook_type: 'PreToolUse' | 'PostToolUse' | 'UserPromptSubmit' | 'Notification' | 'Stop';
|
|
58
|
-
tool_name?: string;
|
|
59
|
-
tool_input?: ToolInputFields;
|
|
60
|
-
tool_output?: Record<string, unknown>;
|
|
61
|
-
user_prompt?: string;
|
|
62
|
-
ai_response?: string;
|
|
63
|
-
event_id?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface BaseEvent {
|
|
67
|
-
session_id: string;
|
|
68
|
-
project_path: string;
|
|
69
|
-
timestamp: string;
|
|
70
|
-
event_id?: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface PreToolUseEvent extends BaseEvent {
|
|
74
|
-
hook_type: 'PreToolUse';
|
|
75
|
-
tool_name: string;
|
|
76
|
-
tool_input: Record<string, unknown>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface PostToolUseEvent extends BaseEvent {
|
|
80
|
-
hook_type: 'PostToolUse';
|
|
81
|
-
tool_name: string;
|
|
82
|
-
tool_input: Record<string, unknown>;
|
|
83
|
-
tool_output: Record<string, unknown>;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface UserPromptSubmitEvent extends BaseEvent {
|
|
87
|
-
hook_type: 'UserPromptSubmit';
|
|
88
|
-
user_prompt: string;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface NotificationEvent extends BaseEvent {
|
|
92
|
-
hook_type: 'Notification';
|
|
93
|
-
ai_response?: string;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface StopEvent extends BaseEvent {
|
|
97
|
-
hook_type: 'Stop';
|
|
98
|
-
ai_response?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Narrow union for handlers / services that already know the hook type. */
|
|
102
|
-
export type ForgeEventNarrow =
|
|
103
|
-
| PreToolUseEvent
|
|
104
|
-
| PostToolUseEvent
|
|
105
|
-
| UserPromptSubmitEvent
|
|
106
|
-
| NotificationEvent
|
|
107
|
-
| StopEvent;
|
|
108
|
-
|
|
109
|
-
// ── Type Guards ──────────────────────────────────────────────────────────
|
|
110
|
-
// Use these in handlers/services to narrow ForgeEvent → specific event type.
|
|
111
|
-
// Under TS control-flow analysis they upgrade `event.tool_name` from
|
|
112
|
-
// `string | undefined` to `string` without runtime asserts.
|
|
113
|
-
|
|
114
|
-
export function isPreToolUse(e: ForgeEvent): e is PreToolUseEvent & ForgeEvent {
|
|
115
|
-
return e.hook_type === 'PreToolUse'
|
|
116
|
-
&& typeof e.tool_name === 'string'
|
|
117
|
-
&& e.tool_input !== undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function isPostToolUse(e: ForgeEvent): e is PostToolUseEvent & ForgeEvent {
|
|
121
|
-
return e.hook_type === 'PostToolUse'
|
|
122
|
-
&& typeof e.tool_name === 'string'
|
|
123
|
-
&& e.tool_input !== undefined
|
|
124
|
-
&& e.tool_output !== undefined;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export function isUserPromptSubmit(e: ForgeEvent): e is UserPromptSubmitEvent & ForgeEvent {
|
|
128
|
-
return e.hook_type === 'UserPromptSubmit' && typeof e.user_prompt === 'string';
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function isNotification(e: ForgeEvent): e is NotificationEvent & ForgeEvent {
|
|
132
|
-
return e.hook_type === 'Notification';
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function isStop(e: ForgeEvent): e is StopEvent & ForgeEvent {
|
|
136
|
-
return e.hook_type === 'Stop';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Hook execution result
|
|
141
|
-
*/
|
|
142
|
-
export interface HookResult {
|
|
143
|
-
allow: boolean;
|
|
144
|
-
reason?: string;
|
|
145
|
-
systemMessage?: string;
|
|
146
|
-
additionalContext?: string;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Security configuration
|
|
151
|
-
*/
|
|
152
|
-
export interface SecurityConfig {
|
|
153
|
-
destructiveOps: boolean;
|
|
154
|
-
secretsCheck: boolean;
|
|
155
|
-
diffSizeCheck: boolean;
|
|
156
|
-
diffSizeThreshold: number;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Configuration structure
|
|
161
|
-
*/
|
|
162
|
-
export interface ForgeConfig {
|
|
163
|
-
ai: {
|
|
164
|
-
api_key: string;
|
|
165
|
-
model: string;
|
|
166
|
-
base_url?: string;
|
|
167
|
-
provider: string;
|
|
168
|
-
};
|
|
169
|
-
storage: {
|
|
170
|
-
path: string;
|
|
171
|
-
max_size_mb: number;
|
|
172
|
-
};
|
|
173
|
-
web: {
|
|
174
|
-
enabled: boolean;
|
|
175
|
-
port: number;
|
|
176
|
-
};
|
|
177
|
-
skill_matching?: {
|
|
178
|
-
api_key?: string;
|
|
179
|
-
};
|
|
180
|
-
security?: SecurityConfig;
|
|
181
|
-
}
|