@0xmaxma/claude-gateway 1.6.8 → 1.7.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/README.md +149 -20
- package/config.template.json +59 -1
- package/dist/agent/dreaming/accept.d.ts +43 -0
- package/dist/agent/dreaming/accept.d.ts.map +1 -0
- package/dist/agent/dreaming/accept.js +230 -0
- package/dist/agent/dreaming/accept.js.map +1 -0
- package/dist/agent/dreaming/applier.d.ts +77 -0
- package/dist/agent/dreaming/applier.d.ts.map +1 -0
- package/dist/agent/dreaming/applier.js +406 -0
- package/dist/agent/dreaming/applier.js.map +1 -0
- package/dist/agent/dreaming/audit.d.ts +27 -0
- package/dist/agent/dreaming/audit.d.ts.map +1 -0
- package/dist/agent/dreaming/audit.js +100 -0
- package/dist/agent/dreaming/audit.js.map +1 -0
- package/dist/agent/dreaming/compactor.d.ts +66 -0
- package/dist/agent/dreaming/compactor.d.ts.map +1 -0
- package/dist/agent/dreaming/compactor.js +306 -0
- package/dist/agent/dreaming/compactor.js.map +1 -0
- package/dist/agent/dreaming/config.d.ts +19 -0
- package/dist/agent/dreaming/config.d.ts.map +1 -0
- package/dist/agent/dreaming/config.js +107 -0
- package/dist/agent/dreaming/config.js.map +1 -0
- package/dist/agent/dreaming/episodic.d.ts +42 -0
- package/dist/agent/dreaming/episodic.d.ts.map +1 -0
- package/dist/agent/dreaming/episodic.js +116 -0
- package/dist/agent/dreaming/episodic.js.map +1 -0
- package/dist/agent/dreaming/gather.d.ts +31 -0
- package/dist/agent/dreaming/gather.d.ts.map +1 -0
- package/dist/agent/dreaming/gather.js +55 -0
- package/dist/agent/dreaming/gather.js.map +1 -0
- package/dist/agent/dreaming/index.d.ts +87 -0
- package/dist/agent/dreaming/index.d.ts.map +1 -0
- package/dist/agent/dreaming/index.js +377 -0
- package/dist/agent/dreaming/index.js.map +1 -0
- package/dist/agent/dreaming/migrate-cli.d.ts +17 -0
- package/dist/agent/dreaming/migrate-cli.d.ts.map +1 -0
- package/dist/agent/dreaming/migrate-cli.js +42 -0
- package/dist/agent/dreaming/migrate-cli.js.map +1 -0
- package/dist/agent/dreaming/migrate.d.ts +72 -0
- package/dist/agent/dreaming/migrate.d.ts.map +1 -0
- package/dist/agent/dreaming/migrate.js +374 -0
- package/dist/agent/dreaming/migrate.js.map +1 -0
- package/dist/agent/dreaming/report.d.ts +39 -0
- package/dist/agent/dreaming/report.d.ts.map +1 -0
- package/dist/agent/dreaming/report.js +121 -0
- package/dist/agent/dreaming/report.js.map +1 -0
- package/dist/agent/dreaming/reviewer.d.ts +43 -0
- package/dist/agent/dreaming/reviewer.d.ts.map +1 -0
- package/dist/agent/dreaming/reviewer.js +249 -0
- package/dist/agent/dreaming/reviewer.js.map +1 -0
- package/dist/agent/dreaming/staleness.d.ts +68 -0
- package/dist/agent/dreaming/staleness.d.ts.map +1 -0
- package/dist/agent/dreaming/staleness.js +281 -0
- package/dist/agent/dreaming/staleness.js.map +1 -0
- package/dist/agent/dreaming/types.d.ts +130 -0
- package/dist/agent/dreaming/types.d.ts.map +1 -0
- package/dist/agent/dreaming/types.js +10 -0
- package/dist/agent/dreaming/types.js.map +1 -0
- package/dist/agent/knowledge/archive-db.d.ts +114 -0
- package/dist/agent/knowledge/archive-db.d.ts.map +1 -0
- package/dist/agent/knowledge/archive-db.js +474 -0
- package/dist/agent/knowledge/archive-db.js.map +1 -0
- package/dist/agent/knowledge/chunk.d.ts +21 -0
- package/dist/agent/knowledge/chunk.d.ts.map +1 -0
- package/dist/agent/knowledge/chunk.js +67 -0
- package/dist/agent/knowledge/chunk.js.map +1 -0
- package/dist/agent/knowledge/config.d.ts +20 -0
- package/dist/agent/knowledge/config.d.ts.map +1 -0
- package/dist/agent/knowledge/config.js +143 -0
- package/dist/agent/knowledge/config.js.map +1 -0
- package/dist/agent/knowledge/graph-demo.d.ts +25 -0
- package/dist/agent/knowledge/graph-demo.d.ts.map +1 -0
- package/dist/agent/knowledge/graph-demo.js +132 -0
- package/dist/agent/knowledge/graph-demo.js.map +1 -0
- package/dist/agent/knowledge/index.d.ts +24 -0
- package/dist/agent/knowledge/index.d.ts.map +1 -0
- package/dist/agent/knowledge/index.js +50 -0
- package/dist/agent/knowledge/index.js.map +1 -0
- package/dist/agent/knowledge/indexer.d.ts +34 -0
- package/dist/agent/knowledge/indexer.d.ts.map +1 -0
- package/dist/agent/knowledge/indexer.js +271 -0
- package/dist/agent/knowledge/indexer.js.map +1 -0
- package/dist/agent/knowledge/lifecycle.d.ts +91 -0
- package/dist/agent/knowledge/lifecycle.d.ts.map +1 -0
- package/dist/agent/knowledge/lifecycle.js +205 -0
- package/dist/agent/knowledge/lifecycle.js.map +1 -0
- package/dist/agent/knowledge/provenance.d.ts +15 -0
- package/dist/agent/knowledge/provenance.d.ts.map +1 -0
- package/dist/agent/knowledge/provenance.js +37 -0
- package/dist/agent/knowledge/provenance.js.map +1 -0
- package/dist/agent/knowledge/reindex-cli.d.ts +13 -0
- package/dist/agent/knowledge/reindex-cli.d.ts.map +1 -0
- package/dist/agent/knowledge/reindex-cli.js +53 -0
- package/dist/agent/knowledge/reindex-cli.js.map +1 -0
- package/dist/agent/knowledge/reindex-spawn.d.ts +30 -0
- package/dist/agent/knowledge/reindex-spawn.d.ts.map +1 -0
- package/dist/agent/knowledge/reindex-spawn.js +97 -0
- package/dist/agent/knowledge/reindex-spawn.js.map +1 -0
- package/dist/agent/knowledge/shared-promote.d.ts +18 -0
- package/dist/agent/knowledge/shared-promote.d.ts.map +1 -0
- package/dist/agent/knowledge/shared-promote.js +29 -0
- package/dist/agent/knowledge/shared-promote.js.map +1 -0
- package/dist/agent/knowledge/shared-writer.d.ts +24 -0
- package/dist/agent/knowledge/shared-writer.d.ts.map +1 -0
- package/dist/agent/knowledge/shared-writer.js +97 -0
- package/dist/agent/knowledge/shared-writer.js.map +1 -0
- package/dist/agent/knowledge/types.d.ts +83 -0
- package/dist/agent/knowledge/types.d.ts.map +1 -0
- package/dist/agent/knowledge/types.js +12 -0
- package/dist/agent/knowledge/types.js.map +1 -0
- package/dist/agent/knowledge/wiki.d.ts +107 -0
- package/dist/agent/knowledge/wiki.d.ts.map +1 -0
- package/dist/agent/knowledge/wiki.js +415 -0
- package/dist/agent/knowledge/wiki.js.map +1 -0
- package/dist/agent/memory-metrics.d.ts +48 -0
- package/dist/agent/memory-metrics.d.ts.map +1 -0
- package/dist/agent/memory-metrics.js +156 -0
- package/dist/agent/memory-metrics.js.map +1 -0
- package/dist/agent/runner.d.ts +24 -1
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +82 -6
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/skill-learning/config.d.ts +18 -0
- package/dist/agent/skill-learning/config.d.ts.map +1 -0
- package/dist/agent/skill-learning/config.js +71 -0
- package/dist/agent/skill-learning/config.js.map +1 -0
- package/dist/agent/skill-learning/curator.d.ts +45 -0
- package/dist/agent/skill-learning/curator.d.ts.map +1 -0
- package/dist/agent/skill-learning/curator.js +171 -0
- package/dist/agent/skill-learning/curator.js.map +1 -0
- package/dist/agent/skill-learning/index.d.ts +79 -0
- package/dist/agent/skill-learning/index.d.ts.map +1 -0
- package/dist/agent/skill-learning/index.js +308 -0
- package/dist/agent/skill-learning/index.js.map +1 -0
- package/dist/agent/skill-learning/metrics.d.ts +13 -0
- package/dist/agent/skill-learning/metrics.d.ts.map +1 -0
- package/dist/agent/skill-learning/metrics.js +109 -0
- package/dist/agent/skill-learning/metrics.js.map +1 -0
- package/dist/agent/skill-learning/notifier.d.ts +111 -0
- package/dist/agent/skill-learning/notifier.d.ts.map +1 -0
- package/dist/agent/skill-learning/notifier.js +398 -0
- package/dist/agent/skill-learning/notifier.js.map +1 -0
- package/dist/agent/skill-learning/reviewer.d.ts +61 -0
- package/dist/agent/skill-learning/reviewer.d.ts.map +1 -0
- package/dist/agent/skill-learning/reviewer.js +271 -0
- package/dist/agent/skill-learning/reviewer.js.map +1 -0
- package/dist/agent/skill-learning/telemetry.d.ts +22 -0
- package/dist/agent/skill-learning/telemetry.d.ts.map +1 -0
- package/dist/agent/skill-learning/telemetry.js +90 -0
- package/dist/agent/skill-learning/telemetry.js.map +1 -0
- package/dist/agent/skill-learning/trigger.d.ts +23 -0
- package/dist/agent/skill-learning/trigger.d.ts.map +1 -0
- package/dist/agent/skill-learning/trigger.js +44 -0
- package/dist/agent/skill-learning/trigger.js.map +1 -0
- package/dist/agent/skill-learning/types.d.ts +165 -0
- package/dist/agent/skill-learning/types.d.ts.map +1 -0
- package/dist/agent/skill-learning/types.js +11 -0
- package/dist/agent/skill-learning/types.js.map +1 -0
- package/dist/agent/skill-learning/writer.d.ts +37 -0
- package/dist/agent/skill-learning/writer.d.ts.map +1 -0
- package/dist/agent/skill-learning/writer.js +223 -0
- package/dist/agent/skill-learning/writer.js.map +1 -0
- package/dist/agent/workspace-loader.d.ts +83 -6
- package/dist/agent/workspace-loader.d.ts.map +1 -1
- package/dist/agent/workspace-loader.js +207 -14
- package/dist/agent/workspace-loader.js.map +1 -1
- package/dist/api/gateway-router.d.ts +2 -0
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +293 -6
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/share-router.d.ts.map +1 -1
- package/dist/api/share-router.js +27 -1
- package/dist/api/share-router.js.map +1 -1
- package/dist/api/skills-router.d.ts +2 -2
- package/dist/api/skills-router.d.ts.map +1 -1
- package/dist/api/skills-router.js +61 -1
- package/dist/api/skills-router.js.map +1 -1
- package/dist/apps/agent-manager.d.ts +7 -0
- package/dist/apps/agent-manager.d.ts.map +1 -1
- package/dist/apps/agent-manager.js +13 -1
- package/dist/apps/agent-manager.js.map +1 -1
- package/dist/config/migrator.d.ts +2 -0
- package/dist/config/migrator.d.ts.map +1 -1
- package/dist/config/migrator.js +72 -1
- package/dist/config/migrator.js.map +1 -1
- package/dist/history/cleanup.d.ts +7 -0
- package/dist/history/cleanup.d.ts.map +1 -1
- package/dist/history/cleanup.js +27 -0
- package/dist/history/cleanup.js.map +1 -1
- package/dist/history/db.d.ts +65 -0
- package/dist/history/db.d.ts.map +1 -1
- package/dist/history/db.js +261 -0
- package/dist/history/db.js.map +1 -1
- package/dist/index.js +122 -20
- package/dist/index.js.map +1 -1
- package/dist/session/process.d.ts +10 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +86 -1
- package/dist/session/process.js.map +1 -1
- package/dist/share/share-store.d.ts +11 -0
- package/dist/share/share-store.d.ts.map +1 -1
- package/dist/share/share-store.js +3 -1
- package/dist/share/share-store.js.map +1 -1
- package/dist/skills/loader.d.ts +8 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +29 -1
- package/dist/skills/loader.js.map +1 -1
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/web-ui.d.ts.map +1 -1
- package/dist/ui/web-ui.js +1126 -3
- package/dist/ui/web-ui.js.map +1 -1
- package/mcp/package.json +2 -1
- package/mcp/server.ts +2 -0
- package/mcp/tools/image/module.ts +114 -9
- package/mcp/tools/memory/archive-reader.test.ts +212 -0
- package/mcp/tools/memory/archive-reader.ts +253 -0
- package/mcp/tools/memory/module.ts +152 -0
- package/mcp/tools/memory/retrieval-recorder.ts +66 -0
- package/mcp/tools/shared/share-client.ts +20 -1
- package/mcp/tools/skills/module.ts +28 -0
- package/package.json +1 -1
- package/resource/claude_gateway.svg +1038 -112
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
# Claude Gateway
|
|
3
3
|
|
|
4
|
-
A self-hosted multi-agent gateway for Claude Code
|
|
4
|
+
A self-hosted multi-agent gateway for Claude Code — with agents that improve themselves, manage their own memory through nightly dreaming, and build a searchable knowledge base from what they learn.
|
|
5
5
|
|
|
6
6
|
<p align="center">
|
|
7
7
|
<img src="resource/claude_gateway.svg" alt="Claude Gateway" width="680" />
|
|
@@ -11,25 +11,28 @@ A self-hosted multi-agent gateway for Claude Code. Connect Claude agents to Tele
|
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
-
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **Auto-
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
-
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
14
|
+
- 🧠 **Skill self-improvement** — agents learn reusable skills from their own work: after a substantive turn a background reviewer creates or updates a skill, hot-reloaded for the next turn. Provenance-guarded (never overwrites human-written skills), capped per day, and audited to `SKILLS_LEARNED.md`. See [`gateway.skillLearning`](#gatewayskilllearning)
|
|
15
|
+
- 📚 **Knowledge base (two-lane memory)** — per-agent SQLite/FTS5 searchable archive exposed through `memory_search` / `memory_get` MCP tools, so agents recall notes that don't fit the always-injected core; chunks carry fail-closed provenance and the index is refreshed off the gateway event loop. See [`gateway.knowledge`](#gatewayknowledge)
|
|
16
|
+
- 🌙 **Nightly dreaming** — background consolidation of long-term memory: a print-only reviewer proposes ops that a safe applier writes to `MEMORY.md` / `USER.md` (backup, bounded-loss, net-negative when over budget). Deterministic compaction, budget-scaled pruning, and staleness GC keep memory near budget without forgetting — archived entries stay searchable. See [`gateway.dreaming`](#gatewaydreaming)
|
|
17
|
+
- 🤖 **Multi-agent** — run multiple bots from a single gateway, each with isolated sessions
|
|
18
|
+
- 🔌 **Multi-channel MCP** — modular tool system per channel (Telegram, Discord, Cron, Skills, extensible to Slack/WhatsApp)
|
|
19
|
+
- 🧩 **Agent skills** — extensible skill system via SKILL.md files; agents can create, delete, and install skills from URLs at runtime with hot-reload
|
|
20
|
+
- 🎭 **Agent identity** — define personality, tone, and rules via workspace markdown files
|
|
21
|
+
- 📡 **Live status messages** — real-time status updates showing tool usage, thinking, and progress
|
|
22
|
+
- ⌨️ **Typing indicators** — continuous typing animation while the agent is working (Telegram and Discord)
|
|
23
|
+
- 🌊 **Streaming API** — SSE (Server-Sent Events) endpoint for real-time response streaming
|
|
24
|
+
- ↪️ **Auto-forward** — agent text output automatically forwarded to Telegram even without explicit reply tool calls
|
|
25
|
+
- ⏰ **Heartbeat / scheduled tasks** — cron-based proactive messages and recurring tasks via HEARTBEAT.md + REST API; agent jobs deliver output to Telegram, Discord, or both
|
|
26
|
+
- 💬 **Persistent chat history** — two-layer storage: session context (`.jsonl`) + permanent SQLite DB with FTS5 full-text search; survives `/compact` and session eviction
|
|
27
|
+
- 🧹 **Auto-cleanup** — configurable retention policy prunes messages and media files older than N days on a daily schedule
|
|
28
|
+
- 🗄️ **Long-term memory** — persistent memory system across sessions
|
|
29
|
+
- 🔄 **Config auto-migration** — automatic schema migration when config format changes
|
|
30
|
+
- 🔐 **Access control** — allowlist, open, or pairing-based Telegram access policies
|
|
31
|
+
- 🌐 **HTTP API** — REST API with key-based auth for external integrations
|
|
32
|
+
- 🛍️ **App Store** — install, update, and host Docker-compose apps on the gateway; apps get a reverse proxy at `/app/:name/:portName/*`, optional Unix socket bridge for host scripts, and optional AI agent injection
|
|
33
|
+
- ⬆️ **Self-update API** — check for newer versions of `claude-gateway` and `claude-code` and trigger an update via a single API call; no SSH or shell access needed
|
|
34
|
+
- 💾 **Session persistence** — conversation history saved and restored across restarts
|
|
35
|
+
- 🖥️ **PTY shell (wrap-shell mode)** — optional interactive pseudo-terminal backend (`gateway.headless: false`) for tools that require a real TTY; includes a live browser viewer (xterm.js) and a `/api/v1/sessions/:sessionId/screen` endpoint that returns the visible screen as plain text — agents can poll it to detect hang states, menus, or unexpected output without parsing ANSI escape codes; a `/cli` chat command (Telegram/Discord/LINE) opens the same viewer for a single agent, agent-scoped and without an admin key; app-agents always stay headless
|
|
33
36
|
|
|
34
37
|
---
|
|
35
38
|
|
|
@@ -338,6 +341,120 @@ Recovery actions are clamped to a per-stage whitelist and a per-turn budget, and
|
|
|
338
341
|
}
|
|
339
342
|
```
|
|
340
343
|
|
|
344
|
+
### `gateway.skillLearning`
|
|
345
|
+
|
|
346
|
+
Controls [skill self-improvement](#skill-self-improvement) — agents learning reusable skills from their own work. Telemetry capture is always on; the reviewer/writer/curator honor `enabled`.
|
|
347
|
+
|
|
348
|
+
| Field | Default | Description |
|
|
349
|
+
|-------|---------|-------------|
|
|
350
|
+
| `enabled` | `true` | Master switch for the reviewer/writer/curator (telemetry is captured regardless) |
|
|
351
|
+
| `mode` | `"auto"` | `auto` writes skills directly; `propose` queues them for approval instead |
|
|
352
|
+
| `minToolCalls` | `5` | Minimum tool calls in a turn before it's eligible for review |
|
|
353
|
+
| `reviewModel` | `claude-haiku-4-5-…` | Model used for the background review pass |
|
|
354
|
+
| `maxAutoSkills` | `50` | Cap on the number of non-pinned `origin: auto` skills kept per agent (pinned skills are never evicted and don't count toward the cap) |
|
|
355
|
+
| `maxAgeDays` | `30` | Curator prunes auto-skills older than this (with too few uses) |
|
|
356
|
+
| `minUsesToKeep` | `2` | Auto-skills used fewer times than this are prune candidates |
|
|
357
|
+
| `maxReviewsPerDay` | `20` | Per-day cap on background review runs |
|
|
358
|
+
| `pruneHour` / `pruneTimezone` | `3` / `UTC` | When the daily curator runs |
|
|
359
|
+
| `notify` | `true` | Push a per-write ping to every configured channel (see [notifications](#skill-self-improvement)); the `SKILLS_LEARNED.md` diary is written regardless |
|
|
360
|
+
|
|
361
|
+
```json
|
|
362
|
+
{
|
|
363
|
+
"gateway": {
|
|
364
|
+
"skillLearning": {
|
|
365
|
+
"enabled": true,
|
|
366
|
+
"mode": "auto",
|
|
367
|
+
"notify": true
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Per-agent overrides are supported under the agent's own `skillLearning` block; unset fields fall back to the gateway default.
|
|
374
|
+
|
|
375
|
+
### `gateway.memory`
|
|
376
|
+
|
|
377
|
+
Memory budget discipline. Self-authored memory files (`MEMORY.md`, `USER.md`) that exceed a **soft** char budget get a loud over-budget banner prepended to their `CLAUDE.md` section at compose time — instead of a silent `[TRUNCATED]` — nudging the agent to consolidate. The banner reaches the agent on its next spawn (frozen-at-spawn, no restart) and self-heals once the file is back under budget. The banner lives only in the composed `CLAUDE.md`; the source file on disk is never rewritten with it.
|
|
378
|
+
|
|
379
|
+
| Field | Default | Description |
|
|
380
|
+
|-------|---------|-------------|
|
|
381
|
+
| `memoryBudgetChars` | `8000` | Soft budget for `MEMORY.md` (`0` = disabled) |
|
|
382
|
+
| `userBudgetChars` | `3000` | Soft budget for `USER.md` (`0` = disabled) |
|
|
383
|
+
| `overBudget` | `"warn"` | Banner severity: `warn` (⚠️) or `error` (🛑, stronger wording); an unknown value falls back to `warn` |
|
|
384
|
+
| `writeRouting` | `true` | Inject the **two-tier write contract** into the Memory Rule (`MEMORY.md` = durable facts; task-log → `memory/<topic>.md`) and let nightly dreaming route episodic ops out. `false` = kill-switch (exact pre-routing behavior) |
|
|
385
|
+
| `episodicArchiveDir` | `"memory"` | Workspace-relative dir episodic notes are written under (validated, path-traversal-guarded) |
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"gateway": {
|
|
390
|
+
"memory": {
|
|
391
|
+
"memoryBudgetChars": 8000,
|
|
392
|
+
"userBudgetChars": 3000,
|
|
393
|
+
"overBudget": "warn",
|
|
394
|
+
"writeRouting": true,
|
|
395
|
+
"episodicArchiveDir": "memory"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
The soft budget sits well under the hard per-file limit (still applied as a context safety net); the banner is the primary over-budget signal for memory files.
|
|
402
|
+
|
|
403
|
+
**Write routing (planning-65).** `MEMORY.md` is injected into every prompt, so it should hold only **durable semantic facts** (preferences, standing rules, identity, lessons). **Episodic task-log** (completed work, PR/issue status, dated events) belongs in `memory/<topic>.md` — indexed and retrieved on demand via `memory_search`, never carried in-prompt. When `writeRouting` is on, the Memory Rule states this tier contract to the agent, and the nightly dreaming reviewer may emit `tier:"episodic"` ops that the applier appends to `memory/<topic>.md` (slug-validated + realpath-confined; a memory-only change ⇒ no session restart). To drain an existing over-budget `MEMORY.md`, run the one-shot migration `node dist/agent/dreaming/migrate-cli.js <workspaceDir> [--apply]` — a deterministic terminal sweep (compactor) plus a gated episodic route-out (`propose` writes `.dreaming/migration-plan.md`; `--apply` performs the moves). Pinned sections (`## User`, `## Feedback`, `## Preferences`) are never moved, and every relocated entry stays searchable via `memory_search` (recall preserved). **planning-67:** with `gateway.dreaming.autoRouteOut` on (the default), the nightly dream performs this same route-out **automatically** whenever `MEMORY.md` is over budget — no manual per-agent run — and every over-budget net-shrink `remove` now **relocates** its block to `memory/archive/pruned.md` (searchable) before cutting it, so no dream op ever silently forgets.
|
|
404
|
+
|
|
405
|
+
### `gateway.dreaming`
|
|
406
|
+
|
|
407
|
+
Nightly memory **dreaming** — background consolidation of an agent's long-term memory. A print-only `claude -p` reviewer (no tools, no `--dangerously-skip-permissions`) reads a lookback window of the agent's own session transcripts and proposes memory-consolidation ops. In **`auto`** mode (the default) a safe applier writes the ops to `MEMORY.md`/`USER.md` (rollback pre-image first; ordered apply with anchor re-resolution; bounded-loss + append-only fallback; net-negative when over budget) — a memory-only change, so no session is restarted. In **`propose`** mode the proposals are written **only** to a `DREAMS.md` diary + JSONL audit under `<workspace>/.dreaming/` — no memory file is modified (set `mode: "propose"` to keep this dry-run behavior).
|
|
408
|
+
|
|
409
|
+
| Field | Default | Description |
|
|
410
|
+
|-------|---------|-------------|
|
|
411
|
+
| `enabled` | `true` | Master switch (`false` ⇒ no scheduler, no run) |
|
|
412
|
+
| `mode` | `"auto"` | `auto` = apply ops via the safe applier (backup, bounded-loss, net-negative); `propose` = diary-only dry-run |
|
|
413
|
+
| `dreamHour` / `dreamTimezone` | `3` / `UTC` | When the nightly dream runs (invalid tz → UTC) |
|
|
414
|
+
| `dreamMinute` | `0` | Minute-of-hour the dream fires at, paired with `dreamHour` (0–59). Set with `staggerWindowMinutes: 0` to fire at an exact `HH:MM` (e.g. for a controlled re-test) |
|
|
415
|
+
| `quietMinutes` | `30` | Skip a run if a session was active within this window |
|
|
416
|
+
| `lookbackDays` | `3` | How far back to scan sessions |
|
|
417
|
+
| `maxChangesPerRun` | `3` | Cap on proposed ops per run (`0` ⇒ no-op) |
|
|
418
|
+
| `reviewModel` | `claude-haiku-4-5-…` | Cheap model for the reviewer |
|
|
419
|
+
| `promotionThreshold` / `minRecallCount` | `0.6` / `2` | Scoring thresholds for promoting a fact |
|
|
420
|
+
| `autoRouteOut` | `true` | planning-67: in `auto` mode, drain an **over-budget** `MEMORY.md` by routing its episodic task-log to `memory/<topic>.md` automatically each night (archive-safe, pinned excluded, idempotent) instead of a manual per-agent `migrate-cli`. `false` = kill-switch |
|
|
421
|
+
| `staggerWindowMinutes` | `30` | planning-68: spread agents' nightly runs across a window (a deterministic per-agent jitter is added to the delay) so they don't all fire at `dreamHour:00` together. Clamped `[0,55]`; `0` = disabled (all fire at `dreamHour:00`) |
|
|
422
|
+
| `staleness` | *(object)* | Archive staleness GC sub-config (planning-66) — see below |
|
|
423
|
+
|
|
424
|
+
Per-agent overrides are supported under the agent's own `dreaming` block; unset fields fall back to the gateway default. `enabled:false` or `maxChangesPerRun:0` makes a run a no-op.
|
|
425
|
+
|
|
426
|
+
> **⚠️ Upgrade note:** the default `mode` for both `gateway.dreaming` and `gateway.knowledge.shared` changed from `propose` (dry-run) to `auto` (configVersion 1.0.24). Once the K4 applier landed (backup + net-negative + bounded-loss + CAS + never-empty; memory-only write ⇒ no session restart), `auto` became the intended default: nightly dreaming now applies consolidation to `MEMORY.md`/`USER.md` and promotes durable memories to the shared vault. Like the `gateway.bind` migration, the migrator upgrades the *retired* `propose` default to `auto` once and logs a one-time warning; an explicit `mode` you set at 1.0.24+ is never touched. To keep dry-run, set `mode: "propose"` explicitly.
|
|
427
|
+
|
|
428
|
+
**Keeping `MEMORY.md` near budget (`auto` mode).** Two mechanisms stop the on-disk `MEMORY.md` from growing unbounded while preserving recall:
|
|
429
|
+
|
|
430
|
+
- **Deterministic compaction** — before the LLM reviewer, every `auto` run moves completed/terminal log entries out of `MEMORY.md` into `memory/archive/completed.md`, leaving a one-line pointer. It is **domain-agnostic** (not just dev): an entry is archived when its lead line carries an explicit done marker — an UPPERCASE status word (`DONE`, `COMPLETED`, `RESOLVED`, `CLOSED`, `CANCELLED`, `ARCHIVED`, `MERGED`, `SUPERSEDED`, `OBSOLETE`, `DEPRECATED`, `EXPIRED`, `SHIPPED`, `FINISHED`), a checked task box `[x]`, a ✅, or a ~~strikethrough~~ — and it works on both list bullets and `###` entry headers. The archive lives under `memory/` so it is still indexed and **searchable via `memory_search`** — the agent recalls completed work on demand instead of carrying its full changelog in-prompt. It is conservative (uppercase words only, so prose like "Closes #123", "we're not done", or an unchecked `[ ]` box is never archived), idempotent, and never drops an open/active item.
|
|
431
|
+
- **Budget-scaled pruning** — when `MEMORY.md` is over its soft budget, the reviewer is put in an explicit net-shrink mode (propose only length-reducing ops) and `maxChangesPerRun` scales up **for removals** (the add cap stays tight), so an over-budget file converges toward budget instead of trickling at a few edits per night.
|
|
432
|
+
- **Archive staleness GC (`gateway.dreaming.staleness`, planning-66)** — a deterministic pass that runs next to the compactor (auto mode) to keep the Lane-2 archive's **search quality** high. This is a **search-quality fix, not a prompt-budget one**: planning-65 already moved task-log off the injected prompt, so the point here is that `memory_search` should keep surfacing *current* truth instead of stale/superseded facts. Each nightly run **soft-invalidates** archive entries — superseded ones (a deterministic `supersedes/replaces/obsoletes #N` match, which finally populates the previously-inert `supersedes_key`) and aged-out ones (idle-since-last-**retrieval** past `staleTtlDays` and retrieved fewer than `minRetrievalKeep` times) — by **moving** them to `memory/archive/stale.md` and stamping `invalid_at`. It **never deletes**: a staled entry stays under `memory/` so it is still indexed and **searchable** (ยุบได้แต่ไม่ลืม). An entry that is **retrieved after** it was invalidated is **promoted back** to the active archive (the recall feedback loop — proof we aged it out too soon). Recall is fed by an append-only read-path log (`kb_retrieval_log`, gated by `recordRetrievals`) that the GC folds into each entry's `last_retrieved`. High-importance entries (`keepImportance`) and **pinned** files (`memory/pinned/**`) are never aged out; evergreen Lane-1 (`MEMORY.md`/`USER.md`) is structurally excluded. Every move is CAS-guarded with a timestamped backup, and — being a memory-only write — drops **no live session**. Kill-switches: `staleness.enabled:false` (GC no-ops) and `recordRetrievals:false` (age falls back to first-seen only).
|
|
433
|
+
|
|
434
|
+
### `gateway.knowledge`
|
|
435
|
+
|
|
436
|
+
**Two-lane memory** — a per-agent searchable knowledge archive so an agent can recall what does not fit in the always-injected core. A SQLite/FTS5 index (`agents/<id>/kb.sqlite`, built on Node's built-in `node:sqlite` — no new dependency) covers the agent's `memory/*.md` notes plus the evergreen `MEMORY.md`/`USER.md`. Every chunk is tagged with **fail-closed provenance** (`owner`/`agent`/`untrusted`/`system`; unclassified ⇒ `untrusted`). The index is refreshed by a detached subprocess at session spawn, entirely **off the gateway event loop**.
|
|
437
|
+
|
|
438
|
+
Two read-only MCP tools expose it to the agent: **`memory_search`** (keyword/FTS5 → ranked snippets with file+line, provenance, importance) and **`memory_get`** (bounded, path-traversal-guarded excerpt of a memory-scoped file). When `MEMORY.md` grows past its `gateway.memory` soft budget, compose injects a compact **auto-generated section index** + a pointer to `memory_search` instead of the truncated full text (**core-shrink**) — the on-disk file is never modified and its full content stays searchable. Whenever the archive is on, a short `--- MEMORY RETRIEVAL ---` note is also injected into every agent's system prompt so the tools stay discoverable at all times (not only when the file is over budget).
|
|
439
|
+
|
|
440
|
+
| Field | Default | Description |
|
|
441
|
+
|-------|---------|-------------|
|
|
442
|
+
| `archive.enabled` | `true` | Master switch (`false` ⇒ complete no-op, no DB created, no core-shrink) |
|
|
443
|
+
| `archive.tokenizer` | `"unicode61"` | FTS5 tokenizer (`"trigram"` for CJK/Thai) |
|
|
444
|
+
| `archive.chunkTokens` | `400` | Target chunk size in ~tokens |
|
|
445
|
+
| `archive.chunkOverlap` | `80` | Overlap between chunks (clamped below `chunkTokens`) |
|
|
446
|
+
| `shared.enabled` | `true` | Enable the cross-agent shared KB |
|
|
447
|
+
| `shared.project` | `"global"` | Sharing partition key (one safe path segment) — agents with the same value share one vault; `"global"` ⇒ shared-by-default |
|
|
448
|
+
| `shared.root` | `~/.claude-gateway/shared/kb` | Shared vault root dir (`<root>/<project>/`) |
|
|
449
|
+
| `shared.mode` | `"auto"` | Per-agent→shared promotion mode; `auto` = promote durable dreamed facts, `propose` = dry-run |
|
|
450
|
+
| `shared.graph` | `false` | Compile the memory-wiki graph + dashboards over the shared vault to `<vault>/reports/*.md` (opt-in). Independent of the dashboard **Knowledge base** tab, which computes its graph on-demand |
|
|
451
|
+
|
|
452
|
+
**Shared KB.** A shared SQLite/FTS5 vault outside any single agent's workspace lets agents build a common knowledge base. Notes under `<root>/<project>/notes/*.md` are indexed and reachable via `memory_search` with `corpus:"shared"` (the shared vault) or `corpus:"all"` (this agent's memory + shared, merged by relevance). Concurrent writers are safe without a lock — atomic note writes (temp+rename) plus a cross-process `PRAGMA busy_timeout` on the index. Per-agent overrides under the agent's own `knowledge` block. The MCP layer runs under Bun, so the read tools query `kb.sqlite` via `bun:sqlite`.
|
|
453
|
+
|
|
454
|
+
**Knowledge base viewer.** The web dashboard's **Knowledge base** tab renders the shared vault as an Obsidian-style force-directed graph (nodes = notes sized by link degree and coloured by `type`; edges = `[[wiki-links]]`; contradicting claims and stale notes are flagged). It is fed by `GET /knowledge/graph`, which computes the model **on-demand** from the vault (no dependency on `shared.graph` or the nightly reindex). When the vault is empty it shows a clearly-labelled demo dataset (with a size selector for scale testing). A **source** selector switches the graph between the cross-agent Shared KB and any single agent's own Lane-2 memory (`workspace/memory`), a node **search** box filters the graph, and clicking a node opens its full note (fetched via `GET /knowledge/note`) rendered as Markdown below the graph.
|
|
455
|
+
|
|
456
|
+
**Nightly dreaming viewer.** A **Nightly dreaming** tab renders each agent's memory-consolidation audit trail (`.dreaming/DREAMS.md` + `promotions.jsonl`) as a newest-first timeline of runs — mode (propose/auto), outcome, the proposed/applied changes with scores + anchors, and per-run token/session counts — fed by `GET /knowledge/dreams` and filterable by agent. For a `propose`-mode run you can **accept** proposals directly from the tab: an **Accept** button per proposal (and **Accept all** per run) POSTs to `POST /knowledge/dreams/apply`, which applies the selected ops to `MEMORY.md`/`USER.md` through the same K4 safe applier auto mode uses (backup + bounded-loss + net-negative + CAS; memory-only ⇒ no restart) and — when the shared KB is `auto` — promotes applied `add`s to the shared vault. Accepts are idempotent (recorded to `.dreaming/accepted.jsonl`); applied proposals show ✓ and a proposal whose anchor has since drifted is safely skipped and stays pending for a later retry.
|
|
457
|
+
|
|
341
458
|
### `gateway.bind`
|
|
342
459
|
|
|
343
460
|
Network interface the HTTP/WebSocket server binds to. Defaults to `127.0.0.1` (localhost-only), so the dashboard and API are **not** exposed to the local network out of the box. Set to `0.0.0.0` to listen on all interfaces (for example when a containerized reverse proxy needs to reach the gateway). The `GATEWAY_BIND` environment variable, when set, takes precedence over this field.
|
|
@@ -829,6 +946,18 @@ Skills placed in `~/.claude-gateway/shared-skills/` are automatically synced to
|
|
|
829
946
|
|
|
830
947
|
This means adding a skill to `shared-skills/` makes it available to **all agents** without per-agent setup or a gateway restart.
|
|
831
948
|
|
|
949
|
+
### Skill self-improvement
|
|
950
|
+
|
|
951
|
+
Agents can **learn skills from their own work**. Telemetry is captured for every turn; when a turn does enough substantive work (default ≥ 5 tool calls) and the session goes idle, a lightweight background reviewer reads the transcript and decides whether a reusable skill should be **created or updated**. Written skills are **hot-reloaded** — usable in the next turn without a restart. Controlled by [`gateway.skillLearning`](#gatewayskilllearning) (enabled by default).
|
|
952
|
+
|
|
953
|
+
- **Provenance guard** — the writer only ever creates new `origin: auto` skills or edits skills it previously authored. Hand-written / user skills are never overwritten.
|
|
954
|
+
- **Caps** — a per-day review cap and a maximum number of auto-skills bound the churn; a daily curator prunes the least-used auto-skills.
|
|
955
|
+
- **Audit diary** — every automatic write appends a line to `<workspace>/SKILLS_LEARNED.md` (always on, offline, immutable).
|
|
956
|
+
- **Notifications** — when `skillLearning.notify` is on (default), a short ping is fanned out to **every channel the agent has configured** (Telegram, Discord, and LINE when set up). Each channel resolves recipients from its own `.<channel>-state/access.json` allowlist. The web/`api` channel has no proactive push and is not notified. Bursts coalesce into a single digest.
|
|
957
|
+
- **Progressive disclosure** — auto-skill descriptions are truncated in the CLAUDE.md skill menu to keep per-turn context small; the full skill body still loads on invoke.
|
|
958
|
+
|
|
959
|
+
Metrics are exposed via `GET /api/v1/agents/:agentId/skill-metrics` and the `skill_metrics` MCP tool (adoption funnel, cost-to-complete deltas, net-token ledger).
|
|
960
|
+
|
|
832
961
|
---
|
|
833
962
|
|
|
834
963
|
## Config Auto-Migration
|
package/config.template.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"claude.dangerouslySkipPermissions"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
|
-
"configVersion": "1.0.
|
|
13
|
+
"configVersion": "1.0.29",
|
|
14
14
|
"gateway": {
|
|
15
15
|
"logDir": "~/.claude-gateway/logs",
|
|
16
16
|
"timezone": "Asia/Bangkok",
|
|
@@ -63,6 +63,64 @@
|
|
|
63
63
|
"buildCachePrune": true,
|
|
64
64
|
"buildCacheMaxAgeHours": 168,
|
|
65
65
|
"danglingImagePrune": true
|
|
66
|
+
},
|
|
67
|
+
"skillLearning": {
|
|
68
|
+
"enabled": true,
|
|
69
|
+
"mode": "auto",
|
|
70
|
+
"minToolCalls": 5,
|
|
71
|
+
"reviewModel": "claude-haiku-4-5-20251001",
|
|
72
|
+
"maxAutoSkills": 50,
|
|
73
|
+
"maxAgeDays": 30,
|
|
74
|
+
"minUsesToKeep": 2,
|
|
75
|
+
"maxReviewsPerDay": 20,
|
|
76
|
+
"pruneHour": 3,
|
|
77
|
+
"pruneTimezone": "UTC",
|
|
78
|
+
"notify": true
|
|
79
|
+
},
|
|
80
|
+
"memory": {
|
|
81
|
+
"memoryBudgetChars": 8000,
|
|
82
|
+
"userBudgetChars": 3000,
|
|
83
|
+
"overBudget": "warn",
|
|
84
|
+
"writeRouting": true,
|
|
85
|
+
"episodicArchiveDir": "memory"
|
|
86
|
+
},
|
|
87
|
+
"dreaming": {
|
|
88
|
+
"enabled": true,
|
|
89
|
+
"mode": "auto",
|
|
90
|
+
"dreamHour": 3,
|
|
91
|
+
"dreamMinute": 0,
|
|
92
|
+
"dreamTimezone": "UTC",
|
|
93
|
+
"quietMinutes": 30,
|
|
94
|
+
"lookbackDays": 3,
|
|
95
|
+
"maxChangesPerRun": 3,
|
|
96
|
+
"reviewModel": "claude-haiku-4-5-20251001",
|
|
97
|
+
"promotionThreshold": 0.6,
|
|
98
|
+
"minRecallCount": 2,
|
|
99
|
+
"autoRouteOut": true,
|
|
100
|
+
"staggerWindowMinutes": 30,
|
|
101
|
+
"staleness": {
|
|
102
|
+
"enabled": true,
|
|
103
|
+
"staleTtlDays": 90,
|
|
104
|
+
"keepImportance": 7,
|
|
105
|
+
"minRetrievalKeep": 1,
|
|
106
|
+
"supersession": true,
|
|
107
|
+
"recordRetrievals": true
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"knowledge": {
|
|
111
|
+
"archive": {
|
|
112
|
+
"enabled": true,
|
|
113
|
+
"tokenizer": "unicode61",
|
|
114
|
+
"chunkTokens": 400,
|
|
115
|
+
"chunkOverlap": 80
|
|
116
|
+
},
|
|
117
|
+
"shared": {
|
|
118
|
+
"enabled": true,
|
|
119
|
+
"project": "global",
|
|
120
|
+
"root": "~/.claude-gateway/shared/kb",
|
|
121
|
+
"mode": "auto",
|
|
122
|
+
"graph": false
|
|
123
|
+
}
|
|
66
124
|
}
|
|
67
125
|
},
|
|
68
126
|
"agents": [
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ApplyFileResult } from './applier';
|
|
2
|
+
import type { DreamProposal } from './types';
|
|
3
|
+
export interface AcceptOptions {
|
|
4
|
+
memoryBudgetChars: number;
|
|
5
|
+
userBudgetChars: number;
|
|
6
|
+
/** planning-65: episodic archive dir (relative to workspace) so accepted episodic ops append to memory/<topic>.md. */
|
|
7
|
+
episodicArchiveDir?: string;
|
|
8
|
+
/** Promote each applied `add` to the shared vault (only when shared KB is auto). */
|
|
9
|
+
sharedPromote?: (p: DreamProposal) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface AcceptResult {
|
|
12
|
+
/** Proposals matched from the run after the index filter (before dedup). */
|
|
13
|
+
requested: number;
|
|
14
|
+
/** Ops the applier actually wrote to memory. */
|
|
15
|
+
applied: number;
|
|
16
|
+
/** Matched but not written this call (stale anchor, net-negative, over-budget add). */
|
|
17
|
+
skipped: number;
|
|
18
|
+
/** Excluded because a prior accept already applied them. */
|
|
19
|
+
alreadyAccepted: number;
|
|
20
|
+
/** Per-file applier outcome (for surfacing backup paths / byte deltas). */
|
|
21
|
+
files: ApplyFileResult[];
|
|
22
|
+
/** Rollback pre-image paths written this call. */
|
|
23
|
+
backups: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Ordered proposals for a single run (matched by `ts`), each with its index —
|
|
27
|
+
* the position among that run's proposals, matching the report/UI ordering.
|
|
28
|
+
* Malformed or unusable lines are skipped but still consume an index slot so
|
|
29
|
+
* indexes stay aligned with what the report renders.
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadRunProposals(workspaceDir: string, ts: number): Array<{
|
|
32
|
+
index: number;
|
|
33
|
+
proposal: DreamProposal;
|
|
34
|
+
}>;
|
|
35
|
+
/** Set of `"<ts>:<index>"` keys already accepted for this agent. */
|
|
36
|
+
export declare function readAcceptedKeys(workspaceDir: string): Set<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Accept (apply) the selected proposals of one dreaming run.
|
|
39
|
+
*
|
|
40
|
+
* @param indexes proposal indexes to accept within the run, or `null` for all.
|
|
41
|
+
*/
|
|
42
|
+
export declare function acceptDreamProposals(workspaceDir: string, ts: number, indexes: number[] | null, opts: AcceptOptions, now?: number): AcceptResult;
|
|
43
|
+
//# sourceMappingURL=accept.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accept.d.ts","sourceRoot":"","sources":["../../../src/agent/dreaming/accept.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,SAAS,CAAC;AAKrE,MAAM,WAAW,aAAa;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,sHAAsH;IACtH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,eAAe,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,kDAAkD;IAClD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA0BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,MAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAAC,CA2BnD;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAsBlE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EACxB,IAAI,EAAE,aAAa,EACnB,GAAG,GAAE,MAAmB,GACvB,YAAY,CAoFd"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadRunProposals = loadRunProposals;
|
|
37
|
+
exports.readAcceptedKeys = readAcceptedKeys;
|
|
38
|
+
exports.acceptDreamProposals = acceptDreamProposals;
|
|
39
|
+
/**
|
|
40
|
+
* Manual accept of dreaming proposals (dashboard action).
|
|
41
|
+
*
|
|
42
|
+
* In `propose` mode the nightly reviewer only records its proposals to
|
|
43
|
+
* `<workspace>/.dreaming/promotions.jsonl` — nothing is written to memory. This
|
|
44
|
+
* module lets a human accept one or more of those recorded proposals from the
|
|
45
|
+
* dashboard and apply them through the SAME K4 safe applier the auto mode uses
|
|
46
|
+
* (backup pre-image + ordered anchor re-resolution + bounded-loss + net-negative
|
|
47
|
+
* + CAS + never-empty). Writing MEMORY.md/USER.md is memory-only ⇒ no session
|
|
48
|
+
* restart.
|
|
49
|
+
*
|
|
50
|
+
* Idempotency: each applied proposal is recorded to `<workspace>/.dreaming/
|
|
51
|
+
* accepted.jsonl` keyed by `"<ts>:<index>"`. A proposal already accepted is
|
|
52
|
+
* skipped on a repeat request. A proposal the applier *skipped* (stale anchor,
|
|
53
|
+
* net-negative, etc.) is NOT recorded, so it can be retried later.
|
|
54
|
+
*
|
|
55
|
+
* Pure of any clock — `now` is injected so it stays unit-testable.
|
|
56
|
+
*/
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const path = __importStar(require("path"));
|
|
59
|
+
const audit_1 = require("./audit");
|
|
60
|
+
const applier_1 = require("./applier");
|
|
61
|
+
const episodic_1 = require("./episodic");
|
|
62
|
+
const OP_KINDS = new Set(['add', 'replace', 'remove']);
|
|
63
|
+
const DREAM_FILES = new Set(['MEMORY.md', 'USER.md']);
|
|
64
|
+
/** One promotions.jsonl object → a valid DreamProposal, or null if unusable. */
|
|
65
|
+
function coerceProposal(o) {
|
|
66
|
+
const op = String(o.op ?? '');
|
|
67
|
+
if (!OP_KINDS.has(op))
|
|
68
|
+
return null;
|
|
69
|
+
const content = typeof o.content === 'string' ? o.content : undefined;
|
|
70
|
+
const target = typeof o.target === 'string' ? o.target : undefined;
|
|
71
|
+
const reason = String(o.reason ?? '');
|
|
72
|
+
const score = Number(o.score) || 0;
|
|
73
|
+
const recallCount = Number(o.recallCount) || 0;
|
|
74
|
+
// planning-65: episodic ops (add-only, memory/<topic>.md) recorded in propose mode.
|
|
75
|
+
if (o.tier === 'episodic') {
|
|
76
|
+
if (op !== 'add' || !(0, episodic_1.isValidTopicSlug)(o.topic) || !content)
|
|
77
|
+
return null;
|
|
78
|
+
return { op, tier: 'episodic', topic: o.topic, content, reason, score, recallCount };
|
|
79
|
+
}
|
|
80
|
+
// Durable op (unchanged): needs a valid evergreen file + the right fields.
|
|
81
|
+
const file = String(o.file ?? '');
|
|
82
|
+
if (!DREAM_FILES.has(file))
|
|
83
|
+
return null;
|
|
84
|
+
if (op === 'add' && !content)
|
|
85
|
+
return null;
|
|
86
|
+
if ((op === 'replace' || op === 'remove') && !target)
|
|
87
|
+
return null;
|
|
88
|
+
return { op, file, tier: 'durable', target, content, reason, score, recallCount };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Ordered proposals for a single run (matched by `ts`), each with its index —
|
|
92
|
+
* the position among that run's proposals, matching the report/UI ordering.
|
|
93
|
+
* Malformed or unusable lines are skipped but still consume an index slot so
|
|
94
|
+
* indexes stay aligned with what the report renders.
|
|
95
|
+
*/
|
|
96
|
+
function loadRunProposals(workspaceDir, ts) {
|
|
97
|
+
const file = path.join(workspaceDir, audit_1.DREAMING_DIR, 'promotions.jsonl');
|
|
98
|
+
let raw;
|
|
99
|
+
try {
|
|
100
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
const out = [];
|
|
106
|
+
let index = 0;
|
|
107
|
+
for (const line of raw.split('\n')) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (!trimmed)
|
|
110
|
+
continue;
|
|
111
|
+
let o;
|
|
112
|
+
try {
|
|
113
|
+
o = JSON.parse(trimmed);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (Number(o.ts) !== ts)
|
|
119
|
+
continue;
|
|
120
|
+
const proposal = coerceProposal(o);
|
|
121
|
+
// Consume an index slot even for an unusable line so indexes match the
|
|
122
|
+
// report's per-run ordering (which also lists every proposal line).
|
|
123
|
+
const slot = index++;
|
|
124
|
+
if (proposal)
|
|
125
|
+
out.push({ index: slot, proposal });
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
/** Set of `"<ts>:<index>"` keys already accepted for this agent. */
|
|
130
|
+
function readAcceptedKeys(workspaceDir) {
|
|
131
|
+
const file = path.join(workspaceDir, audit_1.DREAMING_DIR, 'accepted.jsonl');
|
|
132
|
+
const keys = new Set();
|
|
133
|
+
let raw;
|
|
134
|
+
try {
|
|
135
|
+
raw = fs.readFileSync(file, 'utf8');
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return keys;
|
|
139
|
+
}
|
|
140
|
+
for (const line of raw.split('\n')) {
|
|
141
|
+
const trimmed = line.trim();
|
|
142
|
+
if (!trimmed)
|
|
143
|
+
continue;
|
|
144
|
+
try {
|
|
145
|
+
const o = JSON.parse(trimmed);
|
|
146
|
+
const ts = Number(o.ts);
|
|
147
|
+
const idx = Number(o.index);
|
|
148
|
+
if (Number.isFinite(ts) && Number.isFinite(idx))
|
|
149
|
+
keys.add(`${ts}:${idx}`);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
/* skip malformed line */
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return keys;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Accept (apply) the selected proposals of one dreaming run.
|
|
159
|
+
*
|
|
160
|
+
* @param indexes proposal indexes to accept within the run, or `null` for all.
|
|
161
|
+
*/
|
|
162
|
+
function acceptDreamProposals(workspaceDir, ts, indexes, opts, now = Date.now()) {
|
|
163
|
+
const all = loadRunProposals(workspaceDir, ts);
|
|
164
|
+
const wanted = indexes === null ? all : all.filter((x) => indexes.includes(x.index));
|
|
165
|
+
const acceptedKeys = readAcceptedKeys(workspaceDir);
|
|
166
|
+
const already = wanted.filter((x) => acceptedKeys.has(`${ts}:${x.index}`));
|
|
167
|
+
const fresh = wanted.filter((x) => !acceptedKeys.has(`${ts}:${x.index}`));
|
|
168
|
+
if (fresh.length === 0) {
|
|
169
|
+
return {
|
|
170
|
+
requested: wanted.length,
|
|
171
|
+
applied: 0,
|
|
172
|
+
skipped: 0,
|
|
173
|
+
alreadyAccepted: already.length,
|
|
174
|
+
files: [],
|
|
175
|
+
backups: [],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const res = (0, applier_1.applyDreamProposals)(workspaceDir, fresh.map((x) => x.proposal), {
|
|
179
|
+
memoryBudgetChars: opts.memoryBudgetChars,
|
|
180
|
+
userBudgetChars: opts.userBudgetChars,
|
|
181
|
+
episodicArchiveDir: opts.episodicArchiveDir,
|
|
182
|
+
}, now);
|
|
183
|
+
// Identity match: applyDreamProposals returns the SAME proposal objects it
|
|
184
|
+
// actually wrote, so a reference Set maps applied ops back to their indexes.
|
|
185
|
+
const appliedSet = new Set(res.appliedProposals);
|
|
186
|
+
const acceptedRecords = [];
|
|
187
|
+
for (const x of fresh) {
|
|
188
|
+
if (!appliedSet.has(x.proposal))
|
|
189
|
+
continue;
|
|
190
|
+
acceptedRecords.push(JSON.stringify({
|
|
191
|
+
ts,
|
|
192
|
+
index: x.index,
|
|
193
|
+
file: x.proposal.tier === 'episodic' ? `memory/${x.proposal.topic}.md` : x.proposal.file,
|
|
194
|
+
op: x.proposal.op,
|
|
195
|
+
acceptedAt: now,
|
|
196
|
+
}));
|
|
197
|
+
// Shared promotion mirrors the nightly auto path: only applied DURABLE `add`s.
|
|
198
|
+
// Episodic task-log is per-agent local history — never auto-promoted to shared.
|
|
199
|
+
if (opts.sharedPromote &&
|
|
200
|
+
x.proposal.op === 'add' &&
|
|
201
|
+
x.proposal.content &&
|
|
202
|
+
x.proposal.tier !== 'episodic') {
|
|
203
|
+
try {
|
|
204
|
+
opts.sharedPromote(x.proposal);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
/* best-effort — a promotion failure never fails the local accept */
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (acceptedRecords.length) {
|
|
212
|
+
try {
|
|
213
|
+
const dir = path.join(workspaceDir, audit_1.DREAMING_DIR);
|
|
214
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
215
|
+
fs.appendFileSync(path.join(dir, 'accepted.jsonl'), acceptedRecords.join('\n') + '\n', 'utf8');
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
/* best-effort audit — the memory write already committed */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
requested: wanted.length,
|
|
223
|
+
applied: res.totalApplied,
|
|
224
|
+
skipped: fresh.length - res.totalApplied,
|
|
225
|
+
alreadyAccepted: already.length,
|
|
226
|
+
files: res.files,
|
|
227
|
+
backups: res.files.map((f) => f.backupPath).filter((b) => !!b),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=accept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accept.js","sourceRoot":"","sources":["../../../src/agent/dreaming/accept.ts"],"names":[],"mappings":"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"}
|