@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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +365 -0
  3. package/chunks/chunk-E5A3SCDJ.js +246 -0
  4. package/chunks/chunk-G5VYCA6O.js +69 -0
  5. package/chunks/chunk-H76V36OF.js +1029 -0
  6. package/chunks/chunk-HAPVUJ6A.js +238 -0
  7. package/chunks/chunk-IEKAYVA3.js +137 -0
  8. package/chunks/chunk-IGKYKEKT.js +43 -0
  9. package/chunks/chunk-IIET2K6D.js +7728 -0
  10. package/chunks/chunk-ITIVYGUG.js +347 -0
  11. package/chunks/chunk-JAWZ7ANC.js +208 -0
  12. package/chunks/chunk-JZU37VQ5.js +714 -0
  13. package/chunks/chunk-KC6NRZ7U.js +198 -0
  14. package/chunks/chunk-KDRROLVN.js +433 -0
  15. package/chunks/chunk-L7JICQBW.js +1006 -0
  16. package/chunks/chunk-MINFB5LT.js +1479 -0
  17. package/chunks/chunk-MJ74G5RB.js +5816 -0
  18. package/chunks/chunk-S4TBVCL2.js +2158 -0
  19. package/chunks/chunk-SMVJRPAH.js +2753 -0
  20. package/chunks/chunk-U6OLJ36B.js +438 -0
  21. package/chunks/chunk-URGEODS5.js +752 -0
  22. package/chunks/chunk-YSU3BWV6.js +123 -0
  23. package/chunks/consolidation-indexer-TOTTDZXW.js +21 -0
  24. package/chunks/day-consolidation-NKO63HZQ.js +24 -0
  25. package/chunks/graphrag-ZI2FSU7S.js +13 -0
  26. package/chunks/hierarchical-temporal-search-ZD46UMKR.js +8 -0
  27. package/chunks/hybrid-search-ZVLZVGFS.js +19 -0
  28. package/chunks/memory-store-KNJPMBLQ.js +17 -0
  29. package/chunks/periodic-consolidation-BPKOZDGB.js +10 -0
  30. package/chunks/postgres-3ZXBYTPC.js +8 -0
  31. package/chunks/recall-GMVHWQWW.js +20 -0
  32. package/chunks/search-7HZETVMZ.js +18 -0
  33. package/chunks/session-store-XKPGKXUS.js +44 -0
  34. package/chunks/sqlite-JPF5TICX.js +152 -0
  35. package/chunks/src-6GVZTUH6.js +12 -0
  36. package/chunks/src-QAXOD5SB.js +273 -0
  37. package/chunks/suncalc-NOHGYHDU.js +186 -0
  38. package/chunks/tree-RSHKDTCR.js +10 -0
  39. package/gateway.js +61944 -0
  40. package/package.json +51 -0
  41. 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