Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
d1b6821
feat: pipelines chain agent steps across providers
jappyjan Oct 28, 2026
94db63f
docs: pipelines user guide and glossary entry
jappyjan Oct 28, 2026
db3bce6
feat(mcp): agents can list, start, follow, continue and cancel pipelines
jappyjan Oct 28, 2026
478b3b2
fix(pipelines): address review findings
jappyjan Oct 28, 2026
0cbcbeb
fix(pipelines): paused runs need attention, shared start retry and pr…
jappyjan Oct 28, 2026
53f6fa4
fix(web): pipeline run view and composer polish from browser QA
jappyjan Oct 28, 2026
852303c
feat(pipelines): retry can restore the step's starting files
jappyjan Oct 29, 2026
640101c
fix(pipelines): take the step's start snapshot from its first run
jappyjan Oct 29, 2026
c453b59
fix(pipelines): pipeline steps cannot watch pull requests
jappyjan Oct 29, 2026
59b9ef5
fix(pipelines): keep the Pipelines schema out of the migration ladder
jappyjan Oct 29, 2026
16c09e0
fix(pipelines): build on latest upstream main
jappyjan Oct 29, 2026
ec6c8a7
feat(pipelines): steps hand off explicitly and runs can rerun from a …
jappyjan Oct 30, 2026
e546b81
feat(web): collapsible pipeline rows with a stepped progress bar
JappyMondo Oct 30, 2026
8eff75b
fix(clients): pipelines with a busy step show in the Working section
jappyjan Oct 30, 2026
d641705
feat(pipelines): send feedback to an earlier step, and chat with a ru…
jappyjan Oct 30, 2026
fb15c9f
fix(pipelines): build on latest upstream main
jappyjan Oct 30, 2026
305eabc
feat(pipelines): title pipeline runs like chats
jappyjan Oct 30, 2026
6339974
feat(mobile): collapsible pipeline rows with a stepped progress bar
jappyjan Oct 30, 2026
cc67504
fix(pipelines): refuse a step handoff while its background work still…
jappyjan Oct 31, 2026
f65ecb0
fix(pipelines): name the blocking work and cover every refused handof…
jappyjan Oct 31, 2026
a5761b9
fix(pipelines): build on latest upstream main
jappyjan Oct 31, 2026
399c0c0
fix(pipelines): finished runs' steps no longer list as separate chats
jappyjan Oct 31, 2026
d59a570
fix(pipelines): build on latest upstream main
jappyjan Oct 31, 2026
dbae2e3
fix(pipelines): build on latest upstream main
jappyjan Nov 3, 2026
2175c45
feat(contracts): Linear domain schemas, settings section, RPC methods…
jappyjan Oct 30, 2026
2ab02d5
feat(linear): Linear page, settings, launch flows and server integration
jappyjan Oct 31, 2026
41ae11c
fix(linear): connect, disconnect and resync refresh the connection st…
jappyjan Oct 31, 2026
bed9040
fix(linear): Run pipeline menu no longer crashes the app
jappyjan Oct 31, 2026
4109152
fix(linear): hand-edited filter params no longer bypass search valida…
jappyjan Oct 31, 2026
f9f94ef
fix(linear): pipeline dialog keeps hand-edited input and guards the i…
jappyjan Oct 31, 2026
8e29b02
fix(linear): issue markdown header renders as a list
jappyjan Oct 31, 2026
67bc08e
fix(linear): explain hidden completed issues in the empty milestone list
jappyjan Oct 31, 2026
c3f3cf5
fix(sidebar): new Linear drafts show 'Draft · from ISSUE' without a r…
jappyjan Oct 31, 2026
6672287
fix(linear): link a launch even when Linear can't be read
jappyjan Oct 31, 2026
d03854d
fix(server): a launch on an existing branch name gets a free suffix
jappyjan Oct 31, 2026
5211d3e
fix(linear): server review fixes for errors, caches and write-back
jappyjan Oct 31, 2026
52b5513
fix(linear): server pushes refresh clients; guard Linear commands
jappyjan Oct 31, 2026
94f5ab9
fix(linear): web review fixes for views, rows, feedback and narrow wi…
jappyjan Oct 31, 2026
b61f387
docs(linear): user guide for the Linear page
jappyjan Oct 31, 2026
fb950d6
fix(linear): link a launch when Linear rejects the issue read
jappyjan Oct 31, 2026
22ed3d6
refactor(linear): move shared Linear client logic into client-runtime
jappyjan Oct 31, 2026
0a73b2e
feat(mobile): Linear tab, drill-down, issue detail, start chat and ru…
jappyjan Oct 31, 2026
f914bc8
docs(linear): mention the mobile tab
jappyjan Oct 31, 2026
fcd0c90
fix(linear): manual refresh re-reads team cards and their counts
jappyjan Oct 31, 2026
ec76f59
fix(linear): launch hint no longer pushes the composer controls out o…
jappyjan Oct 31, 2026
0668dd4
docs(linear): say where comment links point for launches from the phone
jappyjan Oct 31, 2026
b635c51
fix(mobile): native tab bars show the Linear tab
jappyjan Oct 31, 2026
322f912
test(mobile): cover Linear launch retry, restore and draft decode
jappyjan Oct 31, 2026
ecfee7c
refactor(linear): share pipeline, chat-launch, jump and milestone logic
jappyjan Oct 31, 2026
438d808
fix(linear): mobile review fixes for environments, drafts, lists and …
jappyjan Oct 31, 2026
db66242
fix(web): Linear launch hint hides once the issue chip is removed
jappyjan Oct 31, 2026
5b786cc
fix(linear): build on latest upstream main
jappyjan Oct 31, 2026
ef49dde
fix(mobile): Linear sheet headers, dock overlap, titles and milestone…
jappyjan Oct 31, 2026
0da6454
feat(linear): Linear issue links open the in-app Linear view
jappyjan Oct 31, 2026
6e17b0e
fix(web): Linear links route in-app on narrow layouts
jappyjan Oct 31, 2026
76c0c85
fix(linear): review fixes for Linear issue links
jappyjan Oct 31, 2026
06408f6
test(web): assert the Linear page keeps its scope through real naviga…
jappyjan Oct 31, 2026
7bab9fa
feat(linear): choose the machine when running a pipeline from an issue
jappyjan Oct 31, 2026
423172d
fix(web): mark only one same-named pipeline as last used in the Linea…
jappyjan Oct 31, 2026
4b824bf
fix(linear): advertise remote links and keep other machines' names pl…
jappyjan Oct 31, 2026
7c43aab
fix(linear): review fixes for the pipeline machine picker
jappyjan Oct 31, 2026
029ba6e
docs(linear): primary serves the Linear page; Auto default and older …
jappyjan Oct 31, 2026
1b9671d
fix(linear): Auto settles when the pipeline list fails; honour the re…
jappyjan Oct 31, 2026
9804086
fix(linear): build on latest upstream main
jappyjan Nov 3, 2026
705025f
feat(projects): port pingdotgg/t3code#26254 multi-repo projects
JappyMondo Nov 3, 2026
24726b2
feat(multi-repo): keep pipelines and Linear launches consistent acros…
JappyMondo Nov 3, 2026
15b11af
fix(multi-repo): test typing and web test mocks for the port
JappyMondo Nov 3, 2026
b50e528
fix(multi-repo): drop a stray conflict-marker file left by the port
JappyMondo Nov 3, 2026
fb707f0
fix(multi-repo): offer and allow rewind for a plain home folder with …
JappyMondo Nov 3, 2026
9fb3ccd
fix(multi-repo): refresh each repo's Git status after the agent chang…
JappyMondo Nov 3, 2026
0312559
fix(multi-repo): refuse a file rewind that would skip a Git home with…
JappyMondo Nov 3, 2026
6b64bfa
fix(multi-repo): never save a pipeline start restore inside a multi-r…
JappyMondo Nov 3, 2026
0754ec5
fix(multi-repo): refresh every repo's Git status on the server after …
JappyMondo Nov 3, 2026
12814cf
fix(multi-repo): find the task folder by its recorded path when check…
JappyMondo Nov 3, 2026
2c02761
fix(multi-repo): clear the Repos chip selection after starting a pipe…
JappyMondo Nov 3, 2026
c8c2871
fix(multi-repo): list a repo's branches from its own checkout on mobile
JappyMondo Nov 3, 2026
b7d06a9
fix(multi-repo): refresh only this run's repos, and only their local …
JappyMondo Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file added apps/mobile/assets/context-chip-icons/linear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ class T3WorkspaceNavigationView(
private fun tabTitle(tab: String) = when (tab) {
"threads" -> "Chats"
"pullRequests" -> "Pulls"
"linear" -> "Linear"
"usage" -> "Usage"
else -> "Settings"
}
Expand All @@ -427,6 +428,7 @@ class T3WorkspaceNavigationView(
when (tab) {
"threads" -> R.drawable.t3_chats
"pullRequests" -> R.drawable.t3_pull_requests
"linear" -> R.drawable.t3_linear
"usage" -> R.drawable.t3_usage
else -> R.drawable.t3_settings
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:fillColor="#000000" android:fillType="evenOdd" android:pathData="M12,2A10,10 0 1,0 12,22A10,10 0 1,0 12,2ZM12,4A8,8 0 1,1 12,20A8,8 0 1,1 12,4ZM12,7A5,5 0 1,0 12,17A5,5 0 1,0 12,7Z" />
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ final class T3SidebarTabBarView: ExpoView, UITabBarDelegate {
private func prepareItems() {
let iconBundle = Bundle(for: Self.self).url(forResource: "T3NativeControlIcons", withExtension: "bundle").flatMap(Bundle.init(url:))
let pullRequestIcon = UIImage(named: "pull-request", in: iconBundle, compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
let labels = ["threads": "Chats", "pullRequests": "PRs", "usage": "Usage", "settings": "Settings"]
let symbols = ["threads": "text.bubble", "usage": "chart.bar.xaxis", "settings": "gearshape"]
let labels = ["threads": "Chats", "pullRequests": "PRs", "linear": "Linear", "usage": "Usage", "settings": "Settings"]
let symbols = ["threads": "text.bubble", "linear": "circle.inset.filled", "usage": "chart.bar.xaxis", "settings": "gearshape"]
for (tab, label) in labels {
let icon = tab == "pullRequests" ? pullRequestIcon : UIImage(systemName: symbols[tab] ?? "circle")
let item = UITabBarItem(title: nil, image: tabIcon(icon), tag: 0)
Expand Down
17 changes: 16 additions & 1 deletion apps/mobile/scripts/sync-context-chip-icons.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ if (!skillSvg) {
);
}

const linearIconSource = NodeFS.readFileSync(
NodePath.join(repositoryRoot, "apps/web/src/components/linear/linearIcons.tsx"),
"utf8",
);
const linearLogoPath = linearIconSource.match(/LINEAR_LOGO_PATH =\s*"([^"]*)"/)?.[1];

if (!linearLogoPath) {
throw new Error(
"Could not read LINEAR_LOGO_PATH from apps/web/src/components/linear/linearIcons.tsx",
);
}

const linearSvg = `<svg viewBox="0 0 100 100" fill="currentColor"><path d="${linearLogoPath}"/></svg>`;

const lucideIcons = [
"circle-dashed",
"film",
Expand Down Expand Up @@ -83,8 +97,9 @@ for (const name of lucideIcons) {
await renderIcon(name, await lucideSvg(name));
}
await renderIcon("skill", skillSvg);
await renderIcon("linear", linearSvg);

const tokens = [...lucideIcons, "skill"].sort();
const tokens = [...lucideIcons, "skill", "linear"].sort();
const generatedSource = `import type { ImageSourcePropType } from "react-native";\n\nexport const CONTEXT_CHIP_ICON_SOURCES = {\n${tokens
.map(
(token) =>
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { pipe } from "effect/Function";

import { RegistryContext } from "@effect/atom-react";
import { ProjectChipIconRasterizer } from "./native/ProjectChipIconImages";
import { LinearStatusKeepAlive } from "./features/linear/LinearStatusKeepAlive";
import { ThreadArrangementHost } from "./features/threads/ThreadArrangementSheet";
import * as Dialog from "./components/ui/Dialog";
import { CloudAuthProvider } from "./features/cloud/CloudAuthProvider";
Expand Down Expand Up @@ -226,6 +227,7 @@ function AppContent() {
<>
<SplashScreenCoordinator />
<SubscriptionUsageCoordinator />
<LinearStatusKeepAlive />
<GestureHandlerRootView className="flex-1">
<KeyboardProvider statusBarTranslucent>
<SafeAreaProvider>
Expand Down
107 changes: 107 additions & 0 deletions apps/mobile/src/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ import { GitConfirmSheet } from "./features/threads/git/GitConfirmSheet";
import { GitOverviewSheet } from "./features/threads/git/GitOverviewSheet";
import { ThreadPullRequestsSheet } from "./features/threads/ThreadPullRequestsSheet";
import { ThreadAgentsSheet } from "./features/threads/ThreadAgentsSheet";
import { PipelineCoordinatorRouteScreen } from "./features/threads/PipelineCoordinatorSheet";
import { PipelineFeedbackSheet } from "./features/threads/PipelineFeedbackSheet";
import { LinearIssueRouteScreen } from "./features/linear/LinearIssueRouteScreen";
import {
LinearMilestoneScreen,
LinearProjectScreen,
LinearTeamScreen,
} from "./features/linear/LinearLevelScreens";
import { LinearWorkspaceLinkScreen } from "./features/linear/LinearWorkspaceLinkScreen";
import { LINEAR_LINK_PATHS } from "./features/linear/linearRoutes";
import { LinearPipelineSheet } from "./features/linear/LinearPipelineSheet";
import { LinearProjectPickerSheet } from "./features/linear/LinearProjectPickerSheet";
import { ThreadBackgroundWorkSheet } from "./features/threads/ThreadBackgroundWorkSheet";
import { ThreadQueueSheet } from "./features/threads/ThreadQueueControl";
import {
Expand Down Expand Up @@ -111,6 +123,12 @@ import {
SettingsScheduledTaskNewRouteScreen,
SettingsScheduledTaskEditRouteScreen,
} from "./features/settings/SettingsScheduledTasksRouteScreen";
import {
SettingsPipelinesRouteScreen,
SettingsPipelineNewRouteScreen,
SettingsPipelineEditRouteScreen,
} from "./features/settings/SettingsPipelinesRouteScreen";
import { PipelineStepModelPickerRouteScreen } from "./features/settings/PipelinePickerScreens";
import {
ScheduledTaskModelPickerRouteScreen,
ScheduledTaskBranchPickerRouteScreen,
Expand Down Expand Up @@ -415,6 +433,35 @@ const SETTINGS_SCREENS = {
}),
},
}),
SettingsPipelines: createNativeStackScreen({
screen: SettingsPipelinesRouteScreen,
linking: "settings/pipelines",
options: {
...SETTINGS_PAGE_OPTIONS,
title: "Pipelines",
headerTitleStyle: { fontSize: 16, fontWeight: "800" },
},
}),
SettingsPipelineNew: createNativeStackScreen({
screen: SettingsPipelineNewRouteScreen,
options: { ...SETTINGS_PAGE_OPTIONS, title: "New pipeline" },
}),
SettingsPipelineEdit: createNativeStackScreen({
screen: SettingsPipelineEditRouteScreen,
options: { ...SETTINGS_PAGE_OPTIONS, title: "Edit pipeline" },
}),
SettingsPipelineStepModel: createNativeStackScreen({
screen: PipelineStepModelPickerRouteScreen,
options: {
...SETTINGS_PAGE_OPTIONS,
headerShown: false,
...(Platform.OS === "android"
? { presentation: "card" as const }
: {
...THREAD_SETTINGS_SHEET_OPTIONS,
}),
},
}),
SettingsClientStorage: createNativeStackScreen({
screen: SettingsClientStorageRouteScreen,
linking: "settings/client-storage",
Expand Down Expand Up @@ -721,6 +768,31 @@ const RootStackConfig = createWorkspaceStackNavigator({
sheetGrabberVisible: true,
},
}),
LinearWorkspace: createNativeStackScreen({
screen: LinearWorkspaceLinkScreen,
linking: LINEAR_LINK_PATHS.LinearWorkspace,
options: { headerShown: false },
}),
LinearTeam: createNativeStackScreen({
screen: LinearTeamScreen,
linking: LINEAR_LINK_PATHS.LinearTeam,
options: DETAIL_HEADER_OPTIONS,
}),
LinearProject: createNativeStackScreen({
screen: LinearProjectScreen,
linking: LINEAR_LINK_PATHS.LinearProject,
options: DETAIL_HEADER_OPTIONS,
}),
LinearMilestone: createNativeStackScreen({
screen: LinearMilestoneScreen,
linking: LINEAR_LINK_PATHS.LinearMilestone,
options: DETAIL_HEADER_OPTIONS,
}),
LinearIssue: createNativeStackScreen({
screen: LinearIssueRouteScreen,
linking: LINEAR_LINK_PATHS.LinearIssue,
options: DETAIL_HEADER_OPTIONS,
}),
Thread: createNativeStackScreen({
screen: ThreadRouteScreen,
linking: { path: "threads/:environmentId?/:threadId?", alias: ["new/draft"] },
Expand Down Expand Up @@ -911,6 +983,41 @@ const RootStackConfig = createWorkspaceStackNavigator({
sheetGrabberVisible: true,
},
}),
PipelineCoordinator: createNativeStackScreen({
screen: PipelineCoordinatorRouteScreen,
options: {
...HORIZONTAL_FORM_SHEET_OPTIONS,
headerShown: false,
sheetAllowedDetents: formSheetDetents(0.9),
sheetGrabberVisible: true,
},
}),
PipelineFeedback: createNativeStackScreen({
screen: PipelineFeedbackSheet,
options: {
...HORIZONTAL_FORM_SHEET_OPTIONS,
sheetAllowedDetents: formSheetDetents(0.7),
sheetGrabberVisible: true,
},
}),
LinearProjectPicker: createNativeStackScreen({
screen: LinearProjectPickerSheet,
options: {
...(Platform.OS === "ios" ? SHEET_GLASS_HEADER_OPTIONS : undefined),
...HORIZONTAL_FORM_SHEET_OPTIONS,
sheetAllowedDetents: formSheetDetents(0.6),
sheetGrabberVisible: true,
},
}),
LinearPipeline: createNativeStackScreen({
screen: LinearPipelineSheet,
options: {
...(Platform.OS === "ios" ? SHEET_GLASS_HEADER_OPTIONS : undefined),
...HORIZONTAL_FORM_SHEET_OPTIONS,
sheetAllowedDetents: formSheetDetents(0.9),
sheetGrabberVisible: true,
},
}),
GitOverview: createNativeStackScreen({
screen: GitOverviewSheet,
linking: `${THREAD_LINKING_PREFIX}/git`,
Expand Down
57 changes: 57 additions & 0 deletions apps/mobile/src/components/ComposerContextSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
import { formatAttachmentSize } from "@t3tools/client-runtime/state/attachments";
import { sourceControlClients } from "@t3tools/client-runtime/source-control-clients";
import { videoMimeType } from "@t3tools/shared/video";
import type { LinearIssueContextRecord } from "@t3tools/contracts";
import { Platform, Pressable, ScrollView, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { REVIEW_MONO_FONT_FAMILY } from "../features/review/reviewDiffRendering";
Expand All @@ -23,6 +24,7 @@ import {
type DraftComposerAttachment,
} from "../lib/composerImages";
import { contextImageGallery } from "../lib/contextImageGallery";
import { tryOpenWebLink } from "../lib/openExternalUrl";
import { FilePreviewModal } from "./FilePreviewModal";
import { VideoPreviewModal } from "./VideoPreviewModal";
import { ComposerContextAttachment } from "./ComposerContextAttachment";
Expand Down Expand Up @@ -75,6 +77,60 @@ function ContextSource(props: { source: ElementContextSource | null }) {
);
}

function LinearIssueSnapshot(props: { readonly record: LinearIssueContextRecord }) {
const { record } = props;
const breadcrumb = [record.teamName, record.projectName, record.milestoneName].filter(
(part): part is string => part !== null && part.length > 0,
);
const meta = [record.stateName, record.priorityLabel, record.assigneeName].filter(
(part): part is string => part !== null && part.length > 0,
);
const excerpt = record.description.trim().slice(0, 600);
return (
<View className="gap-4">
<ContextField label={breadcrumb.join(" › ")} value={`${record.identifier} ${record.title}`} />
<ContextField label="Status" value={meta.join(" · ")} />
<ContextField label="Labels" value={record.labels.join(", ")} />
<ContextField
label="Description"
value={excerpt.length < record.description.trim().length ? `${excerpt}…` : excerpt}
/>
{record.subIssues.length > 0 ? (
<ContextField
label={`Sub-issues (${record.subIssues.length})`}
value={record.subIssues
.slice(0, 5)
.map((sub) => `${sub.identifier} ${sub.title}`)
.concat(record.subIssues.length > 5 ? [`and ${record.subIssues.length - 5} more`] : [])
.join("\n")}
/>
) : null}
{record.comments.length > 0 ? (
<ContextField
label={`Comments (${record.comments.length})`}
value={record.comments
.slice(-2)
.map(
(comment) => `${comment.author ?? "Unknown"}: ${comment.body.trim().slice(0, 200)}`,
)
.join("\n")}
/>
) : null}
<Text className="text-xs text-foreground-muted">
Snapshot taken when attached; later edits in Linear are not included.
</Text>
{/^https?:\/\//i.test(record.url) ? (
<Button
label="Open in Linear"
tone="secondary"
onPress={() => void tryOpenWebLink(record.url, "markdown-link")}
fullWidth
/>
) : null}
</View>
);
}

export function ComposerContextSheet(props: {
readonly label: string;
readonly record: ComposerContextRecord | undefined;
Expand Down Expand Up @@ -324,6 +380,7 @@ export function ComposerContextSheet(props: {
) : null}
</View>
) : null}
{record.kind === "linear-issue" ? <LinearIssueSnapshot record={record} /> : null}
{record.kind === "environment" ? (
<ContextField label="Machine" value={record.label} />
) : null}
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/connection/environment-cache-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const SHELL_SNAPSHOT: OrchestrationV2ShellSnapshot = {
repositoryIdentity: null,
defaultModelSelection: null,
scripts: [],
trackedFolders: [],
createdAt: "2026-07-29T12:00:00.000Z",
updatedAt: "2026-07-29T12:00:00.000Z",
},
Expand Down
12 changes: 12 additions & 0 deletions apps/mobile/src/features/home/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,11 @@ export function HomeScreen(props: HomeScreenProps) {
snoozedShelfExpanded,
workingShelfEnabled,
workingShelfExpanded,
expandedPipelineKeys,
toggleSettledShelf,
toggleSnoozedShelf,
toggleWorkingShelf,
togglePipelineExpanded,
} = useThreadListV2ShelfPreferences();
const now = useThreadListNow(props.threads);
const listEnvironments = useAtomValue(threadListEnvironmentsAtom);
Expand All @@ -442,6 +444,7 @@ export function HomeScreen(props: HomeScreenProps) {
machineByEnvironmentId,
settlementEnvironmentIds,
snoozeEnvironmentIds,
pipelineEnvironmentIds,
snoozePresetsByEnvironmentId,
pinningEnvironmentIds,
autoSettleOptOutEnvironmentIds,
Expand All @@ -464,6 +467,7 @@ export function HomeScreen(props: HomeScreenProps) {
searchQuery: props.searchQuery,
searchMatches: threadSearchMatchByKey,
settlementEnvironmentIds,
pipelineEnvironmentIds,
snoozeEnvironmentIds,
pinReorderEnvironmentIds,
activeReorderEnvironmentIds,
Expand All @@ -476,6 +480,7 @@ export function HomeScreen(props: HomeScreenProps) {
workingShelfExpanded,
snoozedShelfExpanded,
settledShelfExpanded,
expandedPipelineKeys,
selectedThreadKey,
});
// Called as `props.onSelectThread(...)`, the compiler would cache this handler on the whole
Expand Down Expand Up @@ -575,6 +580,13 @@ export function HomeScreen(props: HomeScreenProps) {
onNewThreadOnBranch={props.onNewThreadOnBranch}
thread={thread}
variant={item.item.variant}
nested={item.item.nested}
isLastStep={item.item.isLastStep}
stepStatus={item.item.stepStatus}
stepLabel={item.item.stepLabel}
pipelineProgress={item.item.pipelineProgress}
pipelineExpanded={item.item.pipelineExpanded}
onTogglePipelineSteps={togglePipelineExpanded}
hasQueuedMessages={item.hasQueuedMessages}
snoozed={item.item.snoozed}
pinned={item.item.pinned}
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/features/home/homeThreadList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function makeProject(
repositoryIdentity: null,
defaultModelSelection: null,
scripts: [],
trackedFolders: [],
createdAt: "2026-06-01T00:00:00.000Z",
updatedAt: "2026-06-01T00:00:00.000Z",
...input,
Expand Down
7 changes: 7 additions & 0 deletions apps/mobile/src/features/keyboard/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,13 @@ export function CommandPalette(props: {
searchTerms: ["schedule", "automations", "recurring"],
run: () => openSettings(navigation, "SettingsScheduledTasks"),
},
{
key: "pipelines",
kind: "action",
title: "Pipelines",
searchTerms: ["workflow", "steps", "chain"],
run: () => openSettings(navigation, "SettingsPipelines"),
},
{
key: "usage",
kind: "action",
Expand Down
Loading
Loading