tracegist-mcp-bridge 0.2.0 → 0.2.2

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 CHANGED
@@ -48,13 +48,13 @@ Set `TRACEGIST_DIR` to change where the bridge looks for packages (defaults to `
48
48
 
49
49
  Each session ZIP may include:
50
50
 
51
- | Path | Description |
52
- |---|---|
53
- | `*-coding-agent-handoff.md` | Structured handoff for the coding agent |
54
- | `*-manifest.json` | Session metadata and file index |
55
- | `*-playwright-repro.spec.ts` | Auto-generated Playwright repro script skeleton |
51
+ | Path | Description |
52
+ | ---------------------------- | -------------------------------------------------------------------------------------- |
53
+ | `*-coding-agent-handoff.md` | Structured handoff for the coding agent |
54
+ | `*-manifest.json` | Session metadata and file index |
55
+ | `*-playwright-repro.spec.ts` | Auto-generated Playwright repro script skeleton |
56
56
  | `network/api-requests.jsonl` | API request/response bodies (opt-in, requires Deep Diagnostics + body capture enabled) |
57
- | `markers/marker-NN-*/` | Per-marker screenshots, voice notes, highlight captures |
57
+ | `markers/marker-NN-*/` | Per-marker screenshots, voice notes, highlight captures |
58
58
 
59
59
  ## Prerequisites for transcription
60
60
 
@@ -18,9 +18,7 @@ const { version: BRIDGE_VERSION } = JSON.parse(
18
18
  function resolveDefaultDirectory() {
19
19
  const envDir = process.env.TRACEGIST_DIR;
20
20
  if (envDir) {
21
- const resolved = envDir.startsWith("~")
22
- ? path.join(os.homedir(), envDir.slice(1))
23
- : envDir;
21
+ const resolved = envDir.startsWith("~") ? path.join(os.homedir(), envDir.slice(1)) : envDir;
24
22
  return path.resolve(resolved);
25
23
  }
26
24
  return path.join(os.homedir(), "Downloads");
@@ -128,7 +126,9 @@ async function readZipEntries(zipPath) {
128
126
  }
129
127
 
130
128
  async function tryReadManifest(zip) {
131
- const manifestEntry = Object.values(zip.files).find((entry) => entry.name.endsWith("-manifest.json"));
129
+ const manifestEntry = Object.values(zip.files).find((entry) =>
130
+ entry.name.endsWith("-manifest.json"),
131
+ );
132
132
  if (!manifestEntry) return { manifest: null, manifestEntryName: null };
133
133
  const manifestText = await manifestEntry.async("text");
134
134
  try {
@@ -149,9 +149,10 @@ function normalizeZipBaseName(entryName) {
149
149
  }
150
150
 
151
151
  async function tryReadHandoffMarkdown(zip, entryNames, manifest = null) {
152
- const manifestNamedHandoff = typeof manifest?.handoffMarkdownFilename === "string"
153
- ? normalizeZipBaseName(manifest.handoffMarkdownFilename)
154
- : null;
152
+ const manifestNamedHandoff =
153
+ typeof manifest?.handoffMarkdownFilename === "string"
154
+ ? normalizeZipBaseName(manifest.handoffMarkdownFilename)
155
+ : null;
155
156
  const byBaseName = new Map();
156
157
  for (const name of entryNames) {
157
158
  byBaseName.set(normalizeZipBaseName(name), name);
@@ -162,11 +163,12 @@ async function tryReadHandoffMarkdown(zip, entryNames, manifest = null) {
162
163
  selectedEntryName = byBaseName.get(manifestNamedHandoff) || null;
163
164
  }
164
165
  if (!selectedEntryName) {
165
- selectedEntryName = entryNames.find((name) => {
166
- const baseName = normalizeZipBaseName(name);
167
- if (HANDOFF_SUFFIXES.some((suffix) => baseName.endsWith(suffix))) return true;
168
- return /handoff.*\.md$/i.test(baseName);
169
- }) || null;
166
+ selectedEntryName =
167
+ entryNames.find((name) => {
168
+ const baseName = normalizeZipBaseName(name);
169
+ if (HANDOFF_SUFFIXES.some((suffix) => baseName.endsWith(suffix))) return true;
170
+ return /handoff.*\.md$/i.test(baseName);
171
+ }) || null;
170
172
  }
171
173
  if (!selectedEntryName) {
172
174
  return { handoffMarkdown: null, handoffEntryName: null, debugCandidates: [] };
@@ -356,10 +358,7 @@ async function injectTranscriptsIntoMarkdown(markdown, zip, entryNames) {
356
358
  } else {
357
359
  const hint = whisperDependencyWarnings.join(" | ");
358
360
  for (const shortId of voiceByShortId.keys()) {
359
- transcriptByShortId.set(
360
- shortId,
361
- `[TRANSCRIPTION REQUIRED — Whisper not available: ${hint}]`,
362
- );
361
+ transcriptByShortId.set(shortId, `[TRANSCRIPTION REQUIRED — Whisper not available: ${hint}]`);
363
362
  }
364
363
  }
365
364
 
@@ -416,7 +415,7 @@ server.registerPrompt(
416
415
  "",
417
416
  "1. `list_tracegist_packages` — find available packages (searches TRACEGIST_DIR env var, or ~/Downloads by default).",
418
417
  "2. `get_tracegist_handoff_markdown` — call without a `section` parameter to get a table of contents",
419
- " showing all sections and their sizes. Then request specific sections by name (e.g. `section: \"Marker Timeline\"`).",
418
+ ' showing all sections and their sizes. Then request specific sections by name (e.g. `section: "Marker Timeline"`).',
420
419
  ' Use `section: "all"` to load the full document at once (can be large for deep exports).',
421
420
  " **Voice note transcripts are injected automatically** into the marker sections — no separate step needed.",
422
421
  " If Whisper is unavailable, a placeholder is injected with setup instructions.",
@@ -464,23 +463,25 @@ server.registerTool(
464
463
  async ({ zipPath, model = "base", language }) => {
465
464
  if (whisperDependencyWarnings.length > 0) {
466
465
  return {
467
- content: [{
468
- type: "text",
469
- text: JSON.stringify(
470
- {
471
- zipPath,
472
- model,
473
- language: language || null,
474
- transcriptions: [],
475
- failures: [],
476
- warning:
477
- "Local Whisper dependencies are missing. Fix the dependency warnings and retry transcription.",
478
- dependencyWarnings: whisperDependencyWarnings,
479
- },
480
- null,
481
- 2,
482
- ),
483
- }],
466
+ content: [
467
+ {
468
+ type: "text",
469
+ text: JSON.stringify(
470
+ {
471
+ zipPath,
472
+ model,
473
+ language: language || null,
474
+ transcriptions: [],
475
+ failures: [],
476
+ warning:
477
+ "Local Whisper dependencies are missing. Fix the dependency warnings and retry transcription.",
478
+ dependencyWarnings: whisperDependencyWarnings,
479
+ },
480
+ null,
481
+ 2,
482
+ ),
483
+ },
484
+ ],
484
485
  isError: true,
485
486
  };
486
487
  }
@@ -489,20 +490,22 @@ server.registerTool(
489
490
  const voiceEntries = entryNames.filter((entryName) => looksLikeVoiceNote(entryName));
490
491
  if (voiceEntries.length === 0) {
491
492
  return {
492
- content: [{
493
- type: "text",
494
- text: JSON.stringify(
495
- {
496
- zipPath,
497
- model,
498
- language: language || null,
499
- transcriptions: [],
500
- warning: "No voice-note files found in package.",
501
- },
502
- null,
503
- 2,
504
- ),
505
- }],
493
+ content: [
494
+ {
495
+ type: "text",
496
+ text: JSON.stringify(
497
+ {
498
+ zipPath,
499
+ model,
500
+ language: language || null,
501
+ transcriptions: [],
502
+ warning: "No voice-note files found in package.",
503
+ },
504
+ null,
505
+ 2,
506
+ ),
507
+ },
508
+ ],
506
509
  };
507
510
  }
508
511
 
@@ -564,7 +567,8 @@ server.registerTool(
564
567
  server.registerTool(
565
568
  "list_tracegist_packages",
566
569
  {
567
- description: "List TraceGist marker package zip files. Searches TRACEGIST_DIR (env var), falls back to ~/Downloads, or uses the given directory.",
570
+ description:
571
+ "List TraceGist marker package zip files. Searches TRACEGIST_DIR (env var), falls back to ~/Downloads, or uses the given directory.",
568
572
  inputSchema: z.object({
569
573
  directory: z.string().optional(),
570
574
  limit: z.number().int().min(1).max(200).optional(),
@@ -593,7 +597,11 @@ server.registerTool(
593
597
  async ({ zipPath }) => {
594
598
  const { zip, entryNames } = await readZipEntries(zipPath);
595
599
  const { manifest, manifestEntryName } = await tryReadManifest(zip);
596
- const { handoffMarkdown, handoffEntryName } = await tryReadHandoffMarkdown(zip, entryNames, manifest);
600
+ const { handoffMarkdown, handoffEntryName } = await tryReadHandoffMarkdown(
601
+ zip,
602
+ entryNames,
603
+ manifest,
604
+ );
597
605
 
598
606
  const overview = {
599
607
  zipPath,
@@ -639,17 +647,19 @@ server.registerTool(
639
647
  .filter((name) => /handoff|coding-agent/i.test(path.posix.basename(name)))
640
648
  .slice(0, 5);
641
649
  return {
642
- content: [{
643
- type: "text",
644
- text: [
645
- `No handoff markdown entry found in ${zipPath}.`,
646
- manifest?.handoffMarkdownFilename
647
- ? `Manifest handoff filename: ${manifest.handoffMarkdownFilename}`
648
- : "Manifest handoff filename: (missing)",
649
- `Matching entry candidates: ${hintedEntries.length > 0 ? hintedEntries.join(", ") : "(none)"}`,
650
- `Debug candidates: ${debugCandidates.length > 0 ? debugCandidates.join(", ") : "(none)"}`,
651
- ].join("\n"),
652
- }],
650
+ content: [
651
+ {
652
+ type: "text",
653
+ text: [
654
+ `No handoff markdown entry found in ${zipPath}.`,
655
+ manifest?.handoffMarkdownFilename
656
+ ? `Manifest handoff filename: ${manifest.handoffMarkdownFilename}`
657
+ : "Manifest handoff filename: (missing)",
658
+ `Matching entry candidates: ${hintedEntries.length > 0 ? hintedEntries.join(", ") : "(none)"}`,
659
+ `Debug candidates: ${debugCandidates.length > 0 ? debugCandidates.join(", ") : "(none)"}`,
660
+ ].join("\n"),
661
+ },
662
+ ],
653
663
  isError: true,
654
664
  };
655
665
  }
@@ -659,10 +669,12 @@ server.registerTool(
659
669
  // Full document retrieval
660
670
  if (section && section.toLowerCase() === "all") {
661
671
  return {
662
- content: [{
663
- type: "text",
664
- text: `# Source: ${handoffEntryName}\n\n${enrichedMarkdown}`,
665
- }],
672
+ content: [
673
+ {
674
+ type: "text",
675
+ text: `# Source: ${handoffEntryName}\n\n${enrichedMarkdown}`,
676
+ },
677
+ ],
666
678
  };
667
679
  }
668
680
 
@@ -671,10 +683,12 @@ server.registerTool(
671
683
  // No section requested — return table of contents
672
684
  if (!section) {
673
685
  return {
674
- content: [{
675
- type: "text",
676
- text: `# Source: ${handoffEntryName}\n\n${renderSectionToc(sections, zipPath)}`,
677
- }],
686
+ content: [
687
+ {
688
+ type: "text",
689
+ text: `# Source: ${handoffEntryName}\n\n${renderSectionToc(sections, zipPath)}`,
690
+ },
691
+ ],
678
692
  };
679
693
  }
680
694
 
@@ -684,18 +698,22 @@ server.registerTool(
684
698
  if (!match) {
685
699
  const available = sections.map((s) => s.name).join(", ");
686
700
  return {
687
- content: [{
688
- type: "text",
689
- text: `Section "${section}" not found. Available sections: ${available}`,
690
- }],
701
+ content: [
702
+ {
703
+ type: "text",
704
+ text: `Section "${section}" not found. Available sections: ${available}`,
705
+ },
706
+ ],
691
707
  isError: true,
692
708
  };
693
709
  }
694
710
  return {
695
- content: [{
696
- type: "text",
697
- text: match.content,
698
- }],
711
+ content: [
712
+ {
713
+ type: "text",
714
+ text: match.content,
715
+ },
716
+ ],
699
717
  };
700
718
  },
701
719
  );
@@ -751,7 +769,9 @@ server.registerTool(
751
769
  const outputPath = path.resolve(outDir, path.basename(entryName));
752
770
  if (!outputPath.startsWith(outDir + path.sep) && outputPath !== outDir) {
753
771
  return {
754
- content: [{ type: "text", text: `Refusing to write outside output directory: ${outputPath}` }],
772
+ content: [
773
+ { type: "text", text: `Refusing to write outside output directory: ${outputPath}` },
774
+ ],
755
775
  isError: true,
756
776
  };
757
777
  }
@@ -765,7 +785,9 @@ server.registerTool(
765
785
  );
766
786
 
767
787
  whisperDependencyWarnings = await checkWhisperDependencies();
768
- console.error(`[${BRIDGE_NAME}] Default package directory: ${DEFAULT_DOWNLOADS_DIR}${process.env.TRACEGIST_DIR ? " (from TRACEGIST_DIR)" : ""}`);
788
+ console.error(
789
+ `[${BRIDGE_NAME}] Default package directory: ${DEFAULT_DOWNLOADS_DIR}${process.env.TRACEGIST_DIR ? " (from TRACEGIST_DIR)" : ""}`,
790
+ );
769
791
  if (whisperDependencyWarnings.length > 0) {
770
792
  for (const warning of whisperDependencyWarnings) {
771
793
  console.error(`[${BRIDGE_NAME}] WARNING: ${warning}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracegist-mcp-bridge",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local-first MCP bridge for reading and transcribing TraceGist package zips.",
5
5
  "type": "module",
6
6
  "bin": {