diff --git a/.trajectories/active/traj_cvtqhlwcq9s0.json b/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json similarity index 80% rename from .trajectories/active/traj_cvtqhlwcq9s0.json rename to .trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json index 7b01874ef..99b422b1e 100644 --- a/.trajectories/active/traj_cvtqhlwcq9s0.json +++ b/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json @@ -8,7 +8,7 @@ "id": "dashboard-nav-fix" } }, - "status": "active", + "status": "completed", "startedAt": "2026-01-03T16:37:49.153Z", "agents": [ { @@ -36,11 +36,18 @@ }, "significance": "high" } - ] + ], + "endedAt": "2026-01-03T18:43:48.687Z" } ], "commits": [], "filesChanged": [], "projectId": "/Users/khaliqgant/Projects/agent-workforce/relay", - "tags": [] + "tags": [], + "completedAt": "2026-01-03T18:43:48.687Z", + "retrospective": { + "summary": "Added back button to trajectory viewer header, accessible when viewing a specific trajectory", + "approach": "Standard approach", + "confidence": 0.9 + } } \ No newline at end of file diff --git a/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md b/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md new file mode 100644 index 000000000..f6f1e3d31 --- /dev/null +++ b/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md @@ -0,0 +1,32 @@ +# Trajectory: Fix trajectory viewer navigation - add back to list + +> **Status:** ✅ Completed +> **Task:** dashboard-nav-fix +> **Confidence:** 90% +> **Started:** January 3, 2026 at 04:37 PM +> **Completed:** January 3, 2026 at 06:43 PM + +--- + +## Summary + +Added back button to trajectory viewer header, accessible when viewing a specific trajectory + +**Approach:** Standard approach + +--- + +## Key Decisions + +### Added back button to header instead of only in empty state +- **Chose:** Added back button to header instead of only in empty state +- **Reasoning:** Back button was only visible when no steps were displayed. Moving it to header ensures it's always accessible when viewing a specific trajectory. + +--- + +## Chapters + +### 1. Work +*Agent: default* + +- Added back button to header instead of only in empty state: Added back button to header instead of only in empty state diff --git a/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json b/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json new file mode 100644 index 000000000..602cfed9b --- /dev/null +++ b/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json @@ -0,0 +1,59 @@ +{ + "id": "traj_st8j35b0hrlc", + "version": 1, + "task": { + "title": "Fix cloud provisioning for GitHub cloning and agent credentials", + "source": { + "system": "plain", + "id": "cloud-e2e-fix" + } + }, + "status": "completed", + "startedAt": "2026-01-03T19:04:57.338Z", + "agents": [], + "chapters": [ + { + "id": "chap_4tafbyx9rbsy", + "title": "Work", + "agentName": "default", + "startedAt": "2026-01-03T19:07:03.673Z", + "events": [ + { + "ts": 1767467223674, + "type": "decision", + "content": "Get GitHub token from Nango instead of vault: Get GitHub token from Nango instead of vault", + "raw": { + "question": "Get GitHub token from Nango instead of vault", + "chosen": "Get GitHub token from Nango instead of vault", + "alternatives": [], + "reasoning": "GitHub App tokens come from Nango and expire hourly. Changed provisioner to call getGithubAppTokenForUser() which finds user's Nango connection and fetches fresh token." + }, + "significance": "high" + }, + { + "ts": 1767467301488, + "type": "decision", + "content": "Create CLI credential files from ENV vars in workspace entrypoint: Create CLI credential files from ENV vars in workspace entrypoint", + "raw": { + "question": "Create CLI credential files from ENV vars in workspace entrypoint", + "chosen": "Create CLI credential files from ENV vars in workspace entrypoint", + "alternatives": [], + "reasoning": "Claude CLI expects ~/.claude/credentials.json, Codex expects ~/.codex/credentials.json. Workspace entrypoint now creates these from ANTHROPIC_TOKEN, OPENAI_TOKEN, GOOGLE_TOKEN ENV vars passed by provisioner." + }, + "significance": "high" + } + ], + "endedAt": "2026-01-03T19:09:05.597Z" + } + ], + "commits": [], + "filesChanged": [], + "projectId": "/home/user/relay", + "tags": [], + "completedAt": "2026-01-03T19:09:05.597Z", + "retrospective": { + "summary": "Fixed GitHub token to use Nango (fresh installation tokens) and added credential file creation in workspace entrypoint for Claude/Codex/Gemini", + "approach": "Standard approach", + "confidence": 0.85 + } +} \ No newline at end of file diff --git a/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md b/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md new file mode 100644 index 000000000..299f4759a --- /dev/null +++ b/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md @@ -0,0 +1,37 @@ +# Trajectory: Fix cloud provisioning for GitHub cloning and agent credentials + +> **Status:** ✅ Completed +> **Task:** cloud-e2e-fix +> **Confidence:** 85% +> **Started:** January 3, 2026 at 07:04 PM +> **Completed:** January 3, 2026 at 07:09 PM + +--- + +## Summary + +Fixed GitHub token to use Nango (fresh installation tokens) and added credential file creation in workspace entrypoint for Claude/Codex/Gemini + +**Approach:** Standard approach + +--- + +## Key Decisions + +### Get GitHub token from Nango instead of vault +- **Chose:** Get GitHub token from Nango instead of vault +- **Reasoning:** GitHub App tokens come from Nango and expire hourly. Changed provisioner to call getGithubAppTokenForUser() which finds user's Nango connection and fetches fresh token. + +### Create CLI credential files from ENV vars in workspace entrypoint +- **Chose:** Create CLI credential files from ENV vars in workspace entrypoint +- **Reasoning:** Claude CLI expects ~/.claude/credentials.json, Codex expects ~/.codex/credentials.json. Workspace entrypoint now creates these from ANTHROPIC_TOKEN, OPENAI_TOKEN, GOOGLE_TOKEN ENV vars passed by provisioner. + +--- + +## Chapters + +### 1. Work +*Agent: default* + +- Get GitHub token from Nango instead of vault: Get GitHub token from Nango instead of vault +- Create CLI credential files from ENV vars in workspace entrypoint: Create CLI credential files from ENV vars in workspace entrypoint diff --git a/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json b/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json new file mode 100644 index 000000000..b6bb02430 --- /dev/null +++ b/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json @@ -0,0 +1,59 @@ +{ + "id": "traj_yvdadtvdgnz3", + "version": 1, + "task": { + "title": "Full cloud e2e flow review", + "source": { + "system": "plain", + "id": "cloud-review" + } + }, + "status": "completed", + "startedAt": "2026-01-03T19:17:32.797Z", + "agents": [], + "chapters": [ + { + "id": "chap_vjlhnvwxq9eo", + "title": "Work", + "agentName": "default", + "startedAt": "2026-01-03T19:21:54.982Z", + "events": [ + { + "ts": 1767468114983, + "type": "decision", + "content": "Multi-repo spawning uses workspace root, not specific repo: Multi-repo spawning uses workspace root, not specific repo", + "raw": { + "question": "Multi-repo spawning uses workspace root, not specific repo", + "chosen": "Multi-repo spawning uses workspace root, not specific repo", + "alternatives": [], + "reasoning": "When agents spawn, cwd is /workspace (where all repos live), not /workspace/repo-name. This is acceptable for MVP - tasks can specify which repo to work on, and agents can cd into the right directory." + }, + "significance": "high" + }, + { + "ts": 1767468129191, + "type": "decision", + "content": "Repo sync limited to 100 repos: Repo sync limited to 100 repos", + "raw": { + "question": "Repo sync limited to 100 repos", + "chosen": "Repo sync limited to 100 repos", + "alternatives": [], + "reasoning": "listGithubAppRepos only fetches first 100 repos from GitHub API. This is a known limitation - users with >100 repos won't see all of them. Acceptable for MVP, can add pagination later." + }, + "significance": "high" + } + ], + "endedAt": "2026-01-03T19:22:22.762Z" + } + ], + "commits": [], + "filesChanged": [], + "projectId": "/home/user/relay", + "tags": [], + "completedAt": "2026-01-03T19:22:22.762Z", + "retrospective": { + "summary": "Full cloud e2e flow review complete. Flow is viable for MVP with minor limitations: 100 repo max, multi-repo spawns to workspace root. Key pieces verified: Nango OAuth, GitHub App tokens, vault credentials, workspace provisioning, entrypoint cloning, credential file creation, spawn mechanism.", + "approach": "Standard approach", + "confidence": 0.85 + } +} \ No newline at end of file diff --git a/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md b/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md new file mode 100644 index 000000000..1ecd1cb89 --- /dev/null +++ b/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md @@ -0,0 +1,37 @@ +# Trajectory: Full cloud e2e flow review + +> **Status:** ✅ Completed +> **Task:** cloud-review +> **Confidence:** 85% +> **Started:** January 3, 2026 at 07:17 PM +> **Completed:** January 3, 2026 at 07:22 PM + +--- + +## Summary + +Full cloud e2e flow review complete. Flow is viable for MVP with minor limitations: 100 repo max, multi-repo spawns to workspace root. Key pieces verified: Nango OAuth, GitHub App tokens, vault credentials, workspace provisioning, entrypoint cloning, credential file creation, spawn mechanism. + +**Approach:** Standard approach + +--- + +## Key Decisions + +### Multi-repo spawning uses workspace root, not specific repo +- **Chose:** Multi-repo spawning uses workspace root, not specific repo +- **Reasoning:** When agents spawn, cwd is /workspace (where all repos live), not /workspace/repo-name. This is acceptable for MVP - tasks can specify which repo to work on, and agents can cd into the right directory. + +### Repo sync limited to 100 repos +- **Chose:** Repo sync limited to 100 repos +- **Reasoning:** listGithubAppRepos only fetches first 100 repos from GitHub API. This is a known limitation - users with >100 repos won't see all of them. Acceptable for MVP, can add pagination later. + +--- + +## Chapters + +### 1. Work +*Agent: default* + +- Multi-repo spawning uses workspace root, not specific repo: Multi-repo spawning uses workspace root, not specific repo +- Repo sync limited to 100 repos: Repo sync limited to 100 repos diff --git a/.trajectories/index.json b/.trajectories/index.json index b09974fdd..d7be6e71c 100644 --- a/.trajectories/index.json +++ b/.trajectories/index.json @@ -1,6 +1,6 @@ { "version": 1, - "lastUpdated": "2026-01-03T16:38:36.822Z", + "lastUpdated": "2026-01-03T19:22:22.783Z", "trajectories": { "traj_ozd98si6a7ns": { "title": "Fix thinking indicator showing on all messages", @@ -235,9 +235,24 @@ }, "traj_cvtqhlwcq9s0": { "title": "Fix trajectory viewer navigation - add back to list", - "status": "active", + "status": "completed", "startedAt": "2026-01-03T16:37:49.153Z", - "path": "/Users/khaliqgant/Projects/agent-workforce/relay/.trajectories/active/traj_cvtqhlwcq9s0.json" + "completedAt": "2026-01-03T18:43:48.687Z", + "path": "/home/user/relay/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json" + }, + "traj_st8j35b0hrlc": { + "title": "Fix cloud provisioning for GitHub cloning and agent credentials", + "status": "completed", + "startedAt": "2026-01-03T19:04:57.338Z", + "completedAt": "2026-01-03T19:09:05.597Z", + "path": "/home/user/relay/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json" + }, + "traj_yvdadtvdgnz3": { + "title": "Full cloud e2e flow review", + "status": "completed", + "startedAt": "2026-01-03T19:17:32.797Z", + "completedAt": "2026-01-03T19:22:22.762Z", + "path": "/home/user/relay/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json" } } } \ No newline at end of file diff --git a/deploy/workspace/entrypoint.sh b/deploy/workspace/entrypoint.sh index 5ab343ad0..b60f02a4b 100644 --- a/deploy/workspace/entrypoint.sh +++ b/deploy/workspace/entrypoint.sh @@ -69,6 +69,50 @@ if [[ -n "${REPO_LIST}" ]]; then done fi +# ============================================================================ +# Configure AI provider credentials +# Create credential files that CLIs expect from ENV vars passed by provisioner +# ============================================================================ + +# Claude CLI expects ~/.claude/credentials.json +if [[ -n "${ANTHROPIC_TOKEN:-}" ]]; then + log "Configuring Claude credentials..." + mkdir -p "${HOME}/.claude" + cat > "${HOME}/.claude/credentials.json" < "${HOME}/.codex/credentials.json" < "${HOME}/.config/gcloud/application_default_credentials.json" < { + try { + // Find any repository with a Nango connection for this user + const repos = await db.repositories.findByUserId(userId); + const repoWithConnection = repos.find(r => r.nangoConnectionId); + + if (!repoWithConnection?.nangoConnectionId) { + console.warn(`[provisioner] No Nango GitHub App connection found for user ${userId}`); + return null; + } + + // Get fresh installation token from Nango (handles refresh automatically) + const token = await nangoService.getGithubAppToken(repoWithConnection.nangoConnectionId); + return token; + } catch (error) { + console.error(`[provisioner] Failed to get GitHub App token for user ${userId}:`, error); + return null; + } +} + async function loadCredentialToken(userId: string, provider: string): Promise { try { const cred = await vault.getCredential(userId, provider); @@ -838,12 +863,13 @@ export class WorkspaceProvisioner { } // GitHub token is required for cloning repositories + // Use Nango GitHub App token (fresh installation token, not from vault) if (config.repositories.length > 0) { - const githubToken = await loadCredentialToken(config.userId, 'github'); + const githubToken = await getGithubAppTokenForUser(config.userId); if (githubToken) { credentials.set('github', githubToken); } else { - console.warn(`No GitHub token found for user ${config.userId}; repository cloning may fail.`); + console.warn(`[provisioner] No GitHub App token for user ${config.userId}; repository cloning may fail.`); } }