Skip to content

feat: interactive GitHub issues wizard (ralph-starter github)#270

Open
rubenmarcus wants to merge 5 commits intomainfrom
feat/github-integration-wizard
Open

feat: interactive GitHub issues wizard (ralph-starter github)#270
rubenmarcus wants to merge 5 commits intomainfrom
feat/github-integration-wizard

Conversation

@rubenmarcus
Copy link
Member

Summary

  • New ralph-starter github command — interactive wizard to browse repos, filter by label, multi-select issues, and start building
  • New src/integrations/wizards/shared.ts — shared utilities (credential prompting, browse-or-URL choice) reused by upcoming Linear and Notion wizards
  • ralph-starter run --from github (without --project/--issue) now redirects to the wizard instead of erroring
  • Follows the same pattern as ralph-starter figma

Features

  • Auth check: detects gh CLI auth or prompts for token (saves to ~/.ralph-starter/sources.json)
  • Browse mode: lists repos → optional label filter → multi-select issues
  • URL mode: paste a github.com URL (auto-detects repo + issue number)
  • Options: --commit, --push, --pr, --validate, --agent, --max-iterations

Test plan

  • ralph-starter github launches wizard
  • ralph-starter run --from github (no flags) redirects to wizard
  • ralph-starter run --from github --project owner/repo --issue 1 still works (no regression)
  • Missing credentials prompts for token
  • URL paste parses correctly
  • pnpm build compiles (pre-existing type errors in visual-validation.ts are unrelated)

🤖 Generated with Claude Code

rubenmarcus and others added 4 commits March 8, 2026 11:08
…or-url)

Shared utilities for integration wizards:
- ensureCredentials(): check for existing auth, prompt for API key if missing
- askBrowseOrUrl(): common "browse or paste URL" prompt
- askForUrl(): URL input with domain validation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New `githubCommand()` that guides users through:
1. Authentication check (gh CLI or token prompt)
2. Browse repos/issues or paste a URL
3. Optional label filtering
4. Multi-select issues (checkbox)
5. Delegates to runCommand() for each selected issue

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Register `ralph-starter github` as top-level command in cli.ts
  (same pattern as `ralph-starter figma`)
- Add wizard fallback in run.ts: `--from github` without --project/--issue
  redirects to the interactive github wizard instead of erroring

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Interactive Wizard" section to docs/docs/sources/github.md
- Add github/linear/notion wizard commands to README commands table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

Issue Linking Reminder

This PR doesn't appear to have a linked issue. Consider linking to:

  • This repo: Closes #123
  • ralph-ideas: Closes multivmlabs/ralph-ideas#123

Using Closes, Fixes, or Resolves will auto-close the issue when this PR is merged.


If this PR doesn't need an issue, you can ignore this message.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

✔️ Bundle Size Analysis

Metric Value
Base 2425.03 KB
PR 2451.20 KB
Diff 26.17 KB (1.00%)
Bundle breakdown
156K	dist/auth
32K	dist/automation
4.0K	dist/cli.d.ts
4.0K	dist/cli.d.ts.map
20K	dist/cli.js
12K	dist/cli.js.map
596K	dist/commands
28K	dist/config
4.0K	dist/index.d.ts
4.0K	dist/index.d.ts.map
4.0K	dist/index.js
4.0K	dist/index.js.map
916K	dist/integrations
84K	dist/llm
900K	dist/loop
188K	dist/mcp
32K	dist/presets
92K	dist/setup
40K	dist/skills
392K	dist/sources
76K	dist/ui
144K	dist/utils
336K	dist/wizard

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

🔗 Docs Preview

Preview URL: https://feat-github-integration-wiza.ralph-starter-docs.pages.dev

This preview was deployed from the latest commit on this PR.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR introduces a ralph-starter github interactive wizard command that guides users through authenticating with GitHub, browsing repositories and labels, multi-selecting issues, and delegating each issue to the existing runCommand loop. It also adds a shared src/integrations/wizards/shared.ts utility module designed to be reused by upcoming Linear and Notion wizards, and adds a fallback in run.ts so that ralph-starter run --from github (without --project/--issue) redirects to the wizard instead of erroring.

Key findings:

  • TypeScript convention violation: All new data-structure declarations (GitHubWizardOptions, GitHubRepo, GitHubIssue, GitHubLabel, CredentialOptions) use interface instead of the project's default type keyword for DTOs and simple data structures.
  • Browse mode / token-only auth gap: ensureCredentials can succeed via a plain token (env var or config file) without gh CLI, but browse mode unconditionally shells out to gh repo list / gh issue list. Users who authenticate via token but have no gh CLI installed will see a misleading failure. Only URL mode works reliably in that setup.
  • Circular dependency: run.ts imports githubCommand from github.ts, while github.ts already imports runCommand from run.ts. This cycle works at runtime because both exports are functions, but it is a code smell and could cause problems with bundlers or future refactoring.
  • Undocumented commands in README: The new README entries for ralph-starter linear and ralph-starter notion reference commands that are not yet implemented in this PR.

The core wizard flow is sound and the fallback in run.ts is well-placed. However, the style violations, circular import, browse-mode auth gap, and unimplemented command documentation should be addressed.

Confidence Score: 3/5

  • Mergeable with minor concerns — no crash-level bugs, but circular dependency, token-only browse failure, style violations, and unimplemented command documentation should be addressed.
  • The core wizard flow is sound and the fallback in run.ts is well-placed. However, there are four concrete issues: (1) TypeScript style violations using interface instead of type for all new DTOs/simple data structures, violating project conventions; (2) a circular import between run.ts and github.ts that works at runtime but is a code smell; (3) a UX gap where browse mode fails for users with a plain token but no gh CLI; and (4) documentation of commands (linear, notion) that don't exist yet, which will confuse users.
  • src/commands/github.ts (style violations and auth gap), src/integrations/wizards/shared.ts (style violation), src/commands/run.ts (circular dependency), README.md (unimplemented commands).

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as cli.ts
    participant GH as github.ts (githubCommand)
    participant Shared as shared.ts
    participant GhCLI as gh CLI
    participant Run as run.ts (runCommand)

    User->>CLI: ralph-starter github [options]
    CLI->>GH: githubCommand(options)

    GH->>Shared: ensureCredentials('github', ...)
    Shared->>GhCLI: gh auth status
    alt gh CLI authenticated
        GhCLI-->>Shared: ok → '__cli_auth__'
    else no gh CLI / not authed
        Shared->>Shared: check env var / sources.json
        alt no token found
            Shared->>User: prompt for token (masked)
            User-->>Shared: token
            Shared->>Shared: setSourceCredential → sources.json
        end
    end
    Shared-->>GH: credential

    GH->>Shared: askBrowseOrUrl('GitHub')
    Shared-->>GH: 'browse' | 'url'

    alt URL mode
        GH->>Shared: askForUrl('GitHub', /github\.com/)
        Shared-->>GH: url string
        GH->>GH: parseGitHubUrl(url)
        GH->>Run: runCommand(undefined, {from:'github', project, issue, ...})
    else Browse mode
        GH->>GhCLI: gh repo list --json
        GhCLI-->>GH: repos[]
        GH->>User: select a repository
        GH->>GhCLI: gh label list -R owner/repo
        GhCLI-->>GH: labels[]
        GH->>User: (optional) filter by label
        GH->>GhCLI: gh issue list -R owner/repo [--label x]
        GhCLI-->>GH: issues[]
        GH->>User: checkbox multi-select issues
        loop for each selected issue
            GH->>Run: runCommand(undefined, {from:'github', project, issue, ...})
        end
    end

    alt run.ts --from github (no --project/--issue)
        Run->>GH: githubCommand(options) [wizard fallback]
    end
Loading

Last reviewed commit: b3e759b

Comment on lines +16 to +38
export interface GitHubWizardOptions {
commit?: boolean;
push?: boolean;
pr?: boolean;
validate?: boolean;
maxIterations?: number;
agent?: string;
}

interface GitHubRepo {
name: string;
owner: { login: string };
description: string;
}

interface GitHubIssue {
number: number;
title: string;
labels: Array<{ name: string }>;
}

interface GitHubLabel {
name: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use type instead of interface for simple data structures.

Per the project's TypeScript conventions, type should be used by default for DTOs and simple data structures that don't use inheritance or extension. GitHubWizardOptions, GitHubRepo, GitHubIssue, and GitHubLabel are all plain data structures with no extension. The same applies to CredentialOptions in src/integrations/wizards/shared.ts:12.

Suggested change
export interface GitHubWizardOptions {
commit?: boolean;
push?: boolean;
pr?: boolean;
validate?: boolean;
maxIterations?: number;
agent?: string;
}
interface GitHubRepo {
name: string;
owner: { login: string };
description: string;
}
interface GitHubIssue {
number: number;
title: string;
labels: Array<{ name: string }>;
}
interface GitHubLabel {
name: string;
export type GitHubWizardOptions = {
commit?: boolean;
push?: boolean;
pr?: boolean;
validate?: boolean;
maxIterations?: number;
agent?: string;
}
type GitHubRepo = {
name: string;
owner: { login: string };
description: string;
}
type GitHubIssue = {
number: number;
title: string;
labels: Array<{ name: string }>;
}
type GitHubLabel = {
name: string;
}

Also update src/integrations/wizards/shared.ts:12:

export type CredentialOptions = {
  credKey: string;
  consoleUrl: string;
  envVar: string;
  checkCliAuth?: () => Promise<boolean>;
}

Rule Used: Use type by default in TypeScript unless you spe... (source)

Learnt From
cytonic-network/ai-frontend#48

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/github.ts
Line: 16-38

Comment:
Use `type` instead of `interface` for simple data structures.

Per the project's TypeScript conventions, `type` should be used by default for DTOs and simple data structures that don't use inheritance or extension. `GitHubWizardOptions`, `GitHubRepo`, `GitHubIssue`, and `GitHubLabel` are all plain data structures with no extension. The same applies to `CredentialOptions` in `src/integrations/wizards/shared.ts:12`.

```suggestion
export type GitHubWizardOptions = {
  commit?: boolean;
  push?: boolean;
  pr?: boolean;
  validate?: boolean;
  maxIterations?: number;
  agent?: string;
}

type GitHubRepo = {
  name: string;
  owner: { login: string };
  description: string;
}

type GitHubIssue = {
  number: number;
  title: string;
  labels: Array<{ name: string }>;
}

type GitHubLabel = {
  name: string;
}
```

Also update `src/integrations/wizards/shared.ts:12`:
```ts
export type CredentialOptions = {
  credKey: string;
  consoleUrl: string;
  envVar: string;
  checkCliAuth?: () => Promise<boolean>;
}
```

**Rule Used:** Use `type` by default in TypeScript unless you spe... ([source](https://app.greptile.com/review/custom-context?memory=c862f053-5655-4b41-be69-c840e3c9f280))

**Learnt From**
[cytonic-network/ai-frontend#48](https://github.com/cytonic-network/ai-frontend/pull/48)

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +179 to +189
// Browse mode
// Step 3: Fetch and select repository
console.log(chalk.dim(' Fetching your repositories...'));
let repos: GitHubRepo[];
try {
repos = await fetchReposViaCli();
} catch (err) {
console.log(chalk.red(' Failed to fetch repositories. Check your authentication.'));
console.log(chalk.dim(` Error: ${err instanceof Error ? err.message : String(err)}`));
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Browse mode unconditionally shells out to gh CLI, but ensureCredentials can succeed with a plain token.

ensureCredentials can succeed via a plain token (env var or ~/.ralph-starter/sources.json) when gh CLI is not installed or not authenticated. However, fetchReposViaCli() unconditionally shells out to gh repo list, so browse mode will always fail for token-only users with a confusing error message ("Check your authentication") even though their credentials are valid.

Consider either:

  1. Disabling the "Browse" option in askBrowseOrUrl when gh CLI is unavailable (only offering URL mode).
  2. Implementing a REST API fallback using the token for fetching repos/issues.

As a quick guard, you could check isGhCliAvailable() before offering browse mode:

const ghAvailable = await isGhCliAvailable();
const mode = ghAvailable ? await askBrowseOrUrl('GitHub') : 'url';
if (!ghAvailable) {
  console.log(chalk.dim('  (gh CLI not available — using URL mode)'));
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/github.ts
Line: 179-189

Comment:
Browse mode unconditionally shells out to `gh` CLI, but `ensureCredentials` can succeed with a plain token.

`ensureCredentials` can succeed via a plain token (env var or `~/.ralph-starter/sources.json`) when `gh` CLI is not installed or not authenticated. However, `fetchReposViaCli()` unconditionally shells out to `gh repo list`, so browse mode will always fail for token-only users with a confusing error message ("Check your authentication") even though their credentials are valid.

Consider either:
1. Disabling the "Browse" option in `askBrowseOrUrl` when `gh` CLI is unavailable (only offering URL mode).
2. Implementing a REST API fallback using the token for fetching repos/issues.

As a quick guard, you could check `isGhCliAvailable()` before offering browse mode:
```ts
const ghAvailable = await isGhCliAvailable();
const mode = ghAvailable ? await askBrowseOrUrl('GitHub') : 'url';
if (!ghAvailable) {
  console.log(chalk.dim('  (gh CLI not available — using URL mode)'));
}
```

How can I resolve this? If you propose a fix, please make it concise.

} from '../utils/sanitize.js';
import { ensureSharp } from '../utils/sharp.js';
import { showWelcome } from '../wizard/ui.js';
import { githubCommand } from './github.js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circular dependency between run.ts and github.ts.

run.ts imports githubCommand from github.ts (line 37), while github.ts imports runCommand from run.ts (line 14). This creates a circular module dependency:

run.ts → github.ts → run.ts

In Node.js ESM this typically resolves at runtime because the imports are function references that are only evaluated when called (not at import time). However, circular dependencies are a code smell, can confuse bundlers/tree-shakers, and make the dependency graph harder to reason about.

A cleaner approach would be to introduce a thin shared types/options file (e.g., src/commands/types.ts) that both files can import from, breaking the cycle. Alternatively, the wizard fallback logic in run.ts could be moved to a separate orchestration layer that imports both commands without creating a cycle.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/run.ts
Line: 37

Comment:
Circular dependency between `run.ts` and `github.ts`.

`run.ts` imports `githubCommand` from `github.ts` (line 37), while `github.ts` imports `runCommand` from `run.ts` (line 14). This creates a circular module dependency:

```
run.ts → github.ts → run.ts
```

In Node.js ESM this typically resolves at runtime because the imports are function references that are only evaluated when called (not at import time). However, circular dependencies are a code smell, can confuse bundlers/tree-shakers, and make the dependency graph harder to reason about.

A cleaner approach would be to introduce a thin shared types/options file (e.g., `src/commands/types.ts`) that both files can import from, breaking the cycle. Alternatively, the wizard fallback logic in `run.ts` could be moved to a separate orchestration layer that imports both commands without creating a cycle.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +459 to +461
| `ralph-starter github` | Interactive GitHub issues wizard |
| `ralph-starter linear` | Interactive Linear issues wizard |
| `ralph-starter notion` | Interactive Notion pages wizard |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documenting unimplemented commands in the README.

The ralph-starter linear and ralph-starter notion commands are listed in the commands table but are not implemented in this PR — neither the command handlers nor CLI registrations exist yet. Publishing documentation for commands that don't work yet will confuse users who try running them.

Consider either removing these rows until the commands are implemented, or annotating them as "coming soon":

Suggested change
| `ralph-starter github` | Interactive GitHub issues wizard |
| `ralph-starter linear` | Interactive Linear issues wizard |
| `ralph-starter notion` | Interactive Notion pages wizard |
| `ralph-starter linear` | Interactive Linear issues wizard _(coming soon)_ |
| `ralph-starter notion` | Interactive Notion pages wizard _(coming soon)_ |
Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 459-461

Comment:
Documenting unimplemented commands in the README.

The `ralph-starter linear` and `ralph-starter notion` commands are listed in the commands table but are not implemented in this PR — neither the command handlers nor CLI registrations exist yet. Publishing documentation for commands that don't work yet will confuse users who try running them.

Consider either removing these rows until the commands are implemented, or annotating them as "coming soon":
```suggestion
| `ralph-starter linear` | Interactive Linear issues wizard _(coming soon)_ |
| `ralph-starter notion` | Interactive Notion pages wizard _(coming soon)_ |
```

How can I resolve this? If you propose a fix, please make it concise.

- Anchor GitHub URL regex patterns with ^https?:// (CodeQL fix)
- Change interface to type for plain data structures (Greptile)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant