Skip to content

GitHub shared workspace and codex#66

Merged
khaliqgant merged 7 commits intomainfrom
github-shared-workspace-and-codex
Jan 5, 2026
Merged

GitHub shared workspace and codex#66
khaliqgant merged 7 commits intomainfrom
github-shared-workspace-and-codex

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

No description provided.

khaliqgant and others added 4 commits January 5, 2026 22:15
During early provisioning, computeId isn't set yet. The provider's
getStatus would return 'error' immediately. Now we check the DB
status first and return 'provisioning' if that's the current state.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The /wait endpoint blocks until the machine reaches the target state,
much more efficient than polling every 3 seconds. Also increased
timeout to 120s since machines can take longer to start.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolved trajectory file conflicts by merging both branches' entries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@khaliqgant khaliqgant requested a review from Copilot January 5, 2026 21:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements GitHub repository access management with Nango-based permission checking and enhances the Codex authentication flow with a CLI helper utility. The changes enable users to view and manage GitHub repositories they have access to through OAuth, and provide a streamlined CLI-based method for capturing OAuth callbacks during Codex authentication.

Key changes:

  • Added GitHub repository permission APIs using Nango OAuth proxy for access control
  • Implemented RepoAccessPanel component for managing repository access in workspace settings
  • Enhanced Codex authentication with CLI helper that captures OAuth callbacks locally
  • Refactored machine startup process to use Fly.io's /wait endpoint for more efficient state polling

Reviewed changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/dashboard/react-components/settings/WorkspaceSettingsPanel.tsx Added "GitHub Access" section with navigation and RepoAccessPanel integration
src/dashboard/react-components/RepoAccessPanel.tsx New component for displaying and managing GitHub repository access with permission levels
src/dashboard/react-components/ProviderAuthFlow.tsx Enhanced Codex auth flow with CLI helper option and automatic callback polling
src/cloud/services/nango.ts Added methods for checking user repository access and listing accessible repos via Nango
src/cloud/server.ts Registered codex-auth-helper router and exempted callback endpoint from CSRF
src/cloud/provisioner/index.ts Refactored machine startup to use Fly.io's blocking /wait endpoint
src/cloud/api/repos.ts Added three new endpoints for repository access checking via Nango OAuth
src/cloud/api/codex-auth-helper.ts New API for CLI-based OAuth callback capture with session management
src/cli/index.ts Added codex-auth command for local OAuth callback capture
package.json Version bump to 1.2.2 and agent-trajectories dependency update
.github/workflows/publish.yml Comprehensive workflow redesign with manual version control and dry-run support

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

} catch (err) {
console.error('Failed to fetch CLI session:', err);
}
}, [isCodexFlow, csrfToken, startCliPolling]);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The startCliPolling dependency in the useCallback creates a circular dependency since startCliPolling itself is defined as a useCallback. This can lead to unnecessary re-renders or stale closures. Consider removing startCliPolling from the dependencies array since it's a stable callback reference.

Suggested change
}, [isCodexFlow, csrfToken, startCliPolling]);
}, [isCodexFlow, csrfToken]);

Copilot uses AI. Check for mistakes.
Comment thread src/cloud/api/codex-auth-helper.ts Outdated
Comment on lines +27 to +35
setInterval(() => {
const now = Date.now();
for (const [id, session] of pendingAuthSessions) {
// Remove sessions older than 10 minutes
if (now - session.createdAt.getTime() > 10 * 60 * 1000) {
pendingAuthSessions.delete(id);
}
}
}, 60000);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The cleanup interval is created at module load time and will never be cleared, even if the server shuts down. This can cause memory leaks or unexpected behavior. Store the interval ID and provide a cleanup mechanism, or integrate this into the server lifecycle.

Copilot uses AI. Check for mistakes.
Comment on lines +1027 to +1032
workspaces={workspace ? [{
id: workspace.id,
name: workspace.name,
repositoryFullName: workspace.repositories[0]?.fullName,
status: workspace.status as 'provisioning' | 'running' | 'stopped' | 'error',
}] : []}
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Accessing workspace.repositories[0] without checking if the array exists or has elements could cause runtime errors. While the optional chaining handles undefined, if repositories is an empty array, this will pass undefined to RepoAccessPanel, which may not handle it correctly.

Suggested change
workspaces={workspace ? [{
id: workspace.id,
name: workspace.name,
repositoryFullName: workspace.repositories[0]?.fullName,
status: workspace.status as 'provisioning' | 'running' | 'stopped' | 'error',
}] : []}
workspaces={
workspace && Array.isArray(workspace.repositories) && workspace.repositories.length > 0
? [{
id: workspace.id,
name: workspace.name,
repositoryFullName: workspace.repositories[0].fullName,
status: workspace.status as 'provisioning' | 'running' | 'stopped' | 'error',
}]
: []
}

Copilot uses AI. Check for mistakes.
} finally {
setCreatingWorkspace(null);
}
}, [csrfToken, onWorkspaceCreated]);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The handleCreateWorkspace callback includes onWorkspaceCreated in its dependencies but doesn't use useCallback to memoize onWorkspaceCreated itself. This means the callback will be recreated whenever the parent component re-renders, potentially causing unnecessary re-renders of child components that depend on this callback.

Copilot uses AI. Check for mistakes.
{ headers: { Authorization: `Bearer ${apiToken}` } }
);
const machine = stateRes.ok ? (await stateRes.json()) as { state: string } : { state: 'unknown' };
throw new Error(`Machine ${machineId} did not start within ${timeoutSeconds}s (last state: ${machine.state})`);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The error message refers to timeoutSeconds but this variable is a parameter name that won't be meaningful to users. Consider using a more user-friendly message that explains what happened and what action to take, such as 'Machine failed to start within the configured timeout period. Please try again or contact support if the issue persists.'

Suggested change
throw new Error(`Machine ${machineId} did not start within ${timeoutSeconds}s (last state: ${machine.state})`);
throw new Error(`Machine ${machineId} failed to start within the configured timeout period (${timeoutSeconds}s). Please try again or contact support if the issue persists. Last known state: ${machine.state}`);

Copilot uses AI. Check for mistakes.
Comment thread src/cli/index.ts
Comment on lines +2779 to +2785
while (!authCode && !serverClosed && (Date.now() - startTime) < TIMEOUT_MS) {
await new Promise(resolve => setTimeout(resolve, 1000));
const elapsed = Math.floor((Date.now() - startTime) / 1000);
if (elapsed > 0 && elapsed % 30 === 0) {
console.log(` Still waiting... (${elapsed}s)`);
}
}
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

This polling loop checks the condition every second for potentially 5 minutes (300 seconds by default), which is inefficient. Consider increasing the poll interval or implementing an event-based approach where the server notifies the client when the auth code is received.

Copilot uses AI. Check for mistakes.
Comment on lines +231 to +241

git add package.json package-lock.json

if git diff --staged --quiet; then
echo "No version changes to commit"
else
git commit -m "chore(release): v${NEW_VERSION}" \
-m "NPM Tag: ${TAG}"

git push origin HEAD:main
echo "Version changes committed and pushed"
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

Pushing directly to the main branch bypasses any branch protection rules that may be in place. Consider creating a pull request or using a bot account with appropriate permissions, or ensure that the GitHub token used has the necessary bypass permissions configured.

Suggested change
git add package.json package-lock.json
if git diff --staged --quiet; then
echo "No version changes to commit"
else
git commit -m "chore(release): v${NEW_VERSION}" \
-m "NPM Tag: ${TAG}"
git push origin HEAD:main
echo "Version changes committed and pushed"
TARGET_BRANCH="${GITHUB_REF_NAME}"
RELEASE_BRANCH_CREATED="false"
git add package.json package-lock.json
if git diff --staged --quiet; then
echo "No version changes to commit"
else
# If running on main, create a dedicated release branch instead of pushing directly to main
if [ "$TARGET_BRANCH" = "main" ] || [ "$TARGET_BRANCH" = "refs/heads/main" ]; then
TARGET_BRANCH="release/v${NEW_VERSION}"
git checkout -b "$TARGET_BRANCH"
RELEASE_BRANCH_CREATED="true"
fi
git commit -m "chore(release): v${NEW_VERSION}" \
-m "NPM Tag: ${TAG}"
git push origin "HEAD:${TARGET_BRANCH}"
echo "Version changes committed and pushed to ${TARGET_BRANCH}"
if [ "$RELEASE_BRANCH_CREATED" = "true" ]; then
echo "A release branch '${TARGET_BRANCH}' was created. Please open a pull request to merge it into 'main'."
fi

Copilot uses AI. Check for mistakes.
khaliqgant and others added 3 commits January 5, 2026 23:01
Moved startCliPolling and handleCodeReceivedRef declarations before
fetchCliSession to fix "used before declaration" TypeScript error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@khaliqgant khaliqgant merged commit e892be9 into main Jan 5, 2026
6 checks passed
@khaliqgant khaliqgant deleted the github-shared-workspace-and-codex branch January 5, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants