dsh-github-flow 0.3.0 → 0.5.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.
Files changed (121) hide show
  1. package/README.en.md +287 -143
  2. package/README.md +270 -125
  3. package/docs/UPGRADE-NOTES.md +12 -9
  4. package/docs/architecture.md +126 -126
  5. package/lib/api/routes-actions.js +249 -0
  6. package/lib/api/routes-overview.js +94 -2
  7. package/lib/cache.d.ts +4 -0
  8. package/lib/cache.js +14 -0
  9. package/lib/client.d.ts +14 -1
  10. package/lib/client.js +4287 -2500
  11. package/lib/commands/gh.d.ts +6 -1
  12. package/lib/commands/gh.js +144 -71
  13. package/lib/executor/git-parser.d.ts +57 -0
  14. package/lib/executor/git-parser.js +255 -0
  15. package/lib/executor/platform-guide.d.ts +14 -0
  16. package/lib/executor/platform-guide.js +40 -0
  17. package/lib/executor/process-utils.d.ts +51 -0
  18. package/lib/executor/process-utils.js +162 -0
  19. package/lib/executor/version-utils.d.ts +12 -0
  20. package/lib/executor/version-utils.js +27 -0
  21. package/lib/executor.d.ts +70 -48
  22. package/lib/executor.js +371 -356
  23. package/lib/git-watcher.d.ts +36 -0
  24. package/lib/git-watcher.js +91 -0
  25. package/lib/main.js +37 -3
  26. package/lib/renderers/agent-task.d.ts +16 -0
  27. package/lib/renderers/agent-task.js +107 -0
  28. package/lib/renderers/cache.d.ts +8 -0
  29. package/lib/renderers/cache.js +66 -0
  30. package/lib/renderers/codespace.d.ts +16 -0
  31. package/lib/renderers/codespace.js +103 -0
  32. package/lib/renderers/common.d.ts +24 -0
  33. package/lib/renderers/common.js +88 -0
  34. package/lib/renderers/discussion.d.ts +16 -0
  35. package/lib/renderers/discussion.js +101 -0
  36. package/lib/renderers/gist.d.ts +15 -0
  37. package/lib/renderers/gist.js +99 -0
  38. package/lib/renderers/issue.d.ts +4 -0
  39. package/lib/renderers/issue.js +70 -0
  40. package/lib/renderers/label.d.ts +4 -0
  41. package/lib/renderers/label.js +48 -0
  42. package/lib/renderers/markdown.d.ts +19 -32
  43. package/lib/renderers/markdown.js +19 -624
  44. package/lib/renderers/pr.d.ts +4 -0
  45. package/lib/renderers/pr.js +107 -0
  46. package/lib/renderers/project.d.ts +20 -0
  47. package/lib/renderers/project.js +128 -0
  48. package/lib/renderers/release.d.ts +4 -0
  49. package/lib/renderers/release.js +74 -0
  50. package/lib/renderers/repo.d.ts +4 -0
  51. package/lib/renderers/repo.js +149 -0
  52. package/lib/renderers/ruleset.d.ts +4 -0
  53. package/lib/renderers/ruleset.js +74 -0
  54. package/lib/renderers/run.d.ts +4 -0
  55. package/lib/renderers/run.js +79 -0
  56. package/lib/renderers/skill.d.ts +34 -0
  57. package/lib/renderers/skill.js +241 -0
  58. package/lib/renderers/status.d.ts +28 -0
  59. package/lib/renderers/status.js +176 -0
  60. package/lib/telemetry.d.ts +70 -0
  61. package/lib/telemetry.js +161 -0
  62. package/lib/tools/agent-task.d.ts +54 -0
  63. package/lib/tools/agent-task.js +135 -0
  64. package/lib/tools/cache.d.ts +64 -0
  65. package/lib/tools/cache.js +186 -0
  66. package/lib/tools/codespace.d.ts +51 -0
  67. package/lib/tools/codespace.js +154 -0
  68. package/lib/tools/discussion.d.ts +70 -0
  69. package/lib/tools/discussion.js +195 -0
  70. package/lib/tools/gist.d.ts +155 -0
  71. package/lib/tools/gist.js +190 -0
  72. package/lib/tools/help.js +214 -13
  73. package/lib/tools/image-utils.d.ts +8 -0
  74. package/lib/tools/image-utils.js +34 -0
  75. package/lib/tools/issue.d.ts +8 -1
  76. package/lib/tools/issue.js +26 -4
  77. package/lib/tools/label.d.ts +80 -0
  78. package/lib/tools/label.js +237 -0
  79. package/lib/tools/pr.d.ts +8 -0
  80. package/lib/tools/pr.js +48 -3
  81. package/lib/tools/project.d.ts +80 -0
  82. package/lib/tools/project.js +241 -0
  83. package/lib/tools/repo.js +13 -1
  84. package/lib/tools/ruleset.d.ts +80 -0
  85. package/lib/tools/ruleset.js +177 -0
  86. package/lib/tools/skill.d.ts +24 -1
  87. package/lib/tools/skill.js +115 -5
  88. package/lib/tools/status.d.ts +40 -0
  89. package/lib/tools/status.js +58 -0
  90. package/lib/types.d.ts +44 -0
  91. package/lib/ui/auth-guide-card.d.ts +4 -0
  92. package/lib/ui/auth-guide-card.js +161 -0
  93. package/lib/ui/branch-selector.d.ts +10 -0
  94. package/lib/ui/branch-selector.js +163 -0
  95. package/lib/ui/commit-modal.d.ts +8 -0
  96. package/lib/ui/commit-modal.js +219 -0
  97. package/lib/ui/help-modal.d.ts +15 -0
  98. package/lib/ui/help-modal.js +202 -0
  99. package/lib/ui/icons.d.ts +7 -0
  100. package/lib/ui/icons.js +53 -0
  101. package/lib/ui/network-banner.d.ts +10 -0
  102. package/lib/ui/network-banner.js +54 -0
  103. package/lib/ui/storage.d.ts +35 -0
  104. package/lib/ui/storage.js +158 -0
  105. package/lib/ui/styles.d.ts +6 -0
  106. package/lib/ui/styles.js +1544 -0
  107. package/lib/ui/sync-settings-modal.d.ts +11 -0
  108. package/lib/ui/sync-settings-modal.js +350 -0
  109. package/lib/ui/sync-status-badge.d.ts +8 -0
  110. package/lib/ui/sync-status-badge.js +64 -0
  111. package/lib/ui/upgrade-card.d.ts +7 -0
  112. package/lib/ui/upgrade-card.js +222 -0
  113. package/lib/ui/utils.d.ts +45 -0
  114. package/lib/ui/utils.js +226 -0
  115. package/lib/ui/workspace-panel.d.ts +4 -0
  116. package/lib/ui/workspace-panel.js +489 -0
  117. package/lib/upgrade-manager.d.ts +5 -1
  118. package/lib/upgrade-manager.js +24 -1
  119. package/lib/version.d.ts +1 -1
  120. package/lib/version.js +1 -1
  121. package/package.json +2 -2
@@ -0,0 +1,107 @@
1
+ import { sanitizeCell, formatStateBadge, formatCiBadge, formatConflictBadge } from './common.js';
2
+ /**
3
+ * PR 领域渲染器:负责 PR 列表高密度表格、CI Checks、分支状态与单卡详情格式化
4
+ */
5
+ export function renderPrMarkdown(args, value) {
6
+ if (!value)
7
+ return '无返回内容';
8
+ if (value.status === 'AWAITING_CONFIRMATION') {
9
+ return [
10
+ `> ### ${value.warning || '⚠️ 高危操作拦截警告'}`,
11
+ `> - **影响评估**: ${value.impact || '该操作将改变远端仓库状态。'}`,
12
+ `> - **确认指引**: ${value.requiredAction || '如确认继续,请向用户核实并在参数中附加 `confirm: true` 重新调用。'}`,
13
+ ].join('\n');
14
+ }
15
+ if (typeof value.result === 'string')
16
+ return value.result;
17
+ if (typeof value.message === 'string' && !value.items) {
18
+ const extra = value.detail || value.output;
19
+ return `**${value.message}**` + (value.url ? `\n🔗 链接: ${value.url}` : '') + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
20
+ }
21
+ // 1.1 PR 列表
22
+ if (Array.isArray(value.items) && args?.action === 'list') {
23
+ const list = value.items.filter(Boolean);
24
+ if (list.length === 0)
25
+ return '📭 当前仓库暂无匹配的 Pull Request。';
26
+ const rows = list.map((p) => {
27
+ const numLink = p.url ? `[#${p.number}](${p.url})` : `#${p.number}`;
28
+ const badge = formatStateBadge(p.state, p.isDraft);
29
+ const title = sanitizeCell(p.title, 55);
30
+ const author = p.author?.login ? `@${p.author.login}` : (typeof p.author === 'string' ? `@${p.author}` : '-');
31
+ const date = p.updatedAt ? p.updatedAt.slice(0, 10) : (p.mergedAt ? p.mergedAt.slice(0, 10) : '-');
32
+ return `| ${numLink} | ${badge} | ${title} | ${author} | ${date} |`;
33
+ });
34
+ return [
35
+ `**找到 ${list.length} 个 Pull Request:**\n`,
36
+ '| 编号 | 状态 | 标题 | 作者 | 更新日期 |',
37
+ '| :--- | :--- | :--- | :--- | :--- |',
38
+ ...rows,
39
+ ].join('\n');
40
+ }
41
+ // 1.2 PR CI Checks
42
+ if (Array.isArray(value.items) && args?.action === 'checks') {
43
+ const list = value.items.filter(Boolean);
44
+ if (list.length === 0)
45
+ return '当前 PR 暂无 CI Checks 运行记录。';
46
+ const rows = list.map((c) => {
47
+ const name = sanitizeCell(c.name, 40);
48
+ // bucket 是 gh pr checks 的分类字段(pass/fail/pending/skipping/cancel),
49
+ // 优先于 state 呈现;state(SUCCESS/FAILURE/...)作为兜底——渲染器同步
50
+ // Issue #3 修复:旧 conclusion/detailsUrl 字段在 gh 中不存在。
51
+ const badge = formatCiBadge(c.state, c.bucket);
52
+ const url = c.link ? `[查看详情](${c.link})` : '-';
53
+ const wf = c.workflow ? sanitizeCell(c.workflow, 24) : '-';
54
+ return `| ${name} | ${badge} | ${wf} | ${url} |`;
55
+ });
56
+ return [
57
+ `**CI 检查结果 (${list.length} 项):**\n`,
58
+ '| 检查项名称 | 结论 / 状态 | 工作流 | 详情链接 |',
59
+ '| :--- | :--- | :--- | :--- |',
60
+ ...rows,
61
+ ].join('\n');
62
+ }
63
+ // 1.3 PR Status (冲突与相关状态)
64
+ if (args?.action === 'status') {
65
+ const created = Array.isArray(value.createdBy) ? value.createdBy : [];
66
+ const review = Array.isArray(value.needsReview) ? value.needsReview : [];
67
+ const parts = ['### 🔀 当前分支关联 PR 状态\n'];
68
+ if (created.length > 0) {
69
+ parts.push('**由我发起的 PR:**\n| 编号 | 状态 | 冲突检测 | 标题 |', '| :--- | :--- | :--- | :--- |');
70
+ for (const p of created) {
71
+ const link = p.url ? `[#${p.number}](${p.url})` : `#${p.number}`;
72
+ parts.push(`| ${link} | ${formatStateBadge(p.state)} | ${formatConflictBadge(p.mergeStateStatus)} | ${sanitizeCell(p.title, 50)} |`);
73
+ }
74
+ }
75
+ else {
76
+ parts.push('当前分支未检测到本人发起的活跃 PR。');
77
+ }
78
+ if (review.length > 0) {
79
+ parts.push('\n**待我审查的 PR:**\n| 编号 | 状态 | 标题 |', '| :--- | :--- | :--- |');
80
+ for (const p of review) {
81
+ const link = p.url ? `[#${p.number}](${p.url})` : `#${p.number}`;
82
+ parts.push(`| ${link} | ${formatStateBadge(p.state)} | ${sanitizeCell(p.title, 50)} |`);
83
+ }
84
+ }
85
+ return parts.join('\n');
86
+ }
87
+ // 1.4 PR View 单卡详情
88
+ if (args?.action === 'view' && value.number) {
89
+ const link = value.url ? `[#${value.number}](${value.url})` : `#${value.number}`;
90
+ const badge = formatStateBadge(value.state, value.isDraft);
91
+ const author = value.author?.login ? `@${value.author.login}` : '-';
92
+ const lines = [
93
+ `### ${badge} ${value.title} (${link})`,
94
+ `- **作者**: ${author} | **分支**: \`${value.headRefName || '-'}\` → \`${value.baseRefName || 'main'}\``,
95
+ `- **合并判定**: ${formatConflictBadge(value.mergeable || value.mergeStateStatus)} | **审查判定**: ${value.reviewDecision || 'NONE'}`,
96
+ ];
97
+ if (Array.isArray(value.labels) && value.labels.length > 0) {
98
+ lines.push(`- **标签**: ${value.labels.map((l) => `\`${l.name || l}\``).join(' ')}`);
99
+ }
100
+ if (value.body) {
101
+ lines.push('\n**正文说明:**\n```markdown\n' + sanitizeCell(value.body, 300) + '\n```');
102
+ }
103
+ return lines.join('\n');
104
+ }
105
+ // 兜底降级
106
+ return JSON.stringify(value, null, 2);
107
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 渲染 GitHub OAuth Scope 权限缺失自愈引导卡片
3
+ */
4
+ export declare function renderScopeRequiredMarkdown(value: any): string;
5
+ /**
6
+ * 渲染 Projects 列表表格
7
+ */
8
+ export declare function renderProjectList(items: any[]): string;
9
+ /**
10
+ * 渲染单个 Project 详情卡片
11
+ */
12
+ export declare function renderProjectView(p: any): string;
13
+ /**
14
+ * 渲染 Project Items 看板条目列表
15
+ */
16
+ export declare function renderProjectItemList(items: any[]): string;
17
+ /**
18
+ * Project 领域综合渲染入口
19
+ */
20
+ export declare function renderProjectMarkdown(args: any, value: any): string;
@@ -0,0 +1,128 @@
1
+ import { sanitizeCell } from './common.js';
2
+ /**
3
+ * 渲染 GitHub OAuth Scope 权限缺失自愈引导卡片
4
+ */
5
+ export function renderScopeRequiredMarkdown(value) {
6
+ const scope = value.scope || '相关权限';
7
+ const command = value.command || `gh auth refresh -s ${scope}`;
8
+ const toolName = value.tool ? `「${value.tool}」` : '';
9
+ return [
10
+ `> ### 🔑 需要补充 GitHub 权限授权 (Token Scope)`,
11
+ `> - **缺少权限**: \`${scope}\``,
12
+ `> - **影响工具**: ${toolName || '当前操作'}`,
13
+ `> - **自愈指引**: 请在宿主终端中执行以下单行命令完成授权:`,
14
+ `> \`\`\`bash`,
15
+ `> ${command}`,
16
+ `> \`\`\``,
17
+ `> - **说明**: 授权完成后无需重启插件,直接重新调用当前工具即可正常执行。`,
18
+ ].join('\n');
19
+ }
20
+ /**
21
+ * 渲染 Projects 列表表格
22
+ */
23
+ export function renderProjectList(items) {
24
+ const list = items.filter(Boolean);
25
+ if (list.length === 0) {
26
+ return '📭 暂无项目规划看板 (Projects)。';
27
+ }
28
+ const rows = list.map((p) => {
29
+ const num = p.number ? `#${p.number}` : '-';
30
+ const link = p.url ? `[${num}](${p.url})` : num;
31
+ const title = sanitizeCell(p.title || '(无标题)', 40);
32
+ const stateBadge = p.closed ? '🟣 CLOSED' : '🔵 OPEN';
33
+ const visibility = p.public ? '🌐 Public' : '🔒 Private';
34
+ const desc = sanitizeCell(p.shortDescription || p.readme || '-', 35);
35
+ return `| ${link} | ${title} | ${stateBadge} | ${visibility} | ${desc} |`;
36
+ });
37
+ return [
38
+ `**项目看板列表 (${list.length} 个):**\n`,
39
+ '| 编号 | 项目标题 | 状态 | 可见性 | 描述 |',
40
+ '| :--- | :--- | :--- | :--- | :--- |',
41
+ ...rows,
42
+ ].join('\n');
43
+ }
44
+ /**
45
+ * 渲染单个 Project 详情卡片
46
+ */
47
+ export function renderProjectView(p) {
48
+ if (!p || typeof p !== 'object') {
49
+ return '无项目详情数据';
50
+ }
51
+ const num = p.number ? `#${p.number}` : '';
52
+ const title = p.title || '(无标题)';
53
+ const stateBadge = p.closed ? '🟣 CLOSED' : '🔵 OPEN';
54
+ const visibility = p.public ? '🌐 Public' : '🔒 Private';
55
+ const link = p.url ? `[打开项目网页](${p.url})` : '';
56
+ const lines = [
57
+ `### 📋 Project ${num}: ${title}\n`,
58
+ `- **状态**: ${stateBadge}`,
59
+ `- **可见性**: ${visibility}`,
60
+ `- **项目 ID**: \`${p.id || '-'}\``,
61
+ ];
62
+ if (link)
63
+ lines.push(`- **项目链接**: ${link}`);
64
+ if (p.shortDescription)
65
+ lines.push(`- **简述**: ${p.shortDescription}`);
66
+ if (p.readme) {
67
+ lines.push('\n**项目 README 说明:**', '---', p.readme.trim(), '---');
68
+ }
69
+ return lines.join('\n');
70
+ }
71
+ /**
72
+ * 渲染 Project Items 看板条目列表
73
+ */
74
+ export function renderProjectItemList(items) {
75
+ const list = items.filter(Boolean);
76
+ if (list.length === 0) {
77
+ return '📭 当前项目看板中暂无任何条目 (Items)。';
78
+ }
79
+ const rows = list.map((item) => {
80
+ const rawId = String(item.id || '-');
81
+ const shortId = rawId.length > 8 ? `\`${rawId.slice(0, 8)}...\`` : `\`${rawId}\``;
82
+ const title = sanitizeCell(item.title || item.content?.title || '(无标题条目)', 45);
83
+ const type = item.type || (item.content?.type ? String(item.content.type) : 'DraftIssue');
84
+ const status = item.status || '-';
85
+ return `| ${shortId} | ${title} | \`${type}\` | ${status} |`;
86
+ });
87
+ return [
88
+ `**项目看板条目 (${list.length} 条):**\n`,
89
+ '| 条目 ID | 标题 / 内容 | 类型 | 状态看板 |',
90
+ '| :--- | :--- | :--- | :--- |',
91
+ ...rows,
92
+ ].join('\n');
93
+ }
94
+ /**
95
+ * Project 领域综合渲染入口
96
+ */
97
+ export function renderProjectMarkdown(args, value) {
98
+ if (!value)
99
+ return '无返回内容';
100
+ if (value.status === 'SCOPE_REQUIRED') {
101
+ return renderScopeRequiredMarkdown(value);
102
+ }
103
+ if (value.status === 'AWAITING_CONFIRMATION') {
104
+ return [
105
+ `> ### ${value.warning || '⚠️ 操作确认拦截'}`,
106
+ `> - **影响评估**: ${value.impact || ''}`,
107
+ `> - **确认指引**: ${value.requiredAction || '如确认继续,请在参数中附加 `confirm: true` 重新调用。'}`,
108
+ ].join('\n');
109
+ }
110
+ if (typeof value.result === 'string')
111
+ return value.result;
112
+ if (typeof value.message === 'string' && !value.items && !value.projects) {
113
+ const extra = value.detail || value.output || value.url;
114
+ return `**${value.message}**` + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
115
+ }
116
+ // 列表渲染(适配 projects 或 items 数组)
117
+ const listData = Array.isArray(value.projects) ? value.projects : (Array.isArray(value.items) ? value.items : null);
118
+ if (listData && args?.action === 'list') {
119
+ return renderProjectList(listData);
120
+ }
121
+ if (listData && args?.action === 'item-list') {
122
+ return renderProjectItemList(listData);
123
+ }
124
+ if (args?.action === 'view' || value.number) {
125
+ return renderProjectView(value);
126
+ }
127
+ return JSON.stringify(value, null, 2);
128
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Release 领域渲染器:负责版本发布历史列表与详情卡片(含资产清单、发布说明预览)
3
+ */
4
+ export declare function renderReleaseMarkdown(args: any, value: any): string;
@@ -0,0 +1,74 @@
1
+ import { sanitizeCell, formatReleaseBadge } from './common.js';
2
+ /**
3
+ * Release 领域渲染器:负责版本发布历史列表与详情卡片(含资产清单、发布说明预览)
4
+ */
5
+ export function renderReleaseMarkdown(args, value) {
6
+ if (!value)
7
+ return '无返回内容';
8
+ if (value.status === 'AWAITING_CONFIRMATION') {
9
+ return [
10
+ `> ### ${value.warning || '⚠️ 高危操作拦截警告'}`,
11
+ `> - **影响评估**: ${value.impact || '该操作将改变远端仓库状态。'}`,
12
+ `> - **确认指引**: ${value.requiredAction || '如确认继续,请向用户核实并在参数中附加 `confirm: true` 重新调用。'}`,
13
+ ].join('\n');
14
+ }
15
+ if (typeof value.result === 'string')
16
+ return value.result;
17
+ if (typeof value.message === 'string' && !value.items) {
18
+ const extra = value.detail || value.output;
19
+ return `**${value.message}**` + (value.url ? `\n🔗 链接: ${value.url}` : '') + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
20
+ }
21
+ // 5.1 Release 列表
22
+ if (Array.isArray(value.items) && args?.action === 'list') {
23
+ const list = value.items.filter(Boolean);
24
+ if (list.length === 0)
25
+ return '📭 当前仓库暂无任何 Release。';
26
+ const rows = list.map((r) => {
27
+ const tag = r.tagName ? `\`${r.tagName}\`` : '-';
28
+ const name = sanitizeCell(r.name || r.tagName, 40);
29
+ const badge = formatReleaseBadge(r.isDraft, r.isPrerelease);
30
+ const date = (r.publishedAt || r.createdAt || '').slice(0, 10) || '-';
31
+ return `| ${tag} | ${badge} | ${name} | ${date} |`;
32
+ });
33
+ return [
34
+ `**最近 ${list.length} 个 Release:**\n`,
35
+ '| Tag | 类型 | 名称 | 发布日期 |',
36
+ '| :--- | :--- | :--- | :--- |',
37
+ ...rows,
38
+ ].join('\n');
39
+ }
40
+ // 5.2 Release 详情卡片
41
+ if (args?.action === 'view' && value.tagName) {
42
+ const badge = formatReleaseBadge(value.isDraft, value.isPrerelease);
43
+ const lines = [
44
+ `### 🏷️ Release \`${value.tagName}\` ${badge}`,
45
+ ];
46
+ // 元信息压缩成一段(硬换行分隔),避免逐行 filter 空串把段落分隔也滤掉。
47
+ // Markdown 的列表/段落渲染依赖空行:若标题、资产列表、正文之间没有空行,
48
+ // 列表语法会失效并连成一段——所以这里改为「分段数组 + 空行 join」。
49
+ const meta = [];
50
+ if (value.name)
51
+ meta.push(`**${value.name}**`);
52
+ if (value.url)
53
+ meta.push(`🔗 ${value.url}`);
54
+ if (value.publishedAt)
55
+ meta.push(`📅 发布于 ${value.publishedAt.slice(0, 10)}`);
56
+ if (meta.length > 0)
57
+ lines.push(meta.join(' \n'));
58
+ if (Array.isArray(value.assets) && value.assets.length > 0) {
59
+ const assetLines = value.assets.map((a) => {
60
+ const size = typeof a.size === 'number' ? ` (${(a.size / 1024).toFixed(1)} KB)` : '';
61
+ return `- \`${a.name || '-'}\`${size}`;
62
+ });
63
+ lines.push(`**📎 附属资产 (${value.assets.length}):**\n${assetLines.join('\n')}`);
64
+ }
65
+ if (value.body) {
66
+ // 发版说明可能非常长,只保留前 600 字符做快速预览,避免单次调用撑爆上下文
67
+ const preview = value.body.length > 600 ? value.body.slice(0, 600) + '\n…(已截断,完整内容见 Release 页面)' : value.body;
68
+ lines.push(`**📝 发版说明摘要:**\n\n${preview}`);
69
+ }
70
+ return lines.join('\n\n');
71
+ }
72
+ // 兜底降级
73
+ return JSON.stringify(value, null, 2);
74
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Repo 领域渲染器:负责仓库卡片概览、README 预览、代码/仓库/Issue/Commit 跨仓检索、免 Clone 文件与目录清单渲染
3
+ */
4
+ export declare function renderRepoMarkdown(args: any, value: any): string;
@@ -0,0 +1,149 @@
1
+ import { sanitizeCell, formatStateBadge, appendDegradedNote } from './common.js';
2
+ /**
3
+ * Repo 领域渲染器:负责仓库卡片概览、README 预览、代码/仓库/Issue/Commit 跨仓检索、免 Clone 文件与目录清单渲染
4
+ */
5
+ export function renderRepoMarkdown(args, value) {
6
+ if (!value)
7
+ return '无返回内容';
8
+ if (typeof value.result === 'string')
9
+ return value.result;
10
+ // 4.0 README 预览(文本截断版 + 图片清单)——必须在 message 早退分支之前:
11
+ // readme 返回同时带 message 与 readme 字段,先判 readme 才能渲染预览而非一行摘要
12
+ if (args?.action === 'readme' && typeof value.readme === 'string') {
13
+ const lines = [`### 📖 README 预览`, '', '```markdown', value.readme, '```'];
14
+ if (Array.isArray(value.images) && value.images.length > 0) {
15
+ lines.push('', `**📎 图片清单 (${value.images.length}):** 可用 \`image_urls\` 参数下载指定图片(留空下载全部)`);
16
+ value.images.slice(0, 8).forEach((u, i) => lines.push(`${i + 1}. ${u}`));
17
+ if (value.images.length > 8)
18
+ lines.push(`…共 ${value.images.length} 个`);
19
+ }
20
+ return lines.join('\n');
21
+ }
22
+ if (typeof value.message === 'string' && !value.items) {
23
+ return `**${value.message}**` + (value.output ? `\n\`\`\`\n${value.output}\n\`\`\`` : '');
24
+ }
25
+ // 4.1 Repo View 概览卡片
26
+ if (args?.action === 'view' && value.nameWithOwner) {
27
+ const link = value.url ? `[${value.nameWithOwner}](${value.url})` : `**${value.nameWithOwner}**`;
28
+ const stars = value.stargazerCount ?? value.stars ?? 0;
29
+ const forks = value.forkCount ?? value.forks ?? 0;
30
+ const branch = value.defaultBranchRef?.name || value.defaultBranch || 'main';
31
+ const lines = [
32
+ `### 📦 ${link}`,
33
+ `> ⭐ **Stars**: ${stars} | 🍴 **Forks**: ${forks} | ⎇ **默认分支**: \`${branch}\``,
34
+ value.description ? `\n${value.description}\n` : '',
35
+ ];
36
+ if (value.licenseInfo?.name || value.licenseInfo?.key) {
37
+ lines.push(`- **开源协议**: \`${value.licenseInfo.name || value.licenseInfo.key}\``);
38
+ }
39
+ if (Array.isArray(value.repositoryTopics) && value.repositoryTopics.length > 0) {
40
+ lines.push(`- **仓库标签 (Topics)**: ${value.repositoryTopics.map((t) => `\`${t.name || t}\``).join(' ')}`);
41
+ }
42
+ return lines.filter(Boolean).join('\n');
43
+ }
44
+ // 4.2 Repo Search 仓库搜索列表
45
+ if (Array.isArray(value.items) && args?.action === 'search_repos') {
46
+ if (value.items.length === 0)
47
+ return '未找到匹配的仓库。';
48
+ const rows = value.items.map((r) => {
49
+ const name = r.fullName ? `[${r.fullName}](https://github.com/${r.fullName})` : '-';
50
+ const stars = r.stargazersCount ?? '-';
51
+ const desc = sanitizeCell(r.description, 45);
52
+ const date = r.updatedAt ? r.updatedAt.slice(0, 10) : '-';
53
+ return `| ${name} | ⭐ ${stars} | ${desc} | ${date} |`;
54
+ });
55
+ return [
56
+ `**仓库检索结果 (${value.items.length} 个):**\n`,
57
+ '| 仓库全名 | Stars | 描述 | 更新日期 |',
58
+ '| :--- | :--- | :--- | :--- |',
59
+ ...rows,
60
+ ].join('\n');
61
+ }
62
+ // 4.3 Code Search 代码搜索列表
63
+ if (Array.isArray(value.items) && args?.action === 'search_code') {
64
+ if (value.items.length === 0)
65
+ return '未找到匹配的代码片段。';
66
+ const rows = value.items.map((c) => {
67
+ const repo = c.repository?.fullName || '-';
68
+ const path = sanitizeCell(c.path, 50);
69
+ return `| \`${path}\` | ${repo} |`;
70
+ });
71
+ return [
72
+ `**代码检索结果 (${value.items.length} 处匹配):**\n`,
73
+ '| 文件路径 | 所属仓库 |',
74
+ '| :--- | :--- |',
75
+ ...rows,
76
+ ].join('\n');
77
+ }
78
+ // 4.4 Issue/PR 搜索列表(search_issues / search_prs 共用,字段同构)
79
+ if (Array.isArray(value.items) && (args?.action === 'search_issues' || args?.action === 'search_prs')) {
80
+ if (value.items.length === 0)
81
+ return '未找到匹配的结果。';
82
+ const kind = args.action === 'search_prs' ? 'PR' : 'Issue';
83
+ const rows = value.items.map((it) => {
84
+ const num = it.number ?? '-';
85
+ const repo = it.repository?.nameWithOwner || it.repository?.fullName || '-';
86
+ const link = it.url ? `[#${num}](${it.url})` : `#${num}`;
87
+ const badge = formatStateBadge(it.state, it.isDraft);
88
+ const author = it.author?.login || '-';
89
+ const date = it.updatedAt ? String(it.updatedAt).slice(0, 10) : '-';
90
+ return `| ${link} | ${sanitizeCell(it.title, 45)} | ${badge} | ${repo} | ${author} | ${date} |`;
91
+ });
92
+ return [
93
+ `**${kind} 检索结果 (${value.items.length} 条):**\n`,
94
+ '| 编号 | 标题 | 状态 | 仓库 | 作者 | 更新日期 |',
95
+ '| :--- | :--- | :--- | :--- | :--- | :--- |',
96
+ ...rows,
97
+ ].join('\n');
98
+ }
99
+ // 4.5 Commit 搜索列表(嵌套 commit.commit.message 取首行)
100
+ if (Array.isArray(value.items) && args?.action === 'search_commits') {
101
+ if (value.items.length === 0)
102
+ return '未找到匹配的提交。';
103
+ const rows = value.items.map((c) => {
104
+ const sha = `\`${String(c.sha || '').slice(0, 7)}\``;
105
+ const msg = sanitizeCell(String(c.commit?.message || '').split('\n')[0], 50);
106
+ const author = c.commit?.author?.name || c.author?.login || '-';
107
+ const repo = c.repository?.fullName || '-';
108
+ return `| ${sha} | ${msg} | ${author} | ${repo} |`;
109
+ });
110
+ return [
111
+ `**提交检索结果 (${value.items.length} 条):**\n`,
112
+ '| SHA | 提交信息 | 作者 | 仓库 |',
113
+ '| :--- | :--- | :--- | :--- |',
114
+ ...rows,
115
+ ].join('\n');
116
+ }
117
+ // 4.6 目录清单(read_dir:dir 置顶 + size 人性化;mode 八进制是 Git 内部语义不展示)
118
+ if (args?.action === 'read_dir' && Array.isArray(value.items)) {
119
+ if (value.items.length === 0)
120
+ return `**${value.path || '/'}** 为空目录。` + appendDegradedNote(value);
121
+ const sorted = [...value.items].sort((a, b) => (a.type === b.type ? String(a.name).localeCompare(String(b.name)) : a.type === 'dir' ? -1 : 1));
122
+ const rows = sorted.map((e) => {
123
+ const icon = e.type === 'dir' ? '📁' : '📄';
124
+ const size = e.type === 'dir' ? '-' : (typeof e.size === 'number' ? (e.size > 1024 ? `${(e.size / 1024).toFixed(1)}KB` : `${e.size}B`) : '-');
125
+ return `| ${icon} \`${sanitizeCell(e.name, 60)}\` | ${size} |`;
126
+ });
127
+ return [
128
+ `**目录 ${value.path || '/'}(${value.items.length} 项):**\n`,
129
+ '| 名称 | 大小 |',
130
+ '| :--- | :--- |',
131
+ ...rows,
132
+ appendDegradedNote(value),
133
+ ].filter((l) => l !== '').join('\n');
134
+ }
135
+ // 4.7 文件内容(read_file:代码块 + 元信息行)
136
+ if (args?.action === 'read_file' && typeof value.content === 'string') {
137
+ const ext = (value.path || '').split('.').pop() || '';
138
+ const size = typeof value.size === 'number' ? (value.size > 1024 ? `${(value.size / 1024).toFixed(1)}KB` : `${value.size}B`) : '-';
139
+ return [
140
+ `**📄 \`${value.path}\`** (${size}${value.ref ? ` @ ${value.ref}` : ''})\n`,
141
+ '```' + ext,
142
+ value.content,
143
+ '```',
144
+ appendDegradedNote(value),
145
+ ].filter((l) => l !== '').join('\n');
146
+ }
147
+ // 兜底降级
148
+ return JSON.stringify(value, null, 2);
149
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Ruleset 领域渲染器:负责 GitHub Rulesets 列表、详情与分支策略 check 的 Markdown 格式化
3
+ */
4
+ export declare function renderRulesetMarkdown(args: any, value: any): string;
@@ -0,0 +1,74 @@
1
+ import { sanitizeCell } from './common.js';
2
+ /**
3
+ * Ruleset 领域渲染器:负责 GitHub Rulesets 列表、详情与分支策略 check 的 Markdown 格式化
4
+ */
5
+ export function renderRulesetMarkdown(args, value) {
6
+ if (!value)
7
+ return '无返回内容';
8
+ if (typeof value.result === 'string')
9
+ return value.result;
10
+ // 1. check 操作格式化展示(策略视角 PR 无法合并的核心排障答案)
11
+ if (args?.action === 'check') {
12
+ const branch = value.branch || args?.branch || '当前分支';
13
+ const repo = value.repo || args?.repo || '-';
14
+ const ruleCount = typeof value.ruleCount === 'number' ? value.ruleCount : 0;
15
+ if (ruleCount === 0) {
16
+ return [
17
+ `🟢 分支 \`${branch}\`(仓库 \`${repo}\`)当前**未受任何 Ruleset 规则保护或策略限制**。`,
18
+ '',
19
+ '> 💡 **PR 合并排障指南**: 该分支无策略规则阻断。若 PR 依然无法合并,通常是因为:',
20
+ '> 1. **CI 未通过**: 请调用 \\`github_pr(action: \'checks\')\\` 审查 CI 检查项,若有失败调用 \\`github_run(action: \'log_failed\')\\`;',
21
+ '> 2. **代码冲突**: 请检查 PR 的 \\`mergeable\\` 状态;',
22
+ '> 3. **Draft 状态**: 若为草稿,请使用 \\`github_pr(action: \'ready\')\\` 转为可评审状态。',
23
+ ].join('\n');
24
+ }
25
+ const items = Array.isArray(value.rules) ? value.rules : [];
26
+ const ruleRows = items.map((r) => {
27
+ const name = r.name ? `🔒 **${r.name}**` : '-';
28
+ const params = r.params ? `\`${sanitizeCell(r.params, 50)}\`` : '-';
29
+ const source = r.source ? sanitizeCell(r.source, 40) : '-';
30
+ return `| ${name} | ${params} | ${source} |`;
31
+ });
32
+ const tablePart = items.length > 0
33
+ ? [
34
+ '| 规则类型 | 约束详情 | 规则集来源 |',
35
+ '| :--- | :--- | :--- |',
36
+ ...ruleRows,
37
+ ].join('\n')
38
+ : (value.rawText ? `\`\`\`\n${value.rawText}\n\`\`\`` : '');
39
+ return [
40
+ `⚠️ 分支 \`${branch}\`(仓库 \`${repo}\`)受到 **${ruleCount}** 项策略规则保护与约束:\n`,
41
+ tablePart,
42
+ '',
43
+ '> 💡 **PR 合并策略排障**: PR 合并必须满足上述硬性规则(如必审批准人数、指定 CI 门禁、线性历史、签名提交等)。与 \\`github_pr(action: \'checks\')\\` 配合可完整诊断“PR 为何无法合并”。',
44
+ ].join('\n');
45
+ }
46
+ // 2. list 操作格式化展示
47
+ if (args?.action === 'list') {
48
+ const raw = (value.rawText || value.output || '').trim();
49
+ if (!raw) {
50
+ return '📭 目标仓库/组织当前未配置任何规则集 (Rulesets)。';
51
+ }
52
+ return [
53
+ `**规则集列表 (Rulesets):**\n`,
54
+ '```',
55
+ raw,
56
+ '```',
57
+ ].join('\n');
58
+ }
59
+ // 3. view 操作格式化展示
60
+ if (args?.action === 'view') {
61
+ const raw = (value.rawText || value.output || '').trim();
62
+ const idHint = value.ruleset_id ? ` (ID: ${value.ruleset_id})` : '';
63
+ return [
64
+ `### 🛡️ 规则集详情${idHint}\n`,
65
+ '```',
66
+ raw || '无详细规则内容',
67
+ '```',
68
+ ].join('\n');
69
+ }
70
+ // 4. 兜底
71
+ if (typeof value.message === 'string')
72
+ return value.message;
73
+ return JSON.stringify(value, null, 2);
74
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Actions Run 领域渲染器:负责工作流运行列表、工作流清单、工作流详情与单次 Run 状态渲染
3
+ */
4
+ export declare function renderRunMarkdown(args: any, value: any): string;
@@ -0,0 +1,79 @@
1
+ import { sanitizeCell, formatCiBadge } from './common.js';
2
+ /**
3
+ * Actions Run 领域渲染器:负责工作流运行列表、工作流清单、工作流详情与单次 Run 状态渲染
4
+ */
5
+ export function renderRunMarkdown(args, value) {
6
+ if (!value)
7
+ return '无返回数据';
8
+ if (typeof value.result === 'string')
9
+ return value.result;
10
+ if (typeof value.message === 'string' && !value.items) {
11
+ return `**${value.message}**` + (value.output ? `\n\`\`\`\n${value.output}\n\`\`\`` : '');
12
+ }
13
+ // 3.1 Run 列表
14
+ if (Array.isArray(value.items) && args?.action === 'list') {
15
+ const list = value.items.filter(Boolean);
16
+ if (list.length === 0)
17
+ return '📭 暂无匹配的工作流运行记录。';
18
+ const rows = list.map((r) => {
19
+ const idLink = r.url ? `[${r.databaseId}](${r.url})` : `\`${r.databaseId}\``;
20
+ const badge = formatCiBadge(r.status, r.conclusion);
21
+ const name = sanitizeCell(r.name, 35);
22
+ const branch = r.headBranch ? `\`${r.headBranch}\`` : '-';
23
+ const event = r.event || '-';
24
+ const time = r.createdAt ? r.createdAt.slice(0, 16).replace('T', ' ') : '-';
25
+ return `| ${idLink} | ${badge} | ${name} | ${branch} | ${event} | ${time} |`;
26
+ });
27
+ return [
28
+ `**最近 ${list.length} 次工作流运行:**\n`,
29
+ '| Run ID | 结论 / 状态 | 工作流名称 | 触发分支 | 触发事件 | 运行时间 |',
30
+ '| :--- | :--- | :--- | :--- | :--- | :--- |',
31
+ ...rows,
32
+ ].join('\n');
33
+ }
34
+ // 3.2 Workflow 清单(字段集为 gh 2.96 实测合法全集 4 个)
35
+ if (Array.isArray(value.items) && args?.action === 'workflow_list') {
36
+ const list = value.items.filter(Boolean);
37
+ if (list.length === 0)
38
+ return args?.all === true ? '📭 该仓库没有任何工作流。' : '📭 暂无 active 工作流(可能全部 disabled,传 all: true 查看)。';
39
+ const rows = list.map((w) => {
40
+ const badge = w.state === 'active' ? '🟢 active' : (w.state === 'disabled' ? '🔴 disabled' : String(w.state || '-'));
41
+ return `| \`${w.id}\` | ${sanitizeCell(w.name, 40)} | ${badge} | \`${sanitizeCell(w.path, 45)}\` |`;
42
+ });
43
+ return [
44
+ `**工作流清单 (${list.length} 个${args?.all === true ? ',含 disabled' : ''}):**\n`,
45
+ '| ID | 名称 | 状态 | 文件 |',
46
+ '| :--- | :--- | :--- | :--- |',
47
+ ...rows,
48
+ ].join('\n');
49
+ }
50
+ // 3.3 Workflow 详情(gh 无 --json,头部结构化 + Recent runs 原文引用块——D4 决策)
51
+ if (args?.action === 'workflow_view' && value.workflow) {
52
+ const lines = [
53
+ `### 🔄 ${value.workflow}`,
54
+ `- **ID**: \`${value.id || '-'}\`${value.totalRuns ? ` | **累计运行**: ${value.totalRuns} 次` : ''}`,
55
+ ];
56
+ if (value.recentRuns) {
57
+ lines.push('', '**最近运行:**', '```', value.recentRuns, '```');
58
+ }
59
+ return lines.join('\n');
60
+ }
61
+ // 3.4 Run View 详情
62
+ if (args?.action === 'view' && value.databaseId) {
63
+ const idLink = value.url ? `[${value.databaseId}](${value.url})` : `\`${value.databaseId}\``;
64
+ const badge = formatCiBadge(value.status, value.conclusion);
65
+ const lines = [
66
+ `### 工作流: ${value.name} (Run: ${idLink})`,
67
+ `- **状态**: ${badge}`,
68
+ ];
69
+ if (Array.isArray(value.jobs) && value.jobs.length > 0) {
70
+ lines.push('\n**Jobs 步骤明细:**\n| Job 名称 | 结论 / 状态 | 详情 |', '| :--- | :--- | :--- |');
71
+ for (const j of value.jobs) {
72
+ lines.push(`| ${sanitizeCell(j.name, 30)} | ${formatCiBadge(j.status, j.conclusion)} | ${j.url ? `[链接](${j.url})` : '-'} |`);
73
+ }
74
+ }
75
+ return lines.join('\n');
76
+ }
77
+ // 兜底降级
78
+ return JSON.stringify(value, null, 2);
79
+ }