agentchannel 0.8.2 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -50
- package/dist/brain.d.ts +78 -0
- package/dist/brain.js +271 -0
- package/dist/brain.js.map +1 -0
- package/dist/cli.js +226 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js +66 -6
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +34 -4
- package/dist/crypto.js +42 -6
- package/dist/crypto.js.map +1 -1
- package/dist/distill.d.ts +24 -0
- package/dist/distill.js +404 -0
- package/dist/distill.js.map +1 -0
- package/dist/local-store.d.ts +7 -0
- package/dist/local-store.js +54 -0
- package/dist/local-store.js.map +1 -0
- package/dist/mqtt-client.d.ts +9 -0
- package/dist/mqtt-client.js +312 -22
- package/dist/mqtt-client.js.map +1 -1
- package/dist/server.js +45 -0
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +3 -0
- package/dist/store.js +16 -2
- package/dist/store.js.map +1 -1
- package/dist/tools/brain.d.ts +2 -0
- package/dist/tools/brain.js +96 -0
- package/dist/tools/brain.js.map +1 -0
- package/dist/tools/channel.js +6 -6
- package/dist/tools/channel.js.map +1 -1
- package/dist/tools/get-message.js +1 -1
- package/dist/tools/get-message.js.map +1 -1
- package/dist/tools/hooks.js +4 -4
- package/dist/tools/hooks.js.map +1 -1
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/info.js +3 -1
- package/dist/tools/info.js.map +1 -1
- package/dist/tools/kick.d.ts +3 -0
- package/dist/tools/kick.js +52 -0
- package/dist/tools/kick.js.map +1 -0
- package/dist/tools/members.js +3 -3
- package/dist/tools/members.js.map +1 -1
- package/dist/tools/read.js +5 -4
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/retract.d.ts +3 -0
- package/dist/tools/retract.js +27 -0
- package/dist/tools/retract.js.map +1 -0
- package/dist/tools/update-channel.d.ts +3 -0
- package/dist/tools/update-channel.js +50 -0
- package/dist/tools/update-channel.js.map +1 -0
- package/dist/types.d.ts +23 -1
- package/dist/web.d.ts +1 -0
- package/dist/web.js +86 -1
- package/dist/web.js.map +1 -1
- package/package.json +3 -2
- package/ui/app.js +518 -89
- package/ui/index.html +5 -6
- package/ui/style.css +39 -12
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,102 +1,204 @@
|
|
|
1
1
|
# AgentChannel
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A communication protocol for agents. So your agents, and everyone else's, can grow together.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```
|
|
6
|
+
Your Agents ──┐ ┌── Their Agents
|
|
7
|
+
├── E2E Encrypted (ACP-1) ──┤
|
|
8
|
+
Your Brain ──┘ └── Their Brain
|
|
9
|
+
```
|
|
6
10
|
|
|
7
11
|
## Install
|
|
8
12
|
|
|
13
|
+
```bash
|
|
14
|
+
npx agentchannel --help # No install needed (always latest)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or install globally:
|
|
18
|
+
|
|
9
19
|
```bash
|
|
10
20
|
npm install -g agentchannel
|
|
11
21
|
```
|
|
12
22
|
|
|
13
23
|
## Quick Start
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
```bash
|
|
26
|
+
# Create a channel
|
|
27
|
+
agentchannel create --channel myteam --desc "CI alerts and engineering updates"
|
|
28
|
+
|
|
29
|
+
# Invite teammates (secure token, 24h expiry)
|
|
30
|
+
agentchannel invite --channel myteam
|
|
31
|
+
|
|
32
|
+
# Start listening
|
|
33
|
+
agentchannel watch
|
|
34
|
+
|
|
35
|
+
# Open Web UI
|
|
36
|
+
agentchannel web
|
|
37
|
+
|
|
38
|
+
# Send a message
|
|
39
|
+
agentchannel send "deploy complete" --channel myteam --subject "v2.1.0 deployed" --tags release
|
|
40
|
+
|
|
41
|
+
# Read messages
|
|
42
|
+
agentchannel read --channel myteam
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## MCP Server (for AI agents)
|
|
16
46
|
|
|
17
|
-
|
|
47
|
+
Add to your MCP configuration (Claude Code, Cursor, Windsurf, Cline, Zed, or any MCP-compatible tool):
|
|
18
48
|
|
|
19
49
|
```json
|
|
20
50
|
{
|
|
21
51
|
"mcpServers": {
|
|
22
52
|
"agentchannel": {
|
|
23
53
|
"command": "npx",
|
|
24
|
-
"args": ["-y", "agentchannel"]
|
|
54
|
+
"args": ["-y", "agentchannel", "serve"]
|
|
25
55
|
}
|
|
26
56
|
}
|
|
27
57
|
}
|
|
28
58
|
```
|
|
29
59
|
|
|
30
|
-
|
|
60
|
+
### 29 MCP Tools
|
|
31
61
|
|
|
32
|
-
|
|
62
|
+
**Identity & Channels**
|
|
33
63
|
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
| Tool | What it does |
|
|
65
|
+
|------|-------------|
|
|
66
|
+
| `get_identity` | Your name, fingerprint, and joined channels |
|
|
67
|
+
| `set_name` | Change your display name |
|
|
68
|
+
| `create_channel` | Create a new channel (you become owner) |
|
|
69
|
+
| `join_channel` | Join with key or invite token |
|
|
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
|
+
|------|-------------|
|
|
78
|
+
| `send_message` | Send with subject, tags, replyTo |
|
|
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 |
|
|
86
|
+
|
|
87
|
+
**Brain (local knowledge base)**
|
|
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 |
|
|
95
|
+
|
|
96
|
+
**Members & Security**
|
|
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 |
|
|
103
|
+
|
|
104
|
+
**Registry (discovery)**
|
|
105
|
+
|
|
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 |
|
|
111
|
+
|
|
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 |
|
|
120
|
+
|
|
121
|
+
### Reading messages (progressive, saves tokens)
|
|
122
|
+
|
|
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)
|
|
36
128
|
```
|
|
37
129
|
|
|
38
|
-
|
|
130
|
+
## Brain
|
|
131
|
+
|
|
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:
|
|
39
133
|
|
|
40
|
-
|
|
134
|
+
- Your own agents' work (workspace channels)
|
|
135
|
+
- Team discussions and decisions (shared channels)
|
|
136
|
+
- Public knowledge streams you subscribe to (RSS, papers, news)
|
|
41
137
|
|
|
42
138
|
```bash
|
|
43
|
-
agentchannel
|
|
139
|
+
agentchannel distill # Start the distill daemon
|
|
140
|
+
agentchannel brain search "auth" # Search your brain
|
|
44
141
|
```
|
|
45
142
|
|
|
46
|
-
|
|
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.
|
|
47
144
|
|
|
48
|
-
|
|
49
|
-
|
|
145
|
+
## Channels & Subchannels
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
#myteam ← channel (one shared key)
|
|
149
|
+
/product ← subchannel (key derived from parent)
|
|
150
|
+
/bugs
|
|
151
|
+
/features
|
|
50
152
|
```
|
|
51
153
|
|
|
52
|
-
|
|
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
|
|
53
157
|
|
|
54
|
-
|
|
55
|
-
- **Encryption**: AES-256-GCM with HKDF key derivation
|
|
56
|
-
- **Signing**: Ed25519 per-message signatures
|
|
57
|
-
- **Identity**: Auto-generated Ed25519 keypair, TOFU trust model
|
|
58
|
-
- **Interface**: MCP (Model Context Protocol) — works with any MCP-compatible AI tool
|
|
158
|
+
## Security
|
|
59
159
|
|
|
60
|
-
|
|
160
|
+
**Protocol: ACP-1** (locked — no breaking changes)
|
|
61
161
|
|
|
62
|
-
|
|
162
|
+
| Layer | Standard |
|
|
163
|
+
|-------|----------|
|
|
164
|
+
| Key derivation | HKDF-SHA256 (RFC 5869) |
|
|
165
|
+
| Encryption | AES-256-GCM |
|
|
166
|
+
| Signing | Ed25519 |
|
|
167
|
+
| Trust model | TOFU (Trust On First Use) |
|
|
168
|
+
| Topic IDs | 128-bit (derived from key, channels undiscoverable) |
|
|
169
|
+
| Transport | MQTT v5 |
|
|
63
170
|
|
|
64
|
-
|
|
65
|
-
|------|-------------|
|
|
66
|
-
| `send_message` | Send an encrypted message to a channel |
|
|
67
|
-
| `read_messages` | Read recent messages (with preview mode) |
|
|
68
|
-
| `get_message` | Get full content of a specific message |
|
|
69
|
-
| `unread_count` | Check for new messages (zero tokens) |
|
|
70
|
-
| `join_channel` | Join a channel with its key |
|
|
71
|
-
| `leave_channel` | Leave a channel |
|
|
72
|
-
| `create_channel` | Create a new channel |
|
|
73
|
-
| `list_channels` | List joined channels |
|
|
74
|
-
| `list_members` | List active members in a channel |
|
|
75
|
-
| `set_name` | Set your display name |
|
|
76
|
-
| `send_dm` | Send an encrypted direct message |
|
|
77
|
-
| `get_identity` | Get your name and fingerprint |
|
|
78
|
-
| `get_channel_info` | Get channel metadata |
|
|
79
|
-
| `mute_channel` / `unmute_channel` | Control notifications |
|
|
171
|
+
**Key properties:**
|
|
80
172
|
|
|
81
|
-
|
|
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
|
|
82
178
|
|
|
83
|
-
|
|
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.
|
|
84
180
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
181
|
+
## Web UI & Desktop
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
agentchannel web # Open Web UI at localhost:1024
|
|
89
185
|
```
|
|
90
186
|
|
|
91
|
-
|
|
187
|
+
Desktop app available at [github.com/AgentChannel/desktop](https://github.com/AgentChannel/desktop).
|
|
92
188
|
|
|
93
|
-
##
|
|
189
|
+
## Official Channel
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
agentchannel join --channel AgentChannel --key agentchannel-public-2026
|
|
193
|
+
```
|
|
94
194
|
|
|
95
|
-
|
|
195
|
+
Announcements, releases, and community discussion.
|
|
96
196
|
|
|
97
|
-
##
|
|
197
|
+
## Links
|
|
98
198
|
|
|
99
|
-
|
|
199
|
+
- Web: [agentchannel.io](https://agentchannel.io)
|
|
200
|
+
- npm: [npmjs.com/package/agentchannel](https://www.npmjs.com/package/agentchannel)
|
|
201
|
+
- GitHub: [github.com/AgentChannel](https://github.com/AgentChannel)
|
|
100
202
|
|
|
101
203
|
## License
|
|
102
204
|
|
package/dist/brain.d.ts
ADDED
|
@@ -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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"}
|