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,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Code Mode Readonly Enforcement
|
|
3
|
-
*
|
|
4
|
-
* Tests that mj_execute_code with readonly=true correctly
|
|
5
|
-
* returns structured errors for mutation attempts instead of
|
|
6
|
-
* TypeError or undefined behavior.
|
|
7
|
-
*
|
|
8
|
-
* Uses the standard E2E server (port 3100) with the built-in
|
|
9
|
-
* readonly parameter on mj_execute_code (not --tool-filter readonly
|
|
10
|
-
* which would exclude mj_execute_code entirely).
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { test, expect } from '@playwright/test'
|
|
14
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
15
|
-
import { createClient } from './helpers.js'
|
|
16
|
-
|
|
17
|
-
test.describe('Code Mode Readonly Enforcement', () => {
|
|
18
|
-
let client: Client
|
|
19
|
-
|
|
20
|
-
test.beforeAll(async () => {
|
|
21
|
-
client = await createClient()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test.afterAll(async () => {
|
|
25
|
-
await client.close()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('read operations succeed with readonly=true param', async () => {
|
|
29
|
-
const response = await client.callTool({
|
|
30
|
-
name: 'mj_execute_code',
|
|
31
|
-
arguments: {
|
|
32
|
-
code: `
|
|
33
|
-
const recent = await mj.core.getRecentEntries({ limit: 1 });
|
|
34
|
-
return recent;
|
|
35
|
-
`,
|
|
36
|
-
readonly: true,
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
41
|
-
const content = response.content as Array<{ type: string; text?: string }>
|
|
42
|
-
expect(content.length).toBeGreaterThan(0)
|
|
43
|
-
expect(content[0]!.type).toBe('text')
|
|
44
|
-
// Read should succeed — no error
|
|
45
|
-
const payload = JSON.parse(content[0]!.text!) as Record<string, unknown>
|
|
46
|
-
// Should have entries/count fields, not a structured error
|
|
47
|
-
expect(payload.success).not.toBe(false)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('mj.core.createEntry raises structured error via readonly=true param', async () => {
|
|
51
|
-
const response = await client.callTool({
|
|
52
|
-
name: 'mj_execute_code',
|
|
53
|
-
arguments: {
|
|
54
|
-
code: `
|
|
55
|
-
const result = await mj.core.createEntry({
|
|
56
|
-
content: 'Should not be created',
|
|
57
|
-
entry_type: 'test_entry',
|
|
58
|
-
});
|
|
59
|
-
return result;
|
|
60
|
-
`,
|
|
61
|
-
readonly: true,
|
|
62
|
-
},
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
66
|
-
const content = response.content as Array<{ type: string; text?: string }>
|
|
67
|
-
const payload = JSON.parse(content[0]!.text!) as Record<string, unknown>
|
|
68
|
-
|
|
69
|
-
// Should be a structured error, not a TypeError
|
|
70
|
-
expect(payload.success).toBe(false)
|
|
71
|
-
expect(typeof payload.error).toBe('string')
|
|
72
|
-
// Error message mentions either "not available", "not found in group", or "read-only"
|
|
73
|
-
expect((payload.error as string).toLowerCase()).toMatch(
|
|
74
|
-
/not available|not found in group|readonly|read.only/i
|
|
75
|
-
)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
test('mj.admin.deleteEntry raises structured error via readonly=true param', async () => {
|
|
79
|
-
const response = await client.callTool({
|
|
80
|
-
name: 'mj_execute_code',
|
|
81
|
-
arguments: {
|
|
82
|
-
code: `
|
|
83
|
-
const result = await mj.admin.deleteEntry({ entry_id: 1 });
|
|
84
|
-
return result;
|
|
85
|
-
`,
|
|
86
|
-
readonly: true,
|
|
87
|
-
},
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
91
|
-
const content = response.content as Array<{ type: string; text?: string }>
|
|
92
|
-
const payload = JSON.parse(content[0]!.text!) as Record<string, unknown>
|
|
93
|
-
|
|
94
|
-
expect(payload.success).toBe(false)
|
|
95
|
-
expect(typeof payload.error).toBe('string')
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test('mj.help() works correctly via readonly=true param', async () => {
|
|
99
|
-
const response = await client.callTool({
|
|
100
|
-
name: 'mj_execute_code',
|
|
101
|
-
arguments: {
|
|
102
|
-
code: `
|
|
103
|
-
const help = mj.help();
|
|
104
|
-
return help;
|
|
105
|
-
`,
|
|
106
|
-
readonly: true,
|
|
107
|
-
},
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
111
|
-
const content = response.content as Array<{ type: string; text?: string }>
|
|
112
|
-
expect(content.length).toBeGreaterThan(0)
|
|
113
|
-
// help() should return a string description or object
|
|
114
|
-
expect(content[0]!.text).toBeDefined()
|
|
115
|
-
})
|
|
116
|
-
})
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Code Mode
|
|
3
|
-
*
|
|
4
|
-
* Validates mj_execute_code (Code Mode) execution, multi-step workflows,
|
|
5
|
-
* security rejection, and timeout enforcement via E2E.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test, expect } from '@playwright/test'
|
|
9
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
10
|
-
import { createClient, callToolAndParse } from './helpers.js'
|
|
11
|
-
|
|
12
|
-
test.describe.configure({ mode: 'serial' })
|
|
13
|
-
|
|
14
|
-
test.describe('Payload Contracts: Code Mode', () => {
|
|
15
|
-
let client: Client
|
|
16
|
-
|
|
17
|
-
test.beforeAll(async () => {
|
|
18
|
-
client = await createClient()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterAll(async () => {
|
|
22
|
-
await client.close()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('should execute basic code via mj_execute_code', async () => {
|
|
26
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
27
|
-
code: `
|
|
28
|
-
const result = await mj.core.testSimple({ message: 'code-mode-e2e' });
|
|
29
|
-
return result;
|
|
30
|
-
`,
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
expect(typeof payload).toBe('object')
|
|
34
|
-
// The result should contain the test_simple response
|
|
35
|
-
expect(JSON.stringify(payload)).toContain('code-mode-e2e')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('should execute multi-step workflow in single execution', async () => {
|
|
39
|
-
const payload = await callToolAndParse(client, 'mj_execute_code', {
|
|
40
|
-
code: `
|
|
41
|
-
// Step 1: Create an entry
|
|
42
|
-
const created = await mj.core.createEntry({
|
|
43
|
-
content: 'Code mode multi-step test',
|
|
44
|
-
entry_type: 'test_entry',
|
|
45
|
-
tags: ['codemode-test'],
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Step 2: Retrieve recent entries
|
|
49
|
-
const recent = await mj.core.getRecentEntries({ limit: 1 });
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
created: created.success,
|
|
53
|
-
recentCount: recent.count,
|
|
54
|
-
};
|
|
55
|
-
`,
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
expect(typeof payload).toBe('object')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('should reject code with blocked patterns (require)', async () => {
|
|
62
|
-
const response = await client.callTool({
|
|
63
|
-
name: 'mj_execute_code',
|
|
64
|
-
arguments: {
|
|
65
|
-
code: `const fs = require('fs'); return fs.readFileSync('/etc/passwd');`,
|
|
66
|
-
},
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
expect(response.isError).toBeUndefined()
|
|
70
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
71
|
-
|
|
72
|
-
const text = (response.content[0] as { type: string; text: string }).text
|
|
73
|
-
const parsed = JSON.parse(text)
|
|
74
|
-
|
|
75
|
-
// Should return a structured error with security failure
|
|
76
|
-
expect(parsed.success).toBe(false)
|
|
77
|
-
expect(parsed.error).toBeDefined()
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test('should reject code with blocked patterns (process)', async () => {
|
|
81
|
-
const response = await client.callTool({
|
|
82
|
-
name: 'mj_execute_code',
|
|
83
|
-
arguments: {
|
|
84
|
-
code: `return process.env;`,
|
|
85
|
-
},
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
expect(response.isError).toBeUndefined()
|
|
89
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
90
|
-
|
|
91
|
-
const text = (response.content[0] as { type: string; text: string }).text
|
|
92
|
-
const parsed = JSON.parse(text)
|
|
93
|
-
|
|
94
|
-
expect(parsed.success).toBe(false)
|
|
95
|
-
expect(parsed.error).toBeDefined()
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test('should enforce execution timeout', async () => {
|
|
99
|
-
const response = await client.callTool({
|
|
100
|
-
name: 'mj_execute_code',
|
|
101
|
-
arguments: {
|
|
102
|
-
code: `while (true) {}`,
|
|
103
|
-
timeout: 1,
|
|
104
|
-
},
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
expect(response.isError).toBeUndefined()
|
|
108
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
109
|
-
|
|
110
|
-
const text = (response.content[0] as { type: string; text: string }).text
|
|
111
|
-
const parsed = JSON.parse(text)
|
|
112
|
-
|
|
113
|
-
// Should report timeout or execution failure
|
|
114
|
-
expect(parsed.success).toBe(false)
|
|
115
|
-
})
|
|
116
|
-
})
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Core
|
|
3
|
-
*
|
|
4
|
-
* Validates response shapes for 6 core tools:
|
|
5
|
-
* create_entry, get_recent_entries, get_entry_by_id,
|
|
6
|
-
* create_entry_minimal, test_simple, list_tags.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { test, expect } from '@playwright/test'
|
|
10
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
11
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
12
|
-
|
|
13
|
-
test.describe.configure({ mode: 'serial' })
|
|
14
|
-
|
|
15
|
-
test.describe('Payload Contracts: Core', () => {
|
|
16
|
-
let client: Client
|
|
17
|
-
let createdEntryId: number
|
|
18
|
-
|
|
19
|
-
test.beforeAll(async () => {
|
|
20
|
-
client = await createClient()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test.afterAll(async () => {
|
|
24
|
-
await client.close()
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('test_simple returns { message }', async () => {
|
|
28
|
-
const payload = await callToolAndParse(client, 'test_simple', {
|
|
29
|
-
message: 'payload test',
|
|
30
|
-
})
|
|
31
|
-
expect(typeof payload.message).toBe('string')
|
|
32
|
-
expect(payload.message).toContain('payload test')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('create_entry returns { success, entry }', async () => {
|
|
36
|
-
const payload = await callToolAndParse(client, 'create_entry', {
|
|
37
|
-
content: 'Payload contract test entry',
|
|
38
|
-
entry_type: 'test_entry',
|
|
39
|
-
tags: ['test', 'payload'],
|
|
40
|
-
})
|
|
41
|
-
expectSuccess(payload)
|
|
42
|
-
expect(payload.success).toBe(true)
|
|
43
|
-
expect(payload.entry).toBeDefined()
|
|
44
|
-
const entry = payload.entry as Record<string, unknown>
|
|
45
|
-
expect(typeof entry.id).toBe('number')
|
|
46
|
-
createdEntryId = entry.id as number
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('create_entry_minimal returns { success, entry }', async () => {
|
|
50
|
-
const payload = await callToolAndParse(client, 'create_entry_minimal', {
|
|
51
|
-
content: 'Minimal payload test',
|
|
52
|
-
})
|
|
53
|
-
expectSuccess(payload)
|
|
54
|
-
expect(payload.success).toBe(true)
|
|
55
|
-
expect(payload.entry).toBeDefined()
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('get_recent_entries returns { entries, count }', async () => {
|
|
59
|
-
const payload = await callToolAndParse(client, 'get_recent_entries', {
|
|
60
|
-
limit: 3,
|
|
61
|
-
})
|
|
62
|
-
expectSuccess(payload)
|
|
63
|
-
expect(Array.isArray(payload.entries)).toBe(true)
|
|
64
|
-
expect(typeof payload.count).toBe('number')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('get_entry_by_id returns { entry, importance }', async () => {
|
|
68
|
-
const payload = await callToolAndParse(client, 'get_entry_by_id', {
|
|
69
|
-
entry_id: createdEntryId,
|
|
70
|
-
})
|
|
71
|
-
expectSuccess(payload)
|
|
72
|
-
expect(payload.entry).toBeDefined()
|
|
73
|
-
expect(payload.importance).toBeDefined()
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('list_tags returns { tags, count }', async () => {
|
|
77
|
-
const payload = await callToolAndParse(client, 'list_tags', {})
|
|
78
|
-
expectSuccess(payload)
|
|
79
|
-
expect(Array.isArray(payload.tags)).toBe(true)
|
|
80
|
-
expect(typeof payload.count).toBe('number')
|
|
81
|
-
})
|
|
82
|
-
})
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Structured Error Field Contracts
|
|
3
|
-
*
|
|
4
|
-
* Validates that tool error responses include all required structured fields:
|
|
5
|
-
* { success: false, error: string, code: string, category: string,
|
|
6
|
-
* suggestion: string, recoverable: boolean }
|
|
7
|
-
*
|
|
8
|
-
* Tests specific documented error paths: inverted date range,
|
|
9
|
-
* nonexistent entry, self-loop link, and duplicate link detection.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { test, expect } from '@playwright/test'
|
|
13
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
14
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
15
|
-
|
|
16
|
-
test.describe.configure({ mode: 'serial' })
|
|
17
|
-
|
|
18
|
-
test.describe('Payload Contracts: Structured Error Fields', () => {
|
|
19
|
-
let client: Client
|
|
20
|
-
let entryId1: number
|
|
21
|
-
let entryId2: number
|
|
22
|
-
|
|
23
|
-
test.beforeAll(async () => {
|
|
24
|
-
client = await createClient()
|
|
25
|
-
// Seed two entries for relationship error tests
|
|
26
|
-
const e1 = await callToolAndParse(client, 'create_entry', {
|
|
27
|
-
content: 'Error contract test entry A',
|
|
28
|
-
entry_type: 'test_entry',
|
|
29
|
-
})
|
|
30
|
-
expectSuccess(e1)
|
|
31
|
-
entryId1 = (e1.entry as Record<string, unknown>).id as number
|
|
32
|
-
|
|
33
|
-
const e2 = await callToolAndParse(client, 'create_entry', {
|
|
34
|
-
content: 'Error contract test entry B',
|
|
35
|
-
entry_type: 'test_entry',
|
|
36
|
-
})
|
|
37
|
-
expectSuccess(e2)
|
|
38
|
-
entryId2 = (e2.entry as Record<string, unknown>).id as number
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test.afterAll(async () => {
|
|
42
|
-
await client.close()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Assert minimum structured error fields (success, error, code, category).
|
|
47
|
-
* Use for handlers that return inline error objects without suggestion/recoverable.
|
|
48
|
-
*/
|
|
49
|
-
function expectMinimumError(payload: Record<string, unknown>, expectedCode?: string): void {
|
|
50
|
-
expect(payload.success).toBe(false)
|
|
51
|
-
expect(typeof payload.error).toBe('string')
|
|
52
|
-
expect(typeof payload.code).toBe('string')
|
|
53
|
-
expect(typeof payload.category).toBe('string')
|
|
54
|
-
|
|
55
|
-
if (expectedCode) {
|
|
56
|
-
expect(payload.code).toBe(expectedCode)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Assert all 6 structured error fields are present (formatHandlerError paths).
|
|
62
|
-
* Use for tools that route errors through formatHandlerError or MemoryJournalMcpError.
|
|
63
|
-
*/
|
|
64
|
-
function expectFullError(payload: Record<string, unknown>, expectedCode?: string): void {
|
|
65
|
-
expectMinimumError(payload, expectedCode)
|
|
66
|
-
expect(typeof payload.suggestion).toBe('string')
|
|
67
|
-
expect(typeof payload.recoverable).toBe('boolean')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// --- search_by_date_range: inverted date range ---
|
|
71
|
-
|
|
72
|
-
test('search_by_date_range (inverted range) returns VALIDATION_ERROR with all fields', async () => {
|
|
73
|
-
const payload = await callToolAndParse(client, 'search_by_date_range', {
|
|
74
|
-
start_date: '2030-12-31',
|
|
75
|
-
end_date: '2020-01-01',
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
expectFullError(payload, 'VALIDATION_ERROR')
|
|
79
|
-
expect(payload.category).toBe('validation')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// --- get_entry_by_id: nonexistent entry ---
|
|
83
|
-
|
|
84
|
-
test('get_entry_by_id (nonexistent ID) returns structured error with code+category', async () => {
|
|
85
|
-
const payload = await callToolAndParse(client, 'get_entry_by_id', {
|
|
86
|
-
entry_id: 999999999,
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
expectMinimumError(payload)
|
|
90
|
-
// Resource errors categorize under 'resource' or 'not_found'
|
|
91
|
-
expect(['resource', 'not_found']).toContain(payload.category)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
// --- update_entry: nonexistent entry ---
|
|
95
|
-
|
|
96
|
-
test('update_entry (nonexistent ID) returns structured error with code+category', async () => {
|
|
97
|
-
const payload = await callToolAndParse(client, 'update_entry', {
|
|
98
|
-
entry_id: 999999999,
|
|
99
|
-
content: 'should not update',
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
expectMinimumError(payload)
|
|
103
|
-
expect(typeof payload.category).toBe('string')
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
// --- link_entries: self-loop ---
|
|
107
|
-
|
|
108
|
-
test('link_entries self-loop returns structured error with code+category', async () => {
|
|
109
|
-
const payload = await callToolAndParse(client, 'link_entries', {
|
|
110
|
-
from_entry_id: entryId1,
|
|
111
|
-
to_entry_id: entryId1,
|
|
112
|
-
relationship_type: 'references',
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// Self-loop returns { success, error, code: 'VALIDATION_ERROR', category: 'validation' }
|
|
116
|
-
// (no suggestion/recoverable on inline error paths)
|
|
117
|
-
expectMinimumError(payload, 'VALIDATION_ERROR')
|
|
118
|
-
expect(payload.category).toBe('validation')
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
// --- link_entries: duplicate detection returns { duplicate: true } ---
|
|
122
|
-
|
|
123
|
-
test('link_entries duplicate returns { duplicate: true } (not alreadyExists)', async () => {
|
|
124
|
-
// First link succeeds
|
|
125
|
-
const first = await callToolAndParse(client, 'link_entries', {
|
|
126
|
-
from_entry_id: entryId1,
|
|
127
|
-
to_entry_id: entryId2,
|
|
128
|
-
relationship_type: 'references',
|
|
129
|
-
})
|
|
130
|
-
expectSuccess(first)
|
|
131
|
-
expect(first.success).toBe(true)
|
|
132
|
-
|
|
133
|
-
// Second identical link is a duplicate
|
|
134
|
-
const payload = await callToolAndParse(client, 'link_entries', {
|
|
135
|
-
from_entry_id: entryId1,
|
|
136
|
-
to_entry_id: entryId2,
|
|
137
|
-
relationship_type: 'references',
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
// Duplicate detection: { duplicate: true } — NOT { alreadyExists: true }
|
|
141
|
-
expect(payload.duplicate).toBe(true)
|
|
142
|
-
expect(payload).not.toHaveProperty('alreadyExists')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
// --- delete_entry: nonexistent entry structured error ---
|
|
146
|
-
|
|
147
|
-
test('delete_entry (already-deleted or nonexistent) returns structured error with code+category', async () => {
|
|
148
|
-
// Try to delete a very high ID that doesn't exist
|
|
149
|
-
const payload = await callToolAndParse(client, 'delete_entry', {
|
|
150
|
-
entry_id: 999999998,
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
// Should be a structured error with minimum fields
|
|
154
|
-
if (payload.success === false) {
|
|
155
|
-
expectMinimumError(payload)
|
|
156
|
-
}
|
|
157
|
-
// If success (sqlite soft-delete may silently succeed on missing rows) — also valid
|
|
158
|
-
})
|
|
159
|
-
})
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: Export
|
|
3
|
-
*
|
|
4
|
-
* Validates response shapes for 1 export tool:
|
|
5
|
-
* export_entries.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test, expect } from '@playwright/test'
|
|
9
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
10
|
-
import { createClient, callToolAndParse, expectSuccess } from './helpers.js'
|
|
11
|
-
|
|
12
|
-
test.describe.configure({ mode: 'serial' })
|
|
13
|
-
|
|
14
|
-
test.describe('Payload Contracts: Export', () => {
|
|
15
|
-
let client: Client
|
|
16
|
-
|
|
17
|
-
test.beforeAll(async () => {
|
|
18
|
-
client = await createClient()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.afterAll(async () => {
|
|
22
|
-
await client.close()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('export_entries (json) returns { format, entries, count }', async () => {
|
|
26
|
-
const payload = await callToolAndParse(client, 'export_entries', {
|
|
27
|
-
format: 'json',
|
|
28
|
-
limit: 5,
|
|
29
|
-
})
|
|
30
|
-
expectSuccess(payload)
|
|
31
|
-
expect(payload.format).toBe('json')
|
|
32
|
-
expect(Array.isArray(payload.entries)).toBe(true)
|
|
33
|
-
expect(typeof payload.count).toBe('number')
|
|
34
|
-
expect(payload.count).toBe(payload.entries.length)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('export_entries (markdown) returns { format, content }', async () => {
|
|
38
|
-
const payload = await callToolAndParse(client, 'export_entries', {
|
|
39
|
-
format: 'markdown',
|
|
40
|
-
limit: 5,
|
|
41
|
-
})
|
|
42
|
-
expectSuccess(payload)
|
|
43
|
-
expect(payload.format).toBe('markdown')
|
|
44
|
-
expect(typeof payload.content).toBe('string')
|
|
45
|
-
})
|
|
46
|
-
})
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Payload Contract Tests: GitHub Configuration Degradation
|
|
3
|
-
*
|
|
4
|
-
* Verifies that GitHub tools gracefully degrade and return
|
|
5
|
-
* structured { requiresUserInput: true } errors instead of crashing
|
|
6
|
-
* or throwing unhandled exceptions when GITHUB_REPO_PATH is missing.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { test, expect } from '@playwright/test'
|
|
10
|
-
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
11
|
-
import { startServer, stopServer, createClient } from './helpers.js'
|
|
12
|
-
import { tmpdir } from 'node:os'
|
|
13
|
-
|
|
14
|
-
const GITHUB_DEGRADE_PORT = 3115
|
|
15
|
-
|
|
16
|
-
test.describe.configure({ mode: 'serial' })
|
|
17
|
-
|
|
18
|
-
test.describe('Payload Contracts: GitHub Config Degradation', () => {
|
|
19
|
-
let client: Client
|
|
20
|
-
|
|
21
|
-
test.beforeAll(async () => {
|
|
22
|
-
// Strip out GITHUB_REPO_PATH and GITHUB_TOKEN so auto-detect fails
|
|
23
|
-
const oldRepo = process.env.GITHUB_REPO_PATH
|
|
24
|
-
const oldToken = process.env.GITHUB_TOKEN
|
|
25
|
-
|
|
26
|
-
delete process.env.GITHUB_REPO_PATH
|
|
27
|
-
delete process.env.GITHUB_TOKEN
|
|
28
|
-
|
|
29
|
-
// startServer propagates the current process.env
|
|
30
|
-
try {
|
|
31
|
-
const startOpts = { cwd: tmpdir() }
|
|
32
|
-
await startServer(GITHUB_DEGRADE_PORT, [], 'gh-degrade', startOpts)
|
|
33
|
-
client = await createClient(GITHUB_DEGRADE_PORT)
|
|
34
|
-
} finally {
|
|
35
|
-
if (oldRepo) process.env.GITHUB_REPO_PATH = oldRepo
|
|
36
|
-
if (oldToken) process.env.GITHUB_TOKEN = oldToken
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test.afterAll(async () => {
|
|
41
|
-
if (client) {
|
|
42
|
-
await client.close()
|
|
43
|
-
}
|
|
44
|
-
stopServer(GITHUB_DEGRADE_PORT)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('get_github_issues returns requiresUserInput: true without auto-detect env', async () => {
|
|
48
|
-
const response = await client.callTool({
|
|
49
|
-
name: 'get_github_issues',
|
|
50
|
-
arguments: {}, // Empty properties to fail auto-detect
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
54
|
-
const text = (response.content as Array<{ text: string }>)[0]!.text
|
|
55
|
-
console.log('GitHub Degrade Response:', text)
|
|
56
|
-
// Check for presence of auto-detect mention
|
|
57
|
-
expect(text).toContain('Could not auto-detect')
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('get_github_context degrades gracefully to returning missing state', async () => {
|
|
61
|
-
const response = await client.callTool({
|
|
62
|
-
name: 'get_github_context',
|
|
63
|
-
arguments: {},
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
expect(Array.isArray(response.content)).toBe(true)
|
|
67
|
-
const text = (response.content as Array<{ text: string }>)[0]!.text
|
|
68
|
-
const payload = JSON.parse(text)
|
|
69
|
-
|
|
70
|
-
expect(payload.repoName).toBeNull()
|
|
71
|
-
expect(payload.issueCount).toBe(0)
|
|
72
|
-
})
|
|
73
|
-
})
|