mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
feat: 添加 GitHub 集成命令(issue、share、autofix-pr)
- /issue: 通过 gh CLI 创建 GitHub issue,支持标签/指派 - /share: 会话日志分享到 GitHub Gist,支持密钥脱敏 - /autofix-pr: 自动修复 CI 失败的 PR,进度追踪 - launchCommand: 共享命令启动器 Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>
This commit is contained in:
122
src/commands/_shared/launchCommand.ts
Normal file
122
src/commands/_shared/launchCommand.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* launchCommand — generic factory for local-jsx command implementations.
|
||||
*
|
||||
* Encapsulates the repeated boilerplate across the 6 command launch files:
|
||||
* - args parsing + invalid-args handling
|
||||
* - dispatch error capture + onDone error message
|
||||
* - errorView rendering
|
||||
* - React.createElement call for the happy-path View
|
||||
*
|
||||
* Usage (H2 finding — cuts boilerplate ~50%):
|
||||
*
|
||||
* export const callMyCmd: LocalJSXCommandCall = launchCommand<MyParsed, MyViewProps>({
|
||||
* commandName: 'my-cmd',
|
||||
* parseArgs: parseMyArgs,
|
||||
* dispatch: async (parsed, onDone, context) => { ... return viewProps },
|
||||
* View: MyCmdView,
|
||||
* errorView: (msg) => React.createElement(MyCmdView, { mode: 'error', message: msg }),
|
||||
* })
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import type {
|
||||
LocalJSXCommandCall,
|
||||
LocalJSXCommandOnDone,
|
||||
} from '../../types/command.js'
|
||||
import type { ToolUseContext } from '../../Tool.js'
|
||||
|
||||
/** Shape returned by parseArgs when args are invalid. */
|
||||
export interface InvalidParsed {
|
||||
action: 'invalid'
|
||||
reason: string
|
||||
}
|
||||
|
||||
export interface LaunchCommandOptions<TParsed, TViewProps> {
|
||||
/**
|
||||
* Command name used in error messages (e.g. "local-vault").
|
||||
* Appears in the onDone text when dispatch throws.
|
||||
*/
|
||||
commandName: string
|
||||
|
||||
/**
|
||||
* Parse raw args string into a typed action union or an invalid sentinel.
|
||||
* Must return `{ action: 'invalid'; reason: string }` when args are bad.
|
||||
*/
|
||||
parseArgs: (rawArgs: string) => TParsed | InvalidParsed
|
||||
|
||||
/**
|
||||
* Perform the command operation.
|
||||
* - Call onDone with the user-visible summary text.
|
||||
* - Return the View props to render, or null to render nothing.
|
||||
* - Throw to trigger the error path.
|
||||
*/
|
||||
dispatch: (
|
||||
parsed: TParsed,
|
||||
onDone: LocalJSXCommandOnDone,
|
||||
context: ToolUseContext,
|
||||
) => Promise<TViewProps | null>
|
||||
|
||||
/**
|
||||
* React component rendered with the props returned by dispatch.
|
||||
*/
|
||||
View: React.FC<TViewProps>
|
||||
|
||||
/**
|
||||
* Render an error node when parseArgs returns invalid or dispatch throws.
|
||||
* Receives the human-readable error message string.
|
||||
*/
|
||||
errorView: (message: string) => React.ReactNode
|
||||
|
||||
/**
|
||||
* Optional hook called when dispatch throws, before the error is surfaced.
|
||||
* Useful for analytics logEvent calls.
|
||||
* Default: no-op.
|
||||
*/
|
||||
onDispatchError?: (err: unknown) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a LocalJSXCommandCall that wraps the provided parse / dispatch / View
|
||||
* triple with uniform error handling.
|
||||
*/
|
||||
export function launchCommand<TParsed, TViewProps>(
|
||||
opts: LaunchCommandOptions<TParsed, TViewProps>,
|
||||
): LocalJSXCommandCall {
|
||||
return async (
|
||||
onDone: LocalJSXCommandOnDone,
|
||||
context: ToolUseContext,
|
||||
args: string,
|
||||
): Promise<React.ReactNode> => {
|
||||
// ── Parse args ────────────────────────────────────────────────────────────
|
||||
const parsed = opts.parseArgs(args ?? '')
|
||||
|
||||
if (isInvalid(parsed)) {
|
||||
onDone(`Invalid args: ${parsed.reason}`, { display: 'system' })
|
||||
return opts.errorView(parsed.reason)
|
||||
}
|
||||
|
||||
// ── Dispatch ──────────────────────────────────────────────────────────────
|
||||
try {
|
||||
const viewProps = await opts.dispatch(parsed as TParsed, onDone, context)
|
||||
if (viewProps === null) return null
|
||||
return React.createElement(
|
||||
opts.View as React.ComponentType<object>,
|
||||
viewProps as object,
|
||||
)
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
opts.onDispatchError?.(err)
|
||||
onDone(`${opts.commandName} failed: ${msg}`, { display: 'system' })
|
||||
return opts.errorView(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isInvalid(parsed: unknown): parsed is InvalidParsed {
|
||||
return (
|
||||
typeof parsed === 'object' &&
|
||||
parsed !== null &&
|
||||
'action' in parsed &&
|
||||
(parsed as InvalidParsed).action === 'invalid'
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user