fix: scope gh subcommand help output
This commit is contained in:
@@ -35,6 +35,18 @@ bun scripts/cli.ts gh auth status [--repo owner/name]
|
||||
|
||||
探测 token 来源(`GH_TOKEN`/`GITHUB_TOKEN`/`gh auth token`)、GitHub REST egress、repo 可见性、issue 可读性。不打印 token。
|
||||
|
||||
## 聚焦帮助
|
||||
|
||||
具体子命令用法优先直接查 scoped help,不要先打开顶层长 help 再人工搜索:
|
||||
|
||||
```bash
|
||||
bun scripts/cli.ts gh issue close --help
|
||||
bun scripts/cli.ts gh issue comment --help
|
||||
bun scripts/cli.ts gh pr merge --help
|
||||
```
|
||||
|
||||
`gh <subcommand> --help`、`gh <subcommand> -h` 和 `gh <subcommand> help` 只输出匹配命令或命令组的 bounded JSON,包括相关 usage、短 notes 和完整 help 入口;`gh --help` / `gh help` 才输出完整顶层命令索引。
|
||||
|
||||
---
|
||||
|
||||
## Issue 命令
|
||||
|
||||
@@ -7744,7 +7744,99 @@ export function ghHelp(): unknown {
|
||||
};
|
||||
}
|
||||
|
||||
function isGhHelpRequest(args: string[]): boolean {
|
||||
if (args.length === 0) return true;
|
||||
if (args[0] === "help" || args[0] === "--help" || args[0] === "-h") return true;
|
||||
if (args.includes("--help") || args.includes("-h")) return true;
|
||||
const cleaned = args.filter((arg) => arg !== "--help" && arg !== "-h");
|
||||
return positionalArgs(cleaned).includes("help");
|
||||
}
|
||||
|
||||
function ghHelpCommandTokens(args: string[]): string[] {
|
||||
const cleaned = args.filter((arg) => arg !== "--help" && arg !== "-h");
|
||||
const positionals = positionalArgs(cleaned);
|
||||
if (positionals[0] === "help") positionals.shift();
|
||||
if (positionals[positionals.length - 1] === "help") positionals.pop();
|
||||
return positionals;
|
||||
}
|
||||
|
||||
function ghHelpUsageLines(): string[] {
|
||||
const help = ghHelp() as { usage?: unknown };
|
||||
if (!Array.isArray(help.usage)) return [];
|
||||
return help.usage.filter((line): line is string => typeof line === "string");
|
||||
}
|
||||
|
||||
function ghUsageCommandTokens(usageLine: string): string[] {
|
||||
const prefix = "bun scripts/cli.ts gh ";
|
||||
if (!usageLine.startsWith(prefix)) return [];
|
||||
const tokens: string[] = [];
|
||||
for (const token of usageLine.slice(prefix.length).split(/\s+/u)) {
|
||||
if (token.length === 0) continue;
|
||||
if (token.startsWith("[") || token.startsWith("<") || token.startsWith("--")) break;
|
||||
tokens.push(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function ghUsageMatchesCommandTokens(usageLine: string, requestedTokens: string[]): boolean {
|
||||
const usageTokens = ghUsageCommandTokens(usageLine);
|
||||
if (requestedTokens.length === 0 || requestedTokens.length > usageTokens.length) return false;
|
||||
return requestedTokens.every((requested, index) => usageTokens[index]?.split("|").includes(requested) === true);
|
||||
}
|
||||
|
||||
function ghScopedHelpNotes(tokens: string[]): string[] {
|
||||
const key = tokens.join(" ");
|
||||
const notes = [
|
||||
"Scoped help is bounded to the requested command or command group; use `bun scripts/cli.ts gh --help` for the full top-level command index.",
|
||||
];
|
||||
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 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.");
|
||||
} else if (key === "pr merge") {
|
||||
notes.push("PR merge is guarded: run `gh pr preflight <number>` first when you need an explicit readiness summary.");
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
|
||||
export function ghScopedHelp(args: string[]): unknown | null {
|
||||
if (!isGhHelpRequest(args)) return null;
|
||||
const requestedTokens = ghHelpCommandTokens(args);
|
||||
if (requestedTokens.length === 0) return ghHelp();
|
||||
const usageLines = ghHelpUsageLines();
|
||||
for (let length = requestedTokens.length; length >= 1; length -= 1) {
|
||||
const scopedTokens = requestedTokens.slice(0, length);
|
||||
const usage = usageLines.filter((line) => ghUsageMatchesCommandTokens(line, scopedTokens));
|
||||
if (usage.length === 0) continue;
|
||||
return {
|
||||
command: `gh ${scopedTokens.join(" ")}`,
|
||||
output: "json",
|
||||
scoped: true,
|
||||
requestedCommand: requestedTokens.join(" "),
|
||||
matchedCommand: scopedTokens.join(" "),
|
||||
usage,
|
||||
notes: ghScopedHelpNotes(scopedTokens),
|
||||
fullHelpCommand: "bun scripts/cli.ts gh --help",
|
||||
};
|
||||
}
|
||||
return {
|
||||
command: `gh ${requestedTokens.join(" ")}`,
|
||||
output: "json",
|
||||
scoped: true,
|
||||
requestedCommand: requestedTokens.join(" "),
|
||||
usage: [],
|
||||
message: "No scoped help entry matched this gh command; use the top-level help for the full command index.",
|
||||
fullHelpCommand: "bun scripts/cli.ts gh --help",
|
||||
};
|
||||
}
|
||||
|
||||
export async function runGhCommand(args: string[]): Promise<GitHubCommandResult | unknown> {
|
||||
const scopedHelp = ghScopedHelp(args);
|
||||
if (scopedHelp !== null) return scopedHelp;
|
||||
const [top, sub, third] = args;
|
||||
if (top === undefined || top === "help" || top === "--help" || top === "-h") return ghHelp();
|
||||
let options: GitHubOptions;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { ghHelp } from "./gh";
|
||||
import { ghHelp, ghScopedHelp } from "./gh";
|
||||
import { authBrokerHelp } from "./auth-broker";
|
||||
import { platformDbHelp } from "./platform-db";
|
||||
import { secretsHelp } from "./secrets";
|
||||
@@ -724,7 +724,7 @@ export async function staticNamespaceHelp(args: string[]): Promise<unknown | nul
|
||||
if (top === "dev-env") return devEnvHelp();
|
||||
if (top === "artifact-registry") return artifactRegistryHelp();
|
||||
if (top === "auth-broker") return authBrokerHelp();
|
||||
if (top === "gh") return ghHelp();
|
||||
if (top === "gh") return ghScopedHelp(args.slice(1)) ?? ghHelp();
|
||||
if (top === "agentrun") return loadHelp(async () => (await import("./agentrun")).agentRunHelp(), agentRunHelpSummary());
|
||||
if (top === "platform-infra") return loadHelp(async () => (await import("./platform-infra")).platformInfraHelp(), platformInfraHelpSummary());
|
||||
if (top === "platform-db") return platformDbHelp();
|
||||
|
||||
Reference in New Issue
Block a user