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,346 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Analytics Tool Group - 2 tools
|
|
3
|
-
*
|
|
4
|
-
* Tools: get_statistics, get_cross_project_insights
|
|
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 {
|
|
11
|
-
DATE_FORMAT_REGEX,
|
|
12
|
-
DATE_FORMAT_MESSAGE,
|
|
13
|
-
TagOutputSchema,
|
|
14
|
-
relaxedNumber,
|
|
15
|
-
} from './schemas.js'
|
|
16
|
-
import { ErrorFieldsMixin } from './error-fields-mixin.js'
|
|
17
|
-
|
|
18
|
-
// Named constants (magic value extraction)
|
|
19
|
-
const INACTIVE_THRESHOLD_DAYS = 7
|
|
20
|
-
const MS_PER_DAY = 86_400_000
|
|
21
|
-
const MAX_TAGS_PER_PROJECT = 5
|
|
22
|
-
|
|
23
|
-
// ============================================================================
|
|
24
|
-
// Output Schemas
|
|
25
|
-
// ============================================================================
|
|
26
|
-
|
|
27
|
-
const StatisticsOutputSchema = z
|
|
28
|
-
.object({
|
|
29
|
-
groupBy: z.string().optional(),
|
|
30
|
-
totalEntries: z.number().optional(),
|
|
31
|
-
entriesByType: z.record(z.string(), z.number()).optional(),
|
|
32
|
-
entriesByPeriod: z
|
|
33
|
-
.array(
|
|
34
|
-
z.object({
|
|
35
|
-
period: z.string(),
|
|
36
|
-
count: z.number(),
|
|
37
|
-
})
|
|
38
|
-
)
|
|
39
|
-
.optional(),
|
|
40
|
-
decisionDensity: z
|
|
41
|
-
.array(
|
|
42
|
-
z.object({
|
|
43
|
-
period: z.string(),
|
|
44
|
-
significantCount: z.number(),
|
|
45
|
-
})
|
|
46
|
-
)
|
|
47
|
-
.optional(),
|
|
48
|
-
relationshipComplexity: z
|
|
49
|
-
.object({
|
|
50
|
-
totalRelationships: z.number(),
|
|
51
|
-
avgPerEntry: z.number(),
|
|
52
|
-
})
|
|
53
|
-
.optional(),
|
|
54
|
-
activityTrend: z
|
|
55
|
-
.object({
|
|
56
|
-
currentPeriod: z.string(),
|
|
57
|
-
previousPeriod: z.string(),
|
|
58
|
-
growthPercent: z.number().nullable(),
|
|
59
|
-
})
|
|
60
|
-
.optional(),
|
|
61
|
-
causalMetrics: z
|
|
62
|
-
.object({
|
|
63
|
-
blocked_by: z.number(),
|
|
64
|
-
resolved: z.number(),
|
|
65
|
-
caused: z.number(),
|
|
66
|
-
})
|
|
67
|
-
.optional(),
|
|
68
|
-
dateRange: z
|
|
69
|
-
.object({
|
|
70
|
-
startDate: z.string(),
|
|
71
|
-
endDate: z.string(),
|
|
72
|
-
})
|
|
73
|
-
.optional(),
|
|
74
|
-
projectBreakdown: z
|
|
75
|
-
.array(
|
|
76
|
-
z.object({
|
|
77
|
-
project_number: z.number(),
|
|
78
|
-
entry_count: z.number(),
|
|
79
|
-
})
|
|
80
|
-
)
|
|
81
|
-
.optional(),
|
|
82
|
-
success: z.boolean().optional(),
|
|
83
|
-
error: z.string().optional(),
|
|
84
|
-
})
|
|
85
|
-
.extend(ErrorFieldsMixin.shape)
|
|
86
|
-
|
|
87
|
-
const ProjectSummaryOutputSchema = z
|
|
88
|
-
.object({
|
|
89
|
-
project_number: z.number(),
|
|
90
|
-
entry_count: z.number(),
|
|
91
|
-
first_entry: z.string(),
|
|
92
|
-
last_entry: z.string(),
|
|
93
|
-
active_days: z.number(),
|
|
94
|
-
top_tags: z.array(TagOutputSchema),
|
|
95
|
-
})
|
|
96
|
-
.extend(ErrorFieldsMixin.shape)
|
|
97
|
-
|
|
98
|
-
const CrossProjectInsightsOutputSchema = z
|
|
99
|
-
.object({
|
|
100
|
-
project_count: z.number().optional(),
|
|
101
|
-
total_entries: z.number().optional(),
|
|
102
|
-
projects: z.array(ProjectSummaryOutputSchema).optional(),
|
|
103
|
-
inactive_projects: z
|
|
104
|
-
.array(
|
|
105
|
-
z.object({
|
|
106
|
-
project_number: z.number(),
|
|
107
|
-
last_entry_date: z.string(),
|
|
108
|
-
})
|
|
109
|
-
)
|
|
110
|
-
.optional(),
|
|
111
|
-
inactiveThresholdDays: z.number().optional(),
|
|
112
|
-
time_distribution: z
|
|
113
|
-
.array(
|
|
114
|
-
z.object({
|
|
115
|
-
project_number: z.number(),
|
|
116
|
-
percentage: z.string(),
|
|
117
|
-
})
|
|
118
|
-
)
|
|
119
|
-
.optional(),
|
|
120
|
-
message: z.string().optional(),
|
|
121
|
-
success: z.boolean().optional(),
|
|
122
|
-
error: z.string().optional(),
|
|
123
|
-
})
|
|
124
|
-
.extend(ErrorFieldsMixin.shape)
|
|
125
|
-
|
|
126
|
-
// ============================================================================
|
|
127
|
-
// Input Schemas
|
|
128
|
-
// ============================================================================
|
|
129
|
-
|
|
130
|
-
/** Strict schema — used inside handler for structured Zod errors */
|
|
131
|
-
const GetStatisticsSchema = z.object({
|
|
132
|
-
group_by: z.enum(['day', 'week', 'month']).optional().default('week'),
|
|
133
|
-
start_date: z.string().regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE).optional(),
|
|
134
|
-
end_date: z.string().regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE).optional(),
|
|
135
|
-
project_breakdown: z.boolean().optional().default(false),
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
/** Relaxed schema — passed to SDK inputSchema so Zod errors reach the handler */
|
|
139
|
-
const GetStatisticsSchemaMcp = z.object({
|
|
140
|
-
group_by: z.string().optional().default('week'),
|
|
141
|
-
start_date: z.string().optional(),
|
|
142
|
-
end_date: z.string().optional(),
|
|
143
|
-
project_breakdown: z.boolean().optional().default(false),
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
/** Strict schema — used inside handler for structured Zod errors */
|
|
147
|
-
const CrossProjectInsightsInputSchema = z.object({
|
|
148
|
-
start_date: z
|
|
149
|
-
.string()
|
|
150
|
-
.regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE)
|
|
151
|
-
.optional()
|
|
152
|
-
.describe('Start date (YYYY-MM-DD)'),
|
|
153
|
-
end_date: z
|
|
154
|
-
.string()
|
|
155
|
-
.regex(DATE_FORMAT_REGEX, DATE_FORMAT_MESSAGE)
|
|
156
|
-
.optional()
|
|
157
|
-
.describe('End date (YYYY-MM-DD)'),
|
|
158
|
-
min_entries: z.number().optional().default(3).describe('Minimum entries to include project'),
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
/** Relaxed schema — passed to SDK inputSchema so Zod errors reach the handler */
|
|
162
|
-
const CrossProjectInsightsInputSchemaMcp = z.object({
|
|
163
|
-
start_date: z.string().optional().describe('Start date (YYYY-MM-DD)'),
|
|
164
|
-
end_date: z.string().optional().describe('End date (YYYY-MM-DD)'),
|
|
165
|
-
min_entries: relaxedNumber()
|
|
166
|
-
.optional()
|
|
167
|
-
.default(3)
|
|
168
|
-
.describe('Minimum entries to include project'),
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
// ============================================================================
|
|
172
|
-
// Tool Definitions
|
|
173
|
-
// ============================================================================
|
|
174
|
-
|
|
175
|
-
export function getAnalyticsTools(context: ToolContext): ToolDefinition[] {
|
|
176
|
-
const { db } = context
|
|
177
|
-
return [
|
|
178
|
-
{
|
|
179
|
-
name: 'get_statistics',
|
|
180
|
-
title: 'Get Statistics',
|
|
181
|
-
description:
|
|
182
|
-
'Get journal statistics and analytics (Phase 2: includes project breakdown)',
|
|
183
|
-
group: 'analytics',
|
|
184
|
-
inputSchema: GetStatisticsSchemaMcp,
|
|
185
|
-
outputSchema: StatisticsOutputSchema,
|
|
186
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
187
|
-
handler: (params: unknown) => {
|
|
188
|
-
try {
|
|
189
|
-
const { group_by, start_date, end_date, project_breakdown } =
|
|
190
|
-
GetStatisticsSchema.parse(params)
|
|
191
|
-
const stats = db.getStatistics(
|
|
192
|
-
group_by,
|
|
193
|
-
start_date,
|
|
194
|
-
end_date,
|
|
195
|
-
project_breakdown
|
|
196
|
-
)
|
|
197
|
-
return { ...(stats as object), groupBy: group_by }
|
|
198
|
-
} catch (err) {
|
|
199
|
-
return formatHandlerError(err)
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
name: 'get_cross_project_insights',
|
|
205
|
-
title: 'Get Cross-Project Insights',
|
|
206
|
-
description: 'Analyze patterns across all GitHub Projects tracked in journal entries',
|
|
207
|
-
group: 'analytics',
|
|
208
|
-
inputSchema: CrossProjectInsightsInputSchemaMcp,
|
|
209
|
-
outputSchema: CrossProjectInsightsOutputSchema,
|
|
210
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
211
|
-
handler: (params: unknown) => {
|
|
212
|
-
try {
|
|
213
|
-
const input = CrossProjectInsightsInputSchema.parse(params)
|
|
214
|
-
|
|
215
|
-
// Build WHERE clause
|
|
216
|
-
let where = 'WHERE deleted_at IS NULL AND project_number IS NOT NULL'
|
|
217
|
-
const sqlParams: unknown[] = []
|
|
218
|
-
|
|
219
|
-
if (input.start_date) {
|
|
220
|
-
where += ' AND DATE(timestamp) >= DATE(?)'
|
|
221
|
-
sqlParams.push(input.start_date)
|
|
222
|
-
}
|
|
223
|
-
if (input.end_date) {
|
|
224
|
-
where += ' AND DATE(timestamp) <= DATE(?)'
|
|
225
|
-
sqlParams.push(input.end_date)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Get active projects with stats
|
|
229
|
-
const projectsResult = db.executeRawQuery(
|
|
230
|
-
`
|
|
231
|
-
SELECT project_number, COUNT(*) as entry_count,
|
|
232
|
-
MIN(DATE(timestamp)) as first_entry,
|
|
233
|
-
MAX(DATE(timestamp)) as last_entry,
|
|
234
|
-
COUNT(DISTINCT DATE(timestamp)) as active_days
|
|
235
|
-
FROM memory_journal ${where}
|
|
236
|
-
GROUP BY project_number
|
|
237
|
-
HAVING entry_count >= ?
|
|
238
|
-
ORDER BY entry_count DESC
|
|
239
|
-
`,
|
|
240
|
-
[...sqlParams, input.min_entries]
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
if (!projectsResult[0] || projectsResult[0].values.length === 0) {
|
|
244
|
-
return {
|
|
245
|
-
project_count: 0,
|
|
246
|
-
total_entries: 0,
|
|
247
|
-
projects: [],
|
|
248
|
-
inactive_projects: [],
|
|
249
|
-
inactiveThresholdDays: INACTIVE_THRESHOLD_DAYS,
|
|
250
|
-
time_distribution: [],
|
|
251
|
-
message: `No projects found with at least ${String(input.min_entries)} entries`,
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const columns = projectsResult[0].columns
|
|
256
|
-
const projects = projectsResult[0].values.map((row: unknown[]) => {
|
|
257
|
-
const obj: Record<string, unknown> = {}
|
|
258
|
-
columns.forEach((col: string, i: number) => {
|
|
259
|
-
obj[col] = row[i]
|
|
260
|
-
})
|
|
261
|
-
return obj
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
// Get top tags per project (batch query instead of N+1)
|
|
265
|
-
const projectTags: Record<number, { name: string; count: number }[]> = {}
|
|
266
|
-
const projectNumbers = projects.map((p) => p['project_number'] as number)
|
|
267
|
-
if (projectNumbers.length > 0) {
|
|
268
|
-
const tagPlaceholders = projectNumbers.map(() => '?').join(',')
|
|
269
|
-
const allTagsResult = db.executeRawQuery(
|
|
270
|
-
`
|
|
271
|
-
SELECT m.project_number, t.name, COUNT(*) as count
|
|
272
|
-
FROM tags t
|
|
273
|
-
JOIN entry_tags et ON t.id = et.tag_id
|
|
274
|
-
JOIN memory_journal m ON et.entry_id = m.id
|
|
275
|
-
WHERE m.project_number IN (${tagPlaceholders}) AND m.deleted_at IS NULL
|
|
276
|
-
GROUP BY m.project_number, t.name
|
|
277
|
-
ORDER BY m.project_number, count DESC
|
|
278
|
-
`,
|
|
279
|
-
projectNumbers
|
|
280
|
-
)
|
|
281
|
-
if (allTagsResult[0]) {
|
|
282
|
-
// Partition rows by project_number, keeping top 5 per project
|
|
283
|
-
for (const row of allTagsResult[0].values) {
|
|
284
|
-
const projNum = row[0] as number
|
|
285
|
-
const tagEntry = { name: row[1] as string, count: row[2] as number }
|
|
286
|
-
const existing = projectTags[projNum] ?? []
|
|
287
|
-
if (existing.length < MAX_TAGS_PER_PROJECT) {
|
|
288
|
-
existing.push(tagEntry)
|
|
289
|
-
projectTags[projNum] = existing
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Find inactive projects (last entry > threshold days ago)
|
|
296
|
-
const cutoffDate = new Date(Date.now() - INACTIVE_THRESHOLD_DAYS * MS_PER_DAY)
|
|
297
|
-
.toISOString()
|
|
298
|
-
.split('T')[0]
|
|
299
|
-
const inactiveResult = db.executeRawQuery(
|
|
300
|
-
`
|
|
301
|
-
SELECT project_number, MAX(DATE(timestamp)) as last_entry_date
|
|
302
|
-
FROM memory_journal
|
|
303
|
-
WHERE deleted_at IS NULL AND project_number IS NOT NULL
|
|
304
|
-
GROUP BY project_number
|
|
305
|
-
HAVING last_entry_date < ?
|
|
306
|
-
`,
|
|
307
|
-
[cutoffDate]
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
const inactiveProjects =
|
|
311
|
-
inactiveResult[0]?.values.map((row: unknown[]) => ({
|
|
312
|
-
project_number: row[0] as number,
|
|
313
|
-
last_entry_date: row[1] as string,
|
|
314
|
-
})) ?? []
|
|
315
|
-
|
|
316
|
-
// Calculate time distribution
|
|
317
|
-
const totalEntries = projects.reduce(
|
|
318
|
-
(sum: number, p: Record<string, unknown>) =>
|
|
319
|
-
sum + (p['entry_count'] as number),
|
|
320
|
-
0
|
|
321
|
-
)
|
|
322
|
-
const distribution = projects.slice(0, 5).map((p: Record<string, unknown>) => ({
|
|
323
|
-
project_number: p['project_number'] as number,
|
|
324
|
-
percentage: (((p['entry_count'] as number) / totalEntries) * 100).toFixed(
|
|
325
|
-
1
|
|
326
|
-
),
|
|
327
|
-
}))
|
|
328
|
-
|
|
329
|
-
return {
|
|
330
|
-
project_count: projects.length,
|
|
331
|
-
total_entries: totalEntries,
|
|
332
|
-
projects: projects.map((p) => ({
|
|
333
|
-
...p,
|
|
334
|
-
top_tags: projectTags[p['project_number'] as number] ?? [],
|
|
335
|
-
})),
|
|
336
|
-
inactive_projects: inactiveProjects,
|
|
337
|
-
inactiveThresholdDays: INACTIVE_THRESHOLD_DAYS,
|
|
338
|
-
time_distribution: distribution,
|
|
339
|
-
}
|
|
340
|
-
} catch (err) {
|
|
341
|
-
return formatHandlerError(err)
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
]
|
|
346
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backup Tool Group - 4 tools
|
|
3
|
-
*
|
|
4
|
-
* Tools: backup_journal, list_backups, restore_backup, cleanup_backups
|
|
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 { sendProgress } from '../../utils/progress-utils.js'
|
|
11
|
-
import { relaxedNumber } from './schemas.js'
|
|
12
|
-
import { ErrorFieldsMixin } from './error-fields-mixin.js'
|
|
13
|
-
import { logger } from '../../utils/logger.js'
|
|
14
|
-
|
|
15
|
-
// ============================================================================
|
|
16
|
-
// Output Schemas
|
|
17
|
-
// ============================================================================
|
|
18
|
-
|
|
19
|
-
const BackupResultOutputSchema = z
|
|
20
|
-
.object({
|
|
21
|
-
success: z.boolean(),
|
|
22
|
-
message: z.string().optional(),
|
|
23
|
-
filename: z.string().optional(),
|
|
24
|
-
path: z.string().optional(),
|
|
25
|
-
sizeBytes: z.number().optional(),
|
|
26
|
-
error: z.string().optional(),
|
|
27
|
-
})
|
|
28
|
-
.extend(ErrorFieldsMixin.shape)
|
|
29
|
-
|
|
30
|
-
const BackupInfoSchema = z.object({
|
|
31
|
-
filename: z.string(),
|
|
32
|
-
path: z.string(),
|
|
33
|
-
sizeBytes: z.number(),
|
|
34
|
-
createdAt: z.string(),
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const BackupsListOutputSchema = z
|
|
38
|
-
.object({
|
|
39
|
-
success: z.boolean().optional(),
|
|
40
|
-
backups: z.array(BackupInfoSchema).optional(),
|
|
41
|
-
total: z.number().optional(),
|
|
42
|
-
backupsDirectory: z.string().optional(),
|
|
43
|
-
hint: z.string().optional(),
|
|
44
|
-
error: z.string().optional(),
|
|
45
|
-
})
|
|
46
|
-
.extend(ErrorFieldsMixin.shape)
|
|
47
|
-
|
|
48
|
-
const RestoreResultOutputSchema = z
|
|
49
|
-
.object({
|
|
50
|
-
success: z.boolean(),
|
|
51
|
-
message: z.string().optional(),
|
|
52
|
-
restoredFrom: z.string().optional(),
|
|
53
|
-
previousEntryCount: z.number().optional(),
|
|
54
|
-
newEntryCount: z.number().optional(),
|
|
55
|
-
warning: z.string().optional(),
|
|
56
|
-
revertedChanges: z
|
|
57
|
-
.object({
|
|
58
|
-
tagMerges: z.string().optional(),
|
|
59
|
-
entries: z.string().optional(),
|
|
60
|
-
})
|
|
61
|
-
.optional(),
|
|
62
|
-
error: z.string().optional(),
|
|
63
|
-
})
|
|
64
|
-
.extend(ErrorFieldsMixin.shape)
|
|
65
|
-
|
|
66
|
-
const CleanupBackupsOutputSchema = z
|
|
67
|
-
.object({
|
|
68
|
-
success: z.boolean(),
|
|
69
|
-
deleted: z.array(z.string()).optional(),
|
|
70
|
-
deletedCount: z.number().optional(),
|
|
71
|
-
keptCount: z.number().optional(),
|
|
72
|
-
message: z.string().optional(),
|
|
73
|
-
error: z.string().optional(),
|
|
74
|
-
})
|
|
75
|
-
.extend(ErrorFieldsMixin.shape)
|
|
76
|
-
|
|
77
|
-
// ============================================================================
|
|
78
|
-
// Tool Definitions
|
|
79
|
-
// ============================================================================
|
|
80
|
-
|
|
81
|
-
export function getBackupTools(context: ToolContext): ToolDefinition[] {
|
|
82
|
-
const { db, progress } = context
|
|
83
|
-
return [
|
|
84
|
-
{
|
|
85
|
-
name: 'backup_journal',
|
|
86
|
-
title: 'Backup Journal Database',
|
|
87
|
-
description:
|
|
88
|
-
'Create a timestamped backup of the journal database. Backups are stored in the backups/ directory.',
|
|
89
|
-
group: 'backup',
|
|
90
|
-
inputSchema: z.object({
|
|
91
|
-
name: z
|
|
92
|
-
.string()
|
|
93
|
-
.optional()
|
|
94
|
-
.describe('Custom backup name (optional, defaults to timestamp)'),
|
|
95
|
-
}),
|
|
96
|
-
outputSchema: BackupResultOutputSchema,
|
|
97
|
-
annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },
|
|
98
|
-
handler: async (params: unknown) => {
|
|
99
|
-
try {
|
|
100
|
-
const input = z
|
|
101
|
-
.object({
|
|
102
|
-
name: z.string().optional(),
|
|
103
|
-
})
|
|
104
|
-
.parse(params)
|
|
105
|
-
const result = await db.exportToFile(input.name)
|
|
106
|
-
return {
|
|
107
|
-
success: true,
|
|
108
|
-
message: `Backup created successfully`,
|
|
109
|
-
filename: result.filename,
|
|
110
|
-
path: result.path,
|
|
111
|
-
sizeBytes: result.sizeBytes,
|
|
112
|
-
}
|
|
113
|
-
} catch (err) {
|
|
114
|
-
return formatHandlerError(err)
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
name: 'list_backups',
|
|
120
|
-
title: 'List Journal Backups',
|
|
121
|
-
description: 'List all available backup files with their sizes and creation dates',
|
|
122
|
-
group: 'backup',
|
|
123
|
-
inputSchema: z.object({}).strict(),
|
|
124
|
-
outputSchema: BackupsListOutputSchema,
|
|
125
|
-
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
126
|
-
handler: (_params: unknown) => {
|
|
127
|
-
try {
|
|
128
|
-
const backups = db.listBackups()
|
|
129
|
-
return {
|
|
130
|
-
backups,
|
|
131
|
-
total: backups.length,
|
|
132
|
-
backupsDirectory: db.getBackupsDir(),
|
|
133
|
-
hint:
|
|
134
|
-
backups.length === 0
|
|
135
|
-
? 'No backups found. Use backup_journal to create one.'
|
|
136
|
-
: undefined,
|
|
137
|
-
}
|
|
138
|
-
} catch (err) {
|
|
139
|
-
return formatHandlerError(err)
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
name: 'restore_backup',
|
|
145
|
-
title: 'Restore Journal from Backup',
|
|
146
|
-
description:
|
|
147
|
-
'Restore the journal database from a backup file. WARNING: This replaces all current data. An automatic backup is created before restore.',
|
|
148
|
-
group: 'backup',
|
|
149
|
-
inputSchema: z.object({
|
|
150
|
-
filename: z
|
|
151
|
-
.string()
|
|
152
|
-
.describe('Backup filename to restore from (e.g., backup_2025-01-01.db)'),
|
|
153
|
-
confirm: z
|
|
154
|
-
.boolean()
|
|
155
|
-
.describe('Must be set to true to confirm the restore operation'),
|
|
156
|
-
}),
|
|
157
|
-
outputSchema: RestoreResultOutputSchema,
|
|
158
|
-
annotations: {
|
|
159
|
-
readOnlyHint: false,
|
|
160
|
-
idempotentHint: false,
|
|
161
|
-
destructiveHint: true,
|
|
162
|
-
openWorldHint: false,
|
|
163
|
-
},
|
|
164
|
-
handler: async (params: unknown) => {
|
|
165
|
-
try {
|
|
166
|
-
const input = z
|
|
167
|
-
.object({
|
|
168
|
-
filename: z.string(),
|
|
169
|
-
confirm: z.boolean(),
|
|
170
|
-
})
|
|
171
|
-
.parse(params)
|
|
172
|
-
|
|
173
|
-
if (!input.confirm) {
|
|
174
|
-
return {
|
|
175
|
-
success: false,
|
|
176
|
-
error: 'Restore requires confirm: true. This operation replaces all current data.',
|
|
177
|
-
code: 'VALIDATION_ERROR',
|
|
178
|
-
category: 'validation',
|
|
179
|
-
suggestion: 'Set confirm: true to proceed with restore',
|
|
180
|
-
recoverable: false,
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Capture progress context values BEFORE any async operations
|
|
185
|
-
const progressServer = progress?.server
|
|
186
|
-
const progressTokenValue = progress?.progressToken
|
|
187
|
-
|
|
188
|
-
await sendProgress(progress, 1, 3, 'Preparing restore...')
|
|
189
|
-
await sendProgress(progress, 2, 3, 'Restoring database from backup...')
|
|
190
|
-
const result = await db.restoreFromFile(input.filename)
|
|
191
|
-
|
|
192
|
-
// Send directly using captured primitives (db.restoreFromFile reinitializes DB)
|
|
193
|
-
if (progressServer !== undefined && progressTokenValue !== undefined) {
|
|
194
|
-
try {
|
|
195
|
-
await progressServer.notification({
|
|
196
|
-
method: 'notifications/progress' as const,
|
|
197
|
-
params: {
|
|
198
|
-
progressToken: progressTokenValue,
|
|
199
|
-
progress: 3,
|
|
200
|
-
total: 3,
|
|
201
|
-
message: 'Restore complete',
|
|
202
|
-
},
|
|
203
|
-
})
|
|
204
|
-
} catch (error) {
|
|
205
|
-
logger.debug('Failed to send restore progress notification', {
|
|
206
|
-
module: 'TOOL',
|
|
207
|
-
operation: 'restore-backup',
|
|
208
|
-
error,
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
success: true,
|
|
215
|
-
message: `Database restored from ${input.filename}`,
|
|
216
|
-
restoredFrom: result.restoredFrom,
|
|
217
|
-
previousEntryCount: result.previousEntryCount,
|
|
218
|
-
newEntryCount: result.newEntryCount,
|
|
219
|
-
warning:
|
|
220
|
-
'A pre-restore backup was automatically created. Any changes made since this backup (including tag merges, new entries, and relationships) have been reverted.',
|
|
221
|
-
revertedChanges: {
|
|
222
|
-
tagMerges:
|
|
223
|
-
'Any merge_tags operations since this backup are reverted. Previously merged tags will reappear as separate tags.',
|
|
224
|
-
entries:
|
|
225
|
-
result.previousEntryCount !== result.newEntryCount
|
|
226
|
-
? `Entry count changed from ${String(result.previousEntryCount)} to ${String(result.newEntryCount)}`
|
|
227
|
-
: undefined,
|
|
228
|
-
},
|
|
229
|
-
}
|
|
230
|
-
} catch (err) {
|
|
231
|
-
return formatHandlerError(err)
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
name: 'cleanup_backups',
|
|
237
|
-
title: 'Cleanup Old Backups',
|
|
238
|
-
description:
|
|
239
|
-
'Delete old backup files, keeping only the most recent N backups. Use list_backups to preview before cleanup.',
|
|
240
|
-
group: 'backup',
|
|
241
|
-
inputSchema: z.object({
|
|
242
|
-
keep_count: relaxedNumber()
|
|
243
|
-
.default(5)
|
|
244
|
-
.describe('Number of most recent backups to keep (default: 5)'),
|
|
245
|
-
}),
|
|
246
|
-
outputSchema: CleanupBackupsOutputSchema,
|
|
247
|
-
annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },
|
|
248
|
-
handler: (params: unknown) => {
|
|
249
|
-
try {
|
|
250
|
-
const { keep_count } = z
|
|
251
|
-
.object({ keep_count: z.number().min(1).default(5) })
|
|
252
|
-
.parse(params)
|
|
253
|
-
|
|
254
|
-
const result = db.deleteOldBackups(keep_count)
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
success: true,
|
|
258
|
-
deleted: result.deleted,
|
|
259
|
-
deletedCount: result.deleted.length,
|
|
260
|
-
keptCount: result.kept,
|
|
261
|
-
message:
|
|
262
|
-
result.deleted.length > 0
|
|
263
|
-
? `Deleted ${String(result.deleted.length)} old backup(s), kept ${String(result.kept)}`
|
|
264
|
-
: `No backups to delete. Currently have ${String(result.kept)} backup(s).`,
|
|
265
|
-
}
|
|
266
|
-
} catch (err) {
|
|
267
|
-
return formatHandlerError(err)
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
]
|
|
272
|
-
}
|