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,36 @@
1
+ /**
2
+ * Git 元数据变更事件载荷
3
+ */
4
+ export interface GitChangeEvent {
5
+ /** 是否检测到本地 Git 元数据变动 */
6
+ changed?: boolean;
7
+ /** 触发时间戳(毫秒) */
8
+ at?: number;
9
+ /** 是否因达到长轮询上限而超时返回 */
10
+ timeout?: boolean;
11
+ }
12
+ /**
13
+ * Git 监听器配置项
14
+ */
15
+ export interface GitWatchOptions {
16
+ /** 防抖时间(毫秒),默认 800ms */
17
+ debounceMs?: number;
18
+ /** 长轮询超时时间(毫秒),默认 35,000ms */
19
+ timeoutMs?: number;
20
+ }
21
+ /**
22
+ * 定向针对 .git/HEAD 与 .git/index 创建非递归文件系统监听器。
23
+ * 零源码目录遍历,避免句柄耗尽与高 CPU 占用。
24
+ *
25
+ * 核心机制:
26
+ * 1. 靶向监听:仅监控 .git/HEAD 与 .git/index,若都不存在则兜底监控 .git 目录;
27
+ * 2. 800ms 防抖合并:避免连续 git 操作(如 git add 多个文件)产生事件风暴;
28
+ * 3. 单次触发保证(At-Most-Once):变更触发或超时熔断后,立即自动执行清理并释放全部句柄;
29
+ * 4. 显式释放:返回可随时主动调用的清理函数 stop()。
30
+ *
31
+ * @param cwd 目标 Git 仓库根目录
32
+ * @param onTrigger 变更发生或超时触发时的回调函数
33
+ * @param options 可选配置项(防抖与超时时间)
34
+ * @returns 停止监听并释放全部句柄的清理函数
35
+ */
36
+ export declare function watchGitMetadata(cwd: string, onTrigger: (event: GitChangeEvent) => void, options?: GitWatchOptions): () => void;
@@ -0,0 +1,91 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * 定向针对 .git/HEAD 与 .git/index 创建非递归文件系统监听器。
5
+ * 零源码目录遍历,避免句柄耗尽与高 CPU 占用。
6
+ *
7
+ * 核心机制:
8
+ * 1. 靶向监听:仅监控 .git/HEAD 与 .git/index,若都不存在则兜底监控 .git 目录;
9
+ * 2. 800ms 防抖合并:避免连续 git 操作(如 git add 多个文件)产生事件风暴;
10
+ * 3. 单次触发保证(At-Most-Once):变更触发或超时熔断后,立即自动执行清理并释放全部句柄;
11
+ * 4. 显式释放:返回可随时主动调用的清理函数 stop()。
12
+ *
13
+ * @param cwd 目标 Git 仓库根目录
14
+ * @param onTrigger 变更发生或超时触发时的回调函数
15
+ * @param options 可选配置项(防抖与超时时间)
16
+ * @returns 停止监听并释放全部句柄的清理函数
17
+ */
18
+ export function watchGitMetadata(cwd, onTrigger, options) {
19
+ const debounceMs = options?.debounceMs ?? 800;
20
+ const timeoutMs = options?.timeoutMs ?? 35_000;
21
+ const gitDir = path.join(cwd, '.git');
22
+ let stopped = false;
23
+ let debounceTimer = null;
24
+ let timeoutTimer = null;
25
+ const watchers = [];
26
+ const cleanup = () => {
27
+ if (debounceTimer) {
28
+ clearTimeout(debounceTimer);
29
+ debounceTimer = null;
30
+ }
31
+ if (timeoutTimer) {
32
+ clearTimeout(timeoutTimer);
33
+ timeoutTimer = null;
34
+ }
35
+ for (const w of watchers) {
36
+ try {
37
+ w.close();
38
+ }
39
+ catch { }
40
+ }
41
+ watchers.length = 0;
42
+ };
43
+ const stop = () => {
44
+ if (stopped)
45
+ return;
46
+ stopped = true;
47
+ cleanup();
48
+ };
49
+ const triggerChange = () => {
50
+ if (stopped)
51
+ return;
52
+ if (debounceTimer)
53
+ clearTimeout(debounceTimer);
54
+ debounceTimer = setTimeout(() => {
55
+ if (stopped)
56
+ return;
57
+ stopped = true;
58
+ cleanup();
59
+ try {
60
+ onTrigger({ changed: true, at: Date.now() });
61
+ }
62
+ catch { }
63
+ }, debounceMs);
64
+ };
65
+ try {
66
+ const targets = [path.join(gitDir, 'HEAD'), path.join(gitDir, 'index')];
67
+ for (const target of targets) {
68
+ if (fs.existsSync(target)) {
69
+ watchers.push(fs.watch(target, triggerChange));
70
+ }
71
+ }
72
+ if (watchers.length === 0 && fs.existsSync(gitDir)) {
73
+ watchers.push(fs.watch(gitDir, triggerChange));
74
+ }
75
+ timeoutTimer = setTimeout(() => {
76
+ if (stopped)
77
+ return;
78
+ stopped = true;
79
+ cleanup();
80
+ try {
81
+ onTrigger({ timeout: true });
82
+ }
83
+ catch { }
84
+ }, timeoutMs);
85
+ }
86
+ catch (err) {
87
+ cleanup();
88
+ throw err;
89
+ }
90
+ return stop;
91
+ }
package/lib/main.js CHANGED
@@ -7,7 +7,17 @@ import { createApiTool } from './tools/api.js';
7
7
  import { createReleaseTool } from './tools/release.js';
8
8
  import { createSecretTool } from './tools/secret.js';
9
9
  import { createSkillTool } from './tools/skill.js';
10
+ import { createLabelTool } from './tools/label.js';
11
+ import { createRulesetTool } from './tools/ruleset.js';
12
+ import { createCacheTool } from './tools/cache.js';
13
+ import { createGistTool } from './tools/gist.js';
14
+ import { createStatusTool } from './tools/status.js';
15
+ import { createAgentTaskTool } from './tools/agent-task.js';
16
+ import { createDiscussionTool } from './tools/discussion.js';
17
+ import { createProjectTool } from './tools/project.js';
18
+ import { createCodespaceTool } from './tools/codespace.js';
10
19
  import { createHelpTool } from './tools/help.js';
20
+ import { defaultTelemetryCollector } from './telemetry.js';
11
21
  import { registerGhCommand } from './commands/gh.js';
12
22
  import { registerApiRoutes } from './api/routes.js';
13
23
  import { UpdateChecker } from './updater.js';
@@ -83,11 +93,26 @@ export function apply(ctx, config = {}) {
83
93
  else {
84
94
  ctx.github = executor;
85
95
  }
86
- // 2. 注册人类 Slash 命令 (/gh status, /gh upgrade, /gh help)
96
+ // 2. 注册 Cordis tools/result 事件切面(无侵入全量工具审计与降级率打点)
97
+ if (ctx.on && typeof ctx.on === 'function') {
98
+ ctx.on('tools/result', (exec, result) => {
99
+ try {
100
+ const toolName = exec?.name || exec?.tool?.name || '';
101
+ if (typeof toolName === 'string' && toolName.startsWith('github_')) {
102
+ const args = exec?.arguments || exec?.args || {};
103
+ defaultTelemetryCollector.recordCall(toolName, args, result);
104
+ }
105
+ }
106
+ catch {
107
+ // Fail-Open 非阻塞防线:严禁打点逻辑异常影响主工具调用
108
+ }
109
+ });
110
+ }
111
+ // 3. 注册人类 Slash 命令 (/gh status, /gh upgrade, /gh help)
87
112
  if (ctx.commands) {
88
- registerGhCommand(ctx.commands, executor, updateChecker);
113
+ registerGhCommand(ctx.commands, executor, updateChecker, defaultTelemetryCollector);
89
114
  }
90
- // 3. 注册 Agent 模型工具集(核心领域工具 + 元指南)
115
+ // 4. 注册 Agent 模型工具集(核心领域工具 + 元指南)
91
116
  if (ctx.tools) {
92
117
  ctx.tools.register(createPrTool(executor));
93
118
  ctx.tools.register(createIssueTool(executor));
@@ -97,6 +122,15 @@ export function apply(ctx, config = {}) {
97
122
  ctx.tools.register(createReleaseTool(executor));
98
123
  ctx.tools.register(createSecretTool(executor));
99
124
  ctx.tools.register(createSkillTool(executor));
125
+ ctx.tools.register(createLabelTool(executor));
126
+ ctx.tools.register(createRulesetTool(executor));
127
+ ctx.tools.register(createCacheTool(executor));
128
+ ctx.tools.register(createGistTool(executor));
129
+ ctx.tools.register(createStatusTool(executor, defaultTelemetryCollector));
130
+ ctx.tools.register(createAgentTaskTool(executor));
131
+ ctx.tools.register(createDiscussionTool(executor));
132
+ ctx.tools.register(createProjectTool(executor));
133
+ ctx.tools.register(createCodespaceTool(executor));
100
134
  ctx.tools.register(createHelpTool(executor));
101
135
  }
102
136
  // 4. 注册面向 Client 端的 WebServer HTTP 路由(如果当前环境启用了 Web UI 服务)
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 格式化 Agent Task 状态徽标
3
+ */
4
+ export declare function formatAgentTaskStateBadge(state?: string): string;
5
+ /**
6
+ * 渲染 Agent Tasks 列表表格
7
+ */
8
+ export declare function renderAgentTaskList(items: any[]): string;
9
+ /**
10
+ * 渲染单个 Agent Task 详情卡片
11
+ */
12
+ export declare function renderAgentTaskView(task: any): string;
13
+ /**
14
+ * Agent Task 领域综合渲染入口
15
+ */
16
+ export declare function renderAgentTaskMarkdown(args: any, value: any): string;
@@ -0,0 +1,107 @@
1
+ import { sanitizeCell } from './common.js';
2
+ /**
3
+ * 格式化 Agent Task 状态徽标
4
+ */
5
+ export function formatAgentTaskStateBadge(state) {
6
+ if (!state)
7
+ return '⚪ UNKNOWN';
8
+ const upper = state.toUpperCase();
9
+ switch (upper) {
10
+ case 'COMPLETED':
11
+ case 'SUCCESS':
12
+ return '🟢 COMPLETED';
13
+ case 'IN_PROGRESS':
14
+ case 'RUNNING':
15
+ return '🟡 RUNNING';
16
+ case 'FAILED':
17
+ case 'FAILURE':
18
+ return '🔴 FAILED';
19
+ case 'CANCELLED':
20
+ case 'CANCELED':
21
+ return '⚪ CANCELLED';
22
+ default:
23
+ return `⚪ ${upper}`;
24
+ }
25
+ }
26
+ /**
27
+ * 渲染 Agent Tasks 列表表格
28
+ */
29
+ export function renderAgentTaskList(items) {
30
+ const list = items.filter(Boolean);
31
+ if (list.length === 0) {
32
+ return '📭 暂无智能体任务 (Agent Tasks)。';
33
+ }
34
+ const rows = list.map((t) => {
35
+ const rawId = String(t.id || '-');
36
+ const shortId = rawId.length > 8 ? `\`${rawId.slice(0, 8)}...\`` : `\`${rawId}\``;
37
+ const name = sanitizeCell(t.name || '(无描述)', 40);
38
+ const stateBadge = formatAgentTaskStateBadge(t.state);
39
+ let prCell = '-';
40
+ if (t.pullRequestNumber) {
41
+ const prText = `#${t.pullRequestNumber}`;
42
+ prCell = t.pullRequestUrl ? `[${prText}](${t.pullRequestUrl})` : prText;
43
+ }
44
+ const created = t.createdAt ? t.createdAt.split('T')[0] : '-';
45
+ return `| ${shortId} | ${name} | ${stateBadge} | ${prCell} | ${created} |`;
46
+ });
47
+ return [
48
+ `**智能体任务列表 (${list.length} 条):**\n`,
49
+ '| 任务 ID | 描述 | 状态 | 关联 PR | 创建日期 |',
50
+ '| :--- | :--- | :--- | :--- | :--- |',
51
+ ...rows,
52
+ ].join('\n');
53
+ }
54
+ /**
55
+ * 渲染单个 Agent Task 详情卡片
56
+ */
57
+ export function renderAgentTaskView(task) {
58
+ if (!task || typeof task !== 'object') {
59
+ return '无任务详情数据';
60
+ }
61
+ const name = task.name || '(未命名任务)';
62
+ const stateBadge = formatAgentTaskStateBadge(task.state);
63
+ const repo = task.repository ? `[${task.repository}](https://github.com/${task.repository})` : '-';
64
+ const user = task.user?.login || task.user || '-';
65
+ const created = task.createdAt || '-';
66
+ const completed = task.completedAt || '-';
67
+ const lines = [
68
+ `### 🤖 Agent Task: ${name}\n`,
69
+ `- **任务 ID**: \`${task.id || '-'}\``,
70
+ `- **状态**: ${stateBadge}`,
71
+ `- **目标仓库**: ${repo}`,
72
+ `- **分派用户**: @${user}`,
73
+ `- **创建时间**: ${created}`,
74
+ `- **完成时间**: ${completed}`,
75
+ ];
76
+ if (task.pullRequestNumber) {
77
+ const prTitle = task.pullRequestTitle ? ` - ${task.pullRequestTitle}` : '';
78
+ const prLink = task.pullRequestUrl
79
+ ? `[#${task.pullRequestNumber}${prTitle}](${task.pullRequestUrl})`
80
+ : `#${task.pullRequestNumber}${prTitle}`;
81
+ lines.push(`- **关联 PR**: ${prLink} (${task.pullRequestState || 'OPEN'})`);
82
+ }
83
+ if (task.logs || task.log) {
84
+ lines.push('\n**会话日志记录:**', '```text', String(task.logs || task.log).trim(), '```');
85
+ }
86
+ return lines.join('\n');
87
+ }
88
+ /**
89
+ * Agent Task 领域综合渲染入口
90
+ */
91
+ export function renderAgentTaskMarkdown(args, value) {
92
+ if (!value)
93
+ return '无返回内容';
94
+ if (typeof value.result === 'string')
95
+ return value.result;
96
+ if (typeof value.message === 'string' && !value.items) {
97
+ const extra = value.detail || value.output || value.url;
98
+ return `**${value.message}**` + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
99
+ }
100
+ if (Array.isArray(value.items) && args?.action === 'list') {
101
+ return renderAgentTaskList(value.items);
102
+ }
103
+ if (args?.action === 'view' || value.id) {
104
+ return renderAgentTaskView(value);
105
+ }
106
+ return JSON.stringify(value, null, 2);
107
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 友好文件大小换算:B -> KB -> MB -> GB
3
+ */
4
+ export declare function formatBytes(bytes?: number): string;
5
+ /**
6
+ * Cache 领域渲染器:负责 GitHub Actions 缓存列表、容量盘点与清理操作的 Markdown 格式化
7
+ */
8
+ export declare function renderCacheMarkdown(args: any, value: any): string;
@@ -0,0 +1,66 @@
1
+ import { sanitizeCell } from './common.js';
2
+ /**
3
+ * 友好文件大小换算:B -> KB -> MB -> GB
4
+ */
5
+ export function formatBytes(bytes) {
6
+ if (typeof bytes !== 'number' || isNaN(bytes) || bytes <= 0)
7
+ return '0 B';
8
+ const k = 1024;
9
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
10
+ const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), sizes.length - 1);
11
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
12
+ }
13
+ /**
14
+ * Cache 领域渲染器:负责 GitHub Actions 缓存列表、容量盘点与清理操作的 Markdown 格式化
15
+ */
16
+ export function renderCacheMarkdown(args, value) {
17
+ if (!value)
18
+ return '无返回内容';
19
+ // 1. 高危操作确认拦截报告
20
+ if (value.status === 'AWAITING_CONFIRMATION') {
21
+ return [
22
+ `> ### ${value.warning || '⚠️ 操作确认拦截'}`,
23
+ `> - **影响评估**: ${value.impact || ''}`,
24
+ `> - **确认指引**: ${value.requiredAction || '如确认继续,请在参数中附加 \\`confirm: true\\` 重新调用。'}`,
25
+ ].join('\n');
26
+ }
27
+ if (typeof value.result === 'string')
28
+ return value.result;
29
+ // 2. 单操作消息提示(delete 等)
30
+ if (typeof value.message === 'string' && !value.items) {
31
+ const extra = value.detail || value.output;
32
+ return `**${value.message}**` + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
33
+ }
34
+ // 3. 缓存列表展示
35
+ if (Array.isArray(value.items)) {
36
+ const list = value.items.filter(Boolean);
37
+ if (list.length === 0) {
38
+ return args?.key
39
+ ? `📭 未检索到匹配键名 "${args.key}" 的 Actions 缓存。`
40
+ : '📭 仓库中当前未发现任何 Actions 缓存。';
41
+ }
42
+ let totalBytes = 0;
43
+ const rows = list.map((item) => {
44
+ const id = item.id ? `\`${item.id}\`` : '-';
45
+ const key = item.key ? `\`${sanitizeCell(item.key, 35)}\`` : '-';
46
+ const sizeNum = typeof item.sizeInBytes === 'number' ? item.sizeInBytes : 0;
47
+ totalBytes += sizeNum;
48
+ const sizeStr = formatBytes(sizeNum);
49
+ const ref = item.ref ? `\`${sanitizeCell(item.ref, 25)}\`` : '-';
50
+ const lastAccess = item.lastAccessedAt ? item.lastAccessedAt.replace('T', ' ').replace('Z', '') : '-';
51
+ return `| ${id} | ${key} | ${sizeStr} | ${ref} | ${lastAccess} |`;
52
+ });
53
+ const keyHint = args?.key ? ` (过滤键: "${args.key}")` : '';
54
+ const totalSizeStr = formatBytes(totalBytes);
55
+ return [
56
+ `**Actions 缓存列表 (${list.length} 个, 总计占用 ${totalSizeStr})${keyHint}:**\n`,
57
+ '| 缓存 ID | 键名 (Key) | 大小 | 关联 Ref | 最后访问时间 |',
58
+ '| :--- | :--- | :--- | :--- | :--- |',
59
+ ...rows,
60
+ '',
61
+ '> 💡 **缓存治理建议**: 若 Actions 构建耗时变长或缓存过载,可使用 `github_cache(action: \'delete\', cache_id: ...)` 精准清理,或通过 `all: true, confirm: true` 全量清空。',
62
+ ].join('\n');
63
+ }
64
+ // 4. 兜底降级
65
+ return JSON.stringify(value, null, 2);
66
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 格式化 Codespace 状态徽标
3
+ */
4
+ export declare function formatCodespaceStateBadge(state?: string): string;
5
+ /**
6
+ * 渲染 Codespaces 列表表格
7
+ */
8
+ export declare function renderCodespaceList(items: any[]): string;
9
+ /**
10
+ * 渲染单个 Codespace 详情卡片
11
+ */
12
+ export declare function renderCodespaceView(cs: any): string;
13
+ /**
14
+ * Codespace 领域综合渲染入口
15
+ */
16
+ export declare function renderCodespaceMarkdown(args: any, value: any): string;
@@ -0,0 +1,103 @@
1
+ import { sanitizeCell } from './common.js';
2
+ import { renderScopeRequiredMarkdown } from './project.js';
3
+ /**
4
+ * 格式化 Codespace 状态徽标
5
+ */
6
+ export function formatCodespaceStateBadge(state) {
7
+ if (!state)
8
+ return '⚪ UNKNOWN';
9
+ const lower = state.toLowerCase();
10
+ if (lower === 'available')
11
+ return '🟢 AVAILABLE';
12
+ if (lower === 'shutdown')
13
+ return '⚪ SHUTDOWN';
14
+ if (lower.includes('start') || lower.includes('rebuild'))
15
+ return '🟡 STARTING';
16
+ if (lower.includes('updat') || lower.includes('export'))
17
+ return '🟡 BUSY';
18
+ return `⚪ ${state.toUpperCase()}`;
19
+ }
20
+ /**
21
+ * 渲染 Codespaces 列表表格
22
+ */
23
+ export function renderCodespaceList(items) {
24
+ const list = items.filter(Boolean);
25
+ if (list.length === 0) {
26
+ return '📭 暂无云端开发环境 (Codespaces)。';
27
+ }
28
+ const rows = list.map((cs) => {
29
+ const name = `\`${sanitizeCell(cs.name || '-', 25)}\``;
30
+ const displayName = sanitizeCell(cs.displayName || cs.name || '-', 25);
31
+ const repo = cs.repository ? `[${cs.repository}](https://github.com/${cs.repository})` : '-';
32
+ const stateBadge = formatCodespaceStateBadge(cs.state);
33
+ const machine = sanitizeCell(cs.machineDisplayName || cs.machineName || '-', 20);
34
+ const lastUsed = cs.lastUsedAt ? cs.lastUsedAt.split('T')[0] : '-';
35
+ return `| ${name} | ${displayName} | ${repo} | ${stateBadge} | ${machine} | ${lastUsed} |`;
36
+ });
37
+ return [
38
+ `**云端开发环境列表 (${list.length} 台):**\n`,
39
+ '| 实例标识 | 显示名称 | 关联仓库 | 运行状态 | 机器规格 | 上次使用 |',
40
+ '| :--- | :--- | :--- | :--- | :--- | :--- |',
41
+ ...rows,
42
+ ].join('\n');
43
+ }
44
+ /**
45
+ * 渲染单个 Codespace 详情卡片
46
+ */
47
+ export function renderCodespaceView(cs) {
48
+ if (!cs || typeof cs !== 'object') {
49
+ return '无云端环境详情数据';
50
+ }
51
+ const name = cs.displayName || cs.name || '未命名实例';
52
+ const stateBadge = formatCodespaceStateBadge(cs.state);
53
+ const repo = cs.repository ? `[${cs.repository}](https://github.com/${cs.repository})` : '-';
54
+ const owner = cs.owner || cs.billableOwner || '-';
55
+ const machine = cs.machineDisplayName || cs.machineName || '-';
56
+ const created = cs.createdAt || '-';
57
+ const lastUsed = cs.lastUsedAt || '-';
58
+ const lines = [
59
+ `### ☁️ Codespace: ${name}\n`,
60
+ `- **实例标识**: \`${cs.name || '-'}\``,
61
+ `- **运行状态**: ${stateBadge}`,
62
+ `- **关联仓库**: ${repo}`,
63
+ `- **所有者**: @${owner}`,
64
+ `- **机器规格**: ${machine}`,
65
+ `- **空闲停机**: ${cs.idleTimeoutMinutes ? `${cs.idleTimeoutMinutes} 分钟` : '默认'}`,
66
+ `- **创建时间**: ${created}`,
67
+ `- **上次活跃**: ${lastUsed}`,
68
+ ];
69
+ if (cs.devcontainerPath) {
70
+ lines.push(`- **容器配置**: \`${cs.devcontainerPath}\``);
71
+ }
72
+ return lines.join('\n');
73
+ }
74
+ /**
75
+ * Codespace 领域综合渲染入口
76
+ */
77
+ export function renderCodespaceMarkdown(args, value) {
78
+ if (!value)
79
+ return '无返回内容';
80
+ if (value.status === 'SCOPE_REQUIRED') {
81
+ return renderScopeRequiredMarkdown(value);
82
+ }
83
+ if (value.status === 'AWAITING_CONFIRMATION') {
84
+ return [
85
+ `> ### ${value.warning || '⚠️ 操作确认拦截'}`,
86
+ `> - **影响评估**: ${value.impact || ''}`,
87
+ `> - **确认指引**: ${value.requiredAction || '如确认继续,请在参数中附加 `confirm: true` 重新调用。'}`,
88
+ ].join('\n');
89
+ }
90
+ if (typeof value.result === 'string')
91
+ return value.result;
92
+ if (typeof value.message === 'string' && !value.items) {
93
+ const extra = value.detail || value.output;
94
+ return `**${value.message}**` + (extra ? `\n\`\`\`\n${extra}\n\`\`\`` : '');
95
+ }
96
+ if (Array.isArray(value.items) && args?.action === 'list') {
97
+ return renderCodespaceList(value.items);
98
+ }
99
+ if (args?.action === 'view' || value.name) {
100
+ return renderCodespaceView(value);
101
+ }
102
+ return JSON.stringify(value, null, 2);
103
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * DSH GitHub Flow - 通用 Markdown 格式化原子工具与状态徽章
3
+ */
4
+ /** 安全清洗表格单元格文本:转义竖线,压缩换行,限制最大长度 */
5
+ export declare function sanitizeCell(text: any, maxLen?: number): string;
6
+ /** 格式化 PR / Issue 状态药丸徽章 */
7
+ export declare function formatStateBadge(state?: string, isDraft?: boolean): string;
8
+ /**
9
+ * 格式化 CI 工作流状态徽章。
10
+ * 第二参数按调用域语义不同:run 域传 conclusion(success/failure/cancelled/skipped),
11
+ * pr checks 域传 bucket(pass/fail/pending/skipping/cancel)——取值族不同但映射到
12
+ * 同一组徽章;state 参数兜底(in_progress/queued 等进行中态)。
13
+ */
14
+ export declare function formatCiBadge(status?: string, conclusion?: string): string;
15
+ /** 格式化合并冲突状态 */
16
+ export declare function formatConflictBadge(status?: string): string;
17
+ /** 格式化 Release 状态徽章 */
18
+ export declare function formatReleaseBadge(isDraft?: boolean, isPrerelease?: boolean): string;
19
+ /**
20
+ * 降级链路可见标注(runGuarded 契约的渲染兑现)。
21
+ * 为什么必须可见:降级若是静默的,Agent 就无法感知能力边界(同一 action 在
22
+ * 不同 gh 版本上走不同链路);一条 blockquote 注释成本一行,换链路透明。
23
+ */
24
+ export declare function appendDegradedNote(value: any): string;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * DSH GitHub Flow - 通用 Markdown 格式化原子工具与状态徽章
3
+ */
4
+ /** 安全清洗表格单元格文本:转义竖线,压缩换行,限制最大长度 */
5
+ export function sanitizeCell(text, maxLen = 80) {
6
+ if (text === null || text === undefined || text === '')
7
+ return '-';
8
+ const clean = String(text)
9
+ .replace(/\|/g, '\\|')
10
+ .replace(/[\r\n]+/g, ' ')
11
+ .trim();
12
+ if (clean.length > maxLen) {
13
+ return clean.slice(0, maxLen - 1) + '…';
14
+ }
15
+ return clean || '-';
16
+ }
17
+ /** 格式化 PR / Issue 状态药丸徽章 */
18
+ export function formatStateBadge(state, isDraft) {
19
+ if (!state)
20
+ return '-';
21
+ const s = state.toUpperCase();
22
+ if (isDraft)
23
+ return '⚪ DRAFT';
24
+ if (s === 'OPEN')
25
+ return '🟢 OPEN';
26
+ if (s === 'MERGED')
27
+ return '🟣 MERGED';
28
+ if (s === 'CLOSED')
29
+ return '🔴 CLOSED';
30
+ return s;
31
+ }
32
+ /**
33
+ * 格式化 CI 工作流状态徽章。
34
+ * 第二参数按调用域语义不同:run 域传 conclusion(success/failure/cancelled/skipped),
35
+ * pr checks 域传 bucket(pass/fail/pending/skipping/cancel)——取值族不同但映射到
36
+ * 同一组徽章;state 参数兜底(in_progress/queued 等进行中态)。
37
+ */
38
+ export function formatCiBadge(status, conclusion) {
39
+ const conc = (conclusion || '').toLowerCase();
40
+ const st = (status || '').toLowerCase();
41
+ if (conc === 'success' || conc === 'pass')
42
+ return '✅ ' + conc;
43
+ if (conc === 'failure' || conc === 'fail')
44
+ return '❌ ' + conc;
45
+ if (conc === 'cancelled' || conc === 'cancel')
46
+ return '🚫 ' + conc;
47
+ if (conc === 'skipped' || conc === 'skipping')
48
+ return '⏭️ ' + conc;
49
+ if (conc === 'pending')
50
+ return '⏳ pending';
51
+ if (st === 'in_progress')
52
+ return '⏳ running';
53
+ if (st === 'queued')
54
+ return '⏱️ queued';
55
+ return conc || st || '-';
56
+ }
57
+ /** 格式化合并冲突状态 */
58
+ export function formatConflictBadge(status) {
59
+ if (!status)
60
+ return '-';
61
+ const s = status.toUpperCase();
62
+ if (s === 'CLEAN')
63
+ return '✅ CLEAN';
64
+ if (s === 'DIRTY' || s === 'CONFLICT')
65
+ return '⚠️ CONFLICT';
66
+ if (s === 'BLOCKED')
67
+ return '⛔ BLOCKED';
68
+ return s;
69
+ }
70
+ /** 格式化 Release 状态徽章 */
71
+ export function formatReleaseBadge(isDraft, isPrerelease) {
72
+ if (isDraft)
73
+ return '⚪ DRAFT';
74
+ if (isPrerelease)
75
+ return '🍼 PRE';
76
+ return '✅ STABLE';
77
+ }
78
+ /**
79
+ * 降级链路可见标注(runGuarded 契约的渲染兑现)。
80
+ * 为什么必须可见:降级若是静默的,Agent 就无法感知能力边界(同一 action 在
81
+ * 不同 gh 版本上走不同链路);一条 blockquote 注释成本一行,换链路透明。
82
+ */
83
+ export function appendDegradedNote(value) {
84
+ if (value && value.degraded === true && value.degradedReason) {
85
+ return `\n\n> ⚠️ ${value.degradedReason}`;
86
+ }
87
+ return '';
88
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 格式化 Discussion 状态徽标
3
+ */
4
+ export declare function formatDiscussionStateBadge(state?: string, answered?: boolean, closed?: boolean): string;
5
+ /**
6
+ * 渲染 Discussion 列表表格
7
+ */
8
+ export declare function renderDiscussionList(items: any[]): string;
9
+ /**
10
+ * 渲染单个 Discussion 详情卡片
11
+ */
12
+ export declare function renderDiscussionView(d: any): string;
13
+ /**
14
+ * Discussion 领域综合渲染入口
15
+ */
16
+ export declare function renderDiscussionMarkdown(args: any, value: any): string;