@shykaruu/jarvis-brain 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +153 -0
- package/README.md +428 -0
- package/bin/jarvis.ts +449 -0
- package/package.json +79 -0
- package/roles/activity-observer.yaml +60 -0
- package/roles/ceo-founder.yaml +144 -0
- package/roles/chief-of-staff.yaml +158 -0
- package/roles/dev-lead.yaml +182 -0
- package/roles/executive-assistant.yaml +77 -0
- package/roles/marketing-director.yaml +168 -0
- package/roles/personal-assistant.yaml +266 -0
- package/roles/research-specialist.yaml +60 -0
- package/roles/specialists/content-writer.yaml +53 -0
- package/roles/specialists/customer-support.yaml +57 -0
- package/roles/specialists/data-analyst.yaml +57 -0
- package/roles/specialists/financial-analyst.yaml +56 -0
- package/roles/specialists/hr-specialist.yaml +55 -0
- package/roles/specialists/legal-advisor.yaml +58 -0
- package/roles/specialists/marketing-strategist.yaml +56 -0
- package/roles/specialists/project-coordinator.yaml +55 -0
- package/roles/specialists/research-analyst.yaml +58 -0
- package/roles/specialists/software-engineer.yaml +57 -0
- package/roles/specialists/system-administrator.yaml +57 -0
- package/roles/system-admin.yaml +76 -0
- package/scripts/ensure-bun.cjs +16 -0
- package/src/actions/README.md +421 -0
- package/src/actions/app-control/desktop-controller.test.ts +26 -0
- package/src/actions/app-control/desktop-controller.ts +438 -0
- package/src/actions/app-control/interface.ts +64 -0
- package/src/actions/app-control/linux.ts +273 -0
- package/src/actions/app-control/macos.ts +54 -0
- package/src/actions/app-control/sidecar-launcher.test.ts +23 -0
- package/src/actions/app-control/sidecar-launcher.ts +286 -0
- package/src/actions/app-control/windows.ts +44 -0
- package/src/actions/browser/cdp.ts +138 -0
- package/src/actions/browser/chrome-launcher.ts +261 -0
- package/src/actions/browser/session.ts +506 -0
- package/src/actions/browser/stealth.ts +49 -0
- package/src/actions/index.ts +20 -0
- package/src/actions/terminal/executor.ts +157 -0
- package/src/actions/terminal/wsl-bridge.ts +126 -0
- package/src/actions/test.ts +93 -0
- package/src/actions/tools/agents.ts +363 -0
- package/src/actions/tools/builtin.ts +950 -0
- package/src/actions/tools/commitments.ts +192 -0
- package/src/actions/tools/content.ts +217 -0
- package/src/actions/tools/delegate.ts +147 -0
- package/src/actions/tools/desktop.test.ts +55 -0
- package/src/actions/tools/desktop.ts +305 -0
- package/src/actions/tools/documents.ts +169 -0
- package/src/actions/tools/goals.ts +376 -0
- package/src/actions/tools/local-tools-guard.ts +31 -0
- package/src/actions/tools/registry.ts +173 -0
- package/src/actions/tools/research.ts +111 -0
- package/src/actions/tools/sidecar-list.ts +57 -0
- package/src/actions/tools/sidecar-route.ts +105 -0
- package/src/actions/tools/workflows.ts +216 -0
- package/src/agents/agent.ts +132 -0
- package/src/agents/delegation.ts +107 -0
- package/src/agents/hierarchy.ts +113 -0
- package/src/agents/index.ts +19 -0
- package/src/agents/messaging.ts +125 -0
- package/src/agents/orchestrator.ts +592 -0
- package/src/agents/role-discovery.ts +61 -0
- package/src/agents/sub-agent-runner.ts +309 -0
- package/src/agents/task-manager.ts +151 -0
- package/src/authority/approval-delivery.ts +59 -0
- package/src/authority/approval.ts +196 -0
- package/src/authority/audit.ts +158 -0
- package/src/authority/authority.test.ts +519 -0
- package/src/authority/deferred-executor.ts +103 -0
- package/src/authority/emergency.ts +66 -0
- package/src/authority/engine.ts +301 -0
- package/src/authority/index.ts +12 -0
- package/src/authority/learning.ts +111 -0
- package/src/authority/tool-action-map.ts +74 -0
- package/src/awareness/analytics.ts +466 -0
- package/src/awareness/awareness.test.ts +332 -0
- package/src/awareness/capture-engine.ts +305 -0
- package/src/awareness/context-graph.ts +130 -0
- package/src/awareness/context-tracker.ts +349 -0
- package/src/awareness/index.ts +25 -0
- package/src/awareness/intelligence.ts +321 -0
- package/src/awareness/ocr-engine.ts +88 -0
- package/src/awareness/service.ts +528 -0
- package/src/awareness/struggle-detector.ts +342 -0
- package/src/awareness/suggestion-engine.ts +476 -0
- package/src/awareness/types.ts +201 -0
- package/src/cli/autostart.ts +417 -0
- package/src/cli/deps.ts +449 -0
- package/src/cli/doctor.ts +238 -0
- package/src/cli/helpers.ts +401 -0
- package/src/cli/onboard.ts +827 -0
- package/src/cli/uninstall.test.ts +37 -0
- package/src/cli/uninstall.ts +202 -0
- package/src/comms/README.md +329 -0
- package/src/comms/auth-error.html +48 -0
- package/src/comms/channels/discord.ts +228 -0
- package/src/comms/channels/signal.ts +56 -0
- package/src/comms/channels/telegram.ts +316 -0
- package/src/comms/channels/whatsapp.ts +60 -0
- package/src/comms/channels.test.ts +173 -0
- package/src/comms/dashboard-auth.ts +75 -0
- package/src/comms/desktop-notify.ts +114 -0
- package/src/comms/example.ts +129 -0
- package/src/comms/index.ts +129 -0
- package/src/comms/streaming.ts +149 -0
- package/src/comms/voice.test.ts +504 -0
- package/src/comms/voice.ts +341 -0
- package/src/comms/websocket.test.ts +409 -0
- package/src/comms/websocket.ts +669 -0
- package/src/config/README.md +389 -0
- package/src/config/index.ts +6 -0
- package/src/config/loader.test.ts +183 -0
- package/src/config/loader.ts +148 -0
- package/src/config/types.ts +293 -0
- package/src/daemon/README.md +232 -0
- package/src/daemon/agent-service-interface.ts +9 -0
- package/src/daemon/agent-service.ts +667 -0
- package/src/daemon/api-routes.ts +3067 -0
- package/src/daemon/background-agent-service.ts +396 -0
- package/src/daemon/background-agent.test.ts +78 -0
- package/src/daemon/channel-service.ts +201 -0
- package/src/daemon/commitment-executor.ts +297 -0
- package/src/daemon/dashboard-auth.test.ts +170 -0
- package/src/daemon/event-classifier.ts +239 -0
- package/src/daemon/event-coalescer.ts +123 -0
- package/src/daemon/event-reactor.ts +214 -0
- package/src/daemon/flock.c +7 -0
- package/src/daemon/health.ts +220 -0
- package/src/daemon/index.ts +1070 -0
- package/src/daemon/llm-settings.test.ts +78 -0
- package/src/daemon/llm-settings.ts +450 -0
- package/src/daemon/observer-service.ts +150 -0
- package/src/daemon/pid.test.ts +283 -0
- package/src/daemon/pid.ts +224 -0
- package/src/daemon/research-queue.ts +155 -0
- package/src/daemon/services.ts +175 -0
- package/src/daemon/ws-service.ts +926 -0
- package/src/global.d.ts +4 -0
- package/src/goals/accountability.ts +240 -0
- package/src/goals/awareness-bridge.ts +185 -0
- package/src/goals/estimator.ts +185 -0
- package/src/goals/events.ts +28 -0
- package/src/goals/goals.test.ts +400 -0
- package/src/goals/integration.test.ts +329 -0
- package/src/goals/nl-builder.test.ts +220 -0
- package/src/goals/nl-builder.ts +256 -0
- package/src/goals/rhythm.test.ts +177 -0
- package/src/goals/rhythm.ts +275 -0
- package/src/goals/service.test.ts +135 -0
- package/src/goals/service.ts +407 -0
- package/src/goals/types.ts +106 -0
- package/src/goals/workflow-bridge.ts +96 -0
- package/src/integrations/google-api.ts +134 -0
- package/src/integrations/google-auth.ts +175 -0
- package/src/llm/README.md +291 -0
- package/src/llm/anthropic.ts +400 -0
- package/src/llm/gemini.ts +380 -0
- package/src/llm/groq.ts +406 -0
- package/src/llm/history.ts +147 -0
- package/src/llm/index.ts +21 -0
- package/src/llm/manager.ts +226 -0
- package/src/llm/ollama.ts +316 -0
- package/src/llm/openai.ts +411 -0
- package/src/llm/openrouter.ts +390 -0
- package/src/llm/provider.test.ts +487 -0
- package/src/llm/provider.ts +61 -0
- package/src/llm/test.ts +88 -0
- package/src/observers/README.md +278 -0
- package/src/observers/calendar.ts +113 -0
- package/src/observers/clipboard.ts +136 -0
- package/src/observers/email.ts +109 -0
- package/src/observers/example.ts +58 -0
- package/src/observers/file-watcher.ts +124 -0
- package/src/observers/index.ts +159 -0
- package/src/observers/notifications.ts +197 -0
- package/src/observers/observers.test.ts +203 -0
- package/src/observers/processes.ts +225 -0
- package/src/personality/README.md +61 -0
- package/src/personality/adapter.ts +196 -0
- package/src/personality/index.ts +20 -0
- package/src/personality/learner.ts +209 -0
- package/src/personality/model.ts +132 -0
- package/src/personality/personality.test.ts +236 -0
- package/src/roles/README.md +252 -0
- package/src/roles/authority.ts +120 -0
- package/src/roles/example-usage.ts +198 -0
- package/src/roles/index.ts +42 -0
- package/src/roles/loader.ts +143 -0
- package/src/roles/prompt-builder.ts +218 -0
- package/src/roles/test-multi.ts +102 -0
- package/src/roles/test-role.yaml +77 -0
- package/src/roles/test-utils.ts +93 -0
- package/src/roles/test.ts +106 -0
- package/src/roles/tool-guide.ts +195 -0
- package/src/roles/types.ts +36 -0
- package/src/roles/utils.ts +200 -0
- package/src/scripts/google-setup.ts +168 -0
- package/src/sidecar/connection.ts +179 -0
- package/src/sidecar/index.ts +6 -0
- package/src/sidecar/manager.ts +542 -0
- package/src/sidecar/protocol.ts +85 -0
- package/src/sidecar/rpc.ts +161 -0
- package/src/sidecar/scheduler.ts +136 -0
- package/src/sidecar/types.ts +112 -0
- package/src/sidecar/validator.ts +144 -0
- package/src/sites/builder-tools.ts +215 -0
- package/src/sites/dev-server-manager.ts +286 -0
- package/src/sites/fixtures/security-test-site/.jarvis-project.json +6 -0
- package/src/sites/fixtures/security-test-site/Makefile +15 -0
- package/src/sites/fixtures/security-test-site/README.md +18 -0
- package/src/sites/fixtures/security-test-site/index.html +12 -0
- package/src/sites/fixtures/security-test-site/index.ts +16 -0
- package/src/sites/fixtures/security-test-site/package.json +13 -0
- package/src/sites/fixtures/security-test-site/src/app.tsx +780 -0
- package/src/sites/fixtures/security-test-site/tsconfig.json +10 -0
- package/src/sites/git-manager.ts +240 -0
- package/src/sites/github-manager.ts +355 -0
- package/src/sites/index.ts +25 -0
- package/src/sites/project-manager.ts +389 -0
- package/src/sites/proxy.ts +133 -0
- package/src/sites/service.ts +136 -0
- package/src/sites/templates.ts +169 -0
- package/src/sites/types.ts +89 -0
- package/src/user/profile-followup.test.ts +84 -0
- package/src/user/profile-followup.ts +185 -0
- package/src/user/profile.ts +224 -0
- package/src/vault/README.md +110 -0
- package/src/vault/awareness.ts +341 -0
- package/src/vault/commitments.ts +299 -0
- package/src/vault/content-pipeline.ts +270 -0
- package/src/vault/conversations.ts +173 -0
- package/src/vault/dashboard-sessions.ts +44 -0
- package/src/vault/documents.ts +130 -0
- package/src/vault/entities.ts +185 -0
- package/src/vault/extractor.test.ts +356 -0
- package/src/vault/extractor.ts +345 -0
- package/src/vault/facts.ts +190 -0
- package/src/vault/goals.ts +477 -0
- package/src/vault/index.ts +87 -0
- package/src/vault/keychain.ts +99 -0
- package/src/vault/observations.ts +115 -0
- package/src/vault/relationships.ts +178 -0
- package/src/vault/retrieval.test.ts +139 -0
- package/src/vault/retrieval.ts +258 -0
- package/src/vault/schema.ts +709 -0
- package/src/vault/settings.ts +38 -0
- package/src/vault/user-profile.test.ts +113 -0
- package/src/vault/user-profile.ts +176 -0
- package/src/vault/vectors.ts +92 -0
- package/src/vault/webapp-template-seeds.ts +116 -0
- package/src/vault/webapp-templates.ts +244 -0
- package/src/vault/workflows.ts +403 -0
- package/src/workflows/auto-suggest.ts +290 -0
- package/src/workflows/engine.ts +366 -0
- package/src/workflows/events.ts +24 -0
- package/src/workflows/executor.ts +207 -0
- package/src/workflows/nl-builder.ts +198 -0
- package/src/workflows/nodes/actions/agent-task.ts +73 -0
- package/src/workflows/nodes/actions/calendar-action.ts +85 -0
- package/src/workflows/nodes/actions/code-execution.ts +73 -0
- package/src/workflows/nodes/actions/discord.ts +77 -0
- package/src/workflows/nodes/actions/file-write.ts +73 -0
- package/src/workflows/nodes/actions/gmail.ts +69 -0
- package/src/workflows/nodes/actions/http-request.ts +117 -0
- package/src/workflows/nodes/actions/notification.ts +85 -0
- package/src/workflows/nodes/actions/run-tool.ts +55 -0
- package/src/workflows/nodes/actions/send-message.ts +82 -0
- package/src/workflows/nodes/actions/shell-command.ts +76 -0
- package/src/workflows/nodes/actions/telegram.ts +60 -0
- package/src/workflows/nodes/builtin.ts +119 -0
- package/src/workflows/nodes/error/error-handler.ts +37 -0
- package/src/workflows/nodes/error/fallback.ts +47 -0
- package/src/workflows/nodes/error/retry.ts +82 -0
- package/src/workflows/nodes/logic/delay.ts +42 -0
- package/src/workflows/nodes/logic/if-else.ts +41 -0
- package/src/workflows/nodes/logic/loop.ts +90 -0
- package/src/workflows/nodes/logic/merge.ts +38 -0
- package/src/workflows/nodes/logic/race.ts +40 -0
- package/src/workflows/nodes/logic/switch.ts +59 -0
- package/src/workflows/nodes/logic/template-render.ts +53 -0
- package/src/workflows/nodes/logic/variable-get.ts +37 -0
- package/src/workflows/nodes/logic/variable-set.ts +59 -0
- package/src/workflows/nodes/registry.ts +99 -0
- package/src/workflows/nodes/transform/aggregate.ts +99 -0
- package/src/workflows/nodes/transform/csv-parse.ts +70 -0
- package/src/workflows/nodes/transform/json-parse.ts +63 -0
- package/src/workflows/nodes/transform/map-filter.ts +84 -0
- package/src/workflows/nodes/transform/regex-match.ts +89 -0
- package/src/workflows/nodes/triggers/calendar.ts +33 -0
- package/src/workflows/nodes/triggers/clipboard.ts +32 -0
- package/src/workflows/nodes/triggers/cron.ts +40 -0
- package/src/workflows/nodes/triggers/email.ts +40 -0
- package/src/workflows/nodes/triggers/file-change.ts +45 -0
- package/src/workflows/nodes/triggers/git.ts +46 -0
- package/src/workflows/nodes/triggers/manual.ts +23 -0
- package/src/workflows/nodes/triggers/poll.ts +81 -0
- package/src/workflows/nodes/triggers/process.ts +44 -0
- package/src/workflows/nodes/triggers/screen-event.ts +37 -0
- package/src/workflows/nodes/triggers/webhook.ts +39 -0
- package/src/workflows/safe-eval.ts +139 -0
- package/src/workflows/template.ts +118 -0
- package/src/workflows/triggers/cron.ts +311 -0
- package/src/workflows/triggers/manager.ts +285 -0
- package/src/workflows/triggers/observer-bridge.ts +172 -0
- package/src/workflows/triggers/poller.ts +201 -0
- package/src/workflows/triggers/screen-condition.ts +218 -0
- package/src/workflows/triggers/triggers.test.ts +740 -0
- package/src/workflows/triggers/webhook.ts +191 -0
- package/src/workflows/types.ts +133 -0
- package/src/workflows/variables.ts +72 -0
- package/src/workflows/workflows.test.ts +383 -0
- package/src/workflows/yaml.ts +104 -0
- package/ui/dist/index-3gr23jt9.js +112614 -0
- package/ui/dist/index-9vmj8127.css +14239 -0
- package/ui/dist/index-hy9pc1gm.js +112873 -0
- package/ui/dist/index-j2ep5d1w.js +112374 -0
- package/ui/dist/index-jt00vjqs.js +112858 -0
- package/ui/dist/index-k9ymx5qb.js +112374 -0
- package/ui/dist/index.html +16 -0
- package/ui/public/audio/pcm-capture-processor.js +11 -0
- package/ui/public/openwakeword/models/embedding_model.onnx +0 -0
- package/ui/public/openwakeword/models/hey_jarvis_v0.1.onnx +0 -0
- package/ui/public/openwakeword/models/melspectrogram.onnx +0 -0
- package/ui/public/openwakeword/models/silero_vad.onnx +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.mjs +106 -0
- package/ui/public/ort/ort-wasm-simd-threaded.jsep.wasm +0 -0
- package/ui/public/ort/ort-wasm-simd-threaded.mjs +59 -0
- package/ui/public/ort/ort-wasm-simd-threaded.wasm +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Observer Layer
|
|
2
|
+
|
|
3
|
+
The Observer Layer monitors system events and emits standardized observations to the Vault. All observers implement a common interface and can be managed centrally through the `ObserverManager`.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
### Common Interface
|
|
8
|
+
|
|
9
|
+
All observers implement the `Observer` interface:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
interface Observer {
|
|
13
|
+
name: string;
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
isRunning(): boolean;
|
|
17
|
+
onEvent(handler: ObserverEventHandler): void;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Events are emitted in a standardized format:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
type ObserverEvent = {
|
|
25
|
+
type: string;
|
|
26
|
+
data: Record<string, unknown>;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Observers
|
|
32
|
+
|
|
33
|
+
### FileWatcher (Fully Implemented)
|
|
34
|
+
|
|
35
|
+
Monitors file system changes in specified directories.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { FileWatcher } from './file-watcher';
|
|
39
|
+
|
|
40
|
+
const watcher = new FileWatcher([
|
|
41
|
+
'/home/user/projects',
|
|
42
|
+
'/home/user/documents'
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
watcher.onEvent((event) => {
|
|
46
|
+
// event.type: 'file_change'
|
|
47
|
+
// event.data: { path, eventType: 'rename'|'change', filename, basePath }
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await watcher.start();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Features:
|
|
54
|
+
- Recursive directory watching using `node:fs` watch API
|
|
55
|
+
- Debouncing (100ms) to avoid duplicate rapid-fire events
|
|
56
|
+
- Automatic cleanup of old debounce entries to prevent memory leaks
|
|
57
|
+
|
|
58
|
+
### ClipboardMonitor (Fully Implemented)
|
|
59
|
+
|
|
60
|
+
Polls the system clipboard and detects content changes.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { ClipboardMonitor } from './clipboard';
|
|
64
|
+
|
|
65
|
+
const clipboard = new ClipboardMonitor(1000); // Poll every 1 second
|
|
66
|
+
|
|
67
|
+
clipboard.onEvent((event) => {
|
|
68
|
+
// event.type: 'clipboard'
|
|
69
|
+
// event.data: { content, length }
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await clipboard.start();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Features:
|
|
76
|
+
- Cross-platform clipboard reading (Linux/macOS/Windows/WSL)
|
|
77
|
+
- Automatic platform detection and command selection
|
|
78
|
+
- Silent failure on read errors to avoid spam
|
|
79
|
+
|
|
80
|
+
Platform commands used:
|
|
81
|
+
- Linux: `xclip` or `xsel`
|
|
82
|
+
- macOS: `pbpaste`
|
|
83
|
+
- Windows/WSL: `powershell.exe Get-Clipboard`
|
|
84
|
+
|
|
85
|
+
### ProcessMonitor (Fully Implemented)
|
|
86
|
+
|
|
87
|
+
Monitors running processes and detects lifecycle changes.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { ProcessMonitor } from './processes';
|
|
91
|
+
|
|
92
|
+
const processes = new ProcessMonitor(5000); // Poll every 5 seconds
|
|
93
|
+
|
|
94
|
+
processes.onEvent((event) => {
|
|
95
|
+
// event.type: 'process_started' or 'process_stopped'
|
|
96
|
+
// event.data: { pid, name, cpu?, memory? }
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await processes.start();
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Features:
|
|
103
|
+
- Cross-platform process listing (Linux/macOS/Windows)
|
|
104
|
+
- Detects new and terminated processes
|
|
105
|
+
- Provides CPU and memory usage data
|
|
106
|
+
- Automatic cleanup of terminated process records
|
|
107
|
+
|
|
108
|
+
### NotificationListener (Stub)
|
|
109
|
+
|
|
110
|
+
Placeholder for system notification monitoring.
|
|
111
|
+
|
|
112
|
+
**TODO:**
|
|
113
|
+
- Linux: Monitor D-Bus `org.freedesktop.Notifications`
|
|
114
|
+
- Windows: Use PowerShell to read notification center
|
|
115
|
+
- macOS: Use notification center API
|
|
116
|
+
|
|
117
|
+
### CalendarSync (Stub)
|
|
118
|
+
|
|
119
|
+
Placeholder for calendar integration.
|
|
120
|
+
|
|
121
|
+
**TODO:**
|
|
122
|
+
- Google Calendar API integration (OAuth2)
|
|
123
|
+
- Microsoft Graph API (Outlook/Office 365)
|
|
124
|
+
- CalDAV support for generic providers
|
|
125
|
+
|
|
126
|
+
### EmailSync (Stub)
|
|
127
|
+
|
|
128
|
+
Placeholder for email integration.
|
|
129
|
+
|
|
130
|
+
**TODO:**
|
|
131
|
+
- Gmail API integration (OAuth2)
|
|
132
|
+
- Microsoft Graph API (Outlook/Office 365)
|
|
133
|
+
- IMAP support for generic providers
|
|
134
|
+
|
|
135
|
+
## ObserverManager
|
|
136
|
+
|
|
137
|
+
The `ObserverManager` provides centralized control over all observers.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { ObserverManager, FileWatcher, ClipboardMonitor } from './observers';
|
|
141
|
+
|
|
142
|
+
const manager = new ObserverManager();
|
|
143
|
+
|
|
144
|
+
// Register observers
|
|
145
|
+
manager.register(new FileWatcher(['/path/to/watch']));
|
|
146
|
+
manager.register(new ClipboardMonitor(1000));
|
|
147
|
+
|
|
148
|
+
// Set event handler (typically the Vault's ingestion function)
|
|
149
|
+
manager.setEventHandler((event) => {
|
|
150
|
+
console.log(`[${event.type}]`, event.data);
|
|
151
|
+
// Forward to Vault for storage/analysis
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Start all observers
|
|
155
|
+
await manager.startAll();
|
|
156
|
+
|
|
157
|
+
// Get status
|
|
158
|
+
console.log(manager.getStatus());
|
|
159
|
+
// => { 'file-watcher': true, 'clipboard': true }
|
|
160
|
+
|
|
161
|
+
// Stop specific observer
|
|
162
|
+
await manager.stopObserver('clipboard');
|
|
163
|
+
|
|
164
|
+
// Stop all observers
|
|
165
|
+
await manager.stopAll();
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Manager API
|
|
169
|
+
|
|
170
|
+
- `register(observer: Observer)` - Register a new observer
|
|
171
|
+
- `setEventHandler(handler: ObserverEventHandler)` - Set global event handler
|
|
172
|
+
- `startAll()` - Start all registered observers
|
|
173
|
+
- `stopAll()` - Stop all registered observers
|
|
174
|
+
- `startObserver(name: string)` - Start specific observer
|
|
175
|
+
- `stopObserver(name: string)` - Stop specific observer
|
|
176
|
+
- `getStatus()` - Get running status of all observers
|
|
177
|
+
- `listObservers()` - Get list of registered observer names
|
|
178
|
+
|
|
179
|
+
## Usage Example
|
|
180
|
+
|
|
181
|
+
See `example.ts` for a complete working example:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
bun run src/observers/example.ts
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This will run all observers for 30 seconds and log events to the console.
|
|
188
|
+
|
|
189
|
+
## Integration with Vault
|
|
190
|
+
|
|
191
|
+
The Observer Layer is designed to integrate with the Vault for persistent storage:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { ObserverManager } from './observers';
|
|
195
|
+
import { Vault } from '../vault';
|
|
196
|
+
|
|
197
|
+
const vault = new Vault();
|
|
198
|
+
const manager = new ObserverManager();
|
|
199
|
+
|
|
200
|
+
// Register all observers...
|
|
201
|
+
manager.register(new FileWatcher(['/home/user/projects']));
|
|
202
|
+
// ... etc
|
|
203
|
+
|
|
204
|
+
// Connect to Vault
|
|
205
|
+
manager.setEventHandler((event) => {
|
|
206
|
+
vault.storeObservation(event);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
await manager.startAll();
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Event Types
|
|
213
|
+
|
|
214
|
+
Current event types emitted by observers:
|
|
215
|
+
|
|
216
|
+
- `file_change` - File system change detected
|
|
217
|
+
- `clipboard` - Clipboard content changed
|
|
218
|
+
- `process_started` - New process started
|
|
219
|
+
- `process_stopped` - Process terminated
|
|
220
|
+
|
|
221
|
+
Future event types (when stubs are implemented):
|
|
222
|
+
|
|
223
|
+
- `notification` - System notification received
|
|
224
|
+
- `calendar_event` - Calendar event upcoming/created/updated
|
|
225
|
+
- `new_email` - New email received
|
|
226
|
+
- `email_read` - Email marked as read
|
|
227
|
+
- `email_sent` - Email sent
|
|
228
|
+
|
|
229
|
+
## Performance Considerations
|
|
230
|
+
|
|
231
|
+
- **FileWatcher**: Uses native `node:fs` watch API with minimal overhead
|
|
232
|
+
- **ClipboardMonitor**: Polling-based, configurable interval (default 1s)
|
|
233
|
+
- **ProcessMonitor**: Polling-based, configurable interval (default 5s)
|
|
234
|
+
- **Debouncing**: FileWatcher implements 100ms debouncing for rapid changes
|
|
235
|
+
- **Memory**: Old debounce entries are automatically cleaned up
|
|
236
|
+
|
|
237
|
+
## Error Handling
|
|
238
|
+
|
|
239
|
+
All observers implement graceful error handling:
|
|
240
|
+
|
|
241
|
+
- Silent failures for transient errors (e.g., clipboard read failures)
|
|
242
|
+
- Console logging for persistent errors
|
|
243
|
+
- Proper cleanup in `stop()` methods
|
|
244
|
+
- Error isolation (one observer's failure doesn't affect others)
|
|
245
|
+
|
|
246
|
+
## Platform Support
|
|
247
|
+
|
|
248
|
+
- **Linux**: Full support for all implemented observers
|
|
249
|
+
- **macOS**: Full support for all implemented observers
|
|
250
|
+
- **Windows**: Full support for all implemented observers
|
|
251
|
+
- **WSL**: Full support (uses Windows clipboard via PowerShell)
|
|
252
|
+
|
|
253
|
+
## Testing
|
|
254
|
+
|
|
255
|
+
Run the example to test all observers:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
bun run src/observers/example.ts
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Or create custom tests:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import { test, expect } from 'bun:test';
|
|
265
|
+
import { FileWatcher } from './file-watcher';
|
|
266
|
+
|
|
267
|
+
test('FileWatcher starts and stops', async () => {
|
|
268
|
+
const watcher = new FileWatcher(['/tmp']);
|
|
269
|
+
|
|
270
|
+
expect(watcher.isRunning()).toBe(false);
|
|
271
|
+
|
|
272
|
+
await watcher.start();
|
|
273
|
+
expect(watcher.isRunning()).toBe(true);
|
|
274
|
+
|
|
275
|
+
await watcher.stop();
|
|
276
|
+
expect(watcher.isRunning()).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CalendarSync — Google Calendar Observer
|
|
3
|
+
*
|
|
4
|
+
* Polls Calendar API every 2 minutes with a 30-minute look-ahead.
|
|
5
|
+
* Tracks announced event IDs to avoid duplicate alerts.
|
|
6
|
+
* Graceful: if no Google tokens, logs warning and stays no-op.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Observer, ObserverEventHandler } from './index';
|
|
10
|
+
import type { GoogleAuth } from '../integrations/google-auth.ts';
|
|
11
|
+
import { listUpcomingEvents } from '../integrations/google-api.ts';
|
|
12
|
+
|
|
13
|
+
const POLL_INTERVAL_MS = 2 * 60_000; // 2 minutes
|
|
14
|
+
const LOOK_AHEAD_MS = 30 * 60_000; // 30 minutes
|
|
15
|
+
|
|
16
|
+
export class CalendarSync implements Observer {
|
|
17
|
+
name = 'calendar';
|
|
18
|
+
private running = false;
|
|
19
|
+
private handler: ObserverEventHandler | null = null;
|
|
20
|
+
private pollTimer: Timer | null = null;
|
|
21
|
+
private googleAuth: GoogleAuth | null;
|
|
22
|
+
private announcedEventIds: Set<string> = new Set();
|
|
23
|
+
private calendarId: string;
|
|
24
|
+
|
|
25
|
+
constructor(googleAuth?: GoogleAuth, calendarId?: string) {
|
|
26
|
+
this.googleAuth = googleAuth ?? null;
|
|
27
|
+
this.calendarId = calendarId ?? 'primary';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async start(): Promise<void> {
|
|
31
|
+
this.running = true;
|
|
32
|
+
|
|
33
|
+
if (!this.googleAuth || !this.googleAuth.isAuthenticated()) {
|
|
34
|
+
console.log('[calendar] No Google auth configured — calendar monitoring disabled');
|
|
35
|
+
console.log('[calendar] Run: bun run src/scripts/google-setup.ts to set up Calendar');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log('[calendar] Observer started — polling Calendar every 2min (30min look-ahead)');
|
|
40
|
+
|
|
41
|
+
// Initial poll
|
|
42
|
+
this.poll();
|
|
43
|
+
|
|
44
|
+
// Set up recurring poll
|
|
45
|
+
this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async stop(): Promise<void> {
|
|
49
|
+
this.running = false;
|
|
50
|
+
|
|
51
|
+
if (this.pollTimer) {
|
|
52
|
+
clearInterval(this.pollTimer);
|
|
53
|
+
this.pollTimer = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('[calendar] Observer stopped');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
isRunning(): boolean {
|
|
60
|
+
return this.running;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onEvent(handler: ObserverEventHandler): void {
|
|
64
|
+
this.handler = handler;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private async poll(): Promise<void> {
|
|
68
|
+
if (!this.googleAuth || !this.handler) return;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const accessToken = await this.googleAuth.getAccessToken();
|
|
72
|
+
const now = new Date();
|
|
73
|
+
const later = new Date(now.getTime() + LOOK_AHEAD_MS);
|
|
74
|
+
|
|
75
|
+
const events = await listUpcomingEvents(
|
|
76
|
+
accessToken,
|
|
77
|
+
this.calendarId,
|
|
78
|
+
now.toISOString(),
|
|
79
|
+
later.toISOString(),
|
|
80
|
+
10
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
for (const event of events) {
|
|
84
|
+
// Skip already-announced events
|
|
85
|
+
if (this.announcedEventIds.has(event.id)) continue;
|
|
86
|
+
this.announcedEventIds.add(event.id);
|
|
87
|
+
|
|
88
|
+
this.handler({
|
|
89
|
+
type: 'calendar',
|
|
90
|
+
data: {
|
|
91
|
+
id: event.id,
|
|
92
|
+
summary: event.summary,
|
|
93
|
+
description: event.description,
|
|
94
|
+
start: event.start,
|
|
95
|
+
end: event.end,
|
|
96
|
+
location: event.location,
|
|
97
|
+
attendees: event.attendees,
|
|
98
|
+
htmlLink: event.htmlLink,
|
|
99
|
+
},
|
|
100
|
+
timestamp: Date.now(),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Cap announcedEventIds to prevent unbounded growth
|
|
105
|
+
if (this.announcedEventIds.size > 500) {
|
|
106
|
+
const arr = Array.from(this.announcedEventIds);
|
|
107
|
+
this.announcedEventIds = new Set(arr.slice(arr.length - 250));
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.error('[calendar] Poll error:', err);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClipboardMonitor - Monitors clipboard changes
|
|
3
|
+
*
|
|
4
|
+
* Polls the system clipboard at regular intervals and emits events when content changes.
|
|
5
|
+
* Uses platform-specific commands to read clipboard content.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Observer, ObserverEvent, ObserverEventHandler } from './index';
|
|
9
|
+
|
|
10
|
+
export class ClipboardMonitor implements Observer {
|
|
11
|
+
name = 'clipboard';
|
|
12
|
+
private interval: Timer | null = null;
|
|
13
|
+
private lastContent: string = '';
|
|
14
|
+
private handler: ObserverEventHandler | null = null;
|
|
15
|
+
private running = false;
|
|
16
|
+
private pollMs: number;
|
|
17
|
+
|
|
18
|
+
constructor(pollMs: number = 1000) {
|
|
19
|
+
this.pollMs = pollMs;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async start(): Promise<void> {
|
|
23
|
+
if (this.running) {
|
|
24
|
+
console.log('[clipboard] Already running');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(`[clipboard] Starting clipboard monitoring (polling every ${this.pollMs}ms)...`);
|
|
29
|
+
|
|
30
|
+
// Initialize with current clipboard content
|
|
31
|
+
try {
|
|
32
|
+
this.lastContent = await this.readClipboard();
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('[clipboard] Failed to read initial clipboard:', error);
|
|
35
|
+
this.lastContent = '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Start polling
|
|
39
|
+
this.interval = setInterval(async () => {
|
|
40
|
+
try {
|
|
41
|
+
const content = await this.readClipboard();
|
|
42
|
+
|
|
43
|
+
if (content !== this.lastContent) {
|
|
44
|
+
this.lastContent = content;
|
|
45
|
+
|
|
46
|
+
if (this.handler) {
|
|
47
|
+
const event: ObserverEvent = {
|
|
48
|
+
type: 'clipboard',
|
|
49
|
+
data: {
|
|
50
|
+
content,
|
|
51
|
+
length: content.length,
|
|
52
|
+
},
|
|
53
|
+
timestamp: Date.now(),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
this.handler(event);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// Silent fail on read errors to avoid spam
|
|
61
|
+
// console.error('[clipboard] Failed to read clipboard:', error);
|
|
62
|
+
}
|
|
63
|
+
}, this.pollMs);
|
|
64
|
+
|
|
65
|
+
this.running = true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async stop(): Promise<void> {
|
|
69
|
+
if (!this.running) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('[clipboard] Stopping clipboard monitoring...');
|
|
74
|
+
|
|
75
|
+
if (this.interval) {
|
|
76
|
+
clearInterval(this.interval);
|
|
77
|
+
this.interval = null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.running = false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
isRunning(): boolean {
|
|
84
|
+
return this.running;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
onEvent(handler: ObserverEventHandler): void {
|
|
88
|
+
this.handler = handler;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Read clipboard content using platform-specific commands
|
|
93
|
+
*/
|
|
94
|
+
private async readClipboard(): Promise<string> {
|
|
95
|
+
const platform = process.platform;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
let result: { stdout: Buffer; stderr: Buffer };
|
|
99
|
+
|
|
100
|
+
if (platform === 'linux') {
|
|
101
|
+
// Try xclip first
|
|
102
|
+
try {
|
|
103
|
+
result = await Bun.$`xclip -selection clipboard -o`.quiet();
|
|
104
|
+
return result.stdout.toString().trim();
|
|
105
|
+
} catch {
|
|
106
|
+
// Fall back to xsel
|
|
107
|
+
try {
|
|
108
|
+
result = await Bun.$`xsel --clipboard --output`.quiet();
|
|
109
|
+
return result.stdout.toString().trim();
|
|
110
|
+
} catch {
|
|
111
|
+
// Check if we're in WSL and can use PowerShell
|
|
112
|
+
try {
|
|
113
|
+
result = await Bun.$`powershell.exe Get-Clipboard`.quiet();
|
|
114
|
+
return result.stdout.toString().trim();
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error('No clipboard tool available (tried xclip, xsel, powershell.exe)');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} else if (platform === 'darwin') {
|
|
121
|
+
// macOS
|
|
122
|
+
result = await Bun.$`pbpaste`.quiet();
|
|
123
|
+
return result.stdout.toString().trim();
|
|
124
|
+
} else if (platform === 'win32') {
|
|
125
|
+
// Windows
|
|
126
|
+
result = await Bun.$`powershell.exe Get-Clipboard`.quiet();
|
|
127
|
+
return result.stdout.toString().trim();
|
|
128
|
+
} else {
|
|
129
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Return empty string on error
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmailSync — Gmail Observer
|
|
3
|
+
*
|
|
4
|
+
* Polls Gmail API every 60s for unread messages.
|
|
5
|
+
* Tracks seen message IDs to avoid re-emitting.
|
|
6
|
+
* Fetches detail (subject, from, snippet) for new messages.
|
|
7
|
+
* Graceful: if no Google tokens, logs warning and stays no-op.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Observer, ObserverEventHandler } from './index';
|
|
11
|
+
import type { GoogleAuth } from '../integrations/google-auth.ts';
|
|
12
|
+
import { listUnreadEmails, getEmailDetail } from '../integrations/google-api.ts';
|
|
13
|
+
|
|
14
|
+
const POLL_INTERVAL_MS = 60_000; // 60 seconds
|
|
15
|
+
|
|
16
|
+
export class EmailSync implements Observer {
|
|
17
|
+
name = 'email';
|
|
18
|
+
private running = false;
|
|
19
|
+
private handler: ObserverEventHandler | null = null;
|
|
20
|
+
private pollTimer: Timer | null = null;
|
|
21
|
+
private googleAuth: GoogleAuth | null;
|
|
22
|
+
private seenMessageIds: Set<string> = new Set();
|
|
23
|
+
|
|
24
|
+
constructor(googleAuth?: GoogleAuth) {
|
|
25
|
+
this.googleAuth = googleAuth ?? null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async start(): Promise<void> {
|
|
29
|
+
this.running = true;
|
|
30
|
+
|
|
31
|
+
if (!this.googleAuth || !this.googleAuth.isAuthenticated()) {
|
|
32
|
+
console.log('[email] No Google auth configured — email monitoring disabled');
|
|
33
|
+
console.log('[email] Run: bun run src/scripts/google-setup.ts to set up Gmail');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('[email] Observer started — polling Gmail every 60s');
|
|
38
|
+
|
|
39
|
+
// Initial poll
|
|
40
|
+
this.poll();
|
|
41
|
+
|
|
42
|
+
// Set up recurring poll
|
|
43
|
+
this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async stop(): Promise<void> {
|
|
47
|
+
this.running = false;
|
|
48
|
+
|
|
49
|
+
if (this.pollTimer) {
|
|
50
|
+
clearInterval(this.pollTimer);
|
|
51
|
+
this.pollTimer = null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log('[email] Observer stopped');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
isRunning(): boolean {
|
|
58
|
+
return this.running;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onEvent(handler: ObserverEventHandler): void {
|
|
62
|
+
this.handler = handler;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private async poll(): Promise<void> {
|
|
66
|
+
if (!this.googleAuth || !this.handler) return;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const accessToken = await this.googleAuth.getAccessToken();
|
|
70
|
+
const messages = await listUnreadEmails(accessToken, 10);
|
|
71
|
+
|
|
72
|
+
for (const msg of messages) {
|
|
73
|
+
// Skip already-seen messages
|
|
74
|
+
if (this.seenMessageIds.has(msg.id)) continue;
|
|
75
|
+
this.seenMessageIds.add(msg.id);
|
|
76
|
+
|
|
77
|
+
// Fetch detail
|
|
78
|
+
try {
|
|
79
|
+
const detail = await getEmailDetail(accessToken, msg.id);
|
|
80
|
+
|
|
81
|
+
this.handler({
|
|
82
|
+
type: 'email',
|
|
83
|
+
data: {
|
|
84
|
+
id: detail.id,
|
|
85
|
+
threadId: detail.threadId,
|
|
86
|
+
subject: detail.subject,
|
|
87
|
+
from: detail.from,
|
|
88
|
+
to: detail.to,
|
|
89
|
+
date: detail.date,
|
|
90
|
+
snippet: detail.snippet,
|
|
91
|
+
labels: detail.labels,
|
|
92
|
+
},
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error(`[email] Failed to get detail for ${msg.id}:`, err);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Cap seenMessageIds to prevent unbounded growth
|
|
101
|
+
if (this.seenMessageIds.size > 1000) {
|
|
102
|
+
const arr = Array.from(this.seenMessageIds);
|
|
103
|
+
this.seenMessageIds = new Set(arr.slice(arr.length - 500));
|
|
104
|
+
}
|
|
105
|
+
} catch (err) {
|
|
106
|
+
console.error('[email] Poll error:', err);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example usage of the Observer Layer
|
|
3
|
+
*
|
|
4
|
+
* This demonstrates how to set up and use the ObserverManager with various observers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ObserverManager,
|
|
9
|
+
FileWatcher,
|
|
10
|
+
ClipboardMonitor,
|
|
11
|
+
ProcessMonitor,
|
|
12
|
+
NotificationListener,
|
|
13
|
+
CalendarSync,
|
|
14
|
+
EmailSync,
|
|
15
|
+
type ObserverEvent,
|
|
16
|
+
} from './index';
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
// Create the manager
|
|
20
|
+
const manager = new ObserverManager();
|
|
21
|
+
|
|
22
|
+
// Register observers
|
|
23
|
+
manager.register(new FileWatcher([import.meta.dir + '/../'])); // Watch src directory
|
|
24
|
+
manager.register(new ClipboardMonitor(2000)); // Poll clipboard every 2 seconds
|
|
25
|
+
manager.register(new ProcessMonitor(10000)); // Poll processes every 10 seconds
|
|
26
|
+
manager.register(new NotificationListener()); // Stub
|
|
27
|
+
manager.register(new CalendarSync()); // Stub
|
|
28
|
+
manager.register(new EmailSync()); // Stub
|
|
29
|
+
|
|
30
|
+
// Set up event handler (this would typically be the Vault's ingestion function)
|
|
31
|
+
manager.setEventHandler((event: ObserverEvent) => {
|
|
32
|
+
console.log(`[EVENT] ${event.type} at ${new Date(event.timestamp).toISOString()}`);
|
|
33
|
+
console.log(' Data:', JSON.stringify(event.data, null, 2));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Start all observers
|
|
37
|
+
await manager.startAll();
|
|
38
|
+
|
|
39
|
+
// Get status
|
|
40
|
+
console.log('\n[STATUS] Observer running status:', manager.getStatus());
|
|
41
|
+
|
|
42
|
+
// Run for 30 seconds, then stop
|
|
43
|
+
console.log('\n[INFO] Running observers for 30 seconds...\n');
|
|
44
|
+
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 30000));
|
|
46
|
+
|
|
47
|
+
// Stop all observers
|
|
48
|
+
await manager.stopAll();
|
|
49
|
+
|
|
50
|
+
console.log('\n[INFO] Example complete');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Run example if executed directly
|
|
54
|
+
if (import.meta.main) {
|
|
55
|
+
main().catch(console.error);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { main };
|