@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
package/src/mcp/server.ts
DELETED
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Server for claude-forge
|
|
3
|
-
*
|
|
4
|
-
* 嵌入在 daemon 进程内,通过 HTTP(Streamable HTTP transport)向 Claude Code
|
|
5
|
-
* 暴露以下工具:
|
|
6
|
-
* - skill_invoke:Agent 按需获取某个 Skill 的方法论内容
|
|
7
|
-
* - skill_list:列出所有可用 Skill(id / name / description / keywords)
|
|
8
|
-
*
|
|
9
|
-
* 调用链路:
|
|
10
|
-
* Claude Code → HTTP POST /mcp → MCP server → skillInvoke()/skillList()
|
|
11
|
-
* → writeSkillInvocation() 记录
|
|
12
|
-
*
|
|
13
|
-
* 设计要点:
|
|
14
|
-
* - 复用现有 Express app(不新增端口),路径前缀固定为 /mcp
|
|
15
|
-
* - 沿用 daemon auth token(Bearer),与 /api 写操作同一鉴权链路
|
|
16
|
-
* - Stateless 模式:每个请求开一对 server/transport,避免长连接污染
|
|
17
|
-
* daemon 主循环;Skill 调用本身是短平快、无需流式推送的场景
|
|
18
|
-
* - Session 追踪:优先 header `X-Forge-Session-Id`,缺失时生成匿名 session
|
|
19
|
-
* (Ruflo 模式下 Claude 自主决策,不需要 routing state 回退)
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import type { Application, Request, Response } from 'express';
|
|
23
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
24
|
-
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
25
|
-
import { z } from 'zod';
|
|
26
|
-
|
|
27
|
-
import type { SkillRegistry } from '../skills/registry.js';
|
|
28
|
-
import type { SQLiteStorage } from '../core/storage/sqlite.js';
|
|
29
|
-
import type { InvocationGuard } from '../skills/invocation-guard.js';
|
|
30
|
-
import { skillInvoke } from '../skills/tools/skill-invoke.js';
|
|
31
|
-
import { skillList } from '../skills/tools/skill-list.js';
|
|
32
|
-
import { pipelineSuggest } from '../skills/tools/pipeline-suggest.js';
|
|
33
|
-
import { logger } from '../core/utils/logger.js';
|
|
34
|
-
import { requireAuth } from '../web/auth-middleware.js';
|
|
35
|
-
|
|
36
|
-
/** Resolved session context for a single MCP tool call. */
|
|
37
|
-
export interface SessionContext {
|
|
38
|
-
sessionId: string | null;
|
|
39
|
-
routeRequestId: string | null;
|
|
40
|
-
agentId: string | null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface McpServerOptions {
|
|
44
|
-
skillRegistry: SkillRegistry;
|
|
45
|
-
storage: SQLiteStorage;
|
|
46
|
-
guard?: InvocationGuard;
|
|
47
|
-
/**
|
|
48
|
-
* Override the session-resolution strategy. Default behavior:
|
|
49
|
-
* 1. Read header `X-Forge-Session-Id` (passed by the harness if available)
|
|
50
|
-
* 2. Fallback: pick the freshest live routing entry from routingState
|
|
51
|
-
* 3. If neither yields a sessionId → return all-null context (invocation
|
|
52
|
-
* will be recorded with session_id derived from the synthetic
|
|
53
|
-
* "mcp-anon-<ts>" so the writeSkillInvocation NOT NULL constraint still
|
|
54
|
-
* passes; see resolveSessionContext below).
|
|
55
|
-
*/
|
|
56
|
-
resolveSession?: (req: Request) => SessionContext;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const SERVER_INFO = {
|
|
60
|
-
name: 'claude-forge',
|
|
61
|
-
version: '1.0.0',
|
|
62
|
-
} as const;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Resolve session context for a request.
|
|
66
|
-
*
|
|
67
|
-
* Priority order:
|
|
68
|
-
* 1. Explicit header `X-Forge-Session-Id` (+ optional `X-Forge-Route-Request-Id`,
|
|
69
|
-
* `X-Forge-Agent-Id`).
|
|
70
|
-
* 2. routingState.getMostRecent() — heuristic fallback during the routing
|
|
71
|
-
* window (≤30min TTL).
|
|
72
|
-
* 3. Synthetic anonymous session "mcp-anon-<unix-ts>" so we never blow the
|
|
73
|
-
* NOT NULL session_id constraint when persisting invocations.
|
|
74
|
-
*/
|
|
75
|
-
function resolveSessionContext(req: Request): SessionContext {
|
|
76
|
-
const headerSession = req.header('X-Forge-Session-Id');
|
|
77
|
-
if (headerSession && headerSession.trim().length > 0) {
|
|
78
|
-
const headerRoute = req.header('X-Forge-Route-Request-Id');
|
|
79
|
-
const headerAgent = req.header('X-Forge-Agent-Id');
|
|
80
|
-
return {
|
|
81
|
-
sessionId: headerSession.trim(),
|
|
82
|
-
routeRequestId: headerRoute?.trim() || null,
|
|
83
|
-
agentId: headerAgent?.trim() || null,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// In Ruflo mode, Claude makes autonomous decisions via CLAUDE.md.
|
|
88
|
-
// MCP tools no longer need routing state fallback.
|
|
89
|
-
return {
|
|
90
|
-
sessionId: `mcp-anon-${Date.now()}`,
|
|
91
|
-
routeRequestId: null,
|
|
92
|
-
agentId: null,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Build a fresh MCP server instance bound to the given options & context. */
|
|
97
|
-
function buildServer(
|
|
98
|
-
options: McpServerOptions,
|
|
99
|
-
sessionCtx: SessionContext,
|
|
100
|
-
): McpServer {
|
|
101
|
-
const server = new McpServer(SERVER_INFO, {
|
|
102
|
-
capabilities: { tools: { listChanged: false } },
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// ── Tool 1: skill_invoke ───────────────────────────────────────────────
|
|
106
|
-
server.registerTool(
|
|
107
|
-
'skill_invoke',
|
|
108
|
-
{
|
|
109
|
-
title: 'Invoke a claude-forge skill',
|
|
110
|
-
description:
|
|
111
|
-
'调用指定的 Skill,获取该方法论的完整内容。使用场景:当你需要特定领域的方法论指导(如 TDD、重构、性能优化)时。',
|
|
112
|
-
inputSchema: {
|
|
113
|
-
skill_id: z
|
|
114
|
-
.string()
|
|
115
|
-
.min(1)
|
|
116
|
-
.describe('Skill 的 ID(如 "official-tdd")。可通过 skill_list 工具查询。'),
|
|
117
|
-
reason: z
|
|
118
|
-
.string()
|
|
119
|
-
.optional()
|
|
120
|
-
.describe('调用理由(可选,用于审计 / skill_invocations.reason 列)'),
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
async (args) => {
|
|
124
|
-
try {
|
|
125
|
-
const sessionId = sessionCtx.sessionId ?? `mcp-anon-${Date.now()}`;
|
|
126
|
-
const result = await skillInvoke(
|
|
127
|
-
{ skill_id: args.skill_id, reason: args.reason },
|
|
128
|
-
{
|
|
129
|
-
skillRegistry: options.skillRegistry,
|
|
130
|
-
guard: options.guard,
|
|
131
|
-
storage: options.storage,
|
|
132
|
-
sessionId,
|
|
133
|
-
routeRequestId: sessionCtx.routeRequestId ?? undefined,
|
|
134
|
-
agentId: sessionCtx.agentId ?? undefined,
|
|
135
|
-
invocationType: 'dynamic',
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
return {
|
|
139
|
-
content: [
|
|
140
|
-
{
|
|
141
|
-
type: 'text' as const,
|
|
142
|
-
text: `# ${result.skill_name}\n\n${result.content}`,
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
|
-
};
|
|
146
|
-
} catch (err) {
|
|
147
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
148
|
-
logger.warn(`[MCP] skill_invoke failed: ${message}`);
|
|
149
|
-
return {
|
|
150
|
-
isError: true,
|
|
151
|
-
content: [{ type: 'text' as const, text: message }],
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
// ── Tool 2: skill_list ─────────────────────────────────────────────────
|
|
158
|
-
server.registerTool(
|
|
159
|
-
'skill_list',
|
|
160
|
-
{
|
|
161
|
-
title: 'List available claude-forge skills',
|
|
162
|
-
description: '列出所有可用的 Skill。可以通过 keywords 过滤(OR 语义)。',
|
|
163
|
-
inputSchema: {
|
|
164
|
-
keywords: z
|
|
165
|
-
.array(z.string())
|
|
166
|
-
.optional()
|
|
167
|
-
.describe('可选的关键词过滤(如 ["test", "tdd"])'),
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
async (args) => {
|
|
171
|
-
try {
|
|
172
|
-
logger.info(`[MCP] skill_list called with args: ${JSON.stringify(args)}`);
|
|
173
|
-
const result = await skillList(
|
|
174
|
-
{ keywords: args.keywords },
|
|
175
|
-
{ skillRegistry: options.skillRegistry },
|
|
176
|
-
);
|
|
177
|
-
return {
|
|
178
|
-
content: [
|
|
179
|
-
{ type: 'text' as const, text: JSON.stringify(result, null, 2) },
|
|
180
|
-
],
|
|
181
|
-
};
|
|
182
|
-
} catch (err) {
|
|
183
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
184
|
-
logger.warn(`[MCP] skill_list failed: ${message}`);
|
|
185
|
-
return {
|
|
186
|
-
isError: true,
|
|
187
|
-
content: [{ type: 'text' as const, text: message }],
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
// ── Tool 3: pipeline_suggest ───────────────────────────────────────────
|
|
194
|
-
server.registerTool(
|
|
195
|
-
'pipeline_suggest',
|
|
196
|
-
{
|
|
197
|
-
title: 'Suggest a swarm pipeline for a task',
|
|
198
|
-
description:
|
|
199
|
-
'根据任务特征判断是否需要启动多 Agent 协作的 Pipeline,并生成可直接使用的 Task({...}) 调用代码。',
|
|
200
|
-
inputSchema: {
|
|
201
|
-
task_description: z
|
|
202
|
-
.string()
|
|
203
|
-
.min(1)
|
|
204
|
-
.describe('任务描述(如 "修复用户登录时的 session 过期问题")'),
|
|
205
|
-
file_count: z
|
|
206
|
-
.number()
|
|
207
|
-
.int()
|
|
208
|
-
.optional()
|
|
209
|
-
.describe('预估涉及的文件数量(>=2 时建议使用 Pipeline)'),
|
|
210
|
-
is_new_feature: z
|
|
211
|
-
.boolean()
|
|
212
|
-
.optional()
|
|
213
|
-
.describe('是否为新功能开发'),
|
|
214
|
-
is_refactor: z
|
|
215
|
-
.boolean()
|
|
216
|
-
.optional()
|
|
217
|
-
.describe('是否为重构任务'),
|
|
218
|
-
is_bug_fix: z
|
|
219
|
-
.boolean()
|
|
220
|
-
.optional()
|
|
221
|
-
.describe('是否为 Bug 修复'),
|
|
222
|
-
is_performance: z
|
|
223
|
-
.boolean()
|
|
224
|
-
.optional()
|
|
225
|
-
.describe('是否为性能优化'),
|
|
226
|
-
is_migration: z
|
|
227
|
-
.boolean()
|
|
228
|
-
.optional()
|
|
229
|
-
.describe('是否为技术迁移/升级'),
|
|
230
|
-
is_security: z
|
|
231
|
-
.boolean()
|
|
232
|
-
.optional()
|
|
233
|
-
.describe('是否为安全审计/漏洞修复'),
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
async (args) => {
|
|
237
|
-
try {
|
|
238
|
-
const result = await pipelineSuggest({
|
|
239
|
-
task_description: args.task_description,
|
|
240
|
-
file_count: args.file_count,
|
|
241
|
-
is_new_feature: args.is_new_feature,
|
|
242
|
-
is_refactor: args.is_refactor,
|
|
243
|
-
is_bug_fix: args.is_bug_fix,
|
|
244
|
-
is_performance: args.is_performance,
|
|
245
|
-
is_migration: args.is_migration,
|
|
246
|
-
is_security: args.is_security,
|
|
247
|
-
});
|
|
248
|
-
return {
|
|
249
|
-
content: [
|
|
250
|
-
{ type: 'text' as const, text: JSON.stringify(result, null, 2) },
|
|
251
|
-
],
|
|
252
|
-
};
|
|
253
|
-
} catch (err) {
|
|
254
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
255
|
-
logger.warn(`[MCP] pipeline_suggest failed: ${message}`);
|
|
256
|
-
return {
|
|
257
|
-
isError: true,
|
|
258
|
-
content: [{ type: 'text' as const, text: message }],
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
return server;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Mount the MCP server endpoints on an existing Express application.
|
|
269
|
-
*
|
|
270
|
-
* Routes:
|
|
271
|
-
* POST /mcp — JSON-RPC over Streamable HTTP (initialize, tools/list, tools/call)
|
|
272
|
-
* GET /mcp — Standalone SSE channel (server→client notifications)
|
|
273
|
-
* DELETE /mcp — Session termination (stateful mode only; no-op in stateless)
|
|
274
|
-
*
|
|
275
|
-
* Authentication: every method requires the daemon Bearer token. Token-file
|
|
276
|
-
* absence still falls through (early-startup safety, identical to /api).
|
|
277
|
-
*/
|
|
278
|
-
export function mountMcpServer(app: Application, options: McpServerOptions): void {
|
|
279
|
-
const resolveSession = options.resolveSession ?? resolveSessionContext;
|
|
280
|
-
|
|
281
|
-
const handler = async (req: Request, res: Response): Promise<void> => {
|
|
282
|
-
// Stateless: build a fresh server+transport per request. The transport
|
|
283
|
-
// mutates res so it cannot be reused across requests anyway.
|
|
284
|
-
const sessionCtx = resolveSession(req);
|
|
285
|
-
const server = buildServer(options, sessionCtx);
|
|
286
|
-
const transport = new StreamableHTTPServerTransport({
|
|
287
|
-
// Stateless mode — no session ID generator.
|
|
288
|
-
sessionIdGenerator: undefined,
|
|
289
|
-
enableJsonResponse: true,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
res.on('close', () => {
|
|
293
|
-
// best-effort cleanup; ignore errors because transport may already be closed
|
|
294
|
-
void transport.close().catch(() => undefined);
|
|
295
|
-
void server.close().catch(() => undefined);
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
try {
|
|
299
|
-
await server.connect(transport);
|
|
300
|
-
// express.json() has already populated req.body; pass it through.
|
|
301
|
-
await transport.handleRequest(req, res, req.body);
|
|
302
|
-
} catch (err) {
|
|
303
|
-
logger.warn(`[MCP] request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
304
|
-
if (!res.headersSent) {
|
|
305
|
-
res.status(500).json({
|
|
306
|
-
jsonrpc: '2.0',
|
|
307
|
-
error: { code: -32603, message: 'Internal error' },
|
|
308
|
-
id: null,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
// All MCP requests are auth-gated. We deliberately gate GET too because MCP
|
|
315
|
-
// tool-calls (sensitive ops) can come over GET via SSE; /api keeps GET open
|
|
316
|
-
// only for read-only dashboard polling.
|
|
317
|
-
app.post('/mcp', requireAuth, handler);
|
|
318
|
-
app.get('/mcp', requireAuth, handler);
|
|
319
|
-
app.delete('/mcp', requireAuth, handler);
|
|
320
|
-
|
|
321
|
-
logger.info('[MCP] Server mounted on /mcp (Streamable HTTP, stateless)');
|
|
322
|
-
}
|
package/src/skills/index.ts
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InvocationGuard — Skill 调用防护机制
|
|
3
|
-
*
|
|
4
|
-
* 防止 Agent 陷入无限调用 Skill 的循环,限制:
|
|
5
|
-
* - 单会话总调用次数(默认 10)
|
|
6
|
-
* - 单会话调用深度(默认 3)
|
|
7
|
-
* - 同 session 同 skill 幂等(避免重复调用)
|
|
8
|
-
* - TTL 机制:会话状态 30 分钟后自动过期
|
|
9
|
-
*
|
|
10
|
-
* 状态为进程内存,进程重启会清空;调用链路通常集中在单个会话内,
|
|
11
|
-
* 重启后重建状态是可接受的。
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const MAX_INVOCATIONS_PER_SESSION = 10;
|
|
15
|
-
const MAX_INVOCATION_DEPTH = 3;
|
|
16
|
-
const SESSION_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
17
|
-
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
18
|
-
|
|
19
|
-
export interface SessionInvocations {
|
|
20
|
-
total: number;
|
|
21
|
-
depth: number;
|
|
22
|
-
calledSkills: Set<string>;
|
|
23
|
-
lastAccessTime: number; // Timestamp of last access
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface InvocationCheckResult {
|
|
27
|
-
allowed: boolean;
|
|
28
|
-
reason?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class InvocationGuard {
|
|
32
|
-
private sessions = new Map<string, SessionInvocations>();
|
|
33
|
-
private cleanupTimer: NodeJS.Timeout | null = null;
|
|
34
|
-
|
|
35
|
-
constructor() {
|
|
36
|
-
// Start automatic cleanup timer
|
|
37
|
-
this.startCleanupTimer();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 检查是否允许调用。
|
|
42
|
-
* 不修改状态;调用方决定是否继续后调用 record()。
|
|
43
|
-
*/
|
|
44
|
-
check(sessionId: string, skillId: string): InvocationCheckResult {
|
|
45
|
-
const session = this.sessions.get(sessionId) ?? {
|
|
46
|
-
total: 0,
|
|
47
|
-
depth: 0,
|
|
48
|
-
calledSkills: new Set<string>(),
|
|
49
|
-
lastAccessTime: Date.now(),
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Check if session has expired
|
|
53
|
-
if (Date.now() - session.lastAccessTime > SESSION_TTL_MS) {
|
|
54
|
-
this.sessions.delete(sessionId);
|
|
55
|
-
return { allowed: true }; // Expired session, allow new invocation
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (session.total >= MAX_INVOCATIONS_PER_SESSION) {
|
|
59
|
-
return {
|
|
60
|
-
allowed: false,
|
|
61
|
-
reason: `Reached max invocations per session (${MAX_INVOCATIONS_PER_SESSION})`,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (session.depth >= MAX_INVOCATION_DEPTH) {
|
|
66
|
-
return {
|
|
67
|
-
allowed: false,
|
|
68
|
-
reason: `Reached max invocation depth (${MAX_INVOCATION_DEPTH})`,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (session.calledSkills.has(skillId)) {
|
|
73
|
-
return {
|
|
74
|
-
allowed: false,
|
|
75
|
-
reason: `Skill '${skillId}' already invoked in this session (idempotent guard)`,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return { allowed: true };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 记录一次调用开始(递增 total 和 depth,登记 skill)。
|
|
84
|
-
*/
|
|
85
|
-
record(sessionId: string, skillId: string): void {
|
|
86
|
-
const session = this.sessions.get(sessionId) ?? {
|
|
87
|
-
total: 0,
|
|
88
|
-
depth: 0,
|
|
89
|
-
calledSkills: new Set<string>(),
|
|
90
|
-
lastAccessTime: Date.now(),
|
|
91
|
-
};
|
|
92
|
-
session.total += 1;
|
|
93
|
-
session.depth += 1;
|
|
94
|
-
session.calledSkills.add(skillId);
|
|
95
|
-
session.lastAccessTime = Date.now(); // Update access time
|
|
96
|
-
this.sessions.set(sessionId, session);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 调用完成,递减 depth(不清除已调用 skills)。
|
|
101
|
-
*/
|
|
102
|
-
complete(sessionId: string): void {
|
|
103
|
-
const session = this.sessions.get(sessionId);
|
|
104
|
-
if (session) {
|
|
105
|
-
session.depth = Math.max(0, session.depth - 1);
|
|
106
|
-
session.lastAccessTime = Date.now(); // Update access time
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* 清理会话(Stop hook 或会话结束时调用)。
|
|
112
|
-
*/
|
|
113
|
-
clear(sessionId: string): void {
|
|
114
|
-
this.sessions.delete(sessionId);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* 获取会话统计(调试/观测用)。
|
|
119
|
-
*/
|
|
120
|
-
getStats(sessionId: string): SessionInvocations | null {
|
|
121
|
-
return this.sessions.get(sessionId) ?? null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* 清理过期会话(TTL 机制)。
|
|
126
|
-
*/
|
|
127
|
-
private cleanupExpiredSessions(): void {
|
|
128
|
-
const now = Date.now();
|
|
129
|
-
const expiredSessions: string[] = [];
|
|
130
|
-
|
|
131
|
-
for (const [sessionId, session] of this.sessions.entries()) {
|
|
132
|
-
if (now - session.lastAccessTime > SESSION_TTL_MS) {
|
|
133
|
-
expiredSessions.push(sessionId);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
for (const sessionId of expiredSessions) {
|
|
138
|
-
this.sessions.delete(sessionId);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (expiredSessions.length > 0) {
|
|
142
|
-
// Use console.log instead of logger to avoid circular dependency
|
|
143
|
-
console.log(`[InvocationGuard] Cleaned up ${expiredSessions.length} expired sessions`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* 启动自动清理定时器。
|
|
149
|
-
*/
|
|
150
|
-
private startCleanupTimer(): void {
|
|
151
|
-
if (this.cleanupTimer) return;
|
|
152
|
-
|
|
153
|
-
this.cleanupTimer = setInterval(() => {
|
|
154
|
-
this.cleanupExpiredSessions();
|
|
155
|
-
}, CLEANUP_INTERVAL_MS);
|
|
156
|
-
|
|
157
|
-
// Prevent timer from keeping process alive
|
|
158
|
-
this.cleanupTimer.unref();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* 停止自动清理定时器(用于测试或进程关闭)。
|
|
163
|
-
*/
|
|
164
|
-
stopCleanupTimer(): void {
|
|
165
|
-
if (this.cleanupTimer) {
|
|
166
|
-
clearInterval(this.cleanupTimer);
|
|
167
|
-
this.cleanupTimer = null;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 获取当前会话数量(用于监控)。
|
|
173
|
-
*/
|
|
174
|
-
getSessionCount(): number {
|
|
175
|
-
return this.sessions.size;
|
|
176
|
-
}
|
|
177
|
-
}
|
package/src/skills/matcher.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import type { Skill } from './registry.js';
|
|
2
|
-
|
|
3
|
-
export interface MatchContext {
|
|
4
|
-
prompt: string;
|
|
5
|
-
intentKeywords?: string[];
|
|
6
|
-
projectPath?: string;
|
|
7
|
-
recentFiles?: string[];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface MatchResult {
|
|
11
|
-
skill: Skill;
|
|
12
|
-
confidence: number; // 0-100
|
|
13
|
-
matchedKeywords: string[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Enhanced keyword matching with word boundary detection
|
|
18
|
-
* Reduces false positives by requiring whole-word matches
|
|
19
|
-
*/
|
|
20
|
-
function matchKeywordStrict(text: string, keyword: string): boolean {
|
|
21
|
-
const textLower = text.toLowerCase();
|
|
22
|
-
const kwLower = keyword.toLowerCase();
|
|
23
|
-
|
|
24
|
-
// For Chinese/multi-word keywords, use simple includes
|
|
25
|
-
if (kwLower.includes(' ') || /[一-龥]/.test(kwLower)) {
|
|
26
|
-
return textLower.includes(kwLower);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// For single English word keywords, require word boundaries
|
|
30
|
-
const regex = new RegExp(`\\b${kwLower.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
31
|
-
return regex.test(textLower);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Calculate match confidence score (0-100)
|
|
36
|
-
*/
|
|
37
|
-
export function calculateMatchScore(skill: Skill, context: MatchContext): MatchResult | null {
|
|
38
|
-
const { prompt, intentKeywords = [] } = context;
|
|
39
|
-
const allText = [prompt, ...intentKeywords].join(' ');
|
|
40
|
-
|
|
41
|
-
let matchedKeywords: string[] = [];
|
|
42
|
-
let score = 0;
|
|
43
|
-
|
|
44
|
-
// 1. Keyword matching with flexible scoring
|
|
45
|
-
for (const kw of skill.keywords) {
|
|
46
|
-
if (matchKeywordStrict(allText, kw)) {
|
|
47
|
-
matchedKeywords.push(kw);
|
|
48
|
-
// Base score: 15 points per keyword
|
|
49
|
-
// Bonus for longer keywords (more specific)
|
|
50
|
-
const lengthBonus = Math.min(10, Math.floor(kw.length / 3));
|
|
51
|
-
score += 15 + lengthBonus;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. Negative keywords check (disqualify if present)
|
|
56
|
-
const negativeKeywords = getNegativeKeywords(skill.id);
|
|
57
|
-
for (const negKw of negativeKeywords) {
|
|
58
|
-
if (matchKeywordStrict(allText, negKw)) {
|
|
59
|
-
return null; // Disqualify
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 3. Context bonus (max 30 points)
|
|
64
|
-
const contextBonus = calculateContextBonus(skill, context);
|
|
65
|
-
score += contextBonus;
|
|
66
|
-
|
|
67
|
-
// 4. Fuzzy matching: partial keyword match for longer prompts
|
|
68
|
-
if (matchedKeywords.length === 0 && prompt.length > 50) {
|
|
69
|
-
for (const kw of skill.keywords) {
|
|
70
|
-
if (kw.length >= 3 && allText.toLowerCase().includes(kw.toLowerCase().slice(0, 3))) {
|
|
71
|
-
score = Math.max(score, 25);
|
|
72
|
-
matchedKeywords.push(`~${kw}`);
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Normalize to 0-100
|
|
79
|
-
const confidence = Math.min(100, score);
|
|
80
|
-
|
|
81
|
-
// Threshold: >= 20% confidence is enough to surface a match
|
|
82
|
-
if (confidence < 20) {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
skill,
|
|
88
|
-
confidence,
|
|
89
|
-
matchedKeywords,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Get negative keywords that disqualify a skill
|
|
95
|
-
*/
|
|
96
|
-
function getNegativeKeywords(skillId: string): string[] {
|
|
97
|
-
const negativeMap: Record<string, string[]> = {
|
|
98
|
-
'official-tdd': ['existing', 'legacy', 'refactor', '重构', '遗留'],
|
|
99
|
-
'official-harness-engineering': ['new feature', '新功能', 'from scratch'],
|
|
100
|
-
'official-debug': ['working', 'works fine', '正常'],
|
|
101
|
-
'official-performance-optimization': ['slow network', 'api timeout', '网络慢'],
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
return negativeMap[skillId] || [];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Calculate context-based bonus score
|
|
109
|
-
*/
|
|
110
|
-
function calculateContextBonus(skill: Skill, context: MatchContext): number {
|
|
111
|
-
let bonus = 0;
|
|
112
|
-
|
|
113
|
-
// File extension matching
|
|
114
|
-
if (context.recentFiles && context.recentFiles.length > 0) {
|
|
115
|
-
const fileExts = context.recentFiles.map(f => f.split('.').pop()?.toLowerCase());
|
|
116
|
-
|
|
117
|
-
if (skill.id === 'official-tdd' && fileExts.some(ext => ext === 'test' || ext === 'spec')) {
|
|
118
|
-
bonus += 20;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (skill.id === 'webapp-testing' && fileExts.some(ext => ['tsx', 'jsx', 'html'].includes(ext || ''))) {
|
|
122
|
-
bonus += 20;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (skill.id === 'official-db-schema-design' && fileExts.some(ext => ext === 'sql')) {
|
|
126
|
-
bonus += 20;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return bonus;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if any of the skill's keywords appear in the prompt (case-insensitive).
|
|
135
|
-
* @deprecated Use calculateMatchScore instead
|
|
136
|
-
*/
|
|
137
|
-
export function matchKeywords(prompt: string, skillKeywords: string[]): boolean {
|
|
138
|
-
const promptLower = prompt.toLowerCase();
|
|
139
|
-
return skillKeywords.some(kw => promptLower.includes(kw.toLowerCase()));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Format a skill as a recommendation message for the user.
|
|
144
|
-
*/
|
|
145
|
-
export function formatSkillRecommendation(skill: Skill, confidence?: number): string {
|
|
146
|
-
const confidenceStr = confidence ? ` (${confidence}% 匹配)` : '';
|
|
147
|
-
return `[Forge 技能推荐]${confidenceStr} ${skill.name}\n\n${skill.content}`;
|
|
148
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: code-simplifier
|
|
3
|
-
description: Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality. Focuses on recently modified code unless instructed otherwise.
|
|
4
|
-
model: opus
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. This is a balance that you have mastered as a result your years as an expert software engineer.
|
|
8
|
-
|
|
9
|
-
You will analyze recently modified code and apply refinements that:
|
|
10
|
-
|
|
11
|
-
1. **Preserve Functionality**: Never change what the code does - only how it does it. All original features, outputs, and behaviors must remain intact.
|
|
12
|
-
|
|
13
|
-
2. **Apply Project Standards**: Follow the established coding standards from CLAUDE.md including:
|
|
14
|
-
|
|
15
|
-
- Use ES modules with proper import sorting and extensions
|
|
16
|
-
- Prefer `function` keyword over arrow functions
|
|
17
|
-
- Use explicit return type annotations for top-level functions
|
|
18
|
-
- Follow proper React component patterns with explicit Props types
|
|
19
|
-
- Use proper error handling patterns (avoid try/catch when possible)
|
|
20
|
-
- Maintain consistent naming conventions
|
|
21
|
-
|
|
22
|
-
3. **Enhance Clarity**: Simplify code structure by:
|
|
23
|
-
|
|
24
|
-
- Reducing unnecessary complexity and nesting
|
|
25
|
-
- Eliminating redundant code and abstractions
|
|
26
|
-
- Improving readability through clear variable and function names
|
|
27
|
-
- Consolidating related logic
|
|
28
|
-
- Removing unnecessary comments that describe obvious code
|
|
29
|
-
- IMPORTANT: Avoid nested ternary operators - prefer switch statements or if/else chains for multiple conditions
|
|
30
|
-
- Choose clarity over brevity - explicit code is often better than overly compact code
|
|
31
|
-
|
|
32
|
-
4. **Maintain Balance**: Avoid over-simplification that could:
|
|
33
|
-
|
|
34
|
-
- Reduce code clarity or maintainability
|
|
35
|
-
- Create overly clever solutions that are hard to understand
|
|
36
|
-
- Combine too many concerns into single functions or components
|
|
37
|
-
- Remove helpful abstractions that improve code organization
|
|
38
|
-
- Prioritize "fewer lines" over readability (e.g., nested ternaries, dense one-liners)
|
|
39
|
-
- Make the code harder to debug or extend
|
|
40
|
-
|
|
41
|
-
5. **Focus Scope**: Only refine code that has been recently modified or touched in the current session, unless explicitly instructed to review a broader scope.
|
|
42
|
-
|
|
43
|
-
Your refinement process:
|
|
44
|
-
|
|
45
|
-
1. Identify the recently modified code sections
|
|
46
|
-
2. Analyze for opportunities to improve elegance and consistency
|
|
47
|
-
3. Apply project-specific best practices and coding standards
|
|
48
|
-
4. Ensure all functionality remains unchanged
|
|
49
|
-
5. Verify the refined code is simpler and more maintainable
|
|
50
|
-
6. Document only significant changes that affect understanding
|
|
51
|
-
|
|
52
|
-
You operate autonomously and proactively, refining code immediately after it's written or modified without requiring explicit requests. Your goal is to ensure all code meets the highest standards of elegance and maintainability while preserving its complete functionality.
|