fix: bound github issue comment views (#915)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-26 00:57:39 +08:00
committed by GitHub
parent 29f80935bf
commit 08e6ee575b
7 changed files with 77 additions and 12 deletions
+6 -2
View File
@@ -94,7 +94,7 @@ bun scripts/cli.ts gh issue view <number|url|owner/repo#number> \
`read` 是兼容别名。支持 `owner/repo#number` shorthand(如 `pikasTech/HWLAB#1024`)。
人工读取 issue/PR 正文优先走 `trans gh:/owner/repo/issue/<number> cat|rg``trans gh:/owner/repo/pr/<number> cat|rg``gh issue view/read` 主要保留为结构化 JSON 底座、metadata 读取和兼容入口。
`--json comments` 默认只返回 comment id、URL、作者、时间、正文字符数、body SHA 和短 preview完整 comment body 只在显式 `--full`/`--raw``trans gh:` drill-down 下读取。显式 `--json` 路径的 comments 位于 `.data.json.comments`,不要依赖顶层重复 comments。
`--json comments` 默认只返回 comment id、URL、作者、时间、正文字符数、body SHA 和短 preview`--full` 仍保持评论列表有界,只有 `--raw` 会显式展开所有评论正文。读取单条完整 comment body 使用 `gh issue comment view <commentId> --full`显式 `--json` 路径的 comments 位于 `.data.json.comments`,不要依赖顶层重复 comments。
### 创建
@@ -165,6 +165,10 @@ bun scripts/cli.ts gh issue comment create <number|owner/repo#number> \
评论正文
EOF
# 读取单条评论
bun scripts/cli.ts gh issue comment view <commentId> \
--repo owner/name [--full|--raw]
# 原地修正评论
bun scripts/cli.ts gh issue comment update <commentId> \
--repo owner/name --body-stdin <<'EOF'
@@ -186,7 +190,7 @@ PATCH
bun scripts/cli.ts gh issue comment delete <commentId>
```
`edit``comment update` 的兼容别名。`--body <short-text>` 仅适合短单行。日常修正文案优先用 `patch``update/edit` 保留评论 ID 和时间线;`delete` 只用于确实需要删除的评论。`comment patch` 会先读取 comment id 对应的当前正文,把 envelope 应用到虚拟文件 `comment.md`,再 PATCH 单条评论;上下文不匹配时失败且不写入。
`view` 默认返回 comment id、URL、作者、时间、正文字符数、body SHA 和短 preview`--full` 只展开这一条 comment body。`edit``comment update` 的兼容别名。`--body <short-text>` 仅适合短单行。日常修正文案优先用 `patch``update/edit` 保留评论 ID 和时间线;`delete` 只用于确实需要删除的评论。`comment patch` 会先读取 comment id 对应的当前正文,把 envelope 应用到虚拟文件 `comment.md`,再 PATCH 单条评论;上下文不匹配时失败且不写入。
评论区不要写新的大计划。若评论草稿已经包含多阶段计划、改进清单或验收标准,改为创建新 issue,并在评论中只留下新 issue 链接和短结论。
+1 -1
View File
@@ -169,7 +169,7 @@ UniDesk/HWLAB Web 开发、Playwright wrapper、`trans <route> playwright`、HWL
诊断命令默认采用渐进披露:`server logs``job list/status``codex task/trace/output``microservice health code-queue``microservice proxy` 和 AgentRun control-plane/resource primitive 都必须有默认条数、字节数、表格或文本预览上限;用户显式传 `--limit``--tail-bytes``--full-text``--raw``--full``-o json` 或等价机器消费参数才扩大单次输出。AgentRun `control-plane plan|refresh|cleanup-runners|trigger-current` 默认输出短摘要、关键字段和下一步命令;`describe task -o json` 默认仍是 compact client schema,完整资源用 `--full -o json``result --raw` 属于显式 raw 路径,可以触发 dump 兜底。CLI stdout 遇到下游 pipe 关闭的 `EPIPE` 必须安静退出,不得打印 Bun stack trace。
`gh issue view/read --json comments` 是常用人工 drill-down,不得默认输出完整 comment body 或同时在顶层和 `.data.json.comments` 重复整组 comments。默认只返回 comment metadata、body 字符数/SHA 和短 preview完整正文通过显式 `--full``--raw``trans gh:/owner/repo/issue/<number> cat|rg` 读取
`gh issue view/read --json comments` 是常用人工 drill-down,不得默认输出完整 comment body 或同时在顶层和 `.data.json.comments` 重复整组 comments。默认只返回 comment metadata、body 字符数/SHA 和短 preview`--full` 仍保持评论列表有界,只把 issue 字段扩到完整元数据。单条完整评论正文通过 `gh issue comment view <commentId> --repo owner/name --full` 读取;`--raw` 才是显式展开所有评论正文的排障入口,可能触发 stdout dump
`microservice proxy` 是面向人工验证和受控调试的私有后端入口。默认 method 为 GET;使用 `--body-json JSON``--body-file path``--body-stdin` 时默认 method 切换为 POST,也可显式加 `--method POST|PUT|PATCH|DELETE`,但 GET/HEAD 不允许携带请求体。所有请求仍受 config 中的 `allowedMethods``allowedPathPrefixes` 限制。为了避免 Pipeline snapshot 这类超大业务 JSON 造成 CLI 输出爆炸,响应 body 超过默认阈值时会返回 `bodyOmitted=true``bodyPreview``bodyBytes``rawHint``--raw` 仍受默认硬限额保护,需要完整 body 时显式添加 `--raw --full`,或用 `--max-body-bytes <N>` 调整预览阈值。正式 frontend 展示仍应优先使用业务控件和 `__unideskArrayLimit` 这类展示级裁剪参数,而不是默认倾倒完整 JSON。
+1
View File
@@ -363,6 +363,7 @@ export function issueBodyReadCommands(repo: string, issueNumber: number): Record
export function issueCommentReadCommands(repo: string, issueNumber: number): Record<string, string> {
return {
comments: `bun scripts/cli.ts gh issue view ${issueNumber} --repo ${repo} --json comments`,
comment: `bun scripts/cli.ts gh issue comment view <commentId> --repo ${repo} --full`,
full: `bun scripts/cli.ts gh issue view ${issueNumber} --repo ${repo} --full`,
raw: `bun scripts/cli.ts gh issue view ${issueNumber} --repo ${repo} --raw`,
};
+28
View File
@@ -256,6 +256,34 @@ export async function commentUpdate(repo: string, token: string, ownerKind: "iss
};
}
export async function commentView(repo: string, token: string, ownerKind: "issue" | "pr", commentId: number, includeBody: boolean, commandName?: string): Promise<GitHubCommandResult> {
const command = commandName ?? `${ownerKind} comment view`;
const comment = await getIssueComment(token, repo, commentId);
if (isGitHubError(comment)) return commandError(command, repo, comment, { commentId });
const body = comment.body ?? "";
return {
ok: true,
command,
repo,
commentId,
comment: includeBody ? commentSummary(comment) : compactCommentSummary(comment),
bodyChars: body.length,
bodySha: bodySha(body),
bodyOmitted: !includeBody,
fullBodyIncluded: includeBody,
readCommands: {
compact: `bun scripts/cli.ts gh ${ownerKind} comment view ${commentId} --repo ${repo}`,
full: `bun scripts/cli.ts gh ${ownerKind} comment view ${commentId} --repo ${repo} --full`,
raw: `bun scripts/cli.ts gh ${ownerKind} comment view ${commentId} --repo ${repo} --raw`,
},
request: {
method: "GET",
path: `/repos/{owner}/{repo}/issues/comments/${commentId}`,
},
rest: true,
};
}
export async function commentDelete(repo: string, token: string, ownerKind: "issue" | "pr", commentId: number, dryRun: boolean): Promise<GitHubCommandResult> {
const command = `${ownerKind} comment delete`;
const { owner, name } = repoParts(repo);
+7 -3
View File
@@ -23,6 +23,7 @@ export function ghHelp(): unknown {
"bun scripts/cli.ts gh issue edit <number> (--body-stdin|--body-file <file|->) [--repo owner/name] [--number N compat] [--full|--raw] [compat alias for issue update --mode replace]",
"bun scripts/cli.ts gh issue edit 24 --body-stdin --notify-claudeqq-brief-diff [--dry-run]",
"bun scripts/cli.ts gh issue comment create <number> (--body-stdin|--body-file <file|->|--body <short-text>) [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh issue comment view|read <commentId> [--repo owner/name] [--number N compat] [--full|--raw]",
"bun scripts/cli.ts gh issue comment update <commentId> (--body-stdin|--body-file <file|->|--body <short-text>) [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh issue comment patch <commentId> --body-patch-stdin [--repo owner/name] [--number N compat] [--dry-run] [--expect-updated-at ts|--expect-body-sha sha256]",
"bun scripts/cli.ts gh issue comment edit <commentId> (--body-stdin|--body-file <file|->|--body <short-text>) [--repo owner/name] [--number N compat] [--dry-run] [compatibility alias for issue comment update]",
@@ -52,6 +53,7 @@ export function ghHelp(): unknown {
"bun scripts/cli.ts gh pr edit <number> [--title title] [--body-stdin|--body-file <file|->|--body <text>] [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh pr update <number> --mode replace|append [--body-stdin|--body-file <file|->|--body <text>] [--title title] [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh pr comment create <number> (--body-stdin|--body-file <file|->|--body <text>) [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh pr comment view|read <commentId> [--repo owner/name] [--number N compat] [--full|--raw]",
"bun scripts/cli.ts gh pr comment update <commentId> (--body-stdin|--body-file <file|->|--body <text>) [--repo owner/name] [--number N compat] [--dry-run]",
"bun scripts/cli.ts gh pr comment edit <commentId> (--body-stdin|--body-file <file|->|--body <text>) [--repo owner/name] [--number N compat] [--dry-run] [compatibility alias for pr comment update]",
"bun scripts/cli.ts gh pr comment delete <commentId> [--repo owner/name] [--number N compat] [--dry-run]",
@@ -67,9 +69,9 @@ export function ghHelp(): unknown {
"issue list and pr list accept a single positional owner/repo as a compatibility alias for --repo owner/name. The positional repo and --repo must match if both are supplied; non-repo positionals fail structurally instead of falling back to the default repo.",
"issue list defaults to --state open and bounded --limit 30; it paginates GitHub REST/Search pages internally when --limit exceeds GitHub's per-page cap and discloses pagination/rawCount/hasMore so operators do not mistake a single page for the full repository. --search uses GitHub Search Issues API with repo/type/state qualifiers for low-friction dedupe lookup before creating a new issue. --title-prefix filters the bounded listed issues locally by exact title startsWith, useful for [FEEDBACK] dedupe, and reports titleFilter input/output counts. Supported --json fields are number,title,state,closed,closedAt,url,updatedAt,createdAt,author,labels and unknown fields fail structurally.",
"PR list defaults to --state all for compatibility with earlier UniDesk CLI behavior; supported states are open, closed, and all.",
"issue view is the canonical GitHub CLI-compatible read path; read remains a UniDesk compatibility alias. View/read accept positional numbers, GitHub issue URLs, and owner/repo#number shorthand, deriving --repo unless an explicit conflicting --repo is supplied. --number is accepted on single issue/comment numeric target commands for low-friction compatibility and returns a standard syntax hint; list/create/scan-escape/cleanup-plan/board-audit/board-row list do not accept it. Comment delete treats --number as commentId, not an issue number. View supports lifecycle fields closed/closedAt plus legacy --json field selection; explicit --json fields limit output even with --raw/--full; full body is included only when requested with --json body or when --json is omitted and --full/--raw requests all fields. Unsupported fields fail structurally.",
"issue view is the canonical GitHub CLI-compatible read path; read remains a UniDesk compatibility alias. View/read accept positional numbers, GitHub issue URLs, and owner/repo#number shorthand, deriving --repo unless an explicit conflicting --repo is supplied. --number is accepted on single issue/comment numeric target commands for low-friction compatibility and returns a standard syntax hint; list/create/scan-escape/cleanup-plan/board-audit/board-row list do not accept it. Comment view/read/update/edit/delete treat --number as commentId, not an issue number. View supports lifecycle fields closed/closedAt plus legacy --json field selection; explicit --json fields limit output even with --raw/--full; full issue body is included only when requested with --json body or when --json is omitted and --full/--raw requests all fields. Comment lists always stay bounded except --raw; use gh issue comment view <commentId> --full for a single full comment body. Unsupported fields fail structurally.",
"issue attachment list/download scan issue body and comments for GitHub user attachment URLs (`https://github.com/user-attachments/assets/...`). list is read-only and returns bounded attachment metadata. download writes the selected attachment to --output or /tmp/unidesk-gh-attachments, returns bytes/SHA-256/content-type/path, redacts redirected signed URL query parameters, and never prints binary bytes.",
"--raw and --full are explicit full-disclosure aliases for gh issue list/read/view/update/edit/patch and gh pr list/read/view. For read/view commands, an explicit --json field list narrows the disclosure and prevents accidental full body/comment expansion. For issue writes, default success output omits full issue.body and returns bodyChars/bodySha/bodyPreview plus readCommands; --full|--raw includes the full returned issue body only on commands that explicitly support full disclosure.",
"--raw and --full are explicit full-disclosure aliases for gh issue list/read/view/update/edit/patch/comment view and gh pr list/read/view/comment view. For issue read/view commands, --full expands issue fields but keeps comment lists bounded; --raw is the explicit all-comment-body escape hatch. Use issue comment view <commentId> --full for a single full comment body. For issue writes, default success output omits full issue.body and returns bodyChars/bodySha/bodyPreview plus readCommands; --full|--raw includes the full returned issue body only on commands that explicitly support full disclosure.",
"CLI output larger than config/unidesk-cli.yaml output.maxStdoutBytes is automatically written to /tmp/unidesk-cli-output; stdout stays bounded with outputTruncated=true, warning text, dump file metadata, and drill-down read commands.",
"issue create accepts --body-stdin or --body-file <file|-> plus repeatable --label values and comma-separated labels; inline --body is intentionally unsupported for issue creation. Dry-run prints the parsed labels and non-dry-run sends them in the GitHub REST create-issue payload.",
"--body-stdin is the first-class heredoc/stdin source for Markdown bodies. Use quoted heredoc syntax such as bun scripts/cli.ts gh issue comment create 1 --body-stdin <<'EOF' so real newlines, backticks, and tables are read as stdin bytes instead of shell arguments.",
@@ -78,7 +80,7 @@ export function ghHelp(): unknown {
"issue update accepts --body-stdin or --body-file <file|->, refuses literal null, blank, and too-short bodies by default. Use --allow-short-body only for intentional short writes; #20 requires its board heading, warns when HWLAB product/user issue routing appears in favor of pikasTech/HWLAB, and still rejects commander brief update sections; commander-brief requires its stable heading on legacy #24 plus daily rolling brief issues titled YYYY-MM-DD 指挥简报(北京时间).",
"issue update dry-run reports bounded bodyPreview/bodyPreviewLines, old/new body length slots, body SHA, required heading checks, literal \\n detection, shell-pollution signals, guard/concurrency summary, wouldPatch, and readCommands without printing an unbounded full body. Non-dry-run automatically reads current issue metadata before PATCH and returns oldBodySha/updatedAt; --expect-updated-at or --expect-body-sha remain available for explicit stale-cache protection.",
"issue patch reads the current GitHub issue body, applies a Codex apply_patch envelope against virtual file issue.md from --body-patch-stdin or --body-patch-file <file|->, then runs the same issue body guard before PATCH. It returns old/new bodySha, updatedAt, patch summary, and bounded previews; context mismatch fails with redacted diagnostics and no GitHub write.",
"issue comment create/update/edit accept --body-stdin or --body-file <file|-> for Markdown/generated content and --body only for short single-line text. Blank, multiline, shell-polluted, secret-like, and overlong inline bodies fail structurally. Use comment update/edit to correct existing wording in place; delete remains for intentional removal.",
"issue comment view/read reads one comment by commentId. Default output is compact metadata plus bodyChars/bodySha/preview; --full includes that one full comment body. issue comment create/update/edit accept --body-stdin or --body-file <file|-> for Markdown/generated content and --body only for short single-line text. Blank, multiline, shell-polluted, secret-like, and overlong inline bodies fail structurally. Use comment update/edit to correct existing wording in place; delete remains for intentional removal.",
"issue comment patch reads the current issue comment by commentId, applies a Codex apply_patch envelope against virtual file comment.md, then PATCHes only that comment. It returns comment id, old/new bodySha, updatedAt, patch summary, and redacted mismatch diagnostics without echoing the full comment body.",
"issue close/reopen default success output is compact and omits full issue.body. Optional --comment <short-text>, --comment-stdin, or --comment-file <file|-> posts a bounded lifecycle comment before the state change and aborts the state change if the comment POST fails. --comment-stdin is the first-class heredoc path for generated Markdown closeout evidence; --comment remains the short inline form. Use gh issue view <number> --json body or --full/--raw on view when full text is needed.",
"issue stale-close is the reusable lifecycle cleanup path for policies such as closing open issues inactive for more than 48 hours. It selects open issues by GitHub updatedAt older than observedAt - --inactive-hours, treats comments and state changes as activity, filters pull requests, supports --dry-run, and returns bounded candidate/closed/failure summaries without echoing full bodies.",
@@ -150,12 +152,14 @@ export function ghScopedHelpNotes(tokens: string[]): string[] {
];
if (key === "issue comment" || key.startsWith("issue comment ")) {
notes.push("Issue comments use `--body-stdin` or `--body-file <file|->` for Markdown bodies; inline `--body` is only for short single-line comments.");
notes.push("Use `issue comment view <commentId> --full` to read one full comment body; issue-level `--json comments --full` keeps the comment list bounded.");
notes.push("Use `issue comment update/edit` for wording fixes, `issue comment patch` for apply_patch-style local edits, and `issue comment delete` only for intentional removal.");
} else if (key === "issue close" || key === "issue reopen") {
notes.push("Issue close/reopen can post a lifecycle comment with `--comment`, `--comment-stdin`, or `--comment-file <file|->` before changing state.");
notes.push("For long closeout evidence, prefer `--comment-stdin` with a quoted heredoc.");
} else if (key === "pr comment" || key.startsWith("pr comment ")) {
notes.push("PR comments are GitHub issue comments under the hood; use comment id targets for update/edit/delete.");
notes.push("Use `pr comment view <commentId> --full` to read one full comment body by id.");
} else if (key === "pr merge") {
notes.push("PR merge is one-command guarded: it performs the readiness check itself; `gh pr preflight` is optional read-only diagnosis, not a required first step.");
notes.push("When GitHub reports mergeability as UNKNOWN/null, merge automatically retries with YAML-configured exponential backoff and shows retry attempts as N/M.");
+28 -5
View File
@@ -7,7 +7,7 @@ import { authStatus, prFiles, prList, prRead, prView } from "./auth-pr-read";
import { issueBoardAudit } from "./board-audit";
import { issueBoardRowAdd, issueBoardRowDelete, issueBoardRowGet, issueBoardRowList, issueBoardRowMove, issueBoardRowUpdate, issueBoardRowUpsert } from "./board-commands";
import { authRequired, unsupportedCommand, validationError } from "./client";
import { commentDelete, commentPatch, commentUpdate, issueComment, issueState } from "./comments-and-state";
import { commentDelete, commentPatch, commentUpdate, commentView, issueComment, issueState } from "./comments-and-state";
import { issueScanEscape } from "./escape-scan";
import { ghHelp, ghScopedHelp } from "./help";
import { issueList } from "./issue-list";
@@ -53,13 +53,16 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
return validationError(command, options.repo, "--json field selection is only supported by gh issue read/view/list and gh pr read/view/list");
}
}
if ((optionWasProvided(args, "--raw") || optionWasProvided(args, "--full")) && !((top === "issue" && (isIssueReadCommand(sub) || sub === "list" || sub === "update" || sub === "edit" || sub === "patch")) || top === "preflight" || (top === "pr" && (isPrReadCommand(sub) || sub === "list" || sub === "preflight" || sub === "closeout")))) {
const isIssueCommentReadCommand = top === "issue" && sub === "comment" && (third === "view" || third === "read");
const isPrCommentReadCommand = top === "pr" && sub === "comment" && (third === "view" || third === "read");
if ((optionWasProvided(args, "--raw") || optionWasProvided(args, "--full")) && !((top === "issue" && (isIssueReadCommand(sub) || sub === "list" || sub === "update" || sub === "edit" || sub === "patch")) || isIssueCommentReadCommand || top === "preflight" || (top === "pr" && (isPrReadCommand(sub) || sub === "list" || sub === "preflight" || sub === "closeout")) || isPrCommentReadCommand)) {
const command = [top, sub].filter((value): value is string => value !== undefined).join(" ") || "gh";
return validationError(command, options.repo, "--raw and --full are explicit full-disclosure aliases only for gh issue list/read/view/update/edit/patch, gh pr list/read/view, and gh pr preflight/closeout.", {
return validationError(command, options.repo, "--raw and --full are explicit full-disclosure aliases only for gh issue list/read/view/update/edit/patch/comment view, gh pr list/read/view/comment view, and gh pr preflight/closeout.", {
supportedCommands: [
"bun scripts/cli.ts gh issue list --repo owner/name --limit 200 --full",
"bun scripts/cli.ts gh issue view owner/name#<number> --raw",
"bun scripts/cli.ts gh issue view <number> --repo owner/name --json body,title,state,comments",
"bun scripts/cli.ts gh issue comment view <commentId> --repo owner/name --full",
"bun scripts/cli.ts gh issue update <number> --repo owner/name --body-stdin --full <<'EOF'\n<reviewed body>\nEOF",
"bun scripts/cli.ts gh issue patch <number> --repo owner/name --body-patch-stdin --full <<'PATCH'\n*** Begin Patch\n*** Update File: issue.md\n@@\n-old\n+new\n*** End Patch\nPATCH",
"bun scripts/cli.ts gh pr list --repo owner/name --limit 100 --full",
@@ -226,6 +229,17 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
if (action === "list") return withNumberOptionHint(issueAttachmentList(resolved.repo, token, resolved.number), resolved);
return withNumberOptionHint(issueAttachmentDownload(resolved.repo, token, resolved.number, { ...options, repo: resolved.repo }), resolved);
}
if (sub === "comment" && (third === "view" || third === "read")) {
const commandName = `issue comment ${third}`;
const resolved = resolvePositionalNumberReference("issue", args, 3, commandName, options);
if (isGitHubCommandResult(resolved)) return resolved;
const commentId = resolved.number;
if (typeof commentId !== "number") return commentId;
const { token, probe } = resolveToken(true);
const missing = authRequired(resolved.repo, commandName, probe);
if (missing !== null || token === null) return missing ?? authRequired(resolved.repo, commandName, { present: false, source: null, ghFallbackAttempted: true });
return withNumberOptionHint(commentView(resolved.repo, token, "issue", commentId, options.raw || options.full, commandName), resolved);
}
if (sub === "comment" && third === "delete") {
const resolved = resolvePositionalNumberReference("issue", args, 3, "issue comment delete", options);
if (isGitHubCommandResult(resolved)) return resolved;
@@ -354,8 +368,8 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
const missing = authRequired(resolved.repo, `issue ${sub}`, probe);
if (missing !== null || token === null) return missing ?? authRequired(resolved.repo, `issue ${sub}`, { present: false, source: null, ghFallbackAttempted: true });
const disclosure = readDisclosureOptions(options, resolved.shorthand);
if (sub === "read") return withNumberOptionHint(issueRead(resolved.repo, token, resolved.number, issueReadJsonFields(options), "issue read", disclosure, { includeFullCommentBodies: options.raw || options.full }), resolved);
return withNumberOptionHint(issueView(resolved.repo, token, resolved.number, issueReadJsonFields(options), disclosure, { includeFullCommentBodies: options.raw || options.full }), resolved);
if (sub === "read") return withNumberOptionHint(issueRead(resolved.repo, token, resolved.number, issueReadJsonFields(options), "issue read", disclosure, { includeFullCommentBodies: options.raw }), resolved);
return withNumberOptionHint(issueView(resolved.repo, token, resolved.number, issueReadJsonFields(options), disclosure, { includeFullCommentBodies: options.raw }), resolved);
}
const { token, probe } = resolveToken(true);
const missing = authRequired(options.repo, `issue ${sub ?? ""}`.trim(), probe);
@@ -432,6 +446,15 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
if (missing !== null || token === null) return missing ?? authRequired(resolved.repo, "pr comment delete", { present: false, source: null, ghFallbackAttempted: true });
return withNumberOptionHint(commentDelete(resolved.repo, token, "pr", resolved.number, false), resolved);
}
if (sub === "comment" && (third === "view" || third === "read")) {
const commandName = `pr comment ${third}`;
const resolved = resolvePositionalNumberReference("pr", args, 3, commandName, options);
if (isGitHubCommandResult(resolved)) return resolved;
const { token, probe } = resolveToken(true);
const missing = authRequired(resolved.repo, commandName, probe);
if (missing !== null || token === null) return missing ?? authRequired(resolved.repo, commandName, { present: false, source: null, ghFallbackAttempted: true });
return withNumberOptionHint(commentView(resolved.repo, token, "pr", resolved.number, options.raw || options.full, commandName), resolved);
}
if (sub === "comment" && (third === "update" || third === "edit")) {
const commandName = `pr comment ${third}`;
const resolved = resolvePositionalNumberReference("pr", args, 3, commandName, options);
+6 -1
View File
@@ -5,13 +5,18 @@ import { bodySha, preview, previewLines } from "./auth-and-safety";
import type { GitHubComment } from "./types";
export function commentSummary(comment: GitHubComment): Record<string, unknown> {
const body = comment.body ?? "";
return {
id: comment.id,
body: comment.body ?? "",
body,
url: comment.html_url,
author: comment.user?.login ?? null,
createdAt: comment.created_at ?? null,
updatedAt: comment.updated_at ?? null,
bodyChars: body.length,
bodySha: bodySha(body),
bodyOmitted: false,
fullBodyIncluded: true,
};
}