homaruscc 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/.env.example +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +307 -0
  4. package/bin/event-loop +60 -0
  5. package/config.example.json +55 -0
  6. package/dist/agent-registry.d.ts +38 -0
  7. package/dist/agent-registry.d.ts.map +1 -0
  8. package/dist/agent-registry.js +207 -0
  9. package/dist/agent-registry.js.map +1 -0
  10. package/dist/backend.d.ts +3 -0
  11. package/dist/backend.d.ts.map +1 -0
  12. package/dist/backend.js +59 -0
  13. package/dist/backend.js.map +1 -0
  14. package/dist/browser-service.d.ts +19 -0
  15. package/dist/browser-service.d.ts.map +1 -0
  16. package/dist/browser-service.js +101 -0
  17. package/dist/browser-service.js.map +1 -0
  18. package/dist/channel-adapter.d.ts +22 -0
  19. package/dist/channel-adapter.d.ts.map +1 -0
  20. package/dist/channel-adapter.js +62 -0
  21. package/dist/channel-adapter.js.map +1 -0
  22. package/dist/channel-manager.d.ts +18 -0
  23. package/dist/channel-manager.d.ts.map +1 -0
  24. package/dist/channel-manager.js +73 -0
  25. package/dist/channel-manager.js.map +1 -0
  26. package/dist/compaction-manager.d.ts +23 -0
  27. package/dist/compaction-manager.d.ts.map +1 -0
  28. package/dist/compaction-manager.js +135 -0
  29. package/dist/compaction-manager.js.map +1 -0
  30. package/dist/config.d.ts +21 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +169 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/dashboard-adapter.d.ts +17 -0
  35. package/dist/dashboard-adapter.d.ts.map +1 -0
  36. package/dist/dashboard-adapter.js +41 -0
  37. package/dist/dashboard-adapter.js.map +1 -0
  38. package/dist/dashboard-server.d.ts +29 -0
  39. package/dist/dashboard-server.d.ts.map +1 -0
  40. package/dist/dashboard-server.js +381 -0
  41. package/dist/dashboard-server.js.map +1 -0
  42. package/dist/embedding-provider.d.ts +28 -0
  43. package/dist/embedding-provider.d.ts.map +1 -0
  44. package/dist/embedding-provider.js +91 -0
  45. package/dist/embedding-provider.js.map +1 -0
  46. package/dist/event-bus.d.ts +18 -0
  47. package/dist/event-bus.d.ts.map +1 -0
  48. package/dist/event-bus.js +41 -0
  49. package/dist/event-bus.js.map +1 -0
  50. package/dist/event-queue.d.ts +18 -0
  51. package/dist/event-queue.d.ts.map +1 -0
  52. package/dist/event-queue.js +68 -0
  53. package/dist/event-queue.js.map +1 -0
  54. package/dist/homaruscc.d.ts +69 -0
  55. package/dist/homaruscc.d.ts.map +1 -0
  56. package/dist/homaruscc.js +337 -0
  57. package/dist/homaruscc.js.map +1 -0
  58. package/dist/identity-manager.d.ts +36 -0
  59. package/dist/identity-manager.d.ts.map +1 -0
  60. package/dist/identity-manager.js +142 -0
  61. package/dist/identity-manager.js.map +1 -0
  62. package/dist/mcp-proxy.d.ts +3 -0
  63. package/dist/mcp-proxy.d.ts.map +1 -0
  64. package/dist/mcp-proxy.js +259 -0
  65. package/dist/mcp-proxy.js.map +1 -0
  66. package/dist/mcp-resources.d.ts +10 -0
  67. package/dist/mcp-resources.d.ts.map +1 -0
  68. package/dist/mcp-resources.js +67 -0
  69. package/dist/mcp-resources.js.map +1 -0
  70. package/dist/mcp-server.d.ts +3 -0
  71. package/dist/mcp-server.d.ts.map +1 -0
  72. package/dist/mcp-server.js +169 -0
  73. package/dist/mcp-server.js.map +1 -0
  74. package/dist/mcp-tools.d.ts +14 -0
  75. package/dist/mcp-tools.d.ts.map +1 -0
  76. package/dist/mcp-tools.js +408 -0
  77. package/dist/mcp-tools.js.map +1 -0
  78. package/dist/memory-index.d.ts +79 -0
  79. package/dist/memory-index.d.ts.map +1 -0
  80. package/dist/memory-index.js +437 -0
  81. package/dist/memory-index.js.map +1 -0
  82. package/dist/session-checkpoint.d.ts +22 -0
  83. package/dist/session-checkpoint.d.ts.map +1 -0
  84. package/dist/session-checkpoint.js +100 -0
  85. package/dist/session-checkpoint.js.map +1 -0
  86. package/dist/skill-manager.d.ts +26 -0
  87. package/dist/skill-manager.d.ts.map +1 -0
  88. package/dist/skill-manager.js +156 -0
  89. package/dist/skill-manager.js.map +1 -0
  90. package/dist/skill-transport.d.ts +45 -0
  91. package/dist/skill-transport.d.ts.map +1 -0
  92. package/dist/skill-transport.js +111 -0
  93. package/dist/skill-transport.js.map +1 -0
  94. package/dist/skill.d.ts +22 -0
  95. package/dist/skill.d.ts.map +1 -0
  96. package/dist/skill.js +106 -0
  97. package/dist/skill.js.map +1 -0
  98. package/dist/telegram-adapter.d.ts +43 -0
  99. package/dist/telegram-adapter.d.ts.map +1 -0
  100. package/dist/telegram-adapter.js +188 -0
  101. package/dist/telegram-adapter.js.map +1 -0
  102. package/dist/timer-service.d.ts +30 -0
  103. package/dist/timer-service.d.ts.map +1 -0
  104. package/dist/timer-service.js +176 -0
  105. package/dist/timer-service.js.map +1 -0
  106. package/dist/tool-registry.d.ts +30 -0
  107. package/dist/tool-registry.d.ts.map +1 -0
  108. package/dist/tool-registry.js +108 -0
  109. package/dist/tool-registry.js.map +1 -0
  110. package/dist/tools/bash.d.ts +3 -0
  111. package/dist/tools/bash.d.ts.map +1 -0
  112. package/dist/tools/bash.js +67 -0
  113. package/dist/tools/bash.js.map +1 -0
  114. package/dist/tools/browser.d.ts +4 -0
  115. package/dist/tools/browser.d.ts.map +1 -0
  116. package/dist/tools/browser.js +138 -0
  117. package/dist/tools/browser.js.map +1 -0
  118. package/dist/tools/edit.d.ts +3 -0
  119. package/dist/tools/edit.d.ts.map +1 -0
  120. package/dist/tools/edit.js +47 -0
  121. package/dist/tools/edit.js.map +1 -0
  122. package/dist/tools/git.d.ts +3 -0
  123. package/dist/tools/git.d.ts.map +1 -0
  124. package/dist/tools/git.js +105 -0
  125. package/dist/tools/git.js.map +1 -0
  126. package/dist/tools/glob.d.ts +3 -0
  127. package/dist/tools/glob.d.ts.map +1 -0
  128. package/dist/tools/glob.js +84 -0
  129. package/dist/tools/glob.js.map +1 -0
  130. package/dist/tools/grep.d.ts +3 -0
  131. package/dist/tools/grep.d.ts.map +1 -0
  132. package/dist/tools/grep.js +168 -0
  133. package/dist/tools/grep.js.map +1 -0
  134. package/dist/tools/index.d.ts +6 -0
  135. package/dist/tools/index.d.ts.map +1 -0
  136. package/dist/tools/index.js +46 -0
  137. package/dist/tools/index.js.map +1 -0
  138. package/dist/tools/memory.d.ts +4 -0
  139. package/dist/tools/memory.d.ts.map +1 -0
  140. package/dist/tools/memory.js +64 -0
  141. package/dist/tools/memory.js.map +1 -0
  142. package/dist/tools/read.d.ts +3 -0
  143. package/dist/tools/read.d.ts.map +1 -0
  144. package/dist/tools/read.js +50 -0
  145. package/dist/tools/read.js.map +1 -0
  146. package/dist/tools/web-fetch.d.ts +3 -0
  147. package/dist/tools/web-fetch.d.ts.map +1 -0
  148. package/dist/tools/web-fetch.js +51 -0
  149. package/dist/tools/web-fetch.js.map +1 -0
  150. package/dist/tools/web-search.d.ts +3 -0
  151. package/dist/tools/web-search.d.ts.map +1 -0
  152. package/dist/tools/web-search.js +65 -0
  153. package/dist/tools/web-search.js.map +1 -0
  154. package/dist/tools/write.d.ts +3 -0
  155. package/dist/tools/write.d.ts.map +1 -0
  156. package/dist/tools/write.js +32 -0
  157. package/dist/tools/write.js.map +1 -0
  158. package/dist/transcript-logger.d.ts +23 -0
  159. package/dist/transcript-logger.d.ts.map +1 -0
  160. package/dist/transcript-logger.js +101 -0
  161. package/dist/transcript-logger.js.map +1 -0
  162. package/dist/types.d.ts +190 -0
  163. package/dist/types.d.ts.map +1 -0
  164. package/dist/types.js +14 -0
  165. package/dist/types.js.map +1 -0
  166. package/identity.example/disagreements.md +9 -0
  167. package/identity.example/preferences.md +11 -0
  168. package/identity.example/soul.md +12 -0
  169. package/identity.example/state.md +21 -0
  170. package/identity.example/user.md +14 -0
  171. package/package.json +60 -0
@@ -0,0 +1,207 @@
1
+ // CRC: crc-AgentRegistry.md | Seq: seq-agent-dispatch.md, seq-agent-poll.md
2
+ import { randomUUID } from "node:crypto";
3
+ import { statSync, openSync, readSync, closeSync } from "node:fs";
4
+ // R156: Completion markers found in Task agent JSONL output
5
+ const COMPLETION_MARKERS = ['"stop_reason":"end_turn"', '"type":"result"'];
6
+ // R156: Stable mtime threshold (ms) — file unchanged for this long is considered complete
7
+ const STABLE_THRESHOLD_MS = 10_000;
8
+ // R156: Number of bytes to read from file tail for marker detection
9
+ const TAIL_BYTES = 512;
10
+ export class AgentRegistry {
11
+ agents = new Map();
12
+ maxConcurrent;
13
+ emitFn = null;
14
+ logger;
15
+ // R155: Configurable poll interval
16
+ pollIntervalMs;
17
+ // R159: Global poll timer handle
18
+ pollTimer = null;
19
+ constructor(logger, maxConcurrent = 3, pollIntervalMs = 5000) {
20
+ this.logger = logger;
21
+ this.maxConcurrent = maxConcurrent;
22
+ this.pollIntervalMs = pollIntervalMs;
23
+ }
24
+ setEmitter(fn) {
25
+ this.emitFn = fn;
26
+ }
27
+ register(id, description, outputFile) {
28
+ const active = this.getActiveCount();
29
+ if (active >= this.maxConcurrent) {
30
+ this.logger.warn("Agent registry at capacity", { active, max: this.maxConcurrent });
31
+ return false;
32
+ }
33
+ this.agents.set(id, {
34
+ id,
35
+ description,
36
+ status: "running",
37
+ startTime: Date.now(),
38
+ outputFile,
39
+ });
40
+ this.logger.info("Agent registered", { id, description });
41
+ return true;
42
+ }
43
+ getAll() {
44
+ return Array.from(this.agents.values());
45
+ }
46
+ get(id) {
47
+ return this.agents.get(id) ?? null;
48
+ }
49
+ // R157, R162: Complete only if still running (prevents duplicate events)
50
+ complete(id, result) {
51
+ const agent = this.resolve(id);
52
+ if (!agent)
53
+ return;
54
+ if (agent.status !== "running")
55
+ return;
56
+ agent.status = "completed";
57
+ agent.result = result;
58
+ this.emit("agent_completed", id, agent.description, { result });
59
+ this.logger.info("Agent completed", { id, description: agent.description });
60
+ }
61
+ fail(id, error) {
62
+ const agent = this.resolve(id);
63
+ if (!agent)
64
+ return;
65
+ agent.status = "failed";
66
+ agent.error = error;
67
+ this.emit("agent_failed", id, agent.description, { error });
68
+ this.logger.warn("Agent failed", { id, error });
69
+ }
70
+ // R160: Cleanup removes agent and any associated polling state
71
+ cleanup(id) {
72
+ this.agents.delete(id);
73
+ }
74
+ getAvailableSlots() {
75
+ return Math.max(0, this.maxConcurrent - this.getActiveCount());
76
+ }
77
+ getActiveCount() {
78
+ let count = 0;
79
+ for (const agent of this.agents.values()) {
80
+ if (agent.status === "running")
81
+ count++;
82
+ }
83
+ return count;
84
+ }
85
+ // R159: Start global polling interval
86
+ startPolling() {
87
+ if (this.pollTimer)
88
+ return;
89
+ this.pollTimer = setInterval(() => this.pollAgents(), this.pollIntervalMs);
90
+ // Unref so the timer does not keep the process alive during shutdown
91
+ if (this.pollTimer && typeof this.pollTimer === "object" && "unref" in this.pollTimer) {
92
+ this.pollTimer.unref();
93
+ }
94
+ this.logger.info("Agent completion polling started", { intervalMs: this.pollIntervalMs });
95
+ }
96
+ // R159: Stop global polling interval
97
+ stopPolling() {
98
+ if (this.pollTimer) {
99
+ clearInterval(this.pollTimer);
100
+ this.pollTimer = null;
101
+ this.logger.info("Agent completion polling stopped");
102
+ }
103
+ }
104
+ // R154, R158: Poll all running agents with outputFiles for completion
105
+ pollAgents() {
106
+ for (const agent of this.agents.values()) {
107
+ // R158: Only poll running agents with an outputFile
108
+ if (agent.status !== "running" || !agent.outputFile)
109
+ continue;
110
+ try {
111
+ this.checkAgentFile(agent);
112
+ }
113
+ catch (err) {
114
+ // R161: Log and skip on errors
115
+ this.logger.debug("Poll check error for agent", {
116
+ id: agent.id,
117
+ error: String(err),
118
+ });
119
+ }
120
+ }
121
+ }
122
+ checkAgentFile(agent) {
123
+ // R161: statSync may throw ENOENT if file does not exist yet
124
+ let stat;
125
+ try {
126
+ stat = statSync(agent.outputFile);
127
+ }
128
+ catch {
129
+ return; // File does not exist yet — skip
130
+ }
131
+ // Skip empty files
132
+ if (stat.size === 0)
133
+ return;
134
+ // R156: Read the tail of the file
135
+ const tail = this.readTail(agent.outputFile, stat.size);
136
+ if (!tail)
137
+ return;
138
+ // R156: Check for completion markers in the tail
139
+ const hasMarker = COMPLETION_MARKERS.some((m) => tail.includes(m));
140
+ if (hasMarker) {
141
+ this.logger.info("Detected completion marker in agent output", { id: agent.id });
142
+ this.complete(agent.id, this.extractSummary(tail));
143
+ return;
144
+ }
145
+ // R156: Check for stable mtime (no writes in STABLE_THRESHOLD_MS)
146
+ const age = Date.now() - stat.mtimeMs;
147
+ if (age >= STABLE_THRESHOLD_MS) {
148
+ this.logger.info("Detected stable output file for agent", {
149
+ id: agent.id,
150
+ stableForMs: Math.round(age),
151
+ });
152
+ this.complete(agent.id, this.extractSummary(tail));
153
+ }
154
+ }
155
+ // Read the last `count` bytes of a file as a UTF-8 string
156
+ readTail(filePath, fileSize) {
157
+ const readSize = Math.min(TAIL_BYTES, fileSize);
158
+ const offset = fileSize - readSize;
159
+ const buf = Buffer.alloc(readSize);
160
+ let fd = null;
161
+ try {
162
+ fd = openSync(filePath, "r");
163
+ readSync(fd, buf, 0, readSize, offset);
164
+ return buf.toString("utf-8");
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ finally {
170
+ if (fd !== null) {
171
+ try {
172
+ closeSync(fd);
173
+ }
174
+ catch { /* ignore */ }
175
+ }
176
+ }
177
+ }
178
+ // Extract a brief summary from the file tail for the completion result
179
+ extractSummary(tail) {
180
+ // Try to find the last JSON line that looks like a result
181
+ const lines = tail.split("\n").filter((l) => l.trim().length > 0);
182
+ const lastLine = lines[lines.length - 1] ?? "";
183
+ // Truncate to a reasonable length for the event payload
184
+ if (lastLine.length > 200) {
185
+ return lastLine.slice(0, 200) + "...";
186
+ }
187
+ return lastLine || "(output file completed)";
188
+ }
189
+ resolve(id) {
190
+ const agent = this.agents.get(id);
191
+ if (!agent) {
192
+ this.logger.warn("Unknown agent", { id });
193
+ return null;
194
+ }
195
+ return agent;
196
+ }
197
+ emit(type, agentId, description, extra) {
198
+ this.emitFn?.({
199
+ id: randomUUID(),
200
+ type,
201
+ source: `agent:${agentId}`,
202
+ timestamp: Date.now(),
203
+ payload: { agentId, description, ...extra },
204
+ });
205
+ }
206
+ }
207
+ //# sourceMappingURL=agent-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-registry.js","sourceRoot":"","sources":["../src/agent-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ // CRC: crc-Backend.md | Seq: seq-startup.md
3
+ // HomarUScc backend — standalone process (no MCP stdio)
4
+ // Used by mcp-proxy.ts or as a standalone server.
5
+ import { HomarUScc } from "./homaruscc.js";
6
+ import { DashboardServer } from "./dashboard-server.js";
7
+ import { DashboardAdapter } from "./dashboard-adapter.js";
8
+ const logger = {
9
+ debug(msg, meta) {
10
+ if (process.env.HOMARUSCC_DEBUG) {
11
+ process.stderr.write(`[DEBUG] ${msg} ${meta ? JSON.stringify(meta) : ""}\n`);
12
+ }
13
+ },
14
+ info(msg, meta) {
15
+ process.stderr.write(`[INFO] ${msg} ${meta ? JSON.stringify(meta) : ""}\n`);
16
+ },
17
+ warn(msg, meta) {
18
+ process.stderr.write(`[WARN] ${msg} ${meta ? JSON.stringify(meta) : ""}\n`);
19
+ },
20
+ error(msg, meta) {
21
+ process.stderr.write(`[ERROR] ${msg} ${meta ? JSON.stringify(meta) : ""}\n`);
22
+ },
23
+ };
24
+ async function main() {
25
+ const configPath = process.env.HOMARUSCC_CONFIG ?? undefined;
26
+ const loop = new HomarUScc(logger, configPath);
27
+ await loop.start();
28
+ // Dashboard adapter (channel)
29
+ const dashboardConfig = loop.getConfig().getAll().dashboard;
30
+ let dashboardServer = null;
31
+ if (dashboardConfig?.enabled !== false) {
32
+ const dashboardAdapter = new DashboardAdapter(logger);
33
+ loop.getChannelManager().registerAdapter(dashboardAdapter);
34
+ await dashboardAdapter.connect();
35
+ dashboardAdapter.onMessage((event) => loop.emit(event));
36
+ dashboardServer = new DashboardServer(logger, dashboardConfig?.port ?? 3120, loop, dashboardAdapter);
37
+ await dashboardServer.start();
38
+ // Forward event loop notifications to dashboard WebSocket clients
39
+ loop.setNotifyFn((event) => {
40
+ dashboardServer?.broadcastEvent(event);
41
+ });
42
+ }
43
+ logger.info("HomarUScc backend running (no MCP stdio)");
44
+ // Graceful shutdown
45
+ const shutdown = async () => {
46
+ logger.info("Backend shutting down...");
47
+ if (dashboardServer)
48
+ await dashboardServer.stop();
49
+ await loop.stop();
50
+ process.exit(0);
51
+ };
52
+ process.on("SIGINT", shutdown);
53
+ process.on("SIGTERM", shutdown);
54
+ }
55
+ main().catch((err) => {
56
+ process.stderr.write(`[FATAL] ${String(err)}\n`);
57
+ process.exit(1);
58
+ });
59
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { BrowserConfig, Logger } from "./types.js";
2
+ export declare class BrowserService {
3
+ private browser;
4
+ private persistentContext;
5
+ private page;
6
+ private config;
7
+ private logger;
8
+ constructor(logger: Logger, config: BrowserConfig);
9
+ private ensureBrowser;
10
+ navigate(url: string): Promise<string>;
11
+ snapshot(): Promise<string>;
12
+ screenshot(): Promise<string>;
13
+ click(selector: string): Promise<string>;
14
+ type(selector: string, text: string): Promise<string>;
15
+ evaluate(script: string): Promise<string>;
16
+ getContent(): Promise<string>;
17
+ stop(): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=browser-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-service.d.ts","sourceRoot":"","sources":["../src/browser-service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAExD,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa;YAKnC,aAAa;IAkDrB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAOtC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAM3B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAM7B,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMxC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMrD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMzC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAW5B"}
@@ -0,0 +1,101 @@
1
+ export class BrowserService {
2
+ browser = null;
3
+ persistentContext = null;
4
+ page = null;
5
+ config;
6
+ logger;
7
+ constructor(logger, config) {
8
+ this.logger = logger;
9
+ this.config = config;
10
+ }
11
+ async ensureBrowser() {
12
+ if (this.page)
13
+ return this.page;
14
+ const { chromium } = await import("playwright");
15
+ const headless = this.config.headless ?? true;
16
+ const viewport = this.config.viewport ?? { width: 1280, height: 720 };
17
+ if (this.config.userDataDir) {
18
+ // Persistent context — reuses cookies, localStorage, sessions across launches
19
+ this.logger.info("Launching persistent browser", {
20
+ headless,
21
+ userDataDir: this.config.userDataDir,
22
+ });
23
+ const context = await chromium.launchPersistentContext(this.config.userDataDir, {
24
+ headless,
25
+ viewport,
26
+ ...(this.config.executablePath && {
27
+ executablePath: this.config.executablePath,
28
+ }),
29
+ ...(this.config.proxy && { proxy: { server: this.config.proxy } }),
30
+ });
31
+ // launchPersistentContext returns a BrowserContext, not a Browser
32
+ this.persistentContext = context;
33
+ this.page = context.pages()[0] ?? (await context.newPage());
34
+ }
35
+ else {
36
+ // Ephemeral context — clean session each time
37
+ const launchOptions = { headless };
38
+ if (this.config.executablePath) {
39
+ launchOptions.executablePath = this.config.executablePath;
40
+ }
41
+ if (this.config.proxy) {
42
+ launchOptions.proxy = { server: this.config.proxy };
43
+ }
44
+ this.logger.info("Launching browser", { headless });
45
+ this.browser = await chromium.launch(launchOptions);
46
+ const context = await this.browser.newContext({ viewport });
47
+ this.page = await context.newPage();
48
+ }
49
+ this.page.setDefaultTimeout(this.config.timeout ?? 30000);
50
+ this.logger.info("Browser ready");
51
+ return this.page;
52
+ }
53
+ async navigate(url) {
54
+ const page = await this.ensureBrowser();
55
+ await page.goto(url, { waitUntil: "domcontentloaded" });
56
+ const title = await page.title();
57
+ return `Navigated to: ${page.url()}\nTitle: ${title}`;
58
+ }
59
+ async snapshot() {
60
+ const page = await this.ensureBrowser();
61
+ const snap = await page.locator("body").ariaSnapshot();
62
+ return snap || "Empty accessibility snapshot";
63
+ }
64
+ async screenshot() {
65
+ const page = await this.ensureBrowser();
66
+ const buffer = await page.screenshot({ type: "png" });
67
+ return buffer.toString("base64");
68
+ }
69
+ async click(selector) {
70
+ const page = await this.ensureBrowser();
71
+ await page.click(selector);
72
+ return `Clicked: ${selector}`;
73
+ }
74
+ async type(selector, text) {
75
+ const page = await this.ensureBrowser();
76
+ await page.fill(selector, text);
77
+ return `Typed into: ${selector}`;
78
+ }
79
+ async evaluate(script) {
80
+ const page = await this.ensureBrowser();
81
+ const result = await page.evaluate(script);
82
+ return typeof result === "string" ? result : JSON.stringify(result, null, 2);
83
+ }
84
+ async getContent() {
85
+ const page = await this.ensureBrowser();
86
+ return await page.evaluate(() => document.body.innerText);
87
+ }
88
+ async stop() {
89
+ this.logger.info("Closing browser");
90
+ if (this.persistentContext) {
91
+ await this.persistentContext.close();
92
+ this.persistentContext = null;
93
+ }
94
+ else if (this.browser) {
95
+ await this.browser.close();
96
+ this.browser = null;
97
+ }
98
+ this.page = null;
99
+ }
100
+ }
101
+ //# sourceMappingURL=browser-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-service.js","sourceRoot":"","sources":["../src/browser-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Event, MessagePayload, OutboundMessage, DmPolicy, GroupPolicy, HealthStatus, Logger } from "./types.js";
2
+ export type AdapterState = "disconnected" | "connecting" | "connected" | "error";
3
+ export declare abstract class ChannelAdapter {
4
+ readonly name: string;
5
+ protected state: AdapterState;
6
+ protected dmPolicy: DmPolicy;
7
+ protected groupPolicy: GroupPolicy;
8
+ protected logger: Logger;
9
+ private messageHandler;
10
+ constructor(name: string, logger: Logger, dmPolicy?: DmPolicy, groupPolicy?: GroupPolicy);
11
+ getState(): AdapterState;
12
+ abstract connect(): Promise<void>;
13
+ abstract disconnect(): Promise<void>;
14
+ abstract send(target: string, message: OutboundMessage): Promise<void>;
15
+ abstract health(): HealthStatus;
16
+ onMessage(handler: (event: Event) => void): void;
17
+ protected normalizeInbound(payload: MessagePayload, target?: string): Event;
18
+ protected checkAccess(payload: MessagePayload): boolean;
19
+ protected deliver(payload: MessagePayload): void;
20
+ protected deliverWithTarget(payload: MessagePayload, target: string): void;
21
+ }
22
+ //# sourceMappingURL=channel-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-adapter.d.ts","sourceRoot":"","sources":["../src/channel-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EACpF,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAEjF,8BAAsB,cAAc;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,KAAK,EAAE,YAAY,CAAkB;IAC/C,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IACnC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,cAAc,CAAyC;gBAEnD,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAiB,EAAE,WAAW,GAAE,WAAgC;IAOpH,QAAQ,IAAI,YAAY;IAIxB,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IACtE,QAAQ,CAAC,MAAM,IAAI,YAAY;IAE/B,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAIhD,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK;IAW3E,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO;IAUvD,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAShD,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAQ3E"}
@@ -0,0 +1,62 @@
1
+ // CRC: crc-ChannelAdapter.md | Seq: seq-event-flow.md
2
+ // Channel adapter base — from HomarUS (removed CLIChannelAdapter, not needed for MCP)
3
+ import { v4 as uuid } from "uuid";
4
+ export class ChannelAdapter {
5
+ name;
6
+ state = "disconnected";
7
+ dmPolicy;
8
+ groupPolicy;
9
+ logger;
10
+ messageHandler = null;
11
+ constructor(name, logger, dmPolicy = "open", groupPolicy = "mention_required") {
12
+ this.name = name;
13
+ this.logger = logger;
14
+ this.dmPolicy = dmPolicy;
15
+ this.groupPolicy = groupPolicy;
16
+ }
17
+ getState() {
18
+ return this.state;
19
+ }
20
+ onMessage(handler) {
21
+ this.messageHandler = handler;
22
+ }
23
+ normalizeInbound(payload, target) {
24
+ const source = target ? `channel:${this.name}:${target}` : `channel:${this.name}`;
25
+ return {
26
+ id: uuid(),
27
+ type: "message",
28
+ source,
29
+ timestamp: Date.now(),
30
+ payload,
31
+ };
32
+ }
33
+ checkAccess(payload) {
34
+ if (payload.isGroup) {
35
+ if (this.groupPolicy === "disabled")
36
+ return false;
37
+ if (this.groupPolicy === "mention_required" && !payload.isMention)
38
+ return false;
39
+ return true;
40
+ }
41
+ if (this.dmPolicy === "disabled")
42
+ return false;
43
+ return true;
44
+ }
45
+ deliver(payload) {
46
+ if (!this.checkAccess(payload)) {
47
+ this.logger.debug("Message rejected by policy", { channel: this.name, from: payload.from });
48
+ return;
49
+ }
50
+ const event = this.normalizeInbound(payload);
51
+ this.messageHandler?.(event);
52
+ }
53
+ deliverWithTarget(payload, target) {
54
+ if (!this.checkAccess(payload)) {
55
+ this.logger.debug("Message rejected by policy", { channel: this.name, from: payload.from });
56
+ return;
57
+ }
58
+ const event = this.normalizeInbound(payload, target);
59
+ this.messageHandler?.(event);
60
+ }
61
+ }
62
+ //# sourceMappingURL=channel-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-adapter.js","sourceRoot":"","sources":["../src/channel-adapter.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,sFAAsF;AACtF,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAOlC,MAAM,OAAgB,cAAc;IACzB,IAAI,CAAS;IACZ,KAAK,GAAiB,cAAc,CAAC;IACrC,QAAQ,CAAW;IACnB,WAAW,CAAc;IACzB,MAAM,CAAS;IACjB,cAAc,GAAoC,IAAI,CAAC;IAE/D,YAAY,IAAY,EAAE,MAAc,EAAE,WAAqB,MAAM,EAAE,cAA2B,kBAAkB;QAClH,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAOD,SAAS,CAAC,OAA+B;QACvC,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAChC,CAAC;IAES,gBAAgB,CAAC,OAAuB,EAAE,MAAe;QACjE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC;QAClF,OAAO;YACL,EAAE,EAAE,IAAI,EAAE;YACV,IAAI,EAAE,SAAS;YACf,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,OAAO;SACR,CAAC;IACJ,CAAC;IAES,WAAW,CAAC,OAAuB;QAC3C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,IAAI,CAAC,WAAW,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAC;YAClD,IAAI,IAAI,CAAC,WAAW,KAAK,kBAAkB,IAAI,CAAC,OAAO,CAAC,SAAS;gBAAE,OAAO,KAAK,CAAC;YAChF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAES,OAAO,CAAC,OAAuB;QACvC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAES,iBAAiB,CAAC,OAAuB,EAAE,MAAc;QACjE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACrD,IAAI,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type { Event, OutboundMessage, ChannelConfig, HealthStatus, Logger } from "./types.js";
2
+ import { ChannelAdapter } from "./channel-adapter.js";
3
+ export declare class ChannelManager {
4
+ private adapters;
5
+ private logger;
6
+ private eventHandler;
7
+ constructor(logger: Logger);
8
+ setEventHandler(fn: (event: Event) => void): void;
9
+ loadAdapters(channels: Record<string, ChannelConfig>): void;
10
+ registerAdapter(adapter: ChannelAdapter): void;
11
+ connectAll(): Promise<void>;
12
+ disconnectAll(): Promise<void>;
13
+ send(channel: string, target: string, message: OutboundMessage): Promise<void>;
14
+ getAdapter(name: string): ChannelAdapter | undefined;
15
+ getConnected(): ChannelAdapter[];
16
+ healthCheck(): Record<string, HealthStatus>;
17
+ }
18
+ //# sourceMappingURL=channel-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-manager.d.ts","sourceRoot":"","sources":["../src/channel-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAyC;gBAEjD,MAAM,EAAE,MAAM;IAI1B,eAAe,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;IAIjD,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,IAAI;IAkB3D,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpF,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIpD,YAAY,IAAI,cAAc,EAAE;IAIhC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;CAO5C"}
@@ -0,0 +1,73 @@
1
+ import { TelegramChannelAdapter } from "./telegram-adapter.js";
2
+ export class ChannelManager {
3
+ adapters = new Map();
4
+ logger;
5
+ eventHandler = null;
6
+ constructor(logger) {
7
+ this.logger = logger;
8
+ }
9
+ setEventHandler(fn) {
10
+ this.eventHandler = fn;
11
+ }
12
+ loadAdapters(channels) {
13
+ for (const [name, config] of Object.entries(channels)) {
14
+ let adapter;
15
+ switch (name) {
16
+ case "telegram":
17
+ adapter = TelegramChannelAdapter.fromChannelConfig(config, this.logger);
18
+ break;
19
+ default:
20
+ this.logger.warn("Unknown channel type, skipping", { name });
21
+ continue;
22
+ }
23
+ this.adapters.set(name, adapter);
24
+ }
25
+ }
26
+ // Register an externally-created adapter (e.g., dashboard adapter)
27
+ registerAdapter(adapter) {
28
+ this.adapters.set(adapter.name, adapter);
29
+ }
30
+ async connectAll() {
31
+ for (const [name, adapter] of this.adapters) {
32
+ try {
33
+ adapter.onMessage((event) => this.eventHandler?.(event));
34
+ await adapter.connect();
35
+ }
36
+ catch (err) {
37
+ this.logger.error("Failed to connect channel", { name, error: String(err) });
38
+ }
39
+ }
40
+ this.logger.info("Channels connected", { count: this.adapters.size });
41
+ }
42
+ async disconnectAll() {
43
+ for (const [name, adapter] of this.adapters) {
44
+ try {
45
+ await adapter.disconnect();
46
+ }
47
+ catch (err) {
48
+ this.logger.warn("Error disconnecting channel", { name, error: String(err) });
49
+ }
50
+ }
51
+ }
52
+ async send(channel, target, message) {
53
+ const adapter = this.adapters.get(channel);
54
+ if (!adapter) {
55
+ throw new Error(`Unknown channel: ${channel}`);
56
+ }
57
+ await adapter.send(target, message);
58
+ }
59
+ getAdapter(name) {
60
+ return this.adapters.get(name);
61
+ }
62
+ getConnected() {
63
+ return [...this.adapters.values()].filter((a) => a.getState() === "connected");
64
+ }
65
+ healthCheck() {
66
+ const results = {};
67
+ for (const [name, adapter] of this.adapters) {
68
+ results[name] = adapter.health();
69
+ }
70
+ return results;
71
+ }
72
+ }
73
+ //# sourceMappingURL=channel-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-manager.js","sourceRoot":"","sources":["../src/channel-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Logger } from "./types.js";
2
+ import type { HomarUScc } from "./homaruscc.js";
3
+ export declare class CompactionManager {
4
+ private flushedThisCycle;
5
+ private lastFlushTimestamp;
6
+ private compactedSinceLastWake;
7
+ private logger;
8
+ private loop;
9
+ constructor(loop: HomarUScc, logger: Logger);
10
+ handlePreCompact(): string;
11
+ handlePostCompact(): string;
12
+ /**
13
+ * Returns true if compaction occurred since the last /api/wait delivery.
14
+ * Consuming this resets the flag — the next call returns false until
15
+ * another compaction happens.
16
+ */
17
+ consumeCompactionFlag(): boolean;
18
+ getFlushState(): {
19
+ flushedThisCycle: boolean;
20
+ lastFlushTimestamp: number;
21
+ };
22
+ }
23
+ //# sourceMappingURL=compaction-manager.d.ts.map