@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,55 @@
1
+ import {
2
+ requireEnv,
3
+ describeWithRequirements,
4
+ createAGIContainer,
5
+ API_TIMEOUT,
6
+ } from './helpers'
7
+
8
+ const elevenLabsKey = requireEnv('ELEVENLABS_API_KEY')
9
+
10
+ describeWithRequirements('ElevenLabs Integration', [elevenLabsKey], () => {
11
+ let container: any
12
+ let el: any
13
+
14
+ beforeAll(async () => {
15
+ container = createAGIContainer()
16
+ el = container.client('elevenlabs', {
17
+ apiKey: elevenLabsKey.value,
18
+ })
19
+ await el.connect()
20
+ })
21
+
22
+ it(
23
+ 'listVoices returns available voices',
24
+ async () => {
25
+ const voices = await el.listVoices()
26
+ expect(Array.isArray(voices)).toBe(true)
27
+ expect(voices.length).toBeGreaterThan(0)
28
+ expect(voices[0]).toHaveProperty('voice_id')
29
+ expect(voices[0]).toHaveProperty('name')
30
+ },
31
+ API_TIMEOUT
32
+ )
33
+
34
+ it(
35
+ 'listModels returns available models',
36
+ async () => {
37
+ const models = await el.listModels()
38
+ expect(Array.isArray(models)).toBe(true)
39
+ expect(models.length).toBeGreaterThan(0)
40
+ },
41
+ API_TIMEOUT
42
+ )
43
+
44
+ it(
45
+ 'synthesize produces audio buffer',
46
+ async () => {
47
+ const audio = await el.synthesize('Hello, integration test.', {
48
+ voiceId: '21m00Tcm4TlvDq8ikWAM', // Rachel
49
+ })
50
+ expect(audio).toBeDefined()
51
+ expect(audio.length).toBeGreaterThan(0)
52
+ },
53
+ API_TIMEOUT
54
+ )
55
+ })
@@ -0,0 +1,80 @@
1
+ import {
2
+ requireEnv,
3
+ describeWithRequirements,
4
+ createAGIContainer,
5
+ API_TIMEOUT,
6
+ } from './helpers'
7
+
8
+ const serviceAccountKey = requireEnv('GOOGLE_SERVICE_ACCOUNT_KEY')
9
+
10
+ describeWithRequirements('Google Services Integration', [serviceAccountKey], () => {
11
+ let container: any
12
+
13
+ beforeAll(async () => {
14
+ container = createAGIContainer()
15
+ const auth = container.feature('googleAuth', {
16
+ scopes: [
17
+ 'https://www.googleapis.com/auth/spreadsheets.readonly',
18
+ 'https://www.googleapis.com/auth/calendar.readonly',
19
+ ],
20
+ })
21
+ await auth.authenticateServiceAccount()
22
+ })
23
+
24
+ describe('Google Sheets', () => {
25
+ it(
26
+ 'getSpreadsheet returns metadata when given a valid spreadsheet ID',
27
+ async () => {
28
+ const sheets = container.feature('googleSheets')
29
+ // This test requires GOOGLE_TEST_SPREADSHEET_ID to be set
30
+ const spreadsheetId = process.env.GOOGLE_TEST_SPREADSHEET_ID
31
+ if (!spreadsheetId) {
32
+ console.log('GOOGLE_TEST_SPREADSHEET_ID not set, skipping sheets data test')
33
+ return
34
+ }
35
+ const meta = await sheets.getSpreadsheet(spreadsheetId)
36
+ expect(meta).toBeDefined()
37
+ expect(meta.spreadsheetId).toBe(spreadsheetId)
38
+ },
39
+ API_TIMEOUT
40
+ )
41
+
42
+ it(
43
+ 'listSheets returns sheet names',
44
+ async () => {
45
+ const sheets = container.feature('googleSheets')
46
+ const spreadsheetId = process.env.GOOGLE_TEST_SPREADSHEET_ID
47
+ if (!spreadsheetId) {
48
+ console.log('GOOGLE_TEST_SPREADSHEET_ID not set, skipping')
49
+ return
50
+ }
51
+ const sheetList = await sheets.listSheets(spreadsheetId)
52
+ expect(Array.isArray(sheetList)).toBe(true)
53
+ expect(sheetList.length).toBeGreaterThan(0)
54
+ },
55
+ API_TIMEOUT
56
+ )
57
+ })
58
+
59
+ describe('Google Calendar', () => {
60
+ it(
61
+ 'listCalendars returns at least one calendar',
62
+ async () => {
63
+ const calendar = container.feature('googleCalendar')
64
+ const calendars = await calendar.listCalendars()
65
+ expect(Array.isArray(calendars)).toBe(true)
66
+ },
67
+ API_TIMEOUT
68
+ )
69
+
70
+ it(
71
+ 'getToday returns events array',
72
+ async () => {
73
+ const calendar = container.feature('googleCalendar')
74
+ const events = await calendar.getToday()
75
+ expect(Array.isArray(events)).toBe(true)
76
+ },
77
+ API_TIMEOUT
78
+ )
79
+ })
80
+ })
@@ -0,0 +1,89 @@
1
+ import { AGIContainer } from '../src/agi/container.server'
2
+ import { NodeContainer } from '../src/node/container'
3
+ import { mkdtempSync, rmSync, realpathSync } from 'fs'
4
+ import { join } from 'path'
5
+ import { tmpdir } from 'os'
6
+ import { execSync } from 'child_process'
7
+
8
+ /**
9
+ * Checks that an environment variable is set.
10
+ * Returns its value, or calls describe.skip-style logic.
11
+ * Use at the top of describe blocks — if missing, the value will be empty string
12
+ * and `shouldSkip()` returns the skip reason.
13
+ */
14
+ export function requireEnv(name: string): { value: string; skip?: string } {
15
+ const value = process.env[name]
16
+ if (!value) {
17
+ return { value: '', skip: `${name} not set, skipping` }
18
+ }
19
+ return { value }
20
+ }
21
+
22
+ /**
23
+ * Checks that a binary is available on PATH.
24
+ * Returns the path or a skip reason.
25
+ */
26
+ export function requireBinary(name: string): { path: string; skip?: string } {
27
+ try {
28
+ const result = execSync(`which ${name}`, { encoding: 'utf-8' }).trim()
29
+ return { path: result }
30
+ } catch {
31
+ return { path: '', skip: `'${name}' binary not found in PATH, skipping` }
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Creates a describe block that skips if any of the provided checks have skip reasons.
37
+ */
38
+ export function describeWithRequirements(
39
+ title: string,
40
+ checks: Array<{ skip?: string }>,
41
+ fn: () => void
42
+ ) {
43
+ const skipReason = checks.find((c) => c.skip)?.skip
44
+ if (skipReason) {
45
+ describe.skip(`${title} (${skipReason})`, fn)
46
+ } else {
47
+ describe(title, fn)
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Creates an AGIContainer for integration tests.
53
+ */
54
+ export function createAGIContainer(opts?: { cwd?: string }): any {
55
+ const options = opts?.cwd ? { cwd: opts.cwd } : undefined
56
+ return new (AGIContainer as any)(options)
57
+ }
58
+
59
+ /**
60
+ * Creates a NodeContainer with an optional temp directory.
61
+ * If useTempDir is true, creates a temp directory and cleans up on dispose.
62
+ */
63
+ export function createNodeContainer(opts?: {
64
+ cwd?: string
65
+ useTempDir?: boolean
66
+ }): { container: NodeContainer; tempDir?: string; cleanup: () => void } {
67
+ if (opts?.useTempDir) {
68
+ const tempDir = realpathSync(mkdtempSync(join(tmpdir(), 'luca-integ-')))
69
+ const container = new NodeContainer({ cwd: tempDir })
70
+ return {
71
+ container,
72
+ tempDir,
73
+ cleanup: () => rmSync(tempDir, { recursive: true, force: true }),
74
+ }
75
+ }
76
+
77
+ const container = new NodeContainer({ cwd: opts?.cwd || process.cwd() })
78
+ return { container, cleanup: () => {} }
79
+ }
80
+
81
+ /**
82
+ * Default timeout for API-calling tests (30 seconds).
83
+ */
84
+ export const API_TIMEOUT = 30_000
85
+
86
+ /**
87
+ * Extended timeout for slow operations like CLI subprocesses (60 seconds).
88
+ */
89
+ export const CLI_TIMEOUT = 60_000
@@ -0,0 +1,93 @@
1
+ import {
2
+ requireEnv,
3
+ requireBinary,
4
+ describeWithRequirements,
5
+ createAGIContainer,
6
+ CLI_TIMEOUT,
7
+ } from './helpers'
8
+ import type { AGIContainer } from '../src/agi/container.server'
9
+
10
+ const openaiKey = requireEnv('OPENAI_API_KEY')
11
+ const codexBin = requireBinary('codex')
12
+
13
+ describeWithRequirements(
14
+ 'OpenAI Codex Integration',
15
+ [openaiKey, codexBin],
16
+ () => {
17
+ let container: AGIContainer
18
+
19
+ beforeAll(() => {
20
+ container = createAGIContainer()
21
+ })
22
+
23
+ it(
24
+ 'checkAvailability confirms codex is installed',
25
+ async () => {
26
+ const codex = container.feature('openaiCodex')
27
+ const available = await codex.checkAvailability()
28
+ expect(available).toBe(true)
29
+ },
30
+ CLI_TIMEOUT
31
+ )
32
+
33
+ it(
34
+ 'run() with a simple prompt in read-only sandbox returns a session',
35
+ async () => {
36
+ const codex = container.feature('openaiCodex', {
37
+ sandbox: 'read-only',
38
+ model: 'o4-mini',
39
+ })
40
+
41
+ const session = await codex.run(
42
+ 'Reply with exactly: CODEX_TEST_OK',
43
+ {
44
+ sandbox: 'read-only',
45
+ }
46
+ )
47
+
48
+ expect(session).toBeDefined()
49
+ expect(session.status).toBe('completed')
50
+ expect(typeof session.result).toBe('string')
51
+ },
52
+ CLI_TIMEOUT
53
+ )
54
+
55
+ it(
56
+ 'session events fire during execution',
57
+ async () => {
58
+ const codex = container.feature('openaiCodex', {
59
+ sandbox: 'read-only',
60
+ model: 'o4-mini',
61
+ })
62
+
63
+ const events: string[] = []
64
+ codex.on('session:start', () => events.push('start'))
65
+ codex.on('session:result', () => events.push('result'))
66
+
67
+ await codex.run('Say hello', { sandbox: 'read-only' })
68
+
69
+ expect(events).toContain('start')
70
+ expect(events).toContain('result')
71
+ },
72
+ CLI_TIMEOUT
73
+ )
74
+
75
+ it(
76
+ 'session items are populated from event stream',
77
+ async () => {
78
+ const codex = container.feature('openaiCodex', {
79
+ sandbox: 'read-only',
80
+ model: 'o4-mini',
81
+ })
82
+
83
+ const session = await codex.run('What is 2+2? Reply with just the number.', {
84
+ sandbox: 'read-only',
85
+ })
86
+
87
+ // Items array should exist even if empty
88
+ expect(Array.isArray(session.items)).toBe(true)
89
+ },
90
+ CLI_TIMEOUT
91
+ )
92
+ }
93
+ )
@@ -0,0 +1,58 @@
1
+ import {
2
+ requireEnv,
3
+ describeWithRequirements,
4
+ createAGIContainer,
5
+ API_TIMEOUT,
6
+ } from './helpers'
7
+
8
+ const runpodKey = requireEnv('RUNPOD_API_KEY')
9
+
10
+ describeWithRequirements('RunPod Integration', [runpodKey], () => {
11
+ let container: any
12
+ let runpod: any
13
+
14
+ beforeAll(() => {
15
+ container = createAGIContainer()
16
+ runpod = container.feature('runpod', {
17
+ apiKey: runpodKey.value,
18
+ })
19
+ })
20
+
21
+ it(
22
+ 'lists templates (read-only)',
23
+ async () => {
24
+ const templates = await runpod.listTemplates({ includeRunpod: true })
25
+ expect(Array.isArray(templates)).toBe(true)
26
+ expect(templates.length).toBeGreaterThan(0)
27
+ },
28
+ API_TIMEOUT
29
+ )
30
+
31
+ it(
32
+ 'lists secure GPU availability',
33
+ async () => {
34
+ const gpus = await runpod.listSecureGPUs()
35
+ expect(Array.isArray(gpus)).toBe(true)
36
+ expect(gpus.length).toBeGreaterThan(0)
37
+ },
38
+ API_TIMEOUT
39
+ )
40
+
41
+ it(
42
+ 'lists network volumes',
43
+ async () => {
44
+ const volumes = await runpod.listVolumes()
45
+ expect(Array.isArray(volumes)).toBe(true)
46
+ },
47
+ API_TIMEOUT
48
+ )
49
+
50
+ it(
51
+ 'lists existing pods',
52
+ async () => {
53
+ const pods = await runpod.listPods()
54
+ expect(Array.isArray(pods)).toBe(true)
55
+ },
56
+ API_TIMEOUT
57
+ )
58
+ })
@@ -0,0 +1,97 @@
1
+ import {
2
+ requireEnv,
3
+ describeWithRequirements,
4
+ createAGIContainer,
5
+ API_TIMEOUT,
6
+ } from './helpers'
7
+
8
+ const openaiKey = requireEnv('OPENAI_API_KEY')
9
+
10
+ describeWithRequirements('Server & Endpoints Integration', [openaiKey], () => {
11
+ let container: any
12
+ let server: any
13
+ let port: number
14
+
15
+ beforeAll(async () => {
16
+ container = createAGIContainer()
17
+
18
+ server = container.server('express', {
19
+ port: 0,
20
+ cors: true,
21
+ create: (app: any) => {
22
+ app.get('/health', (_req: any, res: any) => {
23
+ res.json({ status: 'ok' })
24
+ })
25
+ return app
26
+ },
27
+ })
28
+
29
+ await server.start()
30
+ port = server.port
31
+ }, API_TIMEOUT)
32
+
33
+ afterAll(async () => {
34
+ if (server?.isListening) {
35
+ await server.stop()
36
+ }
37
+ })
38
+
39
+ it('server starts and reports listening', () => {
40
+ expect(server.isListening).toBe(true)
41
+ expect(port).toBeGreaterThan(0)
42
+ })
43
+
44
+ it(
45
+ 'health endpoint returns OK',
46
+ async () => {
47
+ const res = await fetch(`http://localhost:${port}/health`)
48
+ expect(res.status).toBe(200)
49
+ const body = await res.json()
50
+ expect(body.status).toBe('ok')
51
+ },
52
+ API_TIMEOUT
53
+ )
54
+
55
+ it(
56
+ 'loads AGI endpoints directory',
57
+ async () => {
58
+ const agiEndpointsDir = container.paths.resolve(
59
+ 'src',
60
+ 'agi',
61
+ 'endpoints'
62
+ )
63
+
64
+ if (container.fs.exists(agiEndpointsDir)) {
65
+ await server.useEndpoints(agiEndpointsDir)
66
+ // After loading endpoints, the /ask endpoint should be available
67
+ const res = await fetch(`http://localhost:${port}/ask`, {
68
+ method: 'POST',
69
+ headers: { 'Content-Type': 'application/json' },
70
+ body: JSON.stringify({
71
+ question: 'Reply with exactly: ENDPOINT_TEST_OK',
72
+ model: 'gpt-4o-mini',
73
+ }),
74
+ })
75
+ // The endpoint may stream SSE or return JSON
76
+ expect(res.status).toBeLessThan(500)
77
+ }
78
+ },
79
+ API_TIMEOUT
80
+ )
81
+
82
+ it(
83
+ 'server shuts down cleanly',
84
+ async () => {
85
+ const testServer = container.server('express', {
86
+ port: 0,
87
+ cors: true,
88
+ })
89
+ await testServer.start()
90
+ expect(testServer.isListening).toBe(true)
91
+
92
+ await testServer.stop()
93
+ expect(testServer.isStopped).toBe(true)
94
+ },
95
+ API_TIMEOUT
96
+ )
97
+ })
@@ -0,0 +1,157 @@
1
+ import { createAGIContainer } from './helpers'
2
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from 'fs'
3
+ import { join } from 'path'
4
+ import { tmpdir } from 'os'
5
+
6
+ describe('Skills Library Integration', () => {
7
+ let container: any
8
+ let tempDir: string
9
+ let skillsDir: string
10
+
11
+ beforeAll(async () => {
12
+ tempDir = realpathSync(mkdtempSync(join(tmpdir(), 'luca-skills-test-')))
13
+ skillsDir = join(tempDir, '.claude', 'skills')
14
+
15
+ // Create a test skill
16
+ const testSkillDir = join(skillsDir, 'code-review')
17
+ mkdirSync(testSkillDir, { recursive: true })
18
+ writeFileSync(
19
+ join(testSkillDir, 'SKILL.md'),
20
+ `---
21
+ name: code-review
22
+ description: Reviews code for common issues and suggests improvements
23
+ version: 1.0.0
24
+ tags:
25
+ - code
26
+ - review
27
+ ---
28
+
29
+ ## Instructions
30
+
31
+ Review the provided code for:
32
+ 1. Common bugs and anti-patterns
33
+ 2. Performance issues
34
+ 3. Security vulnerabilities
35
+ `
36
+ )
37
+
38
+ // Create another test skill
39
+ const debugSkillDir = join(skillsDir, 'debug-helper')
40
+ mkdirSync(debugSkillDir, { recursive: true })
41
+ writeFileSync(
42
+ join(debugSkillDir, 'SKILL.md'),
43
+ `---
44
+ name: debug-helper
45
+ description: Helps debug runtime errors and exceptions
46
+ version: 1.0.0
47
+ tags:
48
+ - debug
49
+ - errors
50
+ ---
51
+
52
+ ## Instructions
53
+
54
+ Help the user debug their issue by asking clarifying questions.
55
+ `
56
+ )
57
+
58
+ container = createAGIContainer({ cwd: tempDir })
59
+ })
60
+
61
+ afterAll(() => {
62
+ rmSync(tempDir, { recursive: true, force: true })
63
+ })
64
+
65
+ it('loads skills from project directory', async () => {
66
+ const skills = container.feature('skillsLibrary', {
67
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
68
+ })
69
+ await skills.load()
70
+
71
+ const list = skills.list()
72
+ expect(list.length).toBeGreaterThanOrEqual(2)
73
+ })
74
+
75
+ it('finds a skill by name', async () => {
76
+ const skills = container.feature('skillsLibrary', {
77
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
78
+ })
79
+ await skills.load()
80
+
81
+ const entry = skills.find('code-review')
82
+ expect(entry).toBeDefined()
83
+ expect(entry!.name).toBe('code-review')
84
+ expect(entry!.description).toContain('Reviews code')
85
+ })
86
+
87
+ it('searches skills by keyword', async () => {
88
+ const skills = container.feature('skillsLibrary', {
89
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
90
+ })
91
+ await skills.load()
92
+
93
+ const results = skills.search('debug')
94
+ expect(results.length).toBeGreaterThanOrEqual(1)
95
+ expect(results[0].name).toBe('debug-helper')
96
+ })
97
+
98
+ it('creates a new skill', async () => {
99
+ const skills = container.feature('skillsLibrary', {
100
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
101
+ })
102
+ await skills.load()
103
+
104
+ const entry = await skills.create(
105
+ {
106
+ name: 'test-new-skill',
107
+ description: 'A skill created during testing',
108
+ body: '## Instructions\n\nDo test things.',
109
+ meta: { tags: ['test'], version: '0.1.0' },
110
+ },
111
+ 'project'
112
+ )
113
+
114
+ expect(entry).toBeDefined()
115
+ expect(entry.name).toBe('test-new-skill')
116
+
117
+ // Verify it's findable
118
+ const found = skills.find('test-new-skill')
119
+ expect(found).toBeDefined()
120
+ })
121
+
122
+ it('removes a skill', async () => {
123
+ const skills = container.feature('skillsLibrary', {
124
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
125
+ })
126
+ await skills.load()
127
+
128
+ // Create one to remove
129
+ await skills.create(
130
+ {
131
+ name: 'to-remove',
132
+ description: 'Will be removed',
133
+ body: '## Instructions\n\nRemove me.',
134
+ meta: {},
135
+ },
136
+ 'project'
137
+ )
138
+
139
+ const removed = await skills.remove('to-remove')
140
+ expect(removed).toBe(true)
141
+
142
+ const found = skills.find('to-remove')
143
+ expect(found).toBeUndefined()
144
+ })
145
+
146
+ it('generates system prompt block', async () => {
147
+ const skills = container.feature('skillsLibrary', {
148
+ projectSkillsPath: join(tempDir, '.claude', 'skills'),
149
+ })
150
+ await skills.load()
151
+
152
+ const block = skills.toSystemPromptBlock()
153
+ expect(typeof block).toBe('string')
154
+ expect(block).toContain('code-review')
155
+ expect(block).toContain('debug-helper')
156
+ })
157
+ })
@@ -0,0 +1,46 @@
1
+ import {
2
+ requireEnv,
3
+ describeWithRequirements,
4
+ createAGIContainer,
5
+ API_TIMEOUT,
6
+ } from './helpers'
7
+
8
+ const telegramToken = requireEnv('TELEGRAM_BOT_TOKEN')
9
+
10
+ describeWithRequirements('Telegram Integration', [telegramToken], () => {
11
+ let container: any
12
+ let tg: any
13
+
14
+ beforeAll(async () => {
15
+ container = createAGIContainer()
16
+ tg = container.feature('telegram', {
17
+ token: telegramToken.value,
18
+ autoStart: false,
19
+ pollingTimeout: 0,
20
+ })
21
+ await tg.enable()
22
+ })
23
+
24
+ it(
25
+ 'getMe returns bot info',
26
+ async () => {
27
+ const me = await tg.getMe()
28
+ expect(me).toBeDefined()
29
+ expect(me.id).toBeDefined()
30
+ expect(typeof me.first_name).toBe('string')
31
+ expect(me.is_bot).toBe(true)
32
+ },
33
+ API_TIMEOUT
34
+ )
35
+
36
+ it('command registration works', () => {
37
+ tg.command('test_integ', (ctx: any) => ctx.reply('test'))
38
+ // If command registration didn't throw, it's working
39
+ expect(true).toBe(true)
40
+ })
41
+
42
+ it('bot instance is accessible', () => {
43
+ expect(tg.bot).toBeDefined()
44
+ expect(tg.bot.api).toBeDefined()
45
+ })
46
+ })