ai-lens 0.8.66 → 0.8.67

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/.commithash CHANGED
@@ -1 +1 @@
1
- 695b8c8
1
+ cf6dbc7
package/CHANGELOG.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  History of changes to the `ai-lens` CLI package on npm. New entries go on top. Format: `## X.Y.Z — YYYY-MM-DD`, followed by user-facing bullets.
4
4
 
5
+ ## 0.8.67 — 2026-05-26
6
+ - fix: sessions launched from a subdirectory of a repo (e.g. `cd scripts/asr-worker && claude`) now attribute to the repo root instead of the subdirectory. Previously the dashboard showed deep subfolders as if they were the project — a session that ran 74 events inside `meetings-lens/scripts/asr-worker` and 7 at the repo root was attributed to `asr-worker`. SessionStart cwd is now walked up to the nearest `.git` like file-path refinement already did.
7
+
5
8
  ## 0.8.66 — 2026-05-26
6
9
  - chore: republish — the npm registry was stuck on 0.8.63 while two patch releases (0.8.64 Codex `apply_patch` multi-file fix and 0.8.65 raw-field preservation on large events) were tagged but never published. Anyone running `npx -y ai-lens init --yes` will now actually receive those fixes.
7
10
  - chore: `CHANGELOG.md` now ships inside the published npm package, so it's visible on the npm registry page alongside the README.
package/client/capture.js CHANGED
@@ -547,37 +547,47 @@ function resolveWorktreeToMainRepo(dir) {
547
547
  }
548
548
 
549
549
  /**
550
- * Walk up from a path to find the nearest .git entry.
550
+ * Walk up from a directory to find the nearest .git entry.
551
551
  * Returns the repo root (parent of a `.git` directory, or the main repo root
552
- * when `.git` is a worktree-pointer file) or null.
552
+ * when `.git` is a worktree-pointer file) or null when no `.git` is found.
553
553
  */
554
- function findGitRoot(filePath) {
555
- let dir = dirname(filePath);
556
- while (dir && dir !== '/' && dir.length > 1) {
554
+ function findGitRootFromDir(dir) {
555
+ let cur = dir;
556
+ while (cur && cur !== '/' && cur.length > 1) {
557
557
  try {
558
- if (existsSync(join(dir, '.git'))) return resolveWorktreeToMainRepo(dir);
558
+ if (existsSync(join(cur, '.git'))) return resolveWorktreeToMainRepo(cur);
559
559
  } catch {}
560
- const parent = dirname(dir);
561
- if (parent === dir) break;
562
- dir = parent;
560
+ const parent = dirname(cur);
561
+ if (parent === cur) break;
562
+ cur = parent;
563
563
  }
564
564
  return null;
565
565
  }
566
566
 
567
567
  /**
568
- * If `dir` is a git worktree checkout, return the main repo root; otherwise
569
- * return `dir` unchanged. Used at session intake where we have a launcher cwd
570
- * (SessionStart / workspace_roots) and want to avoid attributing the session
571
- * to a worktree branch name.
568
+ * Walk up from a file path to find the nearest .git entry.
569
+ * Returns the repo root or null when no `.git` is found.
570
+ */
571
+ function findGitRoot(filePath) {
572
+ return findGitRootFromDir(dirname(filePath));
573
+ }
574
+
575
+ /**
576
+ * Resolve a launcher cwd (SessionStart / workspace_roots) to its repo root.
577
+ *
578
+ * Two cases are handled:
579
+ * 1. `dir` is a worktree checkout (`.git` is a pointer file) — roll up to the
580
+ * main repo so per-project dashboards don't fragment per worktree branch.
581
+ * 2. `dir` is a subdirectory of a repo (e.g. user did `cd scripts/asr-worker`
582
+ * before launching Claude Code) — walk up to the nearest `.git`, otherwise
583
+ * a deep subfolder would dominate the session's representative path and
584
+ * hide that the work belongs to the parent repo.
585
+ *
586
+ * Returns `dir` unchanged when no `.git` is found anywhere up the tree.
572
587
  */
573
588
  function canonicalizeProjectPath(dir) {
574
589
  if (!dir || typeof dir !== 'string') return dir;
575
- try {
576
- if (existsSync(join(dir, '.git'))) {
577
- return resolveWorktreeToMainRepo(dir);
578
- }
579
- } catch {}
580
- return dir;
590
+ return findGitRootFromDir(dir) || dir;
581
591
  }
582
592
 
583
593
  /**
package/client/redact.js CHANGED
@@ -90,8 +90,12 @@ const PATTERNS = [
90
90
  // Meilisearch master/API key (mc_ + 32+ hex chars)
91
91
  { type: 'MEILISEARCH_KEY', re: /\bmc_[0-9a-f]{32,}\b/g },
92
92
 
93
- // Connection string password (://user:password@host) — redacts password only
94
- { type: 'CONNECTION_STRING', re: /:\/\/([^:@\s]+):([^@\s]{3,})@/g, replacer: (m, user, _pw) => `://${user}:[REDACTED:CONNECTION_STRING]@` },
93
+ // Connection string password (://user:password@host) — redacts password only.
94
+ // Tightened: exclude JSON structural chars from the user/password classes so
95
+ // a stringified JSON payload (e.g. MCP `tool_response` kept as a single
96
+ // string leaf) can't be matched across field boundaries. See the same note
97
+ // in server/utils/redact.js.
98
+ { type: 'CONNECTION_STRING', re: /:\/\/([^:@\s"',\[\]{}']+):([^@\s"',\[\]{}']{3,})@/g, replacer: (m, user, _pw) => `://${user}:[REDACTED:CONNECTION_STRING]@` },
95
99
 
96
100
  // MySQL/mysqldump CLI -p<password> syntax (mysql -u user -pSECRET dbname)
97
101
  { type: 'MYSQL_PASSWORD', re: /(\bmysql\w*\b[^\n]*\s-p)(\S{8,})/g, replacer: (m, prefix, _pw) => `${prefix}[REDACTED:MYSQL_PASSWORD]` },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-lens",
3
- "version": "0.8.66",
3
+ "version": "0.8.67",
4
4
  "type": "module",
5
5
  "description": "Centralized session analytics for AI coding tools",
6
6
  "bin": {