agentacta 2026.3.6 → 2026.3.7
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 +4 -2
- package/config.js +20 -2
- package/indexer.js +33 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,18 +118,20 @@ On first run, AgentActa creates:
|
|
|
118
118
|
- `~/.config/agentacta/config.json`
|
|
119
119
|
- or `agentacta.config.json` in current directory (if present)
|
|
120
120
|
|
|
121
|
-
Default config:
|
|
121
|
+
Default config (auto-generated on first run — session directories are detected automatically):
|
|
122
122
|
|
|
123
123
|
```json
|
|
124
124
|
{
|
|
125
125
|
"port": 4003,
|
|
126
126
|
"storage": "reference",
|
|
127
|
-
"sessionsPath":
|
|
127
|
+
"sessionsPath": ["~/.claude/projects", "~/.openclaw/sessions"],
|
|
128
128
|
"dbPath": "./agentacta.db",
|
|
129
129
|
"projectAliases": {}
|
|
130
130
|
}
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
`sessionsPath` accepts a string, a colon-delimited string, or a JSON array.
|
|
134
|
+
|
|
133
135
|
### Storage modes
|
|
134
136
|
|
|
135
137
|
- `reference` (default): index parsed events in SQLite, keep source JSONL on disk. Lightweight.
|
package/config.js
CHANGED
|
@@ -14,6 +14,12 @@ function resolveConfigFile() {
|
|
|
14
14
|
|
|
15
15
|
const CONFIG_FILE = resolveConfigFile();
|
|
16
16
|
|
|
17
|
+
const KNOWN_SESSION_DIRS = [
|
|
18
|
+
path.join(os.homedir(), '.claude', 'projects'), // Claude Code
|
|
19
|
+
path.join(os.homedir(), '.codex', 'sessions'), // Codex CLI
|
|
20
|
+
path.join(os.homedir(), '.openclaw', 'sessions'), // OpenClaw
|
|
21
|
+
];
|
|
22
|
+
|
|
17
23
|
const DEFAULTS = {
|
|
18
24
|
port: 4003,
|
|
19
25
|
storage: 'reference',
|
|
@@ -22,6 +28,11 @@ const DEFAULTS = {
|
|
|
22
28
|
projectAliases: {}
|
|
23
29
|
};
|
|
24
30
|
|
|
31
|
+
function detectSessionDirs() {
|
|
32
|
+
const found = KNOWN_SESSION_DIRS.filter(d => fs.existsSync(d));
|
|
33
|
+
return found.length > 0 ? found : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
function loadConfig() {
|
|
26
37
|
let fileConfig = {};
|
|
27
38
|
|
|
@@ -32,11 +43,18 @@ function loadConfig() {
|
|
|
32
43
|
console.error(`Warning: Could not parse ${CONFIG_FILE}:`, err.message);
|
|
33
44
|
}
|
|
34
45
|
} else {
|
|
35
|
-
// First-run: create default config
|
|
46
|
+
// First-run: create default config with auto-detected session dirs
|
|
47
|
+
const detected = detectSessionDirs();
|
|
48
|
+
const firstRunDefaults = { ...DEFAULTS, sessionsPath: detected };
|
|
36
49
|
const dir = path.dirname(CONFIG_FILE);
|
|
37
50
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
38
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(
|
|
51
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(firstRunDefaults, null, 2) + '\n');
|
|
52
|
+
// Apply to in-memory config so this run also benefits
|
|
53
|
+
fileConfig = firstRunDefaults;
|
|
39
54
|
console.log(`Created default config: ${CONFIG_FILE}`);
|
|
55
|
+
if (detected) {
|
|
56
|
+
console.log(`Auto-detected session directories:\n${detected.map(d => ` - ${d}`).join('\n')}`);
|
|
57
|
+
}
|
|
40
58
|
}
|
|
41
59
|
|
|
42
60
|
const config = { ...DEFAULTS, ...fileConfig };
|
package/indexer.js
CHANGED
|
@@ -29,16 +29,36 @@ function discoverSessionDirs(config) {
|
|
|
29
29
|
const dirs = [];
|
|
30
30
|
const home = process.env.HOME;
|
|
31
31
|
|
|
32
|
+
// Expand a single path into session dirs, handling Claude Code's per-project structure
|
|
33
|
+
function expandPath(p) {
|
|
34
|
+
if (!fs.existsSync(p)) return;
|
|
35
|
+
const stat = fs.statSync(p);
|
|
36
|
+
if (!stat.isDirectory()) return;
|
|
37
|
+
// Claude Code: ~/.claude/projects contains per-project subdirs with JSONL files
|
|
38
|
+
if (p.replace(/\/$/, '').endsWith('/.claude/projects')) {
|
|
39
|
+
for (const proj of fs.readdirSync(p)) {
|
|
40
|
+
const projDir = path.join(p, proj);
|
|
41
|
+
if (fs.statSync(projDir).isDirectory()) {
|
|
42
|
+
const hasJsonl = fs.readdirSync(projDir).some(f => f.endsWith('.jsonl'));
|
|
43
|
+
if (hasJsonl) dirs.push({ path: projDir, agent: 'claude-code' });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
dirs.push({ path: p, agent: path.basename(path.dirname(p)) });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
// Config sessionsPath or env var override
|
|
33
52
|
const sessionsOverride = process.env.AGENTACTA_SESSIONS_PATH || (config && config.sessionsPath);
|
|
34
53
|
if (sessionsOverride) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
const overridePaths = Array.isArray(sessionsOverride)
|
|
55
|
+
? sessionsOverride
|
|
56
|
+
: sessionsOverride.split(':');
|
|
57
|
+
overridePaths.forEach(expandPath);
|
|
38
58
|
if (dirs.length) return dirs;
|
|
39
59
|
}
|
|
40
60
|
|
|
41
|
-
//
|
|
61
|
+
// Auto-discover: ~/.openclaw/agents/*/sessions/
|
|
42
62
|
const oclawAgents = path.join(home, '.openclaw/agents');
|
|
43
63
|
if (fs.existsSync(oclawAgents)) {
|
|
44
64
|
for (const agent of fs.readdirSync(oclawAgents)) {
|
|
@@ -49,23 +69,8 @@ function discoverSessionDirs(config) {
|
|
|
49
69
|
}
|
|
50
70
|
}
|
|
51
71
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
if (fs.existsSync(claudeProjects)) {
|
|
55
|
-
for (const proj of fs.readdirSync(claudeProjects)) {
|
|
56
|
-
const projDir = path.join(claudeProjects, proj);
|
|
57
|
-
// Claude Code: JSONL files directly in project dir
|
|
58
|
-
if (fs.existsSync(projDir) && fs.statSync(projDir).isDirectory()) {
|
|
59
|
-
const hasJsonl = fs.readdirSync(projDir).some(f => f.endsWith('.jsonl'));
|
|
60
|
-
if (hasJsonl) dirs.push({ path: projDir, agent: 'claude-code' });
|
|
61
|
-
}
|
|
62
|
-
// Also check sessions/ subdirectory (future-proofing)
|
|
63
|
-
const sp = path.join(projDir, 'sessions');
|
|
64
|
-
if (fs.existsSync(sp) && fs.statSync(sp).isDirectory()) {
|
|
65
|
-
dirs.push({ path: sp, agent: 'claude-code' });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
72
|
+
// Auto-discover: ~/.claude/projects/
|
|
73
|
+
expandPath(path.join(home, '.claude/projects'));
|
|
69
74
|
|
|
70
75
|
// Scan ~/.codex/sessions recursively (Codex CLI stores nested YYYY/MM/DD/*.jsonl)
|
|
71
76
|
const codexSessions = path.join(home, '.codex/sessions');
|
|
@@ -289,11 +294,16 @@ function indexFile(db, filePath, agentName, stmts, archiveMode, config) {
|
|
|
289
294
|
if (firstLine.agent) agent = firstLine.agent;
|
|
290
295
|
if (firstLine.sessionType) sessionType = firstLine.sessionType;
|
|
291
296
|
if (sessionId.includes('subagent')) sessionType = 'subagent';
|
|
292
|
-
} else if (firstLine.type === 'user' || firstLine.type === 'assistant' || firstLine.type === 'file-history-snapshot') {
|
|
293
|
-
// Claude Code format — no session header, extract from first message line
|
|
297
|
+
} else if (firstLine.type === 'user' || firstLine.type === 'assistant' || firstLine.type === 'file-history-snapshot' || firstLine.type === 'queue-operation') {
|
|
298
|
+
// Claude Code format — no session header, extract from first message or queue-operation line
|
|
294
299
|
isClaudeCode = true;
|
|
295
300
|
for (const line of lines) {
|
|
296
301
|
let obj; try { obj = JSON.parse(line); } catch { continue; }
|
|
302
|
+
if (obj.sessionId && obj.timestamp) {
|
|
303
|
+
sessionId = obj.sessionId;
|
|
304
|
+
sessionStart = obj.timestamp;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
297
307
|
if ((obj.type === 'user' || obj.type === 'assistant') && obj.sessionId) {
|
|
298
308
|
sessionId = obj.sessionId;
|
|
299
309
|
sessionStart = obj.timestamp;
|