@yugenlab/vaayu 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +365 -0
- package/chunks/chunk-E5A3SCDJ.js +246 -0
- package/chunks/chunk-G5VYCA6O.js +69 -0
- package/chunks/chunk-H76V36OF.js +1029 -0
- package/chunks/chunk-HAPVUJ6A.js +238 -0
- package/chunks/chunk-IEKAYVA3.js +137 -0
- package/chunks/chunk-IGKYKEKT.js +43 -0
- package/chunks/chunk-IIET2K6D.js +7728 -0
- package/chunks/chunk-ITIVYGUG.js +347 -0
- package/chunks/chunk-JAWZ7ANC.js +208 -0
- package/chunks/chunk-JZU37VQ5.js +714 -0
- package/chunks/chunk-KC6NRZ7U.js +198 -0
- package/chunks/chunk-KDRROLVN.js +433 -0
- package/chunks/chunk-L7JICQBW.js +1006 -0
- package/chunks/chunk-MINFB5LT.js +1479 -0
- package/chunks/chunk-MJ74G5RB.js +5816 -0
- package/chunks/chunk-S4TBVCL2.js +2158 -0
- package/chunks/chunk-SMVJRPAH.js +2753 -0
- package/chunks/chunk-U6OLJ36B.js +438 -0
- package/chunks/chunk-URGEODS5.js +752 -0
- package/chunks/chunk-YSU3BWV6.js +123 -0
- package/chunks/consolidation-indexer-TOTTDZXW.js +21 -0
- package/chunks/day-consolidation-NKO63HZQ.js +24 -0
- package/chunks/graphrag-ZI2FSU7S.js +13 -0
- package/chunks/hierarchical-temporal-search-ZD46UMKR.js +8 -0
- package/chunks/hybrid-search-ZVLZVGFS.js +19 -0
- package/chunks/memory-store-KNJPMBLQ.js +17 -0
- package/chunks/periodic-consolidation-BPKOZDGB.js +10 -0
- package/chunks/postgres-3ZXBYTPC.js +8 -0
- package/chunks/recall-GMVHWQWW.js +20 -0
- package/chunks/search-7HZETVMZ.js +18 -0
- package/chunks/session-store-XKPGKXUS.js +44 -0
- package/chunks/sqlite-JPF5TICX.js +152 -0
- package/chunks/src-6GVZTUH6.js +12 -0
- package/chunks/src-QAXOD5SB.js +273 -0
- package/chunks/suncalc-NOHGYHDU.js +186 -0
- package/chunks/tree-RSHKDTCR.js +10 -0
- package/gateway.js +61944 -0
- package/package.json +51 -0
- package/pair-cli.js +133 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sriinnu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# VAAYU (वायु)
|
|
2
|
+
|
|
3
|
+
**Like wind — swift, everywhere, carrying what matters.**
|
|
4
|
+
|
|
5
|
+
Vaayu is a self-hosted, privacy-first AI assistant that lives across your messaging
|
|
6
|
+
platforms and native apps. Memory belongs to you, not the provider. Every action
|
|
7
|
+
respects consent. Every tool runs behind policy. Built with the precision of
|
|
8
|
+
Vishwakarma and the strength of Hanuman.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why Vaayu?
|
|
13
|
+
|
|
14
|
+
- **Your memory, your data.** Switch providers mid-conversation without losing context.
|
|
15
|
+
Smriti (memory) is user-centric, not provider-locked.
|
|
16
|
+
- **Local-first.** NLU, embeddings, and fallback LLM all run locally. Cloud is opt-in.
|
|
17
|
+
- **Cost-aware.** Smart routing sends simple queries to cheap/local models, complex ones
|
|
18
|
+
to quality providers. Target: $5-10/month.
|
|
19
|
+
- **Extensible skills.** Weather, finance, health, reminders, notes, music, smart home,
|
|
20
|
+
travel, calls -- and skills that learn on the fly.
|
|
21
|
+
- **Privacy by default.** No exec/write/delete/network without approval. Memory writes
|
|
22
|
+
require consent. Sandbox-first execution.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Upstream Inspiration
|
|
27
|
+
|
|
28
|
+
Vaayu’s provider/LLM registry is **derived from pi‑mono (pi‑ai)** and then refactored
|
|
29
|
+
and extended for Vaayu’s policy, routing, and model‑switching needs. We also adapt
|
|
30
|
+
orchestration and self‑healing patterns from **gru‑main**, while preserving Vaayu’s
|
|
31
|
+
privacy‑first guardrails.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
Vaayu uses a **Pantheon Architecture** -- four subsystems with clear boundaries:
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart TB
|
|
41
|
+
subgraph Channels
|
|
42
|
+
TG[Telegram]
|
|
43
|
+
Hub[Hub UI]
|
|
44
|
+
DC[Discord]
|
|
45
|
+
WA[WhatsApp]
|
|
46
|
+
SL[Slack]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
subgraph Vaayu Core
|
|
50
|
+
GW[Gateway]
|
|
51
|
+
NLU[Saraswati - NLU]
|
|
52
|
+
PL[Brahma - Planner]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subgraph Hanuman[Policy Gateway]
|
|
56
|
+
POL[Tool Policy]
|
|
57
|
+
APR[Approvals]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
subgraph Vishwakarma[Executor]
|
|
61
|
+
SBX[Sandbox]
|
|
62
|
+
BLD[Build/Test]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
subgraph Smriti[Vyasa - Memory]
|
|
66
|
+
MEM[(Sessions + Knowledge)]
|
|
67
|
+
VEC[(Embeddings)]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
subgraph Providers
|
|
71
|
+
CL[Claude]
|
|
72
|
+
OAI[OpenAI]
|
|
73
|
+
OLL[Ollama - Local]
|
|
74
|
+
MM[MiniMax]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
Channels --> GW
|
|
78
|
+
GW --> NLU
|
|
79
|
+
NLU --> PL
|
|
80
|
+
PL --> Hanuman
|
|
81
|
+
Hanuman --> Vishwakarma
|
|
82
|
+
Hanuman --> Providers
|
|
83
|
+
GW --> Smriti
|
|
84
|
+
Vishwakarma --> Smriti
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Role | Subsystem | What It Does |
|
|
88
|
+
|------|-----------|--------------|
|
|
89
|
+
| **Vaayu Core** | Gateway + Brain | NLU, planning, orchestration |
|
|
90
|
+
| **Vyasa (Smriti)** | Memory | Storage, recall, summarization, knowledge extraction |
|
|
91
|
+
| **Hanuman** | Policy Gateway | Approvals, sanitization, risk gating |
|
|
92
|
+
| **Vishwakarma** | Executor | Sandboxed execution, build/test pipeline |
|
|
93
|
+
|
|
94
|
+
For full ASCII flow/state diagrams and concrete examples, see `docs/architecture.md`.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Quick Start
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Clone
|
|
102
|
+
git clone https://github.com/srinivaspendela/vaayu.git
|
|
103
|
+
cd vaayu
|
|
104
|
+
|
|
105
|
+
# Install
|
|
106
|
+
pnpm install
|
|
107
|
+
|
|
108
|
+
# Configure
|
|
109
|
+
cp .env.example .env
|
|
110
|
+
# Edit .env with your API keys (Anthropic, OpenAI, MiniMax, etc.)
|
|
111
|
+
|
|
112
|
+
# Run (gateway + smriti)
|
|
113
|
+
pnpm start:all
|
|
114
|
+
|
|
115
|
+
# Or run them separately
|
|
116
|
+
pnpm dev
|
|
117
|
+
pnpm -C smriti run api
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Open the Hub: [http://127.0.0.1:18369/hub](http://127.0.0.1:18369/hub)
|
|
121
|
+
Legacy Hub (v1): [http://127.0.0.1:18369/hub-old](http://127.0.0.1:18369/hub-old)
|
|
122
|
+
|
|
123
|
+
### Prerequisites
|
|
124
|
+
|
|
125
|
+
- Node.js 22+
|
|
126
|
+
- pnpm 9+
|
|
127
|
+
- Ollama (optional, for local models)
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Features
|
|
132
|
+
|
|
133
|
+
| Category | Details |
|
|
134
|
+
|----------|---------|
|
|
135
|
+
| **Multi-channel** | Telegram, Hub UI, Discord, WhatsApp, Slack, Email |
|
|
136
|
+
| **Multi-provider** | Claude, OpenAI, Ollama, MiniMax -- switch mid-conversation |
|
|
137
|
+
| **Memory (Smriti)** | User-centric, 5-tier progressive summarization, hybrid search |
|
|
138
|
+
| **Skills** | Weather, finance, health, reminders, notes, music, panchangam |
|
|
139
|
+
| **Smart Home** | HoloCube ambient display, IoT integrations |
|
|
140
|
+
| **Voice** | STT transcription, TTS (MiniMax), voice notes |
|
|
141
|
+
| **Security** | Device pairing, approval workflows, sandbox execution |
|
|
142
|
+
| **Cost-aware** | Smart routing, local-first, token accounting |
|
|
143
|
+
| **Privacy** | Self-hosted, consent-gated memory, secret redaction |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Skills
|
|
148
|
+
|
|
149
|
+
Stable skill packs in `../ecosystem/skills/`:
|
|
150
|
+
|
|
151
|
+
| Skill | Description |
|
|
152
|
+
|-------|-------------|
|
|
153
|
+
| `weather` | Forecasts, briefings, sun/moon data |
|
|
154
|
+
| `finance` | CSV analysis, portfolio summaries |
|
|
155
|
+
| `health` | BMI, health metrics tracking |
|
|
156
|
+
| `reminders` | Create, list, manage reminders |
|
|
157
|
+
| `apple-notes` | macOS Notes integration via bridge |
|
|
158
|
+
| `music` | Spotify, Apple Music playback |
|
|
159
|
+
| `panchangam` | Hindu calendar, tithi, nakshatra |
|
|
160
|
+
| `holo-cube` | Ambient display briefings |
|
|
161
|
+
| `audio-transcribe` | Voice/audio transcription |
|
|
162
|
+
|
|
163
|
+
Community skills in `ecosystem/skill-community/`. Experimental skills in `ecosystem/skill-lab/`.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Project Structure
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
vaayu/
|
|
171
|
+
apps/
|
|
172
|
+
gateway/ Gateway server (HTTP + WS + channels)
|
|
173
|
+
cli-gateway/ Gateway CLI
|
|
174
|
+
cli-node/ Node device CLI
|
|
175
|
+
cli-cron/ Scheduled jobs
|
|
176
|
+
bridges/ Hardware bridges (HoloCube, Apple Notes)
|
|
177
|
+
mcp/ MCP servers (NLU)
|
|
178
|
+
|
|
179
|
+
packages/
|
|
180
|
+
core/ Types, routing, profile, identity
|
|
181
|
+
config/ Configuration loader + env overrides
|
|
182
|
+
providers/ LLM provider registry + adapters
|
|
183
|
+
tools/ Tool registry, policy, MCP manager
|
|
184
|
+
storage/ File, SQLite, Postgres drivers
|
|
185
|
+
memory/ Memory pipeline
|
|
186
|
+
channels/ Channel adapters (Telegram, Discord, Slack, etc.)
|
|
187
|
+
protocol/ WebSocket protocol frames
|
|
188
|
+
auth/ OAuth PKCE + device code flows
|
|
189
|
+
scheduler/ Cron + one-shot jobs
|
|
190
|
+
sandbox/ Sandboxed execution
|
|
191
|
+
logger/ Structured logging + secret redaction
|
|
192
|
+
nlu/ In-process rules NLU
|
|
193
|
+
guardian/ Security gate (2FA, rate limit, injection detection)
|
|
194
|
+
|
|
195
|
+
skills-core/ Product-private skill packs (reserved)
|
|
196
|
+
|
|
197
|
+
../ecosystem/ Sibling directory (outside vaayu/)
|
|
198
|
+
skills/ Approved, vetted skill packs (stable runtime tier)
|
|
199
|
+
skill-lab/ Experimental skills (isolated)
|
|
200
|
+
skill-community/ Community-contributed skills
|
|
201
|
+
docs/ Architecture, guides, protocol docs
|
|
202
|
+
vaayu-spec/ Design spec (55+ documents, source of truth)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Providers
|
|
208
|
+
|
|
209
|
+
| Provider | Type | Use Case |
|
|
210
|
+
|----------|------|----------|
|
|
211
|
+
| Claude (Anthropic) | Cloud | Quality reasoning |
|
|
212
|
+
| OpenAI | Cloud | General purpose |
|
|
213
|
+
| MiniMax | Cloud | TTS, cost-effective |
|
|
214
|
+
| Ollama | Local | Offline fallback, free |
|
|
215
|
+
|
|
216
|
+
Recommended model choices are documented in `docs/models.md`.
|
|
217
|
+
|
|
218
|
+
Configure via `.env`:
|
|
219
|
+
```env
|
|
220
|
+
VAAYU_PROVIDER_DEFAULT=anthropic
|
|
221
|
+
VAAYU_PROVIDER_ANTHROPIC_API_KEY=sk-ant-...
|
|
222
|
+
VAAYU_PROVIDER_OPENAI_API_KEY=sk-...
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
See [docs/providers.md](docs/providers.md) for full provider configuration.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Memory (Smriti)
|
|
230
|
+
|
|
231
|
+
Smriti (Sanskrit: remembrance) is Vaayu's user-centric memory system.
|
|
232
|
+
|
|
233
|
+
**Key principles:**
|
|
234
|
+
- Memory belongs to the user, not the provider
|
|
235
|
+
- Provider switches preserve full context
|
|
236
|
+
- 5-tier progressive summarization (94% compression over 1 year)
|
|
237
|
+
- Hybrid search: BM25 (keyword) + Vector (semantic)
|
|
238
|
+
- All writes require explicit consent
|
|
239
|
+
|
|
240
|
+
```env
|
|
241
|
+
VAAYU_SMRITI_ENABLED=true
|
|
242
|
+
VAAYU_SMRITI_BASE_URL=http://127.0.0.1:7788
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
See [docs/memory.md](docs/memory.md) for details.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Local Models
|
|
250
|
+
|
|
251
|
+
| Model | Purpose | Size |
|
|
252
|
+
|-------|---------|------|
|
|
253
|
+
| BGE-M3 | Embeddings (100+ languages) | 1.2 GB |
|
|
254
|
+
| Qwen2.5-7B | Local LLM fallback | 4.3 GB |
|
|
255
|
+
| GLiNER2 | NLU (NER + intent) | 500 MB |
|
|
256
|
+
|
|
257
|
+
Install via Ollama:
|
|
258
|
+
```bash
|
|
259
|
+
ollama pull bge-m3
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
See [vaayu-spec/architecture/VAAYU-INSTALLATION-GUIDE.md](vaayu-spec/architecture/VAAYU-INSTALLATION-GUIDE.md) for complete setup.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Development
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pnpm dev # Start gateway (dev mode)
|
|
270
|
+
pnpm typecheck # Type-check all packages
|
|
271
|
+
pnpm build # Production build
|
|
272
|
+
pnpm secrets:scan # Scan for leaked secrets
|
|
273
|
+
pnpm hooks:install # Install git hooks
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Code Standards
|
|
277
|
+
|
|
278
|
+
- TypeScript (ESM), strict typing, no `any`
|
|
279
|
+
- Max 400 lines per file -- split into modules
|
|
280
|
+
- `@vaayu/*` workspace aliases for cross-package imports
|
|
281
|
+
- Every module has JSDoc documentation
|
|
282
|
+
- Secret redaction in all logging
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Documentation
|
|
287
|
+
|
|
288
|
+
Full documentation at [docs.vaayu.app](https://docs.vaayu.app) (coming soon).
|
|
289
|
+
|
|
290
|
+
| Topic | File |
|
|
291
|
+
|-------|------|
|
|
292
|
+
| Architecture | [docs/architecture.md](docs/architecture.md) |
|
|
293
|
+
| Quick Start | [docs/quickstart.md](docs/quickstart.md) |
|
|
294
|
+
| Configuration | [docs/configuration.md](docs/configuration.md) |
|
|
295
|
+
| **Security** | [docs/security.md](docs/security.md) |
|
|
296
|
+
| Channels | [docs/channels.md](docs/channels.md) |
|
|
297
|
+
| Providers | [docs/providers.md](docs/providers.md) |
|
|
298
|
+
| Memory | [docs/memory.md](docs/memory.md) |
|
|
299
|
+
| Skills | [docs/skills.md](docs/skills.md) |
|
|
300
|
+
| Protocol | [docs/protocol.md](docs/protocol.md) |
|
|
301
|
+
| Hub UI | [docs/hub.md](docs/hub.md) |
|
|
302
|
+
| Structure | [docs/structure.md](docs/structure.md) |
|
|
303
|
+
| NLU | [docs/nlu.md](docs/nlu.md) |
|
|
304
|
+
| Hardware | [docs/hardware.md](docs/hardware.md) |
|
|
305
|
+
| Skill Pack Standard | [docs/skill-pack-standard.md](docs/skill-pack-standard.md) |
|
|
306
|
+
|
|
307
|
+
Design spec: [vaayu-spec/](vaayu-spec/) (55+ documents)
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Security (Guardian)
|
|
312
|
+
|
|
313
|
+
Vaayu includes **Guardian** (`@vaayu/guardian`) - a comprehensive security gate that protects against leaks, injection, and unauthorized access.
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
317
|
+
│ GUARDIAN SECURITY STACK │
|
|
318
|
+
├─────────────────────────────────────────────────────────────┤
|
|
319
|
+
│ IP Guard → Sanitize → Gate (2FA) → Session → Memory Fence │
|
|
320
|
+
└─────────────────────────────────────────────────────────────┘
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
| Layer | Protection |
|
|
324
|
+
|-------|------------|
|
|
325
|
+
| **IP Guard** | Rate limiting, brute force detection, IP blocklist |
|
|
326
|
+
| **Sanitize** | API key redaction, prompt injection detection |
|
|
327
|
+
| **Gate + TOTP** | 2FA for critical ops (delete, financial, system) |
|
|
328
|
+
| **Session Binding** | Ties sessions to devices, detects hijacking |
|
|
329
|
+
| **Memory Fence** | Limits LLM memory access, blocks bulk extraction |
|
|
330
|
+
| **Secrets** | AES-256-GCM encryption at rest |
|
|
331
|
+
| **Alerts** | Real-time alerts via Telegram/webhook |
|
|
332
|
+
|
|
333
|
+
### Security Principles
|
|
334
|
+
|
|
335
|
+
- No exec/write/delete/network without explicit approval
|
|
336
|
+
- Delete requires double confirmation + 2FA for critical data
|
|
337
|
+
- All code runs in sandbox (network off by default)
|
|
338
|
+
- Untrusted content never treated as instructions
|
|
339
|
+
- Memory writes require consent
|
|
340
|
+
- LLM cannot access all memories at once (max 10/query)
|
|
341
|
+
- Secrets redacted before reaching LLM or logs
|
|
342
|
+
- Prompt injection attempts blocked and alerted
|
|
343
|
+
|
|
344
|
+
See [docs/security.md](docs/security.md) for full documentation.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Contributing
|
|
349
|
+
|
|
350
|
+
Contributions welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before submitting PRs.
|
|
351
|
+
|
|
352
|
+
- Follow the [Skill Pack Standard](docs/skill-pack-standard.md) for new skills
|
|
353
|
+
- Keep files under 400 lines
|
|
354
|
+
- Use `@vaayu/*` aliases for imports
|
|
355
|
+
- Run `pnpm typecheck && pnpm secrets:scan` before pushing
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
MIT
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
*vaayuvegena chalamah -- Let's move with the speed of wind.*
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MemoryError,
|
|
3
|
+
getChitraguptaHome
|
|
4
|
+
} from "./chunk-KC6NRZ7U.js";
|
|
5
|
+
|
|
6
|
+
// ../chitragupta/packages/smriti/src/memory-store.ts
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import crypto from "crypto";
|
|
10
|
+
function hashProject(projectPath) {
|
|
11
|
+
return crypto.createHash("sha256").update(projectPath).digest("hex").slice(0, 12);
|
|
12
|
+
}
|
|
13
|
+
function getMemoryRoot() {
|
|
14
|
+
return path.join(getChitraguptaHome(), "memory");
|
|
15
|
+
}
|
|
16
|
+
function resolveMemoryPath(scope) {
|
|
17
|
+
const root = getMemoryRoot();
|
|
18
|
+
switch (scope.type) {
|
|
19
|
+
case "global":
|
|
20
|
+
return path.join(root, "global.md");
|
|
21
|
+
case "project":
|
|
22
|
+
return path.join(root, "projects", hashProject(scope.path), "project.md");
|
|
23
|
+
case "agent":
|
|
24
|
+
return path.join(root, "agents", `${scope.agentId}.md`);
|
|
25
|
+
case "session":
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function ensureDir(filePath) {
|
|
30
|
+
const dir = path.dirname(filePath);
|
|
31
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
var MAX_MEMORY_SIZE = 5e5;
|
|
34
|
+
var memoryWriteQueues = /* @__PURE__ */ new Map();
|
|
35
|
+
function scopeKey(scope) {
|
|
36
|
+
switch (scope.type) {
|
|
37
|
+
case "global":
|
|
38
|
+
return "global";
|
|
39
|
+
case "project":
|
|
40
|
+
return `project:${scope.path}`;
|
|
41
|
+
case "agent":
|
|
42
|
+
return `agent:${scope.agentId}`;
|
|
43
|
+
case "session":
|
|
44
|
+
return `session:${scope.sessionId}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getMemory(scope) {
|
|
48
|
+
if (scope.type === "session") {
|
|
49
|
+
throw new MemoryError(
|
|
50
|
+
"Session memory is stored within the session file. Use loadSession() to access it."
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const filePath = resolveMemoryPath(scope);
|
|
54
|
+
if (!filePath) return "";
|
|
55
|
+
try {
|
|
56
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
57
|
+
} catch (err) {
|
|
58
|
+
const isNotFound = err.code === "ENOENT" || err instanceof Error && err.message.includes("ENOENT");
|
|
59
|
+
if (isNotFound) return "";
|
|
60
|
+
throw new MemoryError(`Failed to read memory at ${filePath}: ${err}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function updateMemory(scope, content) {
|
|
64
|
+
if (scope.type === "session") {
|
|
65
|
+
throw new MemoryError(
|
|
66
|
+
"Session memory is stored within the session file. Use saveSession() to update it."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const filePath = resolveMemoryPath(scope);
|
|
70
|
+
if (!filePath) return Promise.resolve();
|
|
71
|
+
const key = scopeKey(scope);
|
|
72
|
+
const prev = memoryWriteQueues.get(key) ?? Promise.resolve();
|
|
73
|
+
const next = prev.then(() => {
|
|
74
|
+
try {
|
|
75
|
+
ensureDir(filePath);
|
|
76
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
77
|
+
} catch (err) {
|
|
78
|
+
throw new MemoryError(`Failed to write memory at ${filePath}: ${err}`);
|
|
79
|
+
}
|
|
80
|
+
}).finally(() => {
|
|
81
|
+
if (memoryWriteQueues.get(key) === next) {
|
|
82
|
+
memoryWriteQueues.delete(key);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
memoryWriteQueues.set(key, next);
|
|
86
|
+
return next;
|
|
87
|
+
}
|
|
88
|
+
function appendMemory(scope, entry) {
|
|
89
|
+
if (scope.type === "session") {
|
|
90
|
+
throw new MemoryError(
|
|
91
|
+
"Session memory is stored within the session file. Use addTurn() to append."
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const filePath = resolveMemoryPath(scope);
|
|
95
|
+
if (!filePath) return Promise.resolve();
|
|
96
|
+
const key = scopeKey(scope);
|
|
97
|
+
const prev = memoryWriteQueues.get(key) ?? Promise.resolve();
|
|
98
|
+
const next = prev.then(() => {
|
|
99
|
+
try {
|
|
100
|
+
ensureDir(filePath);
|
|
101
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
102
|
+
const formatted = `
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
*${timestamp}*
|
|
106
|
+
|
|
107
|
+
${entry}
|
|
108
|
+
`;
|
|
109
|
+
let existing = null;
|
|
110
|
+
try {
|
|
111
|
+
existing = fs.readFileSync(filePath, "utf-8");
|
|
112
|
+
} catch (readErr) {
|
|
113
|
+
const isNotFound = readErr.code === "ENOENT" || readErr instanceof Error && readErr.message.includes("ENOENT");
|
|
114
|
+
if (!isNotFound) throw readErr;
|
|
115
|
+
}
|
|
116
|
+
if (existing !== null) {
|
|
117
|
+
const totalSize = Buffer.byteLength(existing, "utf-8") + Buffer.byteLength(formatted, "utf-8");
|
|
118
|
+
if (totalSize > MAX_MEMORY_SIZE) {
|
|
119
|
+
const result = truncateToFit(existing, formatted);
|
|
120
|
+
fs.writeFileSync(filePath, result, "utf-8");
|
|
121
|
+
} else {
|
|
122
|
+
fs.appendFileSync(filePath, formatted, "utf-8");
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
const header = buildMemoryHeader(scope);
|
|
126
|
+
fs.writeFileSync(filePath, header + formatted, "utf-8");
|
|
127
|
+
}
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err instanceof MemoryError) throw err;
|
|
130
|
+
throw new MemoryError(`Failed to append memory at ${filePath}: ${err}`);
|
|
131
|
+
}
|
|
132
|
+
}).finally(() => {
|
|
133
|
+
if (memoryWriteQueues.get(key) === next) {
|
|
134
|
+
memoryWriteQueues.delete(key);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
memoryWriteQueues.set(key, next);
|
|
138
|
+
return next;
|
|
139
|
+
}
|
|
140
|
+
var ENTRY_SEPARATOR = "\n---\n\n";
|
|
141
|
+
function truncateToFit(existing, incoming) {
|
|
142
|
+
const segments = existing.split(ENTRY_SEPARATOR);
|
|
143
|
+
const header = segments[0];
|
|
144
|
+
const budget = MAX_MEMORY_SIZE - Buffer.byteLength(incoming, "utf-8");
|
|
145
|
+
const kept = [];
|
|
146
|
+
let size = Buffer.byteLength(header, "utf-8");
|
|
147
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
148
|
+
const segSize = Buffer.byteLength(ENTRY_SEPARATOR + segments[i], "utf-8");
|
|
149
|
+
if (size + segSize > budget) break;
|
|
150
|
+
size += segSize;
|
|
151
|
+
kept.unshift(segments[i]);
|
|
152
|
+
}
|
|
153
|
+
const truncated = kept.length > 0 ? header + ENTRY_SEPARATOR + kept.join(ENTRY_SEPARATOR) : header;
|
|
154
|
+
return truncated + incoming;
|
|
155
|
+
}
|
|
156
|
+
function deleteMemory(scope) {
|
|
157
|
+
if (scope.type === "session") {
|
|
158
|
+
throw new MemoryError(
|
|
159
|
+
"Session memory is stored within the session file. Use deleteSession() to remove."
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const filePath = resolveMemoryPath(scope);
|
|
163
|
+
if (!filePath) return;
|
|
164
|
+
try {
|
|
165
|
+
try {
|
|
166
|
+
fs.unlinkSync(filePath);
|
|
167
|
+
} catch (unlinkErr) {
|
|
168
|
+
const isNotFound = unlinkErr.code === "ENOENT" || unlinkErr instanceof Error && unlinkErr.message.includes("ENOENT");
|
|
169
|
+
if (!isNotFound) throw unlinkErr;
|
|
170
|
+
}
|
|
171
|
+
const dir = path.dirname(filePath);
|
|
172
|
+
try {
|
|
173
|
+
const remaining = fs.readdirSync(dir);
|
|
174
|
+
if (remaining.length === 0) {
|
|
175
|
+
fs.rmdirSync(dir);
|
|
176
|
+
}
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
} catch (err) {
|
|
180
|
+
throw new MemoryError(`Failed to delete memory at ${filePath}: ${err}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function buildMemoryHeader(scope) {
|
|
184
|
+
switch (scope.type) {
|
|
185
|
+
case "global":
|
|
186
|
+
return "# Global Memory\n\nPersistent knowledge shared across all projects and sessions.\n";
|
|
187
|
+
case "project":
|
|
188
|
+
return `# Project Memory
|
|
189
|
+
|
|
190
|
+
Knowledge specific to project: ${scope.path}
|
|
191
|
+
`;
|
|
192
|
+
case "agent":
|
|
193
|
+
return `# Agent Memory: ${scope.agentId}
|
|
194
|
+
|
|
195
|
+
Knowledge specific to agent: ${scope.agentId}
|
|
196
|
+
`;
|
|
197
|
+
default:
|
|
198
|
+
return "# Memory\n";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function listMemoryScopes() {
|
|
202
|
+
const root = getMemoryRoot();
|
|
203
|
+
const scopes = [];
|
|
204
|
+
if (fs.existsSync(path.join(root, "global.md"))) {
|
|
205
|
+
scopes.push({ type: "global" });
|
|
206
|
+
}
|
|
207
|
+
const projectsDir = path.join(root, "projects");
|
|
208
|
+
if (fs.existsSync(projectsDir)) {
|
|
209
|
+
try {
|
|
210
|
+
const projectDirs = fs.readdirSync(projectsDir, { withFileTypes: true });
|
|
211
|
+
for (const entry of projectDirs) {
|
|
212
|
+
if (entry.isDirectory()) {
|
|
213
|
+
const projectFile = path.join(projectsDir, entry.name, "project.md");
|
|
214
|
+
if (fs.existsSync(projectFile)) {
|
|
215
|
+
const content = fs.readFileSync(projectFile, "utf-8");
|
|
216
|
+
const pathMatch = content.match(/project:\s*(.+)/);
|
|
217
|
+
const projectPath = pathMatch ? pathMatch[1].trim() : entry.name;
|
|
218
|
+
scopes.push({ type: "project", path: projectPath });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const agentsDir = path.join(root, "agents");
|
|
226
|
+
if (fs.existsSync(agentsDir)) {
|
|
227
|
+
try {
|
|
228
|
+
const agentFiles = fs.readdirSync(agentsDir).filter((f) => f.endsWith(".md"));
|
|
229
|
+
for (const file of agentFiles) {
|
|
230
|
+
const agentId = file.replace(/\.md$/, "");
|
|
231
|
+
scopes.push({ type: "agent", agentId });
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return scopes;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export {
|
|
240
|
+
getMemory,
|
|
241
|
+
updateMemory,
|
|
242
|
+
appendMemory,
|
|
243
|
+
deleteMemory,
|
|
244
|
+
listMemoryScopes
|
|
245
|
+
};
|
|
246
|
+
//# sourceMappingURL=chunk-E5A3SCDJ.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// apps/gateway/dist/kaala/tree.js
|
|
2
|
+
function buildKaalaHealthNode(snapshot) {
|
|
3
|
+
const issueHistory = snapshot.history?.issues ?? snapshot.issues.map((issue) => ({ ...issue }));
|
|
4
|
+
const issueNodes = issueHistory.slice().sort((a, b) => a.detectedAt.localeCompare(b.detectedAt)).map((issue) => ({
|
|
5
|
+
id: `kaala.issue.${issue.id}.${issue.detectedAt}`,
|
|
6
|
+
status: issue.resolvedAt ? "resolved" : issue.severity,
|
|
7
|
+
lane: issue.category,
|
|
8
|
+
createdAt: issue.detectedAt,
|
|
9
|
+
startedAt: issue.detectedAt,
|
|
10
|
+
endedAt: issue.resolvedAt,
|
|
11
|
+
parentRunId: "kaala.health",
|
|
12
|
+
summary: issue.description,
|
|
13
|
+
error: issue.resolvedAt ? void 0 : issue.description,
|
|
14
|
+
children: []
|
|
15
|
+
}));
|
|
16
|
+
return {
|
|
17
|
+
id: "kaala.health",
|
|
18
|
+
status: snapshot.status,
|
|
19
|
+
lane: "health",
|
|
20
|
+
createdAt: snapshot.updatedAt,
|
|
21
|
+
startedAt: snapshot.lastHeartbeatAt ?? snapshot.updatedAt,
|
|
22
|
+
summary: `issues=${snapshot.issues.length}`,
|
|
23
|
+
children: issueNodes,
|
|
24
|
+
health: snapshot
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function buildAgentTree(records) {
|
|
28
|
+
const index = /* @__PURE__ */ new Map();
|
|
29
|
+
for (const record of records) {
|
|
30
|
+
index.set(record.id, {
|
|
31
|
+
id: record.id,
|
|
32
|
+
status: record.status,
|
|
33
|
+
lane: record.lane,
|
|
34
|
+
createdAt: record.createdAt,
|
|
35
|
+
startedAt: record.startedAt,
|
|
36
|
+
endedAt: record.endedAt,
|
|
37
|
+
parentRunId: record.parentRunId,
|
|
38
|
+
sessionId: record.sessionId,
|
|
39
|
+
summary: record.resultSummary,
|
|
40
|
+
error: record.error,
|
|
41
|
+
children: []
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const roots = [];
|
|
45
|
+
for (const node of index.values()) {
|
|
46
|
+
if (node.parentRunId && index.has(node.parentRunId)) {
|
|
47
|
+
index.get(node.parentRunId).children.push(node);
|
|
48
|
+
} else {
|
|
49
|
+
roots.push(node);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const sortByCreated = (a, b) => a.createdAt.localeCompare(b.createdAt);
|
|
53
|
+
const sortTree = (nodes) => {
|
|
54
|
+
nodes.sort(sortByCreated);
|
|
55
|
+
for (const node of nodes) {
|
|
56
|
+
if (node.children.length > 0) {
|
|
57
|
+
sortTree(node.children);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
sortTree(roots);
|
|
62
|
+
return roots;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export {
|
|
66
|
+
buildKaalaHealthNode,
|
|
67
|
+
buildAgentTree
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=chunk-G5VYCA6O.js.map
|