specweave 0.28.68 → 0.29.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/CLAUDE.md +3 -2
- package/README.md +19 -2
- package/dist/src/cli/commands/discrepancies.d.ts +89 -0
- package/dist/src/cli/commands/discrepancies.d.ts.map +1 -0
- package/dist/src/cli/commands/discrepancies.js +385 -0
- package/dist/src/cli/commands/discrepancies.js.map +1 -0
- package/dist/src/cli/commands/notifications.d.ts +70 -0
- package/dist/src/cli/commands/notifications.d.ts.map +1 -0
- package/dist/src/cli/commands/notifications.js +236 -0
- package/dist/src/cli/commands/notifications.js.map +1 -0
- package/dist/src/cli/commands/sync-logs.d.ts +54 -0
- package/dist/src/cli/commands/sync-logs.d.ts.map +1 -0
- package/dist/src/cli/commands/sync-logs.js +240 -0
- package/dist/src/cli/commands/sync-logs.js.map +1 -0
- package/dist/src/cli/commands/sync-monitor.d.ts +42 -0
- package/dist/src/cli/commands/sync-monitor.d.ts.map +1 -0
- package/dist/src/cli/commands/sync-monitor.js +191 -0
- package/dist/src/cli/commands/sync-monitor.js.map +1 -0
- package/dist/src/cli/helpers/init/brownfield-analysis.d.ts +45 -0
- package/dist/src/cli/helpers/init/brownfield-analysis.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/brownfield-analysis.js +431 -0
- package/dist/src/cli/helpers/init/brownfield-analysis.js.map +1 -0
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/workers/brownfield-worker.d.ts +66 -0
- package/dist/src/cli/workers/brownfield-worker.d.ts.map +1 -0
- package/dist/src/cli/workers/brownfield-worker.js +417 -0
- package/dist/src/cli/workers/brownfield-worker.js.map +1 -0
- package/dist/src/core/background/brownfield-launcher.d.ts +86 -0
- package/dist/src/core/background/brownfield-launcher.d.ts.map +1 -0
- package/dist/src/core/background/brownfield-launcher.js +295 -0
- package/dist/src/core/background/brownfield-launcher.js.map +1 -0
- package/dist/src/core/background/index.d.ts +2 -0
- package/dist/src/core/background/index.d.ts.map +1 -1
- package/dist/src/core/background/index.js +2 -0
- package/dist/src/core/background/index.js.map +1 -1
- package/dist/src/core/background/types.d.ts +23 -2
- package/dist/src/core/background/types.d.ts.map +1 -1
- package/dist/src/core/config/index.d.ts +1 -0
- package/dist/src/core/config/index.d.ts.map +1 -1
- package/dist/src/core/config/index.js +1 -0
- package/dist/src/core/config/index.js.map +1 -1
- package/dist/src/core/config/types.d.ts +6 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/dashboard/dashboard-data.d.ts +156 -0
- package/dist/src/core/dashboard/dashboard-data.d.ts.map +1 -0
- package/dist/src/core/dashboard/dashboard-data.js +191 -0
- package/dist/src/core/dashboard/dashboard-data.js.map +1 -0
- package/dist/src/core/dashboard/index.d.ts +9 -0
- package/dist/src/core/dashboard/index.d.ts.map +1 -0
- package/dist/src/core/dashboard/index.js +9 -0
- package/dist/src/core/dashboard/index.js.map +1 -0
- package/dist/src/core/discrepancy/analyzers/api-route-analyzer.d.ts +77 -0
- package/dist/src/core/discrepancy/analyzers/api-route-analyzer.d.ts.map +1 -0
- package/dist/src/core/discrepancy/analyzers/api-route-analyzer.js +286 -0
- package/dist/src/core/discrepancy/analyzers/api-route-analyzer.js.map +1 -0
- package/dist/src/core/discrepancy/analyzers/index.d.ts +8 -0
- package/dist/src/core/discrepancy/analyzers/index.d.ts.map +1 -0
- package/dist/src/core/discrepancy/analyzers/index.js +8 -0
- package/dist/src/core/discrepancy/analyzers/index.js.map +1 -0
- package/dist/src/core/discrepancy/analyzers/typescript-analyzer.d.ts +96 -0
- package/dist/src/core/discrepancy/analyzers/typescript-analyzer.d.ts.map +1 -0
- package/dist/src/core/discrepancy/analyzers/typescript-analyzer.js +247 -0
- package/dist/src/core/discrepancy/analyzers/typescript-analyzer.js.map +1 -0
- package/dist/src/core/discrepancy/brownfield-manager.d.ts +88 -0
- package/dist/src/core/discrepancy/brownfield-manager.d.ts.map +1 -0
- package/dist/src/core/discrepancy/brownfield-manager.js +520 -0
- package/dist/src/core/discrepancy/brownfield-manager.js.map +1 -0
- package/dist/src/core/discrepancy/brownfield-types.d.ts +174 -0
- package/dist/src/core/discrepancy/brownfield-types.d.ts.map +1 -0
- package/dist/src/core/discrepancy/brownfield-types.js +11 -0
- package/dist/src/core/discrepancy/brownfield-types.js.map +1 -0
- package/dist/src/core/discrepancy/detector.d.ts +92 -0
- package/dist/src/core/discrepancy/detector.d.ts.map +1 -0
- package/dist/src/core/discrepancy/detector.js +346 -0
- package/dist/src/core/discrepancy/detector.js.map +1 -0
- package/dist/src/core/discrepancy/increment-generator.d.ts +51 -0
- package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -0
- package/dist/src/core/discrepancy/increment-generator.js +234 -0
- package/dist/src/core/discrepancy/increment-generator.js.map +1 -0
- package/dist/src/core/discrepancy/index.d.ts +18 -0
- package/dist/src/core/discrepancy/index.d.ts.map +1 -0
- package/dist/src/core/discrepancy/index.js +24 -0
- package/dist/src/core/discrepancy/index.js.map +1 -0
- package/dist/src/core/discrepancy/severity-classifier.d.ts +81 -0
- package/dist/src/core/discrepancy/severity-classifier.d.ts.map +1 -0
- package/dist/src/core/discrepancy/severity-classifier.js +289 -0
- package/dist/src/core/discrepancy/severity-classifier.js.map +1 -0
- package/dist/src/core/discrepancy/spec-parser.d.ts +74 -0
- package/dist/src/core/discrepancy/spec-parser.d.ts.map +1 -0
- package/dist/src/core/discrepancy/spec-parser.js +213 -0
- package/dist/src/core/discrepancy/spec-parser.js.map +1 -0
- package/dist/src/core/discrepancy/update-recommender.d.ts +77 -0
- package/dist/src/core/discrepancy/update-recommender.d.ts.map +1 -0
- package/dist/src/core/discrepancy/update-recommender.js +323 -0
- package/dist/src/core/discrepancy/update-recommender.js.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -16
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +31 -112
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/logs/index.d.ts +10 -0
- package/dist/src/core/logs/index.d.ts.map +1 -0
- package/dist/src/core/logs/index.js +10 -0
- package/dist/src/core/logs/index.js.map +1 -0
- package/dist/src/core/logs/log-aggregator.d.ts +130 -0
- package/dist/src/core/logs/log-aggregator.d.ts.map +1 -0
- package/dist/src/core/logs/log-aggregator.js +206 -0
- package/dist/src/core/logs/log-aggregator.js.map +1 -0
- package/dist/src/core/logs/log-exporter.d.ts +81 -0
- package/dist/src/core/logs/log-exporter.d.ts.map +1 -0
- package/dist/src/core/logs/log-exporter.js +141 -0
- package/dist/src/core/logs/log-exporter.js.map +1 -0
- package/dist/src/core/notifications/command-integration.d.ts +82 -0
- package/dist/src/core/notifications/command-integration.d.ts.map +1 -0
- package/dist/src/core/notifications/command-integration.js +80 -0
- package/dist/src/core/notifications/command-integration.js.map +1 -0
- package/dist/src/core/notifications/index.d.ts +12 -0
- package/dist/src/core/notifications/index.d.ts.map +1 -0
- package/dist/src/core/notifications/index.js +12 -0
- package/dist/src/core/notifications/index.js.map +1 -0
- package/dist/src/core/notifications/notification-display.d.ts +70 -0
- package/dist/src/core/notifications/notification-display.d.ts.map +1 -0
- package/dist/src/core/notifications/notification-display.js +177 -0
- package/dist/src/core/notifications/notification-display.js.map +1 -0
- package/dist/src/core/notifications/notification-manager.d.ts +126 -0
- package/dist/src/core/notifications/notification-manager.d.ts.map +1 -0
- package/dist/src/core/notifications/notification-manager.js +287 -0
- package/dist/src/core/notifications/notification-manager.js.map +1 -0
- package/dist/src/core/notifications/notification-types.d.ts +159 -0
- package/dist/src/core/notifications/notification-types.d.ts.map +1 -0
- package/dist/src/core/notifications/notification-types.js +93 -0
- package/dist/src/core/notifications/notification-types.js.map +1 -0
- package/dist/src/core/scheduler/index.d.ts +11 -0
- package/dist/src/core/scheduler/index.d.ts.map +1 -0
- package/dist/src/core/scheduler/index.js +11 -0
- package/dist/src/core/scheduler/index.js.map +1 -0
- package/dist/src/core/scheduler/job-scheduler.d.ts +179 -0
- package/dist/src/core/scheduler/job-scheduler.d.ts.map +1 -0
- package/dist/src/core/scheduler/job-scheduler.js +282 -0
- package/dist/src/core/scheduler/job-scheduler.js.map +1 -0
- package/dist/src/core/scheduler/schedule-persistence.d.ts +83 -0
- package/dist/src/core/scheduler/schedule-persistence.d.ts.map +1 -0
- package/dist/src/core/scheduler/schedule-persistence.js +180 -0
- package/dist/src/core/scheduler/schedule-persistence.js.map +1 -0
- package/dist/src/core/scheduler/scheduled-job.d.ts +188 -0
- package/dist/src/core/scheduler/scheduled-job.d.ts.map +1 -0
- package/dist/src/core/scheduler/scheduled-job.js +182 -0
- package/dist/src/core/scheduler/scheduled-job.js.map +1 -0
- package/dist/src/core/sync/permission-enforcer.d.ts +206 -0
- package/dist/src/core/sync/permission-enforcer.d.ts.map +1 -0
- package/dist/src/core/sync/permission-enforcer.js +268 -0
- package/dist/src/core/sync/permission-enforcer.js.map +1 -0
- package/dist/src/core/sync/sync-audit-logger.d.ts +217 -0
- package/dist/src/core/sync/sync-audit-logger.d.ts.map +1 -0
- package/dist/src/core/sync/sync-audit-logger.js +327 -0
- package/dist/src/core/sync/sync-audit-logger.js.map +1 -0
- package/dist/src/core/sync/sync-interceptor.d.ts +190 -0
- package/dist/src/core/sync/sync-interceptor.d.ts.map +1 -0
- package/dist/src/core/sync/sync-interceptor.js +224 -0
- package/dist/src/core/sync/sync-interceptor.js.map +1 -0
- package/dist/src/core/types/increment-metadata.d.ts +5 -2
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/sync-config.d.ts +267 -0
- package/dist/src/core/types/sync-config.d.ts.map +1 -0
- package/dist/src/core/types/sync-config.js +304 -0
- package/dist/src/core/types/sync-config.js.map +1 -0
- package/dist/src/hooks/index.d.ts +11 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +11 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/platform.d.ts +125 -0
- package/dist/src/hooks/platform.d.ts.map +1 -0
- package/dist/src/hooks/platform.js +325 -0
- package/dist/src/hooks/platform.js.map +1 -0
- package/dist/src/hooks/processor.d.ts +20 -0
- package/dist/src/hooks/processor.d.ts.map +1 -0
- package/dist/src/hooks/processor.js +317 -0
- package/dist/src/hooks/processor.js.map +1 -0
- package/dist/src/hooks/scheduler-startup.d.ts +19 -0
- package/dist/src/hooks/scheduler-startup.d.ts.map +1 -0
- package/dist/src/hooks/scheduler-startup.js +92 -0
- package/dist/src/hooks/scheduler-startup.js.map +1 -0
- package/dist/src/hooks/session-start.d.ts +16 -0
- package/dist/src/hooks/session-start.d.ts.map +1 -0
- package/dist/src/hooks/session-start.js +92 -0
- package/dist/src/hooks/session-start.js.map +1 -0
- package/dist/src/importers/duplicate-detector.d.ts +13 -2
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -1
- package/dist/src/importers/duplicate-detector.js +21 -2
- package/dist/src/importers/duplicate-detector.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +41 -2
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +225 -38
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.d.ts +7 -0
- package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.js +30 -4
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
- package/dist/src/sync/ado-sync-wrapper.d.ts +137 -0
- package/dist/src/sync/ado-sync-wrapper.d.ts.map +1 -0
- package/dist/src/sync/ado-sync-wrapper.js +148 -0
- package/dist/src/sync/ado-sync-wrapper.js.map +1 -0
- package/dist/src/sync/github-sync-wrapper.d.ts +195 -0
- package/dist/src/sync/github-sync-wrapper.d.ts.map +1 -0
- package/dist/src/sync/github-sync-wrapper.js +220 -0
- package/dist/src/sync/github-sync-wrapper.js.map +1 -0
- package/dist/src/sync/jira-sync-wrapper.d.ts +155 -0
- package/dist/src/sync/jira-sync-wrapper.d.ts.map +1 -0
- package/dist/src/sync/jira-sync-wrapper.js +175 -0
- package/dist/src/sync/jira-sync-wrapper.js.map +1 -0
- package/dist/src/utils/feature-id-derivation.d.ts +58 -0
- package/dist/src/utils/feature-id-derivation.d.ts.map +1 -0
- package/dist/src/utils/feature-id-derivation.js +77 -0
- package/dist/src/utils/feature-id-derivation.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-discrepancies.md +141 -0
- package/plugins/specweave/commands/specweave-discrepancy-to-increment.md +160 -0
- package/plugins/specweave/commands/specweave-jobs.md +45 -2
- package/plugins/specweave/commands/specweave-notifications.md +92 -0
- package/plugins/specweave/commands/specweave-sync-logs.md +131 -0
- package/plugins/specweave/commands/specweave-sync-monitor.md +57 -0
- package/plugins/specweave/hooks/hooks.json +3 -3
- package/plugins/specweave/hooks/lib/scheduler-startup.sh +72 -0
- package/plugins/specweave/hooks/universal/dispatcher.mjs +246 -0
- package/plugins/specweave/hooks/universal/session-start.cmd +16 -0
- package/plugins/specweave/hooks/universal/session-start.ps1 +16 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +14 -5
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +5 -2
- package/plugins/specweave/skills/discrepancy-viewer.md +154 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +34 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +51 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedule Persistence
|
|
3
|
+
*
|
|
4
|
+
* Persists job schedules to disk so they survive session restarts.
|
|
5
|
+
* Uses atomic writes to prevent corruption.
|
|
6
|
+
*
|
|
7
|
+
* @module core/scheduler/schedule-persistence
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs } from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { consoleLogger } from '../../utils/logger.js';
|
|
12
|
+
/**
|
|
13
|
+
* Current schema version
|
|
14
|
+
*/
|
|
15
|
+
const CURRENT_VERSION = 1;
|
|
16
|
+
/**
|
|
17
|
+
* SchedulePersistence - Saves and loads job schedules from disk
|
|
18
|
+
*
|
|
19
|
+
* Features:
|
|
20
|
+
* - Atomic writes using temp file + rename
|
|
21
|
+
* - Schema versioning for migration
|
|
22
|
+
* - Corruption recovery with defaults
|
|
23
|
+
*/
|
|
24
|
+
export class SchedulePersistence {
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
const specweavePath = options.specweavePath ?? path.join(process.cwd(), '.specweave');
|
|
27
|
+
this.filePath = path.join(specweavePath, 'state', 'scheduled-jobs.json');
|
|
28
|
+
this.logger = options.logger ?? consoleLogger;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Load schedules from disk
|
|
32
|
+
*
|
|
33
|
+
* @returns Array of persisted jobs, empty array if file doesn't exist or is corrupted
|
|
34
|
+
*/
|
|
35
|
+
async loadSchedules() {
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(this.filePath, 'utf-8');
|
|
38
|
+
const data = JSON.parse(content);
|
|
39
|
+
// Validate schema version
|
|
40
|
+
if (!data.version || typeof data.version !== 'number') {
|
|
41
|
+
this.logger.warn('Invalid schedule file format, returning empty');
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
// Handle schema migration if needed
|
|
45
|
+
if (data.version < CURRENT_VERSION) {
|
|
46
|
+
this.logger.log(`Migrating schedules from v${data.version} to v${CURRENT_VERSION}`);
|
|
47
|
+
return this.migrateSchedules(data);
|
|
48
|
+
}
|
|
49
|
+
// Validate jobs array
|
|
50
|
+
if (!Array.isArray(data.jobs)) {
|
|
51
|
+
this.logger.warn('Invalid jobs array in schedule file, returning empty');
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
this.logger.debug(`Loaded ${data.jobs.length} scheduled jobs from disk`);
|
|
55
|
+
return data.jobs;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error.code === 'ENOENT') {
|
|
59
|
+
// File doesn't exist - normal for first run
|
|
60
|
+
this.logger.debug('No scheduled jobs file found (first run)');
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
if (error instanceof SyntaxError) {
|
|
64
|
+
// JSON parse error - corrupted file
|
|
65
|
+
this.logger.warn(`Corrupted schedule file, creating backup: ${error.message}`);
|
|
66
|
+
await this.backupCorruptedFile();
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
this.logger.error(`Failed to load schedules: ${error}`);
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Save schedules to disk
|
|
75
|
+
*
|
|
76
|
+
* Uses atomic write (write to temp file, then rename) to prevent corruption.
|
|
77
|
+
*
|
|
78
|
+
* @param jobs - Jobs to persist
|
|
79
|
+
*/
|
|
80
|
+
async saveSchedules(jobs) {
|
|
81
|
+
const data = {
|
|
82
|
+
version: CURRENT_VERSION,
|
|
83
|
+
jobs,
|
|
84
|
+
lastUpdated: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
// Ensure directory exists
|
|
87
|
+
const dir = path.dirname(this.filePath);
|
|
88
|
+
await fs.mkdir(dir, { recursive: true });
|
|
89
|
+
// Write to temp file first
|
|
90
|
+
const tempPath = `${this.filePath}.tmp`;
|
|
91
|
+
const content = JSON.stringify(data, null, 2);
|
|
92
|
+
try {
|
|
93
|
+
await fs.writeFile(tempPath, content, 'utf-8');
|
|
94
|
+
// Atomic rename
|
|
95
|
+
await fs.rename(tempPath, this.filePath);
|
|
96
|
+
this.logger.debug(`Saved ${jobs.length} scheduled jobs to disk`);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Clean up temp file if it exists
|
|
100
|
+
try {
|
|
101
|
+
await fs.unlink(tempPath);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Ignore cleanup errors
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Update a single job in persistence
|
|
111
|
+
*
|
|
112
|
+
* @param jobId - Job ID to update
|
|
113
|
+
* @param updates - Partial job updates
|
|
114
|
+
*/
|
|
115
|
+
async updateJob(jobId, updates) {
|
|
116
|
+
const jobs = await this.loadSchedules();
|
|
117
|
+
const index = jobs.findIndex((j) => j.id === jobId);
|
|
118
|
+
if (index === -1) {
|
|
119
|
+
this.logger.warn(`Job not found for update: ${jobId}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
jobs[index] = { ...jobs[index], ...updates };
|
|
123
|
+
await this.saveSchedules(jobs);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Delete a job from persistence
|
|
127
|
+
*
|
|
128
|
+
* @param jobId - Job ID to delete
|
|
129
|
+
*/
|
|
130
|
+
async deleteJob(jobId) {
|
|
131
|
+
const jobs = await this.loadSchedules();
|
|
132
|
+
const filtered = jobs.filter((j) => j.id !== jobId);
|
|
133
|
+
if (filtered.length < jobs.length) {
|
|
134
|
+
await this.saveSchedules(filtered);
|
|
135
|
+
this.logger.debug(`Deleted job from persistence: ${jobId}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if persistence file exists
|
|
140
|
+
*
|
|
141
|
+
* @returns true if file exists
|
|
142
|
+
*/
|
|
143
|
+
async exists() {
|
|
144
|
+
try {
|
|
145
|
+
await fs.access(this.filePath);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get file path (for testing/debugging)
|
|
154
|
+
*/
|
|
155
|
+
getFilePath() {
|
|
156
|
+
return this.filePath;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Migrate schedules from older schema versions
|
|
160
|
+
*/
|
|
161
|
+
async migrateSchedules(data) {
|
|
162
|
+
// Currently only v1, no migrations needed
|
|
163
|
+
// Future migrations would go here
|
|
164
|
+
return data.jobs || [];
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Backup corrupted file for debugging
|
|
168
|
+
*/
|
|
169
|
+
async backupCorruptedFile() {
|
|
170
|
+
try {
|
|
171
|
+
const backupPath = `${this.filePath}.corrupted.${Date.now()}`;
|
|
172
|
+
await fs.copyFile(this.filePath, backupPath);
|
|
173
|
+
this.logger.log(`Backed up corrupted file to: ${backupPath}`);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Ignore backup errors
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=schedule-persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule-persistence.js","sourceRoot":"","sources":["../../../../src/core/scheduler/schedule-persistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduled Job Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the types for scheduled jobs in the sync orchestration system.
|
|
5
|
+
*
|
|
6
|
+
* @module core/scheduler/scheduled-job
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Job types supported by the scheduler
|
|
10
|
+
*/
|
|
11
|
+
export type JobType = 'external-sync' | 'discrepancy-check' | 'living-docs-sync' | 'notification-cleanup';
|
|
12
|
+
/**
|
|
13
|
+
* Job status values
|
|
14
|
+
*/
|
|
15
|
+
export type JobStatus = 'idle' | 'running' | 'failed' | 'disabled';
|
|
16
|
+
/**
|
|
17
|
+
* Job schedule configuration
|
|
18
|
+
*/
|
|
19
|
+
export interface JobSchedule {
|
|
20
|
+
/**
|
|
21
|
+
* Interval between job runs in milliseconds
|
|
22
|
+
*/
|
|
23
|
+
intervalMs: number;
|
|
24
|
+
/**
|
|
25
|
+
* Whether the job is enabled
|
|
26
|
+
*/
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* ISO timestamp of last successful run
|
|
30
|
+
*/
|
|
31
|
+
lastRun?: string;
|
|
32
|
+
/**
|
|
33
|
+
* ISO timestamp of next scheduled run
|
|
34
|
+
*/
|
|
35
|
+
nextRun?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Current retry count for failed jobs
|
|
38
|
+
*/
|
|
39
|
+
retryCount: number;
|
|
40
|
+
/**
|
|
41
|
+
* Maximum retries before giving up
|
|
42
|
+
* @default 3
|
|
43
|
+
*/
|
|
44
|
+
maxRetries: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Scheduled job definition
|
|
48
|
+
*/
|
|
49
|
+
export interface ScheduledJob {
|
|
50
|
+
/**
|
|
51
|
+
* Unique job identifier (e.g., 'external-sync', 'discrepancy-check')
|
|
52
|
+
*/
|
|
53
|
+
id: string;
|
|
54
|
+
/**
|
|
55
|
+
* Job type
|
|
56
|
+
*/
|
|
57
|
+
type: JobType;
|
|
58
|
+
/**
|
|
59
|
+
* Schedule configuration
|
|
60
|
+
*/
|
|
61
|
+
schedule: JobSchedule;
|
|
62
|
+
/**
|
|
63
|
+
* Current job status
|
|
64
|
+
*/
|
|
65
|
+
status: JobStatus;
|
|
66
|
+
/**
|
|
67
|
+
* Error message if job failed
|
|
68
|
+
*/
|
|
69
|
+
lastError?: string;
|
|
70
|
+
/**
|
|
71
|
+
* ISO timestamp of last state change
|
|
72
|
+
*/
|
|
73
|
+
lastStateChange?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Configuration for registering a new job
|
|
77
|
+
*/
|
|
78
|
+
export interface ScheduledJobConfig {
|
|
79
|
+
/**
|
|
80
|
+
* Job identifier
|
|
81
|
+
*/
|
|
82
|
+
id: string;
|
|
83
|
+
/**
|
|
84
|
+
* Job type
|
|
85
|
+
*/
|
|
86
|
+
type: JobType;
|
|
87
|
+
/**
|
|
88
|
+
* Interval in milliseconds
|
|
89
|
+
*/
|
|
90
|
+
intervalMs: number;
|
|
91
|
+
/**
|
|
92
|
+
* Initial enabled state
|
|
93
|
+
* @default true
|
|
94
|
+
*/
|
|
95
|
+
enabled?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Maximum retries
|
|
98
|
+
* @default 3
|
|
99
|
+
*/
|
|
100
|
+
maxRetries?: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Job execution result
|
|
104
|
+
*/
|
|
105
|
+
export interface JobExecutionResult {
|
|
106
|
+
/**
|
|
107
|
+
* Whether the job succeeded
|
|
108
|
+
*/
|
|
109
|
+
success: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Duration in milliseconds
|
|
112
|
+
*/
|
|
113
|
+
durationMs: number;
|
|
114
|
+
/**
|
|
115
|
+
* Error message if failed
|
|
116
|
+
*/
|
|
117
|
+
error?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Job-specific result data
|
|
120
|
+
*/
|
|
121
|
+
data?: Record<string, unknown>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Create a new scheduled job from config
|
|
125
|
+
*
|
|
126
|
+
* @param config - Job configuration
|
|
127
|
+
* @returns New scheduled job
|
|
128
|
+
*/
|
|
129
|
+
export declare function createScheduledJob(config: ScheduledJobConfig): ScheduledJob;
|
|
130
|
+
/**
|
|
131
|
+
* Calculate next run time with optional exponential backoff
|
|
132
|
+
*
|
|
133
|
+
* @param job - The job to calculate next run for
|
|
134
|
+
* @param withBackoff - Whether to apply exponential backoff (for retries)
|
|
135
|
+
* @returns ISO timestamp of next run
|
|
136
|
+
*/
|
|
137
|
+
export declare function calculateNextRun(job: ScheduledJob, withBackoff?: boolean): string;
|
|
138
|
+
/**
|
|
139
|
+
* Check if a job is due for execution
|
|
140
|
+
*
|
|
141
|
+
* @param job - The job to check
|
|
142
|
+
* @returns true if job should run now
|
|
143
|
+
*/
|
|
144
|
+
export declare function isJobDue(job: ScheduledJob): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Update job state after successful execution
|
|
147
|
+
*
|
|
148
|
+
* @param job - The job to update
|
|
149
|
+
* @returns Updated job
|
|
150
|
+
*/
|
|
151
|
+
export declare function markJobComplete(job: ScheduledJob): ScheduledJob;
|
|
152
|
+
/**
|
|
153
|
+
* Update job state after failed execution
|
|
154
|
+
*
|
|
155
|
+
* @param job - The job to update
|
|
156
|
+
* @param error - Error message
|
|
157
|
+
* @returns Updated job
|
|
158
|
+
*/
|
|
159
|
+
export declare function markJobFailed(job: ScheduledJob, error: string): ScheduledJob;
|
|
160
|
+
/**
|
|
161
|
+
* Mark job as running
|
|
162
|
+
*
|
|
163
|
+
* @param job - The job to update
|
|
164
|
+
* @returns Updated job
|
|
165
|
+
*/
|
|
166
|
+
export declare function markJobRunning(job: ScheduledJob): ScheduledJob;
|
|
167
|
+
/**
|
|
168
|
+
* Pause a job (disable without clearing schedule)
|
|
169
|
+
*
|
|
170
|
+
* @param job - The job to pause
|
|
171
|
+
* @returns Updated job
|
|
172
|
+
*/
|
|
173
|
+
export declare function pauseJob(job: ScheduledJob): ScheduledJob;
|
|
174
|
+
/**
|
|
175
|
+
* Resume a paused job
|
|
176
|
+
*
|
|
177
|
+
* @param job - The job to resume
|
|
178
|
+
* @returns Updated job
|
|
179
|
+
*/
|
|
180
|
+
export declare function resumeJob(job: ScheduledJob): ScheduledJob;
|
|
181
|
+
/**
|
|
182
|
+
* Reset a failed job for retry
|
|
183
|
+
*
|
|
184
|
+
* @param job - The job to reset
|
|
185
|
+
* @returns Updated job
|
|
186
|
+
*/
|
|
187
|
+
export declare function resetJob(job: ScheduledJob): ScheduledJob;
|
|
188
|
+
//# sourceMappingURL=scheduled-job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-job.d.ts","sourceRoot":"","sources":["../../../../src/core/scheduler/scheduled-job.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GACf,eAAe,GACf,mBAAmB,GACnB,kBAAkB,GAClB,sBAAsB,CAAC;AAE3B;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,QAAQ,EAAE,WAAW,CAAC;IAEtB;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAkB3E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,UAAQ,GAAG,MAAM,CAU/E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAgBnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAc/D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAkB5E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAUxD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAazD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,YAAY,CAYxD"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduled Job Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the types for scheduled jobs in the sync orchestration system.
|
|
5
|
+
*
|
|
6
|
+
* @module core/scheduler/scheduled-job
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Create a new scheduled job from config
|
|
10
|
+
*
|
|
11
|
+
* @param config - Job configuration
|
|
12
|
+
* @returns New scheduled job
|
|
13
|
+
*/
|
|
14
|
+
export function createScheduledJob(config) {
|
|
15
|
+
const now = new Date().toISOString();
|
|
16
|
+
const intervalMs = config.intervalMs;
|
|
17
|
+
const nextRun = new Date(Date.now() + intervalMs).toISOString();
|
|
18
|
+
return {
|
|
19
|
+
id: config.id,
|
|
20
|
+
type: config.type,
|
|
21
|
+
schedule: {
|
|
22
|
+
intervalMs,
|
|
23
|
+
enabled: config.enabled ?? true,
|
|
24
|
+
nextRun,
|
|
25
|
+
retryCount: 0,
|
|
26
|
+
maxRetries: config.maxRetries ?? 3,
|
|
27
|
+
},
|
|
28
|
+
status: 'idle',
|
|
29
|
+
lastStateChange: now,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Calculate next run time with optional exponential backoff
|
|
34
|
+
*
|
|
35
|
+
* @param job - The job to calculate next run for
|
|
36
|
+
* @param withBackoff - Whether to apply exponential backoff (for retries)
|
|
37
|
+
* @returns ISO timestamp of next run
|
|
38
|
+
*/
|
|
39
|
+
export function calculateNextRun(job, withBackoff = false) {
|
|
40
|
+
let delayMs = job.schedule.intervalMs;
|
|
41
|
+
if (withBackoff && job.schedule.retryCount > 0) {
|
|
42
|
+
// Exponential backoff: 2^retryCount * base interval, capped at 1 hour
|
|
43
|
+
const backoffMultiplier = Math.pow(2, job.schedule.retryCount);
|
|
44
|
+
delayMs = Math.min(delayMs * backoffMultiplier, 60 * 60 * 1000);
|
|
45
|
+
}
|
|
46
|
+
return new Date(Date.now() + delayMs).toISOString();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if a job is due for execution
|
|
50
|
+
*
|
|
51
|
+
* @param job - The job to check
|
|
52
|
+
* @returns true if job should run now
|
|
53
|
+
*/
|
|
54
|
+
export function isJobDue(job) {
|
|
55
|
+
// Job must be enabled and idle
|
|
56
|
+
if (!job.schedule.enabled || job.status !== 'idle') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// If no next run scheduled, it's due
|
|
60
|
+
if (!job.schedule.nextRun) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// Check if current time is past scheduled time
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
const nextRun = new Date(job.schedule.nextRun).getTime();
|
|
66
|
+
return now >= nextRun;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Update job state after successful execution
|
|
70
|
+
*
|
|
71
|
+
* @param job - The job to update
|
|
72
|
+
* @returns Updated job
|
|
73
|
+
*/
|
|
74
|
+
export function markJobComplete(job) {
|
|
75
|
+
const now = new Date().toISOString();
|
|
76
|
+
return {
|
|
77
|
+
...job,
|
|
78
|
+
status: 'idle',
|
|
79
|
+
schedule: {
|
|
80
|
+
...job.schedule,
|
|
81
|
+
lastRun: now,
|
|
82
|
+
nextRun: calculateNextRun(job),
|
|
83
|
+
retryCount: 0, // Reset retry count on success
|
|
84
|
+
},
|
|
85
|
+
lastError: undefined,
|
|
86
|
+
lastStateChange: now,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Update job state after failed execution
|
|
91
|
+
*
|
|
92
|
+
* @param job - The job to update
|
|
93
|
+
* @param error - Error message
|
|
94
|
+
* @returns Updated job
|
|
95
|
+
*/
|
|
96
|
+
export function markJobFailed(job, error) {
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
const newRetryCount = job.schedule.retryCount + 1;
|
|
99
|
+
const maxRetriesReached = newRetryCount >= job.schedule.maxRetries;
|
|
100
|
+
const updatedJob = {
|
|
101
|
+
...job,
|
|
102
|
+
status: maxRetriesReached ? 'failed' : 'idle',
|
|
103
|
+
schedule: {
|
|
104
|
+
...job.schedule,
|
|
105
|
+
retryCount: newRetryCount,
|
|
106
|
+
nextRun: maxRetriesReached ? undefined : calculateNextRun(job, true),
|
|
107
|
+
},
|
|
108
|
+
lastError: error,
|
|
109
|
+
lastStateChange: now,
|
|
110
|
+
};
|
|
111
|
+
return updatedJob;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Mark job as running
|
|
115
|
+
*
|
|
116
|
+
* @param job - The job to update
|
|
117
|
+
* @returns Updated job
|
|
118
|
+
*/
|
|
119
|
+
export function markJobRunning(job) {
|
|
120
|
+
return {
|
|
121
|
+
...job,
|
|
122
|
+
status: 'running',
|
|
123
|
+
lastStateChange: new Date().toISOString(),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Pause a job (disable without clearing schedule)
|
|
128
|
+
*
|
|
129
|
+
* @param job - The job to pause
|
|
130
|
+
* @returns Updated job
|
|
131
|
+
*/
|
|
132
|
+
export function pauseJob(job) {
|
|
133
|
+
return {
|
|
134
|
+
...job,
|
|
135
|
+
status: 'disabled',
|
|
136
|
+
schedule: {
|
|
137
|
+
...job.schedule,
|
|
138
|
+
enabled: false,
|
|
139
|
+
},
|
|
140
|
+
lastStateChange: new Date().toISOString(),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resume a paused job
|
|
145
|
+
*
|
|
146
|
+
* @param job - The job to resume
|
|
147
|
+
* @returns Updated job
|
|
148
|
+
*/
|
|
149
|
+
export function resumeJob(job) {
|
|
150
|
+
return {
|
|
151
|
+
...job,
|
|
152
|
+
status: 'idle',
|
|
153
|
+
schedule: {
|
|
154
|
+
...job.schedule,
|
|
155
|
+
enabled: true,
|
|
156
|
+
nextRun: calculateNextRun(job),
|
|
157
|
+
retryCount: 0, // Reset retries on resume
|
|
158
|
+
},
|
|
159
|
+
lastError: undefined,
|
|
160
|
+
lastStateChange: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Reset a failed job for retry
|
|
165
|
+
*
|
|
166
|
+
* @param job - The job to reset
|
|
167
|
+
* @returns Updated job
|
|
168
|
+
*/
|
|
169
|
+
export function resetJob(job) {
|
|
170
|
+
return {
|
|
171
|
+
...job,
|
|
172
|
+
status: 'idle',
|
|
173
|
+
schedule: {
|
|
174
|
+
...job.schedule,
|
|
175
|
+
retryCount: 0,
|
|
176
|
+
nextRun: calculateNextRun(job),
|
|
177
|
+
},
|
|
178
|
+
lastError: undefined,
|
|
179
|
+
lastStateChange: new Date().toISOString(),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=scheduled-job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-job.js","sourceRoot":"","sources":["../../../../src/core/scheduler/scheduled-job.ts"],"names":[],"mappings":"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"}
|