@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.
- package/CLAUDE.md +71 -0
- package/README.md +78 -0
- package/bun.lock +2928 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-scaffolds.ts +154 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/update-introspection.ts +67 -0
- package/docs/CLI.md +335 -0
- package/docs/README.md +88 -0
- package/docs/TABLE-OF-CONTENTS.md +157 -0
- package/docs/apis/clients/elevenlabs.md +84 -0
- package/docs/apis/clients/graph.md +56 -0
- package/docs/apis/clients/openai.md +69 -0
- package/docs/apis/clients/rest.md +41 -0
- package/docs/apis/clients/websocket.md +107 -0
- package/docs/apis/features/agi/assistant.md +471 -0
- package/docs/apis/features/agi/assistants-manager.md +154 -0
- package/docs/apis/features/agi/claude-code.md +602 -0
- package/docs/apis/features/agi/conversation-history.md +352 -0
- package/docs/apis/features/agi/conversation.md +333 -0
- package/docs/apis/features/agi/docs-reader.md +121 -0
- package/docs/apis/features/agi/openai-codex.md +318 -0
- package/docs/apis/features/agi/openapi.md +138 -0
- package/docs/apis/features/agi/semantic-search.md +387 -0
- package/docs/apis/features/agi/skills-library.md +216 -0
- package/docs/apis/features/node/container-link.md +133 -0
- package/docs/apis/features/node/content-db.md +313 -0
- package/docs/apis/features/node/disk-cache.md +379 -0
- package/docs/apis/features/node/dns.md +651 -0
- package/docs/apis/features/node/docker.md +705 -0
- package/docs/apis/features/node/downloader.md +81 -0
- package/docs/apis/features/node/esbuild.md +59 -0
- package/docs/apis/features/node/file-manager.md +182 -0
- package/docs/apis/features/node/fs.md +581 -0
- package/docs/apis/features/node/git.md +330 -0
- package/docs/apis/features/node/google-auth.md +174 -0
- package/docs/apis/features/node/google-calendar.md +187 -0
- package/docs/apis/features/node/google-docs.md +151 -0
- package/docs/apis/features/node/google-drive.md +225 -0
- package/docs/apis/features/node/google-sheets.md +179 -0
- package/docs/apis/features/node/grep.md +290 -0
- package/docs/apis/features/node/helpers.md +135 -0
- package/docs/apis/features/node/ink.md +334 -0
- package/docs/apis/features/node/ipc-socket.md +260 -0
- package/docs/apis/features/node/json-tree.md +86 -0
- package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
- package/docs/apis/features/node/networking.md +281 -0
- package/docs/apis/features/node/nlp.md +133 -0
- package/docs/apis/features/node/opener.md +97 -0
- package/docs/apis/features/node/os.md +118 -0
- package/docs/apis/features/node/package-finder.md +402 -0
- package/docs/apis/features/node/postgres.md +212 -0
- package/docs/apis/features/node/proc.md +430 -0
- package/docs/apis/features/node/process-manager.md +210 -0
- package/docs/apis/features/node/python.md +278 -0
- package/docs/apis/features/node/repl.md +88 -0
- package/docs/apis/features/node/runpod.md +673 -0
- package/docs/apis/features/node/secure-shell.md +169 -0
- package/docs/apis/features/node/semantic-search.md +401 -0
- package/docs/apis/features/node/sqlite.md +211 -0
- package/docs/apis/features/node/telegram.md +254 -0
- package/docs/apis/features/node/tts.md +118 -0
- package/docs/apis/features/node/ui.md +703 -0
- package/docs/apis/features/node/vault.md +64 -0
- package/docs/apis/features/node/vm.md +84 -0
- package/docs/apis/features/node/window-manager.md +337 -0
- package/docs/apis/features/node/yaml-tree.md +85 -0
- package/docs/apis/features/node/yaml.md +176 -0
- package/docs/apis/features/web/asset-loader.md +47 -0
- package/docs/apis/features/web/container-link.md +133 -0
- package/docs/apis/features/web/esbuild.md +59 -0
- package/docs/apis/features/web/helpers.md +135 -0
- package/docs/apis/features/web/network.md +30 -0
- package/docs/apis/features/web/speech.md +55 -0
- package/docs/apis/features/web/vault.md +64 -0
- package/docs/apis/features/web/vm.md +84 -0
- package/docs/apis/features/web/voice.md +67 -0
- package/docs/apis/servers/express.md +127 -0
- package/docs/apis/servers/mcp.md +213 -0
- package/docs/apis/servers/websocket.md +99 -0
- package/docs/documentation-audit.md +134 -0
- package/docs/examples/content-db.md +77 -0
- package/docs/examples/disk-cache.md +83 -0
- package/docs/examples/docker.md +101 -0
- package/docs/examples/downloader.md +70 -0
- package/docs/examples/esbuild.md +80 -0
- package/docs/examples/file-manager.md +82 -0
- package/docs/examples/fs.md +83 -0
- package/docs/examples/git.md +85 -0
- package/docs/examples/google-auth.md +88 -0
- package/docs/examples/google-calendar.md +94 -0
- package/docs/examples/google-docs.md +82 -0
- package/docs/examples/google-drive.md +96 -0
- package/docs/examples/google-sheets.md +95 -0
- package/docs/examples/grep.md +85 -0
- package/docs/examples/ink-blocks.md +75 -0
- package/docs/examples/ink-renderer.md +41 -0
- package/docs/examples/ink.md +103 -0
- package/docs/examples/ipc-socket.md +103 -0
- package/docs/examples/json-tree.md +91 -0
- package/docs/examples/launcher-app-command-listener.md +120 -0
- package/docs/examples/networking.md +58 -0
- package/docs/examples/nlp.md +91 -0
- package/docs/examples/opener.md +78 -0
- package/docs/examples/os.md +72 -0
- package/docs/examples/package-finder.md +89 -0
- package/docs/examples/port-exposer.md +89 -0
- package/docs/examples/postgres.md +91 -0
- package/docs/examples/proc.md +81 -0
- package/docs/examples/process-manager.md +79 -0
- package/docs/examples/python.md +91 -0
- package/docs/examples/repl.md +93 -0
- package/docs/examples/runpod.md +119 -0
- package/docs/examples/secure-shell.md +92 -0
- package/docs/examples/sqlite.md +86 -0
- package/docs/examples/telegram.md +77 -0
- package/docs/examples/tts.md +86 -0
- package/docs/examples/ui.md +80 -0
- package/docs/examples/vault.md +70 -0
- package/docs/examples/vm.md +86 -0
- package/docs/examples/window-manager.md +125 -0
- package/docs/examples/yaml-tree.md +93 -0
- package/docs/examples/yaml.md +104 -0
- package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
- package/docs/ideas/container-use-api.md +9 -0
- package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
- package/docs/ideas/feature-stacks.md +22 -0
- package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
- package/docs/ideas/mcp-design.md +9 -0
- package/docs/ideas/web-container-debugging-feature.md +13 -0
- package/docs/introspection-audit.md +49 -0
- package/docs/introspection.md +154 -0
- package/docs/mcp/readme.md +162 -0
- package/docs/models.ts +38 -0
- package/docs/philosophy.md +85 -0
- package/docs/principles.md +7 -0
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
- package/docs/prompts/mcp-test-easy-command.md +27 -0
- package/docs/reports/assistant-bugs.md +38 -0
- package/docs/reports/attach-pattern-usage.md +18 -0
- package/docs/reports/code-audit-results.md +391 -0
- package/docs/reports/introspection-audit-tasks.md +378 -0
- package/docs/reports/luca-mcp-improvements.md +128 -0
- package/docs/scaffolds/client.md +140 -0
- package/docs/scaffolds/command.md +106 -0
- package/docs/scaffolds/endpoint.md +176 -0
- package/docs/scaffolds/feature.md +148 -0
- package/docs/scaffolds/server.md +187 -0
- package/docs/tasks/web-container-helper-discovery.md +71 -0
- package/docs/todos.md +1 -0
- package/docs/tutorials/01-getting-started.md +106 -0
- package/docs/tutorials/02-container.md +210 -0
- package/docs/tutorials/03-scripts.md +194 -0
- package/docs/tutorials/04-features-overview.md +196 -0
- package/docs/tutorials/05-state-and-events.md +171 -0
- package/docs/tutorials/06-servers.md +157 -0
- package/docs/tutorials/07-endpoints.md +198 -0
- package/docs/tutorials/08-commands.md +171 -0
- package/docs/tutorials/09-clients.md +162 -0
- package/docs/tutorials/10-creating-features.md +198 -0
- package/docs/tutorials/11-contentbase.md +191 -0
- package/docs/tutorials/12-assistants.md +215 -0
- package/docs/tutorials/13-introspection.md +147 -0
- package/docs/tutorials/14-type-system.md +174 -0
- package/docs/tutorials/15-project-patterns.md +222 -0
- package/docs/tutorials/16-google-features.md +534 -0
- package/docs/tutorials/17-tui-blocks.md +530 -0
- package/docs/tutorials/18-semantic-search.md +334 -0
- package/index.ts +1 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +154 -0
- package/pyproject.toml +7 -0
- package/scripts/animations/chrome-glitch.ts +55 -0
- package/scripts/animations/index.ts +16 -0
- package/scripts/animations/neon-pulse.ts +64 -0
- package/scripts/animations/types.ts +6 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/telegram-ink-ui.ts +302 -0
- package/scripts/examples/using-assistant-with-mcp.ts +560 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +10 -0
- package/scripts/examples/using-openai-codex.ts +23 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/examples/vm-loading-esm-modules.ts +16 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/test-command-listener.ts +123 -0
- package/scripts/test-window-manager-lifecycle.ts +86 -0
- package/scripts/test-window-manager.ts +43 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +114 -0
- package/src/agi/endpoints/ask.ts +60 -0
- package/src/agi/endpoints/conversations/[id].ts +45 -0
- package/src/agi/endpoints/conversations.ts +31 -0
- package/src/agi/endpoints/experts.ts +37 -0
- package/src/agi/features/assistant.ts +767 -0
- package/src/agi/features/assistants-manager.ts +260 -0
- package/src/agi/features/claude-code.ts +1111 -0
- package/src/agi/features/conversation-history.ts +497 -0
- package/src/agi/features/conversation.ts +799 -0
- package/src/agi/features/openai-codex.ts +631 -0
- package/src/agi/features/openapi.ts +438 -0
- package/src/agi/features/skills-library.ts +425 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/token-counter.ts +122 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +100 -0
- package/src/cli/cli.ts +70 -0
- package/src/client.ts +461 -0
- package/src/clients/civitai/index.ts +541 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +597 -0
- package/src/clients/elevenlabs/index.ts +291 -0
- package/src/clients/openai/index.ts +451 -0
- package/src/clients/supabase/index.ts +366 -0
- package/src/command.ts +164 -0
- package/src/commands/chat.ts +182 -0
- package/src/commands/console.ts +192 -0
- package/src/commands/describe.ts +433 -0
- package/src/commands/eval.ts +116 -0
- package/src/commands/help.ts +214 -0
- package/src/commands/index.ts +14 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +807 -0
- package/src/commands/run.ts +257 -0
- package/src/commands/sandbox-mcp.ts +439 -0
- package/src/commands/scaffold.ts +79 -0
- package/src/commands/serve.ts +172 -0
- package/src/container.ts +781 -0
- package/src/endpoint.ts +340 -0
- package/src/feature.ts +75 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +543 -0
- package/src/introspection/generated.agi.ts +23388 -0
- package/src/introspection/generated.node.ts +18899 -0
- package/src/introspection/generated.web.ts +2021 -0
- package/src/introspection/index.ts +256 -0
- package/src/introspection/scan.ts +912 -0
- package/src/node/container.ts +354 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +558 -0
- package/src/node/features/content-db.ts +475 -0
- package/src/node/features/disk-cache.ts +382 -0
- package/src/node/features/dns.ts +655 -0
- package/src/node/features/docker.ts +912 -0
- package/src/node/features/downloader.ts +92 -0
- package/src/node/features/esbuild.ts +68 -0
- package/src/node/features/file-manager.ts +357 -0
- package/src/node/features/fs.ts +534 -0
- package/src/node/features/git.ts +492 -0
- package/src/node/features/google-auth.ts +502 -0
- package/src/node/features/google-calendar.ts +300 -0
- package/src/node/features/google-docs.ts +404 -0
- package/src/node/features/google-drive.ts +339 -0
- package/src/node/features/google-sheets.ts +279 -0
- package/src/node/features/grep.ts +406 -0
- package/src/node/features/helpers.ts +374 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +459 -0
- package/src/node/features/json-tree.ts +188 -0
- package/src/node/features/launcher-app-command-listener.ts +388 -0
- package/src/node/features/networking.ts +925 -0
- package/src/node/features/nlp.ts +211 -0
- package/src/node/features/opener.ts +166 -0
- package/src/node/features/os.ts +157 -0
- package/src/node/features/package-finder.ts +539 -0
- package/src/node/features/port-exposer.ts +342 -0
- package/src/node/features/postgres.ts +273 -0
- package/src/node/features/proc.ts +502 -0
- package/src/node/features/process-manager.ts +542 -0
- package/src/node/features/python.ts +444 -0
- package/src/node/features/repl.ts +194 -0
- package/src/node/features/runpod.ts +802 -0
- package/src/node/features/secure-shell.ts +248 -0
- package/src/node/features/semantic-search.ts +924 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +342 -0
- package/src/node/features/tts.ts +184 -0
- package/src/node/features/ui.ts +857 -0
- package/src/node/features/vault.ts +164 -0
- package/src/node/features/vm.ts +312 -0
- package/src/node/features/window-manager.ts +804 -0
- package/src/node/features/yaml-tree.ts +149 -0
- package/src/node/features/yaml.ts +132 -0
- package/src/node.ts +70 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +199 -0
- package/src/scaffolds/generated.ts +1613 -0
- package/src/scaffolds/template.ts +37 -0
- package/src/schemas/base.ts +255 -0
- package/src/server.ts +135 -0
- package/src/servers/express.ts +209 -0
- package/src/servers/mcp.ts +805 -0
- package/src/servers/socket.ts +120 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +82 -0
- package/src/web/container.ts +74 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +64 -0
- package/src/web/features/container-link.ts +385 -0
- package/src/web/features/esbuild.ts +79 -0
- package/src/web/features/helpers.ts +267 -0
- package/src/web/features/network.ts +61 -0
- package/src/web/features/speech.ts +87 -0
- package/src/web/features/vault.ts +189 -0
- package/src/web/features/vm.ts +78 -0
- package/src/web/features/voice-recognition.ts +129 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/test/bus.test.ts +134 -0
- package/test/clients-servers.test.ts +216 -0
- package/test/container-link.test.ts +274 -0
- package/test/features.test.ts +160 -0
- package/test/integration.test.ts +787 -0
- package/test/node-container.test.ts +121 -0
- package/test/rate-limit.test.ts +272 -0
- package/test/semantic-search.test.ts +550 -0
- package/test/state.test.ts +121 -0
- package/test-integration/assistant.test.ts +138 -0
- package/test-integration/assistants-manager.test.ts +123 -0
- package/test-integration/claude-code.test.ts +98 -0
- package/test-integration/conversation-history.test.ts +205 -0
- package/test-integration/conversation.test.ts +137 -0
- package/test-integration/elevenlabs.test.ts +55 -0
- package/test-integration/google-services.test.ts +80 -0
- package/test-integration/helpers.ts +89 -0
- package/test-integration/openai-codex.test.ts +93 -0
- package/test-integration/runpod.test.ts +58 -0
- package/test-integration/server-endpoints.test.ts +97 -0
- package/test-integration/skills-library.test.ts +157 -0
- package/test-integration/telegram.test.ts +46 -0
- package/tsconfig.json +58 -0
- package/uv.lock +8 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Semantic Search
|
|
3
|
+
tags: [semantic-search, embeddings, vector-search, bm25, hybrid-search, sqlite, contentdb]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Semantic Search
|
|
7
|
+
|
|
8
|
+
Luca's `semanticSearch` feature provides BM25 keyword search, vector similarity search, and hybrid search with Reciprocal Rank Fusion -- all backed by SQLite. It chunks documents intelligently, generates embeddings via OpenAI or a local GGUF model, and stores everything in a single `.sqlite` file.
|
|
9
|
+
|
|
10
|
+
## Quick Start with ContentDb
|
|
11
|
+
|
|
12
|
+
The fastest way to use semantic search is through the `contentDb` feature, which handles indexing and querying automatically:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import container from '@soederpop/luca'
|
|
16
|
+
|
|
17
|
+
const db = container.feature('contentDb', { rootPath: './docs' })
|
|
18
|
+
await db.load()
|
|
19
|
+
|
|
20
|
+
// Build the search index (generates embeddings for all documents)
|
|
21
|
+
await db.buildSearchIndex({
|
|
22
|
+
onProgress: (indexed, total) => console.log(`${indexed}/${total}`)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Search your documents
|
|
26
|
+
const results = await db.hybridSearch('how does authentication work')
|
|
27
|
+
for (const r of results) {
|
|
28
|
+
console.log(`${r.title} (score: ${r.score.toFixed(3)})`)
|
|
29
|
+
console.log(` ${r.snippet}`)
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
ContentDb provides three search methods that delegate to the underlying semanticSearch feature:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// BM25 keyword search -- best for exact term matching
|
|
37
|
+
await db.search('OAuth2 token refresh')
|
|
38
|
+
|
|
39
|
+
// Vector similarity search -- finds conceptually related documents
|
|
40
|
+
await db.vectorSearch('how do users log in')
|
|
41
|
+
|
|
42
|
+
// Hybrid search -- combines both via Reciprocal Rank Fusion (recommended)
|
|
43
|
+
await db.hybridSearch('authentication flow', { limit: 5 })
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Using SemanticSearch Directly
|
|
47
|
+
|
|
48
|
+
For more control, use the `semanticSearch` feature directly:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import container from '@soederpop/luca'
|
|
52
|
+
import { SemanticSearch } from '@soederpop/luca/node/features/semantic-search'
|
|
53
|
+
|
|
54
|
+
// Attach the feature to the container
|
|
55
|
+
SemanticSearch.attach(container)
|
|
56
|
+
|
|
57
|
+
const search = container.feature('semanticSearch', {
|
|
58
|
+
dbPath: '.contentbase/search.sqlite',
|
|
59
|
+
embeddingProvider: 'openai', // or 'local'
|
|
60
|
+
embeddingModel: 'text-embedding-3-small',
|
|
61
|
+
chunkStrategy: 'section', // 'section' | 'fixed' | 'document'
|
|
62
|
+
chunkSize: 900,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
await search.initDb()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Indexing Documents
|
|
69
|
+
|
|
70
|
+
Documents are represented as `DocumentInput` objects with optional section metadata:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
await search.indexDocuments([
|
|
74
|
+
{
|
|
75
|
+
pathId: 'guides/auth',
|
|
76
|
+
model: 'Guide',
|
|
77
|
+
title: 'Authentication Guide',
|
|
78
|
+
meta: { status: 'published', category: 'security' },
|
|
79
|
+
content: 'Full document content here...',
|
|
80
|
+
sections: [
|
|
81
|
+
{
|
|
82
|
+
heading: 'OAuth2 Flow',
|
|
83
|
+
headingPath: 'Authentication Guide > OAuth2 Flow',
|
|
84
|
+
content: 'OAuth2 uses authorization codes and tokens...',
|
|
85
|
+
level: 2,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
heading: 'Session Management',
|
|
89
|
+
headingPath: 'Authentication Guide > Session Management',
|
|
90
|
+
content: 'Sessions are stored server-side with a cookie...',
|
|
91
|
+
level: 2,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
pathId: 'guides/deployment',
|
|
97
|
+
title: 'Deployment Guide',
|
|
98
|
+
content: 'How to deploy your application...',
|
|
99
|
+
},
|
|
100
|
+
])
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The `indexDocuments` method:
|
|
104
|
+
1. Stores documents in SQLite with FTS5 full-text indexing
|
|
105
|
+
2. Chunks each document based on the configured strategy
|
|
106
|
+
3. Generates embeddings for every chunk
|
|
107
|
+
4. Stores embeddings as BLOBs alongside the chunk text
|
|
108
|
+
|
|
109
|
+
## Chunking Strategies
|
|
110
|
+
|
|
111
|
+
The feature splits documents into chunks before embedding. Choose a strategy based on your content:
|
|
112
|
+
|
|
113
|
+
### Section (default)
|
|
114
|
+
|
|
115
|
+
Splits at heading boundaries (`## H2`, `### H3`). Each section becomes a chunk, prefixed with the heading path for context. Falls back to fixed chunking if the document has no sections.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const search = container.feature('semanticSearch', {
|
|
119
|
+
chunkStrategy: 'section',
|
|
120
|
+
chunkSize: 900, // max tokens per chunk (sections exceeding this are split at paragraphs)
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Best for: structured documents with clear heading hierarchies.
|
|
125
|
+
|
|
126
|
+
### Fixed
|
|
127
|
+
|
|
128
|
+
Splits by word count with configurable overlap between chunks:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const search = container.feature('semanticSearch', {
|
|
132
|
+
chunkStrategy: 'fixed',
|
|
133
|
+
chunkSize: 900,
|
|
134
|
+
chunkOverlap: 0.15, // 15% overlap between adjacent chunks
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Best for: unstructured prose, logs, or transcripts.
|
|
139
|
+
|
|
140
|
+
### Document
|
|
141
|
+
|
|
142
|
+
One chunk per document -- no splitting:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
const search = container.feature('semanticSearch', {
|
|
146
|
+
chunkStrategy: 'document',
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Best for: short documents where splitting would lose context.
|
|
151
|
+
|
|
152
|
+
## Search Methods
|
|
153
|
+
|
|
154
|
+
### BM25 Keyword Search
|
|
155
|
+
|
|
156
|
+
Uses SQLite FTS5 with Porter stemming for traditional keyword matching:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const results = await search.search('authentication tokens', {
|
|
160
|
+
limit: 10,
|
|
161
|
+
model: 'Guide', // filter by document model
|
|
162
|
+
where: { status: 'published' }, // filter by metadata fields
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Returns results ranked by BM25 relevance with highlighted snippets.
|
|
167
|
+
|
|
168
|
+
### Vector Similarity Search
|
|
169
|
+
|
|
170
|
+
Embeds the query and computes cosine similarity against all stored chunk embeddings:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const results = await search.vectorSearch('how do users prove their identity', {
|
|
174
|
+
limit: 10,
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Finds conceptually related content even without keyword overlap. Results are deduplicated by document, keeping the best-scoring chunk per document.
|
|
179
|
+
|
|
180
|
+
### Hybrid Search (Recommended)
|
|
181
|
+
|
|
182
|
+
Runs both BM25 and vector search in parallel, then fuses results using Reciprocal Rank Fusion:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const results = await search.hybridSearch('authentication flow', {
|
|
186
|
+
limit: 10,
|
|
187
|
+
model: 'Guide',
|
|
188
|
+
where: { category: 'security' },
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
This gives the best results for most queries -- keyword precision combined with semantic recall.
|
|
193
|
+
|
|
194
|
+
## Search Results
|
|
195
|
+
|
|
196
|
+
All search methods return `SearchResult[]`:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
interface SearchResult {
|
|
200
|
+
pathId: string // document identifier
|
|
201
|
+
model: string // content model name
|
|
202
|
+
title: string // document title
|
|
203
|
+
meta: Record<string, any> // document metadata
|
|
204
|
+
score: number // relevance score
|
|
205
|
+
snippet: string // matched text excerpt
|
|
206
|
+
matchedSection?: string // section heading where the match occurred
|
|
207
|
+
headingPath?: string // full heading breadcrumb (e.g. "Auth > OAuth2 > Tokens")
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Embedding Providers
|
|
212
|
+
|
|
213
|
+
### OpenAI (default)
|
|
214
|
+
|
|
215
|
+
Uses the OpenAI embeddings API. Requires an `openai` client registered in the container.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
const search = container.feature('semanticSearch', {
|
|
219
|
+
embeddingProvider: 'openai',
|
|
220
|
+
embeddingModel: 'text-embedding-3-small', // 1536 dimensions
|
|
221
|
+
// also available: 'text-embedding-3-large' (3072 dimensions)
|
|
222
|
+
})
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Local (GGUF)
|
|
226
|
+
|
|
227
|
+
Runs embeddings locally using `node-llama-cpp` with a GGUF model file:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
const search = container.feature('semanticSearch', {
|
|
231
|
+
embeddingProvider: 'local',
|
|
232
|
+
embeddingModel: 'embedding-gemma-300M-Q8_0', // 768 dimensions
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// Install the dependency if needed
|
|
236
|
+
await search.installLocalEmbeddings(process.cwd())
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Local models are loaded from `~/.cache/luca/models/` or `~/.cache/qmd/models/`. The model is kept in memory and automatically disposed after 5 minutes of inactivity.
|
|
240
|
+
|
|
241
|
+
## Index Management
|
|
242
|
+
|
|
243
|
+
### Incremental Updates
|
|
244
|
+
|
|
245
|
+
The feature tracks content hashes to avoid re-embedding unchanged documents:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Check if a document needs re-indexing
|
|
249
|
+
if (search.needsReindex(doc)) {
|
|
250
|
+
search.removeDocument(doc.pathId)
|
|
251
|
+
await search.indexDocuments([doc])
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Remove Stale Documents
|
|
256
|
+
|
|
257
|
+
Clean up documents that no longer exist in your collection:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
const currentIds = ['guides/auth', 'guides/deployment']
|
|
261
|
+
search.removeStale(currentIds) // deletes any indexed docs not in this list
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Full Reindex
|
|
265
|
+
|
|
266
|
+
Clear everything and start fresh:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
await search.reindex() // clears all data
|
|
270
|
+
await search.indexDocuments(allDocs) // re-index everything
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Index Status
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const stats = search.getStats()
|
|
277
|
+
// {
|
|
278
|
+
// documentCount: 42,
|
|
279
|
+
// chunkCount: 187,
|
|
280
|
+
// embeddingCount: 187,
|
|
281
|
+
// lastIndexedAt: '2026-03-06T...',
|
|
282
|
+
// provider: 'openai',
|
|
283
|
+
// model: 'text-embedding-3-small',
|
|
284
|
+
// dimensions: 1536,
|
|
285
|
+
// dbSizeBytes: 2457600,
|
|
286
|
+
// }
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Database Scoping
|
|
290
|
+
|
|
291
|
+
Each provider/model combination gets its own SQLite file. If you configure `dbPath: '.contentbase/search.sqlite'` with the OpenAI provider and `text-embedding-3-small` model, the actual file will be `.contentbase/search.openai-text-embedding-3-small.sqlite`. This prevents dimension mismatches if you switch providers.
|
|
292
|
+
|
|
293
|
+
## ContentDb Integration Details
|
|
294
|
+
|
|
295
|
+
When using `contentDb.buildSearchIndex()`, the feature automatically:
|
|
296
|
+
|
|
297
|
+
- Extracts sections from your markdown documents at H2 boundaries
|
|
298
|
+
- Converts each document to a `DocumentInput` with pathId, title, meta, and sections
|
|
299
|
+
- Skips unchanged documents (incremental by default)
|
|
300
|
+
- Removes documents that no longer exist in the collection
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const db = container.feature('contentDb', { rootPath: './docs' })
|
|
304
|
+
await db.load()
|
|
305
|
+
|
|
306
|
+
// Incremental update (default)
|
|
307
|
+
const { indexed, total } = await db.buildSearchIndex()
|
|
308
|
+
console.log(`Indexed ${indexed} of ${total} documents`)
|
|
309
|
+
|
|
310
|
+
// Force full rebuild
|
|
311
|
+
await db.rebuildSearchIndex()
|
|
312
|
+
|
|
313
|
+
// Check index health
|
|
314
|
+
console.log(db.searchIndexStatus)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Lifecycle
|
|
318
|
+
|
|
319
|
+
Always close the feature when done to release the SQLite connection and any loaded models:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
await search.close()
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The feature emits events you can listen to:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
search.on('dbReady', () => console.log('Database initialized'))
|
|
329
|
+
search.on('indexed', ({ documents, chunks }) => {
|
|
330
|
+
console.log(`Indexed ${documents} docs (${chunks} chunks)`)
|
|
331
|
+
})
|
|
332
|
+
search.on('modelLoaded', () => console.log('Local embedding model loaded'))
|
|
333
|
+
search.on('modelDisposed', () => console.log('Local embedding model released'))
|
|
334
|
+
```
|
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
console.log("Hello via Bun!");
|
package/luca.console.ts
ADDED
package/main.py
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@soederpop/luca",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "lightweight universal conversational architecture",
|
|
6
|
+
"author": "jon soeder <jon@soederpop.com>",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"repository": "https://github.com/soederpop/luca",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"conversational",
|
|
15
|
+
"architecture"
|
|
16
|
+
],
|
|
17
|
+
"main": "./src/node.ts",
|
|
18
|
+
"types": "./src/node.ts",
|
|
19
|
+
"browser": "./src/browser.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./src/node.ts",
|
|
22
|
+
"./node": "./src/node.ts",
|
|
23
|
+
"./node/*": "./src/node/*",
|
|
24
|
+
"./web": "./src/browser.ts",
|
|
25
|
+
"./web/*": "./src/web/*",
|
|
26
|
+
"./agi": "./src/agi/index.ts",
|
|
27
|
+
"./agi/*": "./src/agi/*",
|
|
28
|
+
"./schemas": "./src/schemas/base.ts",
|
|
29
|
+
"./schemas/*": "./src/schemas/*",
|
|
30
|
+
"./container": "./src/container.ts",
|
|
31
|
+
"./client": "./src/client.ts",
|
|
32
|
+
"./clients/*": "./src/clients/*",
|
|
33
|
+
"./feature": "./src/feature.ts",
|
|
34
|
+
"./react": "./src/react/index.ts"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"luca": "./src/cli/cli.ts"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"serve": "bun build:web && luca serve --any-port",
|
|
41
|
+
"console": "ts-node --esm scripts/console.ts",
|
|
42
|
+
"lint": "eslint src/ --ext .js,.jsx,.ts,.tsx",
|
|
43
|
+
"clean": "rm -rf dist build package",
|
|
44
|
+
"build:web": "bun run scripts/build-web.ts",
|
|
45
|
+
"build:introspection": "bun run src/cli/cli.ts update-introspection",
|
|
46
|
+
"compile": "bun build ./src/cli/cli.ts --compile --outfile dist/luca --external node-llama-cpp",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"build:scaffolds": "bun run src/cli/cli.ts build-scaffolds",
|
|
49
|
+
"test": "bun test test/*.test.ts",
|
|
50
|
+
"update-all-docs": "bun run test && bun run build:introspection && bun run src/cli/cli.ts generate-api-docs && bun run build:scaffolds",
|
|
51
|
+
"precommit": "bun run update-all-docs && git add docs/apis/ src/introspection/generated.*.ts src/scaffolds/generated.ts && bun compile",
|
|
52
|
+
"test:integration": "bun test ./test-integration/"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/cacache": "^15.0.1",
|
|
56
|
+
"@types/chalk": "^2.2.0",
|
|
57
|
+
"@types/child-process-promise": "^2.2.2",
|
|
58
|
+
"@types/chokidar": "^2.1.3",
|
|
59
|
+
"@types/cors": "^2.8.13",
|
|
60
|
+
"@types/detect-port": "^1.3.2",
|
|
61
|
+
"@types/dotenv": "^8.2.0",
|
|
62
|
+
"@types/express": "^4.17.17",
|
|
63
|
+
"@types/figlet": "^1.5.5",
|
|
64
|
+
"@types/glob": "^8.1.0",
|
|
65
|
+
"@types/inquirer": "^9.0.3",
|
|
66
|
+
"@types/jest": "^27.4.1",
|
|
67
|
+
"@types/js-yaml": "^4.0.5",
|
|
68
|
+
"@types/lodash-es": "^4.17.7",
|
|
69
|
+
"@types/micromatch": "^4.0.2",
|
|
70
|
+
"@types/minimist": "^1.2.2",
|
|
71
|
+
"@types/node": "^18.15.11",
|
|
72
|
+
"@types/node-uuid": "^0.0.29",
|
|
73
|
+
"@types/object-hash": "^3.0.2",
|
|
74
|
+
"@types/react": "^18.2.0",
|
|
75
|
+
"@types/uuid": "^9.0.1",
|
|
76
|
+
"@types/ws": "^8.5.4",
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
|
78
|
+
"@typescript-eslint/parser": "^5.20.0",
|
|
79
|
+
"eslint": "^8.14.0",
|
|
80
|
+
"mkdist": "^1.3.0",
|
|
81
|
+
"prettier": "^2.8.7",
|
|
82
|
+
"ts-node": "^11.0.0-beta.1"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
86
|
+
"@ngrok/ngrok": "^1.5.1",
|
|
87
|
+
"@openai/codex": "^0.99.0",
|
|
88
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
89
|
+
"@supabase/supabase-js": "^2.95.3",
|
|
90
|
+
"@types/marked": "^6.0.0",
|
|
91
|
+
"@types/marked-terminal": "^6.1.1",
|
|
92
|
+
"axios": "^1.3.5",
|
|
93
|
+
"cacache": "^17.0.7",
|
|
94
|
+
"chalk": "^5.2.0",
|
|
95
|
+
"child-process-promise": "^2.2.1",
|
|
96
|
+
"chokidar": "^3.5.3",
|
|
97
|
+
"cli-markdown": "^3.5.0",
|
|
98
|
+
"compromise": "^14.14.5",
|
|
99
|
+
"contentbase": "",
|
|
100
|
+
"cors": "^2.8.5",
|
|
101
|
+
"cross-fetch": "^4.1.0",
|
|
102
|
+
"detect-port": "^1.5.1",
|
|
103
|
+
"dotenv": "^17.2.4",
|
|
104
|
+
"endent": "^2.1.0",
|
|
105
|
+
"esbuild-wasm": "0.17.18",
|
|
106
|
+
"excalidraw-to-svg": "^3.1.0",
|
|
107
|
+
"express": "^4.18.2",
|
|
108
|
+
"figlet": "^1.6.0",
|
|
109
|
+
"glob": "^11.0.2",
|
|
110
|
+
"googleapis": "^171.4.0",
|
|
111
|
+
"grammy": "^1.40.0",
|
|
112
|
+
"inflect": "^0.5.0",
|
|
113
|
+
"ink": "^6.7.0",
|
|
114
|
+
"inquirer": "^9.1.5",
|
|
115
|
+
"isomorphic-vm": "^0.0.1",
|
|
116
|
+
"isomorphic-ws": "^5.0.0",
|
|
117
|
+
"js-tiktoken": "^1.0.21",
|
|
118
|
+
"js-yaml": "^4.1.0",
|
|
119
|
+
"lodash-es": "^4.17.21",
|
|
120
|
+
"marked": "^15.0.12",
|
|
121
|
+
"marked-terminal": "^7.3.0",
|
|
122
|
+
"mdast-util-to-markdown": "^1.5.0",
|
|
123
|
+
"mdast-util-to-string": "^3.2.0",
|
|
124
|
+
"micromatch": "^4.0.5",
|
|
125
|
+
"minimist": "^1.2.8",
|
|
126
|
+
"node-uuid": "^1.4.8",
|
|
127
|
+
"object-hash": "^3.0.0",
|
|
128
|
+
"openai": "^5.1.1",
|
|
129
|
+
"opener": "^1.5.2",
|
|
130
|
+
"react": "^19.2.4",
|
|
131
|
+
"react-devtools-core": "^7.0.1",
|
|
132
|
+
"react-dom": "^19.2.4",
|
|
133
|
+
"react-reconciler": "^0.33.0",
|
|
134
|
+
"remark-gfm": "^3.0.1",
|
|
135
|
+
"rimraf": "^5.0.0",
|
|
136
|
+
"typescript": "^5.9.3",
|
|
137
|
+
"unist-util-find-after": "^4.0.1",
|
|
138
|
+
"unist-util-find-all-after": "^4.0.1",
|
|
139
|
+
"unist-util-find-all-before": "^4.0.1",
|
|
140
|
+
"unist-util-find-before": "^3.0.1",
|
|
141
|
+
"unist-util-select": "^4.0.3",
|
|
142
|
+
"unist-util-visit": "^4.1.2",
|
|
143
|
+
"wink-eng-lite-web-model": "^1.8.1",
|
|
144
|
+
"wink-nlp": "^2.4.0",
|
|
145
|
+
"ws": "^8.13.0",
|
|
146
|
+
"zod": "^4.0.0"
|
|
147
|
+
},
|
|
148
|
+
"optionalDependencies": {
|
|
149
|
+
"node-llama-cpp": "^3.17.1"
|
|
150
|
+
},
|
|
151
|
+
"luca": {
|
|
152
|
+
"aliases": ["luca", "framework", "container", "runtime"]
|
|
153
|
+
}
|
|
154
|
+
}
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AsciiAnimation } from './types'
|
|
2
|
+
|
|
3
|
+
const frames = [
|
|
4
|
+
String.raw`
|
|
5
|
+
###### ###### ########
|
|
6
|
+
## ## ## ## ##
|
|
7
|
+
###### ## ## ##
|
|
8
|
+
## ## ## ## ##
|
|
9
|
+
## ## ###### ##
|
|
10
|
+
## ## ###### ##
|
|
11
|
+
|
|
12
|
+
[o_o] channel-open
|
|
13
|
+
/|\ packet-sync
|
|
14
|
+
/ \ pulse: 71%
|
|
15
|
+
|
|
16
|
+
<<..................>>
|
|
17
|
+
`,
|
|
18
|
+
String.raw`
|
|
19
|
+
###### ###### ########
|
|
20
|
+
## ## ## ## ##
|
|
21
|
+
###### ## ## ##
|
|
22
|
+
## ## ## ## ##
|
|
23
|
+
## ## ###### ##
|
|
24
|
+
## ## ###### ##
|
|
25
|
+
|
|
26
|
+
[0_0] channel-open
|
|
27
|
+
/|\ packet-sync
|
|
28
|
+
/ \ pulse: 84%
|
|
29
|
+
|
|
30
|
+
<<##..##..##..##..##..>>
|
|
31
|
+
`,
|
|
32
|
+
String.raw`
|
|
33
|
+
###### ###### ########
|
|
34
|
+
## ## ## ## ##
|
|
35
|
+
###### ## ## ##
|
|
36
|
+
## ## ## ## ##
|
|
37
|
+
## ## ###### ##
|
|
38
|
+
## ## ###### ##
|
|
39
|
+
|
|
40
|
+
[O_O] channel-open
|
|
41
|
+
/|\ packet-sync
|
|
42
|
+
/ \ pulse: 96%
|
|
43
|
+
|
|
44
|
+
<<##################>>
|
|
45
|
+
`,
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
const chromeGlitch: AsciiAnimation = {
|
|
49
|
+
id: 'chromeGlitch',
|
|
50
|
+
name: 'Chrome Glitch Totem',
|
|
51
|
+
fps: 5,
|
|
52
|
+
frames,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default chromeGlitch
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AsciiAnimation } from './types'
|
|
2
|
+
import neonPulse from './neon-pulse'
|
|
3
|
+
import chromeGlitch from './chrome-glitch'
|
|
4
|
+
|
|
5
|
+
const animations: AsciiAnimation[] = [neonPulse, chromeGlitch]
|
|
6
|
+
|
|
7
|
+
export function listAnimations(): AsciiAnimation[] {
|
|
8
|
+
return animations
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function resolveAnimation(id: string): AsciiAnimation {
|
|
12
|
+
const match = animations.find((animation) => animation.id.toLowerCase() === id.toLowerCase())
|
|
13
|
+
if (match) return match
|
|
14
|
+
if (!animations[0]) throw new Error('No animations are registered.')
|
|
15
|
+
return animations[0]
|
|
16
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AsciiAnimation } from './types'
|
|
2
|
+
|
|
3
|
+
const frames = [
|
|
4
|
+
String.raw`
|
|
5
|
+
.-""-.
|
|
6
|
+
.' .--. '.
|
|
7
|
+
/ / \ \
|
|
8
|
+
| | 0 0 | |
|
|
9
|
+
| | __ | |
|
|
10
|
+
| | /__\ | |
|
|
11
|
+
| | \__/ | |
|
|
12
|
+
| | | |
|
|
13
|
+
/| '.__.' |\
|
|
14
|
+
.' | /::\ | '.
|
|
15
|
+
/ | |::::| | \
|
|
16
|
+
/____|__|::::|__|____\
|
|
17
|
+
/_/ |::| \_\
|
|
18
|
+
/____\
|
|
19
|
+
~ ~ ~ SIGNAL: STABLE ~ ~ ~
|
|
20
|
+
`,
|
|
21
|
+
String.raw`
|
|
22
|
+
.-""-.
|
|
23
|
+
.' .--. '.
|
|
24
|
+
/ / /\ \ \
|
|
25
|
+
| | ^ ^ | |
|
|
26
|
+
| | -- | |
|
|
27
|
+
| | /__\ | |
|
|
28
|
+
| | \__/ | |
|
|
29
|
+
| | /\ | |
|
|
30
|
+
/| '.__.' |\
|
|
31
|
+
.' | _/::\_ | '.
|
|
32
|
+
/ | |::::::| | \
|
|
33
|
+
/____|_|::::::|_|____\
|
|
34
|
+
/_/ |::| \_\
|
|
35
|
+
/____\
|
|
36
|
+
~ ~ ~ SIGNAL: BREATHING ~ ~ ~
|
|
37
|
+
`,
|
|
38
|
+
String.raw`
|
|
39
|
+
.-""-.
|
|
40
|
+
.' .--. '.
|
|
41
|
+
/ / __ \ \
|
|
42
|
+
| | o o | |
|
|
43
|
+
| | .. | |
|
|
44
|
+
| | /__\ | |
|
|
45
|
+
| | \__/ | |
|
|
46
|
+
| | .--. | |
|
|
47
|
+
/| '.__.' |\
|
|
48
|
+
.' | /::\ | '.
|
|
49
|
+
/ | |::::| | \
|
|
50
|
+
/____|__|::::|__|____\
|
|
51
|
+
/_/ |::| \_\
|
|
52
|
+
/____\
|
|
53
|
+
~ ~ ~ SIGNAL: SCANNING ~ ~ ~
|
|
54
|
+
`,
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
const neonPulse: AsciiAnimation = {
|
|
58
|
+
id: 'neonPulse',
|
|
59
|
+
name: 'Neon Pulse Bot',
|
|
60
|
+
fps: 4,
|
|
61
|
+
frames,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default neonPulse
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import path from "path"
|
|
3
|
+
|
|
4
|
+
const result = await Bun.build({
|
|
5
|
+
entrypoints: [path.resolve(import.meta.dir, "../src/browser.ts")],
|
|
6
|
+
outdir: path.resolve(import.meta.dir, "../dist"),
|
|
7
|
+
target: "browser",
|
|
8
|
+
format: "esm",
|
|
9
|
+
naming: "browser.js",
|
|
10
|
+
external: [
|
|
11
|
+
"react",
|
|
12
|
+
"react-dom",
|
|
13
|
+
],
|
|
14
|
+
define: {
|
|
15
|
+
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
16
|
+
"process.env.NODE_DEBUG": JSON.stringify(""),
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
if (!result.success) {
|
|
21
|
+
console.error("Build failed:")
|
|
22
|
+
for (const log of result.logs) {
|
|
23
|
+
console.error(log)
|
|
24
|
+
}
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(`Built browser bundle: dist/browser.js (${(result.outputs[0].size / 1024).toFixed(1)}KB)`)
|