mps 0.5.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.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +29 -0
- data/.gitignore +13 -0
- data/CLAUDE.md +102 -0
- data/GETTING_STARTED.md +447 -0
- data/Gemfile +6 -0
- data/IMPROVEMENTS.md +90 -0
- data/README.md +183 -0
- data/Rakefile +18 -0
- data/bin/console +38 -0
- data/bin/setup +8 -0
- data/exe/mps +5 -0
- data/lib/cli/mps.rb +442 -0
- data/lib/mps/config.rb +64 -0
- data/lib/mps/constants.rb +68 -0
- data/lib/mps/elements/element.rb +49 -0
- data/lib/mps/elements/elements.rb +6 -0
- data/lib/mps/elements/log.rb +32 -0
- data/lib/mps/elements/mps.rb +15 -0
- data/lib/mps/elements/note.rb +15 -0
- data/lib/mps/elements/reminder.rb +16 -0
- data/lib/mps/elements/task.rb +19 -0
- data/lib/mps/engines/engines.rb +1 -0
- data/lib/mps/engines/mps.rb +108 -0
- data/lib/mps/interpolators/interpolators.rb +1 -0
- data/lib/mps/interpolators/time.rb +11 -0
- data/lib/mps/mps.rb +32 -0
- data/lib/mps/store.rb +75 -0
- data/lib/mps/version.rb +5 -0
- data/lib/mps.rb +21 -0
- data/mps.gemspec +49 -0
- data/rust_rollout_spec.md +935 -0
- metadata +258 -0
|
@@ -0,0 +1,935 @@
|
|
|
1
|
+
# MPS Rust Rollout Specification
|
|
2
|
+
|
|
3
|
+
## 1. Current Ruby Implementation Analysis
|
|
4
|
+
|
|
5
|
+
### 1.1 Design Patterns Currently Used
|
|
6
|
+
|
|
7
|
+
| Pattern | Implementation | Assessment |
|
|
8
|
+
|---------|---------------|------------|
|
|
9
|
+
| **Module Namespace** | `module MPS { ... }` | Basic organization, no isolation |
|
|
10
|
+
| **Mixins/Traits** | `include Element` | No real interface enforcement |
|
|
11
|
+
| **Strategy** | Element classes (Task, Note, etc.) | Implicit, no trait bounds |
|
|
12
|
+
| **Factory** | `Engines::MPS.parse_mps_file_to_elments_hash` | Tightly coupled to StringScanner |
|
|
13
|
+
| **Registry** | `MPS::Elements.constants` | Runtime reflection (eval), fragile |
|
|
14
|
+
| **Configuration Object** | `Config` class | Simple but rigid |
|
|
15
|
+
|
|
16
|
+
### 1.2 Current Limitations
|
|
17
|
+
|
|
18
|
+
1. **No Type Safety**: Ruby dynamic typing - no compile-time guarantees
|
|
19
|
+
2. **No Plugin Architecture**: Hardcoded element types, cannot add AI agents at runtime
|
|
20
|
+
3. **No Event System**: Reminders are passive data only, no active notification mechanism
|
|
21
|
+
4. **No Async Support**: Synchronous file I/O blocks everything
|
|
22
|
+
5. **No Persistence Abstention**: Hardcoded YAML, cannot swap to SQLite/PostgreSQL
|
|
23
|
+
6. **Tight Coupling**: Parser (`Engine::MPS`) directly creates elements with `eval`
|
|
24
|
+
7. **No Query System**: Cannot filter/search elements efficiently
|
|
25
|
+
8. **No Error Hierarchy**: Catches generic `Exception`, no typed errors
|
|
26
|
+
9. **No Testing Infrastructure**: Minimal test coverage
|
|
27
|
+
10. **No Serialization Framework**: Cannot export to JSON/CSV/etc.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Rust Architecture Specification
|
|
32
|
+
|
|
33
|
+
### 2.1 Core Design Patterns
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ APPLICATION LAYER │
|
|
38
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
|
|
39
|
+
│ │ CLI (Clap) │ │ REPL REPL │ │ TUI (Ratratat) │ │
|
|
40
|
+
│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
|
|
41
|
+
└─────────┼────────────────┼──────────────────────┼───────────────┘
|
|
42
|
+
│ │ │
|
|
43
|
+
▼ ▼ ▼
|
|
44
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ DOMAIN LAYER (Core) │
|
|
46
|
+
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
47
|
+
│ │ DOMAIN MODEL │ │
|
|
48
|
+
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │ │
|
|
49
|
+
│ │ │ Task │ │ Note │ │ Reminder │ │ Log │ │ │
|
|
50
|
+
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │ │
|
|
51
|
+
│ │ └────────────┴────────────┴──────────────┘ │ │
|
|
52
|
+
│ │ ▼ │ │
|
|
53
|
+
│ │ ┌──────────────────┐ │ │
|
|
54
|
+
│ │ │ Element (Trait) │ ◄─── Super Trait │ │
|
|
55
|
+
│ │ │ - id: Uuid │ │ │
|
|
56
|
+
│ │ │ - created_at │ │ │
|
|
57
|
+
│ │ │ - updated_at │ │ │
|
|
58
|
+
│ │ │ - metadata │ │ │
|
|
59
|
+
│ │ └──────────────────┘ │ │
|
|
60
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
61
|
+
│ │
|
|
62
|
+
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
63
|
+
│ │ AGGREGATE ROOT │ │
|
|
64
|
+
│ │ ┌─────────────────────────────────────────────────────┐ │ │
|
|
65
|
+
│ │ │ MpsFile (Aggregate) │ │ │
|
|
66
|
+
│ │ │ - id: DateStamp │ │ │
|
|
67
|
+
│ │ │ - elements: Vec<Box<dyn Element>> │ │ │
|
|
68
|
+
│ │ │ - add_element(), remove_element(), query() │ │ │
|
|
69
|
+
│ │ └─────────────────────────────────────────────────────┘ │ │
|
|
70
|
+
│ └──────────────────────────────────────────────────────────┘ │
|
|
71
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
72
|
+
│
|
|
73
|
+
▼
|
|
74
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
75
|
+
│ APPLICATION SERVICES │
|
|
76
|
+
│ ┌────────────────┐ ┌────────────────┐ ┌──────────────────┐ │
|
|
77
|
+
│ │ Parser Service │ │ Query Service │ │ Export Service │ │
|
|
78
|
+
│ └───────┬────────┘ └───────┬────────┘ └────────┬─────────┘ │
|
|
79
|
+
└──────────┼───────────────────┼─────────────────────┼───────────┘
|
|
80
|
+
│ │ │
|
|
81
|
+
▼ ▼ ▼
|
|
82
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
83
|
+
│ INFRASTRUCTURE LAYER │
|
|
84
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
|
|
85
|
+
│ │ File Storage │ │ SQLite │ │ AI Agent Plugin │ │
|
|
86
|
+
│ │ (YAML/JSON) │ │ Repository │ │ System (Plugin) │ │
|
|
87
|
+
│ └──────────────┘ └──────────────┘ └───────────────────────┘ │
|
|
88
|
+
│ │
|
|
89
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
|
|
90
|
+
│ │ Notification │ │ Scheduler │ │ Pluggable AI │ │
|
|
91
|
+
│ │ Service │ │ (Async) │ │ Bridge │ │
|
|
92
|
+
│ └──────────────┘ └──────────────┘ └───────────────────────┘ │
|
|
93
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 2.2 Architectural Patterns Used
|
|
97
|
+
|
|
98
|
+
| Pattern | Where Applied | Rationale |
|
|
99
|
+
|---------|--------------|-----------|
|
|
100
|
+
| **Domain-Driven Design** | Domain layer | Clear bounded contexts |
|
|
101
|
+
| **Aggregate Root** | `MpsFile` | Ensures consistency |
|
|
102
|
+
| **Trait Objects** | `Element` trait | Polymorphism for elements |
|
|
103
|
+
| **Repository Pattern** | `MpsRepository` trait | Storage abstraction |
|
|
104
|
+
| **Service Layer** | Parser, Query, Export | Business logic isolation |
|
|
105
|
+
| **Plugin Architecture** | AI Agent system | Extensibility |
|
|
106
|
+
| **Event Sourcing** | Notification system | Audit trail |
|
|
107
|
+
| **CQRS** | Query vs Command | Separation of concerns |
|
|
108
|
+
| **Builder Pattern** | Element creation | Fluent API |
|
|
109
|
+
| **Result/Either** | Error handling | Explicit error types |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 3. Core Domain Model (Rust)
|
|
114
|
+
|
|
115
|
+
### 3.1 Element Trait (Super Trait)
|
|
116
|
+
|
|
117
|
+
```rust
|
|
118
|
+
/// Core trait all MPS elements must implement
|
|
119
|
+
pub trait Element: Send + Sync {
|
|
120
|
+
fn id(&self) -> Uuid;
|
|
121
|
+
fn element_type(&self) -> ElementType;
|
|
122
|
+
fn body(&self) -> &str;
|
|
123
|
+
fn tags(&self) -> &[String];
|
|
124
|
+
fn metadata(&self) -> &ElementMetadata;
|
|
125
|
+
fn created_at(&self) -> DateTime<Utc>;
|
|
126
|
+
fn updated_at(&self) -> DateTime<Utc>;
|
|
127
|
+
|
|
128
|
+
fn with_body(mut self: Box<Self>, body: String) -> Box<dyn Element>;
|
|
129
|
+
fn with_tags(mut self: Box<Self>, tags: Vec<String>) -> Box<dyn Element>;
|
|
130
|
+
fn with_metadata(mut self: Box<Self>, metadata: ElementMetadata) -> Box<dyn Element>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
134
|
+
pub enum ElementType {
|
|
135
|
+
Task,
|
|
136
|
+
Note,
|
|
137
|
+
Reminder,
|
|
138
|
+
Log,
|
|
139
|
+
Mps, // Nested MPS block
|
|
140
|
+
Custom(String), // For plugin elements
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[derive(Clone, Debug, Default)]
|
|
144
|
+
pub struct ElementMetadata {
|
|
145
|
+
pub priority: Option<Priority>,
|
|
146
|
+
pub due_date: Option<DateTime<Utc>>,
|
|
147
|
+
pub completed_at: Option<DateTime<Utc>>,
|
|
148
|
+
pub custom: HashMap<String, String>,
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 3.2 Concrete Element Types
|
|
153
|
+
|
|
154
|
+
```rust
|
|
155
|
+
// ╔═══════════════════════════════════════════════════════════════╗
|
|
156
|
+
// ║ CONCRETE ELEMENTS ║
|
|
157
|
+
// ╚═══════════════════════════════════════════════════════════════╝
|
|
158
|
+
|
|
159
|
+
/// Task element - represents actionable items
|
|
160
|
+
pub struct Task {
|
|
161
|
+
id: Uuid,
|
|
162
|
+
body: String,
|
|
163
|
+
tags: Vec<String>,
|
|
164
|
+
metadata: ElementMetadata,
|
|
165
|
+
created_at: DateTime<Utc>,
|
|
166
|
+
updated_at: DateTime<Utc>,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
impl Task {
|
|
170
|
+
pub fn new(body: impl Into<String>) -> Self { ... }
|
|
171
|
+
pub fn with_priority(mut self, priority: Priority) -> Self { ... }
|
|
172
|
+
pub fn is_completed(&self) -> bool { ... }
|
|
173
|
+
pub fn mark_completed(&mut self) { ... }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/// Note element - free-form information
|
|
177
|
+
pub struct Note {
|
|
178
|
+
id: Uuid,
|
|
179
|
+
body: String,
|
|
180
|
+
tags: Vec<String>,
|
|
181
|
+
metadata: ElementMetadata,
|
|
182
|
+
created_at: DateTime<Utc>,
|
|
183
|
+
updated_at: DateTime<Utc>,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/// Reminder element - time-based notification trigger
|
|
187
|
+
pub struct Reminder {
|
|
188
|
+
id: Uuid,
|
|
189
|
+
body: String,
|
|
190
|
+
tags: Vec<String>,
|
|
191
|
+
metadata: ElementMetadata,
|
|
192
|
+
trigger_at: DateTime<Utc>, // When to trigger
|
|
193
|
+
repeat: Option<RepeatPattern>, // Recurrence rule
|
|
194
|
+
notification_channel: Channel, // How to notify
|
|
195
|
+
created_at: DateTime<Utc>,
|
|
196
|
+
updated_at: DateTime<Utc>,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#[derive(Clone, Debug)]
|
|
200
|
+
pub enum RepeatPattern {
|
|
201
|
+
Daily,
|
|
202
|
+
Weekly(DayOfWeek),
|
|
203
|
+
Monthly(DayOfMonth),
|
|
204
|
+
Custom(CronExpression),
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/// Log element - time tracking
|
|
208
|
+
pub struct Log {
|
|
209
|
+
id: Uuid,
|
|
210
|
+
body: String,
|
|
211
|
+
tags: Vec<String>,
|
|
212
|
+
metadata: ElementMetadata,
|
|
213
|
+
start_time: DateTime<Utc>,
|
|
214
|
+
end_time: Option<DateTime<Utc>>,
|
|
215
|
+
created_at: DateTime<Utc>,
|
|
216
|
+
updated_at: DateTime<Utc>,
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
impl Log {
|
|
220
|
+
pub fn start(body: impl Into<String>) -> Self { ... }
|
|
221
|
+
pub fn stop(&mut self) { ... }
|
|
222
|
+
pub fn duration(&self) -> Duration { ... }
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 3.3 Aggregate Root - MpsFile
|
|
227
|
+
|
|
228
|
+
```rust
|
|
229
|
+
/// MpsFile - Aggregate Root for daily MPS entries
|
|
230
|
+
pub struct MpsFile {
|
|
231
|
+
id: MpsFileId,
|
|
232
|
+
date: NaiveDate,
|
|
233
|
+
elements: Vec<Box<dyn Element>>,
|
|
234
|
+
version: u64,
|
|
235
|
+
created_at: DateTime<Utc>,
|
|
236
|
+
updated_at: DateTime<Utc>,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
impl MpsFile {
|
|
240
|
+
pub fn new(date: NaiveDate) -> Self { ... }
|
|
241
|
+
|
|
242
|
+
// Command methods (mutating)
|
|
243
|
+
pub fn add_element(&mut self, element: Box<dyn Element>) -> Result<(), MpsError> { ... }
|
|
244
|
+
pub fn remove_element(&mut self, id: Uuid) -> Result<Box<dyn Element>, MpsError> { ... }
|
|
245
|
+
pub fn update_element(&mut self, element: Box<dyn Element>) -> Result<(), MpsError> { ... }
|
|
246
|
+
|
|
247
|
+
// Query methods (immutable)
|
|
248
|
+
pub fn get_element(&self, id: Uuid) -> Option<&dyn Element> { ... }
|
|
249
|
+
pub fn query(&self, filter: &ElementFilter) -> Vec<&dyn Element> { ... }
|
|
250
|
+
pub fn tasks(&self) -> Vec<&Task> { ... }
|
|
251
|
+
pub fn reminders(&self) -> Vec<&Reminder> { ... }
|
|
252
|
+
pub fn logs(&self) -> Vec<&Log> { ... }
|
|
253
|
+
|
|
254
|
+
// Serialization
|
|
255
|
+
pub fn to_json(&self) -> String { ... }
|
|
256
|
+
pub fn to_yaml(&self) -> String { ... }
|
|
257
|
+
pub fn to_markdown(&self) -> String { ... }
|
|
258
|
+
pub fn to_plain_text(&self) -> String { ... }
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#[derive(Clone, Debug)]
|
|
262
|
+
pub struct MpsFileId(pub String); // Format: "YYYYMMDD.timestamp.mps"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 4. Plugin Architecture for AI Agents
|
|
268
|
+
|
|
269
|
+
### 4.1 Plugin System Overview
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
273
|
+
│ PLUGIN SYSTEM ARCHITECTURE │
|
|
274
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
275
|
+
│ │
|
|
276
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
277
|
+
│ │ AI Agent │ │ Notification│ │ Custom │ │
|
|
278
|
+
│ │ Plugin A │ │ Plugin B │ │ Plugin C │ │
|
|
279
|
+
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
|
280
|
+
│ │ │ │ │
|
|
281
|
+
│ └────────────────────┼────────────────────┘ │
|
|
282
|
+
│ ▼ │
|
|
283
|
+
│ ┌──────────────────┐ │
|
|
284
|
+
│ │ Plugin Manager │ │
|
|
285
|
+
│ │ (PluginRegistry)│ │
|
|
286
|
+
│ └────────┬─────────┘ │
|
|
287
|
+
│ │ │
|
|
288
|
+
│ ▼ │
|
|
289
|
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
290
|
+
│ │ PLUGIN TRAIT │ │
|
|
291
|
+
│ │ trait Plugin: Send + Sync { │ │
|
|
292
|
+
│ │ fn name(&self) -> &str; │ │
|
|
293
|
+
│ │ fn version(&self) -> &str; │ │
|
|
294
|
+
│ │ fn initialize(&self, ctx: &PluginContext) │ │
|
|
295
|
+
│ │ fn on_event(&self, event: &PluginEvent) │ │
|
|
296
|
+
│ │ fn capabilities(&self) -> PluginCapabilities; │ │
|
|
297
|
+
│ │ } │ │
|
|
298
|
+
│ └─────────────────────────────────────────────────────────┘ │
|
|
299
|
+
│ │
|
|
300
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 4.2 Plugin Trait Definition
|
|
304
|
+
|
|
305
|
+
```rust
|
|
306
|
+
/// Core plugin trait - all AI agents implement this
|
|
307
|
+
pub trait Plugin: Send + Sync {
|
|
308
|
+
/// Unique plugin identifier
|
|
309
|
+
fn name(&self) -> &str;
|
|
310
|
+
|
|
311
|
+
/// Semantic version
|
|
312
|
+
fn version(&self) -> &str;
|
|
313
|
+
|
|
314
|
+
/// Human-readable description
|
|
315
|
+
fn description(&self) -> &str;
|
|
316
|
+
|
|
317
|
+
/// Initialize plugin with configuration
|
|
318
|
+
fn initialize(&self, ctx: &PluginContext) -> Result<(), PluginError>;
|
|
319
|
+
|
|
320
|
+
/// Handle events from MPS system
|
|
321
|
+
fn on_event(&self, event: &PluginEvent) -> PluginResponse;
|
|
322
|
+
|
|
323
|
+
/// Capabilities this plugin provides
|
|
324
|
+
fn capabilities(&self) -> PluginCapabilities;
|
|
325
|
+
|
|
326
|
+
/// Shutdown hook
|
|
327
|
+
fn shutdown(&self) -> Result<(), PluginError>;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
#[derive(Clone, Debug, Default)]
|
|
331
|
+
pub struct PluginCapabilities {
|
|
332
|
+
pub ai_enabled: bool,
|
|
333
|
+
pub notifications: bool,
|
|
334
|
+
pub scheduled_tasks: bool,
|
|
335
|
+
pub custom_elements: bool,
|
|
336
|
+
pub export_formats: Vec<String>,
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
pub enum PluginEvent {
|
|
340
|
+
ElementCreated { element: Box<dyn Element>, file: &MpsFile },
|
|
341
|
+
ElementUpdated { element: Box<dyn Element>, file: &MpsFile },
|
|
342
|
+
ElementDeleted { element_id: Uuid, file: &MpsFile },
|
|
343
|
+
ReminderTriggered { reminder: &Reminder },
|
|
344
|
+
TaskCompleted { task: &Task },
|
|
345
|
+
LogStarted { log: &Log },
|
|
346
|
+
LogEnded { log: &Log, duration: Duration },
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
pub enum PluginResponse {
|
|
350
|
+
None,
|
|
351
|
+
Action(PluginAction),
|
|
352
|
+
Notification(PluginNotification),
|
|
353
|
+
ModifiedElement(Box<dyn Element>),
|
|
354
|
+
Error(String),
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### 4.3 AI Agent Plugin Example
|
|
359
|
+
|
|
360
|
+
```rust
|
|
361
|
+
/// Example: AI Smart Reminder Agent
|
|
362
|
+
pub struct SmartReminderAgent {
|
|
363
|
+
config: SmartReminderConfig,
|
|
364
|
+
model: Option<Box<dyn LlmModel>>,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
impl SmartReminderAgent {
|
|
368
|
+
pub fn new(config: SmartReminderConfig) -> Self { ... }
|
|
369
|
+
|
|
370
|
+
/// Analyze reminder and suggest optimal timing
|
|
371
|
+
pub fn suggest_timing(&self, reminder: &Reminder) -> DateTime<Utc> { ... }
|
|
372
|
+
|
|
373
|
+
/// Generate smart follow-up tasks
|
|
374
|
+
pub fn suggest_followups(&self, completed_task: &Task) -> Vec<Task> { ... }
|
|
375
|
+
|
|
376
|
+
/// Context-aware notification messages
|
|
377
|
+
pub fn generate_message(&self, reminder: &Reminder, context: &MpsFile) -> String { ... }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/// AI LLM trait for model abstraction
|
|
381
|
+
pub trait LlmModel: Send + Sync {
|
|
382
|
+
fn complete(&self, prompt: &str) -> Result<String, LlmError>;
|
|
383
|
+
fn chat(&self, messages: &[ChatMessage]) -> Result<ChatMessage, LlmError>;
|
|
384
|
+
fn embed(&self, text: &str) -> Result<Vec<f32>, EmbeddingError>;
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## 5. Event & Notification System
|
|
391
|
+
|
|
392
|
+
### 5.1 Event Bus
|
|
393
|
+
|
|
394
|
+
```rust
|
|
395
|
+
/// Async event bus for inter-component communication
|
|
396
|
+
pub struct EventBus {
|
|
397
|
+
subscribers: Arc<RwLock<HashMap<EventType, Vec<Subscription>>>>,
|
|
398
|
+
runtime: Runtime,
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
impl EventBus {
|
|
402
|
+
pub fn new() -> Self { ... }
|
|
403
|
+
|
|
404
|
+
pub fn subscribe<F>(&mut self, event_type: EventType, handler: F)
|
|
405
|
+
where
|
|
406
|
+
F: Fn(Box<dyn Event>) -> Pin<Box<dyn Future<Output=()> + Send>> + Send + Sync + 'static
|
|
407
|
+
{ ... }
|
|
408
|
+
|
|
409
|
+
pub async fn publish(&self, event: Box<dyn Event>) { ... }
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
pub trait Event: Send + Debug {
|
|
413
|
+
fn event_type(&self) -> EventType;
|
|
414
|
+
fn timestamp(&self) -> DateTime<Utc>;
|
|
415
|
+
fn source(&self) -> EventSource;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
pub enum EventType {
|
|
419
|
+
ElementCreated,
|
|
420
|
+
ElementUpdated,
|
|
421
|
+
ElementDeleted,
|
|
422
|
+
ReminderFired,
|
|
423
|
+
TaskCompleted,
|
|
424
|
+
LogStarted,
|
|
425
|
+
LogEnded,
|
|
426
|
+
ScheduleTriggered,
|
|
427
|
+
PluginEvent(String),
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### 5.2 Notification Channels
|
|
432
|
+
|
|
433
|
+
```rust
|
|
434
|
+
/// Pluggable notification backends
|
|
435
|
+
pub trait NotificationChannel: Send + Sync {
|
|
436
|
+
fn send(&self, notification: &Notification) -> Result<(), NotificationError>;
|
|
437
|
+
fn capabilities(&self) -> ChannelCapabilities;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
pub struct Notification {
|
|
441
|
+
pub id: Uuid,
|
|
442
|
+
pub title: String,
|
|
443
|
+
pub body: String,
|
|
444
|
+
pub urgency: Urgency,
|
|
445
|
+
pub channel: ChannelType,
|
|
446
|
+
pub actions: Vec<Action>,
|
|
447
|
+
pub scheduled_for: Option<DateTime<Utc>>,
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
pub enum ChannelType {
|
|
451
|
+
Desktop, // libnotify/dunst
|
|
452
|
+
Email, // SMTP
|
|
453
|
+
Slack, // Slack API
|
|
454
|
+
Telegram, // Bot API
|
|
455
|
+
Webhook, // HTTP POST
|
|
456
|
+
Console, // stdout
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
pub enum Urgency {
|
|
460
|
+
Low,
|
|
461
|
+
Normal,
|
|
462
|
+
Critical,
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## 6. Repository & Storage Abstraction
|
|
469
|
+
|
|
470
|
+
### 6.1 Repository Trait
|
|
471
|
+
|
|
472
|
+
```rust
|
|
473
|
+
pub trait MpsRepository: Send + Sync {
|
|
474
|
+
async fn save(&self, file: &MpsFile) -> Result<(), RepositoryError>;
|
|
475
|
+
async fn load(&self, id: &MpsFileId) -> Result<MpsFile, RepositoryError>;
|
|
476
|
+
async fn delete(&self, id: &MpsFileId) -> Result<(), RepositoryError>;
|
|
477
|
+
async fn list(&self, range: DateRange) -> Result<Vec<MpsFileId>, RepositoryError>;
|
|
478
|
+
async fn search(&self, query: &SearchQuery) -> Result<Vec<SearchResult>, RepositoryError>;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
pub trait SearchIndex: Send + Sync {
|
|
482
|
+
fn index(&self, file: &MpsFile) -> Result<(), IndexError>;
|
|
483
|
+
fn search(&self, query: &SearchQuery) -> Result<Vec<SearchResult>, IndexError>;
|
|
484
|
+
fn reindex(&self) -> Result<(), IndexError>;
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### 6.2 Storage Implementations
|
|
489
|
+
|
|
490
|
+
```rust
|
|
491
|
+
// File-based storage (YAML/JSON)
|
|
492
|
+
pub struct FileSystemRepository {
|
|
493
|
+
base_path: PathBuf,
|
|
494
|
+
format: StorageFormat,
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// SQLite with full-text search
|
|
498
|
+
pub struct SqliteRepository {
|
|
499
|
+
connection: SqliteConnection,
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// PostgreSQL for multi-device sync
|
|
503
|
+
pub struct PostgresRepository {
|
|
504
|
+
pool: PgPool,
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## 7. Query & Filter System
|
|
511
|
+
|
|
512
|
+
### 7.1 Query DSL
|
|
513
|
+
|
|
514
|
+
```rust
|
|
515
|
+
/// Fluent query builder
|
|
516
|
+
pub struct MpsQuery {
|
|
517
|
+
filters: Vec<Box<dyn QueryFilter>>,
|
|
518
|
+
sort: SortOption,
|
|
519
|
+
limit: Option<usize>,
|
|
520
|
+
offset: usize,
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
impl MpsQuery {
|
|
524
|
+
pub fn new() -> Self { ... }
|
|
525
|
+
|
|
526
|
+
pub fn for_date(mut self, date: NaiveDate) -> Self { ... }
|
|
527
|
+
pub fn for_date_range(mut self, start: NaiveDate, end: NaiveDate) -> Self { ... }
|
|
528
|
+
|
|
529
|
+
pub fn with_type(mut self, element_type: ElementType) -> Self { ... }
|
|
530
|
+
pub fn with_tag(mut self, tag: impl Into<String>) -> Self { ... }
|
|
531
|
+
pub fn with_tags(mut self, tags: Vec<String>) -> Self { ... }
|
|
532
|
+
|
|
533
|
+
pub fn with_priority(mut self, priority: Priority) -> Self { ... }
|
|
534
|
+
pub fn is_completed(mut self) -> Self { ... }
|
|
535
|
+
pub fn is_pending(mut self) -> Self { ... }
|
|
536
|
+
|
|
537
|
+
pub fn has_due_date(mut self) -> Self { ... }
|
|
538
|
+
pub fn due_before(mut self, date: DateTime<Utc>) -> Self { ... }
|
|
539
|
+
pub fn due_after(mut self, date: DateTime<Utc>) -> Self { ... }
|
|
540
|
+
|
|
541
|
+
pub fn sort_by(mut self, sort: SortOption) -> Self { ... }
|
|
542
|
+
pub fn limit(mut self, n: usize) -> Self { ... }
|
|
543
|
+
pub fn offset(mut self, n: usize) -> Self { ... }
|
|
544
|
+
|
|
545
|
+
pub fn execute(&self, repo: &dyn MpsRepository) -> Result<Vec<Box<dyn Element>>, QueryError> { ... }
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## 8. CLI & Interface Layer
|
|
552
|
+
|
|
553
|
+
### 8.1 Command Structure (using Clap)
|
|
554
|
+
|
|
555
|
+
```rust
|
|
556
|
+
use clap::{Parser, Subcommand};
|
|
557
|
+
|
|
558
|
+
#[derive(Parser)]
|
|
559
|
+
#[command(name = "mps")]
|
|
560
|
+
#[command(about = "MPS - Personal Productivity Manager", long_about = None)]
|
|
561
|
+
pub struct Cli {
|
|
562
|
+
#[command(subcommand)]
|
|
563
|
+
pub command: Commands,
|
|
564
|
+
|
|
565
|
+
#[arg(short, long, global = true)]
|
|
566
|
+
pub config: Option<PathBuf>,
|
|
567
|
+
|
|
568
|
+
#[arg(short, long, global = true, action = clap::ArgAction::Count)]
|
|
569
|
+
pub verbose: u8,
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
#[derive(Subcommand)]
|
|
573
|
+
pub enum Commands {
|
|
574
|
+
/// Open MPS file in editor
|
|
575
|
+
Open {
|
|
576
|
+
/// Date expression (today, yesterday, YYYYMMDD, "2 days ago")
|
|
577
|
+
#[arg(default_value = "today")]
|
|
578
|
+
date: String,
|
|
579
|
+
|
|
580
|
+
/// Open in specified editor
|
|
581
|
+
#[arg(short, long)]
|
|
582
|
+
editor: Option<String>,
|
|
583
|
+
},
|
|
584
|
+
|
|
585
|
+
/// Create new element
|
|
586
|
+
New {
|
|
587
|
+
/// Element type (task, note, reminder, log)
|
|
588
|
+
#[arg(value_enum)]
|
|
589
|
+
element_type: ElementTypeCli,
|
|
590
|
+
|
|
591
|
+
/// Element body/content
|
|
592
|
+
body: String,
|
|
593
|
+
|
|
594
|
+
/// Tags (comma-separated)
|
|
595
|
+
#[arg(short, long, value_delimiter = ',')]
|
|
596
|
+
tags: Vec<String>,
|
|
597
|
+
|
|
598
|
+
/// Date to add element to
|
|
599
|
+
#[arg(short, long)]
|
|
600
|
+
date: Option<String>,
|
|
601
|
+
},
|
|
602
|
+
|
|
603
|
+
/// List/search elements
|
|
604
|
+
List {
|
|
605
|
+
/// Filter by type
|
|
606
|
+
#[arg(short, long)]
|
|
607
|
+
r#type: Option<ElementTypeCli>,
|
|
608
|
+
|
|
609
|
+
/// Filter by tag
|
|
610
|
+
#[arg(short, long)]
|
|
611
|
+
tag: Option<String>,
|
|
612
|
+
|
|
613
|
+
/// Show completed tasks
|
|
614
|
+
#[arg(long)]
|
|
615
|
+
all: bool,
|
|
616
|
+
|
|
617
|
+
/// Date range
|
|
618
|
+
#[arg(short, long)]
|
|
619
|
+
range: Option<String>,
|
|
620
|
+
},
|
|
621
|
+
|
|
622
|
+
/// Git operations
|
|
623
|
+
Git {
|
|
624
|
+
#[arg(last = true)]
|
|
625
|
+
args: Vec<String>,
|
|
626
|
+
},
|
|
627
|
+
|
|
628
|
+
/// AI Agent commands
|
|
629
|
+
Agent {
|
|
630
|
+
#[command(subcommand)]
|
|
631
|
+
subcommand: AgentCommands,
|
|
632
|
+
},
|
|
633
|
+
|
|
634
|
+
/// Export data
|
|
635
|
+
Export {
|
|
636
|
+
/// Output format (json, yaml, markdown, csv)
|
|
637
|
+
#[arg(short, long)]
|
|
638
|
+
format: ExportFormat,
|
|
639
|
+
|
|
640
|
+
/// Output file
|
|
641
|
+
#[arg(short, long)]
|
|
642
|
+
output: Option<PathBuf>,
|
|
643
|
+
|
|
644
|
+
/// Date range
|
|
645
|
+
#[arg(short, long)]
|
|
646
|
+
range: Option<String>,
|
|
647
|
+
},
|
|
648
|
+
|
|
649
|
+
/// Server mode (for remote access/API)
|
|
650
|
+
Serve {
|
|
651
|
+
#[arg(short, long, default_value = "127.0.0.1:3030")]
|
|
652
|
+
address: String,
|
|
653
|
+
},
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## 9. Error Handling
|
|
660
|
+
|
|
661
|
+
### 9.1 Error Types
|
|
662
|
+
|
|
663
|
+
```rust
|
|
664
|
+
#[derive(Error, Debug)]
|
|
665
|
+
pub enum MpsError {
|
|
666
|
+
#[error("Element not found: {0}")]
|
|
667
|
+
ElementNotFound(Uuid),
|
|
668
|
+
|
|
669
|
+
#[error("File not found: {0}")]
|
|
670
|
+
FileNotFound(MpsFileId),
|
|
671
|
+
|
|
672
|
+
#[error("Parse error: {0}")]
|
|
673
|
+
ParseError(String),
|
|
674
|
+
|
|
675
|
+
#[error("Storage error: {0}")]
|
|
676
|
+
StorageError(String),
|
|
677
|
+
|
|
678
|
+
#[error("Configuration error: {0}")]
|
|
679
|
+
ConfigError(String),
|
|
680
|
+
|
|
681
|
+
#[error("Plugin error: {0}")]
|
|
682
|
+
PluginError(String),
|
|
683
|
+
|
|
684
|
+
#[error("Validation error: {0}")]
|
|
685
|
+
ValidationError(String),
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## 10. Project Structure
|
|
692
|
+
|
|
693
|
+
```
|
|
694
|
+
mps/
|
|
695
|
+
├── Cargo.toml
|
|
696
|
+
├── rust-toolchain.toml
|
|
697
|
+
├── .env.example
|
|
698
|
+
├── README.md
|
|
699
|
+
├── CHANGELOG.md
|
|
700
|
+
│
|
|
701
|
+
├── src/
|
|
702
|
+
│ ├── main.rs # Entry point
|
|
703
|
+
│ ├── lib.rs # Library root
|
|
704
|
+
│ │
|
|
705
|
+
│ ├── domain/ # Domain Layer (innermost)
|
|
706
|
+
│ │ ├── mod.rs
|
|
707
|
+
│ │ ├── element.rs # Element trait
|
|
708
|
+
│ │ ├── task.rs
|
|
709
|
+
│ │ ├── note.rs
|
|
710
|
+
│ │ ├── reminder.rs
|
|
711
|
+
│ │ ├── log.rs
|
|
712
|
+
│ │ ├── mps_file.rs # Aggregate root
|
|
713
|
+
│ │ ├── errors.rs # Domain errors
|
|
714
|
+
│ │ └── value_objects/ # Value objects
|
|
715
|
+
│ │ ├── mod.rs
|
|
716
|
+
│ │ ├── mps_file_id.rs
|
|
717
|
+
│ │ ├── priority.rs
|
|
718
|
+
│ │ └── date_stamp.rs
|
|
719
|
+
│ │
|
|
720
|
+
│ ├── application/ # Application Services
|
|
721
|
+
│ │ ├── mod.rs
|
|
722
|
+
│ │ ├── parser.rs # Text file parser
|
|
723
|
+
│ │ ├── query_service.rs # Query execution
|
|
724
|
+
│ │ ├── command_service.rs # Commands (CQRS write)
|
|
725
|
+
│ │ ├── export_service.rs # Export to various formats
|
|
726
|
+
│ │ └── scheduler.rs # Reminder scheduler
|
|
727
|
+
│ │
|
|
728
|
+
│ ├── infrastructure/ # Infrastructure Layer
|
|
729
|
+
│ │ ├── mod.rs
|
|
730
|
+
│ │ ├── repository/
|
|
731
|
+
│ │ │ ├── mod.rs
|
|
732
|
+
│ │ │ ├── repository.rs # Repository trait
|
|
733
|
+
│ │ │ ├── file_system.rs
|
|
734
|
+
│ │ │ ├── sqlite.rs
|
|
735
|
+
│ │ │ └── search_index.rs
|
|
736
|
+
│ │ ├── storage/
|
|
737
|
+
│ │ │ ├── mod.rs
|
|
738
|
+
│ │ │ └── yaml.rs
|
|
739
|
+
│ │ ├── notification/
|
|
740
|
+
│ │ │ ├── mod.rs
|
|
741
|
+
│ │ │ ├── notifier.rs
|
|
742
|
+
│ │ │ └── channels/
|
|
743
|
+
│ │ │ ├── mod.rs
|
|
744
|
+
│ │ │ ├── desktop.rs
|
|
745
|
+
│ │ │ ├── email.rs
|
|
746
|
+
│ │ │ └── slack.rs
|
|
747
|
+
│ │ └── plugins/
|
|
748
|
+
│ │ ├── mod.rs
|
|
749
|
+
│ │ ├── plugin.rs # Plugin trait
|
|
750
|
+
│ │ ├── manager.rs # Plugin registry
|
|
751
|
+
│ │ └── ai/
|
|
752
|
+
│ │ ├── mod.rs
|
|
753
|
+
│ │ ├── llm.rs # LLM trait
|
|
754
|
+
│ │ └── smart_reminder.rs
|
|
755
|
+
│ │
|
|
756
|
+
│ ├── interface/ # Interface Adapters
|
|
757
|
+
│ │ ├── mod.rs
|
|
758
|
+
│ │ ├── cli/
|
|
759
|
+
│ │ │ ├── mod.rs
|
|
760
|
+
│ │ │ ├── commands.rs
|
|
761
|
+
│ │ │ └── parser.rs # CLI arg parsing
|
|
762
|
+
│ │ ├── tui/
|
|
763
|
+
│ │ │ └── mod.rs # Terminal UI
|
|
764
|
+
│ │ └── api/
|
|
765
|
+
│ │ ├── mod.rs
|
|
766
|
+
│ │ └── server.rs # HTTP API server
|
|
767
|
+
│ │
|
|
768
|
+
│ └── common/ # Shared utilities
|
|
769
|
+
│ ├── mod.rs
|
|
770
|
+
│ ├── config.rs
|
|
771
|
+
│ ├── logging.rs
|
|
772
|
+
│ ├── date_utils.rs
|
|
773
|
+
│ └── extensions.rs
|
|
774
|
+
│
|
|
775
|
+
├── tests/
|
|
776
|
+
│ ├── integration/
|
|
777
|
+
│ │ └── mod.rs
|
|
778
|
+
│ ├── domain/
|
|
779
|
+
│ │ ├── mod.rs
|
|
780
|
+
│ │ └── element_tests.rs
|
|
781
|
+
│ └── fixtures/
|
|
782
|
+
│ └── mod.rs
|
|
783
|
+
│
|
|
784
|
+
├── examples/
|
|
785
|
+
│ ├── basic_usage.rs
|
|
786
|
+
│ ├── plugin_example.rs
|
|
787
|
+
│ └── export_example.rs
|
|
788
|
+
│
|
|
789
|
+
└── docs/
|
|
790
|
+
├── architecture.md
|
|
791
|
+
├── plugin_development.md
|
|
792
|
+
└── api_reference.md
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## 11. Dependencies (Cargo.toml)
|
|
798
|
+
|
|
799
|
+
```toml
|
|
800
|
+
[package]
|
|
801
|
+
name = "mps"
|
|
802
|
+
version = "0.1.0"
|
|
803
|
+
edition = "2024"
|
|
804
|
+
|
|
805
|
+
[dependencies]
|
|
806
|
+
# Async runtime
|
|
807
|
+
tokio = { version = "1", features = ["full"] }
|
|
808
|
+
|
|
809
|
+
# CLI
|
|
810
|
+
clap = { version = "4", features = ["derive", "env"] }
|
|
811
|
+
clap_complete = "4"
|
|
812
|
+
|
|
813
|
+
# Serialization
|
|
814
|
+
serde = { version = "1", features = ["derive"] }
|
|
815
|
+
serde_json = "1"
|
|
816
|
+
serde_yaml = "0.9"
|
|
817
|
+
toml = "0.8"
|
|
818
|
+
|
|
819
|
+
# Database
|
|
820
|
+
rusqlite = { version = "0.31", features = ["bundled"] }
|
|
821
|
+
sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite", "postgres"] }
|
|
822
|
+
|
|
823
|
+
# Date/Time
|
|
824
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
825
|
+
chrono-tz = "0.8"
|
|
826
|
+
|
|
827
|
+
# UUID
|
|
828
|
+
uuid = { version = "1", features = ["v4", "serde", "fast-rng"] }
|
|
829
|
+
|
|
830
|
+
# Logging
|
|
831
|
+
tracing = "0.1"
|
|
832
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
833
|
+
tracing-appender = "0.2"
|
|
834
|
+
|
|
835
|
+
# Error handling
|
|
836
|
+
thiserror = "1"
|
|
837
|
+
anyhow = "1"
|
|
838
|
+
|
|
839
|
+
# Async notifications
|
|
840
|
+
tokio-sync = "0.3"
|
|
841
|
+
|
|
842
|
+
# Editor integration
|
|
843
|
+
tui-editor = "0.2"
|
|
844
|
+
|
|
845
|
+
# HTTP server (for API)
|
|
846
|
+
axum = "0.6"
|
|
847
|
+
tower = "0.4"
|
|
848
|
+
|
|
849
|
+
# Regex
|
|
850
|
+
regex = "1"
|
|
851
|
+
fancy-regex = "0.11"
|
|
852
|
+
|
|
853
|
+
# Fuzzy search
|
|
854
|
+
fuzzy-matcher = "0.3"
|
|
855
|
+
|
|
856
|
+
# Async trait support
|
|
857
|
+
async-trait = "0.1"
|
|
858
|
+
|
|
859
|
+
# Conditional compilation
|
|
860
|
+
cfg-if = "1"
|
|
861
|
+
|
|
862
|
+
[dev-dependencies]
|
|
863
|
+
tokio-test = "0.4"
|
|
864
|
+
mockall = "0.11"
|
|
865
|
+
proptest = "1"
|
|
866
|
+
criterion = "0.5"
|
|
867
|
+
|
|
868
|
+
[features]
|
|
869
|
+
default = ["sqlite"]
|
|
870
|
+
sqlite = ["rusqlite"]
|
|
871
|
+
postgres = ["sqlx/postgres"]
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
876
|
+
## 12. Implementation Phases
|
|
877
|
+
|
|
878
|
+
### Phase 1: Core Domain (Weeks 1-2)
|
|
879
|
+
- [ ] Define Element trait and value objects
|
|
880
|
+
- [ ] Implement Task, Note, Reminder, Log types
|
|
881
|
+
- [ ] Implement MpsFile aggregate
|
|
882
|
+
- [ ] Implement basic error types
|
|
883
|
+
- [ ] Unit tests for domain
|
|
884
|
+
|
|
885
|
+
### Phase 2: Storage & Parser (Weeks 3-4)
|
|
886
|
+
- [ ] FileSystem repository implementation
|
|
887
|
+
- [ ] Text parser for .mps files
|
|
888
|
+
- [ ] YAML/JSON serialization
|
|
889
|
+
- [ ] Search index implementation
|
|
890
|
+
|
|
891
|
+
### Phase 3: Query System (Week 5)
|
|
892
|
+
- [ ] MpsQuery builder
|
|
893
|
+
- [ ] Filter implementations
|
|
894
|
+
- [ ] SQLite repository
|
|
895
|
+
|
|
896
|
+
### Phase 4: Event System (Week 6)
|
|
897
|
+
- [ ] EventBus implementation
|
|
898
|
+
- [ ] Scheduler for reminders
|
|
899
|
+
- [ ] Notification channels
|
|
900
|
+
|
|
901
|
+
### Phase 5: Plugin Architecture (Weeks 7-8)
|
|
902
|
+
- [ ] Plugin trait and manager
|
|
903
|
+
- [ ] Plugin registry
|
|
904
|
+
- [ ] AI agent plugin skeleton
|
|
905
|
+
|
|
906
|
+
### Phase 6: Interface Layer (Weeks 9-10)
|
|
907
|
+
- [ ] CLI commands implementation
|
|
908
|
+
- [ ] TUI (optional)
|
|
909
|
+
- [ ] HTTP API server
|
|
910
|
+
|
|
911
|
+
### Phase 7: Polish (Week 11-12)
|
|
912
|
+
- [ ] Integration tests
|
|
913
|
+
- [ ] Performance optimization
|
|
914
|
+
- [ ] Documentation
|
|
915
|
+
- [ ] Release
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## 13. Summary
|
|
920
|
+
|
|
921
|
+
This specification provides a production-grade Rust implementation with:
|
|
922
|
+
|
|
923
|
+
| Feature | Ruby Implementation | Rust Implementation |
|
|
924
|
+
|---------|--------------------|--------------------|
|
|
925
|
+
| Type Safety | None (dynamic) | Full (static) |
|
|
926
|
+
| Concurrency | GIL-limited | True parallelism |
|
|
927
|
+
| Error Handling | Exceptions | Result/Either types |
|
|
928
|
+
| Extensibility | eval() reflection | Plugin trait system |
|
|
929
|
+
| AI Integration | None | Pluggable LLM interface |
|
|
930
|
+
| Notifications | None | Async event bus |
|
|
931
|
+
| Storage | YAML only | Pluggable backends |
|
|
932
|
+
| Query | None | Full query DSL |
|
|
933
|
+
| Testing | Minimal | Property-based |
|
|
934
|
+
|
|
935
|
+
The architecture enables future AI agent integration through a well-defined plugin system, event bus, and async capabilities.
|