memory-journal-mcp 4.4.2 → 5.0.0
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/.github/workflows/codeql.yml +1 -6
- package/.github/workflows/docker-publish.yml +15 -49
- package/.github/workflows/lint-and-test.yml +1 -1
- package/.github/workflows/secrets-scanning.yml +4 -3
- package/.github/workflows/security-update.yml +3 -3
- package/CHANGELOG.md +213 -0
- package/CONTRIBUTING.md +132 -97
- package/DOCKER_README.md +184 -235
- package/Dockerfile +27 -24
- package/README.md +218 -190
- package/SECURITY.md +27 -35
- package/dist/cli.js +16 -1
- package/dist/cli.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +5 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +133 -73
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/constants/icons.d.ts +2 -2
- package/dist/constants/icons.d.ts.map +1 -1
- package/dist/constants/icons.js +7 -6
- package/dist/constants/icons.js.map +1 -1
- package/dist/database/SqliteAdapter.d.ts +37 -24
- package/dist/database/SqliteAdapter.d.ts.map +1 -1
- package/dist/database/SqliteAdapter.js +319 -157
- package/dist/database/SqliteAdapter.js.map +1 -1
- package/dist/database/schema.d.ts +45 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +92 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/filtering/ToolFilter.d.ts +1 -1
- package/dist/filtering/ToolFilter.d.ts.map +1 -1
- package/dist/filtering/ToolFilter.js +13 -2
- package/dist/filtering/ToolFilter.js.map +1 -1
- package/dist/github/GitHubIntegration.d.ts.map +1 -1
- package/dist/github/GitHubIntegration.js +1 -3
- package/dist/github/GitHubIntegration.js.map +1 -1
- package/dist/handlers/prompts/github.d.ts +12 -0
- package/dist/handlers/prompts/github.d.ts.map +1 -0
- package/dist/handlers/prompts/github.js +178 -0
- package/dist/handlers/prompts/github.js.map +1 -0
- package/dist/handlers/prompts/index.d.ts +23 -2
- package/dist/handlers/prompts/index.d.ts.map +1 -1
- package/dist/handlers/prompts/index.js +7 -432
- package/dist/handlers/prompts/index.js.map +1 -1
- package/dist/handlers/prompts/workflow.d.ts +12 -0
- package/dist/handlers/prompts/workflow.d.ts.map +1 -0
- package/dist/handlers/prompts/workflow.js +277 -0
- package/dist/handlers/prompts/workflow.js.map +1 -0
- package/dist/handlers/resources/core.d.ts +11 -0
- package/dist/handlers/resources/core.d.ts.map +1 -0
- package/dist/handlers/resources/core.js +433 -0
- package/dist/handlers/resources/core.js.map +1 -0
- package/dist/handlers/resources/github.d.ts +11 -0
- package/dist/handlers/resources/github.d.ts.map +1 -0
- package/dist/handlers/resources/github.js +314 -0
- package/dist/handlers/resources/github.js.map +1 -0
- package/dist/handlers/resources/graph.d.ts +11 -0
- package/dist/handlers/resources/graph.d.ts.map +1 -0
- package/dist/handlers/resources/graph.js +204 -0
- package/dist/handlers/resources/graph.js.map +1 -0
- package/dist/handlers/resources/index.d.ts +5 -20
- package/dist/handlers/resources/index.d.ts.map +1 -1
- package/dist/handlers/resources/index.js +16 -1278
- package/dist/handlers/resources/index.js.map +1 -1
- package/dist/handlers/resources/shared.d.ts +60 -0
- package/dist/handlers/resources/shared.d.ts.map +1 -0
- package/dist/handlers/resources/shared.js +49 -0
- package/dist/handlers/resources/shared.js.map +1 -0
- package/dist/handlers/resources/team.d.ts +13 -0
- package/dist/handlers/resources/team.d.ts.map +1 -0
- package/dist/handlers/resources/team.js +119 -0
- package/dist/handlers/resources/team.js.map +1 -0
- package/dist/handlers/resources/templates.d.ts +13 -0
- package/dist/handlers/resources/templates.d.ts.map +1 -0
- package/dist/handlers/resources/templates.js +310 -0
- package/dist/handlers/resources/templates.js.map +1 -0
- package/dist/handlers/tools/admin.d.ts +8 -0
- package/dist/handlers/tools/admin.d.ts.map +1 -0
- package/dist/handlers/tools/admin.js +270 -0
- package/dist/handlers/tools/admin.js.map +1 -0
- package/dist/handlers/tools/analytics.d.ts +8 -0
- package/dist/handlers/tools/analytics.d.ts.map +1 -0
- package/dist/handlers/tools/analytics.js +256 -0
- package/dist/handlers/tools/analytics.js.map +1 -0
- package/dist/handlers/tools/backup.d.ts +8 -0
- package/dist/handlers/tools/backup.d.ts.map +1 -0
- package/dist/handlers/tools/backup.js +224 -0
- package/dist/handlers/tools/backup.js.map +1 -0
- package/dist/handlers/tools/core.d.ts +9 -0
- package/dist/handlers/tools/core.d.ts.map +1 -0
- package/dist/handlers/tools/core.js +326 -0
- package/dist/handlers/tools/core.js.map +1 -0
- package/dist/handlers/tools/export.d.ts +8 -0
- package/dist/handlers/tools/export.d.ts.map +1 -0
- package/dist/handlers/tools/export.js +89 -0
- package/dist/handlers/tools/export.js.map +1 -0
- package/dist/handlers/tools/github/helpers.d.ts +34 -0
- package/dist/handlers/tools/github/helpers.d.ts.map +1 -0
- package/dist/handlers/tools/github/helpers.js +52 -0
- package/dist/handlers/tools/github/helpers.js.map +1 -0
- package/dist/handlers/tools/github/insights-tools.d.ts +8 -0
- package/dist/handlers/tools/github/insights-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/insights-tools.js +104 -0
- package/dist/handlers/tools/github/insights-tools.js.map +1 -0
- package/dist/handlers/tools/github/issue-tools.d.ts +8 -0
- package/dist/handlers/tools/github/issue-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/issue-tools.js +359 -0
- package/dist/handlers/tools/github/issue-tools.js.map +1 -0
- package/dist/handlers/tools/github/kanban-tools.d.ts +8 -0
- package/dist/handlers/tools/github/kanban-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/kanban-tools.js +108 -0
- package/dist/handlers/tools/github/kanban-tools.js.map +1 -0
- package/dist/handlers/tools/github/milestone-tools.d.ts +9 -0
- package/dist/handlers/tools/github/milestone-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/milestone-tools.js +302 -0
- package/dist/handlers/tools/github/milestone-tools.js.map +1 -0
- package/dist/handlers/tools/github/mutation-tools.d.ts +12 -0
- package/dist/handlers/tools/github/mutation-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/mutation-tools.js +15 -0
- package/dist/handlers/tools/github/mutation-tools.js.map +1 -0
- package/dist/handlers/tools/github/read-tools.d.ts +8 -0
- package/dist/handlers/tools/github/read-tools.d.ts.map +1 -0
- package/dist/handlers/tools/github/read-tools.js +260 -0
- package/dist/handlers/tools/github/read-tools.js.map +1 -0
- package/dist/handlers/tools/github/schemas.d.ts +467 -0
- package/dist/handlers/tools/github/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/github/schemas.js +335 -0
- package/dist/handlers/tools/github/schemas.js.map +1 -0
- package/dist/handlers/tools/github.d.ts +14 -0
- package/dist/handlers/tools/github.d.ts.map +1 -0
- package/dist/handlers/tools/github.js +28 -0
- package/dist/handlers/tools/github.js.map +1 -0
- package/dist/handlers/tools/index.d.ts +15 -20
- package/dist/handlers/tools/index.d.ts.map +1 -1
- package/dist/handlers/tools/index.js +117 -2909
- package/dist/handlers/tools/index.js.map +1 -1
- package/dist/handlers/tools/relationships.d.ts +8 -0
- package/dist/handlers/tools/relationships.d.ts.map +1 -0
- package/dist/handlers/tools/relationships.js +308 -0
- package/dist/handlers/tools/relationships.js.map +1 -0
- package/dist/handlers/tools/schemas.d.ts +108 -0
- package/dist/handlers/tools/schemas.d.ts.map +1 -0
- package/dist/handlers/tools/schemas.js +122 -0
- package/dist/handlers/tools/schemas.js.map +1 -0
- package/dist/handlers/tools/search.d.ts +8 -0
- package/dist/handlers/tools/search.d.ts.map +1 -0
- package/dist/handlers/tools/search.js +282 -0
- package/dist/handlers/tools/search.js.map +1 -0
- package/dist/handlers/tools/team.d.ts +11 -0
- package/dist/handlers/tools/team.d.ts.map +1 -0
- package/dist/handlers/tools/team.js +239 -0
- package/dist/handlers/tools/team.js.map +1 -0
- package/dist/server/McpServer.d.ts +4 -0
- package/dist/server/McpServer.d.ts.map +1 -1
- package/dist/server/McpServer.js +48 -297
- package/dist/server/McpServer.js.map +1 -1
- package/dist/server/Scheduler.d.ts +91 -0
- package/dist/server/Scheduler.d.ts.map +1 -0
- package/dist/server/Scheduler.js +201 -0
- package/dist/server/Scheduler.js.map +1 -0
- package/dist/transports/http.d.ts +66 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +519 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/types/entities.d.ts +101 -0
- package/dist/types/entities.d.ts.map +1 -0
- package/dist/types/entities.js +5 -0
- package/dist/types/entities.js.map +1 -0
- package/dist/types/filtering.d.ts +34 -0
- package/dist/types/filtering.d.ts.map +1 -0
- package/dist/types/filtering.js +5 -0
- package/dist/types/filtering.js.map +1 -0
- package/dist/types/github.d.ts +166 -0
- package/dist/types/github.d.ts.map +1 -0
- package/dist/types/github.js +5 -0
- package/dist/types/github.js.map +1 -0
- package/dist/types/index.d.ts +35 -292
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -2
- package/dist/types/index.js.map +1 -1
- package/dist/utils/error-helpers.d.ts +37 -0
- package/dist/utils/error-helpers.d.ts.map +1 -0
- package/dist/utils/error-helpers.js +47 -0
- package/dist/utils/error-helpers.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +6 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/security-utils.d.ts +0 -21
- package/dist/utils/security-utils.d.ts.map +1 -1
- package/dist/utils/security-utils.js +0 -47
- package/dist/utils/security-utils.js.map +1 -1
- package/dist/vector/VectorSearchManager.d.ts.map +1 -1
- package/dist/vector/VectorSearchManager.js +9 -32
- package/dist/vector/VectorSearchManager.js.map +1 -1
- package/docker-compose.yml +11 -2
- package/hooks/README.md +107 -0
- package/hooks/cursor/hooks.json +10 -0
- package/hooks/cursor/memory-journal.mdc +22 -0
- package/hooks/cursor/session-end.sh +19 -0
- package/hooks/kilo-code/session-end-mode.json +11 -0
- package/hooks/kiro/session-end.md +13 -0
- package/mcp-config-example.json +1 -0
- package/package.json +11 -9
- package/playwright.config.ts +29 -0
- package/releases/v4.5.0.md +116 -0
- package/releases/v5.0.0.md +105 -0
- package/scripts/generate-server-instructions.ts +176 -0
- package/scripts/server-instructions-function-body.ts +77 -0
- package/server.json +3 -3
- package/src/cli.ts +45 -1
- package/src/constants/ServerInstructions.ts +133 -73
- package/src/constants/icons.ts +8 -7
- package/src/constants/server-instructions.md +268 -0
- package/src/database/SqliteAdapter.ts +358 -192
- package/src/database/schema.ts +125 -0
- package/src/filtering/ToolFilter.ts +13 -2
- package/src/github/GitHubIntegration.ts +1 -3
- package/src/handlers/prompts/github.ts +209 -0
- package/src/handlers/prompts/index.ts +10 -499
- package/src/handlers/prompts/workflow.ts +314 -0
- package/src/handlers/resources/core.ts +528 -0
- package/src/handlers/resources/github.ts +358 -0
- package/src/handlers/resources/graph.ts +254 -0
- package/src/handlers/resources/index.ts +23 -1570
- package/src/handlers/resources/shared.ts +103 -0
- package/src/handlers/resources/team.ts +133 -0
- package/src/handlers/resources/templates.ts +374 -0
- package/src/handlers/tools/admin.ts +285 -0
- package/src/handlers/tools/analytics.ts +301 -0
- package/src/handlers/tools/backup.ts +242 -0
- package/src/handlers/tools/core.ts +350 -0
- package/src/handlers/tools/export.ts +115 -0
- package/src/handlers/tools/github/helpers.ts +86 -0
- package/src/handlers/tools/github/insights-tools.ts +119 -0
- package/src/handlers/tools/github/issue-tools.ts +439 -0
- package/src/handlers/tools/github/kanban-tools.ts +134 -0
- package/src/handlers/tools/github/milestone-tools.ts +392 -0
- package/src/handlers/tools/github/mutation-tools.ts +17 -0
- package/src/handlers/tools/github/read-tools.ts +328 -0
- package/src/handlers/tools/github/schemas.ts +369 -0
- package/src/handlers/tools/github.ts +36 -0
- package/src/handlers/tools/index.ts +144 -3325
- package/src/handlers/tools/relationships.ts +358 -0
- package/src/handlers/tools/schemas.ts +132 -0
- package/src/handlers/tools/search.ts +343 -0
- package/src/handlers/tools/team.ts +273 -0
- package/src/server/McpServer.ts +63 -358
- package/src/server/Scheduler.ts +278 -0
- package/src/transports/http.ts +635 -0
- package/src/types/entities.ts +145 -0
- package/src/types/filtering.ts +54 -0
- package/src/types/github.ts +180 -0
- package/src/types/index.ts +67 -375
- package/src/utils/error-helpers.ts +52 -0
- package/src/utils/logger.ts +6 -3
- package/src/utils/security-utils.ts +0 -52
- package/src/vector/VectorSearchManager.ts +9 -33
- package/tests/constants/icons.test.ts +1 -2
- package/tests/constants/server-instructions.test.ts +30 -4
- package/tests/database/sqlite-adapter.test.ts +91 -7
- package/tests/e2e/auth.spec.ts +154 -0
- package/tests/e2e/health.spec.ts +63 -0
- package/tests/e2e/protocols.spec.ts +134 -0
- package/tests/e2e/resources.spec.ts +103 -0
- package/tests/e2e/scheduler.spec.ts +79 -0
- package/tests/e2e/security.spec.ts +91 -0
- package/tests/e2e/sessions.spec.ts +95 -0
- package/tests/e2e/stateless.spec.ts +121 -0
- package/tests/e2e/tools.spec.ts +111 -0
- package/tests/filtering/tool-filter.test.ts +46 -0
- package/tests/handlers/error-path-coverage.test.ts +324 -0
- package/tests/handlers/github-resource-handlers.test.ts +453 -0
- package/tests/handlers/github-tool-handlers.test.ts +899 -0
- package/tests/handlers/prompt-handler-coverage.test.ts +106 -0
- package/tests/handlers/prompt-handlers.test.ts +40 -0
- package/tests/handlers/resource-handler-coverage.test.ts +181 -0
- package/tests/handlers/resource-handlers.test.ts +33 -9
- package/tests/handlers/search-tool-handlers.test.ts +272 -0
- package/tests/handlers/targeted-gap-closure.test.ts +387 -0
- package/tests/handlers/team-resource-handlers.test.ts +156 -0
- package/tests/handlers/team-tool-handlers.test.ts +301 -0
- package/tests/handlers/tool-handler-coverage.test.ts +469 -0
- package/tests/handlers/tool-handlers.test.ts +2 -2
- package/tests/security/sql-injection.test.ts +3 -54
- package/tests/server/mcp-server.test.ts +503 -8
- package/tests/server/scheduler.test.ts +400 -0
- package/tests/transports/http-transport.test.ts +620 -0
- package/tests/vector/vector-search-manager.test.ts +60 -0
- package/vitest.config.ts +4 -1
- package/.memory-journal-team.db +0 -0
- package/.vscode/settings.json +0 -84
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Journal MCP Server - GitHub Resource Definitions
|
|
3
|
+
*
|
|
4
|
+
* Resources: github/status, github/insights, github/milestones, milestones/{number}
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ICON_GITHUB, ICON_ANALYTICS, ICON_MILESTONE } from '../../constants/icons.js'
|
|
8
|
+
import type { InternalResourceDef, ResourceContext, ResourceResult } from './shared.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get GitHub resource definitions
|
|
12
|
+
*/
|
|
13
|
+
export function getGitHubResourceDefinitions(): InternalResourceDef[] {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
uri: 'memory://github/status',
|
|
17
|
+
name: 'GitHub Status',
|
|
18
|
+
title: 'GitHub Repository Status',
|
|
19
|
+
description:
|
|
20
|
+
'Compact GitHub status: repository, branch, CI, issues, PRs, Kanban summary',
|
|
21
|
+
mimeType: 'application/json',
|
|
22
|
+
icons: [ICON_GITHUB],
|
|
23
|
+
annotations: {
|
|
24
|
+
audience: ['assistant'],
|
|
25
|
+
priority: 0.7,
|
|
26
|
+
},
|
|
27
|
+
handler: async (_uri: string, context: ResourceContext): Promise<ResourceResult> => {
|
|
28
|
+
const lastModified = new Date().toISOString()
|
|
29
|
+
|
|
30
|
+
if (!context.github) {
|
|
31
|
+
return {
|
|
32
|
+
data: {
|
|
33
|
+
error: 'GitHub integration not available',
|
|
34
|
+
hint: 'Set GITHUB_TOKEN and GITHUB_REPO_PATH environment variables.',
|
|
35
|
+
},
|
|
36
|
+
annotations: { lastModified },
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
41
|
+
const owner = repoInfo.owner
|
|
42
|
+
const repo = repoInfo.repo
|
|
43
|
+
|
|
44
|
+
if (!owner || !repo) {
|
|
45
|
+
return {
|
|
46
|
+
data: {
|
|
47
|
+
error: 'Could not detect repository',
|
|
48
|
+
hint: 'Set GITHUB_REPO_PATH to your git repository.',
|
|
49
|
+
branch: repoInfo.branch,
|
|
50
|
+
},
|
|
51
|
+
annotations: { lastModified },
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Get current commit
|
|
56
|
+
let commit: string | null = null
|
|
57
|
+
try {
|
|
58
|
+
const repoContext = await context.github.getRepoContext()
|
|
59
|
+
commit = repoContext.commit
|
|
60
|
+
} catch {
|
|
61
|
+
// Ignore
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Get open issues (limited for token efficiency)
|
|
65
|
+
const issues = await context.github.getIssues(owner, repo, 'open', 5)
|
|
66
|
+
const openIssues = issues.map((i) => ({
|
|
67
|
+
number: i.number,
|
|
68
|
+
title: i.title.slice(0, 50),
|
|
69
|
+
}))
|
|
70
|
+
|
|
71
|
+
// Get open PRs (limited for token efficiency)
|
|
72
|
+
const prs = await context.github.getPullRequests(owner, repo, 'open', 5)
|
|
73
|
+
const openPrs = prs.map((pr) => ({
|
|
74
|
+
number: pr.number,
|
|
75
|
+
title: pr.title.slice(0, 50),
|
|
76
|
+
state: pr.state,
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
// Get CI status from latest workflow run
|
|
80
|
+
const workflowRuns = await context.github.getWorkflowRuns(owner, repo, 5)
|
|
81
|
+
let ciStatus: 'passing' | 'failing' | 'pending' | 'cancelled' | 'unknown' =
|
|
82
|
+
'unknown'
|
|
83
|
+
let latestRun: { name: string; conclusion: string | null; headSha: string } | null =
|
|
84
|
+
null
|
|
85
|
+
|
|
86
|
+
if (workflowRuns.length > 0) {
|
|
87
|
+
const latestCompleted = workflowRuns.find((r) => r.status === 'completed')
|
|
88
|
+
const latest = workflowRuns[0]
|
|
89
|
+
|
|
90
|
+
latestRun = {
|
|
91
|
+
name: latest?.name ?? 'Unknown',
|
|
92
|
+
conclusion: latest?.conclusion ?? null,
|
|
93
|
+
headSha: latest?.headSha?.slice(0, 7) ?? '',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (latestCompleted) {
|
|
97
|
+
switch (latestCompleted.conclusion) {
|
|
98
|
+
case 'success':
|
|
99
|
+
ciStatus = 'passing'
|
|
100
|
+
break
|
|
101
|
+
case 'failure':
|
|
102
|
+
ciStatus = 'failing'
|
|
103
|
+
break
|
|
104
|
+
case 'cancelled':
|
|
105
|
+
ciStatus = 'cancelled'
|
|
106
|
+
break
|
|
107
|
+
default:
|
|
108
|
+
ciStatus = 'unknown'
|
|
109
|
+
}
|
|
110
|
+
} else if (workflowRuns.some((r) => r.status !== 'completed')) {
|
|
111
|
+
ciStatus = 'pending'
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Get Kanban summary if project 1 exists
|
|
116
|
+
let kanbanSummary: Record<string, number> | null = null
|
|
117
|
+
try {
|
|
118
|
+
const kanban = await context.github.getProjectKanban(owner, 1, repo)
|
|
119
|
+
if (kanban) {
|
|
120
|
+
kanbanSummary = {}
|
|
121
|
+
for (const col of kanban.columns) {
|
|
122
|
+
kanbanSummary[col.status] = col.items.length
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
// Kanban not available
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Get milestone summary
|
|
130
|
+
let milestoneSummary:
|
|
131
|
+
| {
|
|
132
|
+
number: number
|
|
133
|
+
title: string
|
|
134
|
+
state: string
|
|
135
|
+
openIssues: number
|
|
136
|
+
closedIssues: number
|
|
137
|
+
completionPercentage: number
|
|
138
|
+
dueOn: string | null
|
|
139
|
+
}[]
|
|
140
|
+
| null = null
|
|
141
|
+
try {
|
|
142
|
+
const milestones = await context.github.getMilestones(owner, repo, 'open', 5)
|
|
143
|
+
if (milestones.length > 0) {
|
|
144
|
+
milestoneSummary = milestones.map((ms) => {
|
|
145
|
+
const total = ms.openIssues + ms.closedIssues
|
|
146
|
+
const pct = total > 0 ? Math.round((ms.closedIssues / total) * 100) : 0
|
|
147
|
+
return {
|
|
148
|
+
number: ms.number,
|
|
149
|
+
title: ms.title,
|
|
150
|
+
state: ms.state,
|
|
151
|
+
openIssues: ms.openIssues,
|
|
152
|
+
closedIssues: ms.closedIssues,
|
|
153
|
+
completionPercentage: pct,
|
|
154
|
+
dueOn: ms.dueOn,
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
} catch {
|
|
159
|
+
// Milestones not available
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
data: {
|
|
164
|
+
repository: `${owner}/${repo}`,
|
|
165
|
+
branch: repoInfo.branch,
|
|
166
|
+
commit: commit?.slice(0, 7) ?? null,
|
|
167
|
+
ci: {
|
|
168
|
+
status: ciStatus,
|
|
169
|
+
latestRun,
|
|
170
|
+
},
|
|
171
|
+
issues: {
|
|
172
|
+
openCount: issues.length,
|
|
173
|
+
items: openIssues,
|
|
174
|
+
},
|
|
175
|
+
pullRequests: {
|
|
176
|
+
openCount: prs.length,
|
|
177
|
+
items: openPrs,
|
|
178
|
+
},
|
|
179
|
+
kanbanSummary,
|
|
180
|
+
milestones: milestoneSummary,
|
|
181
|
+
},
|
|
182
|
+
annotations: { lastModified },
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
// Repository insights resource
|
|
187
|
+
{
|
|
188
|
+
uri: 'memory://github/insights',
|
|
189
|
+
name: 'Repository Insights',
|
|
190
|
+
title: 'Repository Stars & Traffic Summary',
|
|
191
|
+
description: 'Compact repo insights: stars, forks, 14-day traffic totals (~150 tokens)',
|
|
192
|
+
mimeType: 'application/json',
|
|
193
|
+
icons: [ICON_ANALYTICS],
|
|
194
|
+
annotations: {
|
|
195
|
+
audience: ['assistant'],
|
|
196
|
+
priority: 0.4,
|
|
197
|
+
},
|
|
198
|
+
handler: async (_uri: string, context: ResourceContext): Promise<ResourceResult> => {
|
|
199
|
+
const lastModified = new Date().toISOString()
|
|
200
|
+
|
|
201
|
+
if (!context.github) {
|
|
202
|
+
return {
|
|
203
|
+
data: {
|
|
204
|
+
error: 'GitHub integration not available',
|
|
205
|
+
hint: 'Set GITHUB_TOKEN and GITHUB_REPO_PATH environment variables.',
|
|
206
|
+
},
|
|
207
|
+
annotations: { lastModified },
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
212
|
+
const owner = repoInfo.owner
|
|
213
|
+
const repo = repoInfo.repo
|
|
214
|
+
|
|
215
|
+
if (!owner || !repo) {
|
|
216
|
+
return {
|
|
217
|
+
data: {
|
|
218
|
+
error: 'Could not detect repository',
|
|
219
|
+
hint: 'Set GITHUB_REPO_PATH to your git repository.',
|
|
220
|
+
},
|
|
221
|
+
annotations: { lastModified },
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const stats = await context.github.getRepoStats(owner, repo)
|
|
226
|
+
|
|
227
|
+
let traffic: { clones14d: number; views14d: number } | null = null
|
|
228
|
+
try {
|
|
229
|
+
const trafficData = await context.github.getTrafficData(owner, repo)
|
|
230
|
+
if (trafficData) {
|
|
231
|
+
traffic = {
|
|
232
|
+
clones14d: trafficData.clones.total,
|
|
233
|
+
views14d: trafficData.views.total,
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
// Traffic data requires push access
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
data: {
|
|
242
|
+
repository: `${owner}/${repo}`,
|
|
243
|
+
stars: stats?.stars ?? null,
|
|
244
|
+
forks: stats?.forks ?? null,
|
|
245
|
+
watchers: stats?.watchers ?? null,
|
|
246
|
+
...(traffic ?? {}),
|
|
247
|
+
hint: !traffic
|
|
248
|
+
? 'Traffic data requires push access to the repository.'
|
|
249
|
+
: undefined,
|
|
250
|
+
},
|
|
251
|
+
annotations: { lastModified },
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
// Milestone resources
|
|
256
|
+
{
|
|
257
|
+
uri: 'memory://github/milestones',
|
|
258
|
+
name: 'GitHub Milestones',
|
|
259
|
+
title: 'GitHub Repository Milestones',
|
|
260
|
+
description:
|
|
261
|
+
'Open GitHub milestones with completion percentages, due dates, and issue counts',
|
|
262
|
+
mimeType: 'application/json',
|
|
263
|
+
icons: [ICON_MILESTONE],
|
|
264
|
+
annotations: {
|
|
265
|
+
audience: ['assistant'],
|
|
266
|
+
priority: 0.6,
|
|
267
|
+
},
|
|
268
|
+
handler: async (_uri: string, context: ResourceContext) => {
|
|
269
|
+
if (!context.github) {
|
|
270
|
+
return {
|
|
271
|
+
error: 'GitHub integration not available',
|
|
272
|
+
hint: 'Set GITHUB_TOKEN and GITHUB_REPO_PATH environment variables.',
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
277
|
+
const owner = repoInfo.owner
|
|
278
|
+
const repo = repoInfo.repo
|
|
279
|
+
|
|
280
|
+
if (!owner || !repo) {
|
|
281
|
+
return {
|
|
282
|
+
error: 'Could not detect repository',
|
|
283
|
+
hint: 'Set GITHUB_REPO_PATH to your git repository.',
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const milestones = await context.github.getMilestones(owner, repo, 'open', 20)
|
|
288
|
+
const milestonesWithProgress = milestones.map((ms) => {
|
|
289
|
+
const total = ms.openIssues + ms.closedIssues
|
|
290
|
+
const completionPercentage =
|
|
291
|
+
total > 0 ? Math.round((ms.closedIssues / total) * 100) : 0
|
|
292
|
+
return { ...ms, completionPercentage }
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
repository: `${owner}/${repo}`,
|
|
297
|
+
milestones: milestonesWithProgress,
|
|
298
|
+
count: milestonesWithProgress.length,
|
|
299
|
+
hint: 'Use get_github_milestones tool for state filtering. Use memory://milestones/{number} for detail.',
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
uri: 'memory://milestones/{number}',
|
|
305
|
+
name: 'Milestone Detail',
|
|
306
|
+
title: 'GitHub Milestone Detail',
|
|
307
|
+
description:
|
|
308
|
+
'Detailed view of a single GitHub milestone with completion progress and issue counts. Use get_github_issues with the milestone filter for individual issue details.',
|
|
309
|
+
mimeType: 'application/json',
|
|
310
|
+
icons: [ICON_MILESTONE],
|
|
311
|
+
annotations: {
|
|
312
|
+
audience: ['assistant'],
|
|
313
|
+
priority: 0.5,
|
|
314
|
+
},
|
|
315
|
+
handler: async (uri: string, context: ResourceContext) => {
|
|
316
|
+
const match = /memory:\/\/milestones\/(\d+)/.exec(uri)
|
|
317
|
+
const milestoneNumber = match?.[1] ? parseInt(match[1], 10) : null
|
|
318
|
+
|
|
319
|
+
if (milestoneNumber === null) {
|
|
320
|
+
return { error: 'Invalid milestone number' }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!context.github) {
|
|
324
|
+
return {
|
|
325
|
+
error: 'GitHub integration not available',
|
|
326
|
+
hint: 'Set GITHUB_TOKEN and GITHUB_REPO_PATH environment variables.',
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
331
|
+
const owner = repoInfo.owner
|
|
332
|
+
const repo = repoInfo.repo
|
|
333
|
+
|
|
334
|
+
if (!owner || !repo) {
|
|
335
|
+
return {
|
|
336
|
+
error: 'Could not detect repository',
|
|
337
|
+
hint: 'Set GITHUB_REPO_PATH to your git repository.',
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const milestone = await context.github.getMilestone(owner, repo, milestoneNumber)
|
|
342
|
+
if (!milestone) {
|
|
343
|
+
return { error: `Milestone #${String(milestoneNumber)} not found` }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const total = milestone.openIssues + milestone.closedIssues
|
|
347
|
+
const completionPercentage =
|
|
348
|
+
total > 0 ? Math.round((milestone.closedIssues / total) * 100) : 0
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
repository: `${owner}/${repo}`,
|
|
352
|
+
milestone: { ...milestone, completionPercentage },
|
|
353
|
+
hint: 'Use get_github_issues tool to list issues associated with this milestone.',
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Journal MCP Server - Graph Resource Definitions
|
|
3
|
+
*
|
|
4
|
+
* Resources: graph/recent, graph/actions, actions/recent
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ICON_GRAPH, ICON_GITHUB } from '../../constants/icons.js'
|
|
8
|
+
import type { InternalResourceDef, ResourceContext } from './shared.js'
|
|
9
|
+
import { execQuery, transformEntryRow } from './shared.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get graph resource definitions
|
|
13
|
+
*/
|
|
14
|
+
export function getGraphResourceDefinitions(): InternalResourceDef[] {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
uri: 'memory://graph/recent',
|
|
18
|
+
name: 'Recent Relationship Graph',
|
|
19
|
+
title: 'Live Mermaid Diagram',
|
|
20
|
+
description: 'Live Mermaid diagram of recent relationships',
|
|
21
|
+
mimeType: 'text/plain',
|
|
22
|
+
icons: [ICON_GRAPH],
|
|
23
|
+
annotations: {
|
|
24
|
+
audience: ['user', 'assistant'],
|
|
25
|
+
priority: 0.5,
|
|
26
|
+
},
|
|
27
|
+
handler: (_uri: string, context: ResourceContext) => {
|
|
28
|
+
const relationships = execQuery(
|
|
29
|
+
context.db,
|
|
30
|
+
`
|
|
31
|
+
SELECT
|
|
32
|
+
r.id, r.from_entry_id, r.to_entry_id, r.relationship_type, r.description,
|
|
33
|
+
e1.content as from_content,
|
|
34
|
+
e2.content as to_content
|
|
35
|
+
FROM relationships r
|
|
36
|
+
JOIN memory_journal e1 ON r.from_entry_id = e1.id
|
|
37
|
+
JOIN memory_journal e2 ON r.to_entry_id = e2.id
|
|
38
|
+
WHERE e1.deleted_at IS NULL AND e2.deleted_at IS NULL
|
|
39
|
+
ORDER BY r.created_at DESC
|
|
40
|
+
LIMIT 20
|
|
41
|
+
`
|
|
42
|
+
) as {
|
|
43
|
+
from_entry_id: number
|
|
44
|
+
to_entry_id: number
|
|
45
|
+
relationship_type: string
|
|
46
|
+
from_content: string
|
|
47
|
+
to_content: string
|
|
48
|
+
}[]
|
|
49
|
+
|
|
50
|
+
if (relationships.length === 0) {
|
|
51
|
+
return {
|
|
52
|
+
format: 'mermaid',
|
|
53
|
+
diagram: 'graph TD\n NoData[No relationships found]',
|
|
54
|
+
message:
|
|
55
|
+
'No entry relationships exist yet. Use link_entries tool to create relationships.',
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Build Mermaid graph
|
|
60
|
+
const lines: string[] = ['graph TD']
|
|
61
|
+
const seenNodes = new Set<number>()
|
|
62
|
+
|
|
63
|
+
// Relationship type to arrow style mapping
|
|
64
|
+
const arrowStyles: Record<string, string> = {
|
|
65
|
+
references: '-->',
|
|
66
|
+
evolves_from: '-->',
|
|
67
|
+
depends_on: '-->',
|
|
68
|
+
implements: '==>',
|
|
69
|
+
resolved: '==>',
|
|
70
|
+
clarifies: '-..->',
|
|
71
|
+
caused: '-.->',
|
|
72
|
+
related_to: '<-->',
|
|
73
|
+
response_to: '<-->',
|
|
74
|
+
blocked_by: '--x',
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const rel of relationships) {
|
|
78
|
+
if (!seenNodes.has(rel.from_entry_id)) {
|
|
79
|
+
const label = rel.from_content
|
|
80
|
+
.slice(0, 30)
|
|
81
|
+
.replace(/[\]"'`[]]/g, ' ')
|
|
82
|
+
.trim()
|
|
83
|
+
lines.push(
|
|
84
|
+
` E${String(rel.from_entry_id)}["#${String(rel.from_entry_id)}: ${label}..."]`
|
|
85
|
+
)
|
|
86
|
+
seenNodes.add(rel.from_entry_id)
|
|
87
|
+
}
|
|
88
|
+
if (!seenNodes.has(rel.to_entry_id)) {
|
|
89
|
+
const label = rel.to_content
|
|
90
|
+
.slice(0, 30)
|
|
91
|
+
.replace(/[\]"'`[]]/g, ' ')
|
|
92
|
+
.trim()
|
|
93
|
+
lines.push(
|
|
94
|
+
` E${String(rel.to_entry_id)}["#${String(rel.to_entry_id)}: ${label}..."]`
|
|
95
|
+
)
|
|
96
|
+
seenNodes.add(rel.to_entry_id)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const arrow = arrowStyles[rel.relationship_type] ?? '-->'
|
|
100
|
+
lines.push(
|
|
101
|
+
` E${String(rel.from_entry_id)} ${arrow}|${rel.relationship_type}| E${String(rel.to_entry_id)}`
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
format: 'mermaid',
|
|
107
|
+
diagram: lines.join('\n'),
|
|
108
|
+
relationshipCount: relationships.length,
|
|
109
|
+
nodeCount: seenNodes.size,
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
uri: 'memory://graph/actions',
|
|
115
|
+
name: 'Actions Graph',
|
|
116
|
+
title: 'CI/CD Narrative Graph',
|
|
117
|
+
description:
|
|
118
|
+
'CI/CD narrative graph: commits → runs → failures → entries → fixes → deployments',
|
|
119
|
+
mimeType: 'text/plain',
|
|
120
|
+
icons: [ICON_GITHUB],
|
|
121
|
+
annotations: {
|
|
122
|
+
audience: ['user', 'assistant'],
|
|
123
|
+
priority: 0.5,
|
|
124
|
+
},
|
|
125
|
+
handler: async (_uri: string, context: ResourceContext) => {
|
|
126
|
+
if (!context.github) {
|
|
127
|
+
return {
|
|
128
|
+
format: 'mermaid',
|
|
129
|
+
diagram: 'graph LR\n NoGitHub[GitHub integration not available]',
|
|
130
|
+
message:
|
|
131
|
+
'GitHub integration not configured. Set GITHUB_TOKEN and GITHUB_REPO_PATH.',
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
136
|
+
if (!repoInfo.owner || !repoInfo.repo) {
|
|
137
|
+
return {
|
|
138
|
+
format: 'mermaid',
|
|
139
|
+
diagram: 'graph LR\n NoRepo[Repository not detected]',
|
|
140
|
+
message:
|
|
141
|
+
'Could not detect repository. Set GITHUB_REPO_PATH in your config.',
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const workflowRuns = await context.github.getWorkflowRuns(
|
|
146
|
+
repoInfo.owner,
|
|
147
|
+
repoInfo.repo,
|
|
148
|
+
10
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if (workflowRuns.length === 0) {
|
|
152
|
+
return {
|
|
153
|
+
format: 'mermaid',
|
|
154
|
+
diagram: 'graph LR\n NoRuns[No workflow runs found]',
|
|
155
|
+
message: 'No GitHub Actions workflow runs found for this repository.',
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const lines: string[] = ['graph LR']
|
|
160
|
+
|
|
161
|
+
const statusStyles: Record<string, string> = {
|
|
162
|
+
success: ':::success',
|
|
163
|
+
failure: ':::failure',
|
|
164
|
+
cancelled: ':::cancelled',
|
|
165
|
+
skipped: ':::skipped',
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
lines.push(' classDef success fill:#28a745,color:#fff')
|
|
169
|
+
lines.push(' classDef failure fill:#dc3545,color:#fff')
|
|
170
|
+
lines.push(' classDef cancelled fill:#6c757d,color:#fff')
|
|
171
|
+
lines.push(' classDef skipped fill:#ffc107,color:#000')
|
|
172
|
+
|
|
173
|
+
for (const run of workflowRuns) {
|
|
174
|
+
const shortSha = run.headSha.slice(0, 7)
|
|
175
|
+
const nodeId = `R${String(run.id)}`
|
|
176
|
+
const commitId = `C${shortSha}`
|
|
177
|
+
const style = statusStyles[run.conclusion ?? 'skipped'] ?? ''
|
|
178
|
+
const statusIcon =
|
|
179
|
+
run.conclusion === 'success'
|
|
180
|
+
? '✓'
|
|
181
|
+
: run.conclusion === 'failure'
|
|
182
|
+
? '✗'
|
|
183
|
+
: '○'
|
|
184
|
+
|
|
185
|
+
lines.push(` ${commitId}["${shortSha}"]`)
|
|
186
|
+
lines.push(` ${nodeId}["${statusIcon} ${run.name}"]${style}`)
|
|
187
|
+
lines.push(` ${commitId} --> ${nodeId}`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
format: 'mermaid',
|
|
192
|
+
diagram: lines.join('\n'),
|
|
193
|
+
workflowRunCount: workflowRuns.length,
|
|
194
|
+
repository: `${repoInfo.owner}/${repoInfo.repo}`,
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
uri: 'memory://actions/recent',
|
|
200
|
+
name: 'Recent Actions',
|
|
201
|
+
title: 'Recent Workflow Runs',
|
|
202
|
+
description: 'Recent workflow runs with CI status',
|
|
203
|
+
mimeType: 'application/json',
|
|
204
|
+
icons: [ICON_GITHUB],
|
|
205
|
+
annotations: {
|
|
206
|
+
audience: ['assistant'],
|
|
207
|
+
priority: 0.5,
|
|
208
|
+
},
|
|
209
|
+
handler: async (_uri: string, context: ResourceContext) => {
|
|
210
|
+
if (context.github) {
|
|
211
|
+
try {
|
|
212
|
+
const repoInfo = await context.github.getRepoInfo()
|
|
213
|
+
if (repoInfo.owner && repoInfo.repo) {
|
|
214
|
+
const runs = await context.github.getWorkflowRuns(
|
|
215
|
+
repoInfo.owner,
|
|
216
|
+
repoInfo.repo,
|
|
217
|
+
10
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
const entries = runs.map((run) => ({
|
|
221
|
+
id: -1 * run.id,
|
|
222
|
+
entryType: 'tool_output',
|
|
223
|
+
content: `Workflow: ${run.name}\nStatus: ${run.status}\nConclusion: ${run.conclusion || 'pending'}\nBranch: ${run.headBranch}\nURL: ${run.url}`,
|
|
224
|
+
timestamp: run.createdAt,
|
|
225
|
+
isPersonal: false,
|
|
226
|
+
significanceType: null,
|
|
227
|
+
workflowRunId: run.id,
|
|
228
|
+
workflowName: run.name,
|
|
229
|
+
workflowStatus: run.conclusion || run.status,
|
|
230
|
+
}))
|
|
231
|
+
|
|
232
|
+
return { entries, count: entries.length, source: 'github_api' }
|
|
233
|
+
}
|
|
234
|
+
} catch {
|
|
235
|
+
// Fallback to DB if GitHub fails
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const rows = execQuery(
|
|
240
|
+
context.db,
|
|
241
|
+
`
|
|
242
|
+
SELECT * FROM memory_journal
|
|
243
|
+
WHERE workflow_run_id IS NOT NULL
|
|
244
|
+
AND deleted_at IS NULL
|
|
245
|
+
ORDER BY timestamp DESC
|
|
246
|
+
LIMIT 10
|
|
247
|
+
`
|
|
248
|
+
)
|
|
249
|
+
const entries = rows.map(transformEntryRow)
|
|
250
|
+
return { entries, count: entries.length, source: 'database' }
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
]
|
|
254
|
+
}
|