Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
f3c3df8
init
skoob13 Dec 9, 2025
11f844c
fix: electron deps
skoob13 Dec 9, 2025
b4de0da
modules
skoob13 Dec 9, 2025
c68999e
deps again
skoob13 Dec 9, 2025
578efd2
auth
skoob13 Dec 9, 2025
0733cfd
Bativewind init
a-lider Dec 9, 2025
8465b1a
fix: nativewind
skoob13 Dec 9, 2025
6449458
Bump reanimated version
a-lider Dec 9, 2025
1fcaadb
wip fonts
skoob13 Dec 9, 2025
80bc59f
Merge branch 'auth' into mobile-app
skoob13 Dec 9, 2025
0be1980
feat: fonts
skoob13 Dec 9, 2025
b58912d
biome
skoob13 Dec 9, 2025
1ed0016
Restructure project
a-lider Dec 9, 2025
173dd77
Fix classname sorting and OAuth callback
a-lider Dec 9, 2025
d7de818
fix OAuth token exchange
a-lider Dec 9, 2025
6db5a5a
streaming wip
skoob13 Dec 9, 2025
8dda38d
Merge branch 'streaming' into mobile-app
skoob13 Dec 9, 2025
ecae512
Update app schema to posthog
a-lider Dec 9, 2025
54f4b2a
streaming
skoob13 Dec 9, 2025
3bc5d58
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
skoob13 Dec 9, 2025
2eef20d
feat: agent chat
jonathanlab Dec 9, 2025
c4156e3
undo mode switch changes
jonathanlab Dec 9, 2025
a4d313c
undo package bumps for array
jonathanlab Dec 9, 2025
25ae735
Add tabs navigation - first draft
a-lider Dec 9, 2025
b25cdf6
Use streaming
a-lider Dec 9, 2025
28f9b8b
Tabs navigation
a-lider Dec 9, 2025
0b9a4c6
Tabs with action button
a-lider Dec 9, 2025
a2f4e56
Create task button on the main screen instead of tabs
a-lider Dec 9, 2025
2e1315c
bump back
jonathanlab Dec 9, 2025
ab6f439
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
jonathanlab Dec 9, 2025
169d400
Chat UI - first draft with components and keyboard-controller
a-lider Dec 9, 2025
992c15a
query
skoob13 Dec 9, 2025
390c309
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
skoob13 Dec 9, 2025
3e78e75
Make both PostHog AI chat and Array tasks
a-lider Dec 9, 2025
e428698
feat: tasks list
skoob13 Dec 10, 2025
0183b9f
feat: list of tasks and convos
skoob13 Dec 10, 2025
d9b3787
feat: render tool calls
skoob13 Dec 10, 2025
fcd82ed
try to fix infinite rerender in virutalizedlist
jonathanlab Dec 10, 2025
2f243d5
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
jonathanlab Dec 10, 2025
43f5aa8
prevent picking up electron react
jonathanlab Dec 10, 2025
007c7f8
Update the styles to match Array app
a-lider Dec 10, 2025
5bcf116
Update loading and streaming styles
a-lider Dec 10, 2025
aea34e5
tasks component
skoob13 Dec 10, 2025
5b491d5
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
skoob13 Dec 10, 2025
5454e3b
new task
skoob13 Dec 10, 2025
f12ae66
cleanup
skoob13 Dec 10, 2025
388a9f8
Liquid glass chat input
a-lider Dec 10, 2025
b0684b3
Liquid glass mic and send button
a-lider Dec 10, 2025
f215bf4
better sync/persistence for sessions
jonathanlab Dec 10, 2025
d39747d
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
jonathanlab Dec 10, 2025
88e2355
voice mode
skoob13 Dec 10, 2025
825a6e6
Merge branch 'mobile-app' of github.com:PostHog/Array into mobile-app
skoob13 Dec 10, 2025
d7a4b51
Refactor to feature folders
a-lider Dec 19, 2025
2b1a54d
Use audio transcription API
a-lider Dec 26, 2025
4805f45
Only show dev region in development builds
a-lider Dec 27, 2025
13069aa
Update EU client ID
a-lider Dec 27, 2025
8cf75fd
Remove sensitive auth logs
a-lider Dec 27, 2025
464e4b0
Clean up console logs
a-lider Dec 29, 2025
ab5c068
Fix relative imports, use alias
a-lider Dec 29, 2025
967b67f
Minor refactoring
a-lider Dec 29, 2025
8244798
Refactor tailwind styles
a-lider Jan 1, 2026
0563e1e
Make adaptive light/dark theme
a-lider Jan 1, 2026
3f8c262
ChatInput with liquid glass
a-lider Jan 12, 2026
1efc11a
Rename ChatInput to Composer
a-lider Jan 12, 2026
3e28da5
Update eas and app config
a-lider Jan 13, 2026
1d4aab5
Merge remote-tracking branch 'origin/main' into mobile-app
a-lider Jan 14, 2026
df31308
Update mobile app dependencies
a-lider Jan 14, 2026
ee649c0
Merge branch 'main' into mobile-app
a-lider Jan 14, 2026
db126d9
App icon and splash screen
a-lider Jan 14, 2026
097002f
Connect GitHub flow
a-lider Jan 14, 2026
752368a
Update settings tab
a-lider Jan 14, 2026
772056a
Use React Query
a-lider Jan 14, 2026
b20f1c6
Thinking animation when streaming
a-lider Jan 14, 2026
0e35580
Fix streaming rendering
a-lider Jan 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash

pnpm lint-staged
# pnpm lint-staged
3 changes: 2 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node-linker=hoisted
node-linker=hoisted
shamefully-hoist=true
10 changes: 5 additions & 5 deletions apps/array/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/node": "^20.19.21",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@types/uuid": "^9.0.7",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/ui": "^4.0.10",
Expand All @@ -57,7 +57,7 @@
"jsdom": "^26.0.0",
"lint-staged": "^15.5.2",
"postcss": "^8.4.33",
"tailwindcss": "^3.4.1",
"tailwindcss": "^3.4.18",
"tsx": "^4.20.6",
"typed-openapi": "^2.2.2",
"typescript": "^5.9.3",
Expand Down Expand Up @@ -136,8 +136,8 @@
"posthog-js": "^1.283.0",
"posthog-node": "^4.18.0",
"radix-themes-tw": "0.2.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hook-form": "^7.64.0",
"react-hotkeys-hook": "^4.4.4",
"react-markdown": "^10.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ export function VirtualizedList<T>({

const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => estimateSize,
getScrollElement,
estimateSize: getEstimateSize,
overscan,
gap,
getItemKey: getItemKey
? (index) => getItemKey(items[index], index)
: undefined,
getItemKey: stableGetItemKey,
});

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useDeleteTask, useTasks } from "@features/tasks/hooks/useTasks";
import { useTaskStore } from "@features/tasks/stores/taskStore";
import { useMeQuery } from "@hooks/useMeQuery";
import { useTaskContextMenu } from "@hooks/useTaskContextMenu";
import { FolderIcon, FolderOpenIcon } from "@phosphor-icons/react";
import { CloudIcon, FolderIcon, FolderOpenIcon } from "@phosphor-icons/react";
import { Box, Flex } from "@radix-ui/themes";
import { useRegisteredFoldersStore } from "@renderer/stores/registeredFoldersStore";
import { trpcVanilla } from "@renderer/trpc/client";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { useTasks } from "@features/tasks/hooks/useTasks";
import type { ActiveFilters } from "@features/tasks/stores/taskStore";
import { getUserDisplayName } from "@hooks/useUsers";
import { filtersMatch } from "@lib/filters";
import { logger } from "@renderer/lib/logger";
import { useRegisteredFoldersStore } from "@renderer/stores/registeredFoldersStore";
import type { RegisteredFolder, Task, Workspace } from "@shared/types";
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { useWorkspaceStore } from "@/renderer/features/workspace/stores/workspaceStore";
import {
getTaskRepository,
Expand All @@ -19,6 +20,8 @@ import { usePinnedTasksStore } from "../stores/pinnedTasksStore";
import { useSidebarStore } from "../stores/sidebarStore";
import { useTaskViewedStore } from "../stores/taskViewedStore";

const log = logger.scope("sidebar-data");

export interface TaskView {
id: string;
label: string;
Expand Down Expand Up @@ -71,6 +74,7 @@ export interface SidebarData {
activeRepository: string | null;
isLoading: boolean;
folders: FolderData[];
cloudRepos: CloudRepoData[];
activeTaskId: string | null;
historyData: HistoryData;
pinnedData: PinnedData;
Expand Down Expand Up @@ -339,6 +343,51 @@ export function useSidebarData({
syncFolderOrder(folderIds);
}, [syncFolderOrder, folderIds]);

// Auto-sync remote tasks to workspaces based on repository matching
const ensureWorkspace = useWorkspaceStore((state) => state.ensureWorkspace);
const syncingRef = useRef<Set<string>>(new Set());

useEffect(() => {
const syncTasksToWorkspaces = async () => {
for (const task of allTasks) {
const taskRepo = getTaskRepository(task);
if (!taskRepo) continue;

const hasWorkspace = !!workspaces[task.id];
if (hasWorkspace) continue;

if (syncingRef.current.has(task.id)) continue;

const matchingFolder = folders.find(
(f) => f.repository?.toLowerCase() === taskRepo.toLowerCase(),
);
if (!matchingFolder) continue;

syncingRef.current.add(task.id);
log.info("Auto-syncing task to folder", {
taskId: task.id,
taskRepo,
folderId: matchingFolder.id,
});

try {
await ensureWorkspace(task.id, matchingFolder.path, "cloud");
} catch (err) {
log.error("Failed to auto-sync task", {
taskId: task.id,
error: err,
});
} finally {
syncingRef.current.delete(task.id);
}
}
};

if (allTasks.length > 0 && folders.length > 0) {
syncTasksToWorkspaces();
}
}, [allTasks, folders, workspaces, ensureWorkspace]);

// Sort folders by persisted order
const sortedFolders = sortFoldersByOrder(folders, folderOrder);
const tasksByFolder = groupTasksByFolder(allTasks, folders, workspaces);
Expand Down Expand Up @@ -438,6 +487,7 @@ export function useSidebarData({
activeRepository,
isLoading,
folders: folderData,
cloudRepos,
activeTaskId,
historyData,
pinnedData,
Expand Down
1 change: 1 addition & 0 deletions apps/array/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface RegisteredFolder {
lastAccessed: string;
createdAt: string;
exists?: boolean;
repository?: string;
}

export interface WorktreeInfo {
Expand Down
41 changes: 41 additions & 0 deletions apps/mobile/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/
expo-env.d.ts

# Native
.kotlin/
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo

# generated native folders
/ios
/android
164 changes: 164 additions & 0 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
{
"expo": {
"name": "PostHog AI",
"slug": "posthog",
"version": "1.0.0",
"orientation": "portrait",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"bundler": "metro",
"scheme": "posthog",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#0f0f0f"
},
"ios": {
"icon": "./assets/posthog.icon",
"supportsTablet": true,
"bundleIdentifier": "com.posthog.mobile",
"infoPlist": {
"NSMicrophoneUsageDescription": "Allow PostHog to use your microphone for voice-to-text input",
"ITSAppUsesNonExemptEncryption": false
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#E6E6E6"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
"package": "com.posthog.mobile",
"permissions": [
"android.permission.RECORD_AUDIO",
"android.permission.MODIFY_AUDIO_SETTINGS"
]
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
"expo-router",
[
"expo-av",
{
"microphonePermission": "Allow PostHog to use your microphone for voice-to-text input"
}
],
[
"expo-font",
{
"android": {
"fonts": [
{
"fontFamily": "JetBrains Mono",
"fontDefinitions": [
{
"path": "./assets/fonts/JetBrainsMono-Thin.ttf",
"weight": 100
},
{
"path": "./assets/fonts/JetBrainsMono-ThinItalic.ttf",
"weight": 100,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-ExtraLight.ttf",
"weight": 200
},
{
"path": "./assets/fonts/JetBrainsMono-ExtraLightItalic.ttf",
"weight": 200,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-Light.ttf",
"weight": 300
},
{
"path": "./assets/fonts/JetBrainsMono-LightItalic.ttf",
"weight": 300,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-Regular.ttf",
"weight": 400
},
{
"path": "./assets/fonts/JetBrainsMono-Italic.ttf",
"weight": 400,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-Medium.ttf",
"weight": 500
},
{
"path": "./assets/fonts/JetBrainsMono-MediumItalic.ttf",
"weight": 500,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-SemiBold.ttf",
"weight": 600
},
{
"path": "./assets/fonts/JetBrainsMono-SemiBoldItalic.ttf",
"weight": 600,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-Bold.ttf",
"weight": 700
},
{
"path": "./assets/fonts/JetBrainsMono-BoldItalic.ttf",
"weight": 700,
"style": "italic"
},
{
"path": "./assets/fonts/JetBrainsMono-ExtraBold.ttf",
"weight": 800
},
{
"path": "./assets/fonts/JetBrainsMono-ExtraBoldItalic.ttf",
"weight": 800,
"style": "italic"
}
]
}
]
},
"ios": {
"fonts": [
"./assets/fonts/JetBrainsMono-Thin.ttf",
"./assets/fonts/JetBrainsMono-ThinItalic.ttf",
"./assets/fonts/JetBrainsMono-ExtraLight.ttf",
"./assets/fonts/JetBrainsMono-ExtraLightItalic.ttf",
"./assets/fonts/JetBrainsMono-Light.ttf",
"./assets/fonts/JetBrainsMono-LightItalic.ttf",
"./assets/fonts/JetBrainsMono-Regular.ttf",
"./assets/fonts/JetBrainsMono-Italic.ttf",
"./assets/fonts/JetBrainsMono-Medium.ttf",
"./assets/fonts/JetBrainsMono-MediumItalic.ttf",
"./assets/fonts/JetBrainsMono-SemiBold.ttf",
"./assets/fonts/JetBrainsMono-SemiBoldItalic.ttf",
"./assets/fonts/JetBrainsMono-Bold.ttf",
"./assets/fonts/JetBrainsMono-BoldItalic.ttf",
"./assets/fonts/JetBrainsMono-ExtraBold.ttf",
"./assets/fonts/JetBrainsMono-ExtraBoldItalic.ttf"
]
}
}
]
],
"extra": {
"router": {},
"eas": {
"projectId": "4eb57b2f-79f6-4ab0-ae2c-bbd82af2cef9"
}
},
"owner": "posthog"
}
}
Binary file added apps/mobile/assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/mobile/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/mobile/assets/posthog.icon/Assets/posthog-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading