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,390 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* memory-journal-mcp — Token Validator, Search, Statistics, Importance Branch Coverage
|
|
3
|
-
*
|
|
4
|
-
* Targets uncovered branches in:
|
|
5
|
-
* - token-validator.ts (71.05%): JWKS cache hit, invalid issuer URL, error dispatch
|
|
6
|
-
* - search.ts entries (79.24%): searchByDateRange filter combos (isPersonal, project, issue, pr, workflowRunId)
|
|
7
|
-
* - statistics.ts (81.08%): date-filtered path, projectBreakdown, growthPercent null
|
|
8
|
-
* - importance.ts (75%): null rel_count/causal_count
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
12
|
-
import Database from 'better-sqlite3'
|
|
13
|
-
|
|
14
|
-
vi.mock('../../src/utils/logger.js', () => ({
|
|
15
|
-
logger: { info: vi.fn(), warning: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
16
|
-
}))
|
|
17
|
-
|
|
18
|
-
import { TokenValidator, createTokenValidator } from '../../src/auth/token-validator.js'
|
|
19
|
-
import { AUTH_ERROR_CODES } from '../../src/auth/errors.js'
|
|
20
|
-
import { searchByDateRange } from '../../src/database/sqlite-adapter/entries/search.js'
|
|
21
|
-
import { getStatistics } from '../../src/database/sqlite-adapter/entries/statistics.js'
|
|
22
|
-
import { calculateImportance } from '../../src/database/sqlite-adapter/entries/importance.js'
|
|
23
|
-
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Helpers — in-memory SQLite DB
|
|
26
|
-
// ============================================================================
|
|
27
|
-
|
|
28
|
-
function createTestDb() {
|
|
29
|
-
const db = new Database(':memory:')
|
|
30
|
-
db.exec(`
|
|
31
|
-
CREATE TABLE memory_journal (
|
|
32
|
-
id INTEGER PRIMARY KEY,
|
|
33
|
-
content TEXT NOT NULL,
|
|
34
|
-
entry_type TEXT DEFAULT 'personal_reflection',
|
|
35
|
-
timestamp TEXT NOT NULL,
|
|
36
|
-
is_personal INTEGER DEFAULT 1,
|
|
37
|
-
deleted_at TEXT DEFAULT NULL,
|
|
38
|
-
project_number INTEGER DEFAULT NULL,
|
|
39
|
-
issue_number INTEGER DEFAULT NULL,
|
|
40
|
-
pr_number INTEGER DEFAULT NULL,
|
|
41
|
-
issue_url TEXT DEFAULT NULL,
|
|
42
|
-
pr_url TEXT DEFAULT NULL,
|
|
43
|
-
pr_status TEXT DEFAULT NULL,
|
|
44
|
-
project_owner TEXT DEFAULT NULL,
|
|
45
|
-
workflow_run_id INTEGER DEFAULT NULL,
|
|
46
|
-
workflow_name TEXT DEFAULT NULL,
|
|
47
|
-
workflow_status TEXT DEFAULT NULL,
|
|
48
|
-
significance_type TEXT DEFAULT NULL,
|
|
49
|
-
auto_context TEXT DEFAULT NULL,
|
|
50
|
-
share_with_team INTEGER DEFAULT 0
|
|
51
|
-
);
|
|
52
|
-
CREATE TABLE tags (id INTEGER PRIMARY KEY, name TEXT UNIQUE, usage_count INTEGER DEFAULT 0);
|
|
53
|
-
CREATE TABLE entry_tags (entry_id INTEGER, tag_id INTEGER);
|
|
54
|
-
CREATE TABLE relationships (
|
|
55
|
-
id INTEGER PRIMARY KEY,
|
|
56
|
-
from_entry_id INTEGER,
|
|
57
|
-
to_entry_id INTEGER,
|
|
58
|
-
relationship_type TEXT,
|
|
59
|
-
description TEXT DEFAULT NULL
|
|
60
|
-
);
|
|
61
|
-
CREATE VIRTUAL TABLE fts_content USING fts5(content, content_rowid='rowid');
|
|
62
|
-
`)
|
|
63
|
-
return db
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function createTagsMgr() {
|
|
67
|
-
return {
|
|
68
|
-
batchGetTagsForEntries: vi.fn().mockReturnValue(new Map()),
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// ============================================================================
|
|
73
|
-
// TokenValidator Branch Coverage
|
|
74
|
-
// ============================================================================
|
|
75
|
-
|
|
76
|
-
describe('TokenValidator — branch coverage', () => {
|
|
77
|
-
it('should handle invalid issuer URL gracefully in constructor', () => {
|
|
78
|
-
const validator = new TokenValidator({
|
|
79
|
-
jwksUri: 'https://example.com/.well-known/jwks.json',
|
|
80
|
-
issuer: 'not-a-url',
|
|
81
|
-
audience: 'test',
|
|
82
|
-
})
|
|
83
|
-
expect(validator).toBeDefined()
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('should use cached JWKS on second call', () => {
|
|
87
|
-
const validator = new TokenValidator({
|
|
88
|
-
jwksUri: 'https://example.com/.well-known/jwks.json',
|
|
89
|
-
issuer: 'https://example.com',
|
|
90
|
-
audience: 'test',
|
|
91
|
-
})
|
|
92
|
-
// First call creates JWKS
|
|
93
|
-
validator.refreshJwks()
|
|
94
|
-
// Second call triggers cache hit branch because jwksExpiry is in the future
|
|
95
|
-
// We verify no error is thrown
|
|
96
|
-
expect(validator).toBeDefined()
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should clear cache', () => {
|
|
100
|
-
const validator = new TokenValidator({
|
|
101
|
-
jwksUri: 'https://example.com/.well-known/jwks.json',
|
|
102
|
-
issuer: 'https://example.com',
|
|
103
|
-
audience: 'test',
|
|
104
|
-
})
|
|
105
|
-
validator.clearCache()
|
|
106
|
-
expect(validator).toBeDefined()
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('should handle invalid JWKS URI gracefully', () => {
|
|
110
|
-
const validator = new TokenValidator({
|
|
111
|
-
jwksUri: 'not-a-url',
|
|
112
|
-
issuer: 'https://example.com',
|
|
113
|
-
audience: 'test',
|
|
114
|
-
})
|
|
115
|
-
// getJwks internally — URL constructor may throw for invalid jwksUri
|
|
116
|
-
expect(() => validator.refreshJwks()).toThrow()
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
describe('handleValidationError dispatch', () => {
|
|
120
|
-
let validator: TokenValidator
|
|
121
|
-
|
|
122
|
-
beforeEach(() => {
|
|
123
|
-
validator = new TokenValidator({
|
|
124
|
-
jwksUri: 'https://example.com/.well-known/jwks.json',
|
|
125
|
-
issuer: 'https://example.com',
|
|
126
|
-
audience: 'test',
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('should handle JWTExpired', async () => {
|
|
131
|
-
// Access private handleValidationError via validate path
|
|
132
|
-
const result = await validator.validate('invalid.token.here')
|
|
133
|
-
expect(result.valid).toBe(false)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('should return expired error via toOAuthError', () => {
|
|
137
|
-
const result = TokenValidator.toOAuthError({
|
|
138
|
-
valid: false,
|
|
139
|
-
error: 'expired',
|
|
140
|
-
errorCode: AUTH_ERROR_CODES.TOKEN_EXPIRED,
|
|
141
|
-
})
|
|
142
|
-
expect(result.code).toBe(AUTH_ERROR_CODES.TOKEN_EXPIRED)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('should return signature error via toOAuthError', () => {
|
|
146
|
-
const result = TokenValidator.toOAuthError({
|
|
147
|
-
valid: false,
|
|
148
|
-
error: 'bad sig',
|
|
149
|
-
errorCode: AUTH_ERROR_CODES.SIGNATURE_INVALID,
|
|
150
|
-
})
|
|
151
|
-
expect(result.code).toBe(AUTH_ERROR_CODES.SIGNATURE_INVALID)
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('should return generic invalid token via toOAuthError', () => {
|
|
155
|
-
const result = TokenValidator.toOAuthError({
|
|
156
|
-
valid: false,
|
|
157
|
-
error: 'some error',
|
|
158
|
-
errorCode: AUTH_ERROR_CODES.TOKEN_INVALID,
|
|
159
|
-
})
|
|
160
|
-
expect(result.code).toBe(AUTH_ERROR_CODES.TOKEN_INVALID)
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
it('createTokenValidator factory function', () => {
|
|
165
|
-
const validator = createTokenValidator({
|
|
166
|
-
jwksUri: 'https://example.com/.well-known/jwks.json',
|
|
167
|
-
issuer: 'https://example.com',
|
|
168
|
-
audience: 'test',
|
|
169
|
-
})
|
|
170
|
-
expect(validator).toBeInstanceOf(TokenValidator)
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// ============================================================================
|
|
175
|
-
// searchByDateRange Branch Coverage — filter combinations
|
|
176
|
-
// ============================================================================
|
|
177
|
-
|
|
178
|
-
describe('searchByDateRange — filter combinations', () => {
|
|
179
|
-
let db: InstanceType<typeof Database>
|
|
180
|
-
let context: { db: ReturnType<typeof Database>; tagsMgr: ReturnType<typeof createTagsMgr> }
|
|
181
|
-
|
|
182
|
-
beforeEach(() => {
|
|
183
|
-
db = createTestDb()
|
|
184
|
-
db.exec(`
|
|
185
|
-
INSERT INTO memory_journal (id, content, timestamp, is_personal, project_number, issue_number, pr_number, workflow_run_id, entry_type)
|
|
186
|
-
VALUES
|
|
187
|
-
(1, 'entry one', '2025-01-15T10:00:00Z', 1, 42, 10, 20, 100, 'personal_reflection'),
|
|
188
|
-
(2, 'entry two', '2025-01-20T10:00:00Z', 0, 42, 11, null, null, 'decision'),
|
|
189
|
-
(3, 'entry three', '2025-02-01T10:00:00Z', 1, null, null, null, null, 'personal_reflection');
|
|
190
|
-
INSERT INTO tags (id, name, usage_count) VALUES (1, 'test-tag', 1);
|
|
191
|
-
INSERT INTO entry_tags (entry_id, tag_id) VALUES (1, 1);
|
|
192
|
-
INSERT INTO fts_content (rowid, content) VALUES (1, 'entry one'), (2, 'entry two'), (3, 'entry three');
|
|
193
|
-
`)
|
|
194
|
-
context = { db, tagsMgr: createTagsMgr() }
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
it('should filter by date range only', () => {
|
|
198
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-01-31')
|
|
199
|
-
expect(result.length).toBe(2)
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
it('should filter by isPersonal', () => {
|
|
203
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', { isPersonal: true })
|
|
204
|
-
expect(result.every((e) => e.isPersonal === true)).toBe(true)
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
it('should filter by projectNumber', () => {
|
|
208
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', { projectNumber: 42 })
|
|
209
|
-
expect(result.length).toBe(2)
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('should filter by issueNumber', () => {
|
|
213
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', { issueNumber: 10 })
|
|
214
|
-
expect(result.length).toBe(1)
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
it('should filter by prNumber', () => {
|
|
218
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', { prNumber: 20 })
|
|
219
|
-
expect(result.length).toBe(1)
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('should filter by workflowRunId', () => {
|
|
223
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', {
|
|
224
|
-
workflowRunId: 100,
|
|
225
|
-
})
|
|
226
|
-
expect(result.length).toBe(1)
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
it('should filter by entryType', () => {
|
|
230
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', {
|
|
231
|
-
entryType: 'decision',
|
|
232
|
-
})
|
|
233
|
-
expect(result.length).toBe(1)
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
it('should filter by tags', () => {
|
|
237
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', {
|
|
238
|
-
tags: ['test-tag'],
|
|
239
|
-
})
|
|
240
|
-
expect(result.length).toBe(1)
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
it('should handle startDate without T (appends time)', () => {
|
|
244
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-01-31')
|
|
245
|
-
expect(result.length).toBeGreaterThanOrEqual(0)
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
it('should handle endDate without T (appends time)', () => {
|
|
249
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-01-31')
|
|
250
|
-
expect(result.length).toBeGreaterThanOrEqual(0)
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('should combine multiple filters', () => {
|
|
254
|
-
const result = searchByDateRange(context, '2025-01-01', '2025-12-31', {
|
|
255
|
-
isPersonal: true,
|
|
256
|
-
projectNumber: 42,
|
|
257
|
-
issueNumber: 10,
|
|
258
|
-
prNumber: 20,
|
|
259
|
-
workflowRunId: 100,
|
|
260
|
-
})
|
|
261
|
-
expect(result.length).toBe(1)
|
|
262
|
-
})
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
// ============================================================================
|
|
266
|
-
// getStatistics Branch Coverage
|
|
267
|
-
// ============================================================================
|
|
268
|
-
|
|
269
|
-
describe('getStatistics — branch coverage', () => {
|
|
270
|
-
let db: InstanceType<typeof Database>
|
|
271
|
-
let context: { db: ReturnType<typeof Database>; tagsMgr: ReturnType<typeof createTagsMgr> }
|
|
272
|
-
|
|
273
|
-
beforeEach(() => {
|
|
274
|
-
db = createTestDb()
|
|
275
|
-
db.exec(`
|
|
276
|
-
INSERT INTO memory_journal (id, content, timestamp, project_number, significance_type) VALUES
|
|
277
|
-
(1, 'entry 1', '2025-01-15T10:00:00Z', 42, 'decision'),
|
|
278
|
-
(2, 'entry 2', '2025-01-20T10:00:00Z', 42, null),
|
|
279
|
-
(3, 'entry 3', '2025-02-01T10:00:00Z', null, null);
|
|
280
|
-
INSERT INTO relationships (from_entry_id, to_entry_id, relationship_type) VALUES
|
|
281
|
-
(1, 2, 'resolved'),
|
|
282
|
-
(1, 3, 'references');
|
|
283
|
-
`)
|
|
284
|
-
context = { db, tagsMgr: createTagsMgr() }
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
it('should compute stats without date filters (else branch)', () => {
|
|
288
|
-
const result = getStatistics(context)
|
|
289
|
-
expect(result.totalEntries).toBe(3)
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
it('should compute stats with startDate filter', () => {
|
|
293
|
-
const result = getStatistics(context, 'week', '2025-01-18')
|
|
294
|
-
expect(result.totalEntries as number).toBe(2)
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
it('should compute stats with both date filters', () => {
|
|
298
|
-
const result = getStatistics(context, 'week', '2025-01-01', '2025-01-31')
|
|
299
|
-
expect(result.totalEntries as number).toBe(2)
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
it('should include projectBreakdown when requested', () => {
|
|
303
|
-
const result = getStatistics(context, 'week', undefined, undefined, true)
|
|
304
|
-
expect(result.projectBreakdown).toBeDefined()
|
|
305
|
-
const breakdown = result.projectBreakdown as {
|
|
306
|
-
project_number: number
|
|
307
|
-
entry_count: number
|
|
308
|
-
}[]
|
|
309
|
-
expect(breakdown.length).toBe(1)
|
|
310
|
-
expect(breakdown[0]!.project_number).toBe(42)
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
it('should compute growthPercent as null when previousCount is 0', () => {
|
|
314
|
-
// With only one entry, the second period will be empty
|
|
315
|
-
db.exec('DELETE FROM memory_journal WHERE id > 1')
|
|
316
|
-
const result = getStatistics(context)
|
|
317
|
-
const trend = result.activityTrend as { growthPercent: number | null }
|
|
318
|
-
expect(trend.growthPercent).toBeNull()
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
it('should use year groupBy (maps to month format)', () => {
|
|
322
|
-
const result = getStatistics(context, 'year')
|
|
323
|
-
expect(result.totalEntries).toBe(3)
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
it('should include causalMetrics', () => {
|
|
327
|
-
const result = getStatistics(context)
|
|
328
|
-
const causal = result.causalMetrics as Record<string, number>
|
|
329
|
-
expect(causal.resolved).toBe(1)
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
it('should include dateRange when date filters provided', () => {
|
|
333
|
-
const result = getStatistics(context, 'week', '2025-01-01', '2025-12-31')
|
|
334
|
-
expect(result.dateRange).toBeDefined()
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
it('should not include dateRange when no date filters', () => {
|
|
338
|
-
const result = getStatistics(context)
|
|
339
|
-
expect(result.dateRange).toBeUndefined()
|
|
340
|
-
})
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
// ============================================================================
|
|
344
|
-
// calculateImportance Branch Coverage
|
|
345
|
-
// ============================================================================
|
|
346
|
-
|
|
347
|
-
describe('calculateImportance — branch coverage', () => {
|
|
348
|
-
let db: InstanceType<typeof Database>
|
|
349
|
-
let context: { db: ReturnType<typeof Database>; tagsMgr: ReturnType<typeof createTagsMgr> }
|
|
350
|
-
|
|
351
|
-
beforeEach(() => {
|
|
352
|
-
db = createTestDb()
|
|
353
|
-
context = { db, tagsMgr: createTagsMgr() }
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
it('should return 0 score for non-existent entry', () => {
|
|
357
|
-
const result = calculateImportance(context, 999)
|
|
358
|
-
expect(result.score).toBe(0)
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
it('should compute importance for entry with significance and relationships', () => {
|
|
362
|
-
db.exec(`
|
|
363
|
-
INSERT INTO memory_journal (id, content, timestamp, significance_type) VALUES (1, 'test', '${new Date().toISOString()}', 'decision');
|
|
364
|
-
INSERT INTO relationships (from_entry_id, to_entry_id, relationship_type) VALUES (1, 2, 'references'), (1, 3, 'caused');
|
|
365
|
-
`)
|
|
366
|
-
const result = calculateImportance(context, 1)
|
|
367
|
-
expect(result.score).toBeGreaterThan(0)
|
|
368
|
-
expect(result.breakdown.significance).toBeGreaterThan(0)
|
|
369
|
-
expect(result.breakdown.relationships).toBeGreaterThan(0)
|
|
370
|
-
expect(result.breakdown.causal).toBeGreaterThan(0)
|
|
371
|
-
expect(result.breakdown.recency).toBeGreaterThan(0)
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
it('should compute importance with no significance type', () => {
|
|
375
|
-
db.exec(
|
|
376
|
-
`INSERT INTO memory_journal (id, content, timestamp) VALUES (1, 'test', '${new Date().toISOString()}')`
|
|
377
|
-
)
|
|
378
|
-
const result = calculateImportance(context, 1)
|
|
379
|
-
expect(result.breakdown.significance).toBe(0)
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
it('should decay recency for old entries', () => {
|
|
383
|
-
const oldDate = new Date(Date.now() - 100 * 24 * 60 * 60 * 1000).toISOString()
|
|
384
|
-
db.exec(
|
|
385
|
-
`INSERT INTO memory_journal (id, content, timestamp) VALUES (1, 'old entry', '${oldDate}')`
|
|
386
|
-
)
|
|
387
|
-
const result = calculateImportance(context, 1)
|
|
388
|
-
expect(result.breakdown.recency).toBe(0)
|
|
389
|
-
})
|
|
390
|
-
})
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NativeConnectionManager Unit Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for init failure, migration, FTS rebuild,
|
|
5
|
-
* and close-during-initialization branches.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, it, expect, afterAll } from 'vitest'
|
|
9
|
-
import type Database from 'better-sqlite3'
|
|
10
|
-
import fs from 'node:fs'
|
|
11
|
-
import { NativeConnectionManager } from '../../src/database/sqlite-adapter/native-connection.js'
|
|
12
|
-
|
|
13
|
-
const TEST_DB_PATH = './test-native-conn.db'
|
|
14
|
-
const TEST_DB_PATH_2 = './test-native-conn-2.db'
|
|
15
|
-
const TEST_DB_NESTED = './test-native-nested/subdir/test.db'
|
|
16
|
-
|
|
17
|
-
function cleanupFiles(...paths: string[]) {
|
|
18
|
-
for (const p of paths) {
|
|
19
|
-
try {
|
|
20
|
-
if (fs.existsSync(p)) fs.unlinkSync(p)
|
|
21
|
-
} catch {
|
|
22
|
-
// ignore
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function cleanupDirs(...paths: string[]) {
|
|
28
|
-
for (const p of paths) {
|
|
29
|
-
try {
|
|
30
|
-
if (fs.existsSync(p)) fs.rmSync(p, { recursive: true })
|
|
31
|
-
} catch {
|
|
32
|
-
// ignore
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
afterAll(() => {
|
|
38
|
-
cleanupFiles(TEST_DB_PATH, TEST_DB_PATH_2)
|
|
39
|
-
cleanupDirs('./test-native-nested')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
describe('NativeConnectionManager', () => {
|
|
43
|
-
// =========================================================================
|
|
44
|
-
// Basic initialization
|
|
45
|
-
// =========================================================================
|
|
46
|
-
|
|
47
|
-
describe('initialize', () => {
|
|
48
|
-
it('should initialize successfully and return a valid DB', async () => {
|
|
49
|
-
const mgr = new NativeConnectionManager(TEST_DB_PATH)
|
|
50
|
-
await mgr.initialize()
|
|
51
|
-
|
|
52
|
-
const db = mgr.getRawDb() as Database
|
|
53
|
-
expect(db).toBeDefined()
|
|
54
|
-
|
|
55
|
-
// DB should be usable
|
|
56
|
-
const result = db.prepare('SELECT 1 as n').get() as { n: number }
|
|
57
|
-
expect(result.n).toBe(1)
|
|
58
|
-
|
|
59
|
-
mgr.close()
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('should be idempotent (double init)', async () => {
|
|
63
|
-
const mgr = new NativeConnectionManager(TEST_DB_PATH_2)
|
|
64
|
-
await mgr.initialize()
|
|
65
|
-
await mgr.initialize() // should not throw
|
|
66
|
-
|
|
67
|
-
const db = mgr.getRawDb() as Database
|
|
68
|
-
expect(db).toBeDefined()
|
|
69
|
-
mgr.close()
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('should create parent directories if they do not exist', async () => {
|
|
73
|
-
cleanupDirs('./test-native-nested')
|
|
74
|
-
const mgr = new NativeConnectionManager(TEST_DB_NESTED)
|
|
75
|
-
await mgr.initialize()
|
|
76
|
-
|
|
77
|
-
expect(fs.existsSync(TEST_DB_NESTED)).toBe(true)
|
|
78
|
-
mgr.close()
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('should handle and wrap initialization errors', async () => {
|
|
82
|
-
const mkdirSpy = vi
|
|
83
|
-
.spyOn(fs.promises, 'mkdir')
|
|
84
|
-
.mockRejectedValueOnce(new Error('Permission denied'))
|
|
85
|
-
|
|
86
|
-
cleanupDirs('./test-native-nested-error')
|
|
87
|
-
const mgr = new NativeConnectionManager('./test-native-nested-error/db.sqlite')
|
|
88
|
-
|
|
89
|
-
await expect(mgr.initialize()).rejects.toThrow('Permission denied')
|
|
90
|
-
|
|
91
|
-
mkdirSpy.mockRestore()
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
// =========================================================================
|
|
96
|
-
// ensureDb guard
|
|
97
|
-
// =========================================================================
|
|
98
|
-
|
|
99
|
-
describe('ensureDb', () => {
|
|
100
|
-
it('should throw ConnectionError when DB is not initialized', () => {
|
|
101
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
102
|
-
expect(() => mgr.getRawDb()).toThrow()
|
|
103
|
-
})
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
// =========================================================================
|
|
107
|
-
// Close behavior
|
|
108
|
-
// =========================================================================
|
|
109
|
-
|
|
110
|
-
describe('close', () => {
|
|
111
|
-
it('should safely close and nullify DB', async () => {
|
|
112
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
113
|
-
await mgr.initialize()
|
|
114
|
-
mgr.close()
|
|
115
|
-
|
|
116
|
-
// getRawDb should throw after close
|
|
117
|
-
expect(() => mgr.getRawDb()).toThrow()
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('should be safe to call close() multiple times', async () => {
|
|
121
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
122
|
-
await mgr.initialize()
|
|
123
|
-
mgr.close()
|
|
124
|
-
mgr.close() // should not throw
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// =========================================================================
|
|
129
|
-
// Migration — column addition
|
|
130
|
-
// =========================================================================
|
|
131
|
-
|
|
132
|
-
describe('schema migration', () => {
|
|
133
|
-
it('should add missing columns on re-init of existing DB', async () => {
|
|
134
|
-
// First init creates full schema
|
|
135
|
-
const mgr = new NativeConnectionManager(TEST_DB_PATH)
|
|
136
|
-
await mgr.initialize()
|
|
137
|
-
|
|
138
|
-
const db = mgr.getRawDb() as Database
|
|
139
|
-
// Verify some migration columns exist
|
|
140
|
-
const info = db.prepare('PRAGMA table_info(memory_journal)').all() as { name: string }[]
|
|
141
|
-
const cols = info.map((r) => r.name)
|
|
142
|
-
|
|
143
|
-
expect(cols).toContain('issue_url')
|
|
144
|
-
expect(cols).toContain('pr_url')
|
|
145
|
-
expect(cols).toContain('workflow_run_id')
|
|
146
|
-
|
|
147
|
-
mgr.close()
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('should populate FTS5 on existing DBs missing FTS rows', async () => {
|
|
151
|
-
const mgr = new NativeConnectionManager(TEST_DB_PATH_2)
|
|
152
|
-
await mgr.initialize()
|
|
153
|
-
const db = mgr.getRawDb() as Database
|
|
154
|
-
db.exec("INSERT INTO memory_journal(content, entry_type) VALUES ('foo', 'test')")
|
|
155
|
-
// Wipe fts_content manually
|
|
156
|
-
db.exec('DELETE FROM fts_content')
|
|
157
|
-
mgr.close()
|
|
158
|
-
|
|
159
|
-
// Re-init should populate FTS
|
|
160
|
-
const mgr2 = new NativeConnectionManager(TEST_DB_PATH_2)
|
|
161
|
-
await mgr2.initialize()
|
|
162
|
-
mgr2.close()
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
it('should rebuild FTS5 index if ghost entries detected', async () => {
|
|
166
|
-
// First DB is initialized
|
|
167
|
-
const mgr = new NativeConnectionManager(TEST_DB_PATH)
|
|
168
|
-
await mgr.initialize()
|
|
169
|
-
const db = mgr.getRawDb() as Database
|
|
170
|
-
|
|
171
|
-
// FTS count is > 0, entryCount = 0 since we deleted memory_journal entries or made fts larger
|
|
172
|
-
db.exec("INSERT INTO memory_journal(content, entry_type) VALUES ('foo', 'test')")
|
|
173
|
-
db.exec("INSERT INTO memory_journal(content, entry_type) VALUES ('bar', 'test')")
|
|
174
|
-
db.exec("INSERT INTO memory_journal(content, entry_type) VALUES ('baz', 'test')")
|
|
175
|
-
// Drop delete trigger so deletion doesn't hit FTS
|
|
176
|
-
db.exec('DROP TRIGGER IF EXISTS memory_journal_ad')
|
|
177
|
-
db.exec('DELETE FROM memory_journal')
|
|
178
|
-
mgr.close()
|
|
179
|
-
|
|
180
|
-
// Re-init should trigger ghost cleanup because fts_count (3) > entry_count (0)
|
|
181
|
-
const mgr2 = new NativeConnectionManager(TEST_DB_PATH)
|
|
182
|
-
await mgr2.initialize()
|
|
183
|
-
mgr2.close()
|
|
184
|
-
})
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// =========================================================================
|
|
188
|
-
// Team schema
|
|
189
|
-
// =========================================================================
|
|
190
|
-
|
|
191
|
-
describe('applyTeamSchema', () => {
|
|
192
|
-
it('should add author column', async () => {
|
|
193
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
194
|
-
await mgr.initialize()
|
|
195
|
-
mgr.applyTeamSchema()
|
|
196
|
-
|
|
197
|
-
const db = mgr.getRawDb() as Database
|
|
198
|
-
const info = db.prepare('PRAGMA table_info(memory_journal)').all() as { name: string }[]
|
|
199
|
-
const cols = info.map((r) => r.name)
|
|
200
|
-
expect(cols).toContain('author')
|
|
201
|
-
|
|
202
|
-
mgr.close()
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should be idempotent (double apply)', async () => {
|
|
206
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
207
|
-
await mgr.initialize()
|
|
208
|
-
mgr.applyTeamSchema()
|
|
209
|
-
mgr.applyTeamSchema() // should not throw
|
|
210
|
-
|
|
211
|
-
mgr.close()
|
|
212
|
-
})
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
// =========================================================================
|
|
216
|
-
// executeRawQuery
|
|
217
|
-
// =========================================================================
|
|
218
|
-
|
|
219
|
-
describe('exec', () => {
|
|
220
|
-
it('should execute a raw query and return results', async () => {
|
|
221
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
222
|
-
await mgr.initialize()
|
|
223
|
-
|
|
224
|
-
const db = mgr.getRawDb() as Database
|
|
225
|
-
db.exec(
|
|
226
|
-
"INSERT INTO memory_journal (entry_type, content, timestamp, is_personal) VALUES ('test_entry', 'test content', datetime('now'), 1)"
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
const result = mgr.exec('SELECT COUNT(*) as c FROM memory_journal', [])
|
|
230
|
-
expect(result).toBeDefined()
|
|
231
|
-
expect(result.length).toBeGreaterThan(0)
|
|
232
|
-
|
|
233
|
-
mgr.close()
|
|
234
|
-
})
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
// =========================================================================
|
|
238
|
-
// pragma
|
|
239
|
-
// =========================================================================
|
|
240
|
-
|
|
241
|
-
describe('pragma', () => {
|
|
242
|
-
it('should execute pragma commands', async () => {
|
|
243
|
-
const mgr = new NativeConnectionManager(':memory:')
|
|
244
|
-
await mgr.initialize()
|
|
245
|
-
expect(() => mgr.pragma('cache_size = 2000')).not.toThrow()
|
|
246
|
-
mgr.close()
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
|
-
})
|