@usejarvis/brain 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.
- package/LICENSE +153 -0
- package/README.md +278 -0
- package/bin/jarvis.ts +413 -0
- package/package.json +74 -0
- package/scripts/ensure-bun.cjs +8 -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 +252 -0
- package/src/actions/browser/session.ts +437 -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 +321 -0
- package/src/actions/tools/builtin.ts +846 -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/goals.ts +376 -0
- package/src/actions/tools/local-tools-guard.ts +20 -0
- package/src/actions/tools/registry.ts +171 -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 +576 -0
- package/src/agents/role-discovery.ts +61 -0
- package/src/agents/sub-agent-runner.ts +307 -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 +297 -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 +241 -0
- package/src/cli/deps.ts +449 -0
- package/src/cli/doctor.ts +230 -0
- package/src/cli/helpers.ts +401 -0
- package/src/cli/onboard.ts +580 -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/desktop-notify.ts +114 -0
- package/src/comms/example.ts +129 -0
- package/src/comms/index.ts +129 -0
- package/src/comms/streaming.ts +142 -0
- package/src/comms/voice.test.ts +152 -0
- package/src/comms/voice.ts +291 -0
- package/src/comms/websocket.test.ts +409 -0
- package/src/comms/websocket.ts +473 -0
- package/src/config/README.md +387 -0
- package/src/config/index.ts +6 -0
- package/src/config/loader.test.ts +137 -0
- package/src/config/loader.ts +142 -0
- package/src/config/types.ts +260 -0
- package/src/daemon/README.md +232 -0
- package/src/daemon/agent-service-interface.ts +9 -0
- package/src/daemon/agent-service.ts +600 -0
- package/src/daemon/api-routes.ts +2119 -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/event-classifier.ts +239 -0
- package/src/daemon/event-coalescer.ts +123 -0
- package/src/daemon/event-reactor.ts +214 -0
- package/src/daemon/health.ts +220 -0
- package/src/daemon/index.ts +1004 -0
- package/src/daemon/llm-settings.ts +316 -0
- package/src/daemon/observer-service.ts +150 -0
- package/src/daemon/pid.ts +98 -0
- package/src/daemon/research-queue.ts +155 -0
- package/src/daemon/services.ts +175 -0
- package/src/daemon/ws-service.ts +788 -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 +348 -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 +386 -0
- package/src/llm/gemini.ts +371 -0
- package/src/llm/index.ts +19 -0
- package/src/llm/manager.ts +153 -0
- package/src/llm/ollama.ts +307 -0
- package/src/llm/openai.ts +350 -0
- package/src/llm/provider.test.ts +231 -0
- package/src/llm/provider.ts +60 -0
- package/src/llm/test.ts +87 -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 +119 -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 +194 -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 +190 -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/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 +260 -0
- package/src/vault/conversations.ts +173 -0
- package/src/vault/entities.ts +180 -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 +126 -0
- package/src/vault/retrieval.ts +227 -0
- package/src/vault/schema.ts +658 -0
- package/src/vault/settings.ts +38 -0
- package/src/vault/vectors.ts +92 -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-j75njzc1.css +1199 -0
- package/ui/dist/index-p2zh407q.js +80603 -0
- package/ui/dist/index.html +13 -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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResearchQueue — Background Research Engine
|
|
3
|
+
*
|
|
4
|
+
* Manages a queue of topics for JARVIS to research during idle time.
|
|
5
|
+
* Topics come from conversations, explicit requests, or the agent itself.
|
|
6
|
+
* The heartbeat picks up the next topic when nothing urgent is happening.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type ResearchPriority = 'high' | 'normal' | 'low';
|
|
10
|
+
export type ResearchStatus = 'queued' | 'in_progress' | 'completed' | 'failed';
|
|
11
|
+
|
|
12
|
+
export type ResearchTopic = {
|
|
13
|
+
id: string;
|
|
14
|
+
topic: string;
|
|
15
|
+
reason: string;
|
|
16
|
+
source: string; // 'user' | 'agent' | 'conversation'
|
|
17
|
+
priority: ResearchPriority;
|
|
18
|
+
status: ResearchStatus;
|
|
19
|
+
result?: string;
|
|
20
|
+
failReason?: string;
|
|
21
|
+
created_at: number;
|
|
22
|
+
completed_at?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const MAX_QUEUE_SIZE = 50;
|
|
26
|
+
|
|
27
|
+
export class ResearchQueue {
|
|
28
|
+
private topics: Map<string, ResearchTopic> = new Map();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Add a topic to the research queue.
|
|
32
|
+
*/
|
|
33
|
+
addTopic(
|
|
34
|
+
topic: string,
|
|
35
|
+
reason: string,
|
|
36
|
+
source: string = 'user',
|
|
37
|
+
priority: ResearchPriority = 'normal'
|
|
38
|
+
): ResearchTopic {
|
|
39
|
+
// Enforce max queue size (drop oldest low-priority)
|
|
40
|
+
if (this.topics.size >= MAX_QUEUE_SIZE) {
|
|
41
|
+
this.evictOldest();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const entry: ResearchTopic = {
|
|
45
|
+
id: crypto.randomUUID(),
|
|
46
|
+
topic,
|
|
47
|
+
reason,
|
|
48
|
+
source,
|
|
49
|
+
priority,
|
|
50
|
+
status: 'queued',
|
|
51
|
+
created_at: Date.now(),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
this.topics.set(entry.id, entry);
|
|
55
|
+
console.log(`[ResearchQueue] Added: "${topic}" (${priority}, from ${source})`);
|
|
56
|
+
return entry;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the next highest-priority queued topic.
|
|
61
|
+
*/
|
|
62
|
+
getNext(): ResearchTopic | null {
|
|
63
|
+
const queued = Array.from(this.topics.values())
|
|
64
|
+
.filter((t) => t.status === 'queued')
|
|
65
|
+
.sort((a, b) => {
|
|
66
|
+
// Priority order: high > normal > low
|
|
67
|
+
const pOrder: Record<ResearchPriority, number> = { high: 0, normal: 1, low: 2 };
|
|
68
|
+
const pDiff = pOrder[a.priority] - pOrder[b.priority];
|
|
69
|
+
if (pDiff !== 0) return pDiff;
|
|
70
|
+
// Older topics first within same priority
|
|
71
|
+
return a.created_at - b.created_at;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return queued[0] ?? null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Mark a topic as in-progress.
|
|
79
|
+
*/
|
|
80
|
+
startResearch(id: string): boolean {
|
|
81
|
+
const topic = this.topics.get(id);
|
|
82
|
+
if (!topic || topic.status !== 'queued') return false;
|
|
83
|
+
topic.status = 'in_progress';
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Mark a topic as completed with a result.
|
|
89
|
+
*/
|
|
90
|
+
complete(id: string, result: string): boolean {
|
|
91
|
+
const topic = this.topics.get(id);
|
|
92
|
+
if (!topic) return false;
|
|
93
|
+
topic.status = 'completed';
|
|
94
|
+
topic.result = result;
|
|
95
|
+
topic.completed_at = Date.now();
|
|
96
|
+
console.log(`[ResearchQueue] Completed: "${topic.topic}"`);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Mark a topic as failed.
|
|
102
|
+
*/
|
|
103
|
+
fail(id: string, reason: string): boolean {
|
|
104
|
+
const topic = this.topics.get(id);
|
|
105
|
+
if (!topic) return false;
|
|
106
|
+
topic.status = 'failed';
|
|
107
|
+
topic.failReason = reason;
|
|
108
|
+
topic.completed_at = Date.now();
|
|
109
|
+
console.log(`[ResearchQueue] Failed: "${topic.topic}" — ${reason}`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove a topic from the queue.
|
|
115
|
+
*/
|
|
116
|
+
remove(id: string): boolean {
|
|
117
|
+
return this.topics.delete(id);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* List all topics, optionally filtered by status.
|
|
122
|
+
*/
|
|
123
|
+
list(status?: ResearchStatus): ResearchTopic[] {
|
|
124
|
+
const all = Array.from(this.topics.values());
|
|
125
|
+
if (status) return all.filter((t) => t.status === status);
|
|
126
|
+
return all;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get count of queued topics.
|
|
131
|
+
*/
|
|
132
|
+
queuedCount(): number {
|
|
133
|
+
return Array.from(this.topics.values()).filter((t) => t.status === 'queued').length;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private evictOldest(): void {
|
|
137
|
+
// Evict oldest completed, then oldest low-priority queued
|
|
138
|
+
const completed = Array.from(this.topics.values())
|
|
139
|
+
.filter((t) => t.status === 'completed' || t.status === 'failed')
|
|
140
|
+
.sort((a, b) => a.created_at - b.created_at);
|
|
141
|
+
|
|
142
|
+
if (completed.length > 0) {
|
|
143
|
+
this.topics.delete(completed[0]!.id);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const low = Array.from(this.topics.values())
|
|
148
|
+
.filter((t) => t.priority === 'low' && t.status === 'queued')
|
|
149
|
+
.sort((a, b) => a.created_at - b.created_at);
|
|
150
|
+
|
|
151
|
+
if (low.length > 0) {
|
|
152
|
+
this.topics.delete(low[0]!.id);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages lifecycle of all daemon services (observers, agents, WebSocket server, etc.)
|
|
5
|
+
* Services are started in registration order and stopped in reverse order.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type ServiceStatus = 'stopped' | 'starting' | 'running' | 'stopping' | 'error';
|
|
9
|
+
|
|
10
|
+
export interface Service {
|
|
11
|
+
name: string;
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
status(): ServiceStatus;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface RegisteredService {
|
|
18
|
+
service: Service;
|
|
19
|
+
status: ServiceStatus;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ServiceRegistry {
|
|
24
|
+
private services = new Map<string, RegisteredService>();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Register a service
|
|
28
|
+
*/
|
|
29
|
+
register(service: Service): void {
|
|
30
|
+
if (this.services.has(service.name)) {
|
|
31
|
+
throw new Error(`Service '${service.name}' is already registered`);
|
|
32
|
+
}
|
|
33
|
+
this.services.set(service.name, {
|
|
34
|
+
service,
|
|
35
|
+
status: 'stopped',
|
|
36
|
+
});
|
|
37
|
+
console.log(`[ServiceRegistry] Registered service: ${service.name}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Start all registered services in order
|
|
42
|
+
*/
|
|
43
|
+
async startAll(): Promise<void> {
|
|
44
|
+
console.log('[ServiceRegistry] Starting all services...');
|
|
45
|
+
for (const [name, registered] of this.services) {
|
|
46
|
+
await this.startService(name);
|
|
47
|
+
}
|
|
48
|
+
console.log('[ServiceRegistry] All services started');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Stop all services in reverse order
|
|
53
|
+
*/
|
|
54
|
+
async stopAll(): Promise<void> {
|
|
55
|
+
console.log('[ServiceRegistry] Stopping all services...');
|
|
56
|
+
const serviceNames = Array.from(this.services.keys()).reverse();
|
|
57
|
+
for (const name of serviceNames) {
|
|
58
|
+
await this.stopService(name);
|
|
59
|
+
}
|
|
60
|
+
console.log('[ServiceRegistry] All services stopped');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Start a specific service
|
|
65
|
+
*/
|
|
66
|
+
async startService(name: string): Promise<void> {
|
|
67
|
+
const registered = this.services.get(name);
|
|
68
|
+
if (!registered) {
|
|
69
|
+
throw new Error(`Service '${name}' not found`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (registered.status === 'running') {
|
|
73
|
+
console.log(`[ServiceRegistry] Service '${name}' is already running`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
registered.status = 'starting';
|
|
79
|
+
this.services.set(name, registered);
|
|
80
|
+
|
|
81
|
+
console.log(`[ServiceRegistry] Starting ${name}...`);
|
|
82
|
+
await registered.service.start();
|
|
83
|
+
|
|
84
|
+
registered.status = 'running';
|
|
85
|
+
registered.error = undefined;
|
|
86
|
+
this.services.set(name, registered);
|
|
87
|
+
|
|
88
|
+
console.log(`[ServiceRegistry] ✓ ${name} started`);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
registered.status = 'error';
|
|
92
|
+
registered.error = message;
|
|
93
|
+
this.services.set(name, registered);
|
|
94
|
+
|
|
95
|
+
console.error(`[ServiceRegistry] ✗ Failed to start ${name}: ${message}`);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Stop a specific service
|
|
102
|
+
*/
|
|
103
|
+
async stopService(name: string): Promise<void> {
|
|
104
|
+
const registered = this.services.get(name);
|
|
105
|
+
if (!registered) {
|
|
106
|
+
throw new Error(`Service '${name}' not found`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (registered.status === 'stopped') {
|
|
110
|
+
console.log(`[ServiceRegistry] Service '${name}' is already stopped`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
registered.status = 'stopping';
|
|
116
|
+
this.services.set(name, registered);
|
|
117
|
+
|
|
118
|
+
console.log(`[ServiceRegistry] Stopping ${name}...`);
|
|
119
|
+
await registered.service.stop();
|
|
120
|
+
|
|
121
|
+
registered.status = 'stopped';
|
|
122
|
+
registered.error = undefined;
|
|
123
|
+
this.services.set(name, registered);
|
|
124
|
+
|
|
125
|
+
console.log(`[ServiceRegistry] ✓ ${name} stopped`);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
128
|
+
registered.status = 'error';
|
|
129
|
+
registered.error = message;
|
|
130
|
+
this.services.set(name, registered);
|
|
131
|
+
|
|
132
|
+
console.error(`[ServiceRegistry] ✗ Failed to stop ${name}: ${message}`);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get status of all services
|
|
139
|
+
*/
|
|
140
|
+
getStatus(): Record<string, ServiceStatus> {
|
|
141
|
+
const status: Record<string, ServiceStatus> = {};
|
|
142
|
+
for (const [name, registered] of this.services) {
|
|
143
|
+
status[name] = registered.status;
|
|
144
|
+
}
|
|
145
|
+
return status;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get a specific service
|
|
150
|
+
*/
|
|
151
|
+
get(name: string): Service | undefined {
|
|
152
|
+
return this.services.get(name)?.service;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get all registered service names
|
|
157
|
+
*/
|
|
158
|
+
list(): string[] {
|
|
159
|
+
return Array.from(this.services.keys());
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if a service is registered
|
|
164
|
+
*/
|
|
165
|
+
has(name: string): boolean {
|
|
166
|
+
return this.services.has(name);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get detailed service info including errors
|
|
171
|
+
*/
|
|
172
|
+
getServiceInfo(name: string): RegisteredService | undefined {
|
|
173
|
+
return this.services.get(name);
|
|
174
|
+
}
|
|
175
|
+
}
|