feat(git): include remote-only branches in getAllBranches#2137
feat(git): include remote-only branches in getAllBranches#2137charlescook-ph wants to merge 13 commits into
Conversation
Introduces a top-level mode toggle above the nav list. Work mode is an empty shell — placeholder for an upcoming feature set built during the hackathon. Generated-By: PostHog Code Task-Id: bd0f6387-4ee8-42a4-b17d-80927d214463
Generated-By: PostHog Code Task-Id: 770a6aff-7419-424e-a0b0-893d6a1f9b3b
Adds icon assets and BRAND_ICONS entries for Gmail, Granola, Asana, and the Google Workspace apps (Calendar, Drive, Docs, Sheets, Slides) so the marketplace renders them once the backend catalog includes matching templates. The asana.svg is the wordmark for now — a square brand mark wasn't available from public sources and should be swapped in later. Generated-By: PostHog Code Task-Id: 7540ef3b-b0e0-43a2-bb62-5e1836d85765
…Google Calendar/Drive Adds a small client-side registry of MCP templates the backend catalog doesn't yet expose, so the marketplace renders them with their brand icons. Connect routes through the existing custom-install endpoint using the official remote URLs. Drops the Google Docs/Sheets/Slides icons that were registered in the previous commit — there's no official remote MCP server for those (only self-hosted community alternatives), and Drive's MCP already covers their files. Generated-By: PostHog Code Task-Id: af4a4d09-f33e-4053-8f4d-5740d632fcc7
Generated-By: PostHog Code Task-Id: 770a6aff-7419-424e-a0b0-893d6a1f9b3b
Replaces the splash with a full home: hero, real PromptInput-style chat that hands off to TaskInput, clickable sample-project cards, and a Work-mode sidebar with placeholder sections (Projects, Automations, Artifacts, MCP, Memory) plus the standard New task entry. Adds new hedgehog assets and a staggered entrance animation. Generated-By: PostHog Code Task-Id: 14cf4155-07c2-4962-ae8e-4065d6322475
Generated-By: PostHog Code Task-Id: 14cf4155-07c2-4962-ae8e-4065d6322475
Adds the first iteration of Work-mode Skills: - New WorkSidebarMenu listing skills, seeded with an example skill - WorkGenerateView with a centered prompt that creates a task and streams the agent authoring the skill via PostHog MCP - WorkSkillDetailView reuses TaskLogsPanel for live streaming, with a static card for seeded examples - workSkillsStore (persisted) plus workView state in navigationStore - os.getHomeDir tRPC helper for fallback repoPath Includes the user's in-progress sound-recorder settings changes. Generated-By: PostHog Code Task-Id: bd0f6387-4ee8-42a4-b17d-80927d214463
# Conflicts: # apps/code/src/renderer/features/work/components/WorkSidebarMenu.tsx # apps/code/src/renderer/features/work/components/WorkView.tsx
Prompt To Fix All With AIFix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
apps/code/src/renderer/features/work/components/ScheduledTaskEditor.tsx:101-106
The comment here says polling changes "shouldn't clobber user edits," but including `existing` (the full object) in the dependency array defeats that intent. Since `useScheduledTasks` refetches every 30 seconds and returns a new object reference each time, the effect fires on every poll and overwrites whatever the user has typed into the form. Only `existing?.id` needs to be listed so the reset only triggers when the editor is pointed at a different automation.
```suggestion
// Sync the draft when the editor is pointed at a different existing automation.
// Only re-run when the id changes — polling produces new object references for
// the same automation, and we don't want those to overwrite in-progress edits.
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
if (existing) setDraft(toDraft(existing));
}, [existing?.id]);
```
### Issue 2 of 3
apps/code/src/renderer/api/posthogClient.ts:1073-1085
The `/run/` endpoint is a trigger action that doesn't need a request body. Sending `{} as unknown as Schemas.TaskAutomation` is a double type-cast that silently bypasses TypeScript — if the generated client requires no body for this route the cast can cause a type error elsewhere, and if it's optional the empty object is unnecessary noise. Omitting the `body` property entirely is cleaner and more honest about the API contract.
```suggestion
async runTaskAutomationNow(
automationId: string,
): Promise<Schemas.TaskAutomation> {
const teamId = await this.getTeamId();
const data = await this.api.post(
`/api/projects/{project_id}/task_automations/{id}/run/`,
{
path: { project_id: teamId.toString(), id: automationId },
},
);
return data;
}
```
### Issue 3 of 3
apps/code/src/renderer/features/work/utils/parseSchedule.test.ts:60-65
**Prefer parameterised tests for tabular assertions**
The team standard is to use parameterised tests rather than multiple bare assertions inside a single `it`. Cases like `parses individual days of the week` (and similar blocks for hourly variants, month variants, etc.) read more clearly and produce better failure output as `it.each` tables. The same pattern applies to the null-return cases, the daily-at-TIME cases, and the Nth-of-month cases throughout this file and `schedulePresets.test.ts`.
Reviews (1): Last reviewed commit: "feat(work): scheduled tasks under Work m..." | Re-trigger Greptile |
| // Sync the draft when the editor is pointed at a different existing automation. | ||
| useEffect(() => { | ||
| if (existing) setDraft(toDraft(existing)); | ||
| // The id is what should trigger a reset — other field changes from polling | ||
| // shouldn't clobber user edits. | ||
| }, [existing?.id, existing]); |
There was a problem hiding this comment.
The comment here says polling changes "shouldn't clobber user edits," but including
existing (the full object) in the dependency array defeats that intent. Since useScheduledTasks refetches every 30 seconds and returns a new object reference each time, the effect fires on every poll and overwrites whatever the user has typed into the form. Only existing?.id needs to be listed so the reset only triggers when the editor is pointed at a different automation.
| // Sync the draft when the editor is pointed at a different existing automation. | |
| useEffect(() => { | |
| if (existing) setDraft(toDraft(existing)); | |
| // The id is what should trigger a reset — other field changes from polling | |
| // shouldn't clobber user edits. | |
| }, [existing?.id, existing]); | |
| // Sync the draft when the editor is pointed at a different existing automation. | |
| // Only re-run when the id changes — polling produces new object references for | |
| // the same automation, and we don't want those to overwrite in-progress edits. | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| useEffect(() => { | |
| if (existing) setDraft(toDraft(existing)); | |
| }, [existing?.id]); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/work/components/ScheduledTaskEditor.tsx
Line: 101-106
Comment:
The comment here says polling changes "shouldn't clobber user edits," but including `existing` (the full object) in the dependency array defeats that intent. Since `useScheduledTasks` refetches every 30 seconds and returns a new object reference each time, the effect fires on every poll and overwrites whatever the user has typed into the form. Only `existing?.id` needs to be listed so the reset only triggers when the editor is pointed at a different automation.
```suggestion
// Sync the draft when the editor is pointed at a different existing automation.
// Only re-run when the id changes — polling produces new object references for
// the same automation, and we don't want those to overwrite in-progress edits.
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
if (existing) setDraft(toDraft(existing));
}, [existing?.id]);
```
How can I resolve this? If you propose a fix, please make it concise.| async runTaskAutomationNow( | ||
| automationId: string, | ||
| ): Promise<Schemas.TaskAutomation> { | ||
| const teamId = await this.getTeamId(); | ||
| const data = await this.api.post( | ||
| `/api/projects/{project_id}/task_automations/{id}/run/`, | ||
| { | ||
| path: { project_id: teamId.toString(), id: automationId }, | ||
| body: {} as unknown as Schemas.TaskAutomation, | ||
| }, | ||
| ); | ||
| return data; | ||
| } |
There was a problem hiding this comment.
The
/run/ endpoint is a trigger action that doesn't need a request body. Sending {} as unknown as Schemas.TaskAutomation is a double type-cast that silently bypasses TypeScript — if the generated client requires no body for this route the cast can cause a type error elsewhere, and if it's optional the empty object is unnecessary noise. Omitting the body property entirely is cleaner and more honest about the API contract.
| async runTaskAutomationNow( | |
| automationId: string, | |
| ): Promise<Schemas.TaskAutomation> { | |
| const teamId = await this.getTeamId(); | |
| const data = await this.api.post( | |
| `/api/projects/{project_id}/task_automations/{id}/run/`, | |
| { | |
| path: { project_id: teamId.toString(), id: automationId }, | |
| body: {} as unknown as Schemas.TaskAutomation, | |
| }, | |
| ); | |
| return data; | |
| } | |
| async runTaskAutomationNow( | |
| automationId: string, | |
| ): Promise<Schemas.TaskAutomation> { | |
| const teamId = await this.getTeamId(); | |
| const data = await this.api.post( | |
| `/api/projects/{project_id}/task_automations/{id}/run/`, | |
| { | |
| path: { project_id: teamId.toString(), id: automationId }, | |
| }, | |
| ); | |
| return data; | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/api/posthogClient.ts
Line: 1073-1085
Comment:
The `/run/` endpoint is a trigger action that doesn't need a request body. Sending `{} as unknown as Schemas.TaskAutomation` is a double type-cast that silently bypasses TypeScript — if the generated client requires no body for this route the cast can cause a type error elsewhere, and if it's optional the empty object is unnecessary noise. Omitting the `body` property entirely is cleaner and more honest about the API contract.
```suggestion
async runTaskAutomationNow(
automationId: string,
): Promise<Schemas.TaskAutomation> {
const teamId = await this.getTeamId();
const data = await this.api.post(
`/api/projects/{project_id}/task_automations/{id}/run/`,
{
path: { project_id: teamId.toString(), id: automationId },
},
);
return data;
}
```
How can I resolve this? If you propose a fix, please make it concise.| it("parses individual days of the week", () => { | ||
| expect(parseSchedule("Mondays at 9am")?.cron).toBe("0 9 * * 1"); | ||
| expect(parseSchedule("every Tuesday at 5pm")?.cron).toBe("0 17 * * 2"); | ||
| expect(parseSchedule("Friday at 4pm")?.cron).toBe("0 16 * * 5"); | ||
| expect(parseSchedule("Sundays at noon")?.cron).toBe("0 12 * * 0"); | ||
| }); |
There was a problem hiding this comment.
Prefer parameterised tests for tabular assertions
The team standard is to use parameterised tests rather than multiple bare assertions inside a single it. Cases like parses individual days of the week (and similar blocks for hourly variants, month variants, etc.) read more clearly and produce better failure output as it.each tables. The same pattern applies to the null-return cases, the daily-at-TIME cases, and the Nth-of-month cases throughout this file and schedulePresets.test.ts.
Context Used: Do not attempt to comment on incorrect alphabetica... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/work/utils/parseSchedule.test.ts
Line: 60-65
Comment:
**Prefer parameterised tests for tabular assertions**
The team standard is to use parameterised tests rather than multiple bare assertions inside a single `it`. Cases like `parses individual days of the week` (and similar blocks for hourly variants, month variants, etc.) read more clearly and produce better failure output as `it.each` tables. The same pattern applies to the null-return cases, the daily-at-TIME cases, and the Nth-of-month cases throughout this file and `schedulePresets.test.ts`.
**Context Used:** Do not attempt to comment on incorrect alphabetica... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))
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!
Summary
getAllBranchesnow returns remote-only branches alongside locals (deduplicated by name), so callers that list branches from a freshly-cloned or stale-local checkout see everything that exists on the remote.remotes/<remote>/HEADpointer refs thatgit branch -aemits, so they don't appear in the list as a noisy duplicate of the default branch.Test plan
packages/git/src/queries.test.tscovers a repo with a local-only branch, a remote-only branch, and verifies HEAD pointer refs are dropped.pnpm --filter @posthog/git testpasses locally.Created with PostHog Code