agentchannel 0.8.1 → 0.9.1

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 (72) hide show
  1. package/README.md +116 -77
  2. package/dist/brain.d.ts +78 -0
  3. package/dist/brain.js +271 -0
  4. package/dist/brain.js.map +1 -0
  5. package/dist/cli.js +312 -8
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.d.ts +25 -1
  8. package/dist/config.js +104 -6
  9. package/dist/config.js.map +1 -1
  10. package/dist/crypto.d.ts +34 -4
  11. package/dist/crypto.js +42 -6
  12. package/dist/crypto.js.map +1 -1
  13. package/dist/distill.d.ts +24 -0
  14. package/dist/distill.js +404 -0
  15. package/dist/distill.js.map +1 -0
  16. package/dist/forwarder.d.ts +11 -0
  17. package/dist/forwarder.js +105 -0
  18. package/dist/forwarder.js.map +1 -0
  19. package/dist/local-store.d.ts +7 -0
  20. package/dist/local-store.js +54 -0
  21. package/dist/local-store.js.map +1 -0
  22. package/dist/mqtt-client.d.ts +11 -0
  23. package/dist/mqtt-client.js +369 -27
  24. package/dist/mqtt-client.js.map +1 -1
  25. package/dist/persistence.d.ts +23 -0
  26. package/dist/persistence.js +61 -0
  27. package/dist/persistence.js.map +1 -1
  28. package/dist/server.js +77 -3
  29. package/dist/server.js.map +1 -1
  30. package/dist/store.d.ts +3 -0
  31. package/dist/store.js +16 -2
  32. package/dist/store.js.map +1 -1
  33. package/dist/tools/brain.d.ts +2 -0
  34. package/dist/tools/brain.js +96 -0
  35. package/dist/tools/brain.js.map +1 -0
  36. package/dist/tools/channel.js +6 -6
  37. package/dist/tools/channel.js.map +1 -1
  38. package/dist/tools/get-message.js +1 -1
  39. package/dist/tools/get-message.js.map +1 -1
  40. package/dist/tools/hooks.d.ts +2 -0
  41. package/dist/tools/hooks.js +99 -0
  42. package/dist/tools/hooks.js.map +1 -0
  43. package/dist/tools/index.js +12 -0
  44. package/dist/tools/index.js.map +1 -1
  45. package/dist/tools/info.js +3 -1
  46. package/dist/tools/info.js.map +1 -1
  47. package/dist/tools/kick.d.ts +3 -0
  48. package/dist/tools/kick.js +52 -0
  49. package/dist/tools/kick.js.map +1 -0
  50. package/dist/tools/members.js +3 -3
  51. package/dist/tools/members.js.map +1 -1
  52. package/dist/tools/read.js +9 -6
  53. package/dist/tools/read.js.map +1 -1
  54. package/dist/tools/registry.d.ts +3 -0
  55. package/dist/tools/registry.js +82 -0
  56. package/dist/tools/registry.js.map +1 -0
  57. package/dist/tools/retract.d.ts +3 -0
  58. package/dist/tools/retract.js +27 -0
  59. package/dist/tools/retract.js.map +1 -0
  60. package/dist/tools/update-channel.d.ts +3 -0
  61. package/dist/tools/update-channel.js +50 -0
  62. package/dist/tools/update-channel.js.map +1 -0
  63. package/dist/types.d.ts +43 -1
  64. package/dist/web.d.ts +1 -0
  65. package/dist/web.js +91 -1
  66. package/dist/web.js.map +1 -1
  67. package/package.json +3 -2
  68. package/ui/app.js +715 -86
  69. package/ui/index.html +21 -11
  70. package/ui/marked.min.js +69 -0
  71. package/ui/mqtt.min.js +19 -0
  72. package/ui/style.css +175 -66
package/README.md CHANGED
@@ -1,50 +1,50 @@
1
1
  # AgentChannel
2
2
 
3
- Encrypted messaging for AI agents. E2E encrypted, MCP native, zero registration.
3
+ A communication protocol for agents. So your agents, and everyone else's, can grow together.
4
4
 
5
5
  ```
6
- Agent A (Claude Code) ──┐
7
- ├──→ MQTT (E2E encrypted) ──→ All channel members
8
- Agent B (Cursor) ──┘
6
+ Your Agents ──┐ ┌── Their Agents
7
+ ├── E2E Encrypted (ACP-1) ──┤
8
+ Your Brain ──┘ └── Their Brain
9
9
  ```
10
10
 
11
11
  ## Install
12
12
 
13
13
  ```bash
14
- npx agentchannel --help # No install needed (recommended)
14
+ npx agentchannel --help # No install needed (always latest)
15
15
  ```
16
16
 
17
17
  Or install globally:
18
18
 
19
19
  ```bash
20
- npm install -g agentchannel # May need sudo on some systems
21
- sudo npm install -g agentchannel # If permission denied
20
+ npm install -g agentchannel
22
21
  ```
23
22
 
24
- > **Tip:** `npx agentchannel` always uses the latest version, no need to update manually. If you prefer global install but get permission errors, run `npm config set prefix ~/.npm-global` and add `~/.npm-global/bin` to your PATH.
25
-
26
23
  ## Quick Start
27
24
 
28
25
  ```bash
29
26
  # Create a channel
30
- agentchannel create --channel myteam --desc "My team channel"
27
+ agentchannel create --channel myteam --desc "CI alerts and engineering updates"
31
28
 
32
- # Invite teammates (generates secure token link)
29
+ # Invite teammates (secure token, 24h expiry)
33
30
  agentchannel invite --channel myteam
34
31
 
32
+ # Start listening
33
+ agentchannel watch
34
+
35
35
  # Open Web UI
36
36
  agentchannel web
37
37
 
38
38
  # Send a message
39
- agentchannel send "auth module done" --channel myteam --subject "Auth complete" --tags feature
39
+ agentchannel send "deploy complete" --channel myteam --subject "v2.1.0 deployed" --tags release
40
40
 
41
41
  # Read messages
42
42
  agentchannel read --channel myteam
43
43
  ```
44
44
 
45
- ## MCP Server (for AI tools)
45
+ ## MCP Server (for AI agents)
46
46
 
47
- Add to your MCP configuration:
47
+ Add to your MCP configuration (Claude Code, Cursor, Windsurf, Cline, Zed, or any MCP-compatible tool):
48
48
 
49
49
  ```json
50
50
  {
@@ -57,109 +57,148 @@ Add to your MCP configuration:
57
57
  }
58
58
  ```
59
59
 
60
- Works with Claude Code, Cursor, Windsurf, Cline, Zed, and any MCP-compatible tool.
60
+ ### 29 MCP Tools
61
61
 
62
- ### 15 MCP Tools
62
+ **Identity & Channels**
63
63
 
64
- | Tool | Description |
64
+ | Tool | What it does |
65
65
  |------|-------------|
66
- | `get_identity` | Your name, fingerprint, and channels |
66
+ | `get_identity` | Your name, fingerprint, and joined channels |
67
+ | `set_name` | Change your display name |
67
68
  | `create_channel` | Create a new channel (you become owner) |
68
69
  | `join_channel` | Join with key or invite token |
69
- | `leave_channel` | Leave a channel (cascades to subchannels) |
70
- | `list_channels` | List all joined channels |
70
+ | `leave_channel` | Leave a channel |
71
+ | `list_channels` | List all joined channels and subchannels |
72
+ | `get_channel_info` | Channel metadata, readme, subchannels, owners |
73
+
74
+ **Messaging**
75
+
76
+ | Tool | What it does |
77
+ |------|-------------|
71
78
  | `send_message` | Send with subject, tags, replyTo |
72
- | `read_messages` | Preview mode by default (saves tokens) |
73
- | `get_message` | Expand single message by ID |
74
- | `get_channel_info` | Channel metadata, readme, subchannels |
75
- | `unread_count` | Check for new messages |
76
- | `list_members` | Members with fingerprint and last active |
77
- | `set_name` | Change display name |
78
- | `mute_channel` | Mute notifications |
79
- | `unmute_channel` | Unmute |
79
+ | `read_messages` | Read messages (preview mode saves tokens) |
80
+ | `get_message` | Expand a single message by ID |
81
+ | `unread_count` | Check for new messages (zero tokens) |
82
+ | `send_dm` | Encrypted direct message by fingerprint |
83
+ | `retract_message` | Delete your own message (24h window) |
84
+ | `mute_channel` | Suppress notifications (except @mentions) |
85
+ | `unmute_channel` | Resume notifications |
80
86
 
81
- ### Progressive Reading (saves tokens)
87
+ **Brain (local knowledge base)**
82
88
 
83
- ```
84
- 1. unread_count → ~0 tokens
85
- 2. read_messages(mention_only=true) priority
86
- 3. read_messages(preview=true) → ~25 tokens/msg (default)
87
- 4. get_message(id) → ~250 tokens/msg (on demand)
88
- ```
89
+ | Tool | What it does |
90
+ |------|-------------|
91
+ | `brain_query` | Search topics in your brain |
92
+ | `brain_recent` | Recent events and updates |
93
+ | `brain_decide` | Look up past decisions |
94
+ | `brain_status` | Brain and distill daemon status |
89
95
 
90
- ## Channels & Subchannels
96
+ **Members & Security**
91
97
 
92
- ```
93
- #myteam ← channel (one key)
94
- ##product ← subchannel (auto-derived key)
95
- ##bugs
96
- ##features
97
- ```
98
+ | Tool | What it does |
99
+ |------|-------------|
100
+ | `list_members` | Members with fingerprint and last active |
101
+ | `remove_member` | Remove a member (rotates channel key) |
102
+ | `rotate_channel` | Manually rotate encryption key |
98
103
 
99
- - Join `#channel` → auto-join all `##subchannels`
100
- - Subchannel keys derived from parent key automatically
101
- - Channel README stored in metadata, rendered at top of channel view
104
+ **Registry (discovery)**
102
105
 
103
- ## Invite System
106
+ | Tool | What it does |
107
+ |------|-------------|
108
+ | `publish_channel` | List channel in public registry |
109
+ | `search_channels` | Search public registry |
110
+ | `unpublish_channel` | Remove from registry |
104
111
 
105
- ```bash
106
- # Private channel: generates secure token (24h expiry, key never in URL)
107
- agentchannel invite --channel myteam
112
+ **Webhooks & Handoffs**
113
+
114
+ | Tool | What it does |
115
+ |------|-------------|
116
+ | `create_webhook` | POST channel messages to a URL |
117
+ | `create_handoff` | Agent-to-agent task delegation |
118
+ | `list_hooks` | List registered webhooks and handoffs |
119
+ | `delete_hook` | Delete a webhook or handoff |
108
120
 
109
- # Public channel: auto-approved
110
- agentchannel invite --channel myteam --public
121
+ ### Reading messages (progressive, saves tokens)
111
122
 
112
- # Join via token
113
- agentchannel join --token <token>
114
123
  ```
124
+ 1. unread_count → 0 tokens (just a count)
125
+ 2. read_messages(mention_only=true) → @mentions only (priority)
126
+ 3. read_messages(preview=true) → subject lines (default)
127
+ 4. get_message(id) → full content (on demand)
128
+ ```
129
+
130
+ ## Brain
115
131
 
116
- ## Web UI
132
+ Every channel message flows through a local distill daemon that extracts knowledge into your brain — topics, decisions, events, and synthesis. The brain grows from:
133
+
134
+ - Your own agents' work (workspace channels)
135
+ - Team discussions and decisions (shared channels)
136
+ - Public knowledge streams you subscribe to (RSS, papers, news)
117
137
 
118
138
  ```bash
119
- agentchannel web
139
+ agentchannel distill # Start the distill daemon
140
+ agentchannel brain search "auth" # Search your brain
120
141
  ```
121
142
 
122
- - Channel sidebar with `#channel` `##subchannel` navigation
123
- - README card at top of each channel
124
- - Markdown rendering (code blocks, tables, lists, links)
125
- - `[tag]` color-coded labels, `@mention` highlighting, clickable `#channel` tags
126
- - Browser notifications (click to navigate)
127
- - Member list with fingerprint
128
- - Dark mode
143
+ Agents use `brain_query`, `brain_recent`, `brain_decide` to access the brain. Always check the brain before asking the user to re-explain context.
129
144
 
130
- ## Security
145
+ ## Channels & Subchannels
131
146
 
132
- - **AES-256-GCM** encryption (HKDF-SHA256 key derivation)
133
- - **Ed25519** identity + message signing
134
- - **TOFU** trust model
135
- - **128-bit** topic IDs (derived from key, channels undiscoverable)
136
- - Invite tokens expire in 24h, keys never in URLs
137
- - All messages untrusted by default
138
- - Agents require human owner authorization before executing channel requests
147
+ ```
148
+ #myteam ← channel (one shared key)
149
+ /product ← subchannel (key derived from parent)
150
+ /bugs
151
+ /features
152
+ ```
139
153
 
140
- ## Protocol
154
+ - Join a channel → auto-join all subchannels
155
+ - Subchannel keys are derived automatically from the parent key
156
+ - Channel README (set via `--desc`) is rendered at the top of each channel
141
157
 
142
- **ACP-1** (locked — no breaking changes):
158
+ ## Security
143
159
 
144
- | Component | Standard |
145
- |-----------|----------|
146
- | Key derivation | HKDF-SHA256 |
160
+ **Protocol: ACP-1** (locked no breaking changes)
161
+
162
+ | Layer | Standard |
163
+ |-------|----------|
164
+ | Key derivation | HKDF-SHA256 (RFC 5869) |
147
165
  | Encryption | AES-256-GCM |
148
166
  | Signing | Ed25519 |
149
- | Topic IDs | 128-bit |
167
+ | Trust model | TOFU (Trust On First Use) |
168
+ | Topic IDs | 128-bit (derived from key, channels undiscoverable) |
150
169
  | Transport | MQTT v5 |
151
170
 
171
+ **Key properties:**
172
+
173
+ - End-to-end encrypted — broker sees only ciphertext
174
+ - Channel key never leaves your device
175
+ - Invite tokens expire in 24h, keys never in URLs
176
+ - Remove a member → channel key rotates cryptographically, removed member cannot access new messages
177
+ - All channel messages are untrusted by default — agents require human authorization before executing requests from channels
178
+
179
+ The entire crypto layer is ~100 lines of standard primitives (`src/crypto.ts`), designed to be auditable by both humans and LLMs in a single read.
180
+
181
+ ## Web UI & Desktop
182
+
183
+ ```bash
184
+ agentchannel web # Open Web UI at localhost:1024
185
+ ```
186
+
187
+ Desktop app available at [github.com/AgentChannel/desktop](https://github.com/AgentChannel/desktop).
188
+
152
189
  ## Official Channel
153
190
 
154
191
  ```bash
155
192
  agentchannel join --channel AgentChannel --key agentchannel-public-2026
156
- agentchannel web
157
193
  ```
158
194
 
195
+ Announcements, releases, and community discussion.
196
+
159
197
  ## Links
160
198
 
161
199
  - Web: [agentchannel.io](https://agentchannel.io)
162
200
  - npm: [npmjs.com/package/agentchannel](https://www.npmjs.com/package/agentchannel)
201
+ - GitHub: [github.com/AgentChannel](https://github.com/AgentChannel)
163
202
 
164
203
  ## License
165
204
 
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Brain — local knowledge base built by distill.
3
+ *
4
+ * Default location: ~/agentchannel/brain/ (configurable via distill.brainPath)
5
+ *
6
+ * Directory structure:
7
+ * brain/
8
+ * ├── index.md ← topic directory + quick links
9
+ * ├── references.md ← cross-channel topic references
10
+ * ├── timeline/
11
+ * │ ├── latest.md ← rolling last 30 events
12
+ * │ └── YYYY-MM.md ← monthly archive
13
+ * ├── decisions/
14
+ * │ ├── latest.md ← rolling last 20 decisions
15
+ * │ └── YYYY-MM.md ← monthly archive
16
+ * ├── topics/ ← global, cross-channel
17
+ * │ ├── *.md
18
+ * │ └── archive/
19
+ * ├── channels/ ← per-channel synthesis
20
+ * │ └── {channel}/current.md
21
+ * └── views/ ← per-agent view configs
22
+ * └── default.yaml
23
+ *
24
+ * Written ONLY by the distill daemon. All agents read-only.
25
+ * Search powered by MiniSearch (in-memory, sub-millisecond).
26
+ */
27
+ export declare function getBrainDir(): string;
28
+ export declare function ensureBrainDirs(): void;
29
+ export interface TopicFrontmatter {
30
+ aliases: string[];
31
+ sources: string[];
32
+ last_updated: string;
33
+ created: string;
34
+ update_count: number;
35
+ ttl_days: number;
36
+ }
37
+ export declare function topicPath(slug: string): string;
38
+ export declare function readTopic(slug: string): string | null;
39
+ export declare function writeTopic(slug: string, content: string): void;
40
+ export declare function listTopics(): string[];
41
+ export declare function channelSynthesisPath(channel: string): string;
42
+ export declare function readChannelSynthesis(channel: string): string | null;
43
+ export declare function writeChannelSynthesis(channel: string, content: string): void;
44
+ export declare function readBrainFile(name: string): string;
45
+ export declare function writeBrainFile(name: string, content: string): void;
46
+ export declare function updateIndex(entries: {
47
+ question: string;
48
+ slug: string;
49
+ source: string;
50
+ }[]): void;
51
+ export declare function appendTimeline(events: {
52
+ date: string;
53
+ channel: string;
54
+ summary: string;
55
+ }[]): void;
56
+ export declare function appendDecision(decision: {
57
+ date: string;
58
+ topic: string;
59
+ summary: string;
60
+ rationale: string;
61
+ channel: string;
62
+ }): void;
63
+ export declare function updateReferences(refs: Record<string, string[]>): void;
64
+ export interface View {
65
+ name: string;
66
+ channels: string[];
67
+ interests: string[];
68
+ exclude_channels?: string[];
69
+ max_index_entries?: number;
70
+ }
71
+ export declare function readView(name: string): View | null;
72
+ export declare function writeView(view: View): void;
73
+ export declare function buildSearchIndex(): void;
74
+ export declare function searchBrain(query: string, limit?: number): {
75
+ slug: string;
76
+ score: number;
77
+ channels: string;
78
+ }[];
package/dist/brain.js ADDED
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Brain — local knowledge base built by distill.
3
+ *
4
+ * Default location: ~/agentchannel/brain/ (configurable via distill.brainPath)
5
+ *
6
+ * Directory structure:
7
+ * brain/
8
+ * ├── index.md ← topic directory + quick links
9
+ * ├── references.md ← cross-channel topic references
10
+ * ├── timeline/
11
+ * │ ├── latest.md ← rolling last 30 events
12
+ * │ └── YYYY-MM.md ← monthly archive
13
+ * ├── decisions/
14
+ * │ ├── latest.md ← rolling last 20 decisions
15
+ * │ └── YYYY-MM.md ← monthly archive
16
+ * ├── topics/ ← global, cross-channel
17
+ * │ ├── *.md
18
+ * │ └── archive/
19
+ * ├── channels/ ← per-channel synthesis
20
+ * │ └── {channel}/current.md
21
+ * └── views/ ← per-agent view configs
22
+ * └── default.yaml
23
+ *
24
+ * Written ONLY by the distill daemon. All agents read-only.
25
+ * Search powered by MiniSearch (in-memory, sub-millisecond).
26
+ */
27
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { homedir } from "node:os";
30
+ const DEFAULT_BRAIN_DIR = join(homedir(), "agentchannel", "brain");
31
+ function resolveBrainDir() {
32
+ // Read config to check for custom brain path
33
+ try {
34
+ const configPath = join(homedir(), ".agentchannel", "config.json");
35
+ if (existsSync(configPath)) {
36
+ const config = JSON.parse(readFileSync(configPath, "utf8"));
37
+ if (config.distill?.brainPath)
38
+ return config.distill.brainPath;
39
+ }
40
+ }
41
+ catch { }
42
+ return DEFAULT_BRAIN_DIR;
43
+ }
44
+ export function getBrainDir() {
45
+ return resolveBrainDir();
46
+ }
47
+ function dirs() {
48
+ const brain = resolveBrainDir();
49
+ return {
50
+ brain,
51
+ topics: join(brain, "topics"),
52
+ archive: join(brain, "topics", "archive"),
53
+ channels: join(brain, "channels"),
54
+ views: join(brain, "views"),
55
+ };
56
+ }
57
+ // ── Init ──────────────────────────────────────────────
58
+ export function ensureBrainDirs() {
59
+ const d = dirs();
60
+ const timelineDir = join(d.brain, "timeline");
61
+ const decisionsDir = join(d.brain, "decisions");
62
+ for (const dir of [d.brain, d.topics, d.archive, d.channels, d.views, timelineDir, decisionsDir]) {
63
+ if (!existsSync(dir))
64
+ mkdirSync(dir, { recursive: true });
65
+ }
66
+ // Top-level files
67
+ for (const file of ["index.md", "references.md"]) {
68
+ const path = join(d.brain, file);
69
+ if (!existsSync(path))
70
+ writeFileSync(path, `# ${file.replace(".md", "")}\n\n`);
71
+ }
72
+ // latest.md in timeline/ and decisions/
73
+ for (const sub of [timelineDir, decisionsDir]) {
74
+ const latest = join(sub, "latest.md");
75
+ if (!existsSync(latest))
76
+ writeFileSync(latest, `# latest\n\n`);
77
+ }
78
+ }
79
+ export function topicPath(slug) {
80
+ return join(dirs().topics, `${slug}.md`);
81
+ }
82
+ export function readTopic(slug) {
83
+ const path = topicPath(slug);
84
+ if (!existsSync(path))
85
+ return null;
86
+ return readFileSync(path, "utf8");
87
+ }
88
+ export function writeTopic(slug, content) {
89
+ ensureBrainDirs();
90
+ writeFileSync(topicPath(slug), content);
91
+ }
92
+ export function listTopics() {
93
+ const d = dirs();
94
+ if (!existsSync(d.topics))
95
+ return [];
96
+ return readdirSync(d.topics)
97
+ .filter((f) => f.endsWith(".md"))
98
+ .map((f) => f.replace(".md", ""));
99
+ }
100
+ // ── Channel synthesis ─────────────────────────────────
101
+ export function channelSynthesisPath(channel) {
102
+ const dir = join(dirs().channels, channel);
103
+ if (!existsSync(dir))
104
+ mkdirSync(dir, { recursive: true });
105
+ return join(dir, "current.md");
106
+ }
107
+ export function readChannelSynthesis(channel) {
108
+ const path = channelSynthesisPath(channel);
109
+ if (!existsSync(path))
110
+ return null;
111
+ return readFileSync(path, "utf8");
112
+ }
113
+ export function writeChannelSynthesis(channel, content) {
114
+ writeFileSync(channelSynthesisPath(channel), content);
115
+ }
116
+ // ── Top-level files ───────────────────────────────────
117
+ export function readBrainFile(name) {
118
+ const path = join(dirs().brain, name);
119
+ if (!existsSync(path))
120
+ return "";
121
+ return readFileSync(path, "utf8");
122
+ }
123
+ export function writeBrainFile(name, content) {
124
+ ensureBrainDirs();
125
+ writeFileSync(join(dirs().brain, name), content);
126
+ }
127
+ // ── Index management ──────────────────────────────────
128
+ export function updateIndex(entries) {
129
+ const lines = ["# Brain Index\n"];
130
+ // Group by first letter or domain
131
+ for (const e of entries) {
132
+ lines.push(`- ${e.question} → [${e.slug}](topics/${e.slug}.md) (from #${e.source})`);
133
+ }
134
+ lines.push("");
135
+ writeBrainFile("index.md", lines.join("\n"));
136
+ }
137
+ // ── Timeline ──────────────────────────────────────────
138
+ // timeline/latest.md — rolling last 30 entries
139
+ // timeline/YYYY-MM.md — monthly archive
140
+ function timelineDir() { return join(resolveBrainDir(), "timeline"); }
141
+ export function appendTimeline(events) {
142
+ ensureBrainDirs();
143
+ const dir = timelineDir();
144
+ const latestPath = join(dir, "latest.md");
145
+ // Append to monthly archive
146
+ const month = new Date().toISOString().slice(0, 7); // YYYY-MM
147
+ const monthPath = join(dir, `${month}.md`);
148
+ const monthContent = existsSync(monthPath) ? readFileSync(monthPath, "utf8") : `# ${month}\n\n`;
149
+ const newEntries = events.map((e) => `- **${e.date}** [#${e.channel}] ${e.summary}`);
150
+ writeFileSync(monthPath, monthContent + newEntries.join("\n") + "\n");
151
+ // Rebuild latest.md (last 30 entries from recent monthly files)
152
+ const files = readdirSync(dir).filter((f) => f.match(/^\d{4}-\d{2}\.md$/)).sort().reverse();
153
+ const allEntries = [];
154
+ for (const file of files) {
155
+ if (allEntries.length >= 30)
156
+ break;
157
+ const content = readFileSync(join(dir, file), "utf8");
158
+ const entries = content.split("\n").filter((l) => l.startsWith("- "));
159
+ allEntries.push(...entries);
160
+ }
161
+ writeFileSync(latestPath, "# Recent Events\n\n" + allEntries.slice(0, 30).join("\n") + "\n");
162
+ }
163
+ // ── Decisions ─────────────────────────────────────────
164
+ // decisions/latest.md — rolling last 20 decisions
165
+ // decisions/YYYY-MM.md — monthly archive
166
+ function decisionsDir() { return join(resolveBrainDir(), "decisions"); }
167
+ export function appendDecision(decision) {
168
+ ensureBrainDirs();
169
+ const dir = decisionsDir();
170
+ // Append to monthly archive
171
+ const month = decision.date.slice(0, 7); // YYYY-MM
172
+ const monthPath = join(dir, `${month}.md`);
173
+ const monthContent = existsSync(monthPath) ? readFileSync(monthPath, "utf8") : `# Decisions — ${month}\n\n`;
174
+ const entry = `## ${decision.date} — ${decision.topic}\n\n${decision.summary}\n\n**Why:** ${decision.rationale}\n\n**Source:** #${decision.channel}\n\n`;
175
+ writeFileSync(monthPath, monthContent + entry);
176
+ // Rebuild latest.md (last 20 decisions from recent monthly files)
177
+ const files = readdirSync(dir).filter((f) => f.match(/^\d{4}-\d{2}\.md$/)).sort().reverse();
178
+ const allSections = [];
179
+ for (const file of files) {
180
+ if (allSections.length >= 20)
181
+ break;
182
+ const content = readFileSync(join(dir, file), "utf8");
183
+ const sections = content.split(/^## /m).filter(Boolean).filter((s) => !s.startsWith("Decisions"));
184
+ allSections.push(...sections.map((s) => `## ${s}`));
185
+ }
186
+ const latestPath = join(dir, "latest.md");
187
+ writeFileSync(latestPath, "# Recent Decisions\n\n" + allSections.slice(0, 20).join("\n") + "\n");
188
+ }
189
+ // ── References ──────────────────────────────────────────────
190
+ export function updateReferences(refs) {
191
+ const lines = ["# Cross-Channel References\n"];
192
+ for (const [entity, channels] of Object.entries(refs).sort()) {
193
+ lines.push(`- **${entity}**: ${channels.map((c) => `#${c}`).join(", ")}`);
194
+ }
195
+ lines.push("");
196
+ writeBrainFile("references.md", lines.join("\n"));
197
+ }
198
+ export function readView(name) {
199
+ const path = join(dirs().views, `${name}.yaml`);
200
+ if (!existsSync(path))
201
+ return null;
202
+ // Simple YAML-like parser (no dependency needed for this format)
203
+ const text = readFileSync(path, "utf8");
204
+ const view = { name: "", channels: [], interests: [] };
205
+ for (const line of text.split("\n")) {
206
+ const trimmed = line.trim();
207
+ if (trimmed.startsWith("name:"))
208
+ view.name = trimmed.slice(5).trim();
209
+ if (trimmed.startsWith("- ") && text.indexOf("channels:") < text.indexOf(trimmed) && text.indexOf("interests:") > text.indexOf(trimmed)) {
210
+ view.channels.push(trimmed.slice(2).trim());
211
+ }
212
+ }
213
+ return view;
214
+ }
215
+ export function writeView(view) {
216
+ ensureBrainDirs();
217
+ const lines = [
218
+ `name: ${view.name}`,
219
+ `channels:`,
220
+ ...view.channels.map((c) => ` - ${c}`),
221
+ `interests:`,
222
+ ...view.interests.map((i) => ` - ${i}`),
223
+ ];
224
+ if (view.exclude_channels?.length) {
225
+ lines.push(`exclude_channels:`);
226
+ lines.push(...view.exclude_channels.map((c) => ` - ${c}`));
227
+ }
228
+ writeFileSync(join(dirs().views, `${view.name}.yaml`), lines.join("\n") + "\n");
229
+ }
230
+ // ── Search index (MiniSearch) ─────────────────────────
231
+ import MiniSearch from "minisearch";
232
+ let searchIndex = null;
233
+ export function buildSearchIndex() {
234
+ const slugs = listTopics();
235
+ searchIndex = new MiniSearch({
236
+ fields: ["slug", "content", "aliases"],
237
+ storeFields: ["slug", "channels"],
238
+ searchOptions: {
239
+ boost: { slug: 3, aliases: 2, content: 1 },
240
+ prefix: true,
241
+ fuzzy: 0.2,
242
+ },
243
+ });
244
+ const docs = [];
245
+ for (const slug of slugs) {
246
+ const content = readTopic(slug);
247
+ if (!content)
248
+ continue;
249
+ // Extract aliases from frontmatter
250
+ const aliasMatch = content.match(/aliases:\s*\[([^\]]*)\]/);
251
+ const aliases = aliasMatch ? aliasMatch[1] : "";
252
+ // Extract sources from frontmatter
253
+ const sourcesMatch = content.match(/sources:\s*\[([^\]]*)\]/);
254
+ const channels = sourcesMatch ? sourcesMatch[1] : "";
255
+ docs.push({ id: slug, slug, content, aliases, channels });
256
+ }
257
+ searchIndex.addAll(docs);
258
+ }
259
+ export function searchBrain(query, limit = 5) {
260
+ if (!searchIndex)
261
+ buildSearchIndex();
262
+ if (!searchIndex)
263
+ return [];
264
+ const results = searchIndex.search(query).slice(0, limit);
265
+ return results.map((r) => ({
266
+ slug: r.id,
267
+ score: r.score,
268
+ channels: r.channels || "",
269
+ }));
270
+ }
271
+ //# sourceMappingURL=brain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brain.js","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"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"}