memory-journal-mcp 4.3.0 → 4.4.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/.dockerignore +131 -122
- package/.gitattributes +29 -0
- package/.github/workflows/docker-publish.yml +1 -1
- package/.github/workflows/lint-and-test.yml +1 -2
- package/.github/workflows/secrets-scanning.yml +0 -1
- package/.github/workflows/security-update.yml +6 -6
- package/.vscode/settings.json +17 -15
- package/CHANGELOG.md +1065 -11
- package/DOCKER_README.md +51 -33
- package/Dockerfile +14 -12
- package/README.md +68 -33
- package/SECURITY.md +225 -220
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +1 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +70 -26
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/constants/icons.d.ts +2 -0
- package/dist/constants/icons.d.ts.map +1 -1
- package/dist/constants/icons.js +6 -0
- package/dist/constants/icons.js.map +1 -1
- package/dist/database/SqliteAdapter.d.ts +51 -10
- package/dist/database/SqliteAdapter.d.ts.map +1 -1
- package/dist/database/SqliteAdapter.js +143 -43
- package/dist/database/SqliteAdapter.js.map +1 -1
- package/dist/filtering/ToolFilter.d.ts +1 -1
- package/dist/filtering/ToolFilter.d.ts.map +1 -1
- package/dist/filtering/ToolFilter.js +7 -1
- package/dist/filtering/ToolFilter.js.map +1 -1
- package/dist/github/GitHubIntegration.d.ts +74 -2
- package/dist/github/GitHubIntegration.d.ts.map +1 -1
- package/dist/github/GitHubIntegration.js +508 -7
- package/dist/github/GitHubIntegration.js.map +1 -1
- package/dist/handlers/prompts/index.js +1 -0
- package/dist/handlers/prompts/index.js.map +1 -1
- package/dist/handlers/resources/index.d.ts.map +1 -1
- package/dist/handlers/resources/index.js +257 -13
- package/dist/handlers/resources/index.js.map +1 -1
- package/dist/handlers/tools/index.d.ts.map +1 -1
- package/dist/handlers/tools/index.js +595 -8
- package/dist/handlers/tools/index.js.map +1 -1
- package/dist/server/McpServer.d.ts +2 -0
- package/dist/server/McpServer.d.ts.map +1 -1
- package/dist/server/McpServer.js +69 -26
- package/dist/server/McpServer.js.map +1 -1
- package/dist/types/index.d.ts +97 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +8 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/progress-utils.d.ts +18 -3
- package/dist/utils/progress-utils.d.ts.map +1 -1
- package/dist/utils/progress-utils.js.map +1 -1
- package/dist/utils/security-utils.d.ts +91 -0
- package/dist/utils/security-utils.d.ts.map +1 -0
- package/dist/utils/security-utils.js +184 -0
- package/dist/utils/security-utils.js.map +1 -0
- package/dist/vector/VectorSearchManager.d.ts +2 -1
- package/dist/vector/VectorSearchManager.d.ts.map +1 -1
- package/dist/vector/VectorSearchManager.js +100 -34
- package/dist/vector/VectorSearchManager.js.map +1 -1
- package/docker-compose.yml +46 -37
- package/mcp-config-example.json +0 -2
- package/package.json +21 -14
- package/releases/v4.3.1.md +69 -0
- package/releases/v4.4.0.md +120 -0
- package/server.json +3 -3
- package/src/cli.ts +11 -0
- package/src/constants/ServerInstructions.ts +70 -26
- package/src/constants/icons.ts +7 -0
- package/src/database/SqliteAdapter.ts +165 -44
- package/src/filtering/ToolFilter.ts +7 -1
- package/src/github/GitHubIntegration.ts +588 -8
- package/src/handlers/prompts/index.ts +1 -0
- package/src/handlers/resources/index.ts +318 -12
- package/src/handlers/tools/index.ts +686 -13
- package/src/server/McpServer.ts +79 -37
- package/src/types/index.ts +98 -0
- package/src/utils/logger.ts +10 -1
- package/src/utils/progress-utils.ts +17 -6
- package/src/utils/security-utils.ts +205 -0
- package/src/vector/VectorSearchManager.ts +110 -39
- package/tests/constants/icons.test.ts +102 -0
- package/tests/constants/server-instructions.test.ts +549 -0
- package/tests/database/sqlite-adapter.bench.ts +63 -0
- package/tests/database/sqlite-adapter.test.ts +555 -0
- package/tests/filtering/tool-filter.test.ts +266 -0
- package/tests/github/github-integration.test.ts +1024 -0
- package/tests/handlers/github-resource-handlers.test.ts +473 -0
- package/tests/handlers/github-tool-handlers.test.ts +556 -0
- package/tests/handlers/prompt-handlers.test.ts +91 -0
- package/tests/handlers/resource-handlers.test.ts +339 -0
- package/tests/handlers/tool-handlers.test.ts +497 -0
- package/tests/handlers/vector-tool-handlers.test.ts +238 -0
- package/tests/security/sql-injection.test.ts +347 -0
- package/tests/server/mcp-server.bench.ts +55 -0
- package/tests/server/mcp-server.test.ts +675 -0
- package/tests/utils/logger.test.ts +180 -0
- package/tests/utils/mcp-logger.test.ts +212 -0
- package/tests/utils/progress-utils.test.ts +156 -0
- package/tests/utils/security-utils.test.ts +82 -0
- package/tests/vector/vector-search-manager.test.ts +335 -0
- package/tests/vector/vector-search.bench.ts +53 -0
- package/vitest.config.ts +15 -0
- package/.github/workflows/DOCKER_DEPLOYMENT_SETUP.md +0 -387
- package/.github/workflows/dependabot-auto-merge.yml +0 -42
package/src/cli.ts
CHANGED
|
@@ -15,37 +15,47 @@ program
|
|
|
15
15
|
.version(pkg.version)
|
|
16
16
|
.option('--transport <type>', 'Transport type: stdio or http', 'stdio')
|
|
17
17
|
.option('--port <number>', 'HTTP port (for http transport)', '3000')
|
|
18
|
+
.option('--server-host <host>', 'Server bind host for HTTP transport (default: localhost)')
|
|
18
19
|
.option('--stateless', 'Use stateless HTTP mode (no session management)')
|
|
19
20
|
.option('--db <path>', 'Database path', './memory_journal.db')
|
|
20
21
|
.option('--tool-filter <filter>', 'Tool filter string (e.g., "starter", "core,search")')
|
|
21
22
|
.option('--default-project <number>', 'Default GitHub Project number')
|
|
22
23
|
.option('--auto-rebuild-index', 'Rebuild vector index on server startup')
|
|
24
|
+
.option('--cors-origin <origin>', 'CORS allowed origin for HTTP transport (default: *)')
|
|
23
25
|
.option('--log-level <level>', 'Log level: debug, info, warning, error', 'info')
|
|
24
26
|
.action(
|
|
25
27
|
async (options: {
|
|
26
28
|
transport: string
|
|
27
29
|
port: string
|
|
30
|
+
serverHost?: string
|
|
28
31
|
stateless?: boolean
|
|
29
32
|
db: string
|
|
30
33
|
toolFilter?: string
|
|
31
34
|
defaultProject: string
|
|
32
35
|
autoRebuildIndex?: boolean
|
|
36
|
+
corsOrigin?: string
|
|
33
37
|
logLevel: string
|
|
34
38
|
}) => {
|
|
35
39
|
// Set log level
|
|
36
40
|
logger.setLevel(options.logLevel as 'debug' | 'info' | 'warning' | 'error')
|
|
37
41
|
|
|
42
|
+
// Resolve host: CLI flag > env var > default (localhost)
|
|
43
|
+
const host =
|
|
44
|
+
options.serverHost ?? process.env['MCP_HOST'] ?? process.env['HOST'] ?? undefined
|
|
45
|
+
|
|
38
46
|
logger.info('Starting Memory Journal MCP Server', {
|
|
39
47
|
module: 'CLI',
|
|
40
48
|
transport: options.transport,
|
|
41
49
|
stateless: options.stateless ?? false,
|
|
42
50
|
db: options.db,
|
|
51
|
+
...(host ? { host } : {}),
|
|
43
52
|
})
|
|
44
53
|
|
|
45
54
|
try {
|
|
46
55
|
await createServer({
|
|
47
56
|
transport: options.transport as 'stdio' | 'http',
|
|
48
57
|
port: parseInt(options.port, 10),
|
|
58
|
+
host,
|
|
49
59
|
statelessHttp: options.stateless === true,
|
|
50
60
|
dbPath: options.db,
|
|
51
61
|
toolFilter: options.toolFilter,
|
|
@@ -56,6 +66,7 @@ program
|
|
|
56
66
|
: undefined,
|
|
57
67
|
autoRebuildIndex:
|
|
58
68
|
options.autoRebuildIndex ?? process.env['AUTO_REBUILD_INDEX'] === 'true',
|
|
69
|
+
corsOrigin: options.corsOrigin,
|
|
59
70
|
})
|
|
60
71
|
} catch (error) {
|
|
61
72
|
logger.error('Failed to start server', {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* These instructions are automatically sent to MCP clients during initialization,
|
|
5
5
|
* providing guidance for AI agents on tool usage.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Unreleased: Optimized for token efficiency with tiered instruction levels.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ToolGroup } from '../types/index.js'
|
|
@@ -80,6 +80,7 @@ const GITHUB_INSTRUCTIONS = `
|
|
|
80
80
|
- After closing issue/merging PR → create summary entry with learnings
|
|
81
81
|
- CI failures → \`actions-failure-digest\` prompt or \`memory://actions/recent\`
|
|
82
82
|
- Kanban: \`get_kanban_board(project_number)\` → \`move_kanban_item\` → document completion
|
|
83
|
+
- Milestones: \`get_github_milestones\` → track project progress, \`memory://github/milestones\`
|
|
83
84
|
- GitHub tools auto-detect owner/repo from git context; specify explicitly if null
|
|
84
85
|
`
|
|
85
86
|
|
|
@@ -122,10 +123,10 @@ const TOOL_PARAMETER_REFERENCE = `
|
|
|
122
123
|
### Entry Operations
|
|
123
124
|
| Tool | Required Parameters | Optional Parameters |
|
|
124
125
|
|------|---------------------|---------------------|
|
|
125
|
-
| \`create_entry\` | \`content\` (string) | \`entry_type\`, \`tags\` (array), \`is_personal\`
|
|
126
|
+
| \`create_entry\` | \`content\` (string) | \`entry_type\`, \`tags\` (array), \`is_personal\`, \`significance_type\`, \`share_with_team\`, \`auto_context\`, \`issue_number\`, \`issue_url\`, \`pr_number\`, \`pr_url\`, \`pr_status\`, \`project_number\`, \`project_owner\`, \`workflow_run_id\`, \`workflow_name\`, \`workflow_status\` |
|
|
126
127
|
| \`create_entry_minimal\` | \`content\` (string) | none |
|
|
127
|
-
| \`get_entry_by_id\` | \`entry_id\` (number) |
|
|
128
|
-
| \`get_recent_entries\` | none | \`limit\` (default
|
|
128
|
+
| \`get_entry_by_id\` | \`entry_id\` (number) | \`include_relationships\` (bool, default true) |
|
|
129
|
+
| \`get_recent_entries\` | none | \`limit\` (default 5), \`is_personal\` (bool) |
|
|
129
130
|
| \`update_entry\` | \`entry_id\` (number) | \`content\`, \`tags\`, \`entry_type\`, \`is_personal\` |
|
|
130
131
|
| \`delete_entry\` | \`entry_id\` (number) | \`permanent\` (bool, default false) |
|
|
131
132
|
| \`list_tags\` | none | none |
|
|
@@ -133,33 +134,40 @@ const TOOL_PARAMETER_REFERENCE = `
|
|
|
133
134
|
### Search Tools
|
|
134
135
|
| Tool | Required Parameters | Optional Parameters |
|
|
135
136
|
|------|---------------------|---------------------|
|
|
136
|
-
| \`search_entries\` | \`query\`
|
|
137
|
-
| \`search_by_date_range\` | \`start_date\`, \`end_date\` (YYYY-MM-DD) | \`tags\`, \`entry_type\` |
|
|
138
|
-
| \`semantic_search\` | \`query\` (string) | \`limit\`, \`similarity_threshold\` (default 0.
|
|
137
|
+
| \`search_entries\` | none | \`query\`, \`limit\`, \`is_personal\`, \`issue_number\`, \`pr_number\`, \`pr_status\`, \`project_number\`, \`workflow_run_id\` |
|
|
138
|
+
| \`search_by_date_range\` | \`start_date\`, \`end_date\` (YYYY-MM-DD) | \`tags\`, \`entry_type\`, \`is_personal\`, \`issue_number\`, \`pr_number\`, \`project_number\`, \`workflow_run_id\` |
|
|
139
|
+
| \`semantic_search\` | \`query\` (string) | \`limit\`, \`similarity_threshold\` (default 0.25), \`is_personal\`, \`hint_on_empty\` (bool, default true) |
|
|
139
140
|
| \`get_vector_index_stats\` | none | none |
|
|
140
141
|
|
|
141
142
|
### Relationship Tools
|
|
142
143
|
| Tool | Required Parameters | Notes |
|
|
143
144
|
|------|---------------------|-------|
|
|
144
|
-
| \`link_entries\` | \`from_entry_id\`, \`to_entry_id\` (numbers) | Types: \`evolves_from\`, \`references\`, \`implements\`, \`clarifies\`, \`response_to\`, \`blocked_by\`, \`resolved\`, \`caused\` |
|
|
145
|
-
| \`visualize_relationships\` | \`entry_id\` (
|
|
145
|
+
| \`link_entries\` | \`from_entry_id\`, \`to_entry_id\` (numbers) | Types: \`evolves_from\`, \`references\`, \`implements\`, \`clarifies\`, \`response_to\`, \`blocked_by\`, \`resolved\`, \`caused\`. Optional \`description\`. |
|
|
146
|
+
| \`visualize_relationships\` | none | Optional \`entry_id\`, \`tags\` (array), \`depth\` (1-3, default 2), \`limit\` (default 20). Returns Mermaid diagram. |
|
|
146
147
|
|
|
147
148
|
### GitHub Tools
|
|
148
149
|
| Tool | Required Parameters | Notes |
|
|
149
150
|
|------|---------------------|-------|
|
|
150
|
-
| \`get_github_context\` | none | Returns repo info, open issues/PRs |
|
|
151
|
-
| \`get_github_issues\` | none | Optional \`state\` (open/closed/all), \`limit\` |
|
|
152
|
-
| \`get_github_prs\` | none | Optional \`state\`, \`limit\` |
|
|
153
|
-
| \`get_github_issue\` | \`issue_number\` (number) | Fetches single issue details |
|
|
154
|
-
| \`get_github_pr\` | \`pr_number\` (number) | Fetches single PR details |
|
|
151
|
+
| \`get_github_context\` | none | Returns repo info, open issues/PRs. Only counts OPEN items. |
|
|
152
|
+
| \`get_github_issues\` | none | Optional \`state\` (open/closed/all), \`limit\`, \`owner\`, \`repo\` |
|
|
153
|
+
| \`get_github_prs\` | none | Optional \`state\`, \`limit\`, \`owner\`, \`repo\` |
|
|
154
|
+
| \`get_github_issue\` | \`issue_number\` (number) | Optional \`owner\`, \`repo\`. Fetches single issue details. |
|
|
155
|
+
| \`get_github_pr\` | \`pr_number\` (number) | Optional \`owner\`, \`repo\`. Fetches single PR details. |
|
|
156
|
+
| \`get_repo_insights\` | none | Optional \`sections\` (stars/traffic/referrers/paths/all, default "stars"), \`owner\`, \`repo\`. Requires push access for traffic. |
|
|
155
157
|
|
|
156
158
|
GitHub tools auto-detect owner/repo from GITHUB_REPO_PATH. If \`detectedOwner\`/\`detectedRepo\` are null in response, specify \`owner\` and \`repo\` parameters explicitly.
|
|
157
159
|
|
|
160
|
+
### Issue Lifecycle Tools
|
|
161
|
+
| Tool | Required Parameters | Notes |
|
|
162
|
+
|------|---------------------|-------|
|
|
163
|
+
| \`create_github_issue_with_entry\` | \`title\` (string) | Optional \`body\`, \`labels\` (array), \`assignees\` (array), \`project_number\`, \`initial_status\`, \`milestone_number\`, \`entry_content\`, \`tags\`, \`owner\`, \`repo\` |
|
|
164
|
+
| \`close_github_issue_with_entry\` | \`issue_number\` (number) | Optional \`comment\`, \`resolution_notes\`, \`tags\`, \`move_to_done\` (bool), \`project_number\`, \`owner\`, \`repo\` |
|
|
165
|
+
|
|
158
166
|
### Kanban Tools (GitHub Projects v2)
|
|
159
167
|
| Tool | Required Parameters | Notes |
|
|
160
168
|
|------|---------------------|-------|
|
|
161
|
-
| \`get_kanban_board\` | \`project_number\` (number) | Returns columns with items grouped by Status |
|
|
162
|
-
| \`move_kanban_item\` | \`project_number\`, \`item_id\` (string), \`target_status\` (string) | \`item_id\` is the GraphQL node ID from board items |
|
|
169
|
+
| \`get_kanban_board\` | \`project_number\` (number) | Optional \`owner\`. Returns columns with items grouped by Status |
|
|
170
|
+
| \`move_kanban_item\` | \`project_number\`, \`item_id\` (string), \`target_status\` (string) | Optional \`owner\`. \`item_id\` is the GraphQL node ID from board items. Status matching is case-insensitive. |
|
|
163
171
|
|
|
164
172
|
**Finding the right project**: User may have multiple projects. Use \`get_kanban_board\` with different project numbers (1, 2, 3...) to find the correct one by checking \`projectTitle\`.
|
|
165
173
|
|
|
@@ -176,33 +184,53 @@ Kanban resources:
|
|
|
176
184
|
- \`memory://kanban/{project_number}\` - JSON board data
|
|
177
185
|
- \`memory://kanban/{project_number}/diagram\` - Mermaid visualization
|
|
178
186
|
|
|
187
|
+
### Milestone Tools
|
|
188
|
+
| Tool | Required Parameters | Notes |
|
|
189
|
+
|------|---------------------|-------|
|
|
190
|
+
| \`get_github_milestones\` | none | Optional \`state\` (open/closed/all), \`limit\`, \`owner\`, \`repo\` |
|
|
191
|
+
| \`get_github_milestone\` | \`milestone_number\` (number) | Optional \`owner\`, \`repo\`. Single milestone with completion %. |
|
|
192
|
+
| \`create_github_milestone\` | \`title\` (string) | Optional \`description\`, \`due_on\` (YYYY-MM-DD), \`owner\`, \`repo\` |
|
|
193
|
+
| \`update_github_milestone\` | \`milestone_number\` (number) | Optional \`title\`, \`description\`, \`due_on\`, \`state\` (open/closed), \`owner\`, \`repo\` |
|
|
194
|
+
| \`delete_github_milestone\` | \`milestone_number\`, \`confirm: true\` | Optional \`owner\`, \`repo\`. Permanent deletion. |
|
|
195
|
+
|
|
196
|
+
Milestone resources:
|
|
197
|
+
- \`memory://github/milestones\` - Open milestones with completion %
|
|
198
|
+
- \`memory://milestones/{number}\` - Single milestone detail
|
|
199
|
+
|
|
179
200
|
### Admin Tools
|
|
180
201
|
| Tool | Required Parameters | Notes |
|
|
181
202
|
|------|---------------------|-------|
|
|
182
|
-
| \`backup_journal\` | none | Optional \`
|
|
203
|
+
| \`backup_journal\` | none | Optional \`name\` (custom backup name) |
|
|
183
204
|
| \`list_backups\` | none | Returns available backup files |
|
|
184
|
-
| \`
|
|
205
|
+
| \`cleanup_backups\` | none | Optional \`keep_count\` (default 5). Deletes old backups, keeps N most recent. |
|
|
206
|
+
| \`restore_backup\` | \`filename\`, \`confirm: true\` | Creates auto-backup before restore |
|
|
185
207
|
| \`add_to_vector_index\` | \`entry_id\` (single number) | Indexes one entry for semantic search |
|
|
186
208
|
| \`rebuild_vector_index\` | none | Re-indexes all entries |
|
|
187
209
|
|
|
188
210
|
### Export Tools
|
|
189
211
|
| Tool | Required Parameters | Notes |
|
|
190
212
|
|------|---------------------|-------|
|
|
191
|
-
| \`export_entries\` | none | Optional \`format\` (json/markdown), \`limit
|
|
213
|
+
| \`export_entries\` | none | Optional \`format\` (json/markdown), \`limit\` (default 100), \`tags\`, \`start_date\`, \`end_date\`, \`entry_types\` |
|
|
192
214
|
|
|
193
215
|
## Entry Types
|
|
194
216
|
Valid values for \`entry_type\` parameter:
|
|
195
217
|
- \`personal_reflection\` (default) - Personal thoughts and notes
|
|
196
|
-
- \`
|
|
218
|
+
- \`project_decision\` - Architectural and team decisions
|
|
219
|
+
- \`technical_achievement\` - Milestones and breakthroughs
|
|
197
220
|
- \`bug_fix\` - Bug fixes and resolutions
|
|
198
|
-
- \`
|
|
221
|
+
- \`feature_implementation\` - Feature builds and rollouts
|
|
199
222
|
- \`code_review\` - Code review notes
|
|
200
|
-
- \`
|
|
201
|
-
- \`
|
|
223
|
+
- \`meeting_notes\` - Meeting summaries
|
|
224
|
+
- \`learning\` - Learning and research insights
|
|
225
|
+
- \`research\` - Research and exploration
|
|
226
|
+
- \`planning\` - Planning sessions and roadmaps (\`create_github_issue_with_entry\` uses this type)
|
|
227
|
+
- \`retrospective\` - Sprint and project retrospectives
|
|
228
|
+
- \`standup\` - Daily standup notes
|
|
229
|
+
- \`other\` - Miscellaneous
|
|
202
230
|
|
|
203
231
|
## Field Notes
|
|
204
232
|
- **\`autoContext\`**: Reserved for future automatic context capture. Currently always \`null\`.
|
|
205
|
-
- **\`memory://tags\` vs \`list_tags\`**: Resource includes \`id\`, \`name\`, \`count\`; tool returns only \`name\`, \`count\`.
|
|
233
|
+
- **\`memory://tags\` vs \`list_tags\`**: Resource includes \`id\`, \`name\`, \`count\`; tool returns only \`name\`, \`count\`. Neither returns orphan tags with zero usage.
|
|
206
234
|
- **Tag naming**: Use lowercase with dashes (e.g., \`bug-fix\`, \`phase-2\`). Use \`merge_tags\` to consolidate duplicates (e.g., merge \`phase2\` into \`phase-2\`).
|
|
207
235
|
- **\`merge_tags\` behavior**: Only updates non-deleted entries. Deleted entries retain their original tags.
|
|
208
236
|
- **\`prStatus\` in entries**: Reflects PR state at entry creation time, not current state. Use \`get_github_pr\` for live status.
|
|
@@ -211,19 +239,35 @@ Valid values for \`entry_type\` parameter:
|
|
|
211
239
|
- **\`semantic_search\` thresholds**: Default similarity threshold is 0.25. For broader matches, try 0.15-0.2. Higher values (0.4+) return only very close semantic matches.
|
|
212
240
|
- **Causal relationship types**: Use \`blocked_by\` (A was blocked by B), \`resolved\` (A resolved B), \`caused\` (A caused B) for decision tracing and failure analysis. Visualizations use distinct arrow styles for causal types.
|
|
213
241
|
- **Enhanced analytics**: \`get_statistics\` returns \`decisionDensity\` (significant entries per period), \`relationshipComplexity\` (avg relationships per entry), \`activityTrend\` (period-over-period growth %), and \`causalMetrics\` (counts for blocked_by/resolved/caused).
|
|
214
|
-
- **Importance scores**: \`get_entry_by_id\` returns
|
|
242
|
+
- **Importance scores**: \`get_entry_by_id\` returns \`importance\` (0.0-1.0) and \`importanceBreakdown\` showing weighted components: significance (30%), relationships (35%), causal (20%), recency (15%). \`memory://significant\` sorts entries by importance.
|
|
243
|
+
- **\`inactiveThresholdDays\`**: \`get_cross_project_insights\` includes \`inactiveThresholdDays: 7\` in output, documenting the inactive project classification cutoff.
|
|
244
|
+
- **GitHub metadata in entries**: Entry output includes 10 GitHub fields (\`issueNumber\`, \`issueUrl\`, \`prNumber\`, \`prUrl\`, \`prStatus\`, \`projectNumber\`, \`projectOwner\`, \`workflowRunId\`, \`workflowName\`, \`workflowStatus\`) in all tool responses.
|
|
245
|
+
- **\`delete_entry\` on soft-deleted**: \`delete_entry(id, permanent: true)\` works on previously soft-deleted entries. Returns \`success: false\` for nonexistent entries.
|
|
215
246
|
|
|
216
247
|
## Key Resources
|
|
217
248
|
| URI | Description |
|
|
218
249
|
|-----|-------------|
|
|
219
250
|
| \`memory://health\` | Server health, DB stats, tool filter status |
|
|
220
251
|
| \`memory://briefing\` | Session context with userMessage to show user |
|
|
252
|
+
| \`memory://instructions\` | Full server instructions and tool reference |
|
|
221
253
|
| \`memory://statistics\` | Entry counts by type and period |
|
|
222
254
|
| \`memory://recent\` | 10 most recent entries |
|
|
223
255
|
| \`memory://tags\` | All tags with usage counts |
|
|
224
|
-
| \`memory://significant\` | Entries
|
|
256
|
+
| \`memory://significant\` | Entries sorted by importance score |
|
|
225
257
|
| \`memory://graph/recent\` | Mermaid diagram of recent relationships |
|
|
258
|
+
| \`memory://graph/actions\` | CI/CD narrative graph |
|
|
259
|
+
| \`memory://actions/recent\` | Recent workflow runs |
|
|
260
|
+
| \`memory://team/recent\` | Team-shared entries |
|
|
261
|
+
| \`memory://github/status\` | GitHub repo overview (CI, issues, PRs, milestones) |
|
|
262
|
+
| \`memory://github/milestones\` | Open milestones with completion % |
|
|
263
|
+
| \`memory://github/insights\` | Stars, forks, and 14-day traffic summary |
|
|
226
264
|
| \`memory://kanban/{n}\` | Kanban board for project number n |
|
|
265
|
+
| \`memory://kanban/{n}/diagram\` | Mermaid Kanban visualization |
|
|
266
|
+
| \`memory://milestones/{n}\` | Single milestone detail + progress |
|
|
267
|
+
| \`memory://projects/{n}/timeline\` | Project entries timeline |
|
|
268
|
+
| \`memory://issues/{n}/entries\` | Entries linked to issue n |
|
|
269
|
+
| \`memory://prs/{n}/entries\` | Entries linked to PR n |
|
|
270
|
+
| \`memory://prs/{n}/timeline\` | PR lifecycle and linked entries |
|
|
227
271
|
`
|
|
228
272
|
|
|
229
273
|
/**
|
package/src/constants/icons.ts
CHANGED
|
@@ -143,6 +143,13 @@ export const ICON_PR: McpIcon = {
|
|
|
143
143
|
sizes: ['24x24'],
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/** Flag for milestone tracking */
|
|
147
|
+
export const ICON_MILESTONE: McpIcon = {
|
|
148
|
+
src: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"%3E%3Cpath d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/%3E%3Cline x1="4" y1="22" x2="4" y2="15"/%3E%3C/svg%3E',
|
|
149
|
+
mimeType: 'image/svg+xml',
|
|
150
|
+
sizes: ['24x24'],
|
|
151
|
+
}
|
|
152
|
+
|
|
146
153
|
/** Message bubble for prompts */
|
|
147
154
|
export const ICON_PROMPT: McpIcon = {
|
|
148
155
|
src: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"%3E%3Cpath d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/%3E%3C/svg%3E',
|
|
@@ -9,6 +9,7 @@ import initSqlJs, { type Database } from 'sql.js'
|
|
|
9
9
|
import * as fs from 'node:fs'
|
|
10
10
|
import * as path from 'node:path'
|
|
11
11
|
import { logger } from '../utils/logger.js'
|
|
12
|
+
import { validateDateFormatPattern } from '../utils/security-utils.js'
|
|
12
13
|
import type {
|
|
13
14
|
JournalEntry,
|
|
14
15
|
Tag,
|
|
@@ -16,6 +17,8 @@ import type {
|
|
|
16
17
|
EntryType,
|
|
17
18
|
SignificanceType,
|
|
18
19
|
RelationshipType,
|
|
20
|
+
ImportanceBreakdown,
|
|
21
|
+
ImportanceResult,
|
|
19
22
|
} from '../types/index.js'
|
|
20
23
|
|
|
21
24
|
// Schema SQL for initialization
|
|
@@ -124,6 +127,12 @@ export class SqliteAdapter {
|
|
|
124
127
|
private readonly dbPath: string
|
|
125
128
|
private initialized = false
|
|
126
129
|
|
|
130
|
+
/** Timer handle for debounced save */
|
|
131
|
+
private saveTimer: ReturnType<typeof setTimeout> | null = null
|
|
132
|
+
|
|
133
|
+
/** Debounce interval for batching disk writes (ms) */
|
|
134
|
+
private static readonly SAVE_DEBOUNCE_MS = 500
|
|
135
|
+
|
|
127
136
|
constructor(dbPath: string) {
|
|
128
137
|
this.dbPath = dbPath
|
|
129
138
|
}
|
|
@@ -163,14 +172,34 @@ export class SqliteAdapter {
|
|
|
163
172
|
|
|
164
173
|
logger.info('Database opened', { module: 'SqliteAdapter', dbPath: this.dbPath })
|
|
165
174
|
|
|
166
|
-
//
|
|
167
|
-
this.
|
|
175
|
+
// Immediate flush after initialization to persist schema
|
|
176
|
+
this.flushSave()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Schedule a debounced save to disk.
|
|
181
|
+
* Batches rapid mutations into a single write after SAVE_DEBOUNCE_MS.
|
|
182
|
+
* Used by all mutation methods (createEntry, updateEntry, etc.).
|
|
183
|
+
*/
|
|
184
|
+
private scheduleSave(): void {
|
|
185
|
+
if (this.saveTimer !== null) {
|
|
186
|
+
clearTimeout(this.saveTimer)
|
|
187
|
+
}
|
|
188
|
+
this.saveTimer = setTimeout(() => {
|
|
189
|
+
this.flushSave()
|
|
190
|
+
}, SqliteAdapter.SAVE_DEBOUNCE_MS)
|
|
168
191
|
}
|
|
169
192
|
|
|
170
193
|
/**
|
|
171
|
-
*
|
|
194
|
+
* Immediately flush the database to disk (synchronous).
|
|
195
|
+
* Cancels any pending debounced save.
|
|
196
|
+
* Used by close() and initialize() for guaranteed persistence.
|
|
172
197
|
*/
|
|
173
|
-
|
|
198
|
+
flushSave(): void {
|
|
199
|
+
if (this.saveTimer !== null) {
|
|
200
|
+
clearTimeout(this.saveTimer)
|
|
201
|
+
this.saveTimer = null
|
|
202
|
+
}
|
|
174
203
|
if (!this.db) return
|
|
175
204
|
const data = this.db.export()
|
|
176
205
|
const buffer = Buffer.from(data)
|
|
@@ -178,11 +207,12 @@ export class SqliteAdapter {
|
|
|
178
207
|
}
|
|
179
208
|
|
|
180
209
|
/**
|
|
181
|
-
* Close database connection
|
|
210
|
+
* Close database connection.
|
|
211
|
+
* Flushes any pending writes immediately before closing.
|
|
182
212
|
*/
|
|
183
213
|
close(): void {
|
|
184
214
|
if (this.db) {
|
|
185
|
-
this.
|
|
215
|
+
this.flushSave()
|
|
186
216
|
this.db.close()
|
|
187
217
|
this.db = null
|
|
188
218
|
}
|
|
@@ -263,7 +293,7 @@ export class SqliteAdapter {
|
|
|
263
293
|
this.linkTagsToEntry(entryId, tags)
|
|
264
294
|
}
|
|
265
295
|
|
|
266
|
-
this.
|
|
296
|
+
this.scheduleSave()
|
|
267
297
|
|
|
268
298
|
logger.info('Entry created', {
|
|
269
299
|
module: 'SqliteAdapter',
|
|
@@ -296,30 +326,65 @@ export class SqliteAdapter {
|
|
|
296
326
|
return this.rowToEntry(row)
|
|
297
327
|
}
|
|
298
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Get entry by ID, including soft-deleted entries.
|
|
331
|
+
* Used for permanent deletion of previously soft-deleted entries.
|
|
332
|
+
*/
|
|
333
|
+
getEntryByIdIncludeDeleted(id: number): JournalEntry | null {
|
|
334
|
+
const db = this.ensureDb()
|
|
335
|
+
const result = db.exec(`SELECT * FROM memory_journal WHERE id = ?`, [id])
|
|
336
|
+
|
|
337
|
+
if (result.length === 0 || result[0]?.values.length === 0) return null
|
|
338
|
+
|
|
339
|
+
const columns = result[0]?.columns ?? []
|
|
340
|
+
const values = result[0]?.values[0] ?? []
|
|
341
|
+
const row = this.rowToObject(columns, values)
|
|
342
|
+
|
|
343
|
+
return this.rowToEntry(row)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Importance score result with scoring breakdown
|
|
348
|
+
*/
|
|
349
|
+
static readonly IMPORTANCE_WEIGHTS = {
|
|
350
|
+
significance: 0.3,
|
|
351
|
+
relationships: 0.35,
|
|
352
|
+
causal: 0.2,
|
|
353
|
+
recency: 0.15,
|
|
354
|
+
} as const
|
|
355
|
+
|
|
299
356
|
/**
|
|
300
357
|
* Calculate importance score for an entry (0.0-1.0)
|
|
301
358
|
*
|
|
302
359
|
* Formula:
|
|
303
|
-
* -
|
|
304
|
-
* -
|
|
305
|
-
* -
|
|
306
|
-
* -
|
|
360
|
+
* - significance (0.30): 1.0 if significanceType set, else 0.0
|
|
361
|
+
* - relationships (0.35): min(relCount / 5, 1.0)
|
|
362
|
+
* - causal (0.20): min(causalCount / 3, 1.0)
|
|
363
|
+
* - recency (0.15): max(0, 1 - daysSince / 90)
|
|
364
|
+
*
|
|
365
|
+
* Returns ImportanceResult with score and component breakdown.
|
|
307
366
|
*/
|
|
308
|
-
calculateImportance(entryId: number):
|
|
367
|
+
calculateImportance(entryId: number): ImportanceResult {
|
|
309
368
|
const db = this.ensureDb()
|
|
369
|
+
const round2 = (n: number): number => Math.round(n * 100) / 100
|
|
310
370
|
|
|
311
371
|
// Get entry data
|
|
312
372
|
const entryResult = db.exec(
|
|
313
373
|
`SELECT significance_type, timestamp FROM memory_journal WHERE id = ? AND deleted_at IS NULL`,
|
|
314
374
|
[entryId]
|
|
315
375
|
)
|
|
316
|
-
if (entryResult.length === 0 || entryResult[0]?.values.length === 0)
|
|
376
|
+
if (entryResult.length === 0 || entryResult[0]?.values.length === 0) {
|
|
377
|
+
return {
|
|
378
|
+
score: 0,
|
|
379
|
+
breakdown: { significance: 0, relationships: 0, causal: 0, recency: 0 },
|
|
380
|
+
}
|
|
381
|
+
}
|
|
317
382
|
|
|
318
383
|
const significanceType = entryResult[0]?.values[0]?.[0] as string | null
|
|
319
384
|
const timestamp = entryResult[0]?.values[0]?.[1] as string
|
|
320
385
|
|
|
321
386
|
// Significance weight: 1.0 if set, else 0.0
|
|
322
|
-
const
|
|
387
|
+
const significanceRaw = significanceType ? 1.0 : 0.0
|
|
323
388
|
|
|
324
389
|
// Relationship count (total relationships involving this entry)
|
|
325
390
|
const relResult = db.exec(
|
|
@@ -327,7 +392,7 @@ export class SqliteAdapter {
|
|
|
327
392
|
[entryId, entryId]
|
|
328
393
|
)
|
|
329
394
|
const relCount = (relResult[0]?.values[0]?.[0] as number) ?? 0
|
|
330
|
-
const
|
|
395
|
+
const relationshipsRaw = Math.min(relCount / 5, 1.0)
|
|
331
396
|
|
|
332
397
|
// Causal relationships count
|
|
333
398
|
const causalResult = db.exec(
|
|
@@ -337,23 +402,33 @@ export class SqliteAdapter {
|
|
|
337
402
|
[entryId, entryId]
|
|
338
403
|
)
|
|
339
404
|
const causalCount = (causalResult[0]?.values[0]?.[0] as number) ?? 0
|
|
340
|
-
const
|
|
405
|
+
const causalRaw = Math.min(causalCount / 3, 1.0)
|
|
341
406
|
|
|
342
407
|
// Recency weight: decays over 90 days
|
|
343
408
|
const entryDate = new Date(timestamp)
|
|
344
409
|
const now = new Date()
|
|
345
410
|
const daysSince = Math.floor((now.getTime() - entryDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
346
|
-
const
|
|
411
|
+
const recencyRaw = Math.max(0, 1 - daysSince / 90)
|
|
347
412
|
|
|
348
|
-
|
|
349
|
-
const importance =
|
|
350
|
-
significanceWeight * 0.3 +
|
|
351
|
-
relationshipWeight * 0.35 +
|
|
352
|
-
causalWeight * 0.2 +
|
|
353
|
-
recencyWeight * 0.15
|
|
413
|
+
const w = SqliteAdapter.IMPORTANCE_WEIGHTS
|
|
354
414
|
|
|
355
|
-
//
|
|
356
|
-
|
|
415
|
+
// Weighted contributions
|
|
416
|
+
const breakdown: ImportanceBreakdown = {
|
|
417
|
+
significance: round2(significanceRaw * w.significance),
|
|
418
|
+
relationships: round2(relationshipsRaw * w.relationships),
|
|
419
|
+
causal: round2(causalRaw * w.causal),
|
|
420
|
+
recency: round2(recencyRaw * w.recency),
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Total score
|
|
424
|
+
const score = round2(
|
|
425
|
+
significanceRaw * w.significance +
|
|
426
|
+
relationshipsRaw * w.relationships +
|
|
427
|
+
causalRaw * w.causal +
|
|
428
|
+
recencyRaw * w.recency
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
return { score, breakdown }
|
|
357
432
|
}
|
|
358
433
|
|
|
359
434
|
/**
|
|
@@ -381,6 +456,34 @@ export class SqliteAdapter {
|
|
|
381
456
|
)
|
|
382
457
|
}
|
|
383
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Get a page of active entries for batch processing (e.g., vector index rebuild).
|
|
461
|
+
* Returns entries ordered by ID ascending for deterministic pagination.
|
|
462
|
+
*/
|
|
463
|
+
getEntriesPage(offset: number, limit: number): JournalEntry[] {
|
|
464
|
+
const db = this.ensureDb()
|
|
465
|
+
const result = db.exec(
|
|
466
|
+
`SELECT * FROM memory_journal WHERE deleted_at IS NULL ORDER BY id ASC LIMIT ? OFFSET ?`,
|
|
467
|
+
[limit, offset]
|
|
468
|
+
)
|
|
469
|
+
if (result.length === 0) return []
|
|
470
|
+
|
|
471
|
+
const columns = result[0]?.columns ?? []
|
|
472
|
+
return (result[0]?.values ?? []).map((values) =>
|
|
473
|
+
this.rowToEntry(this.rowToObject(columns, values))
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Get total count of active (non-deleted) entries.
|
|
479
|
+
* Used for progress reporting and pagination bounds.
|
|
480
|
+
*/
|
|
481
|
+
getActiveEntryCount(): number {
|
|
482
|
+
const db = this.ensureDb()
|
|
483
|
+
const result = db.exec(`SELECT COUNT(*) FROM memory_journal WHERE deleted_at IS NULL`)
|
|
484
|
+
return (result[0]?.values[0]?.[0] as number) ?? 0
|
|
485
|
+
}
|
|
486
|
+
|
|
384
487
|
/**
|
|
385
488
|
* Update an entry
|
|
386
489
|
*/
|
|
@@ -424,7 +527,7 @@ export class SqliteAdapter {
|
|
|
424
527
|
this.linkTagsToEntry(id, updates.tags)
|
|
425
528
|
}
|
|
426
529
|
|
|
427
|
-
this.
|
|
530
|
+
this.scheduleSave()
|
|
428
531
|
|
|
429
532
|
logger.info('Entry updated', {
|
|
430
533
|
module: 'SqliteAdapter',
|
|
@@ -437,17 +540,23 @@ export class SqliteAdapter {
|
|
|
437
540
|
|
|
438
541
|
/**
|
|
439
542
|
* Soft delete an entry
|
|
543
|
+
* Returns false if entry does not exist (P154: Proactive Object Existence Verification)
|
|
440
544
|
*/
|
|
441
545
|
deleteEntry(id: number, permanent = false): boolean {
|
|
442
546
|
const db = this.ensureDb()
|
|
443
547
|
|
|
548
|
+
// P154: Pre-check entry existence before mutation
|
|
549
|
+
// For permanent deletion, also look through soft-deleted entries
|
|
550
|
+
const entry = permanent ? this.getEntryByIdIncludeDeleted(id) : this.getEntryById(id)
|
|
551
|
+
if (!entry) return false
|
|
552
|
+
|
|
444
553
|
if (permanent) {
|
|
445
554
|
db.run('DELETE FROM memory_journal WHERE id = ?', [id])
|
|
446
555
|
} else {
|
|
447
556
|
db.run(`UPDATE memory_journal SET deleted_at = datetime('now') WHERE id = ?`, [id])
|
|
448
557
|
}
|
|
449
558
|
|
|
450
|
-
this.
|
|
559
|
+
this.scheduleSave()
|
|
451
560
|
return true
|
|
452
561
|
}
|
|
453
562
|
|
|
@@ -609,11 +718,11 @@ export class SqliteAdapter {
|
|
|
609
718
|
}
|
|
610
719
|
|
|
611
720
|
/**
|
|
612
|
-
* List all tags
|
|
721
|
+
* List all tags with at least one usage
|
|
613
722
|
*/
|
|
614
723
|
listTags(): Tag[] {
|
|
615
724
|
const db = this.ensureDb()
|
|
616
|
-
const result = db.exec('SELECT * FROM tags ORDER BY usage_count DESC')
|
|
725
|
+
const result = db.exec('SELECT * FROM tags WHERE usage_count > 0 ORDER BY usage_count DESC')
|
|
617
726
|
|
|
618
727
|
if (result.length === 0) return []
|
|
619
728
|
|
|
@@ -690,7 +799,7 @@ export class SqliteAdapter {
|
|
|
690
799
|
db.run('DELETE FROM entry_tags WHERE tag_id = ?', [sourceTagId])
|
|
691
800
|
db.run('DELETE FROM tags WHERE id = ?', [sourceTagId])
|
|
692
801
|
|
|
693
|
-
this.
|
|
802
|
+
this.scheduleSave()
|
|
694
803
|
|
|
695
804
|
logger.info('Tags merged', {
|
|
696
805
|
module: 'SqliteAdapter',
|
|
@@ -707,6 +816,7 @@ export class SqliteAdapter {
|
|
|
707
816
|
|
|
708
817
|
/**
|
|
709
818
|
* Link two entries
|
|
819
|
+
* Throws if either entry does not exist (P154: Proactive Object Existence Verification)
|
|
710
820
|
*/
|
|
711
821
|
linkEntries(
|
|
712
822
|
fromEntryId: number,
|
|
@@ -716,6 +826,16 @@ export class SqliteAdapter {
|
|
|
716
826
|
): Relationship {
|
|
717
827
|
const db = this.ensureDb()
|
|
718
828
|
|
|
829
|
+
// P154: Pre-check both entries exist before creating relationship
|
|
830
|
+
const fromEntry = this.getEntryById(fromEntryId)
|
|
831
|
+
if (!fromEntry) {
|
|
832
|
+
throw new Error(`Source entry ${String(fromEntryId)} not found`)
|
|
833
|
+
}
|
|
834
|
+
const toEntry = this.getEntryById(toEntryId)
|
|
835
|
+
if (!toEntry) {
|
|
836
|
+
throw new Error(`Target entry ${String(toEntryId)} not found`)
|
|
837
|
+
}
|
|
838
|
+
|
|
719
839
|
db.run(
|
|
720
840
|
`
|
|
721
841
|
INSERT INTO relationships (from_entry_id, to_entry_id, relationship_type, description)
|
|
@@ -727,7 +847,7 @@ export class SqliteAdapter {
|
|
|
727
847
|
const result = db.exec('SELECT last_insert_rowid() as id')
|
|
728
848
|
const id = result[0]?.values[0]?.[0] as number
|
|
729
849
|
|
|
730
|
-
this.
|
|
850
|
+
this.scheduleSave()
|
|
731
851
|
|
|
732
852
|
return {
|
|
733
853
|
id,
|
|
@@ -816,18 +936,8 @@ export class SqliteAdapter {
|
|
|
816
936
|
entriesByType[row[0] as string] = row[1] as number
|
|
817
937
|
}
|
|
818
938
|
|
|
819
|
-
// By period
|
|
820
|
-
|
|
821
|
-
switch (groupBy) {
|
|
822
|
-
case 'day':
|
|
823
|
-
dateFormat = '%Y-%m-%d'
|
|
824
|
-
break
|
|
825
|
-
case 'month':
|
|
826
|
-
dateFormat = '%Y-%m'
|
|
827
|
-
break
|
|
828
|
-
default:
|
|
829
|
-
dateFormat = '%Y-W%W'
|
|
830
|
-
}
|
|
939
|
+
// By period - use validated date format pattern (defense-in-depth)
|
|
940
|
+
const dateFormat = validateDateFormatPattern(groupBy)
|
|
831
941
|
|
|
832
942
|
const byPeriodResult = db.exec(`
|
|
833
943
|
SELECT strftime('${dateFormat}', timestamp) as period, COUNT(*) as count
|
|
@@ -1086,7 +1196,7 @@ export class SqliteAdapter {
|
|
|
1086
1196
|
const newEntryCount = (newCountResult[0]?.values[0]?.[0] as number) ?? 0
|
|
1087
1197
|
|
|
1088
1198
|
// Save to main database path
|
|
1089
|
-
this.
|
|
1199
|
+
this.flushSave()
|
|
1090
1200
|
|
|
1091
1201
|
logger.info('Database restored from backup', {
|
|
1092
1202
|
module: 'SqliteAdapter',
|
|
@@ -1204,6 +1314,17 @@ export class SqliteAdapter {
|
|
|
1204
1314
|
autoContext: row['auto_context'] as string | null,
|
|
1205
1315
|
deletedAt: row['deleted_at'] as string | null,
|
|
1206
1316
|
tags: this.getTagsForEntry(id),
|
|
1317
|
+
// GitHub integration fields
|
|
1318
|
+
projectNumber: (row['project_number'] as number | null) ?? null,
|
|
1319
|
+
projectOwner: (row['project_owner'] as string | null) ?? null,
|
|
1320
|
+
issueNumber: (row['issue_number'] as number | null) ?? null,
|
|
1321
|
+
issueUrl: (row['issue_url'] as string | null) ?? null,
|
|
1322
|
+
prNumber: (row['pr_number'] as number | null) ?? null,
|
|
1323
|
+
prUrl: (row['pr_url'] as string | null) ?? null,
|
|
1324
|
+
prStatus: (row['pr_status'] as string | null) ?? null,
|
|
1325
|
+
workflowRunId: (row['workflow_run_id'] as number | null) ?? null,
|
|
1326
|
+
workflowName: (row['workflow_name'] as string | null) ?? null,
|
|
1327
|
+
workflowStatus: (row['workflow_status'] as string | null) ?? null,
|
|
1207
1328
|
}
|
|
1208
1329
|
}
|
|
1209
1330
|
|
|
@@ -13,7 +13,7 @@ export type { ToolFilterConfig } from '../types/index.js'
|
|
|
13
13
|
/**
|
|
14
14
|
* Tool group definitions mapping group names to tool names
|
|
15
15
|
*
|
|
16
|
-
* All
|
|
16
|
+
* All 39 tools are categorized here for filtering support.
|
|
17
17
|
*/
|
|
18
18
|
export const TOOL_GROUPS: Record<ToolGroup, string[]> = {
|
|
19
19
|
core: [
|
|
@@ -45,6 +45,12 @@ export const TOOL_GROUPS: Record<ToolGroup, string[]> = {
|
|
|
45
45
|
'move_kanban_item',
|
|
46
46
|
'create_github_issue_with_entry',
|
|
47
47
|
'close_github_issue_with_entry',
|
|
48
|
+
'get_github_milestones',
|
|
49
|
+
'get_github_milestone',
|
|
50
|
+
'create_github_milestone',
|
|
51
|
+
'update_github_milestone',
|
|
52
|
+
'delete_github_milestone',
|
|
53
|
+
'get_repo_insights',
|
|
48
54
|
],
|
|
49
55
|
backup: ['backup_journal', 'list_backups', 'restore_backup', 'cleanup_backups'],
|
|
50
56
|
}
|