@vanillagreen/pi-claude-bridge 1.6.2 → 1.9.0

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/src/debug.ts ADDED
@@ -0,0 +1,80 @@
1
+ import { appendFileSync, chmodSync, mkdirSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { piUserDir } from "./config.js";
4
+
5
+ // --- Debug logging ---
6
+ // CLAUDE_BRIDGE_DEBUG=1 enables debug logging to <piUserDir>/claude-bridge.log
7
+ // (~/.pi/agent/claude-bridge.log unless PI_CODING_AGENT_DIR points elsewhere).
8
+
9
+ export const DEBUG = process.env.CLAUDE_BRIDGE_DEBUG === "1";
10
+ export const DEBUG_LOG_PATH = process.env.CLAUDE_BRIDGE_DEBUG_PATH || join(piUserDir(), "claude-bridge.log");
11
+
12
+ export function diagLogPath(): string {
13
+ return process.env.CLAUDE_BRIDGE_DIAG_PATH || join(piUserDir(), "claude-bridge-diag.log");
14
+ }
15
+
16
+ // Ensure log directories exist when debug is enabled
17
+ if (DEBUG) {
18
+ try {
19
+ mkdirSync(dirname(DEBUG_LOG_PATH), { recursive: true });
20
+ mkdirSync(dirname(diagLogPath()), { recursive: true, mode: 0o700 });
21
+ } catch {
22
+ // If directory creation fails, debug functions will throw on first use
23
+ }
24
+ }
25
+
26
+ // Unique per module evaluation — confirms whether subagents share module state
27
+ export const moduleInstanceId = Math.random().toString(36).slice(2, 8);
28
+
29
+ export function debug(...args: unknown[]) {
30
+ if (!DEBUG) return;
31
+ const ts = new Date().toISOString();
32
+ const fmt = (a: unknown): string => {
33
+ if (typeof a === "string") return a;
34
+ if (a instanceof Error) return `${a.name}: ${a.message}${a.stack ? "\n" + a.stack : ""}`;
35
+ return JSON.stringify(a);
36
+ };
37
+ const msg = args.map(fmt).join(" ");
38
+ try { appendFileSync(DEBUG_LOG_PATH, `[${ts}] [${moduleInstanceId}] ${msg}\n`); } catch { /* debug is best effort */ }
39
+ }
40
+
41
+ // Per-query CLI debug capture. When CLAUDE_BRIDGE_DEBUG=1, ask the Claude Code
42
+ // CLI subprocess to write its own debug log to a file we choose, and also
43
+ // forward its stderr into our debug stream. Drops straight into the real SDK's
44
+ // Options — see @anthropic-ai/claude-agent-sdk sdk.d.ts:1245 (debug, debugFile,
45
+ // stderr). Without this, CC's internal view of the world is invisible to us
46
+ // and "No conversation found" / empty-error reports are unactionable.
47
+ let nextCliDebugSeq = 1;
48
+ export function makeCliDebugOptions(tag: string): { debug?: boolean; debugFile?: string; stderr?: (data: string) => void } {
49
+ if (!DEBUG) return {};
50
+ const seq = nextCliDebugSeq++;
51
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
52
+ const logDir = join(dirname(DEBUG_LOG_PATH), "cc-cli-logs");
53
+ try { mkdirSync(logDir, { recursive: true }); } catch { /* ignore */ }
54
+ const debugFile = join(logDir, `${ts}-${tag}-${seq}.log`);
55
+ debug(`cli-debug: ${tag} #${seq} → ${debugFile}`);
56
+ return {
57
+ debug: true,
58
+ debugFile,
59
+ stderr: (data: string) => {
60
+ for (const line of data.split(/\r?\n/)) {
61
+ if (line) debug(`[cli-stderr ${tag}#${seq}] ${line}`);
62
+ }
63
+ },
64
+ };
65
+ }
66
+
67
+ /** Unconditional diagnostic dump — for "should never happen" paths */
68
+ export function diagDump(label: string, data: Record<string, unknown>) {
69
+ try {
70
+ const ts = new Date().toISOString();
71
+ const entry = { ts, moduleInstanceId, label, ...data };
72
+ const path = diagLogPath();
73
+ try { mkdirSync(dirname(path), { recursive: true, mode: 0o700 }); } catch { /* best effort */ }
74
+ appendFileSync(path, JSON.stringify(entry) + "\n", { mode: 0o600 });
75
+ try { chmodSync(path, 0o600); } catch { /* best effort */ }
76
+ debug(`DIAG: ${label} (see ${path})`);
77
+ } catch (error) {
78
+ debug(`DIAG FAILED: ${label}`, error);
79
+ }
80
+ }