@soederpop/luca 0.0.2

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 (358) hide show
  1. package/CLAUDE.md +71 -0
  2. package/README.md +78 -0
  3. package/bun.lock +2928 -0
  4. package/bunfig.toml +3 -0
  5. package/commands/audit-docs.ts +740 -0
  6. package/commands/build-scaffolds.ts +154 -0
  7. package/commands/generate-api-docs.ts +114 -0
  8. package/commands/update-introspection.ts +67 -0
  9. package/docs/CLI.md +335 -0
  10. package/docs/README.md +88 -0
  11. package/docs/TABLE-OF-CONTENTS.md +157 -0
  12. package/docs/apis/clients/elevenlabs.md +84 -0
  13. package/docs/apis/clients/graph.md +56 -0
  14. package/docs/apis/clients/openai.md +69 -0
  15. package/docs/apis/clients/rest.md +41 -0
  16. package/docs/apis/clients/websocket.md +107 -0
  17. package/docs/apis/features/agi/assistant.md +471 -0
  18. package/docs/apis/features/agi/assistants-manager.md +154 -0
  19. package/docs/apis/features/agi/claude-code.md +602 -0
  20. package/docs/apis/features/agi/conversation-history.md +352 -0
  21. package/docs/apis/features/agi/conversation.md +333 -0
  22. package/docs/apis/features/agi/docs-reader.md +121 -0
  23. package/docs/apis/features/agi/openai-codex.md +318 -0
  24. package/docs/apis/features/agi/openapi.md +138 -0
  25. package/docs/apis/features/agi/semantic-search.md +387 -0
  26. package/docs/apis/features/agi/skills-library.md +216 -0
  27. package/docs/apis/features/node/container-link.md +133 -0
  28. package/docs/apis/features/node/content-db.md +313 -0
  29. package/docs/apis/features/node/disk-cache.md +379 -0
  30. package/docs/apis/features/node/dns.md +651 -0
  31. package/docs/apis/features/node/docker.md +705 -0
  32. package/docs/apis/features/node/downloader.md +81 -0
  33. package/docs/apis/features/node/esbuild.md +59 -0
  34. package/docs/apis/features/node/file-manager.md +182 -0
  35. package/docs/apis/features/node/fs.md +581 -0
  36. package/docs/apis/features/node/git.md +330 -0
  37. package/docs/apis/features/node/google-auth.md +174 -0
  38. package/docs/apis/features/node/google-calendar.md +187 -0
  39. package/docs/apis/features/node/google-docs.md +151 -0
  40. package/docs/apis/features/node/google-drive.md +225 -0
  41. package/docs/apis/features/node/google-sheets.md +179 -0
  42. package/docs/apis/features/node/grep.md +290 -0
  43. package/docs/apis/features/node/helpers.md +135 -0
  44. package/docs/apis/features/node/ink.md +334 -0
  45. package/docs/apis/features/node/ipc-socket.md +260 -0
  46. package/docs/apis/features/node/json-tree.md +86 -0
  47. package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
  48. package/docs/apis/features/node/networking.md +281 -0
  49. package/docs/apis/features/node/nlp.md +133 -0
  50. package/docs/apis/features/node/opener.md +97 -0
  51. package/docs/apis/features/node/os.md +118 -0
  52. package/docs/apis/features/node/package-finder.md +402 -0
  53. package/docs/apis/features/node/postgres.md +212 -0
  54. package/docs/apis/features/node/proc.md +430 -0
  55. package/docs/apis/features/node/process-manager.md +210 -0
  56. package/docs/apis/features/node/python.md +278 -0
  57. package/docs/apis/features/node/repl.md +88 -0
  58. package/docs/apis/features/node/runpod.md +673 -0
  59. package/docs/apis/features/node/secure-shell.md +169 -0
  60. package/docs/apis/features/node/semantic-search.md +401 -0
  61. package/docs/apis/features/node/sqlite.md +211 -0
  62. package/docs/apis/features/node/telegram.md +254 -0
  63. package/docs/apis/features/node/tts.md +118 -0
  64. package/docs/apis/features/node/ui.md +703 -0
  65. package/docs/apis/features/node/vault.md +64 -0
  66. package/docs/apis/features/node/vm.md +84 -0
  67. package/docs/apis/features/node/window-manager.md +337 -0
  68. package/docs/apis/features/node/yaml-tree.md +85 -0
  69. package/docs/apis/features/node/yaml.md +176 -0
  70. package/docs/apis/features/web/asset-loader.md +47 -0
  71. package/docs/apis/features/web/container-link.md +133 -0
  72. package/docs/apis/features/web/esbuild.md +59 -0
  73. package/docs/apis/features/web/helpers.md +135 -0
  74. package/docs/apis/features/web/network.md +30 -0
  75. package/docs/apis/features/web/speech.md +55 -0
  76. package/docs/apis/features/web/vault.md +64 -0
  77. package/docs/apis/features/web/vm.md +84 -0
  78. package/docs/apis/features/web/voice.md +67 -0
  79. package/docs/apis/servers/express.md +127 -0
  80. package/docs/apis/servers/mcp.md +213 -0
  81. package/docs/apis/servers/websocket.md +99 -0
  82. package/docs/documentation-audit.md +134 -0
  83. package/docs/examples/content-db.md +77 -0
  84. package/docs/examples/disk-cache.md +83 -0
  85. package/docs/examples/docker.md +101 -0
  86. package/docs/examples/downloader.md +70 -0
  87. package/docs/examples/esbuild.md +80 -0
  88. package/docs/examples/file-manager.md +82 -0
  89. package/docs/examples/fs.md +83 -0
  90. package/docs/examples/git.md +85 -0
  91. package/docs/examples/google-auth.md +88 -0
  92. package/docs/examples/google-calendar.md +94 -0
  93. package/docs/examples/google-docs.md +82 -0
  94. package/docs/examples/google-drive.md +96 -0
  95. package/docs/examples/google-sheets.md +95 -0
  96. package/docs/examples/grep.md +85 -0
  97. package/docs/examples/ink-blocks.md +75 -0
  98. package/docs/examples/ink-renderer.md +41 -0
  99. package/docs/examples/ink.md +103 -0
  100. package/docs/examples/ipc-socket.md +103 -0
  101. package/docs/examples/json-tree.md +91 -0
  102. package/docs/examples/launcher-app-command-listener.md +120 -0
  103. package/docs/examples/networking.md +58 -0
  104. package/docs/examples/nlp.md +91 -0
  105. package/docs/examples/opener.md +78 -0
  106. package/docs/examples/os.md +72 -0
  107. package/docs/examples/package-finder.md +89 -0
  108. package/docs/examples/port-exposer.md +89 -0
  109. package/docs/examples/postgres.md +91 -0
  110. package/docs/examples/proc.md +81 -0
  111. package/docs/examples/process-manager.md +79 -0
  112. package/docs/examples/python.md +91 -0
  113. package/docs/examples/repl.md +93 -0
  114. package/docs/examples/runpod.md +119 -0
  115. package/docs/examples/secure-shell.md +92 -0
  116. package/docs/examples/sqlite.md +86 -0
  117. package/docs/examples/telegram.md +77 -0
  118. package/docs/examples/tts.md +86 -0
  119. package/docs/examples/ui.md +80 -0
  120. package/docs/examples/vault.md +70 -0
  121. package/docs/examples/vm.md +86 -0
  122. package/docs/examples/window-manager.md +125 -0
  123. package/docs/examples/yaml-tree.md +93 -0
  124. package/docs/examples/yaml.md +104 -0
  125. package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
  126. package/docs/ideas/container-use-api.md +9 -0
  127. package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
  128. package/docs/ideas/feature-stacks.md +22 -0
  129. package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
  130. package/docs/ideas/mcp-design.md +9 -0
  131. package/docs/ideas/web-container-debugging-feature.md +13 -0
  132. package/docs/introspection-audit.md +49 -0
  133. package/docs/introspection.md +154 -0
  134. package/docs/mcp/readme.md +162 -0
  135. package/docs/models.ts +38 -0
  136. package/docs/philosophy.md +85 -0
  137. package/docs/principles.md +7 -0
  138. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
  139. package/docs/prompts/mcp-test-easy-command.md +27 -0
  140. package/docs/reports/assistant-bugs.md +38 -0
  141. package/docs/reports/attach-pattern-usage.md +18 -0
  142. package/docs/reports/code-audit-results.md +391 -0
  143. package/docs/reports/introspection-audit-tasks.md +378 -0
  144. package/docs/reports/luca-mcp-improvements.md +128 -0
  145. package/docs/scaffolds/client.md +140 -0
  146. package/docs/scaffolds/command.md +106 -0
  147. package/docs/scaffolds/endpoint.md +176 -0
  148. package/docs/scaffolds/feature.md +148 -0
  149. package/docs/scaffolds/server.md +187 -0
  150. package/docs/tasks/web-container-helper-discovery.md +71 -0
  151. package/docs/todos.md +1 -0
  152. package/docs/tutorials/01-getting-started.md +106 -0
  153. package/docs/tutorials/02-container.md +210 -0
  154. package/docs/tutorials/03-scripts.md +194 -0
  155. package/docs/tutorials/04-features-overview.md +196 -0
  156. package/docs/tutorials/05-state-and-events.md +171 -0
  157. package/docs/tutorials/06-servers.md +157 -0
  158. package/docs/tutorials/07-endpoints.md +198 -0
  159. package/docs/tutorials/08-commands.md +171 -0
  160. package/docs/tutorials/09-clients.md +162 -0
  161. package/docs/tutorials/10-creating-features.md +198 -0
  162. package/docs/tutorials/11-contentbase.md +191 -0
  163. package/docs/tutorials/12-assistants.md +215 -0
  164. package/docs/tutorials/13-introspection.md +147 -0
  165. package/docs/tutorials/14-type-system.md +174 -0
  166. package/docs/tutorials/15-project-patterns.md +222 -0
  167. package/docs/tutorials/16-google-features.md +534 -0
  168. package/docs/tutorials/17-tui-blocks.md +530 -0
  169. package/docs/tutorials/18-semantic-search.md +334 -0
  170. package/index.ts +1 -0
  171. package/luca.console.ts +9 -0
  172. package/main.py +6 -0
  173. package/package.json +154 -0
  174. package/pyproject.toml +7 -0
  175. package/scripts/animations/chrome-glitch.ts +55 -0
  176. package/scripts/animations/index.ts +16 -0
  177. package/scripts/animations/neon-pulse.ts +64 -0
  178. package/scripts/animations/types.ts +6 -0
  179. package/scripts/build-web.ts +28 -0
  180. package/scripts/examples/ask-luca-expert.ts +42 -0
  181. package/scripts/examples/assistant-questions.ts +12 -0
  182. package/scripts/examples/excalidraw-expert.ts +75 -0
  183. package/scripts/examples/expert-chat.ts +0 -0
  184. package/scripts/examples/file-manager.ts +14 -0
  185. package/scripts/examples/ideas.ts +12 -0
  186. package/scripts/examples/interactive-chat.ts +20 -0
  187. package/scripts/examples/openai-tool-calls.ts +113 -0
  188. package/scripts/examples/opening-a-web-browser.ts +5 -0
  189. package/scripts/examples/telegram-bot.ts +79 -0
  190. package/scripts/examples/telegram-ink-ui.ts +302 -0
  191. package/scripts/examples/using-assistant-with-mcp.ts +560 -0
  192. package/scripts/examples/using-claude-code.ts +10 -0
  193. package/scripts/examples/using-contentdb.ts +35 -0
  194. package/scripts/examples/using-conversations.ts +35 -0
  195. package/scripts/examples/using-disk-cache.ts +10 -0
  196. package/scripts/examples/using-docker-shell.ts +75 -0
  197. package/scripts/examples/using-elevenlabs.ts +25 -0
  198. package/scripts/examples/using-google-calendar.ts +57 -0
  199. package/scripts/examples/using-google-docs.ts +74 -0
  200. package/scripts/examples/using-google-drive.ts +74 -0
  201. package/scripts/examples/using-google-sheets.ts +89 -0
  202. package/scripts/examples/using-nlp.ts +55 -0
  203. package/scripts/examples/using-ollama.ts +10 -0
  204. package/scripts/examples/using-openai-codex.ts +23 -0
  205. package/scripts/examples/using-postgres.ts +55 -0
  206. package/scripts/examples/using-runpod.ts +32 -0
  207. package/scripts/examples/using-tts.ts +40 -0
  208. package/scripts/examples/vm-loading-esm-modules.ts +16 -0
  209. package/scripts/scaffold.ts +391 -0
  210. package/scripts/scratch.ts +15 -0
  211. package/scripts/test-command-listener.ts +123 -0
  212. package/scripts/test-window-manager-lifecycle.ts +86 -0
  213. package/scripts/test-window-manager.ts +43 -0
  214. package/scripts/update-introspection-data.ts +58 -0
  215. package/src/agi/README.md +14 -0
  216. package/src/agi/container.server.ts +114 -0
  217. package/src/agi/endpoints/ask.ts +60 -0
  218. package/src/agi/endpoints/conversations/[id].ts +45 -0
  219. package/src/agi/endpoints/conversations.ts +31 -0
  220. package/src/agi/endpoints/experts.ts +37 -0
  221. package/src/agi/features/assistant.ts +767 -0
  222. package/src/agi/features/assistants-manager.ts +260 -0
  223. package/src/agi/features/claude-code.ts +1111 -0
  224. package/src/agi/features/conversation-history.ts +497 -0
  225. package/src/agi/features/conversation.ts +799 -0
  226. package/src/agi/features/openai-codex.ts +631 -0
  227. package/src/agi/features/openapi.ts +438 -0
  228. package/src/agi/features/skills-library.ts +425 -0
  229. package/src/agi/index.ts +6 -0
  230. package/src/agi/lib/token-counter.ts +122 -0
  231. package/src/browser.ts +25 -0
  232. package/src/bus.ts +100 -0
  233. package/src/cli/cli.ts +70 -0
  234. package/src/client.ts +461 -0
  235. package/src/clients/civitai/index.ts +541 -0
  236. package/src/clients/client-template.ts +41 -0
  237. package/src/clients/comfyui/index.ts +597 -0
  238. package/src/clients/elevenlabs/index.ts +291 -0
  239. package/src/clients/openai/index.ts +451 -0
  240. package/src/clients/supabase/index.ts +366 -0
  241. package/src/command.ts +164 -0
  242. package/src/commands/chat.ts +182 -0
  243. package/src/commands/console.ts +192 -0
  244. package/src/commands/describe.ts +433 -0
  245. package/src/commands/eval.ts +116 -0
  246. package/src/commands/help.ts +214 -0
  247. package/src/commands/index.ts +14 -0
  248. package/src/commands/mcp.ts +64 -0
  249. package/src/commands/prompt.ts +807 -0
  250. package/src/commands/run.ts +257 -0
  251. package/src/commands/sandbox-mcp.ts +439 -0
  252. package/src/commands/scaffold.ts +79 -0
  253. package/src/commands/serve.ts +172 -0
  254. package/src/container.ts +781 -0
  255. package/src/endpoint.ts +340 -0
  256. package/src/feature.ts +75 -0
  257. package/src/hash-object.ts +97 -0
  258. package/src/helper.ts +543 -0
  259. package/src/introspection/generated.agi.ts +23388 -0
  260. package/src/introspection/generated.node.ts +18899 -0
  261. package/src/introspection/generated.web.ts +2021 -0
  262. package/src/introspection/index.ts +256 -0
  263. package/src/introspection/scan.ts +912 -0
  264. package/src/node/container.ts +354 -0
  265. package/src/node/feature.ts +13 -0
  266. package/src/node/features/container-link.ts +558 -0
  267. package/src/node/features/content-db.ts +475 -0
  268. package/src/node/features/disk-cache.ts +382 -0
  269. package/src/node/features/dns.ts +655 -0
  270. package/src/node/features/docker.ts +912 -0
  271. package/src/node/features/downloader.ts +92 -0
  272. package/src/node/features/esbuild.ts +68 -0
  273. package/src/node/features/file-manager.ts +357 -0
  274. package/src/node/features/fs.ts +534 -0
  275. package/src/node/features/git.ts +492 -0
  276. package/src/node/features/google-auth.ts +502 -0
  277. package/src/node/features/google-calendar.ts +300 -0
  278. package/src/node/features/google-docs.ts +404 -0
  279. package/src/node/features/google-drive.ts +339 -0
  280. package/src/node/features/google-sheets.ts +279 -0
  281. package/src/node/features/grep.ts +406 -0
  282. package/src/node/features/helpers.ts +374 -0
  283. package/src/node/features/ink.ts +490 -0
  284. package/src/node/features/ipc-socket.ts +459 -0
  285. package/src/node/features/json-tree.ts +188 -0
  286. package/src/node/features/launcher-app-command-listener.ts +388 -0
  287. package/src/node/features/networking.ts +925 -0
  288. package/src/node/features/nlp.ts +211 -0
  289. package/src/node/features/opener.ts +166 -0
  290. package/src/node/features/os.ts +157 -0
  291. package/src/node/features/package-finder.ts +539 -0
  292. package/src/node/features/port-exposer.ts +342 -0
  293. package/src/node/features/postgres.ts +273 -0
  294. package/src/node/features/proc.ts +502 -0
  295. package/src/node/features/process-manager.ts +542 -0
  296. package/src/node/features/python.ts +444 -0
  297. package/src/node/features/repl.ts +194 -0
  298. package/src/node/features/runpod.ts +802 -0
  299. package/src/node/features/secure-shell.ts +248 -0
  300. package/src/node/features/semantic-search.ts +924 -0
  301. package/src/node/features/sqlite.ts +289 -0
  302. package/src/node/features/telegram.ts +342 -0
  303. package/src/node/features/tts.ts +184 -0
  304. package/src/node/features/ui.ts +857 -0
  305. package/src/node/features/vault.ts +164 -0
  306. package/src/node/features/vm.ts +312 -0
  307. package/src/node/features/window-manager.ts +804 -0
  308. package/src/node/features/yaml-tree.ts +149 -0
  309. package/src/node/features/yaml.ts +132 -0
  310. package/src/node.ts +70 -0
  311. package/src/react/index.ts +175 -0
  312. package/src/registry.ts +199 -0
  313. package/src/scaffolds/generated.ts +1613 -0
  314. package/src/scaffolds/template.ts +37 -0
  315. package/src/schemas/base.ts +255 -0
  316. package/src/server.ts +135 -0
  317. package/src/servers/express.ts +209 -0
  318. package/src/servers/mcp.ts +805 -0
  319. package/src/servers/socket.ts +120 -0
  320. package/src/state.ts +101 -0
  321. package/src/web/clients/socket.ts +82 -0
  322. package/src/web/container.ts +74 -0
  323. package/src/web/extension.ts +30 -0
  324. package/src/web/feature.ts +12 -0
  325. package/src/web/features/asset-loader.ts +64 -0
  326. package/src/web/features/container-link.ts +385 -0
  327. package/src/web/features/esbuild.ts +79 -0
  328. package/src/web/features/helpers.ts +267 -0
  329. package/src/web/features/network.ts +61 -0
  330. package/src/web/features/speech.ts +87 -0
  331. package/src/web/features/vault.ts +189 -0
  332. package/src/web/features/vm.ts +78 -0
  333. package/src/web/features/voice-recognition.ts +129 -0
  334. package/src/web/shims/isomorphic-vm.ts +149 -0
  335. package/test/bus.test.ts +134 -0
  336. package/test/clients-servers.test.ts +216 -0
  337. package/test/container-link.test.ts +274 -0
  338. package/test/features.test.ts +160 -0
  339. package/test/integration.test.ts +787 -0
  340. package/test/node-container.test.ts +121 -0
  341. package/test/rate-limit.test.ts +272 -0
  342. package/test/semantic-search.test.ts +550 -0
  343. package/test/state.test.ts +121 -0
  344. package/test-integration/assistant.test.ts +138 -0
  345. package/test-integration/assistants-manager.test.ts +123 -0
  346. package/test-integration/claude-code.test.ts +98 -0
  347. package/test-integration/conversation-history.test.ts +205 -0
  348. package/test-integration/conversation.test.ts +137 -0
  349. package/test-integration/elevenlabs.test.ts +55 -0
  350. package/test-integration/google-services.test.ts +80 -0
  351. package/test-integration/helpers.ts +89 -0
  352. package/test-integration/openai-codex.test.ts +93 -0
  353. package/test-integration/runpod.test.ts +58 -0
  354. package/test-integration/server-endpoints.test.ts +97 -0
  355. package/test-integration/skills-library.test.ts +157 -0
  356. package/test-integration/telegram.test.ts +46 -0
  357. package/tsconfig.json +58 -0
  358. package/uv.lock +8 -0
@@ -0,0 +1,459 @@
1
+ import { z } from 'zod'
2
+ import { FeatureStateSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
+ import { Feature, features } from "../feature.js";
4
+ import { NodeContainer } from "../container.js";
5
+ import { Server, Socket } from "net";
6
+
7
+ /**
8
+ * Zod schema for the IpcSocket feature state.
9
+ * Tracks the operational mode of the IPC socket (server or client).
10
+ */
11
+ export const IpcStateSchema = FeatureStateSchema.extend({
12
+ /** The current mode of the IPC socket - either 'server' or 'client' */
13
+ mode: z.enum(['server', 'client']).optional().describe('The current mode of the IPC socket - either server or client'),
14
+ })
15
+ export type IpcState = z.infer<typeof IpcStateSchema>
16
+
17
+ export const IpcEventsSchema = FeatureEventsSchema.extend({
18
+ connection: z.tuple([
19
+ z.any().describe('The connected net.Socket instance'),
20
+ ]).describe('Emitted on the server when a new client connects'),
21
+ message: z.tuple([
22
+ z.any().describe('The parsed JSON message object received over the socket'),
23
+ ]).describe('Emitted when a complete JSON message is received (server or client)'),
24
+ })
25
+
26
+ /**
27
+ * IpcSocket Feature - Inter-Process Communication via Unix Domain Sockets
28
+ *
29
+ * This feature provides robust IPC (Inter-Process Communication) capabilities using Unix domain sockets.
30
+ * It supports both server and client modes, allowing processes to communicate efficiently through
31
+ * file system-based socket connections.
32
+ *
33
+ * **Key Features:**
34
+ * - Dual-mode operation: server and client functionality
35
+ * - JSON message serialization/deserialization
36
+ * - Multiple client connection support (server mode)
37
+ * - Event-driven message handling
38
+ * - Automatic socket cleanup and management
39
+ * - Broadcast messaging to all connected clients
40
+ * - Lock file management for socket paths
41
+ *
42
+ * **Communication Pattern:**
43
+ * - Messages are automatically JSON-encoded with unique IDs
44
+ * - Both server and client emit 'message' events for incoming data
45
+ * - Server can broadcast to all connected clients
46
+ * - Client maintains single connection to server
47
+ *
48
+ * **Socket Management:**
49
+ * - Automatic cleanup of stale socket files
50
+ * - Connection tracking and management
51
+ * - Graceful shutdown procedures
52
+ * - Lock file protection against conflicts
53
+ *
54
+ * **Usage Examples:**
55
+ *
56
+ * **Server Mode:**
57
+ * ```typescript
58
+ * const ipc = container.feature('ipcSocket');
59
+ * await ipc.listen('/tmp/myapp.sock', true); // removeLock=true
60
+ *
61
+ * ipc.on('connection', (socket) => {
62
+ * console.log('Client connected');
63
+ * });
64
+ *
65
+ * ipc.on('message', (data) => {
66
+ * console.log('Received:', data);
67
+ * ipc.broadcast({ reply: 'ACK', original: data });
68
+ * });
69
+ * ```
70
+ *
71
+ * **Client Mode:**
72
+ * ```typescript
73
+ * const ipc = container.feature('ipcSocket');
74
+ * await ipc.connect('/tmp/myapp.sock');
75
+ *
76
+ * ipc.on('message', (data) => {
77
+ * console.log('Server says:', data);
78
+ * });
79
+ *
80
+ * await ipc.send({ type: 'request', payload: 'hello' });
81
+ * ```
82
+ *
83
+ * @template T - The state type, defaults to IpcState
84
+ * @extends {Feature<T>}
85
+ */
86
+ export class IpcSocket<T extends IpcState = IpcState> extends Feature<T> {
87
+ /** The shortcut path for accessing this feature */
88
+ static override shortcut = "features.ipcSocket" as const
89
+ static override stateSchema = IpcStateSchema
90
+ static override eventsSchema = IpcEventsSchema
91
+
92
+ /** The Node.js net Server instance (when in server mode) */
93
+ server?: Server;
94
+
95
+ /** Set of connected client sockets (server mode only) */
96
+ protected sockets: Set<Socket> = new Set();
97
+
98
+ /** Per-socket NDJSON read buffers for accumulating partial lines */
99
+ private _buffers = new WeakMap<Socket, string>();
100
+
101
+ /**
102
+ * Attaches the IpcSocket feature to a NodeContainer instance.
103
+ * Registers the feature and creates an auto-enabled instance.
104
+ *
105
+ * @param container - The NodeContainer to attach to
106
+ * @returns The container for method chaining
107
+ */
108
+ static attach(container: NodeContainer & { ipcSocket?: IpcSocket }) {
109
+ container.features.register("ipcSocket", IpcSocket);
110
+ container.ipcSocket = container.feature("ipcSocket", { enable: true });
111
+ }
112
+
113
+ /**
114
+ * Checks if the IPC socket is operating in client mode.
115
+ *
116
+ * @returns True if the socket is configured as a client
117
+ */
118
+ get isClient() {
119
+ return this.state.get('mode') === 'client'
120
+ }
121
+
122
+ /**
123
+ * Checks if the IPC socket is operating in server mode.
124
+ *
125
+ * @returns True if the socket is configured as a server
126
+ */
127
+ get isServer() {
128
+ return this.state.get('mode') === 'server'
129
+ }
130
+
131
+ /**
132
+ * Starts the IPC server listening on the specified socket path.
133
+ *
134
+ * This method sets up a Unix domain socket server that can accept multiple client connections.
135
+ * Each connected client is tracked, and the server automatically handles connection lifecycle
136
+ * events. Messages received from clients are JSON-parsed and emitted as 'message' events.
137
+ *
138
+ * **Server Behavior:**
139
+ * - Tracks all connected clients in the sockets Set
140
+ * - Automatically removes clients when they disconnect
141
+ * - JSON-parses incoming messages and emits 'message' events
142
+ * - Emits 'connection' events when clients connect
143
+ * - Prevents starting multiple servers on the same instance
144
+ *
145
+ * **Socket File Management:**
146
+ * - Resolves the socket path relative to the container's working directory
147
+ * - Optionally removes existing socket files to prevent "address in use" errors
148
+ * - Throws error if socket file exists and removeLock is false
149
+ *
150
+ * @param socketPath - The file system path for the Unix domain socket
151
+ * @param removeLock - Whether to remove existing socket file (default: false)
152
+ * @returns Promise resolving to the created Node.js Server instance
153
+ *
154
+ * @throws {Error} When already in client mode, server already running, or socket file exists
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * // Basic server setup
159
+ * const server = await ipc.listen('/tmp/myapp.sock');
160
+ *
161
+ * // With automatic lock removal
162
+ * const server = await ipc.listen('/tmp/myapp.sock', true);
163
+ *
164
+ * // Handle connections and messages
165
+ * ipc.on('connection', (socket) => {
166
+ * console.log('New client connected');
167
+ * });
168
+ *
169
+ * ipc.on('message', (data) => {
170
+ * console.log('Received message:', data);
171
+ * // Echo back to all clients
172
+ * ipc.broadcast({ echo: data });
173
+ * });
174
+ * ```
175
+ */
176
+ async listen(socketPath: string, removeLock = false): Promise<Server> {
177
+ socketPath = this.container.paths.resolve(socketPath)
178
+
179
+ if (this.container.fs.exists(socketPath)) {
180
+ if(removeLock) {
181
+ await this.container.fs.rm(socketPath)
182
+ } else {
183
+ throw new Error('Lock already exists')
184
+ }
185
+ }
186
+
187
+ if(this.isClient) {
188
+ throw new Error("Cannot listen on a client socket.");
189
+ }
190
+
191
+ this.state.set('mode', 'server')
192
+
193
+ if (this.server) {
194
+ throw new Error("An IPC server is already running.");
195
+ }
196
+
197
+ this.server = new Server((socket) => {
198
+ this.sockets.add(socket);
199
+ this._buffers.set(socket, '');
200
+
201
+ socket.on("close", () => {
202
+ this.sockets.delete(socket);
203
+ });
204
+
205
+ socket.on('data', (chunk) => {
206
+ this._handleChunk(socket, chunk)
207
+ })
208
+
209
+ this.emit('connection', socket)
210
+ });
211
+
212
+ this.server.listen(socketPath);
213
+
214
+ return this.server;
215
+ }
216
+
217
+ /**
218
+ * Stops the IPC server and cleans up all connections.
219
+ *
220
+ * This method gracefully shuts down the server by:
221
+ * 1. Closing the server listener
222
+ * 2. Destroying all active client connections
223
+ * 3. Clearing the sockets tracking set
224
+ * 4. Resetting the server instance
225
+ *
226
+ * @returns Promise that resolves when the server is fully stopped
227
+ *
228
+ * @throws {Error} When no server is currently running
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * // Graceful shutdown
233
+ * try {
234
+ * await ipc.stopServer();
235
+ * console.log('IPC server stopped successfully');
236
+ * } catch (error) {
237
+ * console.error('Failed to stop server:', error.message);
238
+ * }
239
+ * ```
240
+ */
241
+ stopServer(): Promise<void> {
242
+ return new Promise((resolve, reject) => {
243
+ if (!this.server) {
244
+ reject(new Error("No IPC server is running."));
245
+ return;
246
+ }
247
+
248
+ this.server.close((err) => {
249
+ if (err) {
250
+ reject(err);
251
+ } else {
252
+ resolve();
253
+ }
254
+ });
255
+
256
+ this.sockets.forEach((socket) => socket.destroy());
257
+ this.sockets.clear();
258
+ this.server = undefined;
259
+ });
260
+ }
261
+
262
+ /** The client connection socket (client mode only) */
263
+ _connection?: Socket
264
+
265
+ /**
266
+ * Gets the current client connection socket.
267
+ *
268
+ * @returns The active Socket connection, or undefined if not connected
269
+ */
270
+ get connection() {
271
+ return this._connection
272
+ }
273
+
274
+ /**
275
+ * Broadcasts a message to all connected clients (server mode only).
276
+ *
277
+ * This method sends a JSON-encoded message with a unique ID to every client
278
+ * currently connected to the server. Each message is automatically wrapped
279
+ * with metadata including a UUID for tracking.
280
+ *
281
+ * **Message Format:**
282
+ * Messages are automatically wrapped in the format:
283
+ * ```json
284
+ * {
285
+ * "data": <your_message>,
286
+ * "id": "<uuid>"
287
+ * }
288
+ * ```
289
+ *
290
+ * @param message - The message object to broadcast to all clients
291
+ * @returns This instance for method chaining
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * // Broadcast to all connected clients
296
+ * ipc.broadcast({
297
+ * type: 'notification',
298
+ * message: 'Server is shutting down in 30 seconds',
299
+ * timestamp: Date.now()
300
+ * });
301
+ *
302
+ * // Chain multiple operations
303
+ * ipc.broadcast({ status: 'ready' })
304
+ * .broadcast({ time: new Date().toISOString() });
305
+ * ```
306
+ */
307
+ broadcast(message: any) {
308
+ this.sockets.forEach((socket) => socket.write(JSON.stringify({
309
+ data: message,
310
+ id: this.container.utils.uuid()
311
+ }) + '\n'))
312
+
313
+ return this
314
+ }
315
+
316
+ /**
317
+ * Sends a message to the server (client mode only).
318
+ *
319
+ * This method sends a JSON-encoded message with a unique ID to the connected server.
320
+ * The message is automatically wrapped with metadata for tracking purposes.
321
+ *
322
+ * **Message Format:**
323
+ * Messages are automatically wrapped in the format:
324
+ * ```json
325
+ * {
326
+ * "data": <your_message>,
327
+ * "id": "<uuid>"
328
+ * }
329
+ * ```
330
+ *
331
+ * @param message - The message object to send to the server
332
+ * @returns Promise that resolves when the message is sent
333
+ *
334
+ * @throws {Error} When no connection is established
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * // Send a simple message
339
+ * await ipc.send({ type: 'ping' });
340
+ *
341
+ * // Send complex data
342
+ * await ipc.send({
343
+ * type: 'data_update',
344
+ * payload: { users: [...], timestamp: Date.now() }
345
+ * });
346
+ * ```
347
+ */
348
+ async send(message: any) {
349
+ const id = this.container.utils.uuid()
350
+
351
+ if(!this._connection) {
352
+ throw new Error("No connection.")
353
+ }
354
+
355
+ this._connection.write(JSON.stringify({ id, data: message }) + '\n')
356
+ }
357
+
358
+ /**
359
+ * Connects to an IPC server at the specified socket path (client mode).
360
+ *
361
+ * This method establishes a client connection to an existing IPC server.
362
+ * Once connected, the client can send messages to the server and receive
363
+ * responses. The connection is maintained until explicitly closed or the
364
+ * server terminates.
365
+ *
366
+ * **Connection Behavior:**
367
+ * - Sets the socket mode to 'client'
368
+ * - Returns existing connection if already connected
369
+ * - Automatically handles connection events and cleanup
370
+ * - JSON-parses incoming messages and emits 'message' events
371
+ * - Cleans up connection reference when socket closes
372
+ *
373
+ * **Error Handling:**
374
+ * - Throws error if already in server mode
375
+ * - Rejects promise on connection failures
376
+ * - Automatically cleans up on connection close
377
+ *
378
+ * @param socketPath - The file system path to the server's Unix domain socket
379
+ * @returns Promise resolving to the established Socket connection
380
+ *
381
+ * @throws {Error} When already in server mode or connection fails
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * // Connect to server
386
+ * const socket = await ipc.connect('/tmp/myapp.sock');
387
+ * console.log('Connected to IPC server');
388
+ *
389
+ * // Handle incoming messages
390
+ * ipc.on('message', (data) => {
391
+ * console.log('Server message:', data);
392
+ * });
393
+ *
394
+ * // Send messages
395
+ * await ipc.send({ type: 'hello', client_id: 'client_001' });
396
+ * ```
397
+ */
398
+ async connect(socketPath: string): Promise<Socket> {
399
+ if(this.isServer) {
400
+ throw new Error("Cannot connect on a server socket.")
401
+ }
402
+
403
+ if(this._connection) {
404
+ return this._connection
405
+ }
406
+
407
+ const connection : Socket = await new Promise((resolve, reject) => {
408
+ const socket = new Socket();
409
+ socket.connect(socketPath, () => {
410
+ resolve(socket);
411
+ });
412
+
413
+ socket.on("error", (err) => {
414
+ reject(err);
415
+ });
416
+ });
417
+
418
+ connection.on("close", () => {
419
+ this._connection = undefined
420
+ })
421
+
422
+ this._buffers.set(connection, '');
423
+ connection.on("data", (chunk) => {
424
+ this._handleChunk(connection, chunk)
425
+ })
426
+
427
+ return this._connection = connection as Socket
428
+ }
429
+
430
+ /**
431
+ * Accumulates incoming data into a per-socket buffer and emits
432
+ * a `message` event for each complete NDJSON line (newline-delimited JSON).
433
+ *
434
+ * This handles the common stream framing issues:
435
+ * - Partial messages split across multiple `data` events
436
+ * - Multiple messages arriving in a single `data` event
437
+ * - Malformed lines (silently skipped)
438
+ *
439
+ * @param socket - The socket the data arrived on
440
+ * @param chunk - The raw data chunk
441
+ */
442
+ private _handleChunk(socket: Socket, chunk: Buffer): void {
443
+ let buffer = (this._buffers.get(socket) || '') + chunk.toString()
444
+ const lines = buffer.split('\n')
445
+ // Last element is either empty (if chunk ended with \n) or an incomplete line
446
+ this._buffers.set(socket, lines.pop() || '')
447
+
448
+ for (const line of lines) {
449
+ if (!line.trim()) continue
450
+ try {
451
+ this.emit('message', JSON.parse(line))
452
+ } catch {
453
+ // Malformed JSON line — skip
454
+ }
455
+ }
456
+ }
457
+ }
458
+
459
+ export default features.register("ipcSocket", IpcSocket);
@@ -0,0 +1,188 @@
1
+ import { z } from 'zod'
2
+ import { FeatureStateSchema, FeatureOptionsSchema } from '../../schemas/base.js'
3
+ import { Feature, features } from "../feature.js";
4
+ import { NodeContainer } from "../container.js";
5
+ import { camelCase, omit, set } from 'lodash-es';
6
+
7
+ /**
8
+ * Zod schema for the JsonTree feature state.
9
+ * Extends FeatureStateSchema and allows any additional string-keyed properties for tree data.
10
+ */
11
+ export const JsonTreeStateSchema = FeatureStateSchema.extend({}).catchall(z.any())
12
+ export type JsonTreeState = z.infer<typeof JsonTreeStateSchema>
13
+
14
+ /**
15
+ * JsonTree Feature - A powerful JSON file tree loader and processor
16
+ *
17
+ * This feature provides functionality to recursively load JSON files from a directory structure
18
+ * and build a hierarchical tree representation. It automatically processes file paths to create
19
+ * a nested object structure where file paths become object property paths.
20
+ *
21
+ * **Key Features:**
22
+ * - Recursive JSON file discovery in directory trees
23
+ * - Automatic path-to-property mapping using camelCase conversion
24
+ * - Integration with FileManager for efficient file operations
25
+ * - State-based tree storage and retrieval
26
+ * - Native JSON parsing for optimal performance
27
+ *
28
+ * **Path Processing:**
29
+ * Files are processed to create a nested object structure:
30
+ * - Directory names become object properties (camelCased)
31
+ * - File names become the final property names (without .json extension)
32
+ * - Nested directories create nested objects
33
+ *
34
+ * **Usage Example:**
35
+ * ```typescript
36
+ * const jsonTree = container.feature('jsonTree', { enable: true });
37
+ * await jsonTree.loadTree('data', 'appData');
38
+ * const userData = jsonTree.tree.appData.users.profiles;
39
+ * ```
40
+ *
41
+ * **Directory Structure Example:**
42
+ * ```
43
+ * data/
44
+ * users/
45
+ * profiles.json -> tree.data.users.profiles
46
+ * settings.json -> tree.data.users.settings
47
+ * config/
48
+ * app-config.json -> tree.data.config.appConfig
49
+ * ```
50
+ *
51
+ * @template T - The state type, defaults to JsonTreeState
52
+ * @extends {Feature<T>}
53
+ */
54
+ export class JsonTree<T extends JsonTreeState = JsonTreeState> extends Feature<T> {
55
+ /** The shortcut path for accessing this feature */
56
+ static override shortcut = "features.jsonTree" as const
57
+ static override stateSchema = JsonTreeStateSchema
58
+ static override optionsSchema = FeatureOptionsSchema
59
+
60
+ /**
61
+ * Attaches the JsonTree feature to a NodeContainer instance.
62
+ * Registers the feature in the container's feature registry for later use.
63
+ *
64
+ * @param container - The NodeContainer to attach to
65
+ * @returns The container for method chaining
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * // Typically called during container setup:
70
+ * JsonTree.attach(container)
71
+ * const jsonTree = container.feature('jsonTree')
72
+ * ```
73
+ */
74
+ static attach(container: NodeContainer & { jsonTree?: JsonTree }) {
75
+ container.features.register("jsonTree", JsonTree);
76
+ }
77
+
78
+ /**
79
+ * Loads a tree of JSON files from the specified base path and stores them in state.
80
+ *
81
+ * This method recursively scans the provided directory for JSON files, processes their
82
+ * content, and builds a hierarchical object structure. File paths are converted to
83
+ * camelCase property names, and the resulting tree is stored in the feature's state.
84
+ *
85
+ * **Processing Steps:**
86
+ * 1. Uses FileManager to discover all .json files recursively
87
+ * 2. Reads each file's content using the file system feature
88
+ * 3. Parses JSON content using native JSON.parse()
89
+ * 4. Converts file paths to nested object properties
90
+ * 5. Stores the complete tree in feature state
91
+ *
92
+ * **Path Transformation:**
93
+ * - Removes the base path prefix from file paths
94
+ * - Converts directory/file names to camelCase
95
+ * - Creates nested objects based on directory structure
96
+ * - Removes .json file extension
97
+ *
98
+ * **Example Transformation:**
99
+ * ```
100
+ * config/
101
+ * database/
102
+ * production.json -> tree.config.database.production
103
+ * staging.json -> tree.config.database.staging
104
+ * api/
105
+ * endpoints.json -> tree.config.api.endpoints
106
+ * ```
107
+ *
108
+ * @param basePath - The root directory path to scan for JSON files
109
+ * @param key - The key to store the tree under in state (defaults to first segment of basePath)
110
+ * @returns Promise resolving to the complete tree object
111
+ *
112
+ * @throws {Error} When FileManager fails to start or files cannot be read/parsed
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // Load all JSON files from 'data' directory into state.data
117
+ * await jsonTree.loadTree('data');
118
+ *
119
+ * // Load with custom key
120
+ * await jsonTree.loadTree('app/config', 'configuration');
121
+ *
122
+ * // Access the loaded data
123
+ * const dbConfig = jsonTree.tree.data.database.production;
124
+ * const apiEndpoints = jsonTree.tree.data.api.endpoints;
125
+ * ```
126
+ */
127
+ async loadTree(basePath: string, key: string = basePath.split('/')[0]!) {
128
+ const { container } = this ;
129
+ const fileManager = container.feature("fileManager");
130
+ const fileSystem = container.feature("fs");
131
+
132
+ await fileManager.start()
133
+
134
+ // Use the FileManager to find all JSON files in the tree.
135
+ const jsonFiles = fileManager.matchFiles([`${basePath}/**/*.json`]);
136
+
137
+ const tree: any = {};
138
+
139
+ for (const file of jsonFiles.filter(Boolean)) {
140
+ if (file?.relativePath) {
141
+ const fileContent = fileSystem.readFile(file.relativePath);
142
+ const fileData = JSON.parse(fileContent);
143
+ const path = file.relativePath
144
+ .replace(/\.json$/, "")
145
+ .replace(basePath + "/", "")
146
+ .split("/")
147
+ .filter((v) => v?.length)
148
+ .map((p) => camelCase(p));
149
+ set(tree, path, fileData);
150
+ }
151
+ }
152
+
153
+ // @ts-ignore-next-line
154
+ this.setState({ ...this.tree, [key]: tree });
155
+
156
+ return this.tree;
157
+ }
158
+
159
+ /**
160
+ * Gets the current tree data, excluding the 'enabled' state property.
161
+ *
162
+ * Returns a clean copy of the tree data without internal state management properties.
163
+ * This provides access to only the JSON tree data that has been loaded through loadTree().
164
+ *
165
+ * @returns The tree object containing all loaded JSON data, organized by keys
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * await jsonTree.loadTree('data');
170
+ * await jsonTree.loadTree('config', 'appConfig');
171
+ *
172
+ * const allTrees = jsonTree.tree;
173
+ * // Returns: {
174
+ * // data: { users: { ... }, products: { ... } },
175
+ * // appConfig: { database: { ... }, api: { ... } }
176
+ * // }
177
+ *
178
+ * // Access specific trees
179
+ * const userData = jsonTree.tree.data.users;
180
+ * const dbConfig = jsonTree.tree.appConfig.database;
181
+ * ```
182
+ */
183
+ get tree() {
184
+ return omit(this.state.current, 'enabled');
185
+ }
186
+ }
187
+
188
+ export default features.register("jsonTree", JsonTree);