@askexenow/exe-os 0.8.0 → 0.8.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.
- package/README.md +178 -79
- package/dist/bin/backfill-responses.js +160 -8
- package/dist/bin/backfill-vectors.js +130 -1
- package/dist/bin/cleanup-stale-review-tasks.js +130 -1
- package/dist/bin/cli.js +10111 -7540
- package/dist/bin/exe-agent.js +159 -1
- package/dist/bin/exe-assign.js +235 -16
- package/dist/bin/exe-boot.js +344 -472
- package/dist/bin/exe-call.js +145 -1
- package/dist/bin/exe-cloud.js +11 -0
- package/dist/bin/exe-dispatch.js +37 -24
- package/dist/bin/exe-doctor.js +130 -1
- package/dist/bin/exe-export-behaviors.js +150 -7
- package/dist/bin/exe-forget.js +822 -665
- package/dist/bin/exe-gateway.js +470 -62
- package/dist/bin/exe-heartbeat.js +133 -2
- package/dist/bin/exe-kill.js +150 -7
- package/dist/bin/exe-launch-agent.js +150 -7
- package/dist/bin/exe-new-employee.js +756 -224
- package/dist/bin/exe-pending-messages.js +132 -2
- package/dist/bin/exe-pending-notifications.js +130 -1
- package/dist/bin/exe-pending-reviews.js +132 -2
- package/dist/bin/exe-review.js +160 -8
- package/dist/bin/exe-search.js +2473 -2008
- package/dist/bin/exe-session-cleanup.js +238 -51
- package/dist/bin/exe-settings.js +11 -0
- package/dist/bin/exe-status.js +130 -1
- package/dist/bin/exe-team.js +130 -1
- package/dist/bin/git-sweep.js +272 -16
- package/dist/bin/graph-backfill.js +150 -7
- package/dist/bin/graph-export.js +150 -7
- package/dist/bin/install.js +5 -0
- package/dist/bin/scan-tasks.js +238 -19
- package/dist/bin/setup.js +1776 -10
- package/dist/bin/shard-migrate.js +150 -7
- package/dist/bin/update.js +9 -6
- package/dist/bin/wiki-sync.js +150 -7
- package/dist/gateway/index.js +470 -62
- package/dist/hooks/bug-report-worker.js +195 -35
- package/dist/hooks/commit-complete.js +272 -16
- package/dist/hooks/error-recall.js +2313 -1847
- package/dist/hooks/exe-heartbeat-hook.js +5 -0
- package/dist/hooks/ingest-worker.js +330 -58
- package/dist/hooks/ingest.js +11 -0
- package/dist/hooks/instructions-loaded.js +199 -10
- package/dist/hooks/notification.js +199 -10
- package/dist/hooks/post-compact.js +199 -10
- package/dist/hooks/pre-compact.js +199 -10
- package/dist/hooks/pre-tool-use.js +199 -10
- package/dist/hooks/prompt-ingest-worker.js +179 -14
- package/dist/hooks/prompt-submit.js +781 -285
- package/dist/hooks/response-ingest-worker.js +1900 -1405
- package/dist/hooks/session-end.js +456 -12
- package/dist/hooks/session-start.js +2188 -1724
- package/dist/hooks/stop.js +200 -10
- package/dist/hooks/subagent-stop.js +199 -10
- package/dist/hooks/summary-worker.js +604 -334
- package/dist/index.js +554 -61
- package/dist/lib/cloud-sync.js +5 -0
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +5 -0
- package/dist/lib/database.js +104 -0
- package/dist/lib/device-registry.js +109 -0
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employee-templates.js +53 -26
- package/dist/lib/employees.js +5 -0
- package/dist/lib/exe-daemon-client.js +5 -0
- package/dist/lib/exe-daemon.js +493 -79
- package/dist/lib/file-grep.js +20 -4
- package/dist/lib/hybrid-search.js +1435 -190
- package/dist/lib/identity-templates.js +126 -5
- package/dist/lib/identity.js +5 -0
- package/dist/lib/license.js +5 -0
- package/dist/lib/messaging.js +37 -24
- package/dist/lib/schedules.js +130 -1
- package/dist/lib/skill-learning.js +11 -0
- package/dist/lib/status-brief.js +5 -0
- package/dist/lib/store.js +199 -10
- package/dist/lib/task-router.js +72 -6
- package/dist/lib/tasks.js +179 -50
- package/dist/lib/tmux-routing.js +179 -46
- package/dist/mcp/server.js +2129 -1855
- package/dist/mcp/tools/create-task.js +86 -36
- package/dist/mcp/tools/deactivate-behavior.js +5 -0
- package/dist/mcp/tools/list-tasks.js +39 -11
- package/dist/mcp/tools/send-message.js +37 -24
- package/dist/mcp/tools/update-task.js +153 -38
- package/dist/runtime/index.js +451 -59
- package/dist/tui/App.js +454 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,42 +1,65 @@
|
|
|
1
1
|
# Exe OS
|
|
2
2
|
|
|
3
|
-
    
|
|
4
4
|
|
|
5
|
-
**AI
|
|
5
|
+
**Hire the team you couldn't afford.** AI employee operating system with persistent memory, identity, and multi-agent orchestration.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Run 5-10 AI employees as a real organization. Each employee has persistent memory across sessions, a permanent identity, and a task queue. You talk to your COO. Your COO coordinates everyone else.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
---
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- **Native CLI automation.** Agents run inside official Claude Code CLI sessions. Exe OS sends keystrokes via `tmux send-keys` — standard Unix terminal multiplexing, the same way any developer scripts their terminal.
|
|
13
|
-
- **Officially supported features only.** All orchestration uses documented Claude Code capabilities: [hooks](https://docs.anthropic.com/en/docs/claude-code/hooks), [MCP servers](https://docs.anthropic.com/en/docs/claude-code/mcp), `.claude.json` permissions, and `--agent` identity injection.
|
|
14
|
-
- **BYOS — Bring Your Own Subscription.** Exe OS is the orchestration layer. The LLM subscription (Claude Max, API key, or any provider) belongs to you. Your subscription, your compute.
|
|
11
|
+
## Install
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @askexenow/exe-os
|
|
15
|
+
exe-os setup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Two commands. Encryption key generated, embedding model downloaded, team created.
|
|
19
|
+
|
|
20
|
+
---
|
|
17
21
|
|
|
18
|
-
##
|
|
22
|
+
## Two Ways to Work
|
|
23
|
+
|
|
24
|
+
### Mode 1: Claude Code
|
|
25
|
+
|
|
26
|
+
Use your existing Claude Code subscription. Type your COO's name in the terminal.
|
|
19
27
|
|
|
20
28
|
```bash
|
|
21
|
-
|
|
22
|
-
exe
|
|
23
|
-
exe-os # launch the TUI
|
|
29
|
+
exe-os claude # wire hooks + MCP into Claude Code (one-time)
|
|
30
|
+
exe # talk to your COO
|
|
24
31
|
```
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
Best for: developers who live in the terminal.
|
|
34
|
+
|
|
35
|
+
### Mode 2: Dashboard
|
|
36
|
+
|
|
37
|
+
Visual terminal UI with sidebar, team view, tasks, and metrics.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
exe-os # launch the dashboard
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Best for: managing multiple projects and employees.
|
|
44
|
+
|
|
45
|
+
**Both modes share the same memory, employees, and data. Switch anytime.**
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## What You Get
|
|
29
50
|
|
|
30
51
|
| Feature | What it does |
|
|
31
52
|
|---------|-------------|
|
|
32
|
-
| **Persistent memory** | Every
|
|
33
|
-
| **
|
|
34
|
-
| **
|
|
35
|
-
| **
|
|
36
|
-
| **
|
|
37
|
-
| **
|
|
38
|
-
| **Cloud sync** | End-to-end encrypted memory sync across devices. |
|
|
39
|
-
| **
|
|
53
|
+
| **Persistent memory** | Every interaction stored in encrypted SQLCipher + vector search. Searchable across sessions. |
|
|
54
|
+
| **Three-layer cognition** | Identity (who you are) + Expertise (what you've learned) + Experience (what you remember) |
|
|
55
|
+
| **Multi-agent orchestration** | COO coordinates CTO, CMO, engineers. Parallel task execution via tmux. |
|
|
56
|
+
| **Task system** | Create, assign, review, chain tasks. Auto-dispatch. Review pipeline with cascading approval. |
|
|
57
|
+
| **Identity injection** | Each employee gets a permanent identity doc. Claude Code's `--agent` flag replaces the default system prompt. |
|
|
58
|
+
| **Skill learning** | Agents learn procedures from repeated patterns. Corrections become permanent behaviors. |
|
|
59
|
+
| **Cloud sync** | End-to-end encrypted memory sync across devices. Your key, your data. |
|
|
60
|
+
| **License activation** | `exe-os --activate <key>` to unlock CTO + CMO. Free tier: 1 employee (COO only). |
|
|
61
|
+
|
|
62
|
+
---
|
|
40
63
|
|
|
41
64
|
## How It Works
|
|
42
65
|
|
|
@@ -44,96 +67,172 @@ Three commands. You're running.
|
|
|
44
67
|
You
|
|
45
68
|
|
|
|
46
69
|
v
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
└── session scoping (one exe per project, isolated)
|
|
70
|
+
Your COO (exe)
|
|
71
|
+
├── Yoshi (CTO) ──> architecture, code reviews, tech decisions
|
|
72
|
+
│ └── Tom (Engineer) ──> implementation, tests, commits
|
|
73
|
+
├── Mari (CMO) ──> design, content, SEO, branding
|
|
74
|
+
│ └── Sasha (Content) ──> video, images, production
|
|
75
|
+
└── Gen (AI Specialist) ──> AI tools, research, evaluation
|
|
54
76
|
```
|
|
55
77
|
|
|
56
|
-
|
|
78
|
+
You talk to your COO. Your COO delegates. Each employee has:
|
|
79
|
+
- **Persistent memory** — remembers past work, decisions, patterns
|
|
80
|
+
- **Identity** — permanent role doc that defines who they are
|
|
81
|
+
- **Task queue** — auto-chains through assigned work
|
|
82
|
+
- **Behavioral expertise** — corrections accumulate as permanent rules
|
|
57
83
|
|
|
58
|
-
|
|
84
|
+
---
|
|
59
85
|
|
|
60
|
-
|
|
86
|
+
## Setup Walkthrough
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
- **Sessions** — navigate between projects and employees, view live output
|
|
64
|
-
- **Tasks** — kanban board of all active tasks across projects
|
|
65
|
-
- **Gateway** — external-facing agent channels and health
|
|
66
|
-
- **Team** — employee roster with live status (internal + external agents)
|
|
67
|
-
- **Memory** — search across all memories with semantic search
|
|
68
|
-
- **Settings** — providers, encryption, runtime config, employee models
|
|
88
|
+
### 1. Install
|
|
69
89
|
|
|
70
|
-
|
|
90
|
+
```bash
|
|
91
|
+
npm install -g @askexenow/exe-os
|
|
92
|
+
```
|
|
71
93
|
|
|
72
|
-
|
|
94
|
+
Requires Node.js 20+ and tmux (`brew install tmux` on macOS).
|
|
73
95
|
|
|
74
|
-
|
|
75
|
-
- **Claude Code** subscription (Max or Pro)
|
|
76
|
-
- **tmux** — auto-detected, required for multi-agent
|
|
96
|
+
### 2. Run Setup
|
|
77
97
|
|
|
78
98
|
```bash
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
exe-os setup
|
|
100
|
+
```
|
|
81
101
|
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
This runs the setup wizard:
|
|
103
|
+
- Generates 256-bit encryption key (stored in system keychain)
|
|
104
|
+
- Downloads Jina v5 embedding model (397MB, runs locally)
|
|
105
|
+
- Names your COO (default: exe)
|
|
106
|
+
- Shows your team (CTO, CMO) and pricing tiers
|
|
107
|
+
- Optionally activates a license key
|
|
108
|
+
|
|
109
|
+
### 3. Choose Your Mode
|
|
110
|
+
|
|
111
|
+
**Mode 1 — Claude Code:**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
exe-os claude # install hooks + MCP into Claude Code
|
|
115
|
+
exe # launch your COO (or whatever you named them)
|
|
84
116
|
```
|
|
85
117
|
|
|
86
|
-
|
|
118
|
+
**Mode 2 — Dashboard:**
|
|
87
119
|
|
|
88
|
-
|
|
120
|
+
```bash
|
|
121
|
+
exe-os # launch the TUI dashboard
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Pricing
|
|
127
|
+
|
|
128
|
+
| Plan | Price | Employees | Memories | Devices |
|
|
129
|
+
|------|-------|-----------|----------|---------|
|
|
130
|
+
| Free | $0 | 1 (COO) | 5,000 | 1 |
|
|
131
|
+
| Solopreneur | $97/mo | 5 | 100,000 | 2 |
|
|
132
|
+
| Company | $297/mo | 20 | 1,000,000 | 10 |
|
|
133
|
+
| Agency | $497/mo | 100 | 10,000,000 | 50 |
|
|
134
|
+
| Enterprise | Custom | Unlimited | Unlimited | Unlimited |
|
|
89
135
|
|
|
90
|
-
|
|
91
|
-
|------|------|--------------|
|
|
92
|
-
| exe | COO | claude-opus-4-6 |
|
|
93
|
-
| yoshi | CTO | claude-opus-4-6 |
|
|
94
|
-
| mari | CMO | claude-sonnet-4-6 |
|
|
95
|
-
| tom | Principal Engineer | claude-sonnet-4-6 |
|
|
96
|
-
| sasha | Content Production | claude-sonnet-4-6 |
|
|
136
|
+
Activate: `exe-os --activate <key>` or paste during `exe-os setup`.
|
|
97
137
|
|
|
98
|
-
|
|
138
|
+
Purchase at [askexe.com](https://askexe.com).
|
|
99
139
|
|
|
100
|
-
|
|
140
|
+
---
|
|
101
141
|
|
|
102
|
-
|
|
142
|
+
## Employee Templates
|
|
143
|
+
|
|
144
|
+
Create employees with built-in templates:
|
|
103
145
|
|
|
104
146
|
```bash
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
147
|
+
exe-new-employee yoshi --template yoshi # CTO
|
|
148
|
+
exe-new-employee mari --template mari # CMO
|
|
149
|
+
exe-new-employee tom --template tom # Principal Engineer
|
|
150
|
+
exe-new-employee sasha --template sasha # Content Specialist
|
|
151
|
+
exe-new-employee gen --template gen # AI Specialist
|
|
108
152
|
```
|
|
109
153
|
|
|
110
|
-
|
|
154
|
+
Or create custom employees:
|
|
111
155
|
|
|
112
|
-
|
|
156
|
+
```bash
|
|
157
|
+
exe-new-employee alex # custom specialist
|
|
158
|
+
```
|
|
113
159
|
|
|
114
|
-
|
|
160
|
+
Each employee gets an identity doc at `~/.exe-os/identity/{name}.md`, a task folder, and launcher commands.
|
|
115
161
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## For Agencies
|
|
165
|
+
|
|
166
|
+
See [docs/Agency-Playbook.md](docs/Agency-Playbook.md) for multi-client VPS deployment:
|
|
167
|
+
- One VPS, multiple clients, full data isolation
|
|
168
|
+
- Per-client wiki workspaces
|
|
169
|
+
- Cross-client querying for agency owners
|
|
170
|
+
- Config-driven white-label theming via `branding.json`
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Commands
|
|
175
|
+
|
|
176
|
+
| Command | What it does |
|
|
177
|
+
|---------|-------------|
|
|
178
|
+
| `exe-os` | Launch TUI dashboard (Mode 2) |
|
|
179
|
+
| `exe-os setup` | Run setup wizard |
|
|
180
|
+
| `exe-os claude` | Install hooks + MCP into Claude Code (Mode 1) |
|
|
181
|
+
| `exe-os --activate <key>` | Activate a license key |
|
|
182
|
+
| `exe` | Launch your COO in Claude Code |
|
|
183
|
+
| `exe-new-employee <name>` | Create a new employee |
|
|
184
|
+
| `/exe` | Boot your COO (inside Claude Code) |
|
|
185
|
+
| `/exe-team` | Show employee roster |
|
|
186
|
+
| `/exe-search <query>` | Search memories |
|
|
187
|
+
|
|
188
|
+
---
|
|
119
189
|
|
|
120
190
|
## Architecture
|
|
121
191
|
|
|
122
192
|
```
|
|
123
193
|
exe-os/
|
|
124
194
|
src/
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
195
|
+
lib/ # Core: memory, tasks, identity, behaviors, search, sync, encryption
|
|
196
|
+
mcp/ # MCP server (20+ tools for Claude Code integration)
|
|
197
|
+
adapters/ # Claude Code hooks (ingest, session-start, pre-tool-use, etc.)
|
|
198
|
+
tui/ # Ink-based terminal dashboard (Mode 2)
|
|
199
|
+
runtime/ # Agent loop, tool registry, permissions (Mode 2 standalone)
|
|
200
|
+
gateway/ # External messaging (WhatsApp, Telegram, Discord, webhook)
|
|
201
|
+
deploy/
|
|
202
|
+
compose/ # Docker Compose for VPS deployment (CRM + wiki + gateway + daemon)
|
|
203
|
+
Dockerfile* # Per-service Docker images
|
|
204
|
+
docs/
|
|
205
|
+
Agency-Playbook.md # Multi-client VPS guide
|
|
131
206
|
```
|
|
132
207
|
|
|
133
|
-
**
|
|
208
|
+
**Three runtime modes:**
|
|
209
|
+
|
|
210
|
+
| Mode | Entry | What you see |
|
|
211
|
+
|------|-------|-------------|
|
|
212
|
+
| Mode 1: Claude Code | `exe` | Claude Code terminal with COO identity |
|
|
213
|
+
| Mode 2: TUI Dashboard | `exe-os` | Terminal dashboard with sidebar + team view |
|
|
214
|
+
| Mode 3: Desktop | `exe-os desktop` | Tauri native app (coming soon) |
|
|
215
|
+
|
|
216
|
+
**Storage:** SQLCipher (encrypted SQLite) + Jina v5 embeddings (local, 1024-dim). No data leaves your machine unless you opt into Exe Cloud (E2EE).
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Requirements
|
|
221
|
+
|
|
222
|
+
- **Node.js 20+**
|
|
223
|
+
- **tmux** — for multi-agent session management
|
|
224
|
+
- **Claude Code** subscription (Mode 1) or API key (Mode 2)
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# macOS
|
|
228
|
+
brew install tmux node
|
|
229
|
+
|
|
230
|
+
# Linux
|
|
231
|
+
apt install tmux nodejs
|
|
232
|
+
```
|
|
134
233
|
|
|
135
|
-
|
|
234
|
+
---
|
|
136
235
|
|
|
137
236
|
## License
|
|
138
237
|
|
|
139
|
-
CC-BY-NC-4.0
|
|
238
|
+
CC-BY-NC-4.0 (non-commercial). Commercial licenses available at [askexe.com](https://askexe.com).
|
|
@@ -81,6 +81,11 @@ function normalizeSessionLifecycle(raw) {
|
|
|
81
81
|
const userSL = raw.sessionLifecycle ?? {};
|
|
82
82
|
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
83
83
|
}
|
|
84
|
+
function normalizeAutoUpdate(raw) {
|
|
85
|
+
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
86
|
+
const userAU = raw.autoUpdate ?? {};
|
|
87
|
+
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
88
|
+
}
|
|
84
89
|
async function loadConfig() {
|
|
85
90
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
86
91
|
await mkdir2(dir, { recursive: true });
|
|
@@ -103,6 +108,7 @@ async function loadConfig() {
|
|
|
103
108
|
}
|
|
104
109
|
normalizeScalingRoadmap(migratedCfg);
|
|
105
110
|
normalizeSessionLifecycle(migratedCfg);
|
|
111
|
+
normalizeAutoUpdate(migratedCfg);
|
|
106
112
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
107
113
|
if (config.dbPath.startsWith("~")) {
|
|
108
114
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -178,6 +184,11 @@ var init_config = __esm({
|
|
|
178
184
|
idleKillTicksRequired: 3,
|
|
179
185
|
idleKillIntercomAckWindowMs: 1e4,
|
|
180
186
|
maxAutoInstances: 10
|
|
187
|
+
},
|
|
188
|
+
autoUpdate: {
|
|
189
|
+
checkOnBoot: true,
|
|
190
|
+
autoInstall: false,
|
|
191
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
181
192
|
}
|
|
182
193
|
};
|
|
183
194
|
CONFIG_MIGRATIONS = [
|
|
@@ -311,13 +322,27 @@ async function ensureShardSchema(client) {
|
|
|
311
322
|
"ALTER TABLE memories ADD COLUMN document_id TEXT",
|
|
312
323
|
"ALTER TABLE memories ADD COLUMN user_id TEXT",
|
|
313
324
|
"ALTER TABLE memories ADD COLUMN char_offset INTEGER",
|
|
314
|
-
"ALTER TABLE memories ADD COLUMN page_number INTEGER"
|
|
325
|
+
"ALTER TABLE memories ADD COLUMN page_number INTEGER",
|
|
326
|
+
// Source provenance columns (must match database.ts)
|
|
327
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
328
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
329
|
+
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
330
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
315
331
|
]) {
|
|
316
332
|
try {
|
|
317
333
|
await client.execute(col);
|
|
318
334
|
} catch {
|
|
319
335
|
}
|
|
320
336
|
}
|
|
337
|
+
for (const idx of [
|
|
338
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
339
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
340
|
+
]) {
|
|
341
|
+
try {
|
|
342
|
+
await client.execute(idx);
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
}
|
|
321
346
|
try {
|
|
322
347
|
await client.execute("CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)");
|
|
323
348
|
} catch {
|
|
@@ -642,6 +667,27 @@ async function ensureSchema() {
|
|
|
642
667
|
});
|
|
643
668
|
} catch {
|
|
644
669
|
}
|
|
670
|
+
try {
|
|
671
|
+
await client.execute({
|
|
672
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
|
|
673
|
+
args: []
|
|
674
|
+
});
|
|
675
|
+
} catch {
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
await client.execute({
|
|
679
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
|
|
680
|
+
args: []
|
|
681
|
+
});
|
|
682
|
+
} catch {
|
|
683
|
+
}
|
|
684
|
+
try {
|
|
685
|
+
await client.execute({
|
|
686
|
+
sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
|
|
687
|
+
args: []
|
|
688
|
+
});
|
|
689
|
+
} catch {
|
|
690
|
+
}
|
|
645
691
|
try {
|
|
646
692
|
await client.execute({
|
|
647
693
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -1052,6 +1098,15 @@ async function ensureSchema() {
|
|
|
1052
1098
|
} catch {
|
|
1053
1099
|
}
|
|
1054
1100
|
}
|
|
1101
|
+
for (const col of [
|
|
1102
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
1103
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'"
|
|
1104
|
+
]) {
|
|
1105
|
+
try {
|
|
1106
|
+
await client.execute(col);
|
|
1107
|
+
} catch {
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1055
1110
|
await client.executeMultiple(`
|
|
1056
1111
|
CREATE INDEX IF NOT EXISTS idx_memories_workspace
|
|
1057
1112
|
ON memories(workspace_id);
|
|
@@ -1116,6 +1171,34 @@ async function ensureSchema() {
|
|
|
1116
1171
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1117
1172
|
ON conversations(channel_id);
|
|
1118
1173
|
`);
|
|
1174
|
+
try {
|
|
1175
|
+
await client.execute({
|
|
1176
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
1177
|
+
args: []
|
|
1178
|
+
});
|
|
1179
|
+
} catch {
|
|
1180
|
+
}
|
|
1181
|
+
try {
|
|
1182
|
+
await client.execute({
|
|
1183
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
|
|
1184
|
+
args: []
|
|
1185
|
+
});
|
|
1186
|
+
} catch {
|
|
1187
|
+
}
|
|
1188
|
+
try {
|
|
1189
|
+
await client.execute({
|
|
1190
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
|
|
1191
|
+
args: []
|
|
1192
|
+
});
|
|
1193
|
+
} catch {
|
|
1194
|
+
}
|
|
1195
|
+
try {
|
|
1196
|
+
await client.execute({
|
|
1197
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
|
|
1198
|
+
args: []
|
|
1199
|
+
});
|
|
1200
|
+
} catch {
|
|
1201
|
+
}
|
|
1119
1202
|
await client.executeMultiple(`
|
|
1120
1203
|
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
1121
1204
|
content_text,
|
|
@@ -1142,6 +1225,52 @@ async function ensureSchema() {
|
|
|
1142
1225
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
1143
1226
|
END;
|
|
1144
1227
|
`);
|
|
1228
|
+
try {
|
|
1229
|
+
await client.execute({
|
|
1230
|
+
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
1231
|
+
args: []
|
|
1232
|
+
});
|
|
1233
|
+
} catch {
|
|
1234
|
+
}
|
|
1235
|
+
try {
|
|
1236
|
+
await client.execute(
|
|
1237
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
1238
|
+
);
|
|
1239
|
+
} catch {
|
|
1240
|
+
}
|
|
1241
|
+
try {
|
|
1242
|
+
await client.execute({
|
|
1243
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
1244
|
+
args: []
|
|
1245
|
+
});
|
|
1246
|
+
await client.execute({
|
|
1247
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
1248
|
+
args: []
|
|
1249
|
+
});
|
|
1250
|
+
} catch {
|
|
1251
|
+
}
|
|
1252
|
+
try {
|
|
1253
|
+
await client.execute({
|
|
1254
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
1255
|
+
args: []
|
|
1256
|
+
});
|
|
1257
|
+
} catch {
|
|
1258
|
+
}
|
|
1259
|
+
try {
|
|
1260
|
+
await client.execute(
|
|
1261
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
1262
|
+
);
|
|
1263
|
+
} catch {
|
|
1264
|
+
}
|
|
1265
|
+
for (const col of [
|
|
1266
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
1267
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
1268
|
+
]) {
|
|
1269
|
+
try {
|
|
1270
|
+
await client.execute(col);
|
|
1271
|
+
} catch {
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1145
1274
|
}
|
|
1146
1275
|
|
|
1147
1276
|
// src/lib/keychain.ts
|
|
@@ -1233,6 +1362,11 @@ async function initStore(options) {
|
|
|
1233
1362
|
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1234
1363
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1235
1364
|
}
|
|
1365
|
+
function classifyTier(record) {
|
|
1366
|
+
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
1367
|
+
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1368
|
+
return 3;
|
|
1369
|
+
}
|
|
1236
1370
|
async function writeMemory(record) {
|
|
1237
1371
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1238
1372
|
throw new Error(
|
|
@@ -1260,7 +1394,11 @@ async function writeMemory(record) {
|
|
|
1260
1394
|
document_id: record.document_id ?? null,
|
|
1261
1395
|
user_id: record.user_id ?? null,
|
|
1262
1396
|
char_offset: record.char_offset ?? null,
|
|
1263
|
-
page_number: record.page_number ?? null
|
|
1397
|
+
page_number: record.page_number ?? null,
|
|
1398
|
+
source_path: record.source_path ?? null,
|
|
1399
|
+
source_type: record.source_type ?? null,
|
|
1400
|
+
tier: record.tier ?? classifyTier(record),
|
|
1401
|
+
supersedes_id: record.supersedes_id ?? null
|
|
1264
1402
|
};
|
|
1265
1403
|
_pendingRecords.push(dbRow);
|
|
1266
1404
|
if (_flushTimer === null) {
|
|
@@ -1292,20 +1430,26 @@ async function flushBatch() {
|
|
|
1292
1430
|
const userId = row.user_id ?? null;
|
|
1293
1431
|
const charOffset = row.char_offset ?? null;
|
|
1294
1432
|
const pageNumber = row.page_number ?? null;
|
|
1433
|
+
const sourcePath = row.source_path ?? null;
|
|
1434
|
+
const sourceType = row.source_type ?? null;
|
|
1435
|
+
const tier = row.tier ?? 3;
|
|
1436
|
+
const supersedesId = row.supersedes_id ?? null;
|
|
1295
1437
|
return {
|
|
1296
1438
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
1297
1439
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1298
1440
|
tool_name, project_name,
|
|
1299
1441
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1300
1442
|
confidence, last_accessed,
|
|
1301
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1302
|
-
|
|
1443
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1444
|
+
source_path, source_type, tier, supersedes_id)
|
|
1445
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
1303
1446
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1304
1447
|
tool_name, project_name,
|
|
1305
1448
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1306
1449
|
confidence, last_accessed,
|
|
1307
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1308
|
-
|
|
1450
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1451
|
+
source_path, source_type, tier, supersedes_id)
|
|
1452
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1309
1453
|
args: hasVector ? [
|
|
1310
1454
|
row.id,
|
|
1311
1455
|
row.agent_id,
|
|
@@ -1327,7 +1471,11 @@ async function flushBatch() {
|
|
|
1327
1471
|
documentId,
|
|
1328
1472
|
userId,
|
|
1329
1473
|
charOffset,
|
|
1330
|
-
pageNumber
|
|
1474
|
+
pageNumber,
|
|
1475
|
+
sourcePath,
|
|
1476
|
+
sourceType,
|
|
1477
|
+
tier,
|
|
1478
|
+
supersedesId
|
|
1331
1479
|
] : [
|
|
1332
1480
|
row.id,
|
|
1333
1481
|
row.agent_id,
|
|
@@ -1348,7 +1496,11 @@ async function flushBatch() {
|
|
|
1348
1496
|
documentId,
|
|
1349
1497
|
userId,
|
|
1350
1498
|
charOffset,
|
|
1351
|
-
pageNumber
|
|
1499
|
+
pageNumber,
|
|
1500
|
+
sourcePath,
|
|
1501
|
+
sourceType,
|
|
1502
|
+
tier,
|
|
1503
|
+
supersedesId
|
|
1352
1504
|
]
|
|
1353
1505
|
};
|
|
1354
1506
|
};
|