memory-journal-mcp 6.1.2 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -28
- package/dist/{chunk-X4SWFATC.js → chunk-BI4ZNSKA.js} +38 -24
- package/dist/{chunk-HCEWINSB.js → chunk-N6EBIDN7.js} +99 -102
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/tools-WPRY5MJ6.js +2 -0
- package/package.json +10 -1
- package/skills/github-commander/SKILL.md +151 -0
- package/skills/github-commander/config/project-config.example.md +125 -0
- package/skills/github-commander/workflows/code-quality-audit.md +80 -0
- package/skills/github-commander/workflows/full-audit.md +134 -0
- package/skills/github-commander/workflows/issue-triage.md +239 -0
- package/skills/github-commander/workflows/milestone-sprint.md +81 -0
- package/skills/github-commander/workflows/perf-audit.md +142 -0
- package/skills/github-commander/workflows/pr-review.md +123 -0
- package/skills/github-commander/workflows/security-audit.md +170 -0
- package/skills/github-commander/workflows/update-deps.md +109 -0
- package/.dockerignore +0 -139
- package/.gitattributes +0 -20
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -95
- package/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -110
- package/.github/ISSUE_TEMPLATE/question.md +0 -78
- package/.github/aw/actions-lock.json +0 -14
- package/.github/copilot-instructions.md +0 -122
- package/.github/dependabot.yml +0 -93
- package/.github/pull_request_template.md +0 -135
- package/.github/workflows/README.md +0 -133
- package/.github/workflows/agentics-maintenance.yml +0 -141
- package/.github/workflows/auto-release.yml +0 -68
- package/.github/workflows/ci-health-monitor.lock.yml +0 -1121
- package/.github/workflows/ci-health-monitor.md +0 -87
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-auto-merge.yml +0 -42
- package/.github/workflows/dependency-maintenance.lock.yml +0 -1182
- package/.github/workflows/dependency-maintenance.md +0 -147
- package/.github/workflows/docker-publish.yml +0 -254
- package/.github/workflows/docs-drift-detector.lock.yml +0 -1142
- package/.github/workflows/docs-drift-detector.md +0 -115
- package/.github/workflows/lint-and-test.yml +0 -60
- package/.github/workflows/publish-npm.yml +0 -85
- package/.github/workflows/secrets-scanning.yml +0 -32
- package/.github/workflows/security-update.yml +0 -127
- package/.gitleaks.toml +0 -9
- package/.prettierignore +0 -21
- package/.prettierrc +0 -33
- package/.scout-ignore +0 -12
- package/.trivyignore +0 -21
- package/CHANGELOG.md +0 -1814
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -263
- package/DOCKER_README.md +0 -331
- package/Dockerfile +0 -128
- package/SECURITY.md +0 -227
- package/UNRELEASED.md +0 -1
- package/dist/tools-T4U5A3X4.js +0 -2
- package/docker-compose.yml +0 -71
- package/docs/README.md +0 -18
- package/docs/agentic-journal-synergy.md +0 -175
- package/docs/copilot-setup.md +0 -72
- package/eslint.config.js +0 -110
- package/mcp-config-example.json +0 -21
- package/playwright.config.ts +0 -35
- package/releases/v2.1.0.md +0 -220
- package/releases/v2.2.0.md +0 -168
- package/releases/v3.0.0.md +0 -237
- package/releases/v3.1.0.md +0 -104
- package/releases/v3.1.1.md +0 -42
- package/releases/v3.1.2.md +0 -40
- package/releases/v3.1.3.md +0 -64
- package/releases/v3.1.4.md +0 -32
- package/releases/v3.1.5.md +0 -44
- package/releases/v4.0.0.md +0 -71
- package/releases/v4.1.0.md +0 -88
- package/releases/v4.2.0.md +0 -90
- package/releases/v4.3.0.md +0 -92
- package/releases/v4.3.1.md +0 -69
- package/releases/v4.4.0.md +0 -120
- package/releases/v4.4.1.md +0 -33
- package/releases/v4.4.2.md +0 -31
- package/releases/v4.5.0.md +0 -116
- package/releases/v5.0.0.md +0 -105
- package/releases/v5.0.1.md +0 -25
- package/releases/v5.1.0.md +0 -83
- package/releases/v5.1.1.md +0 -10
- package/releases/v6.0.0.md +0 -48
- package/releases/v6.0.1.md +0 -36
- package/releases/v6.1.0.md +0 -68
- package/releases/v6.1.1.md +0 -30
- package/releases/v6.1.2.md +0 -23
- package/scripts/generate-server-instructions.ts +0 -306
- package/scripts/server-instructions-function-body.ts +0 -107
- package/scripts/server-instructions-gotchas.ts +0 -45
- package/server.json +0 -42
- package/social-preview.png +0 -0
- package/src/auth/auth-context.ts +0 -78
- package/src/auth/authorization-server-discovery.ts +0 -263
- package/src/auth/errors.ts +0 -215
- package/src/auth/index.ts +0 -58
- package/src/auth/middleware.ts +0 -392
- package/src/auth/oauth-resource-server.ts +0 -170
- package/src/auth/scope-map.ts +0 -46
- package/src/auth/scopes.ts +0 -256
- package/src/auth/token-validator.ts +0 -293
- package/src/auth/transport-agnostic.ts +0 -164
- package/src/auth/types.ts +0 -372
- package/src/cli.ts +0 -279
- package/src/codemode/api-constants.ts +0 -263
- package/src/codemode/api.ts +0 -302
- package/src/codemode/auto-return.ts +0 -65
- package/src/codemode/index.ts +0 -47
- package/src/codemode/sandbox-factory.ts +0 -144
- package/src/codemode/sandbox.ts +0 -220
- package/src/codemode/security.ts +0 -155
- package/src/codemode/types.ts +0 -228
- package/src/codemode/worker-sandbox.ts +0 -277
- package/src/codemode/worker-script.ts +0 -239
- package/src/constants/icons.ts +0 -183
- package/src/constants/server-instructions.md +0 -166
- package/src/constants/server-instructions.ts +0 -514
- package/src/database/adapter-factory.ts +0 -16
- package/src/database/core/entry-columns.ts +0 -10
- package/src/database/core/interfaces.ts +0 -188
- package/src/database/core/schema.ts +0 -152
- package/src/database/sqlite-adapter/backup.ts +0 -167
- package/src/database/sqlite-adapter/entries/crud.ts +0 -233
- package/src/database/sqlite-adapter/entries/importance.ts +0 -76
- package/src/database/sqlite-adapter/entries/index.ts +0 -142
- package/src/database/sqlite-adapter/entries/search.ts +0 -294
- package/src/database/sqlite-adapter/entries/shared.ts +0 -102
- package/src/database/sqlite-adapter/entries/statistics.ts +0 -162
- package/src/database/sqlite-adapter/index.ts +0 -265
- package/src/database/sqlite-adapter/native-connection.ts +0 -301
- package/src/database/sqlite-adapter/relationships.ts +0 -70
- package/src/database/sqlite-adapter/tags.ts +0 -182
- package/src/filtering/tool-filter.ts +0 -312
- package/src/github/github-integration/client.ts +0 -114
- package/src/github/github-integration/index.ts +0 -297
- package/src/github/github-integration/insights.ts +0 -155
- package/src/github/github-integration/issues.ts +0 -213
- package/src/github/github-integration/milestones.ts +0 -262
- package/src/github/github-integration/projects.ts +0 -414
- package/src/github/github-integration/pull-requests.ts +0 -235
- package/src/github/github-integration/repository.ts +0 -110
- package/src/github/github-integration/types.ts +0 -43
- package/src/handlers/prompts/github.ts +0 -210
- package/src/handlers/prompts/index.ts +0 -97
- package/src/handlers/prompts/workflow.ts +0 -361
- package/src/handlers/resources/core/briefing/context-section.ts +0 -182
- package/src/handlers/resources/core/briefing/github-section.ts +0 -354
- package/src/handlers/resources/core/briefing/index.ts +0 -106
- package/src/handlers/resources/core/briefing/user-message.ts +0 -114
- package/src/handlers/resources/core/health.ts +0 -75
- package/src/handlers/resources/core/index.ts +0 -31
- package/src/handlers/resources/core/instructions.ts +0 -45
- package/src/handlers/resources/core/utilities.ts +0 -310
- package/src/handlers/resources/github.ts +0 -340
- package/src/handlers/resources/graph.ts +0 -218
- package/src/handlers/resources/help.ts +0 -410
- package/src/handlers/resources/index.ts +0 -143
- package/src/handlers/resources/shared.ts +0 -219
- package/src/handlers/resources/team.ts +0 -134
- package/src/handlers/resources/templates.ts +0 -334
- package/src/handlers/tools/admin.ts +0 -351
- package/src/handlers/tools/analytics.ts +0 -346
- package/src/handlers/tools/backup.ts +0 -272
- package/src/handlers/tools/codemode.ts +0 -188
- package/src/handlers/tools/core.ts +0 -359
- package/src/handlers/tools/error-fields-mixin.ts +0 -10
- package/src/handlers/tools/export.ts +0 -150
- package/src/handlers/tools/github/copilot-tools.ts +0 -72
- package/src/handlers/tools/github/helpers.ts +0 -125
- package/src/handlers/tools/github/insights-tools.ts +0 -112
- package/src/handlers/tools/github/issue-tools.ts +0 -442
- package/src/handlers/tools/github/kanban-tools.ts +0 -153
- package/src/handlers/tools/github/milestone-tools.ts +0 -371
- package/src/handlers/tools/github/mutation-tools.ts +0 -17
- package/src/handlers/tools/github/read-tools.ts +0 -302
- package/src/handlers/tools/github/schemas.ts +0 -435
- package/src/handlers/tools/github.ts +0 -39
- package/src/handlers/tools/index.ts +0 -255
- package/src/handlers/tools/relationships.ts +0 -390
- package/src/handlers/tools/schemas.ts +0 -165
- package/src/handlers/tools/search.ts +0 -448
- package/src/handlers/tools/team/admin-tools.ts +0 -164
- package/src/handlers/tools/team/analytics-tools.ts +0 -233
- package/src/handlers/tools/team/backup-tools.ts +0 -83
- package/src/handlers/tools/team/core-tools.ts +0 -197
- package/src/handlers/tools/team/export-tools.ts +0 -130
- package/src/handlers/tools/team/helpers.ts +0 -66
- package/src/handlers/tools/team/index.ts +0 -45
- package/src/handlers/tools/team/relationship-tools.ts +0 -219
- package/src/handlers/tools/team/schemas.ts +0 -558
- package/src/handlers/tools/team/search-tools.ts +0 -145
- package/src/handlers/tools/team/vector-tools.ts +0 -261
- package/src/index.ts +0 -57
- package/src/server/mcp-server.ts +0 -446
- package/src/server/registration.ts +0 -141
- package/src/server/scheduler.ts +0 -283
- package/src/transports/http/handlers.ts +0 -78
- package/src/transports/http/index.ts +0 -8
- package/src/transports/http/security.ts +0 -147
- package/src/transports/http/server/index.ts +0 -397
- package/src/transports/http/server/legacy-sse.ts +0 -87
- package/src/transports/http/server/stateful.ts +0 -222
- package/src/transports/http/server/stateless.ts +0 -42
- package/src/transports/http/types.ts +0 -132
- package/src/types/entities.ts +0 -145
- package/src/types/error-types.ts +0 -92
- package/src/types/errors.ts +0 -200
- package/src/types/filtering.ts +0 -55
- package/src/types/github.ts +0 -216
- package/src/types/index.ts +0 -348
- package/src/utils/error-helpers.ts +0 -78
- package/src/utils/errors/error-response-fields.ts +0 -29
- package/src/utils/errors/suggestions.ts +0 -94
- package/src/utils/github-helpers.ts +0 -33
- package/src/utils/logger.ts +0 -107
- package/src/utils/mcp-logger.ts +0 -155
- package/src/utils/progress-utils.ts +0 -100
- package/src/utils/query-helpers.ts +0 -78
- package/src/utils/resource-annotations.ts +0 -75
- package/src/utils/security-utils.ts +0 -198
- package/src/utils/vector-index-helpers.ts +0 -24
- package/src/vector/vector-search-manager.ts +0 -409
- package/src/version.ts +0 -15
- package/test-server/README.md +0 -193
- package/test-server/code-map.md +0 -399
- package/test-server/test-agent-experience.md +0 -213
- package/test-server/test-filter-instructions.mjs +0 -295
- package/test-server/test-instruction-levels.mjs +0 -102
- package/test-server/test-preflight.md +0 -55
- package/test-server/test-prompts.mjs +0 -185
- package/test-server/test-scheduler.mjs +0 -174
- package/test-server/test-tool-annotations.mjs +0 -115
- package/test-server/test-tools-codemode.md +0 -632
- package/test-server/test-tools-codemode2.md +0 -1218
- package/test-server/test-tools-team.md +0 -215
- package/test-server/test-tools.md +0 -429
- package/test-server/test-tools2.md +0 -361
- package/test-server/test-tools3.md +0 -396
- package/test-server/tool-reference.md +0 -231
- package/tests/README.md +0 -54
- package/tests/auth/auth-context.test.ts +0 -162
- package/tests/auth/authorization-server-discovery.test.ts +0 -265
- package/tests/auth/errors.test.ts +0 -170
- package/tests/auth/middleware.test.ts +0 -585
- package/tests/auth/oauth-resource-server.test.ts +0 -173
- package/tests/auth/scope-map.test.ts +0 -66
- package/tests/auth/scopes.test.ts +0 -347
- package/tests/auth/token-validator.test.ts +0 -271
- package/tests/codemode/api.test.ts +0 -396
- package/tests/codemode/auto-return.test.ts +0 -167
- package/tests/codemode/codemode-tool-handlers.test.ts +0 -197
- package/tests/codemode/sandbox-factory.test.ts +0 -152
- package/tests/codemode/sandbox.test.ts +0 -190
- package/tests/codemode/security.test.ts +0 -242
- package/tests/codemode/worker-sandbox.test.ts +0 -106
- package/tests/constants/icons.test.ts +0 -101
- package/tests/constants/server-instructions.test.ts +0 -514
- package/tests/database/crud-workflow-branches.test.ts +0 -418
- package/tests/database/database-branches.test.ts +0 -132
- package/tests/database/entries-auth-branches.test.ts +0 -390
- package/tests/database/native-connection.test.ts +0 -249
- package/tests/database/shared-helpers.test.ts +0 -103
- package/tests/database/sqlite-adapter.bench.ts +0 -63
- package/tests/database/sqlite-adapter.test.ts +0 -690
- package/tests/database/tags.test.ts +0 -134
- package/tests/e2e/README.md +0 -39
- package/tests/e2e/auth.spec.ts +0 -106
- package/tests/e2e/codemode-abuse.spec.ts +0 -75
- package/tests/e2e/health.spec.ts +0 -63
- package/tests/e2e/helpers.ts +0 -139
- package/tests/e2e/oauth-discovery.spec.ts +0 -102
- package/tests/e2e/oauth-scopes.spec.ts +0 -222
- package/tests/e2e/payloads-admin.spec.ts +0 -76
- package/tests/e2e/payloads-analytics.spec.ts +0 -37
- package/tests/e2e/payloads-backup-restore.spec.ts +0 -102
- package/tests/e2e/payloads-backup.spec.ts +0 -44
- package/tests/e2e/payloads-codemode-api.spec.ts +0 -131
- package/tests/e2e/payloads-codemode-readonly.spec.ts +0 -116
- package/tests/e2e/payloads-codemode.spec.ts +0 -116
- package/tests/e2e/payloads-core.spec.ts +0 -82
- package/tests/e2e/payloads-error-contracts.spec.ts +0 -159
- package/tests/e2e/payloads-export.spec.ts +0 -46
- package/tests/e2e/payloads-github-degradation.spec.ts +0 -73
- package/tests/e2e/payloads-github.spec.ts +0 -176
- package/tests/e2e/payloads-relationships.spec.ts +0 -56
- package/tests/e2e/payloads-search.spec.ts +0 -64
- package/tests/e2e/payloads-team-happy.spec.ts +0 -231
- package/tests/e2e/payloads-team.spec.ts +0 -174
- package/tests/e2e/prompts-expanded.spec.ts +0 -137
- package/tests/e2e/prompts.spec.ts +0 -62
- package/tests/e2e/protocols.spec.ts +0 -134
- package/tests/e2e/rate-limiting.spec.ts +0 -291
- package/tests/e2e/resources-briefing-env.spec.ts +0 -106
- package/tests/e2e/resources-complete.spec.ts +0 -180
- package/tests/e2e/resources-expanded.spec.ts +0 -83
- package/tests/e2e/resources-instructions-levels.spec.ts +0 -145
- package/tests/e2e/resources-templates.spec.ts +0 -123
- package/tests/e2e/resources.spec.ts +0 -103
- package/tests/e2e/scheduler.spec.ts +0 -79
- package/tests/e2e/security.spec.ts +0 -112
- package/tests/e2e/session-advanced.spec.ts +0 -152
- package/tests/e2e/sessions.spec.ts +0 -95
- package/tests/e2e/stateless.spec.ts +0 -79
- package/tests/e2e/streaming.spec.ts +0 -176
- package/tests/e2e/tool-filtering-presets.spec.ts +0 -192
- package/tests/e2e/tool-filtering.spec.ts +0 -77
- package/tests/e2e/tools.spec.ts +0 -111
- package/tests/filtering/tool-filter.test.ts +0 -314
- package/tests/github/client-issues-errors.test.ts +0 -433
- package/tests/github/github-integration-branches.test.ts +0 -490
- package/tests/github/github-integration.test.ts +0 -1015
- package/tests/github/github-managers-branches.test.ts +0 -907
- package/tests/github/pull-requests.test.ts +0 -334
- package/tests/handlers/analytics-branches.test.ts +0 -222
- package/tests/handlers/backup-branches.test.ts +0 -270
- package/tests/handlers/briefing-context-section.test.ts +0 -388
- package/tests/handlers/briefing-github-section.test.ts +0 -392
- package/tests/handlers/briefing-user-message.test.ts +0 -405
- package/tests/handlers/codemode-tools.test.ts +0 -85
- package/tests/handlers/copilot-tools.test.ts +0 -126
- package/tests/handlers/error-path-coverage.test.ts +0 -324
- package/tests/handlers/export-tools.test.ts +0 -203
- package/tests/handlers/github-resource-handlers.test.ts +0 -929
- package/tests/handlers/github-tool-handlers.test.ts +0 -1452
- package/tests/handlers/handler-error-branches.test.ts +0 -346
- package/tests/handlers/help-resource.test.ts +0 -92
- package/tests/handlers/prompt-handler-coverage.test.ts +0 -108
- package/tests/handlers/prompt-handlers.test.ts +0 -131
- package/tests/handlers/resource-handler-coverage.test.ts +0 -281
- package/tests/handlers/resource-handlers.test.ts +0 -357
- package/tests/handlers/resource-prompt-branches.test.ts +0 -495
- package/tests/handlers/search-tool-handlers.test.ts +0 -379
- package/tests/handlers/targeted-gap-closure.test.ts +0 -387
- package/tests/handlers/team-admin.test.ts +0 -291
- package/tests/handlers/team-analytics.test.ts +0 -220
- package/tests/handlers/team-core.test.ts +0 -148
- package/tests/handlers/team-data.test.ts +0 -198
- package/tests/handlers/team-relationships.test.ts +0 -271
- package/tests/handlers/team-resource-handlers.test.ts +0 -161
- package/tests/handlers/team-search.test.ts +0 -134
- package/tests/handlers/team-tool-handlers.test.ts +0 -301
- package/tests/handlers/team-vector.test.ts +0 -213
- package/tests/handlers/template-github-branches.test.ts +0 -676
- package/tests/handlers/tool-annotations.test.ts +0 -90
- package/tests/handlers/tool-handler-coverage.test.ts +0 -514
- package/tests/handlers/tool-handlers.test.ts +0 -510
- package/tests/handlers/tool-output-schemas.test.ts +0 -116
- package/tests/handlers/vector-tool-handlers.test.ts +0 -238
- package/tests/security/sql-injection.test.ts +0 -284
- package/tests/server/mcp-server.bench.ts +0 -55
- package/tests/server/mcp-server.test.ts +0 -1326
- package/tests/server/scheduler.test.ts +0 -400
- package/tests/transports/http-legacy-sse.test.ts +0 -275
- package/tests/transports/http-security.test.ts +0 -322
- package/tests/transports/http-stateful.test.ts +0 -487
- package/tests/transports/http-transport-server.test.ts +0 -301
- package/tests/transports/http-transport.test.ts +0 -771
- package/tests/utils/github-helpers.test.ts +0 -58
- package/tests/utils/logger.test.ts +0 -180
- package/tests/utils/mcp-logger.test.ts +0 -211
- package/tests/utils/progress-utils.test.ts +0 -156
- package/tests/utils/query-helpers.test.ts +0 -80
- package/tests/utils/security-utils.test.ts +0 -82
- package/tests/vector/vector-search-branches.test.ts +0 -111
- package/tests/vector/vector-search-manager.test.ts +0 -375
- package/tests/vector/vector-search.bench.ts +0 -48
- package/tsconfig.json +0 -42
- package/tsup.config.ts +0 -19
- package/vitest.config.ts +0 -25
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared Zod Schemas for Tool Handlers
|
|
3
|
-
*
|
|
4
|
-
* Contains cross-group schemas used by multiple tool modules:
|
|
5
|
-
* - EntryOutputSchema: used by core, search, export, admin
|
|
6
|
-
* - EntriesListOutputSchema: used by search, core
|
|
7
|
-
* - RelationshipOutputSchema: used by core, relationships
|
|
8
|
-
* - TagOutputSchema: used by core, analytics
|
|
9
|
-
* - ImportanceBreakdownSchema: used by core
|
|
10
|
-
* - Shared constants: ENTRY_TYPES, SIGNIFICANCE_TYPES, DATE_FORMAT_REGEX
|
|
11
|
-
*
|
|
12
|
-
* Group-specific output schemas stay colocated with their group files.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { z } from 'zod'
|
|
16
|
-
import { ErrorFieldsMixin } from './error-fields-mixin.js'
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Shared Constants
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Valid entry types (matches EntryType union in types/index.ts)
|
|
24
|
-
*/
|
|
25
|
-
export const ENTRY_TYPES = [
|
|
26
|
-
'personal_reflection',
|
|
27
|
-
'project_decision',
|
|
28
|
-
'technical_achievement',
|
|
29
|
-
'bug_fix',
|
|
30
|
-
'feature_implementation',
|
|
31
|
-
'code_review',
|
|
32
|
-
'meeting_notes',
|
|
33
|
-
'learning',
|
|
34
|
-
'research',
|
|
35
|
-
'planning',
|
|
36
|
-
'retrospective',
|
|
37
|
-
'standup',
|
|
38
|
-
'technical_note',
|
|
39
|
-
'development_note',
|
|
40
|
-
'enhancement',
|
|
41
|
-
'milestone',
|
|
42
|
-
'system_integration_test',
|
|
43
|
-
'test_entry',
|
|
44
|
-
'other',
|
|
45
|
-
] as const
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Valid significance types (matches SignificanceType union in types/index.ts)
|
|
49
|
-
*/
|
|
50
|
-
export const SIGNIFICANCE_TYPES = [
|
|
51
|
-
'milestone',
|
|
52
|
-
'breakthrough',
|
|
53
|
-
'technical_breakthrough',
|
|
54
|
-
'decision',
|
|
55
|
-
'lesson_learned',
|
|
56
|
-
'blocker_resolved',
|
|
57
|
-
'release',
|
|
58
|
-
] as const
|
|
59
|
-
|
|
60
|
-
/** Maximum content length for journal entries (chars) */
|
|
61
|
-
export const MAX_CONTENT_LENGTH = 50_000
|
|
62
|
-
|
|
63
|
-
/** Date sentinels for "all time" date range queries */
|
|
64
|
-
export const DATE_MIN_SENTINEL = '1970-01-01'
|
|
65
|
-
export const DATE_MAX_SENTINEL = '2999-12-31'
|
|
66
|
-
|
|
67
|
-
/** YYYY-MM-DD date format regex */
|
|
68
|
-
export const DATE_FORMAT_REGEX = /^\d{4}-\d{2}-\d{2}$/
|
|
69
|
-
export const DATE_FORMAT_MESSAGE = 'Date must be YYYY-MM-DD format'
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Relaxed numeric schema for MCP SDK inputSchema registration.
|
|
73
|
-
*
|
|
74
|
-
* Uses `z.union([z.number(), z.string()])` so the SDK's Zod validation
|
|
75
|
-
* accepts both native numbers and string-typed numbers (e.g., `"42"`).
|
|
76
|
-
* The handler's strict schema (`z.number()`) then validates and coerces
|
|
77
|
-
* the value, producing structured `{success: false, error}` responses
|
|
78
|
-
* via `formatHandlerError()` for invalid input.
|
|
79
|
-
*
|
|
80
|
-
* NOTE: `z.preprocess()` was attempted but its `ZodEffects` return type
|
|
81
|
-
* is too complex for ESLint's strict type resolver, causing cascading
|
|
82
|
-
* `@typescript-eslint/no-unsafe-*` errors across all call sites.
|
|
83
|
-
*/
|
|
84
|
-
export const relaxedNumber = (): z.ZodUnion<[z.ZodNumber, z.ZodString]> =>
|
|
85
|
-
z.union([z.number(), z.string()])
|
|
86
|
-
|
|
87
|
-
// ============================================================================
|
|
88
|
-
// Cross-Group Output Schemas
|
|
89
|
-
// ============================================================================
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Schema for a journal entry in output responses.
|
|
93
|
-
* Uses camelCase to match actual database output format.
|
|
94
|
-
*/
|
|
95
|
-
export const EntryOutputSchema = z
|
|
96
|
-
.object({
|
|
97
|
-
id: z.number(),
|
|
98
|
-
content: z.string(),
|
|
99
|
-
entryType: z.string(),
|
|
100
|
-
isPersonal: z.boolean(),
|
|
101
|
-
timestamp: z.string(),
|
|
102
|
-
tags: z.array(z.string()).optional(),
|
|
103
|
-
significanceType: z.string().nullable().optional(),
|
|
104
|
-
autoContext: z.string().nullable().optional(),
|
|
105
|
-
deletedAt: z.string().nullable().optional(),
|
|
106
|
-
projectNumber: z.number().nullable().optional(),
|
|
107
|
-
projectOwner: z.string().nullable().optional(),
|
|
108
|
-
issueNumber: z.number().nullable().optional(),
|
|
109
|
-
issueUrl: z.string().nullable().optional(),
|
|
110
|
-
prNumber: z.number().nullable().optional(),
|
|
111
|
-
prUrl: z.string().nullable().optional(),
|
|
112
|
-
prStatus: z.string().nullable().optional(),
|
|
113
|
-
workflowRunId: z.number().nullable().optional(),
|
|
114
|
-
workflowName: z.string().nullable().optional(),
|
|
115
|
-
workflowStatus: z.string().nullable().optional(),
|
|
116
|
-
source: z.enum(['personal', 'team']).optional(),
|
|
117
|
-
})
|
|
118
|
-
.extend(ErrorFieldsMixin.shape)
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Schema for list of entries with count.
|
|
122
|
-
* Used by get_recent_entries, search_entries, search_by_date_range.
|
|
123
|
-
*/
|
|
124
|
-
export const EntriesListOutputSchema = z
|
|
125
|
-
.object({
|
|
126
|
-
entries: z.array(EntryOutputSchema).optional(),
|
|
127
|
-
count: z.number().optional(),
|
|
128
|
-
success: z.boolean().optional(),
|
|
129
|
-
error: z.string().optional(),
|
|
130
|
-
})
|
|
131
|
-
.extend(ErrorFieldsMixin.shape)
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Schema for a relationship between entries.
|
|
135
|
-
*/
|
|
136
|
-
export const RelationshipOutputSchema = z
|
|
137
|
-
.object({
|
|
138
|
-
id: z.number(),
|
|
139
|
-
fromEntryId: z.number(),
|
|
140
|
-
toEntryId: z.number(),
|
|
141
|
-
relationshipType: z.string(),
|
|
142
|
-
description: z.string().nullable().optional(),
|
|
143
|
-
createdAt: z.string(),
|
|
144
|
-
})
|
|
145
|
-
.extend(ErrorFieldsMixin.shape)
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Importance score breakdown schema.
|
|
149
|
-
*/
|
|
150
|
-
export const ImportanceBreakdownSchema = z.object({
|
|
151
|
-
significance: z.number(),
|
|
152
|
-
relationships: z.number(),
|
|
153
|
-
causal: z.number(),
|
|
154
|
-
recency: z.number(),
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Tag with usage count.
|
|
159
|
-
*/
|
|
160
|
-
export const TagOutputSchema = z
|
|
161
|
-
.object({
|
|
162
|
-
name: z.string(),
|
|
163
|
-
count: z.number().nullable(),
|
|
164
|
-
})
|
|
165
|
-
.extend(ErrorFieldsMixin.shape)
|
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Tool Group - 4 tools
|
|
3
|
-
*
|
|
4
|
-
* Tools: search_entries, search_by_date_range, semantic_search, get_vector_index_stats
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { z } from 'zod'
|
|
8
|
-
import type { ToolDefinition, ToolContext } from '../../types/index.js'
|
|
9
|
-
import { formatHandlerError } from '../../utils/error-helpers.js'
|
|
10
|
-
import { ErrorFieldsMixin } from './error-fields-mixin.js'
|
|
11
|
-
import {
|
|
12
|
-
ENTRY_TYPES,
|
|
13
|
-
DATE_FORMAT_REGEX,
|
|
14
|
-
DATE_FORMAT_MESSAGE,
|
|
15
|
-
EntryOutputSchema,
|
|
16
|
-
EntriesListOutputSchema,
|
|
17
|
-
relaxedNumber,
|
|
18
|
-
} from './schemas.js'
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Constants
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
/** Maximum entries returned by any single search query */
|
|
25
|
-
const MAX_QUERY_LIMIT = 500
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// Input Schemas
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
/** Strict schema — used inside handler for structured Zod errors */
|
|
32
|
-
const SearchEntriesSchema = z.object({
|
|
33
|
-
query: z.string().optional(),
|
|
34
|
-
limit: z.number().max(MAX_QUERY_LIMIT).optional().default(10),
|
|
35
|
-
is_personal: z.boolean().optional(),
|
|
36
|
-
project_number: z.number().optional(),
|
|
37
|
-
issue_number: z.number().optional(),
|
|
38
|
-
pr_number: z.number().optional(),
|
|
39
|
-
pr_status: z.enum(['draft', 'open', 'merged', 'closed']).optional(),
|
|
40
|
-
workflow_run_id: z.number().optional(),
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
/** Relaxed schema — passed to SDK inputSchema so Zod enum errors reach the handler */
|
|
44
|
-
const SearchEntriesSchemaMcp = z.object({
|
|
45
|
-
query: z.string().optional(),
|
|
46
|
-
limit: relaxedNumber().optional().default(10),
|
|
47
|
-
is_personal: z.boolean().optional(),
|
|
48
|
-
project_number: relaxedNumber().optional(),
|
|
49
|
-
issue_number: relaxedNumber().optional(),
|
|
50
|
-
pr_number: relaxedNumber().optional(),
|
|
51
|
-
pr_status: z.string().optional(),
|
|
52
|
-
workflow_run_id: relaxedNumber().optional(),
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
/** Strict schema — used inside handler for structured Zod errors */
|
|
56
|
-
const SearchByDateRangeSchema = z.object({
|
|
57
|
-
start_date: z.string().regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE),
|
|
58
|
-
end_date: z.string().regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE),
|
|
59
|
-
entry_type: z.enum(ENTRY_TYPES).optional(),
|
|
60
|
-
tags: z.array(z.string()).optional(),
|
|
61
|
-
is_personal: z.boolean().optional(),
|
|
62
|
-
project_number: z.number().optional(),
|
|
63
|
-
issue_number: z.number().optional(),
|
|
64
|
-
pr_number: z.number().optional(),
|
|
65
|
-
workflow_run_id: z.number().optional(),
|
|
66
|
-
limit: z.number().max(MAX_QUERY_LIMIT).optional().default(500),
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
/** Relaxed schema — passed to SDK inputSchema so Zod errors reach the handler */
|
|
70
|
-
const SearchByDateRangeSchemaMcp = z.object({
|
|
71
|
-
start_date: z.string(),
|
|
72
|
-
end_date: z.string(),
|
|
73
|
-
entry_type: z.string().optional(),
|
|
74
|
-
tags: z.array(z.string()).optional(),
|
|
75
|
-
is_personal: z.boolean().optional(),
|
|
76
|
-
project_number: relaxedNumber().optional(),
|
|
77
|
-
issue_number: relaxedNumber().optional(),
|
|
78
|
-
pr_number: relaxedNumber().optional(),
|
|
79
|
-
workflow_run_id: relaxedNumber().optional(),
|
|
80
|
-
limit: relaxedNumber().optional().default(500),
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
/** Strict schema — used inside handler for structured Zod errors */
|
|
84
|
-
const SemanticSearchSchema = z.object({
|
|
85
|
-
query: z.string(),
|
|
86
|
-
limit: z.number().max(MAX_QUERY_LIMIT).optional().default(10),
|
|
87
|
-
similarity_threshold: z.number().optional().default(0.25),
|
|
88
|
-
is_personal: z.boolean().optional(),
|
|
89
|
-
hint_on_empty: z
|
|
90
|
-
.boolean()
|
|
91
|
-
.optional()
|
|
92
|
-
.default(true)
|
|
93
|
-
.describe('Include hint when no results found (default: true)'),
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
/** Relaxed schema — passed to SDK inputSchema so Zod min/max errors reach the handler */
|
|
97
|
-
const SemanticSearchSchemaMcp = z.object({
|
|
98
|
-
query: z.string(),
|
|
99
|
-
limit: relaxedNumber().optional().default(10),
|
|
100
|
-
similarity_threshold: relaxedNumber().optional().default(0.25),
|
|
101
|
-
is_personal: z.boolean().optional(),
|
|
102
|
-
hint_on_empty: z
|
|
103
|
-
.boolean()
|
|
104
|
-
.optional()
|
|
105
|
-
.default(true)
|
|
106
|
-
.describe('Include hint when no results found (default: true)'),
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// ============================================================================
|
|
110
|
-
// Output Schemas
|
|
111
|
-
// ============================================================================
|
|
112
|
-
|
|
113
|
-
const SemanticEntryOutputSchema = EntryOutputSchema.extend({
|
|
114
|
-
similarity: z.number(),
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const SemanticSearchOutputSchema = z
|
|
118
|
-
.object({
|
|
119
|
-
query: z.string().optional(),
|
|
120
|
-
entries: z.array(SemanticEntryOutputSchema).optional(),
|
|
121
|
-
count: z.number().optional(),
|
|
122
|
-
hint: z.string().optional(),
|
|
123
|
-
success: z.boolean().optional(),
|
|
124
|
-
error: z.string().optional(),
|
|
125
|
-
})
|
|
126
|
-
.extend(ErrorFieldsMixin.shape)
|
|
127
|
-
|
|
128
|
-
const VectorStatsOutputSchema = z
|
|
129
|
-
.object({
|
|
130
|
-
available: z.boolean(),
|
|
131
|
-
error: z.string().optional(),
|
|
132
|
-
itemCount: z.number().optional(),
|
|
133
|
-
modelName: z.string().optional(),
|
|
134
|
-
dimensions: z.number().optional(),
|
|
135
|
-
success: z.boolean().optional(),
|
|
136
|
-
})
|
|
137
|
-
.extend(ErrorFieldsMixin.shape)
|
|
138
|
-
|
|
139
|
-
// ============================================================================
|
|
140
|
-
// Tool Definitions
|
|
141
|
-
// ============================================================================
|
|
142
|
-
|
|
143
|
-
export function getSearchTools(context: ToolContext): ToolDefinition[] {
|
|
144
|
-
const { db, teamDb, vectorManager } = context
|
|
145
|
-
return [
|
|
146
|
-
{
|
|
147
|
-
name: 'search_entries',
|
|
148
|
-
title: 'Search Entries',
|
|
149
|
-
description:
|
|
150
|
-
'Full-text search journal entries using FTS5 (supports phrases "exact match", prefix auth*, boolean NOT/OR/AND, ranked by relevance). Optional filters for GitHub Projects, Issues, PRs, and Actions.',
|
|
151
|
-
group: 'search',
|
|
152
|
-
inputSchema: SearchEntriesSchemaMcp,
|
|
153
|
-
outputSchema: EntriesListOutputSchema,
|
|
154
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
155
|
-
handler: (params: unknown) => {
|
|
156
|
-
try {
|
|
157
|
-
const input = SearchEntriesSchema.parse(params)
|
|
158
|
-
const hasFilters =
|
|
159
|
-
input.project_number !== undefined ||
|
|
160
|
-
input.issue_number !== undefined ||
|
|
161
|
-
input.pr_number !== undefined ||
|
|
162
|
-
input.pr_status !== undefined ||
|
|
163
|
-
input.workflow_run_id !== undefined ||
|
|
164
|
-
input.is_personal !== undefined
|
|
165
|
-
|
|
166
|
-
// When merging across DBs, fetch more per-DB so BM25 ranking
|
|
167
|
-
// in one DB doesn't silently drop entries before the merge.
|
|
168
|
-
// The actual user limit is applied by mergeAndDedup.
|
|
169
|
-
const perDbLimit = calcPerDbLimit(input.limit, !!teamDb)
|
|
170
|
-
|
|
171
|
-
let personalEntries
|
|
172
|
-
if (!input.query && !hasFilters) {
|
|
173
|
-
personalEntries = db.getRecentEntries(perDbLimit, input.is_personal)
|
|
174
|
-
} else {
|
|
175
|
-
personalEntries = db.searchEntries(input.query || '', {
|
|
176
|
-
limit: perDbLimit,
|
|
177
|
-
isPersonal: input.is_personal,
|
|
178
|
-
projectNumber: input.project_number,
|
|
179
|
-
issueNumber: input.issue_number,
|
|
180
|
-
prNumber: input.pr_number,
|
|
181
|
-
prStatus: input.pr_status,
|
|
182
|
-
workflowRunId: input.workflow_run_id,
|
|
183
|
-
})
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Cross-database merge when team DB is available
|
|
187
|
-
// Skip team DB when is_personal is explicitly true (team entries are never personal)
|
|
188
|
-
if (teamDb && input.is_personal !== true) {
|
|
189
|
-
let teamEntries
|
|
190
|
-
if (!input.query && !hasFilters) {
|
|
191
|
-
teamEntries = teamDb.getRecentEntries(perDbLimit)
|
|
192
|
-
} else {
|
|
193
|
-
teamEntries = teamDb.searchEntries(input.query || '', {
|
|
194
|
-
limit: perDbLimit,
|
|
195
|
-
projectNumber: input.project_number,
|
|
196
|
-
issueNumber: input.issue_number,
|
|
197
|
-
prNumber: input.pr_number,
|
|
198
|
-
prStatus: input.pr_status,
|
|
199
|
-
workflowRunId: input.workflow_run_id,
|
|
200
|
-
})
|
|
201
|
-
}
|
|
202
|
-
const merged = mergeAndDedup(
|
|
203
|
-
personalEntries.map((e) => ({ ...e, source: 'personal' as const })),
|
|
204
|
-
teamEntries.map((e) => ({ ...e, source: 'team' as const })),
|
|
205
|
-
input.limit
|
|
206
|
-
)
|
|
207
|
-
return { entries: merged, count: merged.length }
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return { entries: personalEntries, count: personalEntries.length }
|
|
211
|
-
} catch (err) {
|
|
212
|
-
return formatHandlerError(err)
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
name: 'search_by_date_range',
|
|
218
|
-
title: 'Search by Date Range',
|
|
219
|
-
description: 'Search journal entries within a date range with optional filters',
|
|
220
|
-
group: 'search',
|
|
221
|
-
inputSchema: SearchByDateRangeSchemaMcp,
|
|
222
|
-
outputSchema: EntriesListOutputSchema,
|
|
223
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
224
|
-
handler: (params: unknown) => {
|
|
225
|
-
try {
|
|
226
|
-
const input = SearchByDateRangeSchema.parse(params)
|
|
227
|
-
|
|
228
|
-
// Validate date range order (YYYY-MM-DD sorts lexicographically)
|
|
229
|
-
if (input.start_date > input.end_date) {
|
|
230
|
-
return {
|
|
231
|
-
success: false,
|
|
232
|
-
error: `Invalid date range: start_date (${input.start_date}) is after end_date (${input.end_date})`,
|
|
233
|
-
code: 'VALIDATION_ERROR',
|
|
234
|
-
category: 'validation',
|
|
235
|
-
suggestion: 'Ensure start_date is before or equal to end_date',
|
|
236
|
-
recoverable: true,
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const perDbLimit = calcPerDbLimit(input.limit, !!teamDb)
|
|
241
|
-
const personalEntries = db.searchByDateRange(input.start_date, input.end_date, {
|
|
242
|
-
entryType: input.entry_type,
|
|
243
|
-
tags: input.tags,
|
|
244
|
-
isPersonal: input.is_personal,
|
|
245
|
-
projectNumber: input.project_number,
|
|
246
|
-
issueNumber: input.issue_number,
|
|
247
|
-
prNumber: input.pr_number,
|
|
248
|
-
workflowRunId: input.workflow_run_id,
|
|
249
|
-
limit: perDbLimit,
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
// Cross-database merge when team DB is available
|
|
253
|
-
// Skip team DB when is_personal is explicitly true (team entries are never personal)
|
|
254
|
-
if (teamDb && input.is_personal !== true) {
|
|
255
|
-
const teamEntries = teamDb.searchByDateRange(
|
|
256
|
-
input.start_date,
|
|
257
|
-
input.end_date,
|
|
258
|
-
{
|
|
259
|
-
entryType: input.entry_type,
|
|
260
|
-
tags: input.tags,
|
|
261
|
-
projectNumber: input.project_number,
|
|
262
|
-
issueNumber: input.issue_number,
|
|
263
|
-
prNumber: input.pr_number,
|
|
264
|
-
workflowRunId: input.workflow_run_id,
|
|
265
|
-
limit: perDbLimit,
|
|
266
|
-
}
|
|
267
|
-
)
|
|
268
|
-
const merged = mergeAndDedup(
|
|
269
|
-
personalEntries.map((e) => ({ ...e, source: 'personal' as const })),
|
|
270
|
-
teamEntries.map((e) => ({ ...e, source: 'team' as const })),
|
|
271
|
-
input.limit
|
|
272
|
-
)
|
|
273
|
-
return { entries: merged, count: merged.length }
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return { entries: personalEntries, count: personalEntries.length }
|
|
277
|
-
} catch (err) {
|
|
278
|
-
return formatHandlerError(err)
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
name: 'semantic_search',
|
|
284
|
-
title: 'Semantic Search',
|
|
285
|
-
description: 'Perform semantic/vector search on journal entries using AI embeddings',
|
|
286
|
-
group: 'search',
|
|
287
|
-
inputSchema: SemanticSearchSchemaMcp,
|
|
288
|
-
outputSchema: SemanticSearchOutputSchema,
|
|
289
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
290
|
-
handler: async (params: unknown) => {
|
|
291
|
-
try {
|
|
292
|
-
const input = SemanticSearchSchema.parse(params)
|
|
293
|
-
|
|
294
|
-
if (!vectorManager) {
|
|
295
|
-
return {
|
|
296
|
-
success: false,
|
|
297
|
-
error: 'Semantic search not initialized. Vector search manager is not available.',
|
|
298
|
-
code: 'CONFIGURATION_ERROR',
|
|
299
|
-
category: 'configuration',
|
|
300
|
-
suggestion:
|
|
301
|
-
'Enable semantic search with --auto-rebuild-index or set up the vector manager',
|
|
302
|
-
recoverable: false,
|
|
303
|
-
query: input.query,
|
|
304
|
-
entries: [],
|
|
305
|
-
count: 0,
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const results = await vectorManager.search(
|
|
310
|
-
input.query,
|
|
311
|
-
input.limit ?? 10,
|
|
312
|
-
input.similarity_threshold ?? 0.25
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
// Batch-fetch all entries in a single query (instead of N+1 getEntryById calls)
|
|
316
|
-
const entryIds = results.map((r) => r.entryId)
|
|
317
|
-
const entriesMap = db.getEntriesByIds(entryIds)
|
|
318
|
-
|
|
319
|
-
const entries = results
|
|
320
|
-
.map((r) => {
|
|
321
|
-
const entry = entriesMap.get(r.entryId)
|
|
322
|
-
if (!entry) return null
|
|
323
|
-
// Apply is_personal filter if specified
|
|
324
|
-
if (
|
|
325
|
-
input.is_personal !== undefined &&
|
|
326
|
-
entry.isPersonal !== input.is_personal
|
|
327
|
-
)
|
|
328
|
-
return null
|
|
329
|
-
return {
|
|
330
|
-
...entry,
|
|
331
|
-
similarity: Math.round(r.score * 100) / 100,
|
|
332
|
-
}
|
|
333
|
-
})
|
|
334
|
-
.filter((e): e is NonNullable<typeof e> => e !== null)
|
|
335
|
-
|
|
336
|
-
const stats = vectorManager.getStats()
|
|
337
|
-
const isIndexEmpty = stats.itemCount === 0
|
|
338
|
-
const includeHint = input.hint_on_empty ?? true
|
|
339
|
-
|
|
340
|
-
// Quality gate: if the best match is below this floor,
|
|
341
|
-
// treat all results as noise and include the hint
|
|
342
|
-
const QUALITY_FLOOR = 0.5
|
|
343
|
-
const bestSimilarity = entries[0]?.similarity ?? 0
|
|
344
|
-
const allNoise = entries.length > 0 && bestSimilarity < QUALITY_FLOOR
|
|
345
|
-
|
|
346
|
-
// Build hint: quality gate hint is always shown (not gated by hint_on_empty)
|
|
347
|
-
// because noisy results ≠ empty results. hint_on_empty only controls
|
|
348
|
-
// the "no results" and "empty index" advisory hints.
|
|
349
|
-
const hint =
|
|
350
|
-
isIndexEmpty && includeHint
|
|
351
|
-
? 'No entries in vector index. Use rebuild_vector_index to index existing entries.'
|
|
352
|
-
: entries.length === 0 && includeHint
|
|
353
|
-
? `No entries matched your query above the similarity threshold (${String(input.similarity_threshold ?? 0.25)}). Try lowering similarity_threshold (e.g., 0.15) for broader matches.`
|
|
354
|
-
: allNoise
|
|
355
|
-
? `Results may be noise — best similarity (${String(bestSimilarity)}) is below quality floor (${String(QUALITY_FLOOR)}). Try a more specific query or raise similarity_threshold to filter weak matches.`
|
|
356
|
-
: undefined
|
|
357
|
-
|
|
358
|
-
return {
|
|
359
|
-
query: input.query,
|
|
360
|
-
entries,
|
|
361
|
-
count: entries.length,
|
|
362
|
-
...(hint !== undefined ? { hint } : {}),
|
|
363
|
-
}
|
|
364
|
-
} catch (err) {
|
|
365
|
-
return formatHandlerError(err)
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
name: 'get_vector_index_stats',
|
|
371
|
-
title: 'Get Vector Index Stats',
|
|
372
|
-
description: 'Get statistics about the semantic search vector index',
|
|
373
|
-
group: 'search',
|
|
374
|
-
inputSchema: z.object({}).strict(),
|
|
375
|
-
outputSchema: VectorStatsOutputSchema,
|
|
376
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
377
|
-
handler: (_params: unknown) => {
|
|
378
|
-
try {
|
|
379
|
-
if (!vectorManager) {
|
|
380
|
-
return {
|
|
381
|
-
success: false,
|
|
382
|
-
available: false,
|
|
383
|
-
error: 'Vector search not available',
|
|
384
|
-
code: 'CONFIGURATION_ERROR',
|
|
385
|
-
category: 'configuration',
|
|
386
|
-
suggestion:
|
|
387
|
-
'Enable semantic search with --auto-rebuild-index or set up the vector manager',
|
|
388
|
-
recoverable: false,
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
const stats = vectorManager.getStats()
|
|
392
|
-
return { success: true, available: true, ...stats }
|
|
393
|
-
} catch (err) {
|
|
394
|
-
return formatHandlerError(err)
|
|
395
|
-
}
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// ============================================================================
|
|
402
|
-
// Helpers
|
|
403
|
-
// ============================================================================
|
|
404
|
-
|
|
405
|
-
/** Number of leading characters used as deduplication key */
|
|
406
|
-
const DEDUP_KEY_LENGTH = 200
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* When merging across personal + team DBs, fetch more per-DB so BM25
|
|
410
|
-
* ranking in one DB doesn't silently drop entries before the merge.
|
|
411
|
-
*/
|
|
412
|
-
function calcPerDbLimit(limit: number, hasTeamDb: boolean): number {
|
|
413
|
-
return hasTeamDb ? Math.min(limit * 2, MAX_QUERY_LIMIT) : limit
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
interface EntryWithSource {
|
|
417
|
-
content: string
|
|
418
|
-
timestamp: string
|
|
419
|
-
source: 'personal' | 'team'
|
|
420
|
-
[key: string]: unknown
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Merge personal and team results, deduplicate by content,
|
|
425
|
-
* and sort by timestamp descending.
|
|
426
|
-
*/
|
|
427
|
-
function mergeAndDedup(
|
|
428
|
-
personal: EntryWithSource[],
|
|
429
|
-
team: EntryWithSource[],
|
|
430
|
-
limit?: number
|
|
431
|
-
): EntryWithSource[] {
|
|
432
|
-
const seen = new Set<string>()
|
|
433
|
-
const merged: EntryWithSource[] = []
|
|
434
|
-
|
|
435
|
-
// Concat and sort by timestamp descending (ISO 8601 sorts lexicographically)
|
|
436
|
-
const all = [...personal, ...team].sort((a, b) => b.timestamp.localeCompare(a.timestamp))
|
|
437
|
-
|
|
438
|
-
for (const entry of all) {
|
|
439
|
-
// Deduplicate by content (same entry shared to team)
|
|
440
|
-
const key = entry.content.slice(0, DEDUP_KEY_LENGTH)
|
|
441
|
-
if (!seen.has(key)) {
|
|
442
|
-
seen.add(key)
|
|
443
|
-
merged.push(entry)
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return limit !== undefined ? merged.slice(0, limit) : merged
|
|
448
|
-
}
|