tracegist-mcp-bridge 0.2.2 → 0.2.4

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/bin/lib.mjs ADDED
@@ -0,0 +1,153 @@
1
+ import path from "node:path";
2
+
3
+ const PACKAGE_SUFFIX = "-package.zip";
4
+ const HANDOFF_SUFFIXES = ["-coding-agent-handoff.md", "-cursor-handoff.md"];
5
+
6
+ export function isTraceGistPackageFile(fileName) {
7
+ return fileName.startsWith("tracegist-") && fileName.endsWith(PACKAGE_SUFFIX);
8
+ }
9
+
10
+ export function normalizeZipBaseName(entryName) {
11
+ return path.posix.basename(entryName).toLowerCase();
12
+ }
13
+
14
+ export function renderPackagesText(packages, directory) {
15
+ if (packages.length === 0) {
16
+ return [
17
+ `No TraceGist package zips found in ${directory}.`,
18
+ "Expected naming pattern: tracegist-...-package.zip",
19
+ ].join("\n");
20
+ }
21
+ const lines = [`Found ${packages.length} TraceGist package(s) in ${directory}:`, ""];
22
+ for (const pkg of packages) {
23
+ lines.push(
24
+ `- ${pkg.name}`,
25
+ ` path: ${pkg.path}`,
26
+ ` size: ${pkg.sizeBytes} bytes`,
27
+ ` modified: ${pkg.modifiedAt}`,
28
+ "",
29
+ );
30
+ }
31
+ return lines.join("\n");
32
+ }
33
+
34
+ export function parseMarkdownSections(markdown) {
35
+ const sections = [];
36
+ const lines = markdown.split("\n");
37
+ let currentName = null;
38
+ let currentStart = 0;
39
+
40
+ for (let i = 0; i < lines.length; i++) {
41
+ if (lines[i].startsWith("## ")) {
42
+ if (currentName !== null) {
43
+ sections.push({
44
+ name: currentName,
45
+ content: lines.slice(currentStart, i).join("\n"),
46
+ });
47
+ }
48
+ currentName = lines[i].slice(3).trim();
49
+ currentStart = i;
50
+ }
51
+ }
52
+
53
+ if (currentName !== null) {
54
+ sections.push({
55
+ name: currentName,
56
+ content: lines.slice(currentStart).join("\n"),
57
+ });
58
+ }
59
+
60
+ return sections;
61
+ }
62
+
63
+ /**
64
+ * Brief purpose hints for known handoff sections.
65
+ * Keys are matched case-insensitively against section names.
66
+ * Unknown sections get a generic hint so the TOC is never incomplete.
67
+ */
68
+ const SECTION_HINTS = {
69
+ "session triage": "Tester summary: expected vs actual, severity",
70
+ "agent guidance": "Suggested investigation focus areas",
71
+ "session context note": "Starting state before the bug (not a bug itself)",
72
+ "notable anomalies": "Pre-flagged JS errors, failed requests, warnings",
73
+ "marker timeline": "Timestamped markers with ±5 s event windows — start here for analysis",
74
+ "user interaction timeline": "Full click/fill/navigation sequence — key for reproduction",
75
+ "session context": "Page URL, title, session metadata",
76
+ "session environment": "Browser, viewport, OS — match for reproduction",
77
+ "package files": "Paths to Playwright script, manifest, network bodies",
78
+ "marker-to-file mapping": "Which screenshots/voice files belong to each marker",
79
+ "backend log correlation": "Absolute timestamps for server-side log alignment",
80
+ "full session console timeline": "All console output (deep exports only)",
81
+ "full session network timeline": "All network requests (deep exports only)",
82
+ "full session network timeline (third-party only)":
83
+ "Third-party network calls (deep exports only)",
84
+ "full session timelines": "Placeholder when deep timelines are omitted",
85
+ context: "AI-generated analysis context (when available)",
86
+ "tracegist agent-processed context": "LLM-processed summary of the session",
87
+ "tester intent": "What the tester was trying to accomplish",
88
+ "handover tasks for coding agent": "Specific tasks the tester wants the agent to do",
89
+ "marker visual evidence": "Screenshot references for each marker",
90
+ "environment at marker time": "Environment snapshot at a specific marker",
91
+ "marker timeline logs (context window)": "Logs within the ±5 s marker window",
92
+ };
93
+
94
+ function getSectionHint(sectionName) {
95
+ return SECTION_HINTS[sectionName.toLowerCase()] || "Additional section";
96
+ }
97
+
98
+ export function renderSectionToc(sections, zipPath) {
99
+ const totalChars = sections.reduce((sum, s) => sum + s.content.length, 0);
100
+ const lines = [
101
+ `Handoff document for ${path.basename(zipPath)} — ${sections.length} sections, ${totalChars.toLocaleString()} chars total.`,
102
+ "",
103
+ "| # | Section | Size | Purpose |",
104
+ "|---|---------|------|---------|",
105
+ ];
106
+ for (let i = 0; i < sections.length; i++) {
107
+ const hint = getSectionHint(sections[i].name);
108
+ lines.push(
109
+ `| ${i + 1} | ${sections[i].name} | ${sections[i].content.length.toLocaleString()} chars | ${hint} |`,
110
+ );
111
+ }
112
+ lines.push(
113
+ "",
114
+ "**Reading guide:** For analysis, start with Session Triage → Marker Timeline → Notable Anomalies.",
115
+ "For reproduction, start with Session Environment → User Interaction Timeline → Package Files (Playwright script path).",
116
+ "",
117
+ 'Pass `section` with a section name (e.g. "Marker Timeline") to retrieve its full content.',
118
+ );
119
+ return lines.join("\n");
120
+ }
121
+
122
+ export function looksLikeVoiceNote(entryName) {
123
+ const base = path.posix.basename(entryName).toLowerCase();
124
+ return /voice/.test(base) && /\.(webm|wav|mp3|m4a|ogg|flac)$/i.test(base);
125
+ }
126
+
127
+ export async function mapConcurrent(items, fn, concurrency) {
128
+ const results = new Array(items.length);
129
+ let i = 0;
130
+ const worker = async () => {
131
+ while (i < items.length) {
132
+ const idx = i++;
133
+ results[idx] = await fn(items[idx], idx);
134
+ }
135
+ };
136
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
137
+ return results;
138
+ }
139
+
140
+ export function toolError(err) {
141
+ const message = err instanceof Error ? err.message : String(err);
142
+ return {
143
+ content: [{ type: "text", text: `Error: ${message}` }],
144
+ isError: true,
145
+ };
146
+ }
147
+
148
+ export function formatExecError(err) {
149
+ if (err instanceof Error && err.message) return err.message;
150
+ return String(err);
151
+ }
152
+
153
+ export { HANDOFF_SUFFIXES };