@rotorsoft/gent 1.12.0 → 1.12.1

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.
@@ -212,19 +212,6 @@ function mergeConfig(defaults, user) {
212
212
  validation: user.validation ?? defaults.validation
213
213
  };
214
214
  }
215
- function updateConfigProvider(provider, cwd = process.cwd()) {
216
- const configPath = getConfigPath(cwd);
217
- if (!existsSync(configPath)) {
218
- writeFileSync(configPath, generateDefaultConfig(provider), "utf-8");
219
- return;
220
- }
221
- const content = readFileSync(configPath, "utf-8");
222
- const updated = content.replace(
223
- /^(\s*provider:\s*)"[^"]*"/m,
224
- `$1"${provider}"`
225
- );
226
- writeFileSync(configPath, updated, "utf-8");
227
- }
228
215
  function generateDefaultConfig(provider = "claude") {
229
216
  return `# Gent Configuration
230
217
  # See https://github.com/rotorsoft/gent for documentation
@@ -841,7 +828,6 @@ export {
841
828
  loadConfig,
842
829
  loadAgentInstructions,
843
830
  configExists,
844
- updateConfigProvider,
845
831
  generateDefaultConfig,
846
832
  createSpinner,
847
833
  withSpinner,
@@ -865,4 +851,4 @@ export {
865
851
  addPrComment,
866
852
  setupLabelsCommand
867
853
  };
868
- //# sourceMappingURL=chunk-TLGYE7J2.js.map
854
+ //# sourceMappingURL=chunk-UWYWIOYZ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/logger.ts","../src/utils/spinner.ts","../src/lib/config.ts","../src/types/index.ts","../src/lib/labels.ts","../src/lib/github.ts","../src/utils/validators.ts","../src/commands/setup-labels.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nexport const logger = {\n info: (message: string) => console.log(chalk.blue(\"ℹ\"), message),\n success: (message: string) => console.log(chalk.green(\"✓\"), message),\n warning: (message: string) => console.log(chalk.yellow(\"⚠\"), message),\n error: (message: string) => console.log(chalk.red(\"✗\"), message),\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(chalk.gray(\"⋯\"), message);\n }\n },\n dim: (message: string) => console.log(chalk.dim(message)),\n bold: (message: string) => console.log(chalk.bold(message)),\n highlight: (message: string) => console.log(chalk.cyan(message)),\n\n box: (title: string, content: string) => {\n const lines = content.split(\"\\n\");\n // Calculate visible length (strips ANSI codes) for proper alignment\n // eslint-disable-next-line no-control-regex\n const stripAnsi = (str: string) => str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n const visibleLength = (str: string) => stripAnsi(str).length;\n const maxLen =\n Math.max(title.length, ...lines.map((l) => visibleLength(l))) + 4;\n const border = \"─\".repeat(maxLen);\n\n // Pad string to target length accounting for ANSI codes\n const padVisible = (str: string, len: number) => {\n const visible = visibleLength(str);\n return str + \" \".repeat(Math.max(0, len - visible));\n };\n\n console.log(chalk.dim(`┌${border}┐`));\n console.log(\n `${chalk.dim(\"│\")} ${chalk.bold(title.padEnd(maxLen - 2))} ${chalk.dim(\"│\")}`\n );\n console.log(chalk.dim(`├${border}┤`));\n for (const line of lines) {\n console.log(\n `${chalk.dim(\"│\")} ${padVisible(line, maxLen - 2)} ${chalk.dim(\"│\")}`\n );\n }\n console.log(chalk.dim(`└${border}┘`));\n },\n\n list: (items: string[], bullet = \"•\") => {\n for (const item of items) {\n console.log(chalk.dim(bullet), item);\n }\n },\n\n newline: () => console.log(),\n};\n\nexport const colors = {\n issue: chalk.cyan,\n branch: chalk.magenta,\n label: chalk.yellow,\n file: chalk.green,\n command: chalk.blue,\n url: chalk.underline.blue,\n provider: chalk.cyan.bold,\n};\n","import ora, { Ora } from \"ora\";\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: \"dots\",\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>\n): Promise<T> {\n const spinner = createSpinner(text);\n spinner.start();\n\n try {\n const result = await fn();\n spinner.succeed();\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { GentConfig, AIProvider } from \"../types/index.js\";\n\nconst DEFAULT_CONFIG: GentConfig = {\n version: 1,\n github: {\n labels: {\n workflow: {\n ready: \"ai-ready\",\n in_progress: \"ai-in-progress\",\n completed: \"ai-completed\",\n blocked: \"ai-blocked\",\n },\n types: [\"feature\", \"fix\", \"refactor\", \"chore\", \"docs\", \"test\"],\n priorities: [\"critical\", \"high\", \"medium\", \"low\"],\n risks: [\"low\", \"medium\", \"high\"],\n areas: [\"ui\", \"api\", \"database\", \"workers\", \"shared\", \"testing\", \"infra\"],\n },\n },\n branch: {\n pattern: \"{author}/{type}-{issue}-{slug}\",\n author_source: \"git\",\n author_env_var: \"GENT_AUTHOR\",\n },\n progress: {\n file: \"progress.txt\",\n archive_threshold: 500,\n archive_dir: \".gent/archive\",\n },\n claude: {\n permission_mode: \"acceptEdits\",\n agent_file: \"AGENT.md\",\n },\n gemini: {\n sandbox_mode: \"on\",\n agent_file: \"AGENT.md\",\n },\n codex: {\n agent_file: \"AGENT.md\",\n },\n ai: {\n provider: \"claude\",\n auto_fallback: true,\n },\n video: {\n enabled: true,\n max_duration: 30,\n width: 1280,\n height: 720,\n },\n validation: [\"npm run typecheck\", \"npm run lint\", \"npm run test\"],\n};\n\nexport function getConfigPath(cwd: string = process.cwd()): string {\n return join(cwd, \".gent.yml\");\n}\n\nexport function getAgentPath(cwd: string = process.cwd()): string | null {\n const config = loadConfig(cwd);\n // Use claude.agent_file for backward compatibility\n const agentPath = join(cwd, config.claude.agent_file);\n return existsSync(agentPath) ? agentPath : null;\n}\n\nexport function loadConfig(cwd: string = process.cwd()): GentConfig {\n const configPath = getConfigPath(cwd);\n\n if (!existsSync(configPath)) {\n return DEFAULT_CONFIG;\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const userConfig = parseYaml(content) as Partial<GentConfig>;\n\n return mergeConfig(DEFAULT_CONFIG, userConfig);\n } catch {\n return DEFAULT_CONFIG;\n }\n}\n\nexport function loadAgentInstructions(cwd: string = process.cwd()): string | null {\n const agentPath = getAgentPath(cwd);\n\n if (!agentPath) {\n return null;\n }\n\n try {\n return readFileSync(agentPath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport function configExists(cwd: string = process.cwd()): boolean {\n return existsSync(getConfigPath(cwd));\n}\n\nfunction mergeConfig(\n defaults: GentConfig,\n user: Partial<GentConfig>\n): GentConfig {\n // Support GENT_AI_PROVIDER environment variable override\n const envProvider = process.env.GENT_AI_PROVIDER as\n | \"claude\"\n | \"gemini\"\n | \"codex\"\n | undefined;\n\n return {\n version: user.version ?? defaults.version,\n github: {\n labels: {\n workflow: {\n ...defaults.github.labels.workflow,\n ...user.github?.labels?.workflow,\n },\n types: user.github?.labels?.types ?? defaults.github.labels.types,\n priorities:\n user.github?.labels?.priorities ?? defaults.github.labels.priorities,\n risks: user.github?.labels?.risks ?? defaults.github.labels.risks,\n areas: user.github?.labels?.areas ?? defaults.github.labels.areas,\n },\n },\n branch: {\n ...defaults.branch,\n ...user.branch,\n },\n progress: {\n ...defaults.progress,\n ...user.progress,\n },\n claude: {\n ...defaults.claude,\n ...user.claude,\n },\n gemini: {\n ...defaults.gemini,\n ...user.gemini,\n },\n codex: {\n ...defaults.codex,\n ...user.codex,\n },\n ai: {\n ...defaults.ai,\n ...user.ai,\n // Environment variable takes precedence\n ...(envProvider && { provider: envProvider }),\n },\n video: {\n ...defaults.video,\n ...user.video,\n },\n validation: user.validation ?? defaults.validation,\n };\n}\n\nexport function updateConfigProvider(provider: AIProvider, cwd: string = process.cwd()): void {\n const configPath = getConfigPath(cwd);\n if (!existsSync(configPath)) {\n writeFileSync(configPath, generateDefaultConfig(provider), \"utf-8\");\n return;\n }\n const content = readFileSync(configPath, \"utf-8\");\n const updated = content.replace(\n /^(\\s*provider:\\s*)\"[^\"]*\"/m,\n `$1\"${provider}\"`,\n );\n writeFileSync(configPath, updated, \"utf-8\");\n}\n\nexport function generateDefaultConfig(provider: AIProvider = \"claude\"): string {\n return `# Gent Configuration\n# See https://github.com/rotorsoft/gent for documentation\nversion: 1\n\n# GitHub settings\ngithub:\n labels:\n workflow:\n ready: \"ai-ready\"\n in_progress: \"ai-in-progress\"\n completed: \"ai-completed\"\n blocked: \"ai-blocked\"\n types:\n - feature\n - fix\n - refactor\n - chore\n - docs\n - test\n priorities:\n - critical\n - high\n - medium\n - low\n risks:\n - low\n - medium\n - high\n areas:\n - ui\n - api\n - database\n - workers\n - shared\n - testing\n - infra\n\n# Branch naming convention\nbranch:\n pattern: \"{author}/{type}-{issue}-{slug}\"\n author_source: \"git\" # git | env | prompt\n author_env_var: \"GENT_AUTHOR\"\n\n# Progress tracking\nprogress:\n file: \"progress.txt\"\n archive_threshold: 500\n archive_dir: \".gent/archive\"\n\n# Claude settings\nclaude:\n permission_mode: \"acceptEdits\"\n agent_file: \"AGENT.md\"\n\n# Gemini settings\ngemini:\n sandbox_mode: \"on\"\n agent_file: \"AGENT.md\"\n\n# Codex settings\ncodex:\n agent_file: \"AGENT.md\"\n\n# AI provider settings\nai:\n provider: \"${provider}\" # claude | gemini | codex\n # fallback_provider: \"gemini\" # optional fallback when rate limited\n auto_fallback: true # automatically switch to fallback on rate limit\n\n# Video capture for UI changes (requires Playwright)\nvideo:\n enabled: true # set to false to disable video capture for PRs with UI changes\n max_duration: 30 # maximum video duration in seconds\n width: 1280 # video width\n height: 720 # video height\n\n# Validation commands (run before commit)\nvalidation:\n - \"npm run typecheck\"\n - \"npm run lint\"\n - \"npm run test\"\n`;\n}\n","export type AIProvider = \"claude\" | \"gemini\" | \"codex\";\n\nexport interface GentConfig {\n version: number;\n github: GitHubConfig;\n branch: BranchConfig;\n progress: ProgressConfig;\n claude: ClaudeConfig;\n gemini: GeminiConfig;\n codex: CodexConfig;\n ai: AIConfig;\n video: VideoConfig;\n validation: string[];\n}\n\nexport interface VideoConfig {\n enabled: boolean;\n max_duration: number; // seconds\n width: number;\n height: number;\n}\n\nexport interface AIConfig {\n provider: AIProvider;\n fallback_provider?: AIProvider;\n auto_fallback: boolean;\n}\n\nexport interface GitHubConfig {\n labels: {\n workflow: WorkflowLabels;\n types: string[];\n priorities: string[];\n risks: string[];\n areas: string[];\n };\n}\n\nexport interface WorkflowLabels {\n ready: string;\n in_progress: string;\n completed: string;\n blocked: string;\n}\n\nexport interface BranchConfig {\n pattern: string;\n author_source: \"git\" | \"env\" | \"prompt\";\n author_env_var: string;\n}\n\nexport interface ProgressConfig {\n file: string;\n archive_threshold: number;\n archive_dir: string;\n}\n\nexport interface ClaudeConfig {\n permission_mode: string;\n agent_file: string;\n}\n\nexport interface GeminiConfig {\n sandbox_mode: string;\n agent_file: string;\n}\n\nexport interface CodexConfig {\n agent_file: string;\n}\n\nexport interface GitHubIssue {\n number: number;\n title: string;\n body: string;\n labels: string[];\n state: \"open\" | \"closed\";\n assignee?: string;\n url: string;\n}\n\nexport interface GitHubLabel {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface GitHubReviewComment {\n id?: number;\n author: string;\n body: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n}\n\nexport interface GitHubReview {\n author: string;\n body: string;\n state: string;\n submittedAt?: string;\n}\n\nexport interface GitHubReviewThread {\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments: GitHubReviewComment[];\n}\n\nexport interface GitHubPRComment {\n id?: string;\n author: string;\n body: string;\n createdAt?: string;\n}\n\nexport interface GitHubReviewData {\n reviews: GitHubReview[];\n reviewThreads: GitHubReviewThread[];\n comments: GitHubPRComment[];\n}\n\nexport interface ProgressEntry {\n date: string;\n type: string;\n description: string;\n issue?: number;\n decisions: string[];\n files: string[];\n tests: string[];\n concerns: string[];\n followUp: string[];\n commit?: string;\n}\n\nexport interface BranchInfo {\n name: string;\n author: string;\n type: string;\n issueNumber: number;\n slug: string;\n}\n\nexport const DEFAULT_LABELS: Record<string, GitHubLabel[]> = {\n workflow: [\n {\n name: \"ai-ready\",\n color: \"0E8A16\",\n description: \"Issue ready for AI implementation\",\n },\n {\n name: \"ai-in-progress\",\n color: \"FFA500\",\n description: \"AI currently working on this\",\n },\n {\n name: \"ai-completed\",\n color: \"1D76DB\",\n description: \"AI done, needs human review\",\n },\n {\n name: \"ai-blocked\",\n color: \"D93F0B\",\n description: \"AI couldn't complete, needs help\",\n },\n ],\n priority: [\n {\n name: \"priority:critical\",\n color: \"B60205\",\n description: \"Blocking production\",\n },\n {\n name: \"priority:high\",\n color: \"D93F0B\",\n description: \"Important features/bugs\",\n },\n {\n name: \"priority:medium\",\n color: \"FBCA04\",\n description: \"Nice-to-have improvements\",\n },\n { name: \"priority:low\", color: \"0E8A16\", description: \"Minor tweaks\" },\n ],\n risk: [\n {\n name: \"risk:low\",\n color: \"C2E0C6\",\n description: \"UI changes, tests, non-critical\",\n },\n {\n name: \"risk:medium\",\n color: \"FEF2C0\",\n description: \"API changes, new features\",\n },\n {\n name: \"risk:high\",\n color: \"F9D0C4\",\n description: \"Migrations, auth, security\",\n },\n ],\n type: [\n { name: \"type:feature\", color: \"1D76DB\", description: \"New feature\" },\n { name: \"type:fix\", color: \"D73A4A\", description: \"Bug fix\" },\n {\n name: \"type:refactor\",\n color: \"5319E7\",\n description: \"Code improvement\",\n },\n { name: \"type:chore\", color: \"FEF2C0\", description: \"Maintenance\" },\n { name: \"type:docs\", color: \"0075CA\", description: \"Documentation\" },\n { name: \"type:test\", color: \"D4C5F9\", description: \"Testing\" },\n ],\n area: [\n { name: \"area:ui\", color: \"C5DEF5\", description: \"User interface\" },\n { name: \"area:api\", color: \"D4C5F9\", description: \"API/Backend\" },\n { name: \"area:database\", color: \"FEF2C0\", description: \"Database/Models\" },\n {\n name: \"area:workers\",\n color: \"F9D0C4\",\n description: \"Background workers\",\n },\n { name: \"area:shared\", color: \"C2E0C6\", description: \"Shared libraries\" },\n { name: \"area:testing\", color: \"E99695\", description: \"Test infrastructure\" },\n { name: \"area:infra\", color: \"BFD4F2\", description: \"Infrastructure/DevOps\" },\n ],\n};\n","import type { GentConfig, GitHubLabel } from \"../types/index.js\";\nimport { DEFAULT_LABELS } from \"../types/index.js\";\n\nexport function getAllLabels(config: GentConfig): GitHubLabel[] {\n const labels: GitHubLabel[] = [];\n\n // Workflow labels\n labels.push(...DEFAULT_LABELS.workflow);\n\n // Priority labels\n for (const priority of config.github.labels.priorities) {\n const defaultLabel = DEFAULT_LABELS.priority.find(\n (l) => l.name === `priority:${priority}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `priority:${priority}`,\n color: \"FBCA04\",\n description: `Priority: ${priority}`,\n });\n }\n }\n\n // Risk labels\n for (const risk of config.github.labels.risks) {\n const defaultLabel = DEFAULT_LABELS.risk.find(\n (l) => l.name === `risk:${risk}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `risk:${risk}`,\n color: \"FEF2C0\",\n description: `Risk: ${risk}`,\n });\n }\n }\n\n // Type labels\n for (const type of config.github.labels.types) {\n const defaultLabel = DEFAULT_LABELS.type.find(\n (l) => l.name === `type:${type}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `type:${type}`,\n color: \"1D76DB\",\n description: `Type: ${type}`,\n });\n }\n }\n\n // Area labels\n for (const area of config.github.labels.areas) {\n const defaultLabel = DEFAULT_LABELS.area.find(\n (l) => l.name === `area:${area}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `area:${area}`,\n color: \"C5DEF5\",\n description: `Area: ${area}`,\n });\n }\n }\n\n return labels;\n}\n\nexport function getWorkflowLabels(config: GentConfig): {\n ready: string;\n inProgress: string;\n completed: string;\n blocked: string;\n} {\n return {\n ready: config.github.labels.workflow.ready,\n inProgress: config.github.labels.workflow.in_progress,\n completed: config.github.labels.workflow.completed,\n blocked: config.github.labels.workflow.blocked,\n };\n}\n\nexport function buildIssueLabels(meta: {\n type: string;\n priority: string;\n risk: string;\n area: string;\n}): string[] {\n return [\n \"ai-ready\",\n `type:${meta.type}`,\n `priority:${meta.priority}`,\n `risk:${meta.risk}`,\n `area:${meta.area}`,\n ];\n}\n\nexport function extractTypeFromLabels(labels: string[]): string {\n for (const label of labels) {\n if (label.startsWith(\"type:\")) {\n return label.replace(\"type:\", \"\");\n }\n }\n return \"feature\";\n}\n\nexport function extractPriorityFromLabels(labels: string[]): string {\n for (const label of labels) {\n if (label.startsWith(\"priority:\")) {\n return label.replace(\"priority:\", \"\");\n }\n }\n return \"medium\";\n}\n\nexport function hasWorkflowLabel(\n labels: string[],\n workflowLabel: string\n): boolean {\n return labels.includes(workflowLabel);\n}\n\nexport function sortByPriority(issues: { labels: string[] }[]): void {\n const priorityOrder = [\"critical\", \"high\", \"medium\", \"low\"];\n\n issues.sort((a, b) => {\n const aPriority = extractPriorityFromLabels(a.labels);\n const bPriority = extractPriorityFromLabels(b.labels);\n return priorityOrder.indexOf(aPriority) - priorityOrder.indexOf(bPriority);\n });\n}\n","import { execa } from \"execa\";\nimport type { GitHubIssue, GitHubLabel, GitHubReviewData } from \"../types/index.js\";\n\nexport async function getIssue(issueNumber: number): Promise<GitHubIssue> {\n const { stdout } = await execa(\"gh\", [\n \"issue\",\n \"view\",\n String(issueNumber),\n \"--json\",\n \"number,title,body,labels,state,assignees,url\",\n ]);\n\n const data = JSON.parse(stdout);\n return {\n number: data.number,\n title: data.title,\n body: data.body || \"\",\n labels: data.labels.map((l: { name: string }) => l.name),\n state: data.state.toLowerCase(),\n assignee: data.assignees?.[0]?.login,\n url: data.url,\n };\n}\n\nexport async function listIssues(options: {\n labels?: string[];\n state?: \"open\" | \"closed\" | \"all\";\n limit?: number;\n}): Promise<GitHubIssue[]> {\n const args = [\"issue\", \"list\", \"--json\", \"number,title,body,labels,state,url\"];\n\n if (options.labels?.length) {\n args.push(\"--label\", options.labels.join(\",\"));\n }\n\n if (options.state) {\n args.push(\"--state\", options.state);\n }\n\n args.push(\"--limit\", String(options.limit || 50));\n\n const { stdout } = await execa(\"gh\", args);\n const data = JSON.parse(stdout);\n\n return data.map(\n (d: {\n number: number;\n title: string;\n body: string;\n labels: { name: string }[];\n state: string;\n url: string;\n }) => ({\n number: d.number,\n title: d.title,\n body: d.body || \"\",\n labels: d.labels.map((l) => l.name),\n state: d.state.toLowerCase() as \"open\" | \"closed\",\n url: d.url,\n })\n );\n}\n\nexport async function createIssue(options: {\n title: string;\n body: string;\n labels?: string[];\n}): Promise<number> {\n const args = [\"issue\", \"create\", \"--title\", options.title, \"--body\", options.body];\n\n if (options.labels?.length) {\n args.push(\"--label\", options.labels.join(\",\"));\n }\n\n const { stdout } = await execa(\"gh\", args);\n\n // Extract issue number from URL\n const match = stdout.match(/\\/issues\\/(\\d+)/);\n if (!match) {\n throw new Error(\"Failed to extract issue number from gh output\");\n }\n\n return parseInt(match[1], 10);\n}\n\nexport async function updateIssueLabels(\n issueNumber: number,\n options: {\n add?: string[];\n remove?: string[];\n }\n): Promise<void> {\n const promises: Promise<unknown>[] = [];\n\n if (options.add?.length) {\n promises.push(\n execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--add-label\",\n options.add.join(\",\"),\n ])\n );\n }\n\n if (options.remove?.length) {\n promises.push(\n execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--remove-label\",\n options.remove.join(\",\"),\n ])\n );\n }\n\n await Promise.all(promises);\n}\n\nexport async function addIssueComment(\n issueNumber: number,\n body: string\n): Promise<void> {\n await execa(\"gh\", [\"issue\", \"comment\", String(issueNumber), \"--body\", body]);\n}\n\nexport async function assignIssue(\n issueNumber: number,\n assignee: string\n): Promise<void> {\n await execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--add-assignee\",\n assignee,\n ]);\n}\n\nexport async function createLabel(label: GitHubLabel): Promise<void> {\n try {\n await execa(\"gh\", [\n \"label\",\n \"create\",\n label.name,\n \"--color\",\n label.color,\n \"--description\",\n label.description || \"\",\n \"--force\",\n ]);\n } catch {\n // Label might already exist, ignore error\n }\n}\n\nexport async function createPullRequest(options: {\n title: string;\n body: string;\n base?: string;\n draft?: boolean;\n}): Promise<string> {\n const args = [\n \"pr\",\n \"create\",\n \"--title\",\n options.title,\n \"--body\",\n options.body,\n \"--assignee\",\n \"@me\",\n ];\n\n if (options.base) {\n args.push(\"--base\", options.base);\n }\n\n if (options.draft) {\n args.push(\"--draft\");\n }\n\n const { stdout } = await execa(\"gh\", args);\n return stdout.trim();\n}\n\nexport interface PrBasicInfo {\n number: number;\n url: string;\n}\n\nexport interface PrStatusInfo {\n number: number;\n title: string;\n url: string;\n state: \"open\" | \"closed\" | \"merged\";\n reviewDecision: string | null;\n isDraft: boolean;\n}\n\nexport async function getPrForBranch(): Promise<PrBasicInfo | null> {\n try {\n const { stdout } = await execa(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,url\",\n ]);\n const data = JSON.parse(stdout);\n return { number: data.number, url: data.url };\n } catch {\n return null;\n }\n}\n\nexport async function getPrStatus(): Promise<PrStatusInfo | null> {\n try {\n const { stdout } = await execa(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,title,url,state,reviewDecision,isDraft\",\n ]);\n const data = JSON.parse(stdout);\n // gh pr view returns state as OPEN, CLOSED, or MERGED (uppercase)\n const state = (data.state?.toLowerCase() ?? \"open\") as \"open\" | \"closed\" | \"merged\";\n return {\n number: data.number,\n title: data.title ?? \"\",\n url: data.url,\n state,\n reviewDecision: data.reviewDecision ?? null,\n isDraft: data.isDraft ?? false,\n };\n } catch {\n return null;\n }\n}\n\nexport async function getPrReviewData(prNumber?: number): Promise<GitHubReviewData> {\n // Fetch reviews and comments using gh pr view (both are supported JSON fields)\n const prArgs = [\"pr\", \"view\"];\n if (prNumber) {\n prArgs.push(String(prNumber));\n }\n prArgs.push(\"--json\", \"reviews,comments\");\n\n const { stdout: prStdout } = await execa(\"gh\", prArgs);\n const prData = JSON.parse(prStdout);\n\n // Fetch review threads using GraphQL API (not available via gh pr view --json)\n // First get repo owner and name since GraphQL doesn't support {owner}/{repo} placeholders\n let reviewThreads: Array<{\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments: Array<{\n author: string;\n body: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n }>;\n }> = [];\n\n try {\n const { stdout: repoStdout } = await execa(\"gh\", [\"repo\", \"view\", \"--json\", \"owner,name\"]);\n const repoData = JSON.parse(repoStdout);\n const owner = repoData.owner?.login ?? repoData.owner;\n const repo = repoData.name;\n\n const graphqlQuery = `query { repository(owner: \"${owner}\", name: \"${repo}\") { pullRequest(number: ${prNumber}) { reviewThreads(first: 100) { nodes { isResolved isOutdated path line comments(first: 100) { nodes { databaseId author { login } body path line createdAt } } } } } } }`;\n\n const { stdout: graphqlStdout } = await execa(\"gh\", [\"api\", \"graphql\", \"-f\", `query=${graphqlQuery}`]);\n const graphqlData = JSON.parse(graphqlStdout);\n const prNode = graphqlData.data?.repository?.pullRequest;\n const threadNodes = prNode?.reviewThreads?.nodes ?? [];\n\n reviewThreads = threadNodes.map((thread: {\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments?: { nodes?: Array<{\n databaseId?: number;\n author?: { login?: string };\n body?: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n }> };\n }) => ({\n isResolved: thread.isResolved ?? null,\n isOutdated: thread.isOutdated ?? false,\n path: thread.path,\n line: thread.line ?? null,\n comments: (thread.comments?.nodes ?? []).map((comment) => ({\n id: comment.databaseId,\n author: comment.author?.login ?? \"unknown\",\n body: comment.body ?? \"\",\n path: comment.path ?? thread.path,\n line: comment.line ?? thread.line ?? null,\n createdAt: comment.createdAt,\n })),\n }));\n } catch {\n // If GraphQL fails (e.g., no permissions), continue with empty threads\n reviewThreads = [];\n }\n\n return {\n reviews: (prData.reviews ?? []).map((review: {\n author?: { login?: string };\n body?: string;\n state?: string;\n submittedAt?: string;\n }) => ({\n author: review.author?.login ?? \"unknown\",\n body: review.body ?? \"\",\n state: review.state ?? \"UNKNOWN\",\n submittedAt: review.submittedAt,\n })),\n reviewThreads,\n comments: (prData.comments ?? []).map((comment: {\n id?: string;\n author?: { login?: string };\n body?: string;\n createdAt?: string;\n }) => ({\n id: comment.id,\n author: comment.author?.login ?? \"unknown\",\n body: comment.body ?? \"\",\n createdAt: comment.createdAt,\n })),\n };\n}\n\nexport async function getCurrentUser(): Promise<string> {\n const { stdout } = await execa(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"]);\n return stdout.trim();\n}\n\nexport async function replyToReviewComment(\n prNumber: number,\n commentId: number,\n body: string\n): Promise<void> {\n await execa(\"gh\", [\n \"api\",\n `repos/{owner}/{repo}/pulls/${prNumber}/comments/${commentId}/replies`,\n \"-f\",\n `body=${body}`,\n ]);\n}\n\nexport async function addPrComment(prNumber: number, body: string): Promise<void> {\n await execa(\"gh\", [\"pr\", \"comment\", String(prNumber), \"--body\", body]);\n}\n","import { execa } from \"execa\";\nimport type { GentConfig, AIProvider } from \"../types/index.js\";\n\nexport async function checkGhCli(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkGhAuth(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"auth\", \"status\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkClaudeCli(): Promise<boolean> {\n try {\n await execa(\"claude\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkGeminiCli(): Promise<boolean> {\n try {\n await execa(\"gemini\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkCodexCLI(): Promise<boolean> {\n try {\n await execa(\"codex\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkAIProvider(provider: AIProvider): Promise<boolean> {\n switch (provider) {\n case \"claude\":\n return checkClaudeCli();\n case \"gemini\":\n return checkGeminiCli();\n case \"codex\":\n return checkCodexCLI();\n }\n}\n\nexport async function checkGitRepo(): Promise<boolean> {\n try {\n await execa(\"git\", [\"rev-parse\", \"--git-dir\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function validatePrerequisites(config?: GentConfig): Promise<{\n valid: boolean;\n missing: string[];\n}> {\n const checks = [\n { name: \"gh CLI\", check: checkGhCli },\n { name: \"gh auth\", check: checkGhAuth },\n { name: \"git repository\", check: checkGitRepo },\n ];\n\n const getProviderName = (provider: AIProvider) => {\n switch (provider) {\n case \"claude\":\n return \"claude CLI\";\n case \"gemini\":\n return \"gemini CLI\";\n case \"codex\":\n return \"codex CLI\";\n }\n };\n\n // Add AI provider check based on config\n if (config) {\n const provider = config.ai.provider;\n checks.push({\n name: getProviderName(provider),\n check: () => checkAIProvider(provider),\n });\n\n // Also check fallback if configured\n if (config.ai.fallback_provider) {\n const fallback = config.ai.fallback_provider;\n checks.push({\n name: `${getProviderName(fallback)} (fallback)`,\n check: () => checkAIProvider(fallback),\n });\n }\n } else {\n // Default to checking claude for backward compatibility\n checks.push({ name: \"claude CLI\", check: checkClaudeCli });\n }\n\n const missing: string[] = [];\n\n for (const { name, check } of checks) {\n const passed = await check();\n if (!passed) {\n missing.push(name);\n }\n }\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\nexport function isValidIssueNumber(value: string): boolean {\n const num = parseInt(value, 10);\n return !isNaN(num) && num > 0;\n}\n\nexport function sanitizeSlug(title: string, maxLength = 40): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLength);\n}\n","import { logger, colors } from \"../utils/logger.js\";\nimport { withSpinner } from \"../utils/spinner.js\";\nimport { loadConfig } from \"../lib/config.js\";\nimport { getAllLabels } from \"../lib/labels.js\";\nimport { createLabel } from \"../lib/github.js\";\nimport { checkGhAuth } from \"../utils/validators.js\";\n\nexport async function setupLabelsCommand(): Promise<void> {\n logger.bold(\"Setting up GitHub labels...\");\n logger.newline();\n\n // Check gh auth\n const isAuthed = await checkGhAuth();\n if (!isAuthed) {\n logger.error(\"Not authenticated with GitHub. Run 'gh auth login' first.\");\n process.exit(1);\n }\n\n const config = loadConfig();\n const labels = getAllLabels(config);\n\n logger.info(`Creating ${labels.length} labels...`);\n logger.newline();\n\n let created = 0;\n let failed = 0;\n\n for (const label of labels) {\n try {\n await withSpinner(`Creating ${colors.label(label.name)}`, async () => {\n await createLabel(label);\n });\n created++;\n } catch (error) {\n logger.error(`Failed to create ${label.name}: ${error}`);\n failed++;\n }\n }\n\n logger.newline();\n logger.success(`Created ${created} labels`);\n if (failed > 0) {\n logger.warning(`Failed to create ${failed} labels`);\n }\n\n logger.newline();\n logger.info(\"Labels are ready. You can now create AI-ready issues.\");\n}\n"],"mappings":"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","names":["execa","execa"]}
1
+ {"version":3,"sources":["../src/utils/logger.ts","../src/utils/spinner.ts","../src/lib/config.ts","../src/types/index.ts","../src/lib/labels.ts","../src/lib/github.ts","../src/utils/validators.ts","../src/commands/setup-labels.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nexport const logger = {\n info: (message: string) => console.log(chalk.blue(\"ℹ\"), message),\n success: (message: string) => console.log(chalk.green(\"✓\"), message),\n warning: (message: string) => console.log(chalk.yellow(\"⚠\"), message),\n error: (message: string) => console.log(chalk.red(\"✗\"), message),\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(chalk.gray(\"⋯\"), message);\n }\n },\n dim: (message: string) => console.log(chalk.dim(message)),\n bold: (message: string) => console.log(chalk.bold(message)),\n highlight: (message: string) => console.log(chalk.cyan(message)),\n\n box: (title: string, content: string) => {\n const lines = content.split(\"\\n\");\n // Calculate visible length (strips ANSI codes) for proper alignment\n // eslint-disable-next-line no-control-regex\n const stripAnsi = (str: string) => str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n const visibleLength = (str: string) => stripAnsi(str).length;\n const maxLen =\n Math.max(title.length, ...lines.map((l) => visibleLength(l))) + 4;\n const border = \"─\".repeat(maxLen);\n\n // Pad string to target length accounting for ANSI codes\n const padVisible = (str: string, len: number) => {\n const visible = visibleLength(str);\n return str + \" \".repeat(Math.max(0, len - visible));\n };\n\n console.log(chalk.dim(`┌${border}┐`));\n console.log(\n `${chalk.dim(\"│\")} ${chalk.bold(title.padEnd(maxLen - 2))} ${chalk.dim(\"│\")}`\n );\n console.log(chalk.dim(`├${border}┤`));\n for (const line of lines) {\n console.log(\n `${chalk.dim(\"│\")} ${padVisible(line, maxLen - 2)} ${chalk.dim(\"│\")}`\n );\n }\n console.log(chalk.dim(`└${border}┘`));\n },\n\n list: (items: string[], bullet = \"•\") => {\n for (const item of items) {\n console.log(chalk.dim(bullet), item);\n }\n },\n\n newline: () => console.log(),\n};\n\nexport const colors = {\n issue: chalk.cyan,\n branch: chalk.magenta,\n label: chalk.yellow,\n file: chalk.green,\n command: chalk.blue,\n url: chalk.underline.blue,\n provider: chalk.cyan.bold,\n};\n","import ora, { Ora } from \"ora\";\n\nexport function createSpinner(text: string): Ora {\n return ora({\n text,\n spinner: \"dots\",\n });\n}\n\nexport async function withSpinner<T>(\n text: string,\n fn: () => Promise<T>\n): Promise<T> {\n const spinner = createSpinner(text);\n spinner.start();\n\n try {\n const result = await fn();\n spinner.succeed();\n return result;\n } catch (error) {\n spinner.fail();\n throw error;\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { GentConfig, AIProvider } from \"../types/index.js\";\n\nconst DEFAULT_CONFIG: GentConfig = {\n version: 1,\n github: {\n labels: {\n workflow: {\n ready: \"ai-ready\",\n in_progress: \"ai-in-progress\",\n completed: \"ai-completed\",\n blocked: \"ai-blocked\",\n },\n types: [\"feature\", \"fix\", \"refactor\", \"chore\", \"docs\", \"test\"],\n priorities: [\"critical\", \"high\", \"medium\", \"low\"],\n risks: [\"low\", \"medium\", \"high\"],\n areas: [\"ui\", \"api\", \"database\", \"workers\", \"shared\", \"testing\", \"infra\"],\n },\n },\n branch: {\n pattern: \"{author}/{type}-{issue}-{slug}\",\n author_source: \"git\",\n author_env_var: \"GENT_AUTHOR\",\n },\n progress: {\n file: \"progress.txt\",\n archive_threshold: 500,\n archive_dir: \".gent/archive\",\n },\n claude: {\n permission_mode: \"acceptEdits\",\n agent_file: \"AGENT.md\",\n },\n gemini: {\n sandbox_mode: \"on\",\n agent_file: \"AGENT.md\",\n },\n codex: {\n agent_file: \"AGENT.md\",\n },\n ai: {\n provider: \"claude\",\n auto_fallback: true,\n },\n video: {\n enabled: true,\n max_duration: 30,\n width: 1280,\n height: 720,\n },\n validation: [\"npm run typecheck\", \"npm run lint\", \"npm run test\"],\n};\n\nexport function getConfigPath(cwd: string = process.cwd()): string {\n return join(cwd, \".gent.yml\");\n}\n\nexport function getAgentPath(cwd: string = process.cwd()): string | null {\n const config = loadConfig(cwd);\n // Use claude.agent_file for backward compatibility\n const agentPath = join(cwd, config.claude.agent_file);\n return existsSync(agentPath) ? agentPath : null;\n}\n\nexport function loadConfig(cwd: string = process.cwd()): GentConfig {\n const configPath = getConfigPath(cwd);\n\n if (!existsSync(configPath)) {\n return DEFAULT_CONFIG;\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const userConfig = parseYaml(content) as Partial<GentConfig>;\n\n return mergeConfig(DEFAULT_CONFIG, userConfig);\n } catch {\n return DEFAULT_CONFIG;\n }\n}\n\nexport function loadAgentInstructions(cwd: string = process.cwd()): string | null {\n const agentPath = getAgentPath(cwd);\n\n if (!agentPath) {\n return null;\n }\n\n try {\n return readFileSync(agentPath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nexport function configExists(cwd: string = process.cwd()): boolean {\n return existsSync(getConfigPath(cwd));\n}\n\nfunction mergeConfig(\n defaults: GentConfig,\n user: Partial<GentConfig>\n): GentConfig {\n // Support GENT_AI_PROVIDER environment variable override\n const envProvider = process.env.GENT_AI_PROVIDER as\n | \"claude\"\n | \"gemini\"\n | \"codex\"\n | undefined;\n\n return {\n version: user.version ?? defaults.version,\n github: {\n labels: {\n workflow: {\n ...defaults.github.labels.workflow,\n ...user.github?.labels?.workflow,\n },\n types: user.github?.labels?.types ?? defaults.github.labels.types,\n priorities:\n user.github?.labels?.priorities ?? defaults.github.labels.priorities,\n risks: user.github?.labels?.risks ?? defaults.github.labels.risks,\n areas: user.github?.labels?.areas ?? defaults.github.labels.areas,\n },\n },\n branch: {\n ...defaults.branch,\n ...user.branch,\n },\n progress: {\n ...defaults.progress,\n ...user.progress,\n },\n claude: {\n ...defaults.claude,\n ...user.claude,\n },\n gemini: {\n ...defaults.gemini,\n ...user.gemini,\n },\n codex: {\n ...defaults.codex,\n ...user.codex,\n },\n ai: {\n ...defaults.ai,\n ...user.ai,\n // Environment variable takes precedence\n ...(envProvider && { provider: envProvider }),\n },\n video: {\n ...defaults.video,\n ...user.video,\n },\n validation: user.validation ?? defaults.validation,\n };\n}\n\nexport function updateConfigProvider(provider: AIProvider, cwd: string = process.cwd()): void {\n const configPath = getConfigPath(cwd);\n if (!existsSync(configPath)) {\n writeFileSync(configPath, generateDefaultConfig(provider), \"utf-8\");\n return;\n }\n const content = readFileSync(configPath, \"utf-8\");\n const updated = content.replace(\n /^(\\s*provider:\\s*)\"[^\"]*\"/m,\n `$1\"${provider}\"`,\n );\n writeFileSync(configPath, updated, \"utf-8\");\n}\n\nexport function generateDefaultConfig(provider: AIProvider = \"claude\"): string {\n return `# Gent Configuration\n# See https://github.com/rotorsoft/gent for documentation\nversion: 1\n\n# GitHub settings\ngithub:\n labels:\n workflow:\n ready: \"ai-ready\"\n in_progress: \"ai-in-progress\"\n completed: \"ai-completed\"\n blocked: \"ai-blocked\"\n types:\n - feature\n - fix\n - refactor\n - chore\n - docs\n - test\n priorities:\n - critical\n - high\n - medium\n - low\n risks:\n - low\n - medium\n - high\n areas:\n - ui\n - api\n - database\n - workers\n - shared\n - testing\n - infra\n\n# Branch naming convention\nbranch:\n pattern: \"{author}/{type}-{issue}-{slug}\"\n author_source: \"git\" # git | env | prompt\n author_env_var: \"GENT_AUTHOR\"\n\n# Progress tracking\nprogress:\n file: \"progress.txt\"\n archive_threshold: 500\n archive_dir: \".gent/archive\"\n\n# Claude settings\nclaude:\n permission_mode: \"acceptEdits\"\n agent_file: \"AGENT.md\"\n\n# Gemini settings\ngemini:\n sandbox_mode: \"on\"\n agent_file: \"AGENT.md\"\n\n# Codex settings\ncodex:\n agent_file: \"AGENT.md\"\n\n# AI provider settings\nai:\n provider: \"${provider}\" # claude | gemini | codex\n # fallback_provider: \"gemini\" # optional fallback when rate limited\n auto_fallback: true # automatically switch to fallback on rate limit\n\n# Video capture for UI changes (requires Playwright)\nvideo:\n enabled: true # set to false to disable video capture for PRs with UI changes\n max_duration: 30 # maximum video duration in seconds\n width: 1280 # video width\n height: 720 # video height\n\n# Validation commands (run before commit)\nvalidation:\n - \"npm run typecheck\"\n - \"npm run lint\"\n - \"npm run test\"\n`;\n}\n","export type AIProvider = \"claude\" | \"gemini\" | \"codex\";\n\nexport interface GentConfig {\n version: number;\n github: GitHubConfig;\n branch: BranchConfig;\n progress: ProgressConfig;\n claude: ClaudeConfig;\n gemini: GeminiConfig;\n codex: CodexConfig;\n ai: AIConfig;\n video: VideoConfig;\n validation: string[];\n}\n\nexport interface VideoConfig {\n enabled: boolean;\n max_duration: number; // seconds\n width: number;\n height: number;\n}\n\nexport interface AIConfig {\n provider: AIProvider;\n fallback_provider?: AIProvider;\n auto_fallback: boolean;\n}\n\nexport interface GitHubConfig {\n labels: {\n workflow: WorkflowLabels;\n types: string[];\n priorities: string[];\n risks: string[];\n areas: string[];\n };\n}\n\nexport interface WorkflowLabels {\n ready: string;\n in_progress: string;\n completed: string;\n blocked: string;\n}\n\nexport interface BranchConfig {\n pattern: string;\n author_source: \"git\" | \"env\" | \"prompt\";\n author_env_var: string;\n}\n\nexport interface ProgressConfig {\n file: string;\n archive_threshold: number;\n archive_dir: string;\n}\n\nexport interface ClaudeConfig {\n permission_mode: string;\n agent_file: string;\n}\n\nexport interface GeminiConfig {\n sandbox_mode: string;\n agent_file: string;\n}\n\nexport interface CodexConfig {\n agent_file: string;\n}\n\nexport interface GitHubIssue {\n number: number;\n title: string;\n body: string;\n labels: string[];\n state: \"open\" | \"closed\";\n assignee?: string;\n url: string;\n}\n\nexport interface GitHubLabel {\n name: string;\n color: string;\n description?: string;\n}\n\nexport interface GitHubReviewComment {\n id?: number;\n author: string;\n body: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n}\n\nexport interface GitHubReview {\n author: string;\n body: string;\n state: string;\n submittedAt?: string;\n}\n\nexport interface GitHubReviewThread {\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments: GitHubReviewComment[];\n}\n\nexport interface GitHubPRComment {\n id?: string;\n author: string;\n body: string;\n createdAt?: string;\n}\n\nexport interface GitHubReviewData {\n reviews: GitHubReview[];\n reviewThreads: GitHubReviewThread[];\n comments: GitHubPRComment[];\n}\n\nexport interface ProgressEntry {\n date: string;\n type: string;\n description: string;\n issue?: number;\n decisions: string[];\n files: string[];\n tests: string[];\n concerns: string[];\n followUp: string[];\n commit?: string;\n}\n\nexport interface BranchInfo {\n name: string;\n author: string;\n type: string;\n issueNumber: number;\n slug: string;\n}\n\nexport const DEFAULT_LABELS: Record<string, GitHubLabel[]> = {\n workflow: [\n {\n name: \"ai-ready\",\n color: \"0E8A16\",\n description: \"Issue ready for AI implementation\",\n },\n {\n name: \"ai-in-progress\",\n color: \"FFA500\",\n description: \"AI currently working on this\",\n },\n {\n name: \"ai-completed\",\n color: \"1D76DB\",\n description: \"AI done, needs human review\",\n },\n {\n name: \"ai-blocked\",\n color: \"D93F0B\",\n description: \"AI couldn't complete, needs help\",\n },\n ],\n priority: [\n {\n name: \"priority:critical\",\n color: \"B60205\",\n description: \"Blocking production\",\n },\n {\n name: \"priority:high\",\n color: \"D93F0B\",\n description: \"Important features/bugs\",\n },\n {\n name: \"priority:medium\",\n color: \"FBCA04\",\n description: \"Nice-to-have improvements\",\n },\n { name: \"priority:low\", color: \"0E8A16\", description: \"Minor tweaks\" },\n ],\n risk: [\n {\n name: \"risk:low\",\n color: \"C2E0C6\",\n description: \"UI changes, tests, non-critical\",\n },\n {\n name: \"risk:medium\",\n color: \"FEF2C0\",\n description: \"API changes, new features\",\n },\n {\n name: \"risk:high\",\n color: \"F9D0C4\",\n description: \"Migrations, auth, security\",\n },\n ],\n type: [\n { name: \"type:feature\", color: \"1D76DB\", description: \"New feature\" },\n { name: \"type:fix\", color: \"D73A4A\", description: \"Bug fix\" },\n {\n name: \"type:refactor\",\n color: \"5319E7\",\n description: \"Code improvement\",\n },\n { name: \"type:chore\", color: \"FEF2C0\", description: \"Maintenance\" },\n { name: \"type:docs\", color: \"0075CA\", description: \"Documentation\" },\n { name: \"type:test\", color: \"D4C5F9\", description: \"Testing\" },\n ],\n area: [\n { name: \"area:ui\", color: \"C5DEF5\", description: \"User interface\" },\n { name: \"area:api\", color: \"D4C5F9\", description: \"API/Backend\" },\n { name: \"area:database\", color: \"FEF2C0\", description: \"Database/Models\" },\n {\n name: \"area:workers\",\n color: \"F9D0C4\",\n description: \"Background workers\",\n },\n { name: \"area:shared\", color: \"C2E0C6\", description: \"Shared libraries\" },\n { name: \"area:testing\", color: \"E99695\", description: \"Test infrastructure\" },\n { name: \"area:infra\", color: \"BFD4F2\", description: \"Infrastructure/DevOps\" },\n ],\n};\n","import type { GentConfig, GitHubLabel } from \"../types/index.js\";\nimport { DEFAULT_LABELS } from \"../types/index.js\";\n\nexport function getAllLabels(config: GentConfig): GitHubLabel[] {\n const labels: GitHubLabel[] = [];\n\n // Workflow labels\n labels.push(...DEFAULT_LABELS.workflow);\n\n // Priority labels\n for (const priority of config.github.labels.priorities) {\n const defaultLabel = DEFAULT_LABELS.priority.find(\n (l) => l.name === `priority:${priority}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `priority:${priority}`,\n color: \"FBCA04\",\n description: `Priority: ${priority}`,\n });\n }\n }\n\n // Risk labels\n for (const risk of config.github.labels.risks) {\n const defaultLabel = DEFAULT_LABELS.risk.find(\n (l) => l.name === `risk:${risk}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `risk:${risk}`,\n color: \"FEF2C0\",\n description: `Risk: ${risk}`,\n });\n }\n }\n\n // Type labels\n for (const type of config.github.labels.types) {\n const defaultLabel = DEFAULT_LABELS.type.find(\n (l) => l.name === `type:${type}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `type:${type}`,\n color: \"1D76DB\",\n description: `Type: ${type}`,\n });\n }\n }\n\n // Area labels\n for (const area of config.github.labels.areas) {\n const defaultLabel = DEFAULT_LABELS.area.find(\n (l) => l.name === `area:${area}`\n );\n if (defaultLabel) {\n labels.push(defaultLabel);\n } else {\n labels.push({\n name: `area:${area}`,\n color: \"C5DEF5\",\n description: `Area: ${area}`,\n });\n }\n }\n\n return labels;\n}\n\nexport function getWorkflowLabels(config: GentConfig): {\n ready: string;\n inProgress: string;\n completed: string;\n blocked: string;\n} {\n return {\n ready: config.github.labels.workflow.ready,\n inProgress: config.github.labels.workflow.in_progress,\n completed: config.github.labels.workflow.completed,\n blocked: config.github.labels.workflow.blocked,\n };\n}\n\nexport function buildIssueLabels(meta: {\n type: string;\n priority: string;\n risk: string;\n area: string;\n}): string[] {\n return [\n \"ai-ready\",\n `type:${meta.type}`,\n `priority:${meta.priority}`,\n `risk:${meta.risk}`,\n `area:${meta.area}`,\n ];\n}\n\nexport function extractTypeFromLabels(labels: string[]): string {\n for (const label of labels) {\n if (label.startsWith(\"type:\")) {\n return label.replace(\"type:\", \"\");\n }\n }\n return \"feature\";\n}\n\nexport function extractPriorityFromLabels(labels: string[]): string {\n for (const label of labels) {\n if (label.startsWith(\"priority:\")) {\n return label.replace(\"priority:\", \"\");\n }\n }\n return \"medium\";\n}\n\nexport function hasWorkflowLabel(\n labels: string[],\n workflowLabel: string\n): boolean {\n return labels.includes(workflowLabel);\n}\n\nexport function sortByPriority(issues: { labels: string[] }[]): void {\n const priorityOrder = [\"critical\", \"high\", \"medium\", \"low\"];\n\n issues.sort((a, b) => {\n const aPriority = extractPriorityFromLabels(a.labels);\n const bPriority = extractPriorityFromLabels(b.labels);\n return priorityOrder.indexOf(aPriority) - priorityOrder.indexOf(bPriority);\n });\n}\n","import { execa } from \"execa\";\nimport type { GitHubIssue, GitHubLabel, GitHubReviewData } from \"../types/index.js\";\n\nexport async function getIssue(issueNumber: number): Promise<GitHubIssue> {\n const { stdout } = await execa(\"gh\", [\n \"issue\",\n \"view\",\n String(issueNumber),\n \"--json\",\n \"number,title,body,labels,state,assignees,url\",\n ]);\n\n const data = JSON.parse(stdout);\n return {\n number: data.number,\n title: data.title,\n body: data.body || \"\",\n labels: data.labels.map((l: { name: string }) => l.name),\n state: data.state.toLowerCase(),\n assignee: data.assignees?.[0]?.login,\n url: data.url,\n };\n}\n\nexport async function listIssues(options: {\n labels?: string[];\n state?: \"open\" | \"closed\" | \"all\";\n limit?: number;\n}): Promise<GitHubIssue[]> {\n const args = [\"issue\", \"list\", \"--json\", \"number,title,body,labels,state,url\"];\n\n if (options.labels?.length) {\n args.push(\"--label\", options.labels.join(\",\"));\n }\n\n if (options.state) {\n args.push(\"--state\", options.state);\n }\n\n args.push(\"--limit\", String(options.limit || 50));\n\n const { stdout } = await execa(\"gh\", args);\n const data = JSON.parse(stdout);\n\n return data.map(\n (d: {\n number: number;\n title: string;\n body: string;\n labels: { name: string }[];\n state: string;\n url: string;\n }) => ({\n number: d.number,\n title: d.title,\n body: d.body || \"\",\n labels: d.labels.map((l) => l.name),\n state: d.state.toLowerCase() as \"open\" | \"closed\",\n url: d.url,\n })\n );\n}\n\nexport async function createIssue(options: {\n title: string;\n body: string;\n labels?: string[];\n}): Promise<number> {\n const args = [\"issue\", \"create\", \"--title\", options.title, \"--body\", options.body];\n\n if (options.labels?.length) {\n args.push(\"--label\", options.labels.join(\",\"));\n }\n\n const { stdout } = await execa(\"gh\", args);\n\n // Extract issue number from URL\n const match = stdout.match(/\\/issues\\/(\\d+)/);\n if (!match) {\n throw new Error(\"Failed to extract issue number from gh output\");\n }\n\n return parseInt(match[1], 10);\n}\n\nexport async function updateIssueLabels(\n issueNumber: number,\n options: {\n add?: string[];\n remove?: string[];\n }\n): Promise<void> {\n const promises: Promise<unknown>[] = [];\n\n if (options.add?.length) {\n promises.push(\n execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--add-label\",\n options.add.join(\",\"),\n ])\n );\n }\n\n if (options.remove?.length) {\n promises.push(\n execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--remove-label\",\n options.remove.join(\",\"),\n ])\n );\n }\n\n await Promise.all(promises);\n}\n\nexport async function addIssueComment(\n issueNumber: number,\n body: string\n): Promise<void> {\n await execa(\"gh\", [\"issue\", \"comment\", String(issueNumber), \"--body\", body]);\n}\n\nexport async function assignIssue(\n issueNumber: number,\n assignee: string\n): Promise<void> {\n await execa(\"gh\", [\n \"issue\",\n \"edit\",\n String(issueNumber),\n \"--add-assignee\",\n assignee,\n ]);\n}\n\nexport async function createLabel(label: GitHubLabel): Promise<void> {\n try {\n await execa(\"gh\", [\n \"label\",\n \"create\",\n label.name,\n \"--color\",\n label.color,\n \"--description\",\n label.description || \"\",\n \"--force\",\n ]);\n } catch {\n // Label might already exist, ignore error\n }\n}\n\nexport async function createPullRequest(options: {\n title: string;\n body: string;\n base?: string;\n draft?: boolean;\n}): Promise<string> {\n const args = [\n \"pr\",\n \"create\",\n \"--title\",\n options.title,\n \"--body\",\n options.body,\n \"--assignee\",\n \"@me\",\n ];\n\n if (options.base) {\n args.push(\"--base\", options.base);\n }\n\n if (options.draft) {\n args.push(\"--draft\");\n }\n\n const { stdout } = await execa(\"gh\", args);\n return stdout.trim();\n}\n\nexport interface PrBasicInfo {\n number: number;\n url: string;\n}\n\nexport interface PrStatusInfo {\n number: number;\n title: string;\n url: string;\n state: \"open\" | \"closed\" | \"merged\";\n reviewDecision: string | null;\n isDraft: boolean;\n}\n\nexport async function getPrForBranch(): Promise<PrBasicInfo | null> {\n try {\n const { stdout } = await execa(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,url\",\n ]);\n const data = JSON.parse(stdout);\n return { number: data.number, url: data.url };\n } catch {\n return null;\n }\n}\n\nexport async function getPrStatus(): Promise<PrStatusInfo | null> {\n try {\n const { stdout } = await execa(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,title,url,state,reviewDecision,isDraft\",\n ]);\n const data = JSON.parse(stdout);\n // gh pr view returns state as OPEN, CLOSED, or MERGED (uppercase)\n const state = (data.state?.toLowerCase() ?? \"open\") as \"open\" | \"closed\" | \"merged\";\n return {\n number: data.number,\n title: data.title ?? \"\",\n url: data.url,\n state,\n reviewDecision: data.reviewDecision ?? null,\n isDraft: data.isDraft ?? false,\n };\n } catch {\n return null;\n }\n}\n\nexport async function getPrReviewData(prNumber?: number): Promise<GitHubReviewData> {\n // Fetch reviews and comments using gh pr view (both are supported JSON fields)\n const prArgs = [\"pr\", \"view\"];\n if (prNumber) {\n prArgs.push(String(prNumber));\n }\n prArgs.push(\"--json\", \"reviews,comments\");\n\n const { stdout: prStdout } = await execa(\"gh\", prArgs);\n const prData = JSON.parse(prStdout);\n\n // Fetch review threads using GraphQL API (not available via gh pr view --json)\n // First get repo owner and name since GraphQL doesn't support {owner}/{repo} placeholders\n let reviewThreads: Array<{\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments: Array<{\n author: string;\n body: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n }>;\n }> = [];\n\n try {\n const { stdout: repoStdout } = await execa(\"gh\", [\"repo\", \"view\", \"--json\", \"owner,name\"]);\n const repoData = JSON.parse(repoStdout);\n const owner = repoData.owner?.login ?? repoData.owner;\n const repo = repoData.name;\n\n const graphqlQuery = `query { repository(owner: \"${owner}\", name: \"${repo}\") { pullRequest(number: ${prNumber}) { reviewThreads(first: 100) { nodes { isResolved isOutdated path line comments(first: 100) { nodes { databaseId author { login } body path line createdAt } } } } } } }`;\n\n const { stdout: graphqlStdout } = await execa(\"gh\", [\"api\", \"graphql\", \"-f\", `query=${graphqlQuery}`]);\n const graphqlData = JSON.parse(graphqlStdout);\n const prNode = graphqlData.data?.repository?.pullRequest;\n const threadNodes = prNode?.reviewThreads?.nodes ?? [];\n\n reviewThreads = threadNodes.map((thread: {\n isResolved?: boolean | null;\n isOutdated?: boolean;\n path?: string;\n line?: number | null;\n comments?: { nodes?: Array<{\n databaseId?: number;\n author?: { login?: string };\n body?: string;\n path?: string;\n line?: number | null;\n createdAt?: string;\n }> };\n }) => ({\n isResolved: thread.isResolved ?? null,\n isOutdated: thread.isOutdated ?? false,\n path: thread.path,\n line: thread.line ?? null,\n comments: (thread.comments?.nodes ?? []).map((comment) => ({\n id: comment.databaseId,\n author: comment.author?.login ?? \"unknown\",\n body: comment.body ?? \"\",\n path: comment.path ?? thread.path,\n line: comment.line ?? thread.line ?? null,\n createdAt: comment.createdAt,\n })),\n }));\n } catch {\n // If GraphQL fails (e.g., no permissions), continue with empty threads\n reviewThreads = [];\n }\n\n return {\n reviews: (prData.reviews ?? []).map((review: {\n author?: { login?: string };\n body?: string;\n state?: string;\n submittedAt?: string;\n }) => ({\n author: review.author?.login ?? \"unknown\",\n body: review.body ?? \"\",\n state: review.state ?? \"UNKNOWN\",\n submittedAt: review.submittedAt,\n })),\n reviewThreads,\n comments: (prData.comments ?? []).map((comment: {\n id?: string;\n author?: { login?: string };\n body?: string;\n createdAt?: string;\n }) => ({\n id: comment.id,\n author: comment.author?.login ?? \"unknown\",\n body: comment.body ?? \"\",\n createdAt: comment.createdAt,\n })),\n };\n}\n\nexport async function getCurrentUser(): Promise<string> {\n const { stdout } = await execa(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"]);\n return stdout.trim();\n}\n\nexport async function replyToReviewComment(\n prNumber: number,\n commentId: number,\n body: string\n): Promise<void> {\n await execa(\"gh\", [\n \"api\",\n `repos/{owner}/{repo}/pulls/${prNumber}/comments/${commentId}/replies`,\n \"-f\",\n `body=${body}`,\n ]);\n}\n\nexport async function addPrComment(prNumber: number, body: string): Promise<void> {\n await execa(\"gh\", [\"pr\", \"comment\", String(prNumber), \"--body\", body]);\n}\n","import { execa } from \"execa\";\nimport type { GentConfig, AIProvider } from \"../types/index.js\";\n\nexport async function checkGhCli(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkGhAuth(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"auth\", \"status\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkClaudeCli(): Promise<boolean> {\n try {\n await execa(\"claude\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkGeminiCli(): Promise<boolean> {\n try {\n await execa(\"gemini\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkCodexCLI(): Promise<boolean> {\n try {\n await execa(\"codex\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function checkAIProvider(provider: AIProvider): Promise<boolean> {\n switch (provider) {\n case \"claude\":\n return checkClaudeCli();\n case \"gemini\":\n return checkGeminiCli();\n case \"codex\":\n return checkCodexCLI();\n }\n}\n\nexport async function checkGitRepo(): Promise<boolean> {\n try {\n await execa(\"git\", [\"rev-parse\", \"--git-dir\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function validatePrerequisites(config?: GentConfig): Promise<{\n valid: boolean;\n missing: string[];\n}> {\n const checks = [\n { name: \"gh CLI\", check: checkGhCli },\n { name: \"gh auth\", check: checkGhAuth },\n { name: \"git repository\", check: checkGitRepo },\n ];\n\n const getProviderName = (provider: AIProvider) => {\n switch (provider) {\n case \"claude\":\n return \"claude CLI\";\n case \"gemini\":\n return \"gemini CLI\";\n case \"codex\":\n return \"codex CLI\";\n }\n };\n\n // Add AI provider check based on config\n if (config) {\n const provider = config.ai.provider;\n checks.push({\n name: getProviderName(provider),\n check: () => checkAIProvider(provider),\n });\n\n // Also check fallback if configured\n if (config.ai.fallback_provider) {\n const fallback = config.ai.fallback_provider;\n checks.push({\n name: `${getProviderName(fallback)} (fallback)`,\n check: () => checkAIProvider(fallback),\n });\n }\n } else {\n // Default to checking claude for backward compatibility\n checks.push({ name: \"claude CLI\", check: checkClaudeCli });\n }\n\n const missing: string[] = [];\n\n for (const { name, check } of checks) {\n const passed = await check();\n if (!passed) {\n missing.push(name);\n }\n }\n\n return {\n valid: missing.length === 0,\n missing,\n };\n}\n\nexport function isValidIssueNumber(value: string): boolean {\n const num = parseInt(value, 10);\n return !isNaN(num) && num > 0;\n}\n\nexport function sanitizeSlug(title: string, maxLength = 40): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLength);\n}\n","import { logger, colors } from \"../utils/logger.js\";\nimport { withSpinner } from \"../utils/spinner.js\";\nimport { loadConfig } from \"../lib/config.js\";\nimport { getAllLabels } from \"../lib/labels.js\";\nimport { createLabel } from \"../lib/github.js\";\nimport { checkGhAuth } from \"../utils/validators.js\";\n\nexport async function setupLabelsCommand(): Promise<void> {\n logger.bold(\"Setting up GitHub labels...\");\n logger.newline();\n\n // Check gh auth\n const isAuthed = await checkGhAuth();\n if (!isAuthed) {\n logger.error(\"Not authenticated with GitHub. Run 'gh auth login' first.\");\n process.exit(1);\n }\n\n const config = loadConfig();\n const labels = getAllLabels(config);\n\n logger.info(`Creating ${labels.length} labels...`);\n logger.newline();\n\n let created = 0;\n let failed = 0;\n\n for (const label of labels) {\n try {\n await withSpinner(`Creating ${colors.label(label.name)}`, async () => {\n await createLabel(label);\n });\n created++;\n } catch (error) {\n logger.error(`Failed to create ${label.name}: ${error}`);\n failed++;\n }\n }\n\n logger.newline();\n logger.success(`Created ${created} labels`);\n if (failed > 0) {\n logger.warning(`Failed to create ${failed} labels`);\n }\n\n logger.newline();\n logger.info(\"Labels are ready. You can now create AI-ready issues.\");\n}\n"],"mappings":"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","names":["execa","execa"]}
package/dist/index.js CHANGED
@@ -33,10 +33,9 @@ import {
33
33
  sanitizeSlug,
34
34
  setupLabelsCommand,
35
35
  sortByPriority,
36
- updateConfigProvider,
37
36
  updateIssueLabels,
38
37
  withSpinner
39
- } from "./chunk-TLGYE7J2.js";
38
+ } from "./chunk-UWYWIOYZ.js";
40
39
 
41
40
  // src/index.ts
42
41
  import { Command } from "commander";
@@ -197,7 +196,7 @@ async function initCommand(options) {
197
196
  }
198
197
  ]);
199
198
  if (setupLabels) {
200
- const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-FLCGVPFY.js");
199
+ const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-5EHRPUPF.js");
201
200
  await setupLabelsCommand2();
202
201
  }
203
202
  }
@@ -473,7 +472,7 @@ META:type=<type>,priority=<priority>,risk=<risk>,area=<area>
473
472
  Example: META:type=feature,priority=high,risk=low,area=ui`;
474
473
  return basePrompt;
475
474
  }
476
- function buildImplementationPrompt(issue, agentInstructions, progressContent, config, reviewFeedback = null) {
475
+ function buildImplementationPrompt(issue, agentInstructions, progressContent, config, extraContext = null) {
477
476
  const providerName = getProviderDisplayName(config.ai.provider);
478
477
  const providerEmail = getProviderEmail(config.ai.provider);
479
478
  return `GitHub Issue #${issue.number}: ${issue.title}
@@ -488,8 +487,7 @@ ${progressContent ? `## Previous Progress
488
487
  ${progressContent}
489
488
 
490
489
  ` : ""}
491
- ${reviewFeedback ? `## Review Feedback
492
- ${reviewFeedback}
490
+ ${extraContext ? `${extraContext}
493
491
 
494
492
  ` : ""}
495
493
 
@@ -664,11 +662,11 @@ async function createCommand(description, options) {
664
662
  ]);
665
663
  if (!ghAuth) {
666
664
  logger.error("Not authenticated with GitHub. Run 'gh auth login' first.");
667
- process.exit(1);
665
+ return;
668
666
  }
669
667
  if (!aiOk) {
670
668
  logger.error(`${providerName} CLI not found. Please install ${provider} CLI first.`);
671
- process.exit(1);
669
+ return;
672
670
  }
673
671
  const agentInstructions = loadAgentInstructions();
674
672
  let aiOutput;
@@ -1115,11 +1113,11 @@ async function runCommand(issueNumberArg, options) {
1115
1113
  ]);
1116
1114
  if (!ghAuth) {
1117
1115
  logger.error("Not authenticated with GitHub. Run 'gh auth login' first.");
1118
- process.exit(1);
1116
+ return;
1119
1117
  }
1120
1118
  if (!aiOk) {
1121
1119
  logger.error(`${providerName} CLI not found. Please install ${provider} CLI first.`);
1122
- process.exit(1);
1120
+ return;
1123
1121
  }
1124
1122
  const hasChanges = await hasUncommittedChanges();
1125
1123
  if (hasChanges) {
@@ -1134,7 +1132,7 @@ async function runCommand(issueNumberArg, options) {
1134
1132
  ]);
1135
1133
  if (!proceed) {
1136
1134
  logger.info("Aborting. Please commit or stash your changes first.");
1137
- process.exit(0);
1135
+ return;
1138
1136
  }
1139
1137
  }
1140
1138
  const workflowLabels = getWorkflowLabels(config);
@@ -1143,19 +1141,19 @@ async function runCommand(issueNumberArg, options) {
1143
1141
  const autoIssue = await autoSelectIssue(workflowLabels.ready);
1144
1142
  if (!autoIssue) {
1145
1143
  logger.error("No ai-ready issues found.");
1146
- process.exit(1);
1144
+ return;
1147
1145
  }
1148
1146
  issueNumber = autoIssue.number;
1149
1147
  logger.info(`Auto-selected: ${colors.issue(`#${issueNumber}`)} - ${autoIssue.title}`);
1150
1148
  } else if (issueNumberArg) {
1151
1149
  if (!isValidIssueNumber(issueNumberArg)) {
1152
1150
  logger.error("Invalid issue number.");
1153
- process.exit(1);
1151
+ return;
1154
1152
  }
1155
1153
  issueNumber = parseInt(issueNumberArg, 10);
1156
1154
  } else {
1157
1155
  logger.error("Please provide an issue number or use --auto");
1158
- process.exit(1);
1156
+ return;
1159
1157
  }
1160
1158
  let issue;
1161
1159
  try {
@@ -1814,7 +1812,8 @@ async function fixCommand(options) {
1814
1812
  });
1815
1813
  const agentInstructions = loadAgentInstructions();
1816
1814
  const progressContent = readProgress(config);
1817
- const prompt = buildImplementationPrompt(issue, agentInstructions, progressContent, config, summary);
1815
+ const prompt = buildImplementationPrompt(issue, agentInstructions, progressContent, config, `## Review Feedback
1816
+ ${summary}`);
1818
1817
  logger.newline();
1819
1818
  logger.info(`Starting ${colors.provider(providerName)} fix session...`);
1820
1819
  logger.dim("Review feedback will be appended to the implementation prompt.");
@@ -1894,7 +1893,7 @@ import { homedir } from "os";
1894
1893
  // package.json
1895
1894
  var package_default = {
1896
1895
  name: "@rotorsoft/gent",
1897
- version: "1.12.0",
1896
+ version: "1.12.1",
1898
1897
  description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
1899
1898
  keywords: [
1900
1899
  "cli",
@@ -2442,16 +2441,16 @@ function getAvailableActions(state) {
2442
2441
  if (state.hasUncommittedChanges) {
2443
2442
  actions.push({ id: "commit", label: "commit", shortcut: "c" });
2444
2443
  }
2445
- if (state.hasUnpushedCommits) {
2444
+ if (state.hasUnpushedCommits && state.commits.length > 0) {
2446
2445
  actions.push({ id: "push", label: "Push", shortcut: "P" });
2447
2446
  }
2448
2447
  if (!state.pr && state.commits.length > 0) {
2449
2448
  actions.push({ id: "pr", label: "Create pr", shortcut: "C" });
2450
2449
  }
2450
+ if (state.issue) {
2451
+ actions.push({ id: "implement", label: "implement", shortcut: "i" });
2452
+ }
2451
2453
  if (state.pr && state.pr.state === "open") {
2452
- if (state.hasActionableFeedback) {
2453
- actions.push({ id: "fix", label: "fix feedback", shortcut: "f" });
2454
- }
2455
2454
  if (state.hasUIChanges && state.isPlaywrightAvailable && state.config.video.enabled) {
2456
2455
  actions.push({ id: "video", label: "video", shortcut: "v" });
2457
2456
  }
@@ -2602,6 +2601,14 @@ function renderModal(message) {
2602
2601
  for (let i = 0; i < padY; i++) console.log();
2603
2602
  for (const line of lines) console.log(line);
2604
2603
  }
2604
+ function renderActionPanel(title, content) {
2605
+ const w = termWidth();
2606
+ console.log(topRow(title, w));
2607
+ for (const line of content) {
2608
+ console.log(row(line, w));
2609
+ }
2610
+ console.log(botRow(w));
2611
+ }
2605
2612
  function renderSettings(state, w) {
2606
2613
  const provider = getProviderDisplayName(state.config.ai.provider);
2607
2614
  const provTag = state.isAIProviderAvailable ? chalk3.green(provider) : chalk3.red(provider);
@@ -2773,7 +2780,7 @@ async function waitForKey(validKeys) {
2773
2780
  stdin.on("data", onData);
2774
2781
  });
2775
2782
  }
2776
- async function executeAction(actionId, state) {
2783
+ async function executeAction(actionId, state, providerSetter) {
2777
2784
  switch (actionId) {
2778
2785
  case "quit":
2779
2786
  return false;
@@ -2785,7 +2792,12 @@ async function executeAction(actionId, state) {
2785
2792
  case "run-auto": {
2786
2793
  clearScreen();
2787
2794
  if (!await confirm("Start AI agent to implement next ticket?")) return true;
2788
- await runCommand(void 0, { auto: true });
2795
+ try {
2796
+ await runCommand(void 0, { auto: true });
2797
+ } catch (error) {
2798
+ logger.error(`Run failed: ${error}`);
2799
+ await promptContinue();
2800
+ }
2789
2801
  return false;
2790
2802
  }
2791
2803
  case "create": {
@@ -2801,7 +2813,11 @@ async function executeAction(actionId, state) {
2801
2813
  logger.info("Cancelled");
2802
2814
  return true;
2803
2815
  }
2804
- await createCommand(description, {});
2816
+ try {
2817
+ await createCommand(description, {});
2818
+ } catch (error) {
2819
+ logger.error(`Create failed: ${error}`);
2820
+ }
2805
2821
  await promptContinue();
2806
2822
  return true;
2807
2823
  }
@@ -2822,10 +2838,20 @@ async function executeAction(actionId, state) {
2822
2838
  await promptContinue();
2823
2839
  return true;
2824
2840
  }
2825
- case "fix": {
2841
+ case "implement": {
2826
2842
  clearScreen();
2827
- if (!await confirm("Start AI agent to fix review feedback?")) return true;
2828
- await fixCommand({});
2843
+ const hasCommits = state.commits.length > 0;
2844
+ const hasFeedback = state.hasActionableFeedback;
2845
+ let msg;
2846
+ if (hasFeedback && hasCommits) {
2847
+ msg = "Start AI agent to address review feedback?";
2848
+ } else if (hasCommits) {
2849
+ msg = "Start AI agent to continue implementation from existing commits?";
2850
+ } else {
2851
+ msg = "Start AI agent to implement this ticket from scratch?";
2852
+ }
2853
+ if (!await confirm(msg)) return true;
2854
+ await handleImplement(state);
2829
2855
  return false;
2830
2856
  }
2831
2857
  case "video": {
@@ -2837,7 +2863,7 @@ async function executeAction(actionId, state) {
2837
2863
  }
2838
2864
  case "switch-provider":
2839
2865
  clearScreen();
2840
- await handleSwitchProvider(state);
2866
+ await handleSwitchProvider(state, providerSetter);
2841
2867
  return true;
2842
2868
  case "checkout-main": {
2843
2869
  clearScreen();
@@ -2920,6 +2946,50 @@ async function generateCommitMessage(diffContent, issueNumber, issueTitle, state
2920
2946
  return message.trim() || CANCEL;
2921
2947
  }
2922
2948
  }
2949
+ async function handleImplement(state) {
2950
+ if (!state.issue) {
2951
+ logger.error("No linked issue found");
2952
+ return;
2953
+ }
2954
+ const agentInstructions = loadAgentInstructions();
2955
+ const progressContent = readProgress(state.config);
2956
+ const contextParts = [];
2957
+ if (state.commits.length > 0) {
2958
+ contextParts.push(
2959
+ `## Current Progress
2960
+ There are ${state.commits.length} existing commit(s) on this branch:
2961
+ ${state.commits.map((c) => `- ${c}`).join("\n")}
2962
+
2963
+ Continue the implementation from where it left off. Review the existing work and complete any remaining tasks.`
2964
+ );
2965
+ }
2966
+ if (state.hasActionableFeedback && state.reviewFeedback.length > 0) {
2967
+ const feedbackLines = state.reviewFeedback.map((f) => `- [${f.source}] ${f.body.slice(0, 200)}`).join("\n");
2968
+ contextParts.push(`## Review Feedback
2969
+ ${feedbackLines}`);
2970
+ }
2971
+ const extraContext = contextParts.length > 0 ? contextParts.join("\n\n") : null;
2972
+ const prompt = buildImplementationPrompt(
2973
+ state.issue,
2974
+ agentInstructions,
2975
+ progressContent,
2976
+ state.config,
2977
+ extraContext
2978
+ );
2979
+ const providerName = getProviderDisplayName(state.config.ai.provider);
2980
+ clearScreen();
2981
+ renderActionPanel(`${providerName} Session`, [
2982
+ `Implementing: #${state.issue.number} ${state.issue.title}`,
2983
+ state.commits.length > 0 ? `Continuing from ${state.commits.length} existing commit(s)` : "Starting fresh implementation",
2984
+ ...state.hasActionableFeedback ? [`Includes ${state.reviewFeedback.length} review feedback item(s)`] : []
2985
+ ]);
2986
+ console.log();
2987
+ try {
2988
+ await invokeAIInteractive(prompt, state.config);
2989
+ } catch (error) {
2990
+ logger.error(`${providerName} session failed: ${error}`);
2991
+ }
2992
+ }
2923
2993
  async function handlePush() {
2924
2994
  try {
2925
2995
  const { stdout: branch } = await execa4("git", ["branch", "--show-current"]);
@@ -2933,7 +3003,7 @@ async function handlePush() {
2933
3003
  }
2934
3004
  }
2935
3005
  var PROVIDERS = ["claude", "gemini", "codex"];
2936
- async function handleSwitchProvider(state) {
3006
+ async function handleSwitchProvider(state, setProvider) {
2937
3007
  const current = state.config.ai.provider;
2938
3008
  const { provider } = await inquirer6.prompt([
2939
3009
  {
@@ -2948,12 +3018,8 @@ async function handleSwitchProvider(state) {
2948
3018
  }
2949
3019
  ]);
2950
3020
  if (provider === current) return;
2951
- try {
2952
- updateConfigProvider(provider);
2953
- logger.success(`Provider switched to ${provider}`);
2954
- } catch (error) {
2955
- logger.error(`Failed to switch provider: ${error}`);
2956
- }
3021
+ setProvider(provider);
3022
+ logger.success(`Provider switched to ${provider} (session only)`);
2957
3023
  }
2958
3024
  async function handleCheckoutMain() {
2959
3025
  try {
@@ -2971,6 +3037,13 @@ async function handleVideoCapture(state) {
2971
3037
  logger.error("No linked issue found");
2972
3038
  return;
2973
3039
  }
3040
+ const providerName = getProviderDisplayName(state.config.ai.provider);
3041
+ clearScreen();
3042
+ renderActionPanel("Video Capture", [
3043
+ `Recording: #${state.issue.number} ${state.issue.title}`,
3044
+ `Provider: ${providerName}`
3045
+ ]);
3046
+ console.log();
2974
3047
  try {
2975
3048
  const agentInstructions = loadAgentInstructions();
2976
3049
  const videoPrompt = buildVideoPrompt(
@@ -2997,8 +3070,15 @@ async function promptContinue() {
2997
3070
  }
2998
3071
  async function tuiCommand() {
2999
3072
  let running = true;
3073
+ let providerOverride = null;
3074
+ const setProvider = (p) => {
3075
+ providerOverride = p;
3076
+ };
3000
3077
  while (running) {
3001
3078
  const state = await loadState();
3079
+ if (providerOverride) {
3080
+ state.config.ai.provider = providerOverride;
3081
+ }
3002
3082
  clearScreen();
3003
3083
  const actions = getAvailableActions(state);
3004
3084
  let hint;
@@ -3014,7 +3094,7 @@ async function tuiCommand() {
3014
3094
  const key = await waitForKey(validKeys);
3015
3095
  const action = actions.find((a) => a.shortcut === key);
3016
3096
  if (action) {
3017
- running = await executeAction(action.id, state);
3097
+ running = await executeAction(action.id, state, setProvider);
3018
3098
  }
3019
3099
  }
3020
3100
  }