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,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Journal MCP Server - Scheduler
|
|
3
|
+
*
|
|
4
|
+
* Lightweight in-process scheduler for periodic maintenance jobs.
|
|
5
|
+
* Only meaningful for HTTP/SSE transport (long-lived server processes).
|
|
6
|
+
* Uses setInterval for simplicity — no external dependencies.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { SqliteAdapter } from '../database/SqliteAdapter.js'
|
|
10
|
+
import type { VectorSearchManager } from '../vector/VectorSearchManager.js'
|
|
11
|
+
import { logger } from '../utils/logger.js'
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Types
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
/** Scheduler configuration options */
|
|
18
|
+
export interface SchedulerOptions {
|
|
19
|
+
/** Automated backup interval in minutes (0 = disabled) */
|
|
20
|
+
backupIntervalMinutes: number
|
|
21
|
+
/** Max backups to retain during automated cleanup */
|
|
22
|
+
keepBackups: number
|
|
23
|
+
/** Database optimize interval in minutes (0 = disabled) */
|
|
24
|
+
vacuumIntervalMinutes: number
|
|
25
|
+
/** Vector index rebuild interval in minutes (0 = disabled) */
|
|
26
|
+
rebuildIndexIntervalMinutes: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Status of a single scheduled job */
|
|
30
|
+
export interface JobStatus {
|
|
31
|
+
name: string
|
|
32
|
+
enabled: boolean
|
|
33
|
+
intervalMinutes: number
|
|
34
|
+
lastRun: string | null
|
|
35
|
+
lastResult: 'success' | 'error' | null
|
|
36
|
+
lastError: string | null
|
|
37
|
+
nextRun: string | null
|
|
38
|
+
runCount: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Overall scheduler status */
|
|
42
|
+
export interface SchedulerStatus {
|
|
43
|
+
active: boolean
|
|
44
|
+
jobs: JobStatus[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Internal timer tracking for a job */
|
|
48
|
+
interface JobTimer {
|
|
49
|
+
name: string
|
|
50
|
+
intervalMinutes: number
|
|
51
|
+
timer: ReturnType<typeof setInterval>
|
|
52
|
+
lastRun: Date | null
|
|
53
|
+
lastResult: 'success' | 'error' | null
|
|
54
|
+
lastError: string | null
|
|
55
|
+
runCount: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Scheduler
|
|
60
|
+
// ============================================================================
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Scheduler — runs periodic maintenance jobs for long-lived server processes.
|
|
64
|
+
*
|
|
65
|
+
* Jobs:
|
|
66
|
+
* - **backup**: Exports database to timestamped file, then prunes old backups.
|
|
67
|
+
* - **vacuum**: Runs `PRAGMA optimize` and flushes database to disk.
|
|
68
|
+
* - **rebuild-index**: Rebuilds vector search index from all entries.
|
|
69
|
+
*/
|
|
70
|
+
export class Scheduler {
|
|
71
|
+
private readonly options: SchedulerOptions
|
|
72
|
+
private readonly db: SqliteAdapter
|
|
73
|
+
private readonly vectorManager: VectorSearchManager | null
|
|
74
|
+
private readonly timers: JobTimer[] = []
|
|
75
|
+
private started = false
|
|
76
|
+
|
|
77
|
+
constructor(options: SchedulerOptions, db: SqliteAdapter, vectorManager?: VectorSearchManager) {
|
|
78
|
+
this.options = options
|
|
79
|
+
this.db = db
|
|
80
|
+
this.vectorManager = vectorManager ?? null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Start all enabled scheduled jobs.
|
|
85
|
+
* Each job runs on its own interval and failures are isolated.
|
|
86
|
+
*/
|
|
87
|
+
start(): void {
|
|
88
|
+
if (this.started) {
|
|
89
|
+
logger.warning('Scheduler already started, ignoring duplicate start()', {
|
|
90
|
+
module: 'Scheduler',
|
|
91
|
+
})
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
this.started = true
|
|
95
|
+
|
|
96
|
+
const { backupIntervalMinutes, vacuumIntervalMinutes, rebuildIndexIntervalMinutes } =
|
|
97
|
+
this.options
|
|
98
|
+
|
|
99
|
+
if (backupIntervalMinutes > 0) {
|
|
100
|
+
this.scheduleJob('backup', backupIntervalMinutes, () => this.runBackup())
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (vacuumIntervalMinutes > 0) {
|
|
104
|
+
this.scheduleJob('vacuum', vacuumIntervalMinutes, () => this.runVacuumOptimize())
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (rebuildIndexIntervalMinutes > 0) {
|
|
108
|
+
if (this.vectorManager) {
|
|
109
|
+
this.scheduleJob('rebuild-index', rebuildIndexIntervalMinutes, () =>
|
|
110
|
+
this.runRebuildIndex()
|
|
111
|
+
)
|
|
112
|
+
} else {
|
|
113
|
+
logger.warning(
|
|
114
|
+
'rebuild-index-interval specified but vector manager not available, skipping',
|
|
115
|
+
{ module: 'Scheduler' }
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.timers.length > 0) {
|
|
121
|
+
const summary = this.timers.map((t) => `${t.name} (${String(t.intervalMinutes)}min)`)
|
|
122
|
+
logger.info(`Scheduler started: ${summary.join(', ')}`, { module: 'Scheduler' })
|
|
123
|
+
} else {
|
|
124
|
+
logger.info('Scheduler started with no jobs enabled', { module: 'Scheduler' })
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Stop all scheduled jobs and clear timers.
|
|
130
|
+
* Safe to call multiple times.
|
|
131
|
+
*/
|
|
132
|
+
stop(): void {
|
|
133
|
+
for (const job of this.timers) {
|
|
134
|
+
clearInterval(job.timer)
|
|
135
|
+
}
|
|
136
|
+
if (this.timers.length > 0) {
|
|
137
|
+
logger.info(`Scheduler stopped, cleared ${String(this.timers.length)} job(s)`, {
|
|
138
|
+
module: 'Scheduler',
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
this.timers.length = 0
|
|
142
|
+
this.started = false
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get the current status of all scheduled jobs.
|
|
147
|
+
*/
|
|
148
|
+
getStatus(): SchedulerStatus {
|
|
149
|
+
return {
|
|
150
|
+
active: this.started,
|
|
151
|
+
jobs: this.timers.map((t) => ({
|
|
152
|
+
name: t.name,
|
|
153
|
+
enabled: true,
|
|
154
|
+
intervalMinutes: t.intervalMinutes,
|
|
155
|
+
lastRun: t.lastRun?.toISOString() ?? null,
|
|
156
|
+
lastResult: t.lastResult,
|
|
157
|
+
lastError: t.lastError,
|
|
158
|
+
nextRun: t.lastRun
|
|
159
|
+
? new Date(t.lastRun.getTime() + t.intervalMinutes * 60_000).toISOString()
|
|
160
|
+
: new Date(Date.now() + t.intervalMinutes * 60_000).toISOString(),
|
|
161
|
+
runCount: t.runCount,
|
|
162
|
+
})),
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ========================================================================
|
|
167
|
+
// Private — Job scheduling
|
|
168
|
+
// ========================================================================
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Schedule a recurring job.
|
|
172
|
+
*/
|
|
173
|
+
private scheduleJob(name: string, intervalMinutes: number, fn: () => Promise<void>): void {
|
|
174
|
+
const intervalMs = intervalMinutes * 60_000
|
|
175
|
+
|
|
176
|
+
const jobTimer: JobTimer = {
|
|
177
|
+
name,
|
|
178
|
+
intervalMinutes,
|
|
179
|
+
timer: setInterval(() => {
|
|
180
|
+
void this.executeJob(jobTimer, fn)
|
|
181
|
+
}, intervalMs),
|
|
182
|
+
lastRun: null,
|
|
183
|
+
lastResult: null,
|
|
184
|
+
lastError: null,
|
|
185
|
+
runCount: 0,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.timers.push(jobTimer)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Execute a job with error isolation and status tracking.
|
|
193
|
+
*/
|
|
194
|
+
private async executeJob(job: JobTimer, fn: () => Promise<void>): Promise<void> {
|
|
195
|
+
const startTime = Date.now()
|
|
196
|
+
try {
|
|
197
|
+
await fn()
|
|
198
|
+
job.lastRun = new Date(startTime)
|
|
199
|
+
job.lastResult = 'success'
|
|
200
|
+
job.lastError = null
|
|
201
|
+
job.runCount++
|
|
202
|
+
} catch (error) {
|
|
203
|
+
job.lastRun = new Date(startTime)
|
|
204
|
+
job.lastResult = 'error'
|
|
205
|
+
job.lastError = error instanceof Error ? error.message : String(error)
|
|
206
|
+
job.runCount++
|
|
207
|
+
logger.error(`Scheduled job '${job.name}' failed`, {
|
|
208
|
+
module: 'Scheduler',
|
|
209
|
+
operation: job.name,
|
|
210
|
+
error: job.lastError,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ========================================================================
|
|
216
|
+
// Private — Job implementations
|
|
217
|
+
// ========================================================================
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Backup job: export database to file, then cleanup old backups.
|
|
221
|
+
*/
|
|
222
|
+
private async runBackup(): Promise<void> {
|
|
223
|
+
const result = this.db.exportToFile()
|
|
224
|
+
logger.info('Scheduled backup created', {
|
|
225
|
+
module: 'Scheduler',
|
|
226
|
+
operation: 'backup',
|
|
227
|
+
context: { filename: result.filename, sizeBytes: result.sizeBytes },
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
const cleanup = this.db.deleteOldBackups(this.options.keepBackups)
|
|
231
|
+
if (cleanup.deleted.length > 0) {
|
|
232
|
+
logger.info(
|
|
233
|
+
`Backup cleanup: deleted ${String(cleanup.deleted.length)}, kept ${String(cleanup.kept)}`,
|
|
234
|
+
{
|
|
235
|
+
module: 'Scheduler',
|
|
236
|
+
operation: 'backup-cleanup',
|
|
237
|
+
}
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
await Promise.resolve()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Vacuum/optimize job: run PRAGMA optimize and flush to disk.
|
|
246
|
+
*
|
|
247
|
+
* Note: sql.js uses an in-memory database. PRAGMA optimize updates
|
|
248
|
+
* internal statistics, and flushSave() ensures the disk file is current.
|
|
249
|
+
* A full VACUUM on sql.js only compacts the in-memory representation.
|
|
250
|
+
*/
|
|
251
|
+
private async runVacuumOptimize(): Promise<void> {
|
|
252
|
+
const rawDb = this.db.getRawDb()
|
|
253
|
+
rawDb.run('PRAGMA optimize')
|
|
254
|
+
this.db.flushSave()
|
|
255
|
+
logger.info('Scheduled database optimize completed', {
|
|
256
|
+
module: 'Scheduler',
|
|
257
|
+
operation: 'vacuum',
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
await Promise.resolve()
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Rebuild index job: full vector index rebuild from database entries.
|
|
265
|
+
*/
|
|
266
|
+
private async runRebuildIndex(): Promise<void> {
|
|
267
|
+
if (!this.vectorManager) {
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const count = await this.vectorManager.rebuildIndex(this.db)
|
|
272
|
+
logger.info(`Scheduled vector index rebuild: ${String(count)} entries indexed`, {
|
|
273
|
+
module: 'Scheduler',
|
|
274
|
+
operation: 'rebuild-index',
|
|
275
|
+
context: { entriesIndexed: count },
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
}
|