metame-cli 1.3.4 → 1.3.6

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/index.js CHANGED
@@ -571,6 +571,7 @@ if (isDaemon) {
571
571
  const DAEMON_SCRIPT = path.join(METAME_DIR, 'daemon.js');
572
572
 
573
573
  if (subCmd === 'init') {
574
+ (async () => {
574
575
  const readline = require('readline');
575
576
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
576
577
  const ask = (q) => new Promise(r => rl.question(q, r));
@@ -694,6 +695,8 @@ if (isDaemon) {
694
695
 
695
696
  rl.close();
696
697
  process.exit(0);
698
+ })();
699
+ return; // Prevent further execution while async runs
697
700
  }
698
701
 
699
702
  if (subCmd === 'install-launchd') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metame-cli",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "The Cognitive Profile Layer for Claude Code. Knows how you think, not just what you said.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -47,3 +47,10 @@ budget:
47
47
  daemon:
48
48
  log_max_size: 1048576
49
49
  heartbeat_check_interval: 60
50
+ # Pre-authorize tools for mobile sessions (no permission prompts)
51
+ # Examples: "Bash(git:*)" "Bash(npm:*)" "Edit" "Write" "WebFetch" "WebSearch"
52
+ session_allowed_tools:
53
+ - "WebFetch"
54
+ - "WebSearch"
55
+ - "Bash(git:*)"
56
+ - "Bash(npm:*)"
package/scripts/daemon.js CHANGED
@@ -947,17 +947,64 @@ function listRecentSessions(limit, cwd) {
947
947
  try {
948
948
  if (!fs.existsSync(CLAUDE_PROJECTS_DIR)) return [];
949
949
  const projects = fs.readdirSync(CLAUDE_PROJECTS_DIR);
950
- let all = [];
950
+
951
+ // Build a map: sessionId -> entry (for deduplication)
952
+ const sessionMap = new Map();
953
+ // Cache: projDirName -> real projectPath (from index)
954
+ const projPathCache = new Map();
955
+
951
956
  for (const proj of projects) {
952
- const indexFile = path.join(CLAUDE_PROJECTS_DIR, proj, 'sessions-index.json');
957
+ const projDir = path.join(CLAUDE_PROJECTS_DIR, proj);
958
+
959
+ // 1. Read from sessions-index.json (Claude's native index)
960
+ const indexFile = path.join(projDir, 'sessions-index.json');
961
+ try {
962
+ if (fs.existsSync(indexFile)) {
963
+ const data = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
964
+ if (data.entries && data.entries.length > 0) {
965
+ // Cache the real projectPath from any indexed session
966
+ const realPath = data.entries[0].projectPath;
967
+ if (realPath) projPathCache.set(proj, realPath);
968
+
969
+ for (const entry of data.entries) {
970
+ if (entry.messageCount >= 1) {
971
+ sessionMap.set(entry.sessionId, entry);
972
+ }
973
+ }
974
+ }
975
+ }
976
+ } catch { /* skip */ }
977
+
978
+ // 2. Direct scan of .jsonl files (hot reload: catches sessions not yet indexed)
953
979
  try {
954
- if (!fs.existsSync(indexFile)) continue;
955
- const data = JSON.parse(fs.readFileSync(indexFile, 'utf8'));
956
- if (data.entries) all = all.concat(data.entries);
980
+ const files = fs.readdirSync(projDir).filter(f => f.endsWith('.jsonl'));
981
+ for (const file of files) {
982
+ const sessionId = file.replace('.jsonl', '');
983
+ const filePath = path.join(projDir, file);
984
+ const stat = fs.statSync(filePath);
985
+ const fileMtime = stat.mtimeMs;
986
+
987
+ // Only add if not already in map, or if file is newer
988
+ const existing = sessionMap.get(sessionId);
989
+ if (!existing || fileMtime > (existing.fileMtime || 0)) {
990
+ // Use cached real projectPath, or fall back to lossy decode
991
+ const projectPath = projPathCache.get(proj) || proj.slice(1).replace(/-/g, '/');
992
+ sessionMap.set(sessionId, {
993
+ sessionId,
994
+ projectPath,
995
+ fileMtime,
996
+ modified: new Date(fileMtime).toISOString(),
997
+ messageCount: 1, // Assume at least 1 if file exists
998
+ ...(existing || {}), // Preserve existing metadata like customTitle
999
+ fileMtime, // Override with real mtime
1000
+ });
1001
+ }
1002
+ }
957
1003
  } catch { /* skip */ }
958
1004
  }
959
- // Filter: must have at least 1 message
960
- all = all.filter(s => s.messageCount >= 1);
1005
+
1006
+ let all = Array.from(sessionMap.values());
1007
+
961
1008
  // Filter by cwd if provided
962
1009
  if (cwd) {
963
1010
  const matched = all.filter(s => s.projectPath === cwd);