@thehammer/danx-session-telemetry 0.1.1 → 0.1.3

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.
@@ -89,6 +89,28 @@ export interface SessionLogWatcherOptions {
89
89
  * binds `<repo>/claude-projects/` at `/home/danxbot/.claude/projects/` and
90
90
  * relies on the same encoding for the bound subdir name. Keep the encoding
91
91
  * logic centralized here so both runtimes stay in lockstep.
92
+ *
93
+ * DX-3069 — Windows host-mode dispatches (this dev machine included, see
94
+ * `.claude/rules/agent-dispatch.md` "Host" runtime) pass an ALREADY-ABSOLUTE
95
+ * Windows cwd (`C:\Users\...`), which never starts with `/`. The prior
96
+ * `cwd.startsWith("/") ? cwd : "/" + cwd` unconditionally prepended `/`,
97
+ * producing a malformed path (`/C:\Users\...`) that `realpathSync` cannot
98
+ * resolve (ENOENT — Windows reads the leading `/C:` as its own root segment),
99
+ * so the code fell into the catch and kept that malformed string. The old
100
+ * regex (`/[/._]/g`) never touched `\` or `:`, so every backslash and the
101
+ * drive-letter colon survived verbatim into the "encoded" dir name, and
102
+ * `join(homedir(), ".claude", "projects", encoded)` then produced a NESTED,
103
+ * DOUBLED path — `C:\Users\...\.claude\projects\-C:\Users\...` — a directory
104
+ * Claude Code never writes to, so every host-mode watcher on Windows silently
105
+ * never found its own transcript. Verified empirically against a real Claude
106
+ * Code install on this machine: `C:\Users\newms\projects\danxbot` encodes on
107
+ * disk to `C--Users-newms-projects-danxbot` (`ls ~/.claude/projects`) — no
108
+ * leading dash, `:` and each `\` both become `-`, exactly like `/` and `.` do
109
+ * for a POSIX cwd. `isAbsolute` (platform-native — win32 on Windows, posix
110
+ * elsewhere) replaces the POSIX-only `startsWith("/")` check so an
111
+ * already-absolute Windows path is never re-prefixed, and the replacement
112
+ * regex now also covers `\` and `:` so no separator survives into the
113
+ * encoded name on either platform.
92
114
  */
93
115
  export declare function encodeClaudeProjectsCwd(cwd: string): string;
94
116
  /**
@@ -23,7 +23,7 @@
23
23
  import { existsSync, realpathSync } from "node:fs";
24
24
  import { open, readFile, readdir, stat } from "node:fs/promises";
25
25
  import { homedir } from "node:os";
26
- import { basename, dirname, join } from "node:path";
26
+ import { basename, dirname, isAbsolute, join } from "node:path";
27
27
  import { createLogger } from "./internal-logger.js";
28
28
  import { buildAssistantSummary, buildToolResultSummary, } from "./tool-summary.js";
29
29
  const log = createLogger("session-log-watcher");
@@ -68,9 +68,31 @@ export const DISPATCH_TAG_PREFIX = "<!-- danxbot-dispatch:";
68
68
  * binds `<repo>/claude-projects/` at `/home/danxbot/.claude/projects/` and
69
69
  * relies on the same encoding for the bound subdir name. Keep the encoding
70
70
  * logic centralized here so both runtimes stay in lockstep.
71
+ *
72
+ * DX-3069 — Windows host-mode dispatches (this dev machine included, see
73
+ * `.claude/rules/agent-dispatch.md` "Host" runtime) pass an ALREADY-ABSOLUTE
74
+ * Windows cwd (`C:\Users\...`), which never starts with `/`. The prior
75
+ * `cwd.startsWith("/") ? cwd : "/" + cwd` unconditionally prepended `/`,
76
+ * producing a malformed path (`/C:\Users\...`) that `realpathSync` cannot
77
+ * resolve (ENOENT — Windows reads the leading `/C:` as its own root segment),
78
+ * so the code fell into the catch and kept that malformed string. The old
79
+ * regex (`/[/._]/g`) never touched `\` or `:`, so every backslash and the
80
+ * drive-letter colon survived verbatim into the "encoded" dir name, and
81
+ * `join(homedir(), ".claude", "projects", encoded)` then produced a NESTED,
82
+ * DOUBLED path — `C:\Users\...\.claude\projects\-C:\Users\...` — a directory
83
+ * Claude Code never writes to, so every host-mode watcher on Windows silently
84
+ * never found its own transcript. Verified empirically against a real Claude
85
+ * Code install on this machine: `C:\Users\newms\projects\danxbot` encodes on
86
+ * disk to `C--Users-newms-projects-danxbot` (`ls ~/.claude/projects`) — no
87
+ * leading dash, `:` and each `\` both become `-`, exactly like `/` and `.` do
88
+ * for a POSIX cwd. `isAbsolute` (platform-native — win32 on Windows, posix
89
+ * elsewhere) replaces the POSIX-only `startsWith("/")` check so an
90
+ * already-absolute Windows path is never re-prefixed, and the replacement
91
+ * regex now also covers `\` and `:` so no separator survives into the
92
+ * encoded name on either platform.
71
93
  */
72
94
  export function encodeClaudeProjectsCwd(cwd) {
73
- const normalized = cwd.startsWith("/") ? cwd : `/${cwd}`;
95
+ const normalized = isAbsolute(cwd) ? cwd : `/${cwd}`;
74
96
  let resolved;
75
97
  try {
76
98
  resolved = realpathSync(normalized);
@@ -80,12 +102,13 @@ export function encodeClaudeProjectsCwd(cwd) {
80
102
  resolved = normalized;
81
103
  }
82
104
  // Claude Code encodes its cwd into ~/.claude/projects/<dir> by replacing
83
- // EVERY non-alphanumeric separator — `/`, `.`, AND `_` — with `-`. The `_`
84
- // matters: the clean-room key (`cleanRoomKey`, DX-1511)
85
- // joins its components with `__`, so Claude writes the dir as `--` on disk.
86
- // Omitting `_` here made the watcher wait on a `__` path Claude never
87
- // creates → "session file not found after 180s" on every clean-room dispatch.
88
- return resolved.replace(/[/._]/g, "-");
105
+ // EVERY non-alphanumeric separator with `-`: `/`, `.`, and `_` on every
106
+ // platform, plus `\` and the drive-letter `:` on Windows. The `_` matters:
107
+ // the clean-room key (`cleanRoomKey`, DX-1511) joins its components with
108
+ // `__`, so Claude writes the dir as `--` on disk. Omitting `_` here made
109
+ // the watcher wait on a `__` path Claude never creates → "session file not
110
+ // found after 180s" on every clean-room dispatch.
111
+ return resolved.replace(/[/\\:._]/g, "-");
89
112
  }
90
113
  /**
91
114
  * Derives the Claude Code session directory from a working directory path.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-session-telemetry",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Shared Claude Code transcript collector (DX-2962) — incremental JSONL tailing for the danxbot worker and the danx-dashboard-mcp desktop bridge, so both run identical collector code.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,6 +37,6 @@
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.0.0",
39
39
  "typescript": "^5.7.0",
40
- "vitest": "^4.1.5"
40
+ "vitest": "^4.0.18"
41
41
  }
42
42
  }