@rotorsoft/gent 1.7.0 → 1.8.0
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.
- package/README.md +16 -7
- package/dist/{chunk-2LGYNV6S.js → chunk-XQJWUAG6.js} +30 -4
- package/dist/chunk-XQJWUAG6.js.map +1 -0
- package/dist/index.js +197 -30
- package/dist/index.js.map +1 -1
- package/dist/{setup-labels-3IMSEEKN.js → setup-labels-WXNPB6OD.js} +2 -2
- package/package.json +2 -2
- package/dist/chunk-2LGYNV6S.js.map +0 -1
- /package/dist/{setup-labels-3IMSEEKN.js.map → setup-labels-WXNPB6OD.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @rotorsoft/gent
|
|
2
2
|
|
|
3
|
-
AI-powered GitHub workflow CLI - leverage AI (Claude or
|
|
3
|
+
AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -21,15 +21,17 @@ pnpm add -g @rotorsoft/gent
|
|
|
21
21
|
|
|
22
22
|
- **Node.js** 20 or higher
|
|
23
23
|
- **GitHub CLI** (`gh`) - [Install](https://cli.github.com/)
|
|
24
|
-
- **AI CLI** (one or
|
|
24
|
+
- **AI CLI** (one or more):
|
|
25
25
|
- **Claude CLI** - [Install](https://claude.ai/code)
|
|
26
26
|
- **Gemini CLI** - [Install](https://github.com/google-gemini/gemini-cli)
|
|
27
|
+
- **Codex CLI** - [Install](https://github.com/openai/codex)
|
|
27
28
|
|
|
28
29
|
Verify prerequisites:
|
|
29
30
|
```bash
|
|
30
31
|
gh auth status # Should show authenticated
|
|
31
32
|
claude --version # Should show version (if using Claude)
|
|
32
33
|
gemini --version # Should show version (if using Gemini)
|
|
34
|
+
codex --version # Should show version (if using Codex)
|
|
33
35
|
```
|
|
34
36
|
|
|
35
37
|
## Quick Start
|
|
@@ -133,7 +135,7 @@ gent create "Fix login bug" --provider gemini # Use specific AI provider
|
|
|
133
135
|
|
|
134
136
|
Options:
|
|
135
137
|
- `-y, --yes` - Skip confirmation and create issue immediately
|
|
136
|
-
- `-p, --provider <provider>` - AI provider to use (`claude` or `
|
|
138
|
+
- `-p, --provider <provider>` - AI provider to use (`claude`, `gemini`, or `codex`)
|
|
137
139
|
|
|
138
140
|
### `gent list`
|
|
139
141
|
|
|
@@ -163,7 +165,7 @@ gent run 123 --provider gemini # Use specific AI provider
|
|
|
163
165
|
|
|
164
166
|
Options:
|
|
165
167
|
- `-a, --auto` - Auto-select highest priority ai-ready issue
|
|
166
|
-
- `-p, --provider <provider>` - AI provider to use (`claude` or `
|
|
168
|
+
- `-p, --provider <provider>` - AI provider to use (`claude`, `gemini`, or `codex`)
|
|
167
169
|
|
|
168
170
|
### `gent pr`
|
|
169
171
|
|
|
@@ -177,7 +179,7 @@ gent pr --provider gemini # Use specific AI provider
|
|
|
177
179
|
|
|
178
180
|
Options:
|
|
179
181
|
- `-d, --draft` - Create as draft PR
|
|
180
|
-
- `-p, --provider <provider>` - AI provider to use (`claude` or `
|
|
182
|
+
- `-p, --provider <provider>` - AI provider to use (`claude`, `gemini`, or `codex`)
|
|
181
183
|
|
|
182
184
|
### `gent status`
|
|
183
185
|
|
|
@@ -231,8 +233,15 @@ claude:
|
|
|
231
233
|
permission_mode: "acceptEdits"
|
|
232
234
|
agent_file: "AGENT.md"
|
|
233
235
|
|
|
236
|
+
gemini:
|
|
237
|
+
sandbox_mode: "on"
|
|
238
|
+
agent_file: "AGENT.md"
|
|
239
|
+
|
|
240
|
+
codex:
|
|
241
|
+
agent_file: "AGENT.md"
|
|
242
|
+
|
|
234
243
|
ai:
|
|
235
|
-
provider: "claude" # claude | gemini
|
|
244
|
+
provider: "claude" # claude | gemini | codex
|
|
236
245
|
fallback_provider: "gemini" # optional fallback when rate limited
|
|
237
246
|
auto_fallback: true # automatically switch to fallback on rate limit
|
|
238
247
|
|
|
@@ -371,7 +380,7 @@ The author is derived from:
|
|
|
371
380
|
| Variable | Description |
|
|
372
381
|
|----------|-------------|
|
|
373
382
|
| `GENT_AUTHOR` | Override author initials for branch naming |
|
|
374
|
-
| `GENT_AI_PROVIDER` | Override AI provider (`claude` or `
|
|
383
|
+
| `GENT_AI_PROVIDER` | Override AI provider (`claude`, `gemini`, or `codex`) |
|
|
375
384
|
| `DEBUG` | Enable debug output |
|
|
376
385
|
|
|
377
386
|
## Tips
|
|
@@ -113,6 +113,9 @@ var DEFAULT_CONFIG = {
|
|
|
113
113
|
sandbox_mode: "on",
|
|
114
114
|
agent_file: "AGENT.md"
|
|
115
115
|
},
|
|
116
|
+
codex: {
|
|
117
|
+
agent_file: "AGENT.md"
|
|
118
|
+
},
|
|
116
119
|
ai: {
|
|
117
120
|
provider: "claude",
|
|
118
121
|
auto_fallback: true
|
|
@@ -186,6 +189,10 @@ function mergeConfig(defaults, user) {
|
|
|
186
189
|
...defaults.gemini,
|
|
187
190
|
...user.gemini
|
|
188
191
|
},
|
|
192
|
+
codex: {
|
|
193
|
+
...defaults.codex,
|
|
194
|
+
...user.codex
|
|
195
|
+
},
|
|
189
196
|
ai: {
|
|
190
197
|
...defaults.ai,
|
|
191
198
|
...user.ai,
|
|
@@ -195,7 +202,7 @@ function mergeConfig(defaults, user) {
|
|
|
195
202
|
validation: user.validation ?? defaults.validation
|
|
196
203
|
};
|
|
197
204
|
}
|
|
198
|
-
function generateDefaultConfig() {
|
|
205
|
+
function generateDefaultConfig(provider = "claude") {
|
|
199
206
|
return `# Gent Configuration
|
|
200
207
|
# See https://github.com/rotorsoft/gent for documentation
|
|
201
208
|
version: 1
|
|
@@ -255,9 +262,13 @@ gemini:
|
|
|
255
262
|
sandbox_mode: "on"
|
|
256
263
|
agent_file: "AGENT.md"
|
|
257
264
|
|
|
265
|
+
# Codex settings
|
|
266
|
+
codex:
|
|
267
|
+
agent_file: "AGENT.md"
|
|
268
|
+
|
|
258
269
|
# AI provider settings
|
|
259
270
|
ai:
|
|
260
|
-
provider: "
|
|
271
|
+
provider: "${provider}" # claude | gemini | codex
|
|
261
272
|
# fallback_provider: "gemini" # optional fallback when rate limited
|
|
262
273
|
auto_fallback: true # automatically switch to fallback on rate limit
|
|
263
274
|
|
|
@@ -632,8 +643,23 @@ async function checkGeminiCli() {
|
|
|
632
643
|
return false;
|
|
633
644
|
}
|
|
634
645
|
}
|
|
646
|
+
async function checkCodexCLI() {
|
|
647
|
+
try {
|
|
648
|
+
await execa2("codex", ["--version"]);
|
|
649
|
+
return true;
|
|
650
|
+
} catch {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
635
654
|
async function checkAIProvider(provider) {
|
|
636
|
-
|
|
655
|
+
switch (provider) {
|
|
656
|
+
case "claude":
|
|
657
|
+
return checkClaudeCli();
|
|
658
|
+
case "gemini":
|
|
659
|
+
return checkGeminiCli();
|
|
660
|
+
case "codex":
|
|
661
|
+
return checkCodexCLI();
|
|
662
|
+
}
|
|
637
663
|
}
|
|
638
664
|
async function checkGitRepo() {
|
|
639
665
|
try {
|
|
@@ -718,4 +744,4 @@ export {
|
|
|
718
744
|
getCurrentUser,
|
|
719
745
|
setupLabelsCommand
|
|
720
746
|
};
|
|
721
|
-
//# sourceMappingURL=chunk-
|
|
747
|
+
//# sourceMappingURL=chunk-XQJWUAG6.js.map
|
|
@@ -0,0 +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 } 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 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 validation: user.validation ?? defaults.validation,\n };\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# 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 validation: string[];\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 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 } 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 async function getPrForBranch(): Promise<{\n number: number;\n url: string;\n} | 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 getCurrentUser(): Promise<string> {\n const { stdout } = await execa(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"]);\n return stdout.trim();\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
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
sortByPriority,
|
|
31
31
|
updateIssueLabels,
|
|
32
32
|
withSpinner
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-XQJWUAG6.js";
|
|
34
34
|
|
|
35
35
|
// src/index.ts
|
|
36
36
|
import { Command } from "commander";
|
|
@@ -154,8 +154,17 @@ async function initCommand(options) {
|
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
+
const { provider } = await inquirer.prompt([
|
|
158
|
+
{
|
|
159
|
+
type: "list",
|
|
160
|
+
name: "provider",
|
|
161
|
+
message: "Which AI provider would you like to use by default?",
|
|
162
|
+
choices: ["claude", "gemini", "codex"],
|
|
163
|
+
default: "claude"
|
|
164
|
+
}
|
|
165
|
+
]);
|
|
157
166
|
const configPath = getConfigPath(cwd);
|
|
158
|
-
writeFileSync2(configPath, generateDefaultConfig(), "utf-8");
|
|
167
|
+
writeFileSync2(configPath, generateDefaultConfig(provider), "utf-8");
|
|
159
168
|
logger.success(`Created ${colors.file(".gent.yml")}`);
|
|
160
169
|
const agentPath = join2(cwd, "AGENT.md");
|
|
161
170
|
if (!existsSync2(agentPath) || options.force) {
|
|
@@ -182,7 +191,7 @@ async function initCommand(options) {
|
|
|
182
191
|
}
|
|
183
192
|
]);
|
|
184
193
|
if (setupLabels) {
|
|
185
|
-
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-
|
|
194
|
+
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-WXNPB6OD.js");
|
|
186
195
|
await setupLabelsCommand2();
|
|
187
196
|
}
|
|
188
197
|
}
|
|
@@ -194,17 +203,27 @@ import chalk from "chalk";
|
|
|
194
203
|
// src/lib/ai-provider.ts
|
|
195
204
|
import { spawn } from "child_process";
|
|
196
205
|
import { execa } from "execa";
|
|
206
|
+
async function invokeInternal(provider, options) {
|
|
207
|
+
switch (provider) {
|
|
208
|
+
case "claude":
|
|
209
|
+
return invokeClaudeInternal(options);
|
|
210
|
+
case "gemini":
|
|
211
|
+
return invokeGeminiInternal(options);
|
|
212
|
+
case "codex":
|
|
213
|
+
return invokeCodexInternal(options);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
197
216
|
async function invokeAI(options, config, providerOverride) {
|
|
198
217
|
const provider = providerOverride ?? config.ai.provider;
|
|
199
218
|
try {
|
|
200
|
-
const output =
|
|
219
|
+
const output = await invokeInternal(provider, options);
|
|
201
220
|
return { output, provider };
|
|
202
221
|
} catch (error) {
|
|
203
222
|
if (isRateLimitError(error, provider)) {
|
|
204
223
|
if (config.ai.auto_fallback && config.ai.fallback_provider && !providerOverride) {
|
|
205
224
|
const fallback = config.ai.fallback_provider;
|
|
206
225
|
logger.warning(`Rate limit reached on ${getProviderDisplayName(provider)}, switching to ${getProviderDisplayName(fallback)}...`);
|
|
207
|
-
const output =
|
|
226
|
+
const output = await invokeInternal(fallback, options);
|
|
208
227
|
return { output, provider: fallback };
|
|
209
228
|
}
|
|
210
229
|
const err = error;
|
|
@@ -217,28 +236,52 @@ async function invokeAI(options, config, providerOverride) {
|
|
|
217
236
|
}
|
|
218
237
|
async function invokeAIInteractive(prompt, config, providerOverride) {
|
|
219
238
|
const provider = providerOverride ?? config.ai.provider;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
239
|
+
switch (provider) {
|
|
240
|
+
case "claude": {
|
|
241
|
+
const args = ["--permission-mode", config.claude.permission_mode, prompt];
|
|
242
|
+
return {
|
|
243
|
+
result: execa("claude", args, { stdio: "inherit" }),
|
|
244
|
+
provider
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
case "gemini": {
|
|
248
|
+
return {
|
|
249
|
+
result: execa("gemini", ["-i", prompt], { stdio: "inherit" }),
|
|
250
|
+
provider
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
case "codex": {
|
|
254
|
+
const args = prompt ? [prompt] : [];
|
|
255
|
+
return {
|
|
256
|
+
result: execa("codex", args, { stdio: "inherit" }),
|
|
257
|
+
provider
|
|
258
|
+
};
|
|
259
|
+
}
|
|
231
260
|
}
|
|
232
261
|
}
|
|
233
262
|
function getProviderDisplayName(provider) {
|
|
234
|
-
|
|
263
|
+
switch (provider) {
|
|
264
|
+
case "claude":
|
|
265
|
+
return "Claude";
|
|
266
|
+
case "gemini":
|
|
267
|
+
return "Gemini";
|
|
268
|
+
case "codex":
|
|
269
|
+
return "Codex";
|
|
270
|
+
}
|
|
235
271
|
}
|
|
236
272
|
function getProviderEmail(provider) {
|
|
237
|
-
|
|
273
|
+
switch (provider) {
|
|
274
|
+
case "claude":
|
|
275
|
+
return "noreply@anthropic.com";
|
|
276
|
+
case "gemini":
|
|
277
|
+
return "noreply@google.com";
|
|
278
|
+
case "codex":
|
|
279
|
+
return "noreply@openai.com";
|
|
280
|
+
}
|
|
238
281
|
}
|
|
239
282
|
function isRateLimitError(error, provider) {
|
|
240
283
|
if (!error || typeof error !== "object") return false;
|
|
241
|
-
if (provider === "claude" && "exitCode" in error && error.exitCode === 2) {
|
|
284
|
+
if ((provider === "claude" || provider === "codex") && "exitCode" in error && error.exitCode === 2) {
|
|
242
285
|
return true;
|
|
243
286
|
}
|
|
244
287
|
if ("message" in error && typeof error.message === "string") {
|
|
@@ -330,6 +373,44 @@ async function invokeGeminiInternal(options) {
|
|
|
330
373
|
return stdout;
|
|
331
374
|
}
|
|
332
375
|
}
|
|
376
|
+
async function invokeCodexInternal(options) {
|
|
377
|
+
const args = ["exec", options.prompt];
|
|
378
|
+
if (options.printOutput) {
|
|
379
|
+
const subprocess = execa("codex", args, {
|
|
380
|
+
stdio: "inherit"
|
|
381
|
+
});
|
|
382
|
+
await subprocess;
|
|
383
|
+
return "";
|
|
384
|
+
} else if (options.streamOutput) {
|
|
385
|
+
return new Promise((resolve, reject) => {
|
|
386
|
+
const child = spawn("codex", args, {
|
|
387
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
388
|
+
});
|
|
389
|
+
let output = "";
|
|
390
|
+
child.stdout.on("data", (chunk) => {
|
|
391
|
+
const text = chunk.toString();
|
|
392
|
+
output += text;
|
|
393
|
+
process.stdout.write(text);
|
|
394
|
+
});
|
|
395
|
+
child.stderr.on("data", (chunk) => {
|
|
396
|
+
process.stderr.write(chunk);
|
|
397
|
+
});
|
|
398
|
+
child.on("close", (code) => {
|
|
399
|
+
if (code === 0) {
|
|
400
|
+
resolve(output);
|
|
401
|
+
} else {
|
|
402
|
+
const error = new Error(`Codex exited with code ${code}`);
|
|
403
|
+
error.exitCode = code ?? 1;
|
|
404
|
+
reject(error);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
child.on("error", reject);
|
|
408
|
+
});
|
|
409
|
+
} else {
|
|
410
|
+
const { stdout } = await execa("codex", args);
|
|
411
|
+
return stdout;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
333
414
|
|
|
334
415
|
// src/lib/prompts.ts
|
|
335
416
|
function buildTicketPrompt(description, agentInstructions, additionalHints = null) {
|
|
@@ -1355,20 +1436,106 @@ function generateFallbackBody(issue, commits) {
|
|
|
1355
1436
|
|
|
1356
1437
|
// src/lib/version.ts
|
|
1357
1438
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1358
|
-
import { join as join3
|
|
1359
|
-
import { fileURLToPath } from "url";
|
|
1439
|
+
import { join as join3 } from "path";
|
|
1360
1440
|
import { homedir } from "os";
|
|
1361
|
-
|
|
1441
|
+
|
|
1442
|
+
// package.json
|
|
1443
|
+
var package_default = {
|
|
1444
|
+
name: "@rotorsoft/gent",
|
|
1445
|
+
version: "1.8.0",
|
|
1446
|
+
description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
|
|
1447
|
+
keywords: [
|
|
1448
|
+
"cli",
|
|
1449
|
+
"ai",
|
|
1450
|
+
"claude",
|
|
1451
|
+
"github",
|
|
1452
|
+
"workflow",
|
|
1453
|
+
"automation",
|
|
1454
|
+
"developer-tools"
|
|
1455
|
+
],
|
|
1456
|
+
homepage: "https://github.com/rotorsoft/gent#readme",
|
|
1457
|
+
bugs: {
|
|
1458
|
+
url: "https://github.com/rotorsoft/gent/issues"
|
|
1459
|
+
},
|
|
1460
|
+
repository: {
|
|
1461
|
+
type: "git",
|
|
1462
|
+
url: "git+https://github.com/rotorsoft/gent.git"
|
|
1463
|
+
},
|
|
1464
|
+
license: "MIT",
|
|
1465
|
+
author: "Rotorsoft",
|
|
1466
|
+
type: "module",
|
|
1467
|
+
exports: {
|
|
1468
|
+
".": {
|
|
1469
|
+
import: "./dist/index.js",
|
|
1470
|
+
types: "./dist/index.d.ts"
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
main: "./dist/index.js",
|
|
1474
|
+
types: "./dist/index.d.ts",
|
|
1475
|
+
bin: {
|
|
1476
|
+
gent: "./dist/index.js"
|
|
1477
|
+
},
|
|
1478
|
+
files: [
|
|
1479
|
+
"dist",
|
|
1480
|
+
"templates"
|
|
1481
|
+
],
|
|
1482
|
+
scripts: {
|
|
1483
|
+
build: "tsup",
|
|
1484
|
+
dev: "tsx src/index.ts",
|
|
1485
|
+
watch: "tsup --watch",
|
|
1486
|
+
test: "vitest run",
|
|
1487
|
+
"test:watch": "vitest",
|
|
1488
|
+
"test:coverage": "vitest run --coverage",
|
|
1489
|
+
lint: "eslint src/",
|
|
1490
|
+
"lint:fix": "eslint src/ --fix",
|
|
1491
|
+
format: 'prettier --write "src/**/*.ts"',
|
|
1492
|
+
"format:check": 'prettier --check "src/**/*.ts"',
|
|
1493
|
+
typecheck: "tsc --noEmit",
|
|
1494
|
+
prepublishOnly: "npm run build",
|
|
1495
|
+
prepare: "npm run build"
|
|
1496
|
+
},
|
|
1497
|
+
dependencies: {
|
|
1498
|
+
chalk: "^5.3.0",
|
|
1499
|
+
commander: "^12.1.0",
|
|
1500
|
+
execa: "^9.5.2",
|
|
1501
|
+
inquirer: "^12.2.0",
|
|
1502
|
+
ora: "^8.1.1",
|
|
1503
|
+
yaml: "^2.6.1"
|
|
1504
|
+
},
|
|
1505
|
+
devDependencies: {
|
|
1506
|
+
"@eslint/js": "^9.17.0",
|
|
1507
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
1508
|
+
"@semantic-release/git": "^10.0.1",
|
|
1509
|
+
"@types/inquirer": "^9.0.7",
|
|
1510
|
+
"@types/node": "^22.10.5",
|
|
1511
|
+
"@typescript-eslint/eslint-plugin": "^8.19.1",
|
|
1512
|
+
"@typescript-eslint/parser": "^8.19.1",
|
|
1513
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
1514
|
+
eslint: "^9.17.0",
|
|
1515
|
+
"eslint-config-prettier": "^9.1.0",
|
|
1516
|
+
prettier: "^3.4.2",
|
|
1517
|
+
"semantic-release": "^24.2.1",
|
|
1518
|
+
tsup: "^8.3.5",
|
|
1519
|
+
tsx: "^4.21.0",
|
|
1520
|
+
typescript: "^5.7.3",
|
|
1521
|
+
vitest: "^2.1.8"
|
|
1522
|
+
},
|
|
1523
|
+
engines: {
|
|
1524
|
+
node: ">=20.0.0"
|
|
1525
|
+
},
|
|
1526
|
+
publishConfig: {
|
|
1527
|
+
access: "public"
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
// src/lib/version.ts
|
|
1362
1532
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@rotorsoft/gent/latest";
|
|
1363
1533
|
var CACHE_DIR = join3(homedir(), ".gent");
|
|
1364
1534
|
var CACHE_FILE = join3(CACHE_DIR, "version-check.json");
|
|
1365
1535
|
var DEFAULT_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
1366
1536
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
1367
1537
|
function getVersion() {
|
|
1368
|
-
|
|
1369
|
-
readFileSync2(join3(__dirname, "../../package.json"), "utf8")
|
|
1370
|
-
);
|
|
1371
|
-
return packageJson.version;
|
|
1538
|
+
return package_default.version;
|
|
1372
1539
|
}
|
|
1373
1540
|
function compareVersions(a, b) {
|
|
1374
1541
|
const parseVersion = (v) => {
|
|
@@ -1617,7 +1784,7 @@ function startVersionCheck() {
|
|
|
1617
1784
|
});
|
|
1618
1785
|
}
|
|
1619
1786
|
var program = new Command();
|
|
1620
|
-
program.name("gent").description("AI-powered GitHub workflow CLI - leverage AI (Claude or
|
|
1787
|
+
program.name("gent").description("AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs").version(version).option("--skip-update-check", "Skip checking for CLI updates").hook("preAction", (thisCommand) => {
|
|
1621
1788
|
if (!thisCommand.opts().skipUpdateCheck) {
|
|
1622
1789
|
startVersionCheck();
|
|
1623
1790
|
}
|
|
@@ -1628,7 +1795,7 @@ program.command("init").description("Initialize gent workflow in current reposit
|
|
|
1628
1795
|
program.command("setup-labels").description("Setup GitHub labels for AI workflow").action(async () => {
|
|
1629
1796
|
await setupLabelsCommand();
|
|
1630
1797
|
});
|
|
1631
|
-
program.command("create <description>").description("Create an AI-enhanced GitHub issue").option("-y, --yes", "Skip confirmation and create issue immediately").option("-p, --provider <provider>", "AI provider to use (claude or
|
|
1798
|
+
program.command("create <description>").description("Create an AI-enhanced GitHub issue").option("-y, --yes", "Skip confirmation and create issue immediately").option("-p, --provider <provider>", "AI provider to use (claude, gemini, or codex)").option("-t, --title <title>", "Override the generated issue title").action(async (description, options) => {
|
|
1632
1799
|
await createCommand(description, { yes: options.yes, provider: options.provider, title: options.title });
|
|
1633
1800
|
});
|
|
1634
1801
|
program.command("list").description("List GitHub issues by label/status").option("-l, --label <label>", "Filter by label").option("-s, --status <status>", "Filter by workflow status (ready, in-progress, completed, blocked, all)").option("-n, --limit <number>", "Maximum number of issues to show", "20").action(async (options) => {
|
|
@@ -1638,10 +1805,10 @@ program.command("list").description("List GitHub issues by label/status").option
|
|
|
1638
1805
|
limit: parseInt(options.limit, 10)
|
|
1639
1806
|
});
|
|
1640
1807
|
});
|
|
1641
|
-
program.command("run [issue-number]").description("Run AI to implement a GitHub issue").option("-a, --auto", "Auto-select highest priority ai-ready issue").option("-p, --provider <provider>", "AI provider to use (claude or
|
|
1808
|
+
program.command("run [issue-number]").description("Run AI to implement a GitHub issue").option("-a, --auto", "Auto-select highest priority ai-ready issue").option("-p, --provider <provider>", "AI provider to use (claude, gemini, or codex)").action(async (issueNumber, options) => {
|
|
1642
1809
|
await runCommand(issueNumber, { auto: options.auto, provider: options.provider });
|
|
1643
1810
|
});
|
|
1644
|
-
program.command("pr").description("Create an AI-enhanced pull request").option("-d, --draft", "Create as draft PR").option("-p, --provider <provider>", "AI provider to use (claude or
|
|
1811
|
+
program.command("pr").description("Create an AI-enhanced pull request").option("-d, --draft", "Create as draft PR").option("-p, --provider <provider>", "AI provider to use (claude, gemini, or codex)").action(async (options) => {
|
|
1645
1812
|
await prCommand({ draft: options.draft, provider: options.provider });
|
|
1646
1813
|
});
|
|
1647
1814
|
program.command("status").description("Show current workflow status").action(async () => {
|