homaruscc 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +148 -15
  2. package/bin/event-loop +7 -1
  3. package/bin/nuke-claude +80 -0
  4. package/bin/restart-claude +58 -0
  5. package/bin/setup +104 -0
  6. package/dashboard/dist/assets/index-6VG2qhXN.js +55 -0
  7. package/dashboard/dist/index.html +1 -1
  8. package/dist/__tests__/app-data-store.test.d.ts +2 -0
  9. package/dist/__tests__/app-data-store.test.d.ts.map +1 -0
  10. package/dist/__tests__/app-data-store.test.js +134 -0
  11. package/dist/__tests__/app-data-store.test.js.map +1 -0
  12. package/dist/__tests__/app-registry.test.d.ts +2 -0
  13. package/dist/__tests__/app-registry.test.d.ts.map +1 -0
  14. package/dist/__tests__/app-registry.test.js +109 -0
  15. package/dist/__tests__/app-registry.test.js.map +1 -0
  16. package/dist/__tests__/claude-code-registrar.test.d.ts +2 -0
  17. package/dist/__tests__/claude-code-registrar.test.d.ts.map +1 -0
  18. package/dist/__tests__/claude-code-registrar.test.js +67 -0
  19. package/dist/__tests__/claude-code-registrar.test.js.map +1 -0
  20. package/dist/__tests__/scaffolder.test.d.ts +2 -0
  21. package/dist/__tests__/scaffolder.test.d.ts.map +1 -0
  22. package/dist/__tests__/scaffolder.test.js +93 -0
  23. package/dist/__tests__/scaffolder.test.js.map +1 -0
  24. package/dist/app-data-store.d.ts +17 -0
  25. package/dist/app-data-store.d.ts.map +1 -0
  26. package/dist/app-data-store.js +78 -0
  27. package/dist/app-data-store.js.map +1 -0
  28. package/dist/app-registry.d.ts +25 -0
  29. package/dist/app-registry.d.ts.map +1 -0
  30. package/dist/app-registry.js +77 -0
  31. package/dist/app-registry.js.map +1 -0
  32. package/dist/backend.js +18 -0
  33. package/dist/backend.js.map +1 -1
  34. package/dist/claude-code-registrar.d.ts +10 -0
  35. package/dist/claude-code-registrar.d.ts.map +1 -0
  36. package/dist/claude-code-registrar.js +71 -0
  37. package/dist/claude-code-registrar.js.map +1 -0
  38. package/dist/cli.d.ts +3 -0
  39. package/dist/cli.d.ts.map +1 -0
  40. package/dist/cli.js +28 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/compaction-manager.d.ts +29 -0
  43. package/dist/compaction-manager.d.ts.map +1 -1
  44. package/dist/compaction-manager.js +123 -7
  45. package/dist/compaction-manager.js.map +1 -1
  46. package/dist/dashboard/assets/index-CeGuwmXB.js +55 -0
  47. package/dist/dashboard/favicon.ico +0 -0
  48. package/dist/dashboard/favicon.png +0 -0
  49. package/dist/dashboard/index.html +15 -0
  50. package/dist/dashboard-server.d.ts +16 -0
  51. package/dist/dashboard-server.d.ts.map +1 -1
  52. package/dist/dashboard-server.js +675 -44
  53. package/dist/dashboard-server.js.map +1 -1
  54. package/dist/docs-index.d.ts +50 -0
  55. package/dist/docs-index.d.ts.map +1 -0
  56. package/dist/docs-index.js +357 -0
  57. package/dist/docs-index.js.map +1 -0
  58. package/dist/fact-extractor.d.ts +45 -0
  59. package/dist/fact-extractor.d.ts.map +1 -0
  60. package/dist/fact-extractor.js +165 -0
  61. package/dist/fact-extractor.js.map +1 -0
  62. package/dist/homaruscc.d.ts +14 -0
  63. package/dist/homaruscc.d.ts.map +1 -1
  64. package/dist/homaruscc.js +142 -2
  65. package/dist/homaruscc.js.map +1 -1
  66. package/dist/mcp-tools.d.ts.map +1 -1
  67. package/dist/mcp-tools.js +907 -0
  68. package/dist/mcp-tools.js.map +1 -1
  69. package/dist/memory-index.js +1 -1
  70. package/dist/memory-index.js.map +1 -1
  71. package/dist/plugin-loader.d.ts +41 -0
  72. package/dist/plugin-loader.d.ts.map +1 -0
  73. package/dist/plugin-loader.js +122 -0
  74. package/dist/plugin-loader.js.map +1 -0
  75. package/dist/plugins/needoh-tracker/amazon-check.d.ts +21 -0
  76. package/dist/plugins/needoh-tracker/amazon-check.d.ts.map +1 -0
  77. package/dist/plugins/needoh-tracker/amazon-check.js +130 -0
  78. package/dist/plugins/needoh-tracker/amazon-check.js.map +1 -0
  79. package/dist/plugins/needoh-tracker/index.d.ts +104 -0
  80. package/dist/plugins/needoh-tracker/index.d.ts.map +1 -0
  81. package/dist/plugins/needoh-tracker/index.js +448 -0
  82. package/dist/plugins/needoh-tracker/index.js.map +1 -0
  83. package/dist/plugins/needoh-tracker/store.d.ts +95 -0
  84. package/dist/plugins/needoh-tracker/store.d.ts.map +1 -0
  85. package/dist/plugins/needoh-tracker/store.js +267 -0
  86. package/dist/plugins/needoh-tracker/store.js.map +1 -0
  87. package/dist/plugins/needoh-tracker/target-api.d.ts +26 -0
  88. package/dist/plugins/needoh-tracker/target-api.d.ts.map +1 -0
  89. package/dist/plugins/needoh-tracker/target-api.js +120 -0
  90. package/dist/plugins/needoh-tracker/target-api.js.map +1 -0
  91. package/dist/plugins/record-collection/identifier.d.ts +58 -0
  92. package/dist/plugins/record-collection/identifier.d.ts.map +1 -0
  93. package/dist/plugins/record-collection/identifier.js +384 -0
  94. package/dist/plugins/record-collection/identifier.js.map +1 -0
  95. package/dist/plugins/record-collection/index.d.ts +399 -0
  96. package/dist/plugins/record-collection/index.d.ts.map +1 -0
  97. package/dist/plugins/record-collection/index.js +701 -0
  98. package/dist/plugins/record-collection/index.js.map +1 -0
  99. package/dist/plugins/record-collection/store.d.ts +83 -0
  100. package/dist/plugins/record-collection/store.d.ts.map +1 -0
  101. package/dist/plugins/record-collection/store.js +215 -0
  102. package/dist/plugins/record-collection/store.js.map +1 -0
  103. package/dist/record-identifier.d.ts +32 -0
  104. package/dist/record-identifier.d.ts.map +1 -0
  105. package/dist/record-identifier.js +199 -0
  106. package/dist/record-identifier.js.map +1 -0
  107. package/dist/record-store.d.ts +66 -0
  108. package/dist/record-store.d.ts.map +1 -0
  109. package/dist/record-store.js +185 -0
  110. package/dist/record-store.js.map +1 -0
  111. package/dist/scaffolder.d.ts +16 -0
  112. package/dist/scaffolder.d.ts.map +1 -0
  113. package/dist/scaffolder.js +154 -0
  114. package/dist/scaffolder.js.map +1 -0
  115. package/dist/sensor-bridge.d.ts +26 -0
  116. package/dist/sensor-bridge.d.ts.map +1 -0
  117. package/dist/sensor-bridge.js +94 -0
  118. package/dist/sensor-bridge.js.map +1 -0
  119. package/dist/session-checkpoint.d.ts +3 -0
  120. package/dist/session-checkpoint.d.ts.map +1 -1
  121. package/dist/session-checkpoint.js +24 -0
  122. package/dist/session-checkpoint.js.map +1 -1
  123. package/dist/session-extractor.d.ts +36 -0
  124. package/dist/session-extractor.d.ts.map +1 -0
  125. package/dist/session-extractor.js +290 -0
  126. package/dist/session-extractor.js.map +1 -0
  127. package/dist/spaces-manager.d.ts +115 -0
  128. package/dist/spaces-manager.d.ts.map +1 -0
  129. package/dist/spaces-manager.js +585 -0
  130. package/dist/spaces-manager.js.map +1 -0
  131. package/dist/telegram-adapter.d.ts +10 -0
  132. package/dist/telegram-adapter.d.ts.map +1 -1
  133. package/dist/telegram-adapter.js +173 -1
  134. package/dist/telegram-adapter.js.map +1 -1
  135. package/dist/telegram-command-handler.d.ts +27 -0
  136. package/dist/telegram-command-handler.d.ts.map +1 -0
  137. package/dist/telegram-command-handler.js +102 -0
  138. package/dist/telegram-command-handler.js.map +1 -0
  139. package/dist/timer-service.d.ts +7 -0
  140. package/dist/timer-service.d.ts.map +1 -1
  141. package/dist/timer-service.js +37 -1
  142. package/dist/timer-service.js.map +1 -1
  143. package/dist/tools/docs.d.ts +4 -0
  144. package/dist/tools/docs.d.ts.map +1 -0
  145. package/dist/tools/docs.js +114 -0
  146. package/dist/tools/docs.js.map +1 -0
  147. package/dist/tools/index.d.ts +2 -1
  148. package/dist/tools/index.d.ts.map +1 -1
  149. package/dist/tools/index.js +11 -1
  150. package/dist/tools/index.js.map +1 -1
  151. package/dist/transcript-logger.d.ts +10 -0
  152. package/dist/transcript-logger.d.ts.map +1 -1
  153. package/dist/transcript-logger.js +4 -0
  154. package/dist/transcript-logger.js.map +1 -1
  155. package/dist/types.d.ts +29 -0
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/types.js.map +1 -1
  158. package/dist/wizard.d.ts +24 -0
  159. package/dist/wizard.d.ts.map +1 -0
  160. package/dist/wizard.js +146 -0
  161. package/dist/wizard.js.map +1 -0
  162. package/package.json +8 -2
  163. package/dashboard/dist/assets/index-Xu4GUpcF.js +0 -49
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  **An MCP server that gives Claude Code a body** — messaging, memory, identity, timers, browser automation, and tools. Claude Code is the brain. HomarUScc is the nervous system.
4
4
 
5
+ [kcdjmaxx.com/homaruscc](https://kcdjmaxx.com/homaruscc/)
6
+
5
7
  Most MCP servers add capabilities. HomarUScc adds _continuity_. It gives the agent persistent identity (who it is across sessions), evolving memory (what it's learned), and zero-token idle (it costs nothing when nobody's talking to it). The agent wakes on events, reasons, responds, reflects, and goes back to sleep.
6
8
 
7
9
  The result is an agent that remembers yesterday's conversation, carries forward its own preferences and opinions, writes a daily journal, dreams overnight, and can modify its own personality file as it develops. Not a chatbot that resets every session — a persistent presence that grows over time.
@@ -24,6 +26,7 @@ Claude Code <-> MCP (stdio) <-> Proxy (mcp-proxy.ts)
24
26
  +-- Identity manager (soul.md / user.md / state.md + journal)
25
27
  +-- Session checkpoint (compaction resilience)
26
28
  +-- Agent registry (background task dispatch)
29
+ +-- Plugin loader (backend plugins from dist/plugins/)
27
30
  +-- Skill plugins (hot-loadable)
28
31
  +-- Tool registry (bash, fs, git, web, memory)
29
32
  ```
@@ -155,6 +158,7 @@ Restart Claude Code. HomarUScc's tools will appear automatically. The proxy auto
155
158
  | `telegram_send` | Send a message to a Telegram chat |
156
159
  | `telegram_read` | Read recent incoming messages |
157
160
  | `telegram_typing` | Send a typing indicator |
161
+ | `telegram_react` | React to a message with an emoji |
158
162
  | `memory_search` | Hybrid vector + full-text search over stored content |
159
163
  | `memory_store` | Store and index content for later retrieval |
160
164
  | `timer_schedule` | Schedule cron, interval, or one-shot timers |
@@ -170,6 +174,9 @@ Restart Claude Code. HomarUScc's tools will appear automatically. The proxy auto
170
174
  | `browser_type` | Type into an input by CSS selector |
171
175
  | `browser_evaluate` | Execute JavaScript in the page |
172
176
  | `browser_content` | Get page text content |
177
+ | `crm_search` | Fuzzy CRM contact search with Levenshtein matching |
178
+ | `calendar_today` | Fetch today's calendar events from Zoho Calendar |
179
+ | `session_extract` | Analyze Claude Code transcripts for insights and patterns |
173
180
  | `run_tool` | Execute any registered tool (bash, read, write, edit, glob, grep, git, web) |
174
181
 
175
182
  ## MCP Resources
@@ -190,19 +197,66 @@ When enabled, the dashboard runs on `http://localhost:3120` with:
190
197
  - Real-time event log via WebSocket
191
198
  - System status panel
192
199
  - Memory search browser
200
+ - CRM (People) — markdown-based contact manager with search, tags, connections, and linked document viewer
201
+ - Kanban — task board synced with the agent's task system
193
202
 
194
203
  The dashboard is responsive — on mobile devices the sidebar collapses into a hamburger menu. Accessible remotely over Tailscale at `http://<your-tailscale-ip>:3120`.
195
204
 
196
- ### Apps Platform (planned)
205
+ ### Plugin System
206
+
207
+ HomarUScc supports two kinds of extensibility:
208
+
209
+ **Simple apps** — lightweight data apps with JSON storage and optional HTML UI. Live at `~/.homaruscc/apps/{slug}/` with a `manifest.json`, optional `index.html`, and `data.json`. Hooks (`read`, `write`, `describe`) are exposed via the `app_invoke` MCP tool.
210
+
211
+ **Backend plugins** — full-featured plugins with their own database, Express routes, and MCP tools. Plugin source lives in `src/plugins/<slug>/` (gitignored, per-user) and compiles with the project to `dist/plugins/<slug>/`. At startup, the plugin loader discovers compiled plugins, initializes them with a data directory, and mounts their routes and tools.
212
+
213
+ ```
214
+ ~/.homaruscc/apps/<slug>/
215
+ ├── manifest.json # { "type": "plugin", "name": "...", ... }
216
+ ├── collection.sqlite # Plugin's own database (example)
217
+ └── ... # Plugin data files
218
+
219
+ src/plugins/<slug>/ # Source (gitignored, compiles to dist/plugins/)
220
+ ├── index.ts # Exports: init(), routes(), tools(), shutdown()
221
+ ├── store.ts # Plugin's data layer
222
+ └── ...
223
+
224
+ dashboard/src/plugins/ # Frontend components (gitignored)
225
+ └── <slug>.tsx # Auto-discovered via import.meta.glob
226
+ ```
227
+
228
+ Plugin backend interface:
229
+ ```typescript
230
+ export function init(dataDir: string): void; // Called at startup
231
+ export function routes?(router: Router): void; // Express routes mounted at /api/plugins/<slug>/
232
+ export function tools?(): PluginToolDef[]; // MCP tools registered alongside core tools
233
+ export function shutdown?(): void; // Cleanup on stop
234
+ ```
197
235
 
198
- The dashboard supports a pluggable apps system. The agent can build mini web apps on request (budget trackers, reading lists, dashboards) that live inside the dashboard UI:
236
+ Plugin frontend components register themselves using `registerSkill()` with a `surface` field that controls where they appear:
237
+
238
+ ```typescript
239
+ import { registerSkill } from "../skills-registry";
240
+ import MyPluginView from "./my-plugin-view";
241
+
242
+ registerSkill({
243
+ id: "my-plugin",
244
+ name: "My Plugin",
245
+ icon: "#",
246
+ surface: "sidebar", // "sidebar" | "apps" | "headless"
247
+ order: 100,
248
+ core: false,
249
+ component: MyPluginView,
250
+ });
251
+ ```
199
252
 
200
- - Apps live at `~/.homaruscc/apps/{slug}/` with a manifest, React component, and JSON data store
201
- - Each app declares hooks (`read`, `write`, `describe`) exposed via a single `app_invoke` MCP tool
202
- - The agent can query and update app state through hooks "what's on my reading list?" triggers `app_invoke(slug=reading-list, hook=describe)`
203
- - Apps are created by the agent via filesystem tools and auto-discovered on manifest scan
253
+ | Surface | Where it renders | Required fields |
254
+ |---------|-----------------|-----------------|
255
+ | `sidebar` | Own tab in the sidebar (like Chat, Events, Records) | `component` |
256
+ | `apps` | Card in the Apps grid panel | `url`, `description` |
257
+ | `headless` | No UI — tools and timers only | `tools`, `timers` |
204
258
 
205
- See `specs/apps-platform.md` and `design/crc-App*.md` for the full design.
259
+ Plugins are personal — they don't ship with the repo. When someone clones HomarUScc, they get a clean core. The agent builds plugins on request and they live entirely in user-space.
206
260
 
207
261
  ### Dashboard Development
208
262
 
@@ -214,14 +268,19 @@ npm run dev # Dev server on :3121, proxies API to :3120
214
268
 
215
269
  ## Runtime Directories
216
270
 
217
- HomarUScc creates runtime data that's gitignored and stays local:
271
+ HomarUScc creates runtime data that's gitignored and stays local. All user data lives under `local/` (one gitignore line):
218
272
 
219
273
  | Directory | Purpose |
220
274
  |-----------|---------|
221
- | `user/context/` | Facts the assistant learns about you |
222
- | `user/corrections/` | Corrections you've made (so it doesn't repeat mistakes) |
223
- | `user/preferences/` | Your stated preferences |
224
- | `system/` | System-level learned knowledge |
275
+ | `local/user/context/` | Facts the assistant learns about you |
276
+ | `local/user/corrections/` | Corrections you've made (so it doesn't repeat mistakes) |
277
+ | `local/user/preferences/` | Your stated preferences |
278
+ | `local/system/` | System-level learned knowledge |
279
+ | `local/crm/` | CRM contact files (markdown + YAML frontmatter, see `crm.example/`) |
280
+ | `local/dreams/` | Dream cycle output (nightly, stored at 0.5x weight) |
281
+ | `local/research/` | Research notes stored by memory system |
282
+ | `local/docs/` | Private documents (outreach drafts, session notes, etc.) |
283
+ | `~/.homaruscc/apps/` | App and plugin data directories (per-user) |
225
284
  | `~/.homaruscc/memory/` | Vector + FTS search index (SQLite) |
226
285
  | `~/.homaruscc/identity/` | Agent identity files (soul, user, state, preferences, disagreements) |
227
286
  | `~/.homaruscc/journal/` | Daily reflection journal entries (indexed by memory system) |
@@ -248,7 +307,7 @@ The `PreCompact` hook sets a flag on the backend. The next `/api/wait` response
248
307
 
249
308
  Claude Code compresses conversation history when the context window fills up. Without mitigation, the post-compaction agent loses track of what it was doing. HomarUScc handles this with two mechanisms:
250
309
 
251
- **Session checkpoint** — Before compaction, the agent saves its current task context (topic, recent decisions, in-progress work, modified files) to `~/.homaruscc/checkpoint.json` via `POST /api/checkpoint`. After compaction, the post-compact context injection includes this checkpoint so the new instance knows exactly where things left off. The checkpoint is cleared at session end.
310
+ **Session checkpoint** — Before compaction, the agent saves its current task context (topic, recent decisions, in-progress work, modified files, session texture, highlight snippets) to `~/.homaruscc/checkpoint.json` via `POST /api/checkpoint`. After compaction, the post-compact context injection includes this checkpoint so the new instance knows exactly where things left off. The checkpoint is cleared at session end. The `texture` field captures the session's conversational dynamic (e.g., "rapid shipping, playful, terse messages") and `highlights` preserves 2-3 raw exchange snippets that exemplify the vibe — restoring not just _what_ was happening but _how_ it felt.
252
311
 
253
312
  **Delivery watermark** — The server tracks the timestamp of the last event delivered to Claude Code. After compaction, the event loop resumes from the watermark instead of replaying old events. This prevents the "bad loop" problem where a post-compaction agent re-handles messages it already responded to.
254
313
 
@@ -271,6 +330,42 @@ Both are wired into the `PreCompact` Claude Code hook that calls `/api/pre-compa
271
330
  }
272
331
  ```
273
332
 
333
+ ### Hook Configuration
334
+
335
+ HomarUScc hooks into Claude Code's compaction lifecycle to preserve context. Add the following to your project's `.claude/settings.local.json`:
336
+
337
+ ```json
338
+ {
339
+ "hooks": {
340
+ "PreCompact": [
341
+ {
342
+ "hooks": [
343
+ {
344
+ "type": "command",
345
+ "command": "curl -s http://127.0.0.1:3120/api/pre-compact"
346
+ }
347
+ ]
348
+ }
349
+ ],
350
+ "SessionStart": [
351
+ {
352
+ "hooks": [
353
+ {
354
+ "type": "command",
355
+ "command": "curl -s http://127.0.0.1:3120/api/post-compact"
356
+ }
357
+ ]
358
+ }
359
+ ]
360
+ }
361
+ }
362
+ ```
363
+
364
+ - **PreCompact**: Flushes transcripts, triggers checkpoint save, and returns a prompt reminding Claude to persist important context before compaction
365
+ - **SessionStart**: Returns post-compaction context including checkpoint data, active timers, and identity refresh
366
+
367
+ These hooks are optional but strongly recommended for long sessions. Without them, the agent loses task context across compaction boundaries.
368
+
274
369
  ## Agent Dispatch
275
370
 
276
371
  For tasks that would consume significant context (research, multi-file processing, mini-spec workflows), the agent can dispatch work to background agents instead of doing it inline:
@@ -285,6 +380,20 @@ Max concurrent agents is configurable via `agents.maxConcurrent` in config (defa
285
380
 
286
381
  **Completion detection:** Agents signal completion by calling `POST /api/agents/:id/complete` with a result summary. This emits an `agent_completed` event that wakes the main event loop. A 30-minute timeout fallback catches agents that fail to call back. No polling needed — results arrive as events.
287
382
 
383
+ ## Passive Knowledge Capture
384
+
385
+ HomarUScc continuously extracts structured knowledge from conversations without explicit user action.
386
+
387
+ **FactExtractor** — Batches conversation turns and sends them to Claude Haiku for extraction of preferences, corrections, patterns, facts, and decisions. Results are stored in the memory index under structured key prefixes (`local/user/preferences/`, `local/user/corrections/`, etc.). Runs in the background during normal conversation.
388
+
389
+ **SessionExtractor** — Analyzes Claude Code JSONL transcripts (the raw session logs) to extract architecture decisions, debugging solutions, and workflow patterns. Designed to feed the daily reflection timer with deeper insights than real-time extraction can capture.
390
+
391
+ Both systems complement the agent's explicit reflection cycle (journal entries, prediction error logging, dream cycles) by capturing knowledge that would otherwise be lost between sessions.
392
+
393
+ ## Compaction Auto-Restart
394
+
395
+ After a configurable number of context compactions (default 8), the event loop signals that a full restart is needed. This prevents degraded performance from accumulated compaction artifacts. The `/nuke` Telegram command provides a manual escape hatch that kills all Claude processes and starts a fresh session.
396
+
288
397
  ## Architecture
289
398
 
290
399
  HomarUScc is a fork of HomarUS with the agent loop, model router, and HTTP API removed. Claude Code handles all reasoning; HomarUScc just provides the I/O layer.
@@ -300,22 +409,46 @@ Key source files:
300
409
  | `src/mcp-tools.ts` | MCP tool definitions |
301
410
  | `src/mcp-resources.ts` | MCP resource definitions |
302
411
  | `src/config.ts` | Config loader with env var resolution and hot-reload |
303
- | `src/telegram-adapter.ts` | Telegram long-polling adapter (text, photos, documents) |
412
+ | `src/telegram-adapter.ts` | Telegram long-polling adapter (text, photos, documents, reactions, edits) |
304
413
  | `src/dashboard-server.ts` | Express + WebSocket dashboard server |
305
414
  | `src/dashboard-adapter.ts` | Dashboard channel adapter |
306
415
  | `src/memory-index.ts` | SQLite + sqlite-vec hybrid search with dream-aware scoring |
307
- | `src/compaction-manager.ts` | Auto-flush memory before context compaction |
416
+ | `src/fact-extractor.ts` | Passive fact extraction from conversations via Haiku |
417
+ | `src/session-extractor.ts` | Session transcript analysis for architecture insights |
418
+ | `src/telegram-command-handler.ts` | Telegram slash commands (/ping, /status, /restart, /nuke) |
419
+ | `src/compaction-manager.ts` | Auto-flush memory before context compaction, auto-restart after threshold |
308
420
  | `src/session-checkpoint.ts` | Save/restore task context across compaction |
309
421
  | `src/agent-registry.ts` | Track background agents with callback completion and timeout fallback |
310
422
  | `src/transcript-logger.ts` | Session transcript capture and indexing |
311
423
  | `src/identity-manager.ts` | Identity loader (soul.md, user.md, state.md) |
312
424
  | `src/timer-service.ts` | Cron, interval, and one-shot timers |
313
425
  | `src/browser-service.ts` | Playwright browser automation |
426
+ | `src/plugin-loader.ts` | Backend plugin discovery, loading, and mounting |
314
427
  | `src/skill-manager.ts` | Hot-loadable skill plugins |
315
428
  | `src/tool-registry.ts` | Tool registration and policy enforcement |
316
429
  | `src/tools/` | Built-in tools (bash, fs, git, web, memory) |
317
430
  | `dashboard/` | React + Vite SPA |
318
431
 
432
+ ## Publishing to npm
433
+
434
+ ```bash
435
+ # 1. Bump version in package.json
436
+ npm version patch # or minor/major
437
+
438
+ # 2. Build everything
439
+ npm run build
440
+ cd dashboard && npm run build && cd ..
441
+
442
+ # 3. Login (if not already)
443
+ npm login
444
+
445
+ # 4. Publish (dry run first)
446
+ npm publish --dry-run
447
+ npm publish
448
+ ```
449
+
450
+ The `files` array in package.json controls what gets published: `dist/`, `dashboard/dist/`, `bin/`, `identity.example/`, config/env examples, README, and LICENSE. Source files, specs, design docs, and tests are excluded via `.npmignore`.
451
+
319
452
  ## License
320
453
 
321
454
  MIT - see [LICENSE](LICENSE)
package/bin/event-loop CHANGED
@@ -49,7 +49,13 @@ while true; do
49
49
  cat /tmp/homaruscc-wait-response.json
50
50
  echo ""
51
51
  echo "---"
52
- echo "Event loop paused. Handle the events above, then restart: bash \"\$PWD/bin/event-loop\""
52
+ # Check if backend is signaling auto-restart due to high compaction count
53
+ if command -v jq &>/dev/null && jq -e '.shouldRestart' /tmp/homaruscc-wait-response.json &>/dev/null; then
54
+ echo "⚠️ COMPACTION LIMIT REACHED — Auto-restart required."
55
+ echo "Handle the events above, save state, then run: bash \"\$PWD/bin/restart-claude\""
56
+ else
57
+ echo "Event loop paused. Handle the events above, then restart: bash \"\$PWD/bin/event-loop\""
58
+ fi
53
59
  exit 0
54
60
  ;;
55
61
  *)
@@ -0,0 +1,80 @@
1
+ #!/bin/bash
2
+ # Nuclear restart — kill ALL claude processes system-wide, then start fresh
3
+ # Called by the /nuke Telegram command when /restart fails
4
+ # Env vars: HOMARUSCC_PROJECT_DIR, HOMARUSCC_CHAT_ID, HOMARUSCC_PORT
5
+
6
+ set -euo pipefail
7
+
8
+ PROJECT_DIR="${HOMARUSCC_PROJECT_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
9
+ PORT="${HOMARUSCC_PORT:-3120}"
10
+ CHAT_ID="${HOMARUSCC_CHAT_ID:-}"
11
+ SESSION_NAME="homaruscc"
12
+
13
+ report() {
14
+ local success="$1"
15
+ local message="$2"
16
+ if [ -n "$CHAT_ID" ] && [ -n "$PORT" ]; then
17
+ curl -s -X POST "http://127.0.0.1:${PORT}/api/restart-result" \
18
+ -H "Content-Type: application/json" \
19
+ -d "{\"success\":${success},\"message\":\"${message}\"}" \
20
+ > /dev/null 2>&1 || true
21
+ fi
22
+ }
23
+
24
+ echo "[nuke] Starting nuclear restart..."
25
+
26
+ # Ignore TERM/HUP/INT so we survive our own kill commands
27
+ # (script name contains "claude" so pkill/pgrep match us)
28
+ trap '' TERM HUP INT
29
+ MY_PID=$$
30
+
31
+ # Phase 1: Kill ALL tmux sessions
32
+ for session in $(tmux list-sessions -F '#{session_name}' 2>/dev/null || true); do
33
+ echo "[nuke] Killing tmux session: $session"
34
+ tmux kill-session -t "$session" 2>/dev/null || true
35
+ done
36
+ sleep 1
37
+
38
+ # Phase 2: Kill ALL claude processes (exclude ourselves)
39
+ echo "[nuke] Killing all claude processes (excluding PID $MY_PID)..."
40
+ for pid in $(pgrep -f "claude" 2>/dev/null || true); do
41
+ [ "$pid" = "$MY_PID" ] && continue
42
+ echo "[nuke] Killing PID $pid"
43
+ kill "$pid" 2>/dev/null || true
44
+ done
45
+ sleep 2
46
+
47
+ # Phase 3: Kill any event-loop curl processes
48
+ pkill -f "homaruscc-wait-response" 2>/dev/null || true
49
+
50
+ # Phase 4: Verify everything is dead (exclude ourselves)
51
+ REMAINING=0
52
+ for pid in $(pgrep -f "claude" 2>/dev/null || true); do
53
+ [ "$pid" = "$MY_PID" ] && continue
54
+ REMAINING=$((REMAINING + 1))
55
+ done
56
+ if [ "$REMAINING" -gt 0 ]; then
57
+ echo "[nuke] $REMAINING claude processes still alive — force killing"
58
+ for pid in $(pgrep -f "claude" 2>/dev/null || true); do
59
+ [ "$pid" = "$MY_PID" ] && continue
60
+ kill -9 "$pid" 2>/dev/null || true
61
+ done
62
+ sleep 1
63
+ fi
64
+
65
+ # Restore signal handling
66
+ trap - TERM HUP INT
67
+
68
+ # Phase 5: Start fresh tmux session
69
+ echo "[nuke] Starting fresh tmux session..."
70
+ tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_DIR"
71
+
72
+ if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
73
+ report "false" "Nuke: killed all processes but failed to create new tmux session"
74
+ exit 1
75
+ fi
76
+
77
+ tmux send-keys -t "$SESSION_NAME" 'claude --dangerously-skip-permissions "/homaruscc"' Enter
78
+
79
+ report "true" "Nuke complete. All claude processes killed, fresh session started. Attach: tmux attach -t ${SESSION_NAME}"
80
+ echo "[nuke] Done. Fresh session '${SESSION_NAME}' started."
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ # Restart Claude Code in a tmux session with /homaruscc
3
+ # Called by the /restart Telegram command (TelegramCommandHandler)
4
+ # Env vars: HOMARUSCC_PROJECT_DIR, HOMARUSCC_CHAT_ID, HOMARUSCC_PORT
5
+
6
+ set -euo pipefail
7
+
8
+ PROJECT_DIR="${HOMARUSCC_PROJECT_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
9
+ PORT="${HOMARUSCC_PORT:-3120}"
10
+ CHAT_ID="${HOMARUSCC_CHAT_ID:-}"
11
+ SESSION_NAME="homaruscc"
12
+
13
+ report() {
14
+ local success="$1"
15
+ local message="$2"
16
+ if [ -n "$CHAT_ID" ] && [ -n "$PORT" ]; then
17
+ curl -s -X POST "http://127.0.0.1:${PORT}/api/restart-result" \
18
+ -H "Content-Type: application/json" \
19
+ -d "{\"success\":${success},\"message\":\"${message}\"}" \
20
+ > /dev/null 2>&1 || true
21
+ fi
22
+ }
23
+
24
+ # Store chat ID for result callback
25
+ if [ -n "$CHAT_ID" ] && [ -n "$PORT" ]; then
26
+ curl -s -X POST "http://127.0.0.1:${PORT}/api/restart-chat" \
27
+ -H "Content-Type: application/json" \
28
+ -d "{\"chatId\":\"${CHAT_ID}\"}" \
29
+ > /dev/null 2>&1 || true
30
+ fi
31
+
32
+ # Reset compaction counter so new session starts clean
33
+ echo '{"count":0}' > "$HOME/.homaruscc/compaction-count.json"
34
+
35
+ # Kill existing tmux session if it exists
36
+ if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
37
+ tmux kill-session -t "$SESSION_NAME"
38
+ sleep 1
39
+ fi
40
+
41
+ # Also kill any stray claude processes for this project
42
+ # (in case claude was running outside tmux)
43
+ pkill -f "claude.*$(basename "$PROJECT_DIR")" 2>/dev/null || true
44
+ sleep 2
45
+
46
+ # Start new tmux session — interactive claude inside it
47
+ # Step 1: Create session with a shell
48
+ tmux new-session -d -s "$SESSION_NAME" -c "$PROJECT_DIR"
49
+
50
+ if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
51
+ report "false" "Failed to create tmux session"
52
+ exit 1
53
+ fi
54
+
55
+ # Step 2: Start claude with /homaruscc prompt passed directly
56
+ tmux send-keys -t "$SESSION_NAME" 'claude --dangerously-skip-permissions "/homaruscc"' Enter
57
+
58
+ report "true" "tmux session '${SESSION_NAME}' started with claude + /homaruscc. Attach: tmux attach -t ${SESSION_NAME}"
package/bin/setup ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bash
2
+ # HomarUScc first-run setup
3
+ # Creates ~/.homaruscc directory structure and launches the alignment interview
4
+ # to generate identity files (soul.md, user.md, state.md, preferences.md, disagreements.md).
5
+
6
+ set -euo pipefail
7
+
8
+ HOMARUSCC_DIR="${HOMARUSCC_DIR:-$HOME/.homaruscc}"
9
+
10
+ echo "=== HomarUScc Setup ==="
11
+ echo ""
12
+
13
+ # 1. Create directory structure
14
+ dirs=(
15
+ "$HOMARUSCC_DIR"
16
+ "$HOMARUSCC_DIR/identity"
17
+ "$HOMARUSCC_DIR/journal"
18
+ "$HOMARUSCC_DIR/memory"
19
+ "$HOMARUSCC_DIR/secrets"
20
+ )
21
+
22
+ for dir in "${dirs[@]}"; do
23
+ if [ ! -d "$dir" ]; then
24
+ mkdir -p "$dir"
25
+ echo "Created $dir"
26
+ fi
27
+ done
28
+
29
+ # 2. Create config.json if it doesn't exist
30
+ if [ ! -f "$HOMARUSCC_DIR/config.json" ]; then
31
+ cat > "$HOMARUSCC_DIR/config.json" << 'CONF'
32
+ {
33
+ "channels": {
34
+ "telegram": {
35
+ "enabled": false,
36
+ "botToken": ""
37
+ }
38
+ },
39
+ "memory": {
40
+ "extraPaths": [
41
+ "~/.homaruscc/identity",
42
+ "~/.homaruscc/journal"
43
+ ]
44
+ },
45
+ "timers": {
46
+ "defaults": []
47
+ }
48
+ }
49
+ CONF
50
+ echo "Created $HOMARUSCC_DIR/config.json (edit to add Telegram bot token)"
51
+ fi
52
+
53
+ # 3. Create .env template if it doesn't exist
54
+ if [ ! -f "$HOMARUSCC_DIR/.env" ]; then
55
+ cat > "$HOMARUSCC_DIR/.env" << 'ENV'
56
+ # Telegram Bot Token (get from @BotFather)
57
+ TELEGRAM_BOT_TOKEN=
58
+
59
+ # Optional: Anthropic API key for phone/voice features
60
+ # ANTHROPIC_API_KEY=
61
+ ENV
62
+ echo "Created $HOMARUSCC_DIR/.env (edit to add tokens)"
63
+ fi
64
+
65
+ # 4. Check for identity files
66
+ if [ -f "$HOMARUSCC_DIR/identity/soul.md" ]; then
67
+ echo ""
68
+ echo "Identity files already exist at $HOMARUSCC_DIR/identity/"
69
+ echo "Skipping alignment interview. Delete identity files to re-run."
70
+ echo ""
71
+ echo "Setup complete. Run: npx homaruscc"
72
+ exit 0
73
+ fi
74
+
75
+ # 5. Launch alignment interview
76
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
77
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
78
+ ALIGNMENT_DIR="$PROJECT_DIR/../alignment-generator"
79
+
80
+ echo ""
81
+ echo "Next step: Run the Alignment Interview to generate your identity files."
82
+ echo "This is a browser-based questionnaire that maps your values and preferences"
83
+ echo "into files your agent can use from day one."
84
+ echo ""
85
+
86
+ if [ -f "$ALIGNMENT_DIR/index.html" ]; then
87
+ echo "Opening alignment interview..."
88
+ echo " 1. Complete the interview (select 'HomarUScc' format)"
89
+ echo " 2. Download the identity kit"
90
+ echo " 3. Move the files to $HOMARUSCC_DIR/identity/"
91
+ echo ""
92
+ open "$ALIGNMENT_DIR/index.html" 2>/dev/null || echo "Open $ALIGNMENT_DIR/index.html in your browser"
93
+ else
94
+ echo "Alignment interview not found at $ALIGNMENT_DIR"
95
+ echo "You can create identity files manually in $HOMARUSCC_DIR/identity/:"
96
+ echo " soul.md - Agent identity and values"
97
+ echo " user.md - About you (the human)"
98
+ echo " state.md - Session continuity"
99
+ echo " preferences.md - Agent's emergent preferences"
100
+ echo " disagreements.md - Times the agent pushed back"
101
+ fi
102
+
103
+ echo ""
104
+ echo "After identity files are in place, run: npx homaruscc"