Merge pull request #1530 from pikasTech/fix/issue-1529-gh-comments
fix: add bounded gh issue comments command
This commit is contained in:
@@ -26,6 +26,7 @@ bun scripts/cli.ts gh auth status --repo pikasTech/unidesk
|
||||
bun scripts/cli.ts gh issue list --repo pikasTech/unidesk --state open --limit 30
|
||||
bun scripts/cli.ts gh issue view <number> --repo pikasTech/unidesk
|
||||
bun scripts/cli.ts gh issue view <number> --repo pikasTech/unidesk --json body,title,state
|
||||
bun scripts/cli.ts gh issue comments <number> --repo pikasTech/unidesk --limit 8
|
||||
bun scripts/cli.ts gh issue create --repo pikasTech/unidesk --title "标题" --body-stdin
|
||||
bun scripts/cli.ts gh pr list --repo pikasTech/unidesk --state all --limit 10
|
||||
bun scripts/cli.ts gh pr review-plan <number> --repo pikasTech/unidesk
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Issue writes use `bun scripts/cli.ts gh ...` or the `trans gh:` virtual filesystem.
|
||||
|
||||
- Body and comments default to Chinese.
|
||||
- Recent issue comment progress should prefer `bun scripts/cli.ts gh issue comments <number> --repo owner/name [--limit N] [--full|--raw]`; structured output is stable at `.data.comments`.
|
||||
- New issues include `目标合并分支`.
|
||||
- Multi-stage architecture/API/platform issues begin with `P0 SPEC 先行`.
|
||||
- Long body text uses `--body-stdin`.
|
||||
|
||||
@@ -362,10 +362,11 @@ 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`,
|
||||
comments: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo}`,
|
||||
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`,
|
||||
full: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo} --full`,
|
||||
raw: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo} --raw`,
|
||||
issue: `bun scripts/cli.ts gh issue view ${issueNumber} --repo ${repo}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ function renderGhDefaultText(result: GitHubCommandResult): string {
|
||||
if (result.ok === false) return renderGhError(result);
|
||||
const command = result.command;
|
||||
if (isIssueReadResult(result)) return renderIssueView(result);
|
||||
if (command === "issue comments") return renderIssueComments(result);
|
||||
if (isPrReadResult(result)) return renderPrView(result);
|
||||
if (command === "pr list") return renderPrList(result);
|
||||
if (command === "pr files" || command === "pr diff --stat") return renderPrFiles(result);
|
||||
@@ -138,6 +139,7 @@ function renderIssueView(result: GitHubCommandResult): string {
|
||||
` author=${ghText(issue.author)} bodySha=${ghText(issue.bodySha)} bodyPreview=${body.preview}`,
|
||||
"",
|
||||
"Next:",
|
||||
` ${ghText(readCommands.comments ?? `bun scripts/cli.ts gh issue comments ${number} --repo ${result.repo}`)}`,
|
||||
` ${ghText(readCommands.body ?? `bun scripts/cli.ts gh issue view ${number} --repo ${result.repo} --json body`)}`,
|
||||
` ${ghText(readCommands.full ?? `bun scripts/cli.ts gh issue view ${number} --repo ${result.repo} --full`)}`,
|
||||
"",
|
||||
@@ -147,6 +149,39 @@ function renderIssueView(result: GitHubCommandResult): string {
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function renderIssueComments(result: GitHubCommandResult): string {
|
||||
const issue = record(result.issue);
|
||||
const comments = arrayOfRecords(result.comments);
|
||||
const commentRange = record(result.commentRange);
|
||||
const readCommands = record(result.readCommands);
|
||||
const rows = comments.slice(0, 40).map((comment) => [
|
||||
ghText(comment.id),
|
||||
ghText(comment.author),
|
||||
shortDate(comment.createdAt),
|
||||
ghShort(ghText(comment.url), 40),
|
||||
ghShort(previewFrom(comment), 72),
|
||||
]);
|
||||
const lines = [
|
||||
"gh issue comments (observed)",
|
||||
"",
|
||||
rows.length > 0
|
||||
? ghTable(["COMMENT", "AUTHOR", "CREATED", "URL", "PREVIEW"], rows)
|
||||
: "No comments found.",
|
||||
"",
|
||||
"Summary:",
|
||||
` repo=${ghText(result.repo)} issue=#${ghText(issue.number ?? result.issueNumber)} total=${ghText(result.totalComments)} returned=${ghText(result.returned)} omitted=${ghText(result.omitted)}`,
|
||||
` range=${ghText(commentRange.from)}..${ghText(commentRange.to)} title=${ghShort(ghText(issue.title), 96)}`,
|
||||
"",
|
||||
"Next:",
|
||||
` ${ghText(readCommands.full ?? `bun scripts/cli.ts gh issue comments ${ghText(issue.number ?? result.issueNumber)} --repo ${result.repo} --full`)}`,
|
||||
` ${ghText(readCommands.comment ?? `bun scripts/cli.ts gh issue comment view <commentId> --repo ${result.repo} --full`)}`,
|
||||
"",
|
||||
"Disclosure:",
|
||||
" default comments output is a bounded recent-comment table with body preview; use --full/--raw for structured full bodies.",
|
||||
];
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function renderPrView(result: GitHubCommandResult): string {
|
||||
const pr = record(result.pullRequest);
|
||||
const number = ghText(pr.number);
|
||||
|
||||
@@ -15,6 +15,7 @@ export function ghHelp(): unknown {
|
||||
"bun scripts/cli.ts gh issue list [owner/repo] [--state open|closed|all] [--limit N] [--search text] [--title-prefix text] [--label label[,label...]]... [--repo owner/name] [--json number,title,state,closed,closedAt,url,updatedAt,createdAt,author,labels] [--raw|--full]",
|
||||
"bun scripts/cli.ts gh issue view <number|url|owner/repo#number> [--repo owner/name] [--number N compat] [--json body,title,state,closed,closedAt,comments,commentCount] [--raw|--full]",
|
||||
"bun scripts/cli.ts gh issue read <number|url|owner/repo#number> [--repo owner/name] [--number N compat] [--raw|--full] [compatibility alias for issue view]",
|
||||
"bun scripts/cli.ts gh issue comments <number|url|owner/repo#number> [--repo owner/name] [--number N compat] [--limit N] [--full|--raw] [bounded recent comment progress path]",
|
||||
"bun scripts/cli.ts gh issue attachment list <number|url|owner/repo#number> [--repo owner/name] [--number N compat]",
|
||||
"bun scripts/cli.ts gh issue attachment download <number|url|owner/repo#number> [--repo owner/name] [--number N compat] [--attachment index|assetId|url] [--output path] [--dry-run]",
|
||||
"bun scripts/cli.ts gh issue create --title <title> (--body-stdin|--body-file <file|->) [--label label[,label...]]... [--repo owner/name] [--dry-run]",
|
||||
@@ -72,9 +73,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 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 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. For recent comment progress, prefer `gh issue comments <number>`: it defaults to a bounded recent-comment table and structured output lives at `.data.comments` instead of `.data.json.comments`. `gh issue view --json comments` remains the compatibility path. Use gh issue comment view <commentId> --full for one 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/comment view, gh pr list/read/view/comment view, and gh pr diff --file. 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.",
|
||||
"--raw and --full are explicit full-disclosure aliases for gh issue list/read/view/comments/update/edit/patch/comment view, gh pr list/read/view/comment view, and gh pr diff --file. For issue read/view commands, --full expands issue fields but keeps comment lists bounded; --raw is the explicit all-comment-body escape hatch. For `gh issue comments`, both --full and --raw keep the list bounded to recent comments and include full comment bodies in structured output. 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.",
|
||||
@@ -157,8 +158,11 @@ 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 view <commentId> --full` to read one full comment body; use `issue comments <number>` for the bounded recent-comment issue view.");
|
||||
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 comments") {
|
||||
notes.push("Use `issue comments <number>` as the low-friction recent-progress path; default output is bounded and structured output is at `.data.comments`.");
|
||||
notes.push("`--full` or `--raw` includes full bodies for the bounded recent list without changing the stable top-level `comments` path.");
|
||||
} 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.");
|
||||
|
||||
+12
-3
@@ -11,7 +11,7 @@ import { commentDelete, commentPatch, commentUpdate, commentView, issueComment,
|
||||
import { issueScanEscape } from "./escape-scan";
|
||||
import { ghHelp, ghScopedHelp } from "./help";
|
||||
import { issueList } from "./issue-list";
|
||||
import { issueRead, issueView } from "./issue-read";
|
||||
import { issueComments, issueRead, issueView } from "./issue-read";
|
||||
import { repoCreate, repoView } from "./issue-summary";
|
||||
import { issueCreate, issueEdit, issuePatch } from "./issue-write";
|
||||
import { allowsNumberTargetAlias, isIssueReadCommand, isPrReadCommand, optionValue, optionWasProvided, parseOptions } from "./options";
|
||||
@@ -57,12 +57,13 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
|
||||
const isIssueCommentReadCommand = top === "issue" && sub === "comment" && (third === "view" || third === "read");
|
||||
const isPrCommentReadCommand = top === "pr" && sub === "comment" && (third === "view" || third === "read");
|
||||
const isPrDiffFileCommand = top === "pr" && sub === "diff" && optionWasProvided(args, "--file");
|
||||
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 || isPrDiffFileCommand)) {
|
||||
if ((optionWasProvided(args, "--raw") || optionWasProvided(args, "--full")) && !((top === "issue" && (isIssueReadCommand(sub) || sub === "comments" || sub === "list" || sub === "update" || sub === "edit" || sub === "patch")) || isIssueCommentReadCommand || top === "preflight" || (top === "pr" && (isPrReadCommand(sub) || sub === "list" || sub === "preflight" || sub === "closeout")) || isPrCommentReadCommand || isPrDiffFileCommand)) {
|
||||
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/comment view, gh pr list/read/view/comment view, gh pr preflight/closeout, and gh pr diff --file.", {
|
||||
return validationError(command, options.repo, "--raw and --full are explicit full-disclosure aliases only for gh issue list/read/view/comments/update/edit/patch/comment view, gh pr list/read/view/comment view, gh pr preflight/closeout, and gh pr diff --file.", {
|
||||
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 comments <number> --repo owner/name --limit 8 --full",
|
||||
"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",
|
||||
@@ -306,6 +307,14 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
|
||||
if (missing !== null || token === null) return missing ?? authRequired(options.repo, "issue comment create", { present: false, source: null, ghFallbackAttempted: true });
|
||||
return withNumberOptionHint(issueComment(resolved.repo, token, issueNumber, { ...options, repo: resolved.repo }), resolved);
|
||||
}
|
||||
if (sub === "comments") {
|
||||
const resolved = resolvePositionalIssueReference(args, 2, "issue comments", options);
|
||||
if (isGitHubCommandResult(resolved)) return resolved;
|
||||
const { token, probe } = resolveToken(true);
|
||||
const missing = authRequired(resolved.repo, "issue comments", probe);
|
||||
if (missing !== null || token === null) return missing ?? authRequired(resolved.repo, "issue comments", { present: false, source: null, ghFallbackAttempted: true });
|
||||
return withNumberOptionHint(issueComments(resolved.repo, token, resolved.number, options.limit, { includeFullCommentBodies: options.full || options.raw }), resolved);
|
||||
}
|
||||
if (sub === "scan-escape" || sub === "cleanup-plan") {
|
||||
const { token, probe } = resolveToken(true);
|
||||
const commandName = sub === "cleanup-plan" ? "issue cleanup-plan" : "issue scan-escape";
|
||||
|
||||
@@ -10,9 +10,13 @@ import { commentSummary, compactCommentSummary, compactIssueViewCommentSummary }
|
||||
import { GITHUB_REST_PAGE_SIZE } from "./types";
|
||||
import type { GitHubCommandResult, GitHubComment, GitHubErrorPayload, GitHubIssue, GitHubIssueListPage, GitHubIssueListResult, GitHubIssueSearchResponse, IssueListState, IssueViewJsonField } from "./types";
|
||||
|
||||
export async function listIssueComments(token: string, repo: string, issueNumber: number): Promise<GitHubComment[] | GitHubErrorPayload> {
|
||||
export async function listIssueComments(token: string, repo: string, issueNumber: number, options: { page?: number; perPage?: number } = {}): Promise<GitHubComment[] | GitHubErrorPayload> {
|
||||
const { owner, name } = repoParts(repo);
|
||||
return githubRequest<GitHubComment[]>(token, "GET", `/repos/${owner}/${name}/issues/${issueNumber}/comments?per_page=100`);
|
||||
const params = new URLSearchParams({
|
||||
per_page: String(options.perPage ?? GITHUB_REST_PAGE_SIZE),
|
||||
page: String(options.page ?? 1),
|
||||
});
|
||||
return githubRequest<GitHubComment[]>(token, "GET", `/repos/${owner}/${name}/issues/${issueNumber}/comments?${params.toString()}`);
|
||||
}
|
||||
|
||||
export function githubSearchLabelQualifier(label: string): string {
|
||||
@@ -99,6 +103,22 @@ export async function getIssueComment(token: string, repo: string, commentId: nu
|
||||
return githubRequest<GitHubComment>(token, "GET", `/repos/${owner}/${name}/issues/comments/${commentId}`);
|
||||
}
|
||||
|
||||
async function listRecentIssueComments(token: string, repo: string, issueNumber: number, totalComments: number, limit: number): Promise<GitHubComment[] | GitHubErrorPayload> {
|
||||
if (totalComments <= 0 || limit <= 0) return [];
|
||||
const boundedLimit = Math.min(limit, GITHUB_REST_PAGE_SIZE);
|
||||
const pages: GitHubComment[][] = [];
|
||||
let collected = 0;
|
||||
let page = Math.max(1, Math.ceil(totalComments / GITHUB_REST_PAGE_SIZE));
|
||||
while (page >= 1 && collected < boundedLimit) {
|
||||
const pageComments = await listIssueComments(token, repo, issueNumber, { page, perPage: GITHUB_REST_PAGE_SIZE });
|
||||
if (isGitHubError(pageComments)) return pageComments;
|
||||
pages.unshift(pageComments);
|
||||
collected += pageComments.length;
|
||||
page -= 1;
|
||||
}
|
||||
return pages.flat().slice(-boundedLimit);
|
||||
}
|
||||
|
||||
export function selectedIssueJson(issue: GitHubIssue, comments: GitHubComment[] | null, fields: IssueViewJsonField[] | undefined, options: { includeFullCommentBodies?: boolean } = {}): Record<string, unknown> | null {
|
||||
if (fields === undefined) return null;
|
||||
const summary = issueSummary(issue);
|
||||
@@ -151,3 +171,57 @@ export async function issueRead(repo: string, token: string, issueNumber: number
|
||||
export async function issueView(repo: string, token: string, issueNumber: number, jsonFields: IssueViewJsonField[] | undefined, disclosure: Record<string, unknown> | null = null, options: { includeFullCommentBodies?: boolean } = {}): Promise<GitHubCommandResult> {
|
||||
return issueRead(repo, token, issueNumber, jsonFields, "issue view", disclosure, options);
|
||||
}
|
||||
|
||||
export async function issueComments(repo: string, token: string, issueNumber: number, limit: number, options: { includeFullCommentBodies?: boolean } = {}): Promise<GitHubCommandResult> {
|
||||
const issue = await getIssue(token, repo, issueNumber);
|
||||
if (isGitHubError(issue)) return commandError("issue comments", repo, issue, { issueNumber });
|
||||
const totalComments = Math.max(0, issue.comments ?? 0);
|
||||
const boundedLimit = Math.min(limit, GITHUB_REST_PAGE_SIZE);
|
||||
const includeFullCommentBodies = options.includeFullCommentBodies === true;
|
||||
const comments = await listRecentIssueComments(token, repo, issueNumber, totalComments, boundedLimit);
|
||||
if (isGitHubError(comments)) return commandError("issue comments", repo, comments, {
|
||||
issueNumber,
|
||||
issue: issueSummary(issue, { includeBody: false, includePreview: false }),
|
||||
});
|
||||
const shownFrom = comments.length === 0 ? 0 : Math.max(1, totalComments - comments.length + 1);
|
||||
return {
|
||||
ok: true,
|
||||
command: "issue comments",
|
||||
repo,
|
||||
issue: issueSummary(issue, { includeBody: false, includePreview: false }),
|
||||
issueNumber,
|
||||
limit: boundedLimit,
|
||||
totalComments,
|
||||
returned: comments.length,
|
||||
omitted: Math.max(0, totalComments - comments.length),
|
||||
commentRange: {
|
||||
from: shownFrom,
|
||||
to: comments.length === 0 ? 0 : shownFrom + comments.length - 1,
|
||||
total: totalComments,
|
||||
},
|
||||
comments: comments.map(includeFullCommentBodies ? commentSummary : compactCommentSummary),
|
||||
disclosure: {
|
||||
boundedRecentComments: true,
|
||||
fullCommentBodiesIncluded: includeFullCommentBodies,
|
||||
bodyOmitted: !includeFullCommentBodies,
|
||||
note: includeFullCommentBodies
|
||||
? "issue comments returns a bounded recent-comment list with full bodies because --full or --raw was explicitly requested."
|
||||
: "issue comments defaults to bounded recent-comment previews; use --full or --raw for full bodies, or issue comment view <commentId> --full for a single comment.",
|
||||
},
|
||||
compatibility: {
|
||||
commentsPath: ".data.comments",
|
||||
issuePath: ".data.issue",
|
||||
authorField: "string|null",
|
||||
previewField: includeFullCommentBodies ? null : "bodyPreview",
|
||||
fullBodyField: includeFullCommentBodies ? "body" : null,
|
||||
nestedIssueViewCommentsPath: ".data.json.comments",
|
||||
},
|
||||
readCommands: {
|
||||
self: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo}`,
|
||||
full: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo} --limit ${boundedLimit} --full`,
|
||||
raw: `bun scripts/cli.ts gh issue comments ${issueNumber} --repo ${repo} --limit ${boundedLimit} --raw`,
|
||||
comment: `bun scripts/cli.ts gh issue comment view <commentId> --repo ${repo} --full`,
|
||||
issue: `bun scripts/cli.ts gh issue view ${issueNumber} --repo ${repo}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPEC: PJ2026-010606 GitHub入口 draft-2026-06-25-gh-split
|
||||
// Moved mechanically from scripts/src/gh.ts:614-978.
|
||||
|
||||
import { BOARD_GITHUB_STATUSES, BOARD_MUTATION_SECTIONS, BOARD_ROW_FIELDS, BODY_UPDATE_MODES, CODE_QUEUE_BOARD_TARGET_ISSUE, DEFAULT_REPO, DEFAULT_STALE_CLOSE_INACTIVE_HOURS, GH_FLAG_OPTIONS, GH_VALUE_OPTIONS, ISSUE_LIST_JSON_FIELDS, ISSUE_LIST_STATES, ISSUE_VIEW_JSON_FIELDS, MAX_ISSUE_LIST_LIMIT, MAX_PR_FILES_LIMIT, MAX_STALE_CLOSE_INACTIVE_HOURS, PR_CLOSEOUT_JSON_FIELDS, PR_CLOSEOUT_VIEW_JSON, PR_LIST_JSON_FIELDS, PR_READ_JSON_FIELDS } from "./types";
|
||||
import { BOARD_GITHUB_STATUSES, BOARD_MUTATION_SECTIONS, BOARD_ROW_FIELDS, BODY_UPDATE_MODES, CODE_QUEUE_BOARD_TARGET_ISSUE, DEFAULT_ISSUE_COMMENTS_LIMIT, DEFAULT_REPO, DEFAULT_STALE_CLOSE_INACTIVE_HOURS, GH_FLAG_OPTIONS, GH_VALUE_OPTIONS, ISSUE_LIST_JSON_FIELDS, ISSUE_LIST_STATES, ISSUE_VIEW_JSON_FIELDS, MAX_ISSUE_LIST_LIMIT, MAX_PR_FILES_LIMIT, MAX_STALE_CLOSE_INACTIVE_HOURS, PR_CLOSEOUT_JSON_FIELDS, PR_CLOSEOUT_VIEW_JSON, PR_LIST_JSON_FIELDS, PR_READ_JSON_FIELDS } from "./types";
|
||||
import type { BoardGithubStatus, BoardMutationSection, BoardRowField, BoardRowUpsertValues, BodyUpdateMode, GitHubOptions, IssueBodyProfileOption, IssueListJsonField, IssueListState, IssueViewJsonField, PrListJsonField, PrListState, PrReadJsonField, PullRequestMergeMethod, RepoVisibility } from "./types";
|
||||
|
||||
export function optionValue(args: string[], name: string): string | undefined {
|
||||
@@ -158,7 +158,7 @@ export function isPrReadCommand(sub: string | undefined): boolean {
|
||||
export function allowsNumberTargetAlias(top: string | undefined, sub: string | undefined, third: string | undefined): boolean {
|
||||
if (top === "preflight") return true;
|
||||
if (top === "issue") {
|
||||
if (sub === "read" || sub === "view" || sub === "edit" || sub === "update" || sub === "patch" || sub === "close" || sub === "reopen" || sub === "delete") return true;
|
||||
if (sub === "read" || sub === "view" || sub === "comments" || sub === "edit" || sub === "update" || sub === "patch" || sub === "close" || sub === "reopen" || sub === "delete") return true;
|
||||
if (sub === "comment") return true;
|
||||
if (sub === "attachment" && (third === "list" || third === "download")) return true;
|
||||
if (sub === "board-row" && ["get", "update", "add", "move", "delete", "upsert"].includes(third ?? "")) return true;
|
||||
@@ -335,7 +335,18 @@ export function parseOptions(args: string[]): GitHubOptions {
|
||||
dryRun: hasFlag(args, "--dry-run"),
|
||||
raw: hasFlag(args, "--raw"),
|
||||
full: hasFlag(args, "--full"),
|
||||
limit: positiveIntegerOption(args, "--limit", top === "issue" && sub === "board-audit" ? 100 : top === "issue" && sub === "stale-close" ? MAX_ISSUE_LIST_LIMIT : 30, limitMax),
|
||||
limit: positiveIntegerOption(
|
||||
args,
|
||||
"--limit",
|
||||
top === "issue" && sub === "board-audit"
|
||||
? 100
|
||||
: top === "issue" && sub === "stale-close"
|
||||
? MAX_ISSUE_LIST_LIMIT
|
||||
: top === "issue" && sub === "comments"
|
||||
? DEFAULT_ISSUE_COMMENTS_LIMIT
|
||||
: 30,
|
||||
limitMax,
|
||||
),
|
||||
inactiveHours: positiveNumberOption(args, "--inactive-hours", DEFAULT_STALE_CLOSE_INACTIVE_HOURS, MAX_STALE_CLOSE_INACTIVE_HOURS),
|
||||
boardIssue: positiveIntegerSingleOption(args, "--board-issue", CODE_QUEUE_BOARD_TARGET_ISSUE),
|
||||
knownMetaIssues: positiveIntegerValuesOption(args, "--known-meta-issue"),
|
||||
|
||||
@@ -25,6 +25,8 @@ export const GITHUB_REST_PAGE_SIZE = 100;
|
||||
|
||||
export const MAX_ISSUE_LIST_LIMIT = 1000;
|
||||
|
||||
export const DEFAULT_ISSUE_COMMENTS_LIMIT = 8;
|
||||
|
||||
export const DEFAULT_STALE_CLOSE_INACTIVE_HOURS = 48;
|
||||
|
||||
export const MAX_STALE_CLOSE_INACTIVE_HOURS = 24 * 365 * 10;
|
||||
|
||||
Reference in New Issue
Block a user