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 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": null,
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 in XDG location
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(DEFAULTS, null, 2) + '\n');
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
- for (const p of sessionsOverride.split(':')) {
36
- if (fs.existsSync(p)) dirs.push({ path: p, agent: path.basename(path.dirname(p)) });
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
- // Scan ~/.openclaw/agents/*/sessions/
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
- // Scan ~/.claude/projects/*/ (Claude Code stores JSONL directly in project dirs)
53
- const claudeProjects = path.join(home, '.claude/projects');
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentacta",
3
- "version": "2026.3.6",
3
+ "version": "2026.3.7",
4
4
  "description": "Audit trail and search engine for AI agent sessions",
5
5
  "main": "index.js",
6
6
  "bin": {