@fbdo/smart-agentic-calendar 0.1.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.
Files changed (154) hide show
  1. package/README.md +195 -0
  2. package/dist/analytics/allocation.d.ts +9 -0
  3. package/dist/analytics/allocation.d.ts.map +1 -0
  4. package/dist/analytics/allocation.js +27 -0
  5. package/dist/analytics/allocation.js.map +1 -0
  6. package/dist/analytics/analytics-engine.d.ts +17 -0
  7. package/dist/analytics/analytics-engine.d.ts.map +1 -0
  8. package/dist/analytics/analytics-engine.js +33 -0
  9. package/dist/analytics/analytics-engine.js.map +1 -0
  10. package/dist/analytics/estimation.d.ts +9 -0
  11. package/dist/analytics/estimation.d.ts.map +1 -0
  12. package/dist/analytics/estimation.js +74 -0
  13. package/dist/analytics/estimation.js.map +1 -0
  14. package/dist/analytics/health.d.ts +14 -0
  15. package/dist/analytics/health.d.ts.map +1 -0
  16. package/dist/analytics/health.js +146 -0
  17. package/dist/analytics/health.js.map +1 -0
  18. package/dist/analytics/period.d.ts +9 -0
  19. package/dist/analytics/period.d.ts.map +1 -0
  20. package/dist/analytics/period.js +41 -0
  21. package/dist/analytics/period.js.map +1 -0
  22. package/dist/analytics/productivity.d.ts +9 -0
  23. package/dist/analytics/productivity.d.ts.map +1 -0
  24. package/dist/analytics/productivity.js +34 -0
  25. package/dist/analytics/productivity.js.map +1 -0
  26. package/dist/common/constants.d.ts +13 -0
  27. package/dist/common/constants.d.ts.map +1 -0
  28. package/dist/common/constants.js +19 -0
  29. package/dist/common/constants.js.map +1 -0
  30. package/dist/common/id.d.ts +2 -0
  31. package/dist/common/id.d.ts.map +1 -0
  32. package/dist/common/id.js +5 -0
  33. package/dist/common/id.js.map +1 -0
  34. package/dist/common/time.d.ts +11 -0
  35. package/dist/common/time.d.ts.map +1 -0
  36. package/dist/common/time.js +67 -0
  37. package/dist/common/time.js.map +1 -0
  38. package/dist/engine/conflict-detector.d.ts +22 -0
  39. package/dist/engine/conflict-detector.d.ts.map +1 -0
  40. package/dist/engine/conflict-detector.js +194 -0
  41. package/dist/engine/conflict-detector.js.map +1 -0
  42. package/dist/engine/dependency-resolver.d.ts +8 -0
  43. package/dist/engine/dependency-resolver.d.ts.map +1 -0
  44. package/dist/engine/dependency-resolver.js +160 -0
  45. package/dist/engine/dependency-resolver.js.map +1 -0
  46. package/dist/engine/recurrence-manager.d.ts +24 -0
  47. package/dist/engine/recurrence-manager.d.ts.map +1 -0
  48. package/dist/engine/recurrence-manager.js +140 -0
  49. package/dist/engine/recurrence-manager.js.map +1 -0
  50. package/dist/engine/replan-coordinator.d.ts +24 -0
  51. package/dist/engine/replan-coordinator.d.ts.map +1 -0
  52. package/dist/engine/replan-coordinator.js +107 -0
  53. package/dist/engine/replan-coordinator.js.map +1 -0
  54. package/dist/engine/scheduler.d.ts +65 -0
  55. package/dist/engine/scheduler.d.ts.map +1 -0
  56. package/dist/engine/scheduler.js +368 -0
  57. package/dist/engine/scheduler.js.map +1 -0
  58. package/dist/index.d.ts +19 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +69 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/mcp/server.d.ts +25 -0
  63. package/dist/mcp/server.d.ts.map +1 -0
  64. package/dist/mcp/server.js +421 -0
  65. package/dist/mcp/server.js.map +1 -0
  66. package/dist/mcp/tools/analytics-tools.d.ts +45 -0
  67. package/dist/mcp/tools/analytics-tools.d.ts.map +1 -0
  68. package/dist/mcp/tools/analytics-tools.js +27 -0
  69. package/dist/mcp/tools/analytics-tools.js.map +1 -0
  70. package/dist/mcp/tools/config-tools.d.ts +55 -0
  71. package/dist/mcp/tools/config-tools.d.ts.map +1 -0
  72. package/dist/mcp/tools/config-tools.js +47 -0
  73. package/dist/mcp/tools/config-tools.js.map +1 -0
  74. package/dist/mcp/tools/event-tools.d.ts +50 -0
  75. package/dist/mcp/tools/event-tools.d.ts.map +1 -0
  76. package/dist/mcp/tools/event-tools.js +48 -0
  77. package/dist/mcp/tools/event-tools.js.map +1 -0
  78. package/dist/mcp/tools/schedule-tools.d.ts +80 -0
  79. package/dist/mcp/tools/schedule-tools.d.ts.map +1 -0
  80. package/dist/mcp/tools/schedule-tools.js +103 -0
  81. package/dist/mcp/tools/schedule-tools.js.map +1 -0
  82. package/dist/mcp/tools/task-tools.d.ts +106 -0
  83. package/dist/mcp/tools/task-tools.d.ts.map +1 -0
  84. package/dist/mcp/tools/task-tools.js +161 -0
  85. package/dist/mcp/tools/task-tools.js.map +1 -0
  86. package/dist/mcp/validators.d.ts +231 -0
  87. package/dist/mcp/validators.d.ts.map +1 -0
  88. package/dist/mcp/validators.js +405 -0
  89. package/dist/mcp/validators.js.map +1 -0
  90. package/dist/models/analytics.d.ts +55 -0
  91. package/dist/models/analytics.d.ts.map +1 -0
  92. package/dist/models/analytics.js +2 -0
  93. package/dist/models/analytics.js.map +1 -0
  94. package/dist/models/config.d.ts +32 -0
  95. package/dist/models/config.d.ts.map +1 -0
  96. package/dist/models/config.js +2 -0
  97. package/dist/models/config.js.map +1 -0
  98. package/dist/models/conflict.d.ts +21 -0
  99. package/dist/models/conflict.d.ts.map +1 -0
  100. package/dist/models/conflict.js +2 -0
  101. package/dist/models/conflict.js.map +1 -0
  102. package/dist/models/dependency.d.ts +5 -0
  103. package/dist/models/dependency.d.ts.map +1 -0
  104. package/dist/models/dependency.js +2 -0
  105. package/dist/models/dependency.js.map +1 -0
  106. package/dist/models/errors.d.ts +19 -0
  107. package/dist/models/errors.d.ts.map +1 -0
  108. package/dist/models/errors.js +29 -0
  109. package/dist/models/errors.js.map +1 -0
  110. package/dist/models/event.d.ts +11 -0
  111. package/dist/models/event.d.ts.map +1 -0
  112. package/dist/models/event.js +2 -0
  113. package/dist/models/event.js.map +1 -0
  114. package/dist/models/recurrence.d.ts +22 -0
  115. package/dist/models/recurrence.d.ts.map +1 -0
  116. package/dist/models/recurrence.js +2 -0
  117. package/dist/models/recurrence.js.map +1 -0
  118. package/dist/models/schedule.d.ts +16 -0
  119. package/dist/models/schedule.d.ts.map +1 -0
  120. package/dist/models/schedule.js +2 -0
  121. package/dist/models/schedule.js.map +1 -0
  122. package/dist/models/task.d.ts +21 -0
  123. package/dist/models/task.d.ts.map +1 -0
  124. package/dist/models/task.js +9 -0
  125. package/dist/models/task.js.map +1 -0
  126. package/dist/storage/analytics-repository.d.ts +17 -0
  127. package/dist/storage/analytics-repository.d.ts.map +1 -0
  128. package/dist/storage/analytics-repository.js +99 -0
  129. package/dist/storage/analytics-repository.js.map +1 -0
  130. package/dist/storage/config-repository.d.ts +20 -0
  131. package/dist/storage/config-repository.d.ts.map +1 -0
  132. package/dist/storage/config-repository.js +145 -0
  133. package/dist/storage/config-repository.js.map +1 -0
  134. package/dist/storage/database.d.ts +6 -0
  135. package/dist/storage/database.d.ts.map +1 -0
  136. package/dist/storage/database.js +160 -0
  137. package/dist/storage/database.js.map +1 -0
  138. package/dist/storage/event-repository.d.ts +16 -0
  139. package/dist/storage/event-repository.d.ts.map +1 -0
  140. package/dist/storage/event-repository.js +120 -0
  141. package/dist/storage/event-repository.js.map +1 -0
  142. package/dist/storage/recurrence-repository.d.ts +18 -0
  143. package/dist/storage/recurrence-repository.d.ts.map +1 -0
  144. package/dist/storage/recurrence-repository.js +99 -0
  145. package/dist/storage/recurrence-repository.js.map +1 -0
  146. package/dist/storage/schedule-repository.d.ts +13 -0
  147. package/dist/storage/schedule-repository.d.ts.map +1 -0
  148. package/dist/storage/schedule-repository.js +53 -0
  149. package/dist/storage/schedule-repository.js.map +1 -0
  150. package/dist/storage/task-repository.d.ts +29 -0
  151. package/dist/storage/task-repository.d.ts.map +1 -0
  152. package/dist/storage/task-repository.js +235 -0
  153. package/dist/storage/task-repository.js.map +1 -0
  154. package/package.json +77 -0
@@ -0,0 +1,145 @@
1
+ import { ValidationError } from "../models/errors.js";
2
+ import { isValidTimeHHMM } from "../common/time.js";
3
+ import { DEFAULT_BUFFER_TIME_MINUTES, DEFAULT_PRIORITY, DEFAULT_DURATION_MINUTES, DEFAULT_SCHEDULING_HORIZON_WEEKS, DEFAULT_MINIMUM_BLOCK_MINUTES, DEFAULT_FOCUS_TIME_MINIMUM_BLOCK_MINUTES, MAX_SCHEDULING_HORIZON_WEEKS, MIN_MINIMUM_BLOCK_MINUTES, MAX_MINIMUM_BLOCK_MINUTES, } from "../common/constants.js";
4
+ export class ConfigRepository {
5
+ db;
6
+ constructor(db) {
7
+ this.db = db;
8
+ }
9
+ getAvailability() {
10
+ const rows = this.db
11
+ .prepare("SELECT day, start_time, end_time FROM config_availability ORDER BY day ASC, start_time ASC")
12
+ .all();
13
+ return {
14
+ windows: rows.map((row) => this.rowToAvailabilityWindow(row)),
15
+ };
16
+ }
17
+ setAvailability(availability) {
18
+ for (const window of availability.windows) {
19
+ this.validateDayAndTime(window.day, window.startTime, window.endTime);
20
+ }
21
+ this.db.transaction(() => {
22
+ this.db.prepare("DELETE FROM config_availability").run();
23
+ const insert = this.db.prepare("INSERT INTO config_availability (day, start_time, end_time) VALUES (?, ?, ?)");
24
+ for (const window of availability.windows) {
25
+ insert.run(window.day, window.startTime, window.endTime);
26
+ }
27
+ })();
28
+ }
29
+ getFocusTime() {
30
+ const rows = this.db
31
+ .prepare("SELECT day, start_time, end_time FROM config_focus_time ORDER BY day ASC, start_time ASC")
32
+ .all();
33
+ const minRow = this.db
34
+ .prepare("SELECT value FROM config_preferences WHERE key = 'focus_time_minimum_block_minutes'")
35
+ .get();
36
+ return {
37
+ blocks: rows.map((row) => this.rowToFocusBlock(row)),
38
+ minimumBlockMinutes: minRow
39
+ ? JSON.parse(minRow.value)
40
+ : DEFAULT_FOCUS_TIME_MINIMUM_BLOCK_MINUTES,
41
+ };
42
+ }
43
+ setFocusTime(focusTime) {
44
+ for (const block of focusTime.blocks) {
45
+ this.validateDayAndTime(block.day, block.startTime, block.endTime);
46
+ }
47
+ this.db.transaction(() => {
48
+ this.db.prepare("DELETE FROM config_focus_time").run();
49
+ const insert = this.db.prepare("INSERT INTO config_focus_time (day, start_time, end_time) VALUES (?, ?, ?)");
50
+ for (const block of focusTime.blocks) {
51
+ insert.run(block.day, block.startTime, block.endTime);
52
+ }
53
+ this.db
54
+ .prepare("INSERT OR REPLACE INTO config_preferences (key, value) VALUES (?, ?)")
55
+ .run("focus_time_minimum_block_minutes", JSON.stringify(focusTime.minimumBlockMinutes));
56
+ })();
57
+ }
58
+ getPreferences() {
59
+ const rows = this.db
60
+ .prepare("SELECT key, value FROM config_preferences WHERE key IN ('buffer_time_minutes', 'default_priority', 'default_duration', 'scheduling_horizon_weeks', 'minimum_block_minutes')")
61
+ .all();
62
+ return this.preferencesFromRows(rows);
63
+ }
64
+ setPreferences(preferences) {
65
+ if (preferences.bufferTimeMinutes !== undefined && preferences.bufferTimeMinutes < 0) {
66
+ throw new ValidationError("buffer time must be non-negative");
67
+ }
68
+ if (preferences.defaultDuration !== undefined && preferences.defaultDuration <= 0) {
69
+ throw new ValidationError("default duration must be positive");
70
+ }
71
+ if (preferences.schedulingHorizonWeeks !== undefined &&
72
+ (preferences.schedulingHorizonWeeks < 1 ||
73
+ preferences.schedulingHorizonWeeks > MAX_SCHEDULING_HORIZON_WEEKS)) {
74
+ throw new ValidationError(`scheduling horizon must be between 1 and ${MAX_SCHEDULING_HORIZON_WEEKS} weeks`);
75
+ }
76
+ if (preferences.minimumBlockMinutes !== undefined &&
77
+ (preferences.minimumBlockMinutes < MIN_MINIMUM_BLOCK_MINUTES ||
78
+ preferences.minimumBlockMinutes > MAX_MINIMUM_BLOCK_MINUTES)) {
79
+ throw new ValidationError(`minimum block must be between ${MIN_MINIMUM_BLOCK_MINUTES} and ${MAX_MINIMUM_BLOCK_MINUTES} minutes`);
80
+ }
81
+ const keyMap = {
82
+ bufferTimeMinutes: "buffer_time_minutes",
83
+ defaultPriority: "default_priority",
84
+ defaultDuration: "default_duration",
85
+ schedulingHorizonWeeks: "scheduling_horizon_weeks",
86
+ minimumBlockMinutes: "minimum_block_minutes",
87
+ };
88
+ const upsert = this.db.prepare("INSERT OR REPLACE INTO config_preferences (key, value) VALUES (?, ?)");
89
+ for (const [prop, dbKey] of Object.entries(keyMap)) {
90
+ const value = preferences[prop];
91
+ if (value !== undefined) {
92
+ upsert.run(dbKey, JSON.stringify(value));
93
+ }
94
+ }
95
+ }
96
+ getFullConfig() {
97
+ return {
98
+ availability: this.getAvailability(),
99
+ focusTime: this.getFocusTime(),
100
+ preferences: this.getPreferences(),
101
+ };
102
+ }
103
+ validateDayAndTime(day, startTime, endTime) {
104
+ if (day < 0 || day > 6 || !Number.isInteger(day)) {
105
+ throw new ValidationError("invalid day of week");
106
+ }
107
+ if (!isValidTimeHHMM(startTime)) {
108
+ throw new ValidationError("invalid time format");
109
+ }
110
+ if (!isValidTimeHHMM(endTime)) {
111
+ throw new ValidationError("invalid time format");
112
+ }
113
+ if (endTime <= startTime) {
114
+ throw new ValidationError("end time must be after start time");
115
+ }
116
+ }
117
+ rowToAvailabilityWindow(row) {
118
+ return this.rowToDayTimeRange(row);
119
+ }
120
+ rowToFocusBlock(row) {
121
+ return this.rowToDayTimeRange(row);
122
+ }
123
+ rowToDayTimeRange(row) {
124
+ return {
125
+ day: row.day,
126
+ startTime: row.start_time,
127
+ endTime: row.end_time,
128
+ };
129
+ }
130
+ parsePref(map, key, fallback) {
131
+ const raw = map.get(key);
132
+ return raw !== undefined ? JSON.parse(raw) : fallback;
133
+ }
134
+ preferencesFromRows(rows) {
135
+ const map = new Map(rows.map((r) => [r.key, r.value]));
136
+ return {
137
+ bufferTimeMinutes: this.parsePref(map, "buffer_time_minutes", DEFAULT_BUFFER_TIME_MINUTES),
138
+ defaultPriority: this.parsePref(map, "default_priority", DEFAULT_PRIORITY),
139
+ defaultDuration: this.parsePref(map, "default_duration", DEFAULT_DURATION_MINUTES),
140
+ schedulingHorizonWeeks: this.parsePref(map, "scheduling_horizon_weeks", DEFAULT_SCHEDULING_HORIZON_WEEKS),
141
+ minimumBlockMinutes: this.parsePref(map, "minimum_block_minutes", DEFAULT_MINIMUM_BLOCK_MINUTES),
142
+ };
143
+ }
144
+ }
145
+ //# sourceMappingURL=config-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-repository.js","sourceRoot":"","sources":["../../src/storage/config-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import BetterSqlite3 from "better-sqlite3";
2
+ export declare const LATEST_VERSION: number;
3
+ export declare class Database extends BetterSqlite3 {
4
+ constructor(filename: string);
5
+ }
6
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAC;AA2I3C,eAAO,MAAM,cAAc,QAAmD,CAAC;AAsB/E,qBAAa,QAAS,SAAQ,aAAa;gBAC7B,QAAQ,EAAE,MAAM;CAM7B"}
@@ -0,0 +1,160 @@
1
+ import BetterSqlite3 from "better-sqlite3";
2
+ const migrations = {
3
+ 1: (db) => {
4
+ db.exec(`
5
+ CREATE TABLE IF NOT EXISTS recurrence_templates (
6
+ id TEXT PRIMARY KEY,
7
+ task_data TEXT NOT NULL,
8
+ rrule TEXT NOT NULL,
9
+ is_active INTEGER NOT NULL DEFAULT 1,
10
+ created_at TEXT NOT NULL
11
+ );
12
+
13
+ CREATE TABLE IF NOT EXISTS tasks (
14
+ id TEXT PRIMARY KEY,
15
+ title TEXT NOT NULL,
16
+ description TEXT,
17
+ duration INTEGER NOT NULL,
18
+ deadline TEXT,
19
+ priority TEXT NOT NULL DEFAULT 'P3',
20
+ status TEXT NOT NULL DEFAULT 'pending',
21
+ category TEXT,
22
+ tags TEXT NOT NULL DEFAULT '[]',
23
+ is_recurring INTEGER NOT NULL DEFAULT 0,
24
+ recurrence_template_id TEXT,
25
+ actual_duration INTEGER,
26
+ created_at TEXT NOT NULL,
27
+ updated_at TEXT NOT NULL,
28
+ FOREIGN KEY (recurrence_template_id) REFERENCES recurrence_templates(id)
29
+ );
30
+
31
+ CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
32
+ CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
33
+ CREATE INDEX IF NOT EXISTS idx_tasks_deadline ON tasks(deadline);
34
+ CREATE INDEX IF NOT EXISTS idx_tasks_category ON tasks(category);
35
+ CREATE INDEX IF NOT EXISTS idx_tasks_recurrence_template ON tasks(recurrence_template_id);
36
+
37
+ CREATE TABLE IF NOT EXISTS events (
38
+ id TEXT PRIMARY KEY,
39
+ title TEXT NOT NULL,
40
+ start_time TEXT,
41
+ end_time TEXT,
42
+ is_all_day INTEGER NOT NULL DEFAULT 0,
43
+ date TEXT,
44
+ created_at TEXT NOT NULL,
45
+ updated_at TEXT NOT NULL
46
+ );
47
+
48
+ CREATE INDEX IF NOT EXISTS idx_events_start ON events(start_time);
49
+ CREATE INDEX IF NOT EXISTS idx_events_date ON events(date);
50
+
51
+ CREATE TABLE IF NOT EXISTS time_blocks (
52
+ id TEXT PRIMARY KEY,
53
+ task_id TEXT NOT NULL,
54
+ start_time TEXT NOT NULL,
55
+ end_time TEXT NOT NULL,
56
+ date TEXT NOT NULL,
57
+ block_index INTEGER NOT NULL DEFAULT 0,
58
+ total_blocks INTEGER NOT NULL DEFAULT 1,
59
+ FOREIGN KEY (task_id) REFERENCES tasks(id)
60
+ );
61
+
62
+ CREATE INDEX IF NOT EXISTS idx_time_blocks_task ON time_blocks(task_id);
63
+ CREATE INDEX IF NOT EXISTS idx_time_blocks_date ON time_blocks(date);
64
+ CREATE INDEX IF NOT EXISTS idx_time_blocks_start ON time_blocks(start_time);
65
+
66
+ CREATE TABLE IF NOT EXISTS dependencies (
67
+ task_id TEXT NOT NULL,
68
+ depends_on_id TEXT NOT NULL,
69
+ PRIMARY KEY (task_id, depends_on_id),
70
+ FOREIGN KEY (task_id) REFERENCES tasks(id),
71
+ FOREIGN KEY (depends_on_id) REFERENCES tasks(id)
72
+ );
73
+
74
+ CREATE TABLE IF NOT EXISTS schedule_status (
75
+ id INTEGER PRIMARY KEY CHECK (id = 1),
76
+ status TEXT NOT NULL DEFAULT 'up_to_date',
77
+ last_replan_at TEXT
78
+ );
79
+
80
+ CREATE TABLE IF NOT EXISTS config_availability (
81
+ day INTEGER NOT NULL,
82
+ start_time TEXT NOT NULL,
83
+ end_time TEXT NOT NULL,
84
+ PRIMARY KEY (day, start_time)
85
+ );
86
+
87
+ CREATE TABLE IF NOT EXISTS config_focus_time (
88
+ day INTEGER NOT NULL,
89
+ start_time TEXT NOT NULL,
90
+ end_time TEXT NOT NULL,
91
+ PRIMARY KEY (day, start_time)
92
+ );
93
+
94
+ CREATE TABLE IF NOT EXISTS config_preferences (
95
+ key TEXT PRIMARY KEY,
96
+ value TEXT NOT NULL
97
+ );
98
+
99
+ CREATE TABLE IF NOT EXISTS recurrence_instances (
100
+ id TEXT PRIMARY KEY,
101
+ template_id TEXT NOT NULL,
102
+ task_id TEXT NOT NULL,
103
+ scheduled_date TEXT NOT NULL,
104
+ is_exception INTEGER NOT NULL DEFAULT 0,
105
+ FOREIGN KEY (template_id) REFERENCES recurrence_templates(id),
106
+ FOREIGN KEY (task_id) REFERENCES tasks(id)
107
+ );
108
+
109
+ CREATE INDEX IF NOT EXISTS idx_recurrence_instances_template ON recurrence_instances(template_id);
110
+ CREATE INDEX IF NOT EXISTS idx_recurrence_instances_date ON recurrence_instances(scheduled_date);
111
+
112
+ CREATE TABLE IF NOT EXISTS recurrence_exceptions (
113
+ template_id TEXT NOT NULL,
114
+ date TEXT NOT NULL,
115
+ type TEXT NOT NULL,
116
+ overrides TEXT,
117
+ PRIMARY KEY (template_id, date),
118
+ FOREIGN KEY (template_id) REFERENCES recurrence_templates(id)
119
+ );
120
+
121
+ INSERT OR IGNORE INTO schedule_status (id, status, last_replan_at) VALUES (1, 'up_to_date', NULL);
122
+
123
+ INSERT OR IGNORE INTO config_preferences (key, value) VALUES
124
+ ('buffer_time_minutes', '15'),
125
+ ('default_priority', '"P3"'),
126
+ ('default_duration', '60'),
127
+ ('scheduling_horizon_weeks', '4'),
128
+ ('minimum_block_minutes', '30'),
129
+ ('focus_time_minimum_block_minutes', '60');
130
+ `);
131
+ },
132
+ // Future migrations go here:
133
+ // 2: (db) => { db.exec("ALTER TABLE tasks ADD COLUMN notes TEXT"); },
134
+ };
135
+ export const LATEST_VERSION = Math.max(...Object.keys(migrations).map(Number));
136
+ function runMigrations(db) {
137
+ const currentVersion = db.pragma("user_version")[0].user_version;
138
+ if (currentVersion >= LATEST_VERSION) {
139
+ return;
140
+ }
141
+ for (let version = currentVersion + 1; version <= LATEST_VERSION; version++) {
142
+ const migration = migrations[version];
143
+ if (!migration) {
144
+ throw new Error(`Missing migration for version ${version}`);
145
+ }
146
+ db.transaction(() => {
147
+ migration(db);
148
+ db.pragma(`user_version = ${version}`);
149
+ })();
150
+ }
151
+ }
152
+ export class Database extends BetterSqlite3 {
153
+ constructor(filename) {
154
+ super(filename);
155
+ this.pragma("journal_mode = WAL");
156
+ this.pragma("foreign_keys = ON");
157
+ runMigrations(this);
158
+ }
159
+ }
160
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAI3C,MAAM,UAAU,GAA8B;IAC5C,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;QACR,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8HP,CAAC,CAAC;IACL,CAAC;IAED,6BAA6B;IAC7B,sEAAsE;CACvE,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAE/E,SAAS,aAAa,CAAC,EAA0B;IAC/C,MAAM,cAAc,GAAI,EAAE,CAAC,MAAM,CAAC,cAAc,CAAgC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAEjG,IAAI,cAAc,IAAI,cAAc,EAAE,CAAC;QACrC,OAAO;IACT,CAAC;IAED,KAAK,IAAI,OAAO,GAAG,cAAc,GAAG,CAAC,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,EAAE,EAAE,CAAC;QAC5E,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;YAClB,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,EAAE,CAAC,MAAM,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;AACH,CAAC;AAED,MAAM,OAAO,QAAS,SAAQ,aAAa;IACzC,YAAY,QAAgB;QAC1B,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACjC,aAAa,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import type { Event } from "../models/event.js";
2
+ import type { Database } from "./database.js";
3
+ type EventInput = Omit<Event, "id" | "createdAt" | "updatedAt">;
4
+ type EventUpdates = Partial<Pick<Event, "title" | "startTime" | "endTime" | "isAllDay" | "date">>;
5
+ export declare class EventRepository {
6
+ private readonly db;
7
+ constructor(db: Database);
8
+ create(input: EventInput): Event;
9
+ findById(id: string): Event | undefined;
10
+ findInRange(start: string, end: string): Event[];
11
+ update(id: string, updates: EventUpdates): Event;
12
+ delete(id: string): void;
13
+ private rowToEvent;
14
+ }
15
+ export {};
16
+ //# sourceMappingURL=event-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-repository.d.ts","sourceRoot":"","sources":["../../src/storage/event-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAIhD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAa9C,KAAK,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC;AAChE,KAAK,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC;AAElG,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;gBAElB,EAAE,EAAE,QAAQ;IAIxB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK;IAqDhC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAQvC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE;IAmBhD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,KAAK;IAwChD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAOxB,OAAO,CAAC,UAAU;CAYnB"}
@@ -0,0 +1,120 @@
1
+ import { ValidationError, NotFoundError } from "../models/errors.js";
2
+ import { generateId } from "../common/id.js";
3
+ import { nowUTC } from "../common/time.js";
4
+ export class EventRepository {
5
+ db;
6
+ constructor(db) {
7
+ this.db = db;
8
+ }
9
+ create(input) {
10
+ const title = input.title.trim();
11
+ if (!title) {
12
+ throw new ValidationError("title is required");
13
+ }
14
+ if (!input.isAllDay) {
15
+ if (!input.startTime) {
16
+ throw new ValidationError("start time is required");
17
+ }
18
+ if (!input.endTime) {
19
+ throw new ValidationError("end time must be after start time");
20
+ }
21
+ if (input.endTime <= input.startTime) {
22
+ throw new ValidationError("end time must be after start time");
23
+ }
24
+ }
25
+ else {
26
+ if (!input.date) {
27
+ throw new ValidationError("date is required for all-day events");
28
+ }
29
+ }
30
+ const now = nowUTC();
31
+ const event = {
32
+ id: generateId(),
33
+ title,
34
+ startTime: input.startTime,
35
+ endTime: input.endTime,
36
+ isAllDay: input.isAllDay,
37
+ date: input.date,
38
+ createdAt: now,
39
+ updatedAt: now,
40
+ };
41
+ this.db
42
+ .prepare(`INSERT INTO events (id, title, start_time, end_time, is_all_day, date, created_at, updated_at)
43
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
44
+ .run(event.id, event.title, event.startTime, event.endTime, event.isAllDay ? 1 : 0, event.date, event.createdAt, event.updatedAt);
45
+ return event;
46
+ }
47
+ findById(id) {
48
+ const row = this.db.prepare("SELECT * FROM events WHERE id = ?").get(id);
49
+ if (!row)
50
+ return undefined;
51
+ return this.rowToEvent(row);
52
+ }
53
+ findInRange(start, end) {
54
+ const startDate = start.substring(0, 10);
55
+ const endDate = end.substring(0, 10);
56
+ const rows = this.db
57
+ .prepare(`SELECT * FROM events
58
+ WHERE
59
+ (is_all_day = 0 AND start_time < ? AND end_time > ?)
60
+ OR
61
+ (is_all_day = 1 AND date >= ? AND date <= ?)
62
+ ORDER BY
63
+ CASE WHEN is_all_day = 1 THEN date ELSE start_time END ASC`)
64
+ .all(end, start, startDate, endDate);
65
+ return rows.map((row) => this.rowToEvent(row));
66
+ }
67
+ update(id, updates) {
68
+ const setClauses = [];
69
+ const params = [];
70
+ if (updates.title !== undefined) {
71
+ setClauses.push("title = ?");
72
+ params.push(updates.title.trim());
73
+ }
74
+ if (updates.startTime !== undefined) {
75
+ setClauses.push("start_time = ?");
76
+ params.push(updates.startTime);
77
+ }
78
+ if (updates.endTime !== undefined) {
79
+ setClauses.push("end_time = ?");
80
+ params.push(updates.endTime);
81
+ }
82
+ if (updates.isAllDay !== undefined) {
83
+ setClauses.push("is_all_day = ?");
84
+ params.push(updates.isAllDay ? 1 : 0);
85
+ }
86
+ if (updates.date !== undefined) {
87
+ setClauses.push("date = ?");
88
+ params.push(updates.date);
89
+ }
90
+ setClauses.push("updated_at = ?");
91
+ params.push(nowUTC());
92
+ params.push(id);
93
+ const result = this.db
94
+ .prepare(`UPDATE events SET ${setClauses.join(", ")} WHERE id = ?`)
95
+ .run(...params);
96
+ if (result.changes === 0) {
97
+ throw new NotFoundError("Event", id);
98
+ }
99
+ return this.findById(id);
100
+ }
101
+ delete(id) {
102
+ const result = this.db.prepare("DELETE FROM events WHERE id = ?").run(id);
103
+ if (result.changes === 0) {
104
+ throw new NotFoundError("Event", id);
105
+ }
106
+ }
107
+ rowToEvent(row) {
108
+ return {
109
+ id: row.id,
110
+ title: row.title,
111
+ startTime: row.start_time,
112
+ endTime: row.end_time,
113
+ isAllDay: !!row.is_all_day,
114
+ date: row.date,
115
+ createdAt: row.created_at,
116
+ updatedAt: row.updated_at,
117
+ };
118
+ }
119
+ }
120
+ //# sourceMappingURL=event-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-repository.js","sourceRoot":"","sources":["../../src/storage/event-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { RecurrenceTemplate, RecurrenceInstance, RecurrenceException } from "../models/recurrence.js";
2
+ import type { Database } from "./database.js";
3
+ export declare class RecurrenceRepository {
4
+ private readonly db;
5
+ constructor(db: Database);
6
+ createTemplate(input: Omit<RecurrenceTemplate, "id" | "createdAt" | "isActive">): RecurrenceTemplate;
7
+ getTemplate(id: string): RecurrenceTemplate | undefined;
8
+ getActiveTemplates(): RecurrenceTemplate[];
9
+ deleteTemplate(id: string): void;
10
+ createInstance(input: Omit<RecurrenceInstance, "id">): RecurrenceInstance;
11
+ getInstances(templateId: string, start: string, end: string): RecurrenceInstance[];
12
+ addException(templateId: string, date: string, exception: Omit<RecurrenceException, "templateId" | "date">): void;
13
+ getExceptions(templateId: string): RecurrenceException[];
14
+ private rowToTemplate;
15
+ private rowToInstance;
16
+ private rowToException;
17
+ }
18
+ //# sourceMappingURL=recurrence-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recurrence-repository.d.ts","sourceRoot":"","sources":["../../src/storage/recurrence-repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AA2B9C,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;gBAElB,EAAE,EAAE,QAAQ;IAIxB,cAAc,CACZ,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,CAAC,GAC/D,kBAAkB;IAkBrB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IASvD,kBAAkB,IAAI,kBAAkB,EAAE;IAQ1C,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAUhC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAAG,kBAAkB;IAwBzE,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAUlF,YAAY,CACV,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,MAAM,CAAC,GAC1D,IAAI;IAaP,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAQxD,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,cAAc;CAQvB"}
@@ -0,0 +1,99 @@
1
+ import { NotFoundError } from "../models/errors.js";
2
+ import { generateId } from "../common/id.js";
3
+ import { nowUTC } from "../common/time.js";
4
+ export class RecurrenceRepository {
5
+ db;
6
+ constructor(db) {
7
+ this.db = db;
8
+ }
9
+ createTemplate(input) {
10
+ const template = {
11
+ id: generateId(),
12
+ taskData: input.taskData,
13
+ rrule: input.rrule,
14
+ isActive: true,
15
+ createdAt: nowUTC(),
16
+ };
17
+ this.db
18
+ .prepare("INSERT INTO recurrence_templates (id, task_data, rrule, is_active, created_at) VALUES (?, ?, ?, 1, ?)")
19
+ .run(template.id, JSON.stringify(template.taskData), template.rrule, template.createdAt);
20
+ return template;
21
+ }
22
+ getTemplate(id) {
23
+ const row = this.db.prepare("SELECT * FROM recurrence_templates WHERE id = ?").get(id);
24
+ if (!row)
25
+ return undefined;
26
+ return this.rowToTemplate(row);
27
+ }
28
+ getActiveTemplates() {
29
+ const rows = this.db
30
+ .prepare("SELECT * FROM recurrence_templates WHERE is_active = 1 ORDER BY created_at ASC")
31
+ .all();
32
+ return rows.map((row) => this.rowToTemplate(row));
33
+ }
34
+ deleteTemplate(id) {
35
+ const result = this.db
36
+ .prepare("UPDATE recurrence_templates SET is_active = 0 WHERE id = ?")
37
+ .run(id);
38
+ if (result.changes === 0) {
39
+ throw new NotFoundError("RecurrenceTemplate", id);
40
+ }
41
+ }
42
+ createInstance(input) {
43
+ const instance = {
44
+ id: generateId(),
45
+ templateId: input.templateId,
46
+ taskId: input.taskId,
47
+ scheduledDate: input.scheduledDate,
48
+ isException: input.isException,
49
+ };
50
+ this.db
51
+ .prepare("INSERT INTO recurrence_instances (id, template_id, task_id, scheduled_date, is_exception) VALUES (?, ?, ?, ?, ?)")
52
+ .run(instance.id, instance.templateId, instance.taskId, instance.scheduledDate, instance.isException ? 1 : 0);
53
+ return instance;
54
+ }
55
+ getInstances(templateId, start, end) {
56
+ const rows = this.db
57
+ .prepare("SELECT * FROM recurrence_instances WHERE template_id = ? AND scheduled_date >= ? AND scheduled_date <= ? ORDER BY scheduled_date ASC")
58
+ .all(templateId, start, end);
59
+ return rows.map((row) => this.rowToInstance(row));
60
+ }
61
+ addException(templateId, date, exception) {
62
+ this.db
63
+ .prepare("INSERT OR REPLACE INTO recurrence_exceptions (template_id, date, type, overrides) VALUES (?, ?, ?, ?)")
64
+ .run(templateId, date, exception.type, exception.overrides ? JSON.stringify(exception.overrides) : null);
65
+ }
66
+ getExceptions(templateId) {
67
+ const rows = this.db
68
+ .prepare("SELECT * FROM recurrence_exceptions WHERE template_id = ? ORDER BY date ASC")
69
+ .all(templateId);
70
+ return rows.map((row) => this.rowToException(row));
71
+ }
72
+ rowToTemplate(row) {
73
+ return {
74
+ id: row.id,
75
+ taskData: JSON.parse(row.task_data),
76
+ rrule: row.rrule,
77
+ isActive: !!row.is_active,
78
+ createdAt: row.created_at,
79
+ };
80
+ }
81
+ rowToInstance(row) {
82
+ return {
83
+ id: row.id,
84
+ templateId: row.template_id,
85
+ taskId: row.task_id,
86
+ scheduledDate: row.scheduled_date,
87
+ isException: !!row.is_exception,
88
+ };
89
+ }
90
+ rowToException(row) {
91
+ return {
92
+ templateId: row.template_id,
93
+ date: row.date,
94
+ type: row.type,
95
+ overrides: row.overrides ? JSON.parse(row.overrides) : null,
96
+ };
97
+ }
98
+ }
99
+ //# sourceMappingURL=recurrence-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recurrence-repository.js","sourceRoot":"","sources":["../../src/storage/recurrence-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { TimeBlock, ScheduleStatus } from "../models/schedule.js";
2
+ import type { Database } from "./database.js";
3
+ export declare class ScheduleRepository {
4
+ private readonly db;
5
+ constructor(db: Database);
6
+ saveSchedule(timeBlocks: TimeBlock[]): void;
7
+ getSchedule(start: string, end: string): TimeBlock[];
8
+ getScheduleStatus(): ScheduleStatus;
9
+ setScheduleStatus(status: ScheduleStatus): void;
10
+ clearSchedule(): void;
11
+ private rowToTimeBlock;
12
+ }
13
+ //# sourceMappingURL=schedule-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule-repository.d.ts","sourceRoot":"","sources":["../../src/storage/schedule-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAY9C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;gBAElB,EAAE,EAAE,QAAQ;IAIxB,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI;IAoB3C,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE;IAUpD,iBAAiB,IAAI,cAAc;IAOnC,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAc/C,aAAa,IAAI,IAAI;IAIrB,OAAO,CAAC,cAAc;CAWvB"}