agentacta 1.0.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/LICENSE +21 -0
- package/README.md +216 -0
- package/config.js +55 -0
- package/db.js +137 -0
- package/index.js +376 -0
- package/indexer.js +330 -0
- package/package.json +51 -0
- package/public/app.js +658 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/icon.svg +72 -0
- package/public/index.html +50 -0
- package/public/manifest.json +26 -0
- package/public/style.css +562 -0
- package/public/sw.js +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miraj Chokshi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# AgentActa
|
|
2
|
+
|
|
3
|
+
[](https://github.com/mirajchokshi/agentacta/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/agentacta)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
**Your AI agent does hundreds of things. Can you find them?**
|
|
8
|
+
|
|
9
|
+
AgentActa is an audit trail and search engine for AI agent sessions. It indexes everything your agent did — every message, tool call, file edit, web search, and decision — into a fast, searchable local interface.
|
|
10
|
+
|
|
11
|
+
One command. Zero config. Full visibility.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx agentacta
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
AI agents are powerful. They write code, send emails, manage infrastructure, make decisions on your behalf. But when you need to know *what happened* — what was changed, when, and why — you're digging through scattered logs or asking the agent to remember (it won't).
|
|
22
|
+
|
|
23
|
+
AgentActa gives you a single, searchable view of everything.
|
|
24
|
+
|
|
25
|
+
## What You Get
|
|
26
|
+
|
|
27
|
+
🔍 **Full-text search** across all messages, tool calls, and results
|
|
28
|
+
📋 **Session browser** with summaries, token breakdowns (input/output), and model info
|
|
29
|
+
📅 **Timeline view** — everything that happened on any given day
|
|
30
|
+
📁 **File activity** — every file your agent touched, across all sessions
|
|
31
|
+
📊 **Stats** — sessions, messages, tool usage, token counts
|
|
32
|
+
⚡ **Live indexing** — new sessions appear automatically via file watching
|
|
33
|
+
📱 **Mobile-friendly** — responsive UI with bottom tab navigation
|
|
34
|
+
💡 **Smart suggestions** — quick search chips derived from your actual session data
|
|
35
|
+
|
|
36
|
+
## Demo
|
|
37
|
+
|
|
38
|
+
https://github.com/mirajchokshi/agentacta/raw/main/screenshots/demo-final.mp4
|
|
39
|
+
|
|
40
|
+
## Screenshots
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Run directly (no install needed)
|
|
54
|
+
npx agentacta
|
|
55
|
+
|
|
56
|
+
# Or install globally
|
|
57
|
+
npm install -g agentacta
|
|
58
|
+
agentacta
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Open `http://localhost:4003` in your browser.
|
|
62
|
+
|
|
63
|
+
AgentActa automatically finds your sessions in:
|
|
64
|
+
- `~/.openclaw/agents/*/sessions/` (OpenClaw)
|
|
65
|
+
- `~/.claude/projects/*/sessions/` (Claude Code)
|
|
66
|
+
|
|
67
|
+
Or point it at a custom path:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
AGENTACTA_SESSIONS_PATH=/path/to/sessions agentacta
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
### Search
|
|
76
|
+
Full-text search powered by SQLite FTS5. Filter by message type (messages, tool calls, results) and role (user, assistant). Quick search suggestions are generated from your actual data — most-used tools, common topics, frequently touched files.
|
|
77
|
+
|
|
78
|
+
### Sessions
|
|
79
|
+
Browse all indexed sessions with auto-generated summaries, token breakdowns (output vs input), and model info. Click into any session to see the full event history, most recent first.
|
|
80
|
+
|
|
81
|
+
### Timeline
|
|
82
|
+
Pick a date, see everything that happened. Messages, tool invocations, file changes — most recent first.
|
|
83
|
+
|
|
84
|
+
### File Activity
|
|
85
|
+
See every file your agent read, wrote, or edited. Sort by most touched, most recent, or most sessions. Filter by extension, group by directory. Click any file to see which sessions touched it and what was done.
|
|
86
|
+
|
|
87
|
+
### Export
|
|
88
|
+
Download any session or search results as Markdown or JSON. Great for sharing, auditing, or archiving.
|
|
89
|
+
|
|
90
|
+
## How It Works
|
|
91
|
+
|
|
92
|
+
AgentActa reads JSONL session files (the standard format used by OpenClaw and Claude Code), parses every message and tool call, and indexes them into a local SQLite database with FTS5 full-text search.
|
|
93
|
+
|
|
94
|
+
The web UI is a single-page app served by a lightweight Node.js HTTP server. No frameworks, no build step, no external dependencies beyond `better-sqlite3`.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Session JSONL files → SQLite + FTS5 index → HTTP API → Web UI
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Data never leaves your machine.
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
On first run, AgentActa creates `agentacta.config.json` with sensible defaults:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"port": 4003,
|
|
109
|
+
"storage": "reference",
|
|
110
|
+
"sessionDirs": []
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Storage Modes
|
|
115
|
+
|
|
116
|
+
- **`reference`** (default) — Lightweight index. Stores parsed events in SQLite but not the raw JSONL. Source files must remain on disk.
|
|
117
|
+
- **`archive`** — Full JSONL stored in SQLite. Sessions survive even if the original files are deleted. Uses more disk space.
|
|
118
|
+
|
|
119
|
+
### Environment Variables
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Description |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `PORT` | `4003` | Server port |
|
|
124
|
+
| `AGENTACTA_HOST` | `127.0.0.1` | Bind address (see [Security](#security)) |
|
|
125
|
+
| `AGENTACTA_SESSIONS_PATH` | Auto-detected | Custom sessions directory |
|
|
126
|
+
| `AGENTACTA_DB_PATH` | `./agentacta.db` | Database file location |
|
|
127
|
+
| `AGENTACTA_STORAGE` | `reference` | Storage mode (`reference` or `archive`) |
|
|
128
|
+
|
|
129
|
+
## API
|
|
130
|
+
|
|
131
|
+
AgentActa exposes a JSON API for programmatic access — useful for integrating search into your agent's workflow.
|
|
132
|
+
|
|
133
|
+
| Endpoint | Description |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `GET /api/stats` | Overview: session count, messages, tools, tokens |
|
|
136
|
+
| `GET /api/sessions` | List sessions with metadata and token breakdowns |
|
|
137
|
+
| `GET /api/sessions/:id` | Full session with all events |
|
|
138
|
+
| `GET /api/search?q=<query>` | Full-text search with type/role/date filters |
|
|
139
|
+
| `GET /api/suggestions` | Data-driven search suggestions |
|
|
140
|
+
| `GET /api/timeline?date=YYYY-MM-DD` | All events for a given day |
|
|
141
|
+
| `GET /api/files` | All files touched across sessions |
|
|
142
|
+
| `GET /api/export/session/:id?format=md` | Export session as Markdown or JSON |
|
|
143
|
+
| `GET /api/export/search?q=<query>&format=md` | Export search results |
|
|
144
|
+
|
|
145
|
+
### Agent Integration
|
|
146
|
+
|
|
147
|
+
Your AI agent can query AgentActa for better recall:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
const results = await fetch('http://localhost:4003/api/search?q=deployment+issue&limit=5');
|
|
151
|
+
const data = await results.json();
|
|
152
|
+
// Agent now has context from past sessions
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Demo Mode
|
|
156
|
+
|
|
157
|
+
Want to see what AgentActa looks like with data? Run with demo sessions:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Generate demo data and start in demo mode
|
|
161
|
+
npm run demo
|
|
162
|
+
|
|
163
|
+
# Or separately:
|
|
164
|
+
node scripts/seed-demo.js
|
|
165
|
+
node index.js --demo
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This creates 7 realistic sessions simulating a developer building a weather app — scaffolding, API integration, frontend, debugging, deployment, tests, and a sub-agent task.
|
|
169
|
+
|
|
170
|
+
## Security
|
|
171
|
+
|
|
172
|
+
**AgentActa is a local tool.** It binds to `127.0.0.1` by default — only accessible from your machine.
|
|
173
|
+
|
|
174
|
+
To expose on your network (e.g., for Tailscale access):
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
AGENTACTA_HOST=0.0.0.0 agentacta
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
⚠️ **Important:** Agent session data can contain sensitive information — file contents, API responses, personal messages, tool call arguments. If you expose AgentActa on a network, ensure it's a trusted one. There is no built-in authentication.
|
|
181
|
+
|
|
182
|
+
## Tech Stack
|
|
183
|
+
|
|
184
|
+
- **Node.js** — HTTP server (built-in `http`, no Express)
|
|
185
|
+
- **better-sqlite3** — Fast SQLite with FTS5 full-text search
|
|
186
|
+
- **Vanilla HTML/CSS/JS** — No framework, no build step
|
|
187
|
+
- **PWA** — Installable as a home screen app
|
|
188
|
+
|
|
189
|
+
## Privacy
|
|
190
|
+
|
|
191
|
+
All data stays local. AgentActa runs entirely on your machine — no cloud services, no telemetry, no external requests. Your agent history is yours.
|
|
192
|
+
|
|
193
|
+
## Compatibility
|
|
194
|
+
|
|
195
|
+
- ✅ [OpenClaw](https://github.com/openclaw/openclaw)
|
|
196
|
+
- ✅ Claude Code
|
|
197
|
+
- 🔜 Codex CLI
|
|
198
|
+
- 🔜 Custom JSONL formats
|
|
199
|
+
|
|
200
|
+
## Contributing
|
|
201
|
+
|
|
202
|
+
PRs welcome. If you're adding support for a new agent format, add a parser in `indexer.js` and open a PR.
|
|
203
|
+
|
|
204
|
+
## Etymology
|
|
205
|
+
|
|
206
|
+
*Acta* (Latin) — "things done." In ancient Rome, the *acta diurna* were daily public records of official proceedings — senate decisions, military victories, births and deaths — posted in public spaces for all citizens to read.
|
|
207
|
+
|
|
208
|
+
AgentActa is the same idea: a complete, searchable record of everything your AI agent did.
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
MIT
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
Built in Chicago by humans and agents working together.
|
package/config.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const CWD_CONFIG_FILE = path.join(process.cwd(), 'agentacta.config.json');
|
|
6
|
+
const XDG_CONFIG_DIR = path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'agentacta');
|
|
7
|
+
const XDG_CONFIG_FILE = path.join(XDG_CONFIG_DIR, 'config.json');
|
|
8
|
+
|
|
9
|
+
// Resolve config file: CWD first (backward compat), then XDG default
|
|
10
|
+
function resolveConfigFile() {
|
|
11
|
+
if (fs.existsSync(CWD_CONFIG_FILE)) return CWD_CONFIG_FILE;
|
|
12
|
+
return XDG_CONFIG_FILE;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CONFIG_FILE = resolveConfigFile();
|
|
16
|
+
|
|
17
|
+
const DEFAULTS = {
|
|
18
|
+
port: 4003,
|
|
19
|
+
storage: 'reference',
|
|
20
|
+
sessionsPath: null,
|
|
21
|
+
dbPath: './agentacta.db'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function loadConfig() {
|
|
25
|
+
let fileConfig = {};
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
28
|
+
try {
|
|
29
|
+
fileConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error(`Warning: Could not parse ${CONFIG_FILE}:`, err.message);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
// First-run: create default config in XDG location
|
|
35
|
+
const dir = path.dirname(CONFIG_FILE);
|
|
36
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
37
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULTS, null, 2) + '\n');
|
|
38
|
+
console.log(`Created default config: ${CONFIG_FILE}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const config = { ...DEFAULTS, ...fileConfig };
|
|
42
|
+
|
|
43
|
+
// Env var overrides (highest priority)
|
|
44
|
+
if (process.env.PORT) config.port = parseInt(process.env.PORT);
|
|
45
|
+
if (process.env.AGENTACTA_STORAGE) config.storage = process.env.AGENTACTA_STORAGE;
|
|
46
|
+
if (process.env.AGENTACTA_SESSIONS_PATH) config.sessionsPath = process.env.AGENTACTA_SESSIONS_PATH;
|
|
47
|
+
if (process.env.AGENTACTA_DB_PATH) config.dbPath = process.env.AGENTACTA_DB_PATH;
|
|
48
|
+
|
|
49
|
+
// Resolve dbPath relative to cwd
|
|
50
|
+
config.dbPath = path.resolve(config.dbPath);
|
|
51
|
+
|
|
52
|
+
return config;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { loadConfig, CONFIG_FILE };
|
package/db.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const Database = require('better-sqlite3');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { loadConfig } = require('./config');
|
|
4
|
+
|
|
5
|
+
let _config = null;
|
|
6
|
+
function getConfig() {
|
|
7
|
+
if (!_config) _config = loadConfig();
|
|
8
|
+
return _config;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function open(dbPath) {
|
|
12
|
+
const p = dbPath || getConfig().dbPath;
|
|
13
|
+
const db = new Database(p);
|
|
14
|
+
db.pragma('journal_mode = WAL');
|
|
15
|
+
db.pragma('foreign_keys = ON');
|
|
16
|
+
return db;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function init(dbPath) {
|
|
20
|
+
const db = open(dbPath);
|
|
21
|
+
|
|
22
|
+
db.exec(`
|
|
23
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
24
|
+
id TEXT PRIMARY KEY,
|
|
25
|
+
start_time TEXT NOT NULL,
|
|
26
|
+
end_time TEXT,
|
|
27
|
+
message_count INTEGER DEFAULT 0,
|
|
28
|
+
tool_count INTEGER DEFAULT 0,
|
|
29
|
+
model TEXT,
|
|
30
|
+
summary TEXT,
|
|
31
|
+
agent TEXT,
|
|
32
|
+
session_type TEXT,
|
|
33
|
+
total_cost REAL DEFAULT 0,
|
|
34
|
+
total_tokens INTEGER DEFAULT 0,
|
|
35
|
+
input_tokens INTEGER DEFAULT 0,
|
|
36
|
+
output_tokens INTEGER DEFAULT 0,
|
|
37
|
+
cache_read_tokens INTEGER DEFAULT 0,
|
|
38
|
+
cache_write_tokens INTEGER DEFAULT 0,
|
|
39
|
+
initial_prompt TEXT,
|
|
40
|
+
first_message_id TEXT,
|
|
41
|
+
first_message_timestamp TEXT
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
45
|
+
id TEXT PRIMARY KEY,
|
|
46
|
+
session_id TEXT NOT NULL,
|
|
47
|
+
timestamp TEXT NOT NULL,
|
|
48
|
+
type TEXT NOT NULL,
|
|
49
|
+
role TEXT,
|
|
50
|
+
content TEXT,
|
|
51
|
+
tool_name TEXT,
|
|
52
|
+
tool_args TEXT,
|
|
53
|
+
tool_result TEXT,
|
|
54
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_events_tool_name ON events(tool_name);
|
|
61
|
+
|
|
62
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
|
|
63
|
+
content, tool_name, tool_args,
|
|
64
|
+
content='events',
|
|
65
|
+
content_rowid='rowid'
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE TRIGGER IF NOT EXISTS events_ai AFTER INSERT ON events BEGIN
|
|
69
|
+
INSERT INTO events_fts(rowid, content, tool_name, tool_args)
|
|
70
|
+
VALUES (new.rowid, new.content, new.tool_name, new.tool_args);
|
|
71
|
+
END;
|
|
72
|
+
|
|
73
|
+
CREATE TRIGGER IF NOT EXISTS events_ad AFTER DELETE ON events BEGIN
|
|
74
|
+
INSERT INTO events_fts(events_fts, rowid, content, tool_name, tool_args)
|
|
75
|
+
VALUES ('delete', old.rowid, old.content, old.tool_name, old.tool_args);
|
|
76
|
+
END;
|
|
77
|
+
|
|
78
|
+
CREATE TABLE IF NOT EXISTS index_state (
|
|
79
|
+
file_path TEXT PRIMARY KEY,
|
|
80
|
+
last_offset INTEGER DEFAULT 0,
|
|
81
|
+
last_modified TEXT
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
CREATE TABLE IF NOT EXISTS file_activity (
|
|
85
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
86
|
+
session_id TEXT NOT NULL,
|
|
87
|
+
file_path TEXT NOT NULL,
|
|
88
|
+
operation TEXT NOT NULL,
|
|
89
|
+
timestamp TEXT,
|
|
90
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_file_activity_path ON file_activity(file_path);
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_file_activity_session ON file_activity(session_id);
|
|
95
|
+
|
|
96
|
+
CREATE TABLE IF NOT EXISTS archive (
|
|
97
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
98
|
+
session_id TEXT NOT NULL,
|
|
99
|
+
line_number INTEGER NOT NULL,
|
|
100
|
+
raw_json TEXT NOT NULL,
|
|
101
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
CREATE INDEX IF NOT EXISTS idx_archive_session ON archive(session_id);
|
|
105
|
+
`);
|
|
106
|
+
|
|
107
|
+
// Add columns if missing (migration)
|
|
108
|
+
const cols = db.prepare("PRAGMA table_info(sessions)").all().map(c => c.name);
|
|
109
|
+
if (!cols.includes('agent')) db.exec("ALTER TABLE sessions ADD COLUMN agent TEXT");
|
|
110
|
+
if (!cols.includes('session_type')) db.exec("ALTER TABLE sessions ADD COLUMN session_type TEXT");
|
|
111
|
+
if (!cols.includes('total_cost')) db.exec("ALTER TABLE sessions ADD COLUMN total_cost REAL DEFAULT 0");
|
|
112
|
+
if (!cols.includes('total_tokens')) db.exec("ALTER TABLE sessions ADD COLUMN total_tokens INTEGER DEFAULT 0");
|
|
113
|
+
if (!cols.includes('input_tokens')) db.exec("ALTER TABLE sessions ADD COLUMN input_tokens INTEGER DEFAULT 0");
|
|
114
|
+
if (!cols.includes('output_tokens')) db.exec("ALTER TABLE sessions ADD COLUMN output_tokens INTEGER DEFAULT 0");
|
|
115
|
+
if (!cols.includes('cache_read_tokens')) db.exec("ALTER TABLE sessions ADD COLUMN cache_read_tokens INTEGER DEFAULT 0");
|
|
116
|
+
if (!cols.includes('cache_write_tokens')) db.exec("ALTER TABLE sessions ADD COLUMN cache_write_tokens INTEGER DEFAULT 0");
|
|
117
|
+
|
|
118
|
+
db.close();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createStmts(db) {
|
|
122
|
+
return {
|
|
123
|
+
getState: db.prepare('SELECT * FROM index_state WHERE file_path = ?'),
|
|
124
|
+
getSession: db.prepare('SELECT id FROM sessions WHERE id = ?'),
|
|
125
|
+
deleteEvents: db.prepare('DELETE FROM events WHERE session_id = ?'),
|
|
126
|
+
deleteSession: db.prepare('DELETE FROM sessions WHERE id = ?'),
|
|
127
|
+
deleteFileActivity: db.prepare('DELETE FROM file_activity WHERE session_id = ?'),
|
|
128
|
+
insertEvent: db.prepare(`INSERT OR REPLACE INTO events (id, session_id, timestamp, type, role, content, tool_name, tool_args, tool_result) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
|
129
|
+
upsertSession: db.prepare(`INSERT OR REPLACE INTO sessions (id, start_time, end_time, message_count, tool_count, model, summary, agent, session_type, total_cost, total_tokens, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, initial_prompt, first_message_id, first_message_timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
|
130
|
+
upsertState: db.prepare(`INSERT OR REPLACE INTO index_state (file_path, last_offset, last_modified) VALUES (?, ?, ?)`),
|
|
131
|
+
insertFileActivity: db.prepare(`INSERT INTO file_activity (session_id, file_path, operation, timestamp) VALUES (?, ?, ?, ?)`),
|
|
132
|
+
deleteArchive: db.prepare('DELETE FROM archive WHERE session_id = ?'),
|
|
133
|
+
insertArchive: db.prepare('INSERT INTO archive (session_id, line_number, raw_json) VALUES (?, ?, ?)')
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = { open, init, createStmts };
|