@mkterswingman/5mghost-yonder 0.0.35 → 0.0.37

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
@@ -40,7 +40,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1
40
40
  Client registration notes:
41
41
 
42
42
  - `setup` auto-registers Claude/Codex/Gemini/OpenCode when their CLI supports `mcp add`
43
- - OpenClaw is registered by writing `mcporter.json` directly, which avoids Windows path escaping issues
43
+ - OpenClaw is registered via `mcporter config add --command ... --arg ...` (native stdio mode)
44
44
  - pasted PAT tokens are stored in `~/.mkterswingman/auth.json`; client `env.YT_MCP_TOKEN` is optional after setup
45
45
 
46
46
  Media download runtime expectations:
package/dist/cli/setup.js CHANGED
@@ -51,6 +51,13 @@ function tryRegisterMcp(cmd, label) {
51
51
  return false;
52
52
  }
53
53
  }
54
+ function buildMcporterConfigAddCommand(launcherCommand) {
55
+ const args = ["config", "add", "yt-mcp", "--command", launcherCommand.file];
56
+ for (const arg of launcherCommand.args) {
57
+ args.push("--arg", arg);
58
+ }
59
+ return { file: "mcporter", args };
60
+ }
54
61
  export function buildSetupCliCandidates(launcherCommand) {
55
62
  return [
56
63
  { bin: "claude-internal", label: "Claude Code (internal)", command: { file: "claude-internal", args: ["mcp", "add", "-s", "user", "yt-mcp", "--", launcherCommand.file, ...launcherCommand.args] } },
@@ -370,10 +377,22 @@ export async function runSetup() {
370
377
  }
371
378
  if (isOpenClawInstallLikelyInstalled(detectCli)) {
372
379
  try {
373
- const status = writeOpenClawConfig("yt-mcp", launcherCommand);
374
- const suffix = status === "created" ? "created" : "updated";
375
- console.log(` ✅ MCP registered in OpenClaw (${suffix} mcporter.json)`);
376
- registered = true;
380
+ let openClawRegistered = false;
381
+ if (detectCli("mcporter")) {
382
+ openClawRegistered = tryRegisterMcp(buildMcporterConfigAddCommand({
383
+ file: launcherCommand.command,
384
+ args: launcherCommand.args,
385
+ }), "OpenClaw (mcporter config)");
386
+ }
387
+ if (!openClawRegistered) {
388
+ const status = writeOpenClawConfig("yt-mcp", launcherCommand);
389
+ const suffix = status === "created" ? "created" : "updated";
390
+ console.log(` ✅ MCP registered in OpenClaw (${suffix} ${getOpenClawConfigPath()})`);
391
+ openClawRegistered = true;
392
+ }
393
+ if (openClawRegistered) {
394
+ registered = true;
395
+ }
377
396
  }
378
397
  catch (err) {
379
398
  console.log(` ⚠️ OpenClaw auto-register failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -427,6 +446,8 @@ export async function runSetup() {
427
446
  }
428
447
  }
429
448
  `);
449
+ console.log(" OpenClaw stdio CLI (recommended):");
450
+ console.log(` mcporter config add yt-mcp --command node --arg ${JSON.stringify(PATHS.launcherJs)} --arg serve`);
430
451
  console.log(` OpenClaw uses ${PATHS.sharedAuthJson} for PAT/JWT, so env.YT_MCP_TOKEN is optional after setup.`);
431
452
  if (skillsInstalled) {
432
453
  console.log(" ✅ Installed bundled yt-mcp analysis skill for detected AI clients");
@@ -33,6 +33,7 @@ function tryRemoveMcp(command, label) {
33
33
  }
34
34
  export function buildUninstallCliCandidates() {
35
35
  return [
36
+ { bin: "mcporter", label: "OpenClaw (mcporter config)", command: { file: "mcporter", args: ["config", "remove", "yt-mcp"] } },
36
37
  { bin: "claude-internal", label: "Claude Code (internal)", command: { file: "claude-internal", args: ["mcp", "remove", "-s", "user", "yt-mcp"] } },
37
38
  { bin: "claude", label: "Claude Code", command: { file: "claude", args: ["mcp", "remove", "-s", "user", "yt-mcp"] } },
38
39
  { bin: "codex", label: "Codex CLI / Codex App", command: { file: "codex", args: ["mcp", "remove", "yt-mcp"] } },
@@ -19,7 +19,7 @@ function parseOpenClawConfig(raw) {
19
19
  if (parsed && typeof parsed === "object") {
20
20
  return parsed;
21
21
  }
22
- throw new Error("OpenClaw mcporter.json must be a JSON object");
22
+ throw new Error("OpenClaw config must be a JSON object");
23
23
  }
24
24
  export function upsertOpenClawConfigText(currentText, serverName, launcherCommand) {
25
25
  const config = currentText ? parseOpenClawConfig(currentText) : {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mkterswingman/5mghost-yonder",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "description": "Internal MCP client with local data tools and remote API proxy",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: use-yt-mcp
3
3
  preamble-tier: 3
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  description: |
6
6
  Use when the user wants YouTube analysis through yt-mcp: channel performance,
7
7
  video stats, subtitles, comments, trending, or batch YouTube data work.
@@ -44,6 +44,7 @@ Focus on YouTube analysis with yt-mcp MCP tools. Answer the analysis question fi
44
44
  | List channel uploads | `list_channel_uploads` |
45
45
  | Trending videos | `get_trending` |
46
46
  | Local download | `start_download_job` -> `poll_download_job` |
47
+ | Summarize a video | `get_video_stats` -> `get_subtitles` -> `get_comments` (see Video Summary workflow) |
47
48
 
48
49
  All tools are prefixed `mcp__yt-mcp__` in actual calls.
49
50
 
@@ -87,11 +88,57 @@ Default output:
87
88
  | 直播回放 | 3 | 345,678 | 115,226 | 200,000 | 45,678 |
88
89
  ```
89
90
 
90
- ### Video Summary
91
+ ### Video Summary (Multi-Source)
91
92
 
92
- 1. `get_subtitles(video, format="csv")`
93
- 2. Build a timestamped summary from the transcript
94
- 3. Output section headers with timestamps, not a single long paragraph
93
+ Fuse metadata + subtitles + comments into a rich summary with automatic segmentation.
94
+
95
+ **Phase 1 Metadata**
96
+ 1. `get_video_stats(videos=[video_id])` → title, description, duration, view/like/comment counts, published_at
97
+ 2. Parse description for chapter markers (`0:00 Title` lines). If found, use them as segment anchors in Phase 4.
98
+
99
+ **Phase 2 — Subtitles**
100
+ 3. `get_subtitles(video, format="csv")` → timestamped transcript
101
+ - If it fails or returns empty, call `list_available_subtitles(video)` and retry with the best available language.
102
+ - If no subtitles exist at all, proceed with metadata + comments only and note the limitation.
103
+
104
+ **Phase 3 — Comments**
105
+ 4. `get_comments(video, max_comments=100, order="relevance")`
106
+ - For long videos (>20 min) or videos with >1,000 comments, increase to `max_comments=200`.
107
+
108
+ **Phase 4 — Generate Summary**
109
+
110
+ Synthesize all three sources into this output structure:
111
+
112
+ ```md
113
+ ## 📺 {Video Title}
114
+
115
+ **基本信息**: {duration} | {view_count} 播放 | {like_count} 赞 | {comment_count} 条评论 | {published_at}
116
+
117
+ ### 核心观点
118
+ (2-3 sentences capturing the video's central theme and conclusion)
119
+
120
+ ### 分段总结
121
+
122
+ **[00:00] {Segment Topic}**
123
+ {Key points of this segment, 2-3 sentences}
124
+
125
+ **[05:23] {Segment Topic}**
126
+ {Key points of this segment, 2-3 sentences}
127
+
128
+ ...
129
+
130
+ ### 观众反馈
131
+ - **主流观点**: top recurring sentiment from high-liked comments
132
+ - **争议/补充**: notable disagreements or additions (if any)
133
+ - **精选评论**: quote 2-3 representative comments with like counts
134
+ ```
135
+
136
+ **Segmentation rules**:
137
+ - If description contains chapter markers, use them as primary segment boundaries.
138
+ - Otherwise, detect topic shifts from the transcript automatically.
139
+ - Target 3-8 segments: short videos (<10 min) → 3-4, medium (10-30 min) → 4-6, long (>30 min) → 6-8.
140
+ - Each segment heading includes the start timestamp.
141
+ - Follow the user's language for the summary body.
95
142
 
96
143
  ### Comment Analysis
97
144