@mrclrchtr/supi-debug 0.1.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/README.md +57 -0
- package/node_modules/@mrclrchtr/supi-core/README.md +90 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +30 -0
- package/node_modules/@mrclrchtr/supi-core/src/config-settings.ts +76 -0
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +186 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-messages.ts +119 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-provider-registry.ts +36 -0
- package/node_modules/@mrclrchtr/supi-core/src/context-tag.ts +31 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +255 -0
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +83 -0
- package/node_modules/@mrclrchtr/supi-core/src/project-roots.ts +170 -0
- package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +54 -0
- package/node_modules/@mrclrchtr/supi-core/src/session-utils.ts +29 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-command.ts +15 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-registry.ts +41 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +226 -0
- package/node_modules/@mrclrchtr/supi-core/src/terminal.ts +60 -0
- package/package.json +43 -0
- package/src/debug.ts +351 -0
- package/src/format.ts +89 -0
- package/src/index.ts +1 -0
- package/src/renderer.ts +104 -0
package/src/format.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function formatPrimitive(value: unknown): string[] {
|
|
2
|
+
if (value === null) return ["null"];
|
|
3
|
+
if (typeof value === "boolean") return [String(value)];
|
|
4
|
+
if (typeof value === "number") return [String(value)];
|
|
5
|
+
if (typeof value === "bigint") return [`${value}n`];
|
|
6
|
+
if (typeof value === "string") {
|
|
7
|
+
if (value.includes("\n")) {
|
|
8
|
+
return value.split("\n");
|
|
9
|
+
}
|
|
10
|
+
return [JSON.stringify(value)];
|
|
11
|
+
}
|
|
12
|
+
return [String(value)];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatArray(value: unknown[], seen: WeakSet<object>): string[] {
|
|
16
|
+
if (value.length === 0) return ["[]"];
|
|
17
|
+
const lines: string[] = ["["];
|
|
18
|
+
for (let i = 0; i < value.length; i++) {
|
|
19
|
+
const itemLines = formatDataLinesRecursive(value[i], seen);
|
|
20
|
+
const indented = itemLines.map((line) => ` ${line}`);
|
|
21
|
+
if (i < value.length - 1) {
|
|
22
|
+
indented[indented.length - 1] += ",";
|
|
23
|
+
}
|
|
24
|
+
lines.push(...indented);
|
|
25
|
+
}
|
|
26
|
+
lines.push("]");
|
|
27
|
+
return lines;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function formatObjectEntry(
|
|
31
|
+
key: string,
|
|
32
|
+
value: unknown,
|
|
33
|
+
seen: WeakSet<object>,
|
|
34
|
+
isLast: boolean,
|
|
35
|
+
): string[] {
|
|
36
|
+
const keyStr = JSON.stringify(key);
|
|
37
|
+
const valueLines = formatDataLinesRecursive(value, seen);
|
|
38
|
+
const lines: string[] = [];
|
|
39
|
+
|
|
40
|
+
if (typeof value === "string" && value.includes("\n")) {
|
|
41
|
+
lines.push(` ${keyStr}:`);
|
|
42
|
+
for (const line of valueLines) {
|
|
43
|
+
lines.push(` ${line}`);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
valueLines[0] = ` ${keyStr}: ${valueLines[0]}`;
|
|
47
|
+
for (let j = 1; j < valueLines.length; j++) {
|
|
48
|
+
valueLines[j] = ` ${valueLines[j]}`;
|
|
49
|
+
}
|
|
50
|
+
lines.push(...valueLines);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!isLast) {
|
|
54
|
+
lines[lines.length - 1] += ",";
|
|
55
|
+
}
|
|
56
|
+
return lines;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function formatObject(value: Record<string, unknown>, seen: WeakSet<object>): string[] {
|
|
60
|
+
const entries = Object.entries(value);
|
|
61
|
+
if (entries.length === 0) return ["{}"];
|
|
62
|
+
const lines: string[] = ["{"];
|
|
63
|
+
for (let i = 0; i < entries.length; i++) {
|
|
64
|
+
const [k, v] = entries[i];
|
|
65
|
+
lines.push(...formatObjectEntry(k, v, seen, i === entries.length - 1));
|
|
66
|
+
}
|
|
67
|
+
lines.push("}");
|
|
68
|
+
return lines;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function formatDataLinesRecursive(value: unknown, seen: WeakSet<object>): string[] {
|
|
72
|
+
if (value === undefined) return [];
|
|
73
|
+
if (value === null || typeof value !== "object") {
|
|
74
|
+
return formatPrimitive(value);
|
|
75
|
+
}
|
|
76
|
+
if (seen.has(value)) {
|
|
77
|
+
return ['"[Circular]"'];
|
|
78
|
+
}
|
|
79
|
+
seen.add(value);
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
return formatArray(value, seen);
|
|
82
|
+
}
|
|
83
|
+
return formatObject(value as Record<string, unknown>, seen);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Recursively format a debug payload into readable, indented lines. */
|
|
87
|
+
export function formatDataLines(value: unknown): string[] {
|
|
88
|
+
return formatDataLinesRecursive(value, new WeakSet<object>());
|
|
89
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./debug.ts";
|
package/src/renderer.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
3
|
+
import type { DebugEventView } from "@mrclrchtr/supi-core";
|
|
4
|
+
import { formatDataLines } from "./format.ts";
|
|
5
|
+
|
|
6
|
+
const DEBUG_REPORT_TYPE = "supi-debug-report";
|
|
7
|
+
|
|
8
|
+
interface DebugReportDetails {
|
|
9
|
+
events?: DebugEventView[];
|
|
10
|
+
rawAccessDenied?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Theme = Parameters<Parameters<ExtensionAPI["registerMessageRenderer"]>[1]>[2];
|
|
14
|
+
|
|
15
|
+
function formatLevel(theme: Theme, level: string): string {
|
|
16
|
+
const color =
|
|
17
|
+
level === "error"
|
|
18
|
+
? "error"
|
|
19
|
+
: level === "warning"
|
|
20
|
+
? "warning"
|
|
21
|
+
: level === "info"
|
|
22
|
+
? "accent"
|
|
23
|
+
: "muted";
|
|
24
|
+
return theme.fg(color, level.toUpperCase());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function pushEventLines(lines: string[], event: DebugEventView, theme: Theme): void {
|
|
28
|
+
const timestamp = theme.fg("dim", `[${new Date(event.timestamp).toISOString()}]`);
|
|
29
|
+
const level = formatLevel(theme, event.level);
|
|
30
|
+
const source = theme.fg("toolTitle", `${event.source}/${event.category}`);
|
|
31
|
+
|
|
32
|
+
lines.push(`${timestamp} ${level} ${source}: ${event.message}`);
|
|
33
|
+
|
|
34
|
+
if (event.cwd) {
|
|
35
|
+
lines.push(theme.fg("dim", ` cwd: ${event.cwd}`));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const dataLines = formatDataLines(event.data);
|
|
39
|
+
if (dataLines.length > 0) {
|
|
40
|
+
if (dataLines.length === 1) {
|
|
41
|
+
lines.push(theme.fg("dim", ` data: ${dataLines[0]}`));
|
|
42
|
+
} else {
|
|
43
|
+
lines.push(theme.fg("dim", " data:"));
|
|
44
|
+
for (const dl of dataLines) {
|
|
45
|
+
lines.push(theme.fg("dim", ` ${dl}`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rawLines = formatDataLines(event.rawData);
|
|
51
|
+
if (rawLines.length > 0) {
|
|
52
|
+
if (rawLines.length === 1) {
|
|
53
|
+
lines.push(theme.fg("dim", ` rawData: ${rawLines[0]}`));
|
|
54
|
+
} else {
|
|
55
|
+
lines.push(theme.fg("dim", " rawData:"));
|
|
56
|
+
for (const rl of rawLines) {
|
|
57
|
+
lines.push(theme.fg("dim", ` ${rl}`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renderExpandedReport(details: DebugReportDetails, theme: Theme): string {
|
|
64
|
+
const lines: string[] = [];
|
|
65
|
+
for (const event of details.events ?? []) {
|
|
66
|
+
if (lines.length > 0) lines.push("");
|
|
67
|
+
pushEventLines(lines, event, theme);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (details.rawAccessDenied) {
|
|
71
|
+
lines.push("");
|
|
72
|
+
lines.push(
|
|
73
|
+
theme.fg(
|
|
74
|
+
"warning",
|
|
75
|
+
"Raw debug data was requested but is not enabled in SuPi Debug settings.",
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Register the TUI message renderer for supi-debug-report custom messages. */
|
|
84
|
+
export function registerDebugMessageRenderer(pi: ExtensionAPI): void {
|
|
85
|
+
pi.registerMessageRenderer(DEBUG_REPORT_TYPE, (message, options, theme) => {
|
|
86
|
+
const { expanded } = options;
|
|
87
|
+
const details = (message.details ?? {}) as DebugReportDetails;
|
|
88
|
+
const events = details.events ?? [];
|
|
89
|
+
|
|
90
|
+
if (events.length === 0) {
|
|
91
|
+
const text = typeof message.content === "string" ? message.content : "No debug events.";
|
|
92
|
+
return new Text(theme.fg("muted", text), 0, 0);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!expanded) {
|
|
96
|
+
const first = events[0];
|
|
97
|
+
const more = events.length > 1 ? ` +${events.length - 1} more` : "";
|
|
98
|
+
const summary = `${events.length} event${events.length === 1 ? "" : "s"} — ${first.source}/${first.category}${more}`;
|
|
99
|
+
return new Text(theme.fg("muted", summary), 0, 0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return new Text(renderExpandedReport(details, theme), 0, 0);
|
|
103
|
+
});
|
|
104
|
+
}
|