@adminide-stack/yantra-mobile 12.0.120-alpha.1 → 12.0.120-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import {jsxs,Fragment,jsx}from'react/jsx-runtime';import {useState,useCallback}from'react';import {ScrollView,StyleSheet,Text,View,Pressable,ActivityIndicator}from'react-native';import {useFocusEffect}from'@react-navigation/native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {MAX_CONCURRENT_TASKS}from'../../config/constants.js';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useGatewayContext}from'../../contexts/GatewayContext.js';import {useAgentSessionState}from'../../hooks/useAgentSessionState.js';import {agentSessionManager}from'../../services/agentSessionManager.js';import {mobileTokens}from'../../theme/mobileTokens.js';import {HeaderSheet}from'./HeaderSheet.js';import {HeaderToolbarButton}from'./HeaderToolbarButton.js';const STATUS_LABEL = {
1
+ import {jsxs,Fragment,jsx}from'react/jsx-runtime';import {useState,useEffect,useCallback}from'react';import {Linking,ScrollView,StyleSheet,Text,View,Pressable,ActivityIndicator}from'react-native';import {useFocusEffect,useNavigation}from'@react-navigation/native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {isJobRunning,jobStateLabel,jobDetailLine,slugLabel}from'common';import {MAX_CONCURRENT_TASKS}from'../../config/constants.js';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useGatewayContext}from'../../contexts/GatewayContext.js';import {WEBBUILDER_JOB_SURFACE}from'../../features/webbuilder/buildJob.js';import {useAgentSessionState}from'../../hooks/useAgentSessionState.js';import {useSurfaceJobs}from'../../hooks/useSurfaceJobs.js';import {agentSessionManager}from'../../services/agentSessionManager.js';import {mobileTokens}from'../../theme/mobileTokens.js';import {HeaderSheet}from'./HeaderSheet.js';import {HeaderToolbarButton}from'./HeaderToolbarButton.js';const STATUS_LABEL = {
2
2
  idle: "Idle",
3
3
  connecting: "Connecting",
4
4
  running: "Running",
@@ -6,6 +6,23 @@ import {jsxs,Fragment,jsx}from'react/jsx-runtime';import {useState,useCallback}f
6
6
  failed: "Failed",
7
7
  aborted: "Aborted"
8
8
  };
9
+ const STATUS_GLYPH = {
10
+ completed: {
11
+ name: "check-circle-outline",
12
+ light: "#16a34a",
13
+ dark: "#4ade80"
14
+ },
15
+ failed: {
16
+ name: "alert-circle-outline",
17
+ light: "#dc2626",
18
+ dark: "#f87171"
19
+ },
20
+ aborted: {
21
+ name: "close-circle-outline",
22
+ light: "#ea580c",
23
+ dark: "#fb923c"
24
+ }
25
+ };
9
26
  function StatusGlyph({
10
27
  status,
11
28
  isDark
@@ -13,9 +30,17 @@ function StatusGlyph({
13
30
  if (status === "running" || status === "connecting") {
14
31
  return /* @__PURE__ */ jsx(ActivityIndicator, { size: 14, color: isDark ? "#60a5fa" : "#2563eb" });
15
32
  }
16
- const name = status === "completed" ? "check-circle-outline" : status === "failed" ? "alert-circle-outline" : status === "aborted" ? "close-circle-outline" : "circle-outline";
17
- const color = status === "completed" ? isDark ? "#4ade80" : "#16a34a" : status === "failed" ? isDark ? "#f87171" : "#dc2626" : status === "aborted" ? isDark ? "#fb923c" : "#ea580c" : isDark ? "#94a3b8" : mobileTokens.color.textMuted;
18
- return /* @__PURE__ */ jsx(MaterialCommunityIcons, { name, size: 16, color });
33
+ const glyph = STATUS_GLYPH[status];
34
+ if (!glyph) {
35
+ const muted = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
36
+ return /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "circle-outline", size: 16, color: muted });
37
+ }
38
+ return /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: glyph.name, size: 16, color: isDark ? glyph.dark : glyph.light });
39
+ }
40
+ function previewOf(task) {
41
+ const last = task.messages[task.messages.length - 1];
42
+ if (!last) return "No messages yet";
43
+ return last.content.length > 60 ? `${last.content.slice(0, 60)}\u2026` : last.content;
19
44
  }
20
45
  function TaskRow({
21
46
  task,
@@ -26,8 +51,7 @@ function TaskRow({
26
51
  }) {
27
52
  const foreground = isDark ? "#e2e8f0" : mobileTokens.color.text;
28
53
  const muted = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
29
- const last = task.messages[task.messages.length - 1];
30
- const preview = last ? last.content.length > 60 ? `${last.content.slice(0, 60)}\u2026` : last.content : "No messages yet";
54
+ const preview = previewOf(task);
31
55
  const skillLabel = task.skillTemplateName || task.skillTemplate;
32
56
  return /* @__PURE__ */ jsxs(Pressable, { onPress: onSelect, style: ({
33
57
  pressed
@@ -53,11 +77,76 @@ function TaskRow({
53
77
  /* @__PURE__ */ jsx(Pressable, { onPress: onRemove, hitSlop: 8, accessibilityLabel: "Remove task", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "trash-can-outline", size: 16, color: muted }) })
54
78
  ] });
55
79
  }
80
+ function JobRow({
81
+ job,
82
+ now,
83
+ isDark,
84
+ onOpen,
85
+ onDismiss
86
+ }) {
87
+ const foreground = isDark ? "#e2e8f0" : mobileTokens.color.text;
88
+ const muted = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
89
+ const stateLabel = jobStateLabel(job, now);
90
+ const detail = jobDetailLine(job);
91
+ return /* @__PURE__ */ jsxs(Pressable, { onPress: onOpen != null ? onOpen : void 0, disabled: !onOpen, accessibilityRole: "button", accessibilityLabel: `${job.title}, ${stateLabel}`, style: ({
92
+ pressed
93
+ }) => [styles.row, pressed && styles.pressed], children: [
94
+ job.state === "running" ? /* @__PURE__ */ jsx(ActivityIndicator, { size: 14, color: isDark ? "#60a5fa" : "#2563eb" }) : /* @__PURE__ */ jsx(StatusGlyph, { status: job.state === "succeeded" ? "completed" : "failed", isDark }),
95
+ /* @__PURE__ */ jsxs(View, { style: styles.rowBody, children: [
96
+ /* @__PURE__ */ jsxs(View, { style: styles.titleRow, children: [
97
+ /* @__PURE__ */ jsx(Text, { style: [styles.rowTitle, {
98
+ color: foreground
99
+ }], numberOfLines: 1, children: job.title }),
100
+ /* @__PURE__ */ jsx(View, { style: [styles.skillChip, isDark && styles.skillChipDark], children: /* @__PURE__ */ jsx(Text, { style: [styles.skillChipText, {
101
+ color: muted
102
+ }], numberOfLines: 1, children: slugLabel(job.slug) }) })
103
+ ] }),
104
+ /* @__PURE__ */ jsx(Text, { style: [styles.rowMeta, {
105
+ color: muted
106
+ }], numberOfLines: 2, children: detail ? `${stateLabel} \xB7 ${detail}` : stateLabel })
107
+ ] }),
108
+ job.state === "running" ? null : /* @__PURE__ */ jsx(Pressable, { onPress: onDismiss, hitSlop: 8, accessibilityLabel: "Remove task", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "trash-can-outline", size: 16, color: muted }) })
109
+ ] });
110
+ }
111
+ function webBuilderChannel(job) {
112
+ var _a;
113
+ const channelId = (_a = job.handle) == null ? void 0 : _a.channelId;
114
+ return job.slug === WEBBUILDER_JOB_SURFACE && typeof channelId === "string" && channelId ? channelId : null;
115
+ }
56
116
  function TasksSheet({
57
117
  isDark,
58
- onClose
118
+ onClose,
119
+ jobs,
120
+ runningJobs,
121
+ onDismissJob
59
122
  }) {
60
123
  const session = useAgentSessionState();
124
+ const navigation = useNavigation();
125
+ const [now, setNow] = useState(() => Date.now());
126
+ useEffect(() => {
127
+ if (!jobs.some(isJobRunning)) return void 0;
128
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
129
+ return () => clearInterval(timer);
130
+ }, [jobs]);
131
+ const openJob = useCallback((job) => {
132
+ const channelId = webBuilderChannel(job);
133
+ if (channelId) {
134
+ return () => {
135
+ onClose();
136
+ navigation.navigate("MainStack.WebBuilderNative", {
137
+ openChannelId: channelId
138
+ });
139
+ };
140
+ }
141
+ const {
142
+ pageUrl
143
+ } = job;
144
+ if (!pageUrl) return null;
145
+ return () => {
146
+ onClose();
147
+ Linking.openURL(pageUrl).catch(() => void 0);
148
+ };
149
+ }, [navigation, onClose]);
61
150
  const {
62
151
  selectedGateway
63
152
  } = useGatewayContext();
@@ -72,30 +161,47 @@ function TasksSheet({
72
161
  title: "General Assistant"
73
162
  });
74
163
  }, [canCreate]);
75
- return /* @__PURE__ */ jsx(HeaderSheet, { visible: true, title: "Tasks", subtitle: `${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots`, isDark, onClose, headerRight: /* @__PURE__ */ jsxs(View, { style: styles.headerRight, children: [
164
+ return /* @__PURE__ */ jsx(HeaderSheet, { visible: true, title: "Tasks", subtitle: jobs.length ? `${runningJobs} running \xB7 ${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots` : `${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots`, isDark, onClose, headerRight: /* @__PURE__ */ jsxs(View, { style: styles.headerRight, children: [
76
165
  /* @__PURE__ */ jsx(View, { style: [styles.gwDot, {
77
166
  backgroundColor: connected ? "#22c55e" : "#94a3b8"
78
167
  }] }),
79
168
  /* @__PURE__ */ jsx(Pressable, { onPress: handleNew, disabled: !canCreate, accessibilityLabel: "Start new task", style: ({
80
169
  pressed
81
170
  }) => [styles.newBtn, pressed && styles.pressed, !canCreate && styles.disabled], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "plus", size: 16, color: mobileTokens.color.primary }) })
82
- ] }), children: /* @__PURE__ */ jsx(ScrollView, { style: {
171
+ ] }), children: /* @__PURE__ */ jsxs(ScrollView, { style: {
83
172
  flex: 1
84
- }, contentContainerStyle: styles.list, keyboardShouldPersistTaps: "handled", children: session.tasks.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles.empty, {
85
- color: muted
86
- }], children: connected ? "No tasks yet. Create one to get started." : "Connect Yantra to create tasks." }) : session.tasks.map((task) => /* @__PURE__ */ jsx(TaskRow, { task, isActive: session.activeTaskId === task.id, isDark, onSelect: () => agentSessionManager.setActiveTask(task.id), onRemove: () => agentSessionManager.removeTask(task.id) }, task.id)) }) });
173
+ }, contentContainerStyle: styles.list, keyboardShouldPersistTaps: "handled", children: [
174
+ jobs.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
175
+ /* @__PURE__ */ jsx(Text, { style: [styles.sectionLabel, {
176
+ color: muted
177
+ }], children: "Jobs" }),
178
+ jobs.map((job) => /* @__PURE__ */ jsx(JobRow, { job, now, isDark, onOpen: openJob(job), onDismiss: () => onDismissJob(job.id) }, job.id)),
179
+ session.tasks.length > 0 ? /* @__PURE__ */ jsx(Text, { style: [styles.sectionLabel, {
180
+ color: muted
181
+ }], children: "Sessions" }) : null
182
+ ] }) : null,
183
+ session.tasks.map((task) => /* @__PURE__ */ jsx(TaskRow, { task, isActive: session.activeTaskId === task.id, isDark, onSelect: () => agentSessionManager.setActiveTask(task.id), onRemove: () => agentSessionManager.removeTask(task.id) }, task.id)),
184
+ session.tasks.length === 0 && jobs.length === 0 ? /* @__PURE__ */ jsx(Text, { style: [styles.empty, {
185
+ color: muted
186
+ }], children: connected ? "No tasks yet. Create one to get started." : "Connect Yantra to create tasks." }) : null
187
+ ] }) });
87
188
  }
88
189
  function HeaderTasksButton({
89
190
  isDark
90
191
  }) {
91
192
  const session = useAgentSessionState();
92
193
  const [open, setOpen] = useState(false);
93
- useFocusEffect(useCallback(() => {
94
- return () => setOpen(false);
95
- }, []));
194
+ const surfaceJobs = useSurfaceJobs(open);
195
+ const {
196
+ refresh: refreshJobs
197
+ } = surfaceJobs;
198
+ useEffect(() => {
199
+ if (open) refreshJobs();
200
+ }, [open, refreshJobs]);
201
+ useFocusEffect(useCallback(() => () => setOpen(false), []));
96
202
  return /* @__PURE__ */ jsxs(Fragment, { children: [
97
- /* @__PURE__ */ jsx(HeaderToolbarButton, { icon: "pulse", label: "Tasks", badge: session.tasks.length, active: open, onPress: () => setOpen(true), accessibilityLabel: "Tasks", isDark }),
98
- open ? /* @__PURE__ */ jsx(TasksSheet, { isDark, onClose: () => setOpen(false) }) : null
203
+ /* @__PURE__ */ jsx(HeaderToolbarButton, { icon: "pulse", label: "Tasks", badge: session.tasks.length + surfaceJobs.runningCount, active: open, onPress: () => setOpen(true), accessibilityLabel: "Tasks", isDark }),
204
+ open ? /* @__PURE__ */ jsx(TasksSheet, { isDark, onClose: () => setOpen(false), jobs: surfaceJobs.jobs, runningJobs: surfaceJobs.runningCount, onDismissJob: surfaceJobs.dismiss }) : null
99
205
  ] });
100
206
  }
101
207
  const styles = StyleSheet.create({
@@ -161,6 +267,13 @@ const styles = StyleSheet.create({
161
267
  rowMeta: {
162
268
  fontSize: 12
163
269
  },
270
+ sectionLabel: {
271
+ fontSize: 11,
272
+ fontWeight: "700",
273
+ letterSpacing: 0.4,
274
+ textTransform: "uppercase",
275
+ marginTop: 4
276
+ },
164
277
  empty: {
165
278
  fontSize: 14,
166
279
  lineHeight: 20,
@@ -1 +1 @@
1
- {"version":3,"file":"HeaderTasksButton.js","sources":["../../../src/components/NavigationHeader/HeaderTasksButton.tsx"],"sourcesContent":["import React, { useCallback, useState } from 'react';\nimport { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { useFocusEffect } from '@react-navigation/native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { MAX_CONCURRENT_TASKS } from '../../config/constants';\nimport { useCdecliConnection } from '../../contexts/CdecliConnectionContext';\nimport { useGatewayContext } from '../../contexts/GatewayContext';\nimport { useAgentSessionState } from '../../hooks/useAgentSessionState';\nimport { agentSessionManager, type AgentTask, type TaskStatus } from '../../services/agentSessionManager';\nimport { mobileTokens } from '../../theme/mobileTokens';\nimport { HeaderSheet } from './HeaderSheet';\nimport { HeaderToolbarButton } from './HeaderToolbarButton';\n\ntype Props = {\n isDark: boolean;\n};\n\nconst STATUS_LABEL: Record<TaskStatus, string> = {\n idle: 'Idle',\n connecting: 'Connecting',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n aborted: 'Aborted',\n};\n\nfunction StatusGlyph({ status, isDark }: { status: TaskStatus; isDark: boolean }) {\n if (status === 'running' || status === 'connecting') {\n return <ActivityIndicator size={14} color={isDark ? '#60a5fa' : '#2563eb'} />;\n }\n const name =\n status === 'completed'\n ? 'check-circle-outline'\n : status === 'failed'\n ? 'alert-circle-outline'\n : status === 'aborted'\n ? 'close-circle-outline'\n : 'circle-outline';\n const color =\n status === 'completed'\n ? isDark\n ? '#4ade80'\n : '#16a34a'\n : status === 'failed'\n ? isDark\n ? '#f87171'\n : '#dc2626'\n : status === 'aborted'\n ? isDark\n ? '#fb923c'\n : '#ea580c'\n : isDark\n ? '#94a3b8'\n : mobileTokens.color.textMuted;\n return <MaterialCommunityIcons name={name} size={16} color={color} />;\n}\n\nfunction TaskRow({\n task,\n isActive,\n isDark,\n onSelect,\n onRemove,\n}: {\n task: AgentTask;\n isActive: boolean;\n isDark: boolean;\n onSelect: () => void;\n onRemove: () => void;\n}) {\n const foreground = isDark ? '#e2e8f0' : mobileTokens.color.text;\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const last = task.messages[task.messages.length - 1];\n const preview = last\n ? last.content.length > 60\n ? `${last.content.slice(0, 60)}…`\n : last.content\n : 'No messages yet';\n const skillLabel = task.skillTemplateName || task.skillTemplate;\n\n return (\n <Pressable\n onPress={onSelect}\n style={({ pressed }) => [\n styles.row,\n isActive && styles.rowActive,\n isDark && isActive && styles.rowActiveDark,\n pressed && styles.pressed,\n ]}\n >\n <StatusGlyph status={task.status} isDark={isDark} />\n <View style={styles.rowBody}>\n <View style={styles.titleRow}>\n <Text style={[styles.rowTitle, { color: foreground }]} numberOfLines={1}>\n {task.title}\n </Text>\n {skillLabel ? (\n <View style={[styles.skillChip, isDark && styles.skillChipDark]}>\n <Text style={[styles.skillChipText, { color: muted }]} numberOfLines={1}>\n {skillLabel}\n </Text>\n </View>\n ) : null}\n </View>\n <Text style={[styles.rowMeta, { color: muted }]} numberOfLines={1}>\n {STATUS_LABEL[task.status]} · {preview}\n </Text>\n </View>\n <Pressable onPress={onRemove} hitSlop={8} accessibilityLabel=\"Remove task\">\n <MaterialCommunityIcons name=\"trash-can-outline\" size={16} color={muted} />\n </Pressable>\n </Pressable>\n );\n}\n\nfunction TasksSheet({ isDark, onClose }: { isDark: boolean; onClose: () => void }) {\n const session = useAgentSessionState();\n const { selectedGateway } = useGatewayContext();\n const cdecli = useCdecliConnection();\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const cdecliSelected = selectedGateway?.channelType === 'cdecli-serve';\n const connected = cdecliSelected ? cdecli.channelConnected : session.gatewayConnected;\n const canCreate = session.tasks.length < MAX_CONCURRENT_TASKS && (cdecliSelected || session.gatewayConnected);\n\n const handleNew = useCallback(() => {\n if (!canCreate) return;\n agentSessionManager.createTask({ title: 'General Assistant' });\n }, [canCreate]);\n\n return (\n <HeaderSheet\n visible\n title=\"Tasks\"\n subtitle={`${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots`}\n isDark={isDark}\n onClose={onClose}\n headerRight={\n <View style={styles.headerRight}>\n <View style={[styles.gwDot, { backgroundColor: connected ? '#22c55e' : '#94a3b8' }]} />\n <Pressable\n onPress={handleNew}\n disabled={!canCreate}\n accessibilityLabel=\"Start new task\"\n style={({ pressed }) => [\n styles.newBtn,\n pressed && styles.pressed,\n !canCreate && styles.disabled,\n ]}\n >\n <MaterialCommunityIcons name=\"plus\" size={16} color={mobileTokens.color.primary} />\n </Pressable>\n </View>\n }\n >\n <ScrollView style={{ flex: 1 }} contentContainerStyle={styles.list} keyboardShouldPersistTaps=\"handled\">\n {session.tasks.length === 0 ? (\n <Text style={[styles.empty, { color: muted }]}>\n {connected ? 'No tasks yet. Create one to get started.' : 'Connect Yantra to create tasks.'}\n </Text>\n ) : (\n session.tasks.map((task) => (\n <TaskRow\n key={task.id}\n task={task}\n isActive={session.activeTaskId === task.id}\n isDark={isDark}\n onSelect={() => agentSessionManager.setActiveTask(task.id)}\n onRemove={() => agentSessionManager.removeTask(task.id)}\n />\n ))\n )}\n </ScrollView>\n </HeaderSheet>\n );\n}\n\nexport function HeaderTasksButton({ isDark }: Props) {\n const session = useAgentSessionState();\n const [open, setOpen] = useState(false);\n\n useFocusEffect(\n useCallback(() => {\n return () => setOpen(false);\n }, []),\n );\n\n return (\n <>\n <HeaderToolbarButton\n icon=\"pulse\"\n label=\"Tasks\"\n badge={session.tasks.length}\n active={open}\n onPress={() => setOpen(true)}\n accessibilityLabel=\"Tasks\"\n isDark={isDark}\n />\n {open ? <TasksSheet isDark={isDark} onClose={() => setOpen(false)} /> : null}\n </>\n );\n}\n\nconst styles = StyleSheet.create({\n list: {\n paddingHorizontal: 16,\n paddingBottom: 12,\n gap: 8,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 10,\n borderRadius: 12,\n borderWidth: 1,\n borderColor: 'transparent',\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: mobileTokens.color.surfaceMuted,\n },\n rowActive: {\n borderColor: mobileTokens.color.primaryBorder,\n backgroundColor: mobileTokens.color.primarySoft,\n },\n rowActiveDark: {\n backgroundColor: 'rgba(79,70,229,0.18)',\n },\n pressed: {\n opacity: 0.7,\n },\n disabled: {\n opacity: 0.4,\n },\n titleRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n minWidth: 0,\n },\n skillChip: {\n maxWidth: 96,\n borderRadius: 6,\n paddingHorizontal: 6,\n paddingVertical: 2,\n backgroundColor: mobileTokens.color.surface,\n },\n skillChipDark: {\n backgroundColor: '#0f172a',\n },\n skillChipText: {\n fontSize: 10,\n fontWeight: '600',\n },\n rowBody: {\n flex: 1,\n minWidth: 0,\n gap: 2,\n },\n rowTitle: {\n flexShrink: 1,\n fontSize: 14,\n fontWeight: '600',\n },\n rowMeta: {\n fontSize: 12,\n },\n empty: {\n fontSize: 14,\n lineHeight: 20,\n paddingVertical: 20,\n textAlign: 'center',\n },\n headerRight: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n },\n gwDot: {\n width: 6,\n height: 6,\n borderRadius: 3,\n },\n newBtn: {\n width: 32,\n height: 32,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 10,\n },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HeaderTasksButton.js","sources":["../../../src/components/NavigationHeader/HeaderTasksButton.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from 'react';\nimport { ActivityIndicator, Linking, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { useFocusEffect, useNavigation, type NavigationProp, type ParamListBase } from '@react-navigation/native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { isJobRunning, jobDetailLine, jobStateLabel, slugLabel, type CentralJob } from 'common';\nimport { MAX_CONCURRENT_TASKS } from '../../config/constants';\nimport { useCdecliConnection } from '../../contexts/CdecliConnectionContext';\nimport { useGatewayContext } from '../../contexts/GatewayContext';\nimport { WEBBUILDER_JOB_SURFACE } from '../../features/webbuilder/buildJob';\nimport { useAgentSessionState } from '../../hooks/useAgentSessionState';\nimport { useSurfaceJobs } from '../../hooks/useSurfaceJobs';\nimport { agentSessionManager, type AgentTask, type TaskStatus } from '../../services/agentSessionManager';\nimport { mobileTokens } from '../../theme/mobileTokens';\nimport { HeaderSheet } from './HeaderSheet';\nimport { HeaderToolbarButton } from './HeaderToolbarButton';\n\ntype Props = {\n isDark: boolean;\n};\n\nconst STATUS_LABEL: Record<TaskStatus, string> = {\n idle: 'Idle',\n connecting: 'Connecting',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n aborted: 'Aborted',\n};\n\ntype IconName = React.ComponentProps<typeof MaterialCommunityIcons>['name'];\n\n/** The glyph and its light/dark tone for a finished status; anything else is a plain circle. */\nconst STATUS_GLYPH: Partial<Record<TaskStatus, { name: IconName; light: string; dark: string }>> = {\n completed: { name: 'check-circle-outline', light: '#16a34a', dark: '#4ade80' },\n failed: { name: 'alert-circle-outline', light: '#dc2626', dark: '#f87171' },\n aborted: { name: 'close-circle-outline', light: '#ea580c', dark: '#fb923c' },\n};\n\nfunction StatusGlyph({ status, isDark }: { status: TaskStatus; isDark: boolean }) {\n if (status === 'running' || status === 'connecting') {\n return <ActivityIndicator size={14} color={isDark ? '#60a5fa' : '#2563eb'} />;\n }\n const glyph = STATUS_GLYPH[status];\n if (!glyph) {\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n return <MaterialCommunityIcons name=\"circle-outline\" size={16} color={muted} />;\n }\n return <MaterialCommunityIcons name={glyph.name} size={16} color={isDark ? glyph.dark : glyph.light} />;\n}\n\n/** The last message, cut to a line. */\nfunction previewOf(task: AgentTask): string {\n const last = task.messages[task.messages.length - 1];\n if (!last) return 'No messages yet';\n return last.content.length > 60 ? `${last.content.slice(0, 60)}…` : last.content;\n}\n\nfunction TaskRow({\n task,\n isActive,\n isDark,\n onSelect,\n onRemove,\n}: {\n task: AgentTask;\n isActive: boolean;\n isDark: boolean;\n onSelect: () => void;\n onRemove: () => void;\n}) {\n const foreground = isDark ? '#e2e8f0' : mobileTokens.color.text;\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const preview = previewOf(task);\n const skillLabel = task.skillTemplateName || task.skillTemplate;\n\n return (\n <Pressable\n onPress={onSelect}\n style={({ pressed }) => [\n styles.row,\n isActive && styles.rowActive,\n isDark && isActive && styles.rowActiveDark,\n pressed && styles.pressed,\n ]}\n >\n <StatusGlyph status={task.status} isDark={isDark} />\n <View style={styles.rowBody}>\n <View style={styles.titleRow}>\n <Text style={[styles.rowTitle, { color: foreground }]} numberOfLines={1}>\n {task.title}\n </Text>\n {skillLabel ? (\n <View style={[styles.skillChip, isDark && styles.skillChipDark]}>\n <Text style={[styles.skillChipText, { color: muted }]} numberOfLines={1}>\n {skillLabel}\n </Text>\n </View>\n ) : null}\n </View>\n <Text style={[styles.rowMeta, { color: muted }]} numberOfLines={1}>\n {STATUS_LABEL[task.status]} · {preview}\n </Text>\n </View>\n <Pressable onPress={onRemove} hitSlop={8} accessibilityLabel=\"Remove task\">\n <MaterialCommunityIcons name=\"trash-can-outline\" size={16} color={muted} />\n </Pressable>\n </Pressable>\n );\n}\n\n/** A long-running job (a Web Builder build, a canvas video, ...) from the server's record. */\nfunction JobRow({\n job,\n now,\n isDark,\n onOpen,\n onDismiss,\n}: {\n job: CentralJob;\n now: number;\n isDark: boolean;\n onOpen: (() => void) | null;\n onDismiss: () => void;\n}) {\n const foreground = isDark ? '#e2e8f0' : mobileTokens.color.text;\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const stateLabel = jobStateLabel(job, now);\n const detail = jobDetailLine(job);\n\n return (\n <Pressable\n onPress={onOpen ?? undefined}\n disabled={!onOpen}\n accessibilityRole=\"button\"\n accessibilityLabel={`${job.title}, ${stateLabel}`}\n style={({ pressed }) => [styles.row, pressed && styles.pressed]}\n >\n {job.state === 'running' ? (\n <ActivityIndicator size={14} color={isDark ? '#60a5fa' : '#2563eb'} />\n ) : (\n <StatusGlyph status={job.state === 'succeeded' ? 'completed' : 'failed'} isDark={isDark} />\n )}\n <View style={styles.rowBody}>\n <View style={styles.titleRow}>\n <Text style={[styles.rowTitle, { color: foreground }]} numberOfLines={1}>\n {job.title}\n </Text>\n <View style={[styles.skillChip, isDark && styles.skillChipDark]}>\n <Text style={[styles.skillChipText, { color: muted }]} numberOfLines={1}>\n {slugLabel(job.slug)}\n </Text>\n </View>\n </View>\n <Text style={[styles.rowMeta, { color: muted }]} numberOfLines={2}>\n {detail ? `${stateLabel} · ${detail}` : stateLabel}\n </Text>\n </View>\n {job.state === 'running' ? null : (\n <Pressable onPress={onDismiss} hitSlop={8} accessibilityLabel=\"Remove task\">\n <MaterialCommunityIcons name=\"trash-can-outline\" size={16} color={muted} />\n </Pressable>\n )}\n </Pressable>\n );\n}\n\n/** The chat a Web Builder job built in, which its screen reopens. */\nfunction webBuilderChannel(job: CentralJob): string | null {\n const channelId = job.handle?.channelId;\n return job.slug === WEBBUILDER_JOB_SURFACE && typeof channelId === 'string' && channelId ? channelId : null;\n}\n\nfunction TasksSheet({\n isDark,\n onClose,\n jobs,\n runningJobs,\n onDismissJob,\n}: {\n isDark: boolean;\n onClose: () => void;\n jobs: CentralJob[];\n runningJobs: number;\n onDismissJob: (id: string) => void;\n}) {\n const session = useAgentSessionState();\n const navigation = useNavigation<NavigationProp<ParamListBase>>();\n // Running jobs show the time they have worked, so the clock ticks while one runs.\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (!jobs.some(isJobRunning)) return undefined;\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, [jobs]);\n const openJob = useCallback(\n (job: CentralJob): (() => void) | null => {\n const channelId = webBuilderChannel(job);\n if (channelId) {\n return () => {\n onClose();\n navigation.navigate('MainStack.WebBuilderNative', { openChannelId: channelId });\n };\n }\n const { pageUrl } = job;\n if (!pageUrl) return null;\n return () => {\n onClose();\n Linking.openURL(pageUrl).catch(() => undefined);\n };\n },\n [navigation, onClose],\n );\n const { selectedGateway } = useGatewayContext();\n const cdecli = useCdecliConnection();\n const muted = isDark ? '#94a3b8' : mobileTokens.color.textMuted;\n const cdecliSelected = selectedGateway?.channelType === 'cdecli-serve';\n const connected = cdecliSelected ? cdecli.channelConnected : session.gatewayConnected;\n const canCreate = session.tasks.length < MAX_CONCURRENT_TASKS && (cdecliSelected || session.gatewayConnected);\n\n const handleNew = useCallback(() => {\n if (!canCreate) return;\n agentSessionManager.createTask({ title: 'General Assistant' });\n }, [canCreate]);\n\n return (\n <HeaderSheet\n visible\n title=\"Tasks\"\n subtitle={\n jobs.length\n ? `${runningJobs} running · ${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots`\n : `${session.tasks.length} of ${MAX_CONCURRENT_TASKS} slots`\n }\n isDark={isDark}\n onClose={onClose}\n headerRight={\n <View style={styles.headerRight}>\n <View style={[styles.gwDot, { backgroundColor: connected ? '#22c55e' : '#94a3b8' }]} />\n <Pressable\n onPress={handleNew}\n disabled={!canCreate}\n accessibilityLabel=\"Start new task\"\n style={({ pressed }) => [\n styles.newBtn,\n pressed && styles.pressed,\n !canCreate && styles.disabled,\n ]}\n >\n <MaterialCommunityIcons name=\"plus\" size={16} color={mobileTokens.color.primary} />\n </Pressable>\n </View>\n }\n >\n <ScrollView style={{ flex: 1 }} contentContainerStyle={styles.list} keyboardShouldPersistTaps=\"handled\">\n {jobs.length > 0 ? (\n <>\n <Text style={[styles.sectionLabel, { color: muted }]}>Jobs</Text>\n {jobs.map((job) => (\n <JobRow\n key={job.id}\n job={job}\n now={now}\n isDark={isDark}\n onOpen={openJob(job)}\n onDismiss={() => onDismissJob(job.id)}\n />\n ))}\n {session.tasks.length > 0 ? (\n <Text style={[styles.sectionLabel, { color: muted }]}>Sessions</Text>\n ) : null}\n </>\n ) : null}\n {session.tasks.map((task) => (\n <TaskRow\n key={task.id}\n task={task}\n isActive={session.activeTaskId === task.id}\n isDark={isDark}\n onSelect={() => agentSessionManager.setActiveTask(task.id)}\n onRemove={() => agentSessionManager.removeTask(task.id)}\n />\n ))}\n {session.tasks.length === 0 && jobs.length === 0 ? (\n <Text style={[styles.empty, { color: muted }]}>\n {connected ? 'No tasks yet. Create one to get started.' : 'Connect Yantra to create tasks.'}\n </Text>\n ) : null}\n </ScrollView>\n </HeaderSheet>\n );\n}\n\nexport function HeaderTasksButton({ isDark }: Props) {\n const session = useAgentSessionState();\n const [open, setOpen] = useState(false);\n const surfaceJobs = useSurfaceJobs(open);\n const { refresh: refreshJobs } = surfaceJobs;\n // Opening the sheet reads the jobs again rather than showing the last poll.\n useEffect(() => {\n if (open) refreshJobs();\n }, [open, refreshJobs]);\n\n useFocusEffect(useCallback(() => () => setOpen(false), []));\n\n return (\n <>\n <HeaderToolbarButton\n icon=\"pulse\"\n label=\"Tasks\"\n badge={session.tasks.length + surfaceJobs.runningCount}\n active={open}\n onPress={() => setOpen(true)}\n accessibilityLabel=\"Tasks\"\n isDark={isDark}\n />\n {open ? (\n <TasksSheet\n isDark={isDark}\n onClose={() => setOpen(false)}\n jobs={surfaceJobs.jobs}\n runningJobs={surfaceJobs.runningCount}\n onDismissJob={surfaceJobs.dismiss}\n />\n ) : null}\n </>\n );\n}\n\nconst styles = StyleSheet.create({\n list: {\n paddingHorizontal: 16,\n paddingBottom: 12,\n gap: 8,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 10,\n borderRadius: 12,\n borderWidth: 1,\n borderColor: 'transparent',\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: mobileTokens.color.surfaceMuted,\n },\n rowActive: {\n borderColor: mobileTokens.color.primaryBorder,\n backgroundColor: mobileTokens.color.primarySoft,\n },\n rowActiveDark: {\n backgroundColor: 'rgba(79,70,229,0.18)',\n },\n pressed: {\n opacity: 0.7,\n },\n disabled: {\n opacity: 0.4,\n },\n titleRow: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n minWidth: 0,\n },\n skillChip: {\n maxWidth: 96,\n borderRadius: 6,\n paddingHorizontal: 6,\n paddingVertical: 2,\n backgroundColor: mobileTokens.color.surface,\n },\n skillChipDark: {\n backgroundColor: '#0f172a',\n },\n skillChipText: {\n fontSize: 10,\n fontWeight: '600',\n },\n rowBody: {\n flex: 1,\n minWidth: 0,\n gap: 2,\n },\n rowTitle: {\n flexShrink: 1,\n fontSize: 14,\n fontWeight: '600',\n },\n rowMeta: {\n fontSize: 12,\n },\n sectionLabel: {\n fontSize: 11,\n fontWeight: '700',\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n marginTop: 4,\n },\n empty: {\n fontSize: 14,\n lineHeight: 20,\n paddingVertical: 20,\n textAlign: 'center',\n },\n headerRight: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n },\n gwDot: {\n width: 6,\n height: 6,\n borderRadius: 3,\n },\n newBtn: {\n width: 32,\n height: 32,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 10,\n },\n});\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {jsxs,jsx,Fragment}from'react/jsx-runtime';import {useMemo,useState,useCallback,useRef,useEffect}from'react';import {StyleSheet,Keyboard,BackHandler,View,Text,Share,Platform,ActionSheetIOS,Alert,Linking}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {GestureHandlerRootView}from'react-native-gesture-handler';import {useSafeInsets}from'../canvas/withRemoteSafeArea.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {Tap,DIM}from'../inbox/components/Tap.js';import {isBareSeed,studioTurnText,brandBriefBlock,siteScoreTurn}from'./studioCatalog.js';import {useBrandKit}from'./brandKitStorage.js';import {parseToolActivity}from'../chat/toolActivity.js';import {wakePreviewPrompt}from'./webbuilderPrompts.js';import {webbuilderTheme}from'./webbuilderTheme.js';import {BrandKitSheet}from'./components/BrandKitSheet.js';import {CodeView}from'./components/CodeView.js';import {ProjectChat}from'./components/ProjectChat.js';import {PreviewScreen}from'./components/PreviewScreen.js';import {PublishSheet}from'./components/PublishSheet.js';import {BOTTOM_TABS_SPACE,BottomTabs}from'./components/BottomTabs.js';import {SiteScoreSheet}from'./components/SiteScoreSheet.js';import {ProjectsScreen}from'./components/ProjectsScreen.js';import {TemplatesSheet}from'./components/TemplatesSheet.js';import {StudioHome}from'./components/StudioHome.js';import {VersionsSheet}from'./components/VersionsSheet.js';import {IconButton,Toast}from'./components/ui.js';var __defProp = Object.defineProperty;
1
+ import {jsxs,jsx,Fragment}from'react/jsx-runtime';import {useMemo,useState,useCallback,useRef,useEffect}from'react';import {StyleSheet,Keyboard,BackHandler,View,Text,Share,Platform,ActionSheetIOS,Alert,Linking}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {GestureHandlerRootView}from'react-native-gesture-handler';import {useSafeInsets}from'../canvas/withRemoteSafeArea.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {Tap,DIM}from'../inbox/components/Tap.js';import {isBareSeed,studioTurnText,brandBriefBlock,siteScoreTurn}from'./studioCatalog.js';import {titleFromPrompt}from'./buildFragments.js';import {useBrandKit}from'./brandKitStorage.js';import {parseToolActivity}from'../chat/toolActivity.js';import {wakePreviewPrompt}from'./webbuilderPrompts.js';import {webbuilderTheme}from'./webbuilderTheme.js';import {BrandKitSheet}from'./components/BrandKitSheet.js';import {CodeView}from'./components/CodeView.js';import {ProjectChat}from'./components/ProjectChat.js';import {PreviewScreen}from'./components/PreviewScreen.js';import {PublishSheet}from'./components/PublishSheet.js';import {BOTTOM_TABS_SPACE,BottomTabs}from'./components/BottomTabs.js';import {SiteScoreSheet}from'./components/SiteScoreSheet.js';import {ProjectsScreen}from'./components/ProjectsScreen.js';import {TemplatesSheet}from'./components/TemplatesSheet.js';import {StudioHome}from'./components/StudioHome.js';import {VersionsSheet}from'./components/VersionsSheet.js';import {IconButton,Toast}from'./components/ui.js';var __defProp = Object.defineProperty;
2
2
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
3
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
4
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -44,7 +44,7 @@ function WebBuilderExperience({
44
44
  onResumePreview,
45
45
  initialAgentSeed = null
46
46
  }) {
47
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
47
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
48
48
  const appTheme = useAppTheme();
49
49
  const isDark = hostIsDark != null ? hostIsDark : appTheme.isDark;
50
50
  const theme = useMemo(() => webbuilderTheme(isDark), [isDark]);
@@ -103,7 +103,9 @@ function WebBuilderExperience({
103
103
  var _a2;
104
104
  return selectedKey ? (_a2 = builds.find((b) => b.key === selectedKey)) != null ? _a2 : latest : latest;
105
105
  }, [builds, selectedKey, latest]);
106
- const siteTitle = (project == null ? void 0 : project.title) || (build == null ? void 0 : build.title) || null;
106
+ const firstAsk = (_b = hostChat == null ? void 0 : hostChat.messages.find((m) => m.role === "user")) == null ? void 0 : _b.content;
107
+ const askTitle = useMemo(() => titleFromPrompt(firstAsk), [firstAsk]);
108
+ const siteTitle = (project == null ? void 0 : project.title) || (build == null ? void 0 : build.title) || askTitle || null;
107
109
  const [previewNonce, setPreviewNonce] = useState(0);
108
110
  const seenBuildAt = useRef({
109
111
  key: null,
@@ -207,7 +209,7 @@ function WebBuilderExperience({
207
209
  });
208
210
  return () => sub.remove();
209
211
  }, [back]);
210
- const live = (_c = (_b = build == null ? void 0 : build.liveUrl) != null ? _b : project == null ? void 0 : project.liveUrl) != null ? _c : null;
212
+ const live = (_d = (_c = build == null ? void 0 : build.liveUrl) != null ? _c : project == null ? void 0 : project.liveUrl) != null ? _d : null;
211
213
  let statusText = "New";
212
214
  let statusTone = theme.muted;
213
215
  if (building || (hostChat == null ? void 0 : hostChat.busy)) {
@@ -318,12 +320,12 @@ function WebBuilderExperience({
318
320
  ] })
319
321
  ] })
320
322
  ] }),
321
- mode === "chat" ? /* @__PURE__ */ jsx(ProjectChat, { messages: (_d = hostChat == null ? void 0 : hostChat.messages) != null ? _d : [], streaming: (_e = hostChat == null ? void 0 : hostChat.streaming) != null ? _e : null, busy: Boolean(hostChat == null ? void 0 : hostChat.busy), error: (_f = hostChat == null ? void 0 : hostChat.error) != null ? _f : null, connected: Boolean(hostChat == null ? void 0 : hostChat.connected), building, build, siteTitle: siteTitle || "Your site", onSend: (text) => sendToAgent(text), onOpenPreview: () => setMode("preview"), onPublish: () => setPublishOpen(true), onPreviewAsleep: wakePreview, theme, bottomInset: insets.bottom }) : null,
322
- mode === "preview" ? /* @__PURE__ */ jsx(PreviewScreen, { build, building, loading: buildsLoading, previewNonce, onReload: () => setPreviewNonce((n) => n + 1), onHome: () => setPreviewNonce((n) => n + 1), onWake: wakePreview, waking: waking || Boolean(hostChat == null ? void 0 : hostChat.busy), steps: liveSteps, onPublish: () => setPublishOpen(true), publishLabel, error: (_g = hostChat == null ? void 0 : hostChat.error) != null ? _g : null, theme, bottomInset: insets.bottom }) : null,
323
+ mode === "chat" ? /* @__PURE__ */ jsx(ProjectChat, { messages: (_e = hostChat == null ? void 0 : hostChat.messages) != null ? _e : [], streaming: (_f = hostChat == null ? void 0 : hostChat.streaming) != null ? _f : null, busy: Boolean(hostChat == null ? void 0 : hostChat.busy), error: (_g = hostChat == null ? void 0 : hostChat.error) != null ? _g : null, connected: Boolean(hostChat == null ? void 0 : hostChat.connected), building, build, siteTitle: siteTitle || "Your site", onSend: (text) => sendToAgent(text), onOpenPreview: () => setMode("preview"), onPublish: () => setPublishOpen(true), onPreviewAsleep: wakePreview, theme, bottomInset: insets.bottom }) : null,
324
+ mode === "preview" ? /* @__PURE__ */ jsx(PreviewScreen, { build, building, loading: buildsLoading, previewNonce, onReload: () => setPreviewNonce((n) => n + 1), onHome: () => setPreviewNonce((n) => n + 1), onWake: wakePreview, waking: waking || Boolean(hostChat == null ? void 0 : hostChat.busy), steps: liveSteps, onPublish: () => setPublishOpen(true), publishLabel, error: (_h = hostChat == null ? void 0 : hostChat.error) != null ? _h : null, theme, bottomInset: insets.bottom }) : null,
323
325
  mode === "code" ? /* @__PURE__ */ jsx(View, { style: [styles.fill, {
324
326
  backgroundColor: theme.card,
325
327
  paddingBottom: insets.bottom
326
- }], children: /* @__PURE__ */ jsx(CodeView, { files: (_h = build == null ? void 0 : build.files) != null ? _h : null, theme, onAsk: openChat }) }) : null
328
+ }], children: /* @__PURE__ */ jsx(CodeView, { files: (_i = build == null ? void 0 : build.files) != null ? _i : null, theme, onAsk: openChat }) }) : null
327
329
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
328
330
  homeTab === "create" ? /* @__PURE__ */ jsx(View, { style: [styles.header, styles.headerBare, {
329
331
  paddingTop: insets.top + 4,
@@ -332,7 +334,7 @@ function WebBuilderExperience({
332
334
  /* @__PURE__ */ jsx(View, { style: styles.fill, children: homeTab === "create" ? /* @__PURE__ */ jsx(StudioHome, { draft, onDraft: setDraft, template, onClearTemplate: () => setTemplate(null), onBrowseTemplates: () => setTemplatesOpen(true), brand, onBrand: () => setBrandOpen(true), onSiteScore: () => setScoreOpen(true), onStart: startSite, connecting: startBlocked, startNotice, theme, bottomInset: BOTTOM_TABS_SPACE + insets.bottom }) : /* @__PURE__ */ jsx(ProjectsScreen, { projects, loading: projectsLoading, error: projectsError, hasMore: projectsHasMore, onRefresh: onRefreshProjects, onLoadMore: onLoadMoreProjects, onOpen: (p) => onOpenProject(p.channelId), onNewProject: () => setHomeTab("create"), topInset: insets.top + 12, bottomInset: BOTTOM_TABS_SPACE + insets.bottom, theme }) }),
333
335
  /* @__PURE__ */ jsx(BottomTabs, { tab: homeTab, onTab: setHomeTab, theme, bottomInset: insets.bottom })
334
336
  ] }),
335
- /* @__PURE__ */ jsx(TemplatesSheet, { visible: templatesOpen, onClose: () => setTemplatesOpen(false), templates, loading: templatesLoading, error: templatesError, onReload: onReloadTemplates, selectedId: (_i = template == null ? void 0 : template.id) != null ? _i : null, onPick: pickTemplate, theme }),
337
+ /* @__PURE__ */ jsx(TemplatesSheet, { visible: templatesOpen, onClose: () => setTemplatesOpen(false), templates, loading: templatesLoading, error: templatesError, onReload: onReloadTemplates, selectedId: (_j = template == null ? void 0 : template.id) != null ? _j : null, onPick: pickTemplate, theme }),
336
338
  /* @__PURE__ */ jsx(SiteScoreSheet, { visible: scoreOpen, onClose: () => setScoreOpen(false), blocked: startBlocked, onCheck: (url) => {
337
339
  setScoreOpen(false);
338
340
  onStartProject({