bazilion 0.0.0 → 0.1.0

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.
Files changed (265) hide show
  1. package/README.md +53 -152
  2. package/dist/cli.js +2730 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/daemon.js +5888 -0
  5. package/dist/daemon.js.map +1 -0
  6. package/dist/worker.js +1830 -0
  7. package/dist/worker.js.map +1 -0
  8. package/package.json +57 -28
  9. package/.understand-anything/.understandignore +0 -25
  10. package/.understand-anything/fingerprints.json +0 -14267
  11. package/.understand-anything/knowledge-graph.json +0 -18128
  12. package/.understand-anything/meta.json +0 -6
  13. package/CLAUDE.md +0 -164
  14. package/apps/cli/package.json +0 -21
  15. package/apps/cli/src/auth-file.ts +0 -18
  16. package/apps/cli/src/client.ts +0 -37
  17. package/apps/cli/src/columnize.ts +0 -32
  18. package/apps/cli/src/commands/agent.ts +0 -574
  19. package/apps/cli/src/commands/auth.ts +0 -110
  20. package/apps/cli/src/commands/backup.ts +0 -135
  21. package/apps/cli/src/commands/completion.ts +0 -155
  22. package/apps/cli/src/commands/config.ts +0 -95
  23. package/apps/cli/src/commands/doctor.ts +0 -131
  24. package/apps/cli/src/commands/group.ts +0 -132
  25. package/apps/cli/src/commands/inbox.ts +0 -82
  26. package/apps/cli/src/commands/login.ts +0 -73
  27. package/apps/cli/src/commands/memory.ts +0 -106
  28. package/apps/cli/src/commands/profile.ts +0 -259
  29. package/apps/cli/src/commands/provider.ts +0 -170
  30. package/apps/cli/src/commands/send.ts +0 -24
  31. package/apps/cli/src/commands/serve.ts +0 -89
  32. package/apps/cli/src/commands/skill.ts +0 -120
  33. package/apps/cli/src/commands/token.ts +0 -148
  34. package/apps/cli/src/commands/trigger.ts +0 -129
  35. package/apps/cli/src/commands/uninstall.ts +0 -156
  36. package/apps/cli/src/index.ts +0 -196
  37. package/apps/cli/src/paths.ts +0 -12
  38. package/apps/cli/test/agent.test.ts +0 -213
  39. package/apps/cli/test/backup.test.ts +0 -95
  40. package/apps/cli/test/chat.test.ts +0 -539
  41. package/apps/cli/test/columnize.test.ts +0 -29
  42. package/apps/cli/test/completion.test.ts +0 -45
  43. package/apps/cli/test/config-page.test.ts +0 -151
  44. package/apps/cli/test/group.test.ts +0 -74
  45. package/apps/cli/test/helpers.ts +0 -70
  46. package/apps/cli/test/inbox-autodeliver.test.ts +0 -143
  47. package/apps/cli/test/inbox.test.ts +0 -147
  48. package/apps/cli/test/memory.test.ts +0 -69
  49. package/apps/cli/test/profile.test.ts +0 -110
  50. package/apps/cli/test/send.test.ts +0 -30
  51. package/apps/cli/test/server-fixture.ts +0 -212
  52. package/apps/cli/test/session-head.test.ts +0 -45
  53. package/apps/cli/test/skill.test.ts +0 -128
  54. package/apps/cli/test/token.test.ts +0 -109
  55. package/apps/cli/test/trigger.test.ts +0 -245
  56. package/apps/cli/tsconfig.json +0 -4
  57. package/apps/daemon/package.json +0 -31
  58. package/apps/daemon/src/app.ts +0 -41
  59. package/apps/daemon/src/core/agent/archive.ts +0 -8
  60. package/apps/daemon/src/core/agent/delete.ts +0 -30
  61. package/apps/daemon/src/core/agent/resolve.ts +0 -31
  62. package/apps/daemon/src/core/agent/spawn.ts +0 -95
  63. package/apps/daemon/src/core/agent/unarchive.ts +0 -11
  64. package/apps/daemon/src/core/availableModels.ts +0 -58
  65. package/apps/daemon/src/core/db/client.ts +0 -113
  66. package/apps/daemon/src/core/db/migrate.ts +0 -41
  67. package/apps/daemon/src/core/db/migrations/0001_init.sql +0 -179
  68. package/apps/daemon/src/core/group/delete.ts +0 -21
  69. package/apps/daemon/src/core/group/register.ts +0 -68
  70. package/apps/daemon/src/core/index.ts +0 -71
  71. package/apps/daemon/src/core/paths.ts +0 -56
  72. package/apps/daemon/src/core/profile/create.ts +0 -78
  73. package/apps/daemon/src/core/profile/delete.ts +0 -26
  74. package/apps/daemon/src/core/profile/identity.ts +0 -70
  75. package/apps/daemon/src/core/profile/load.ts +0 -45
  76. package/apps/daemon/src/core/profile/seed.ts +0 -74
  77. package/apps/daemon/src/core/profile/templates.ts +0 -60
  78. package/apps/daemon/src/core/profile/update.ts +0 -57
  79. package/apps/daemon/src/core/profile/validate.ts +0 -9
  80. package/apps/daemon/src/core/repos/agents.ts +0 -202
  81. package/apps/daemon/src/core/repos/config.ts +0 -78
  82. package/apps/daemon/src/core/repos/groups.ts +0 -55
  83. package/apps/daemon/src/core/repos/messages.ts +0 -127
  84. package/apps/daemon/src/core/repos/profiles.ts +0 -83
  85. package/apps/daemon/src/core/repos/providerModels.ts +0 -58
  86. package/apps/daemon/src/core/repos/providerState.ts +0 -37
  87. package/apps/daemon/src/core/repos/secrets.ts +0 -145
  88. package/apps/daemon/src/core/repos/skillMeta.ts +0 -49
  89. package/apps/daemon/src/core/repos/triggers.ts +0 -101
  90. package/apps/daemon/src/core/repos/webTokens.ts +0 -87
  91. package/apps/daemon/src/core/secrets.ts +0 -65
  92. package/apps/daemon/src/core/services.ts +0 -264
  93. package/apps/daemon/src/core/skills/discover.ts +0 -28
  94. package/apps/daemon/src/core/skills/import.ts +0 -136
  95. package/apps/daemon/src/core/skills/parse.ts +0 -52
  96. package/apps/daemon/src/core/skills/resolve.ts +0 -50
  97. package/apps/daemon/src/index.ts +0 -45
  98. package/apps/daemon/src/lib/agent-cancel.ts +0 -48
  99. package/apps/daemon/src/lib/agent-id.ts +0 -13
  100. package/apps/daemon/src/lib/agent-turn.ts +0 -56
  101. package/apps/daemon/src/lib/api-key.ts +0 -56
  102. package/apps/daemon/src/lib/auth.ts +0 -41
  103. package/apps/daemon/src/lib/cron.ts +0 -93
  104. package/apps/daemon/src/lib/ctx.ts +0 -80
  105. package/apps/daemon/src/lib/messaging-host.ts +0 -34
  106. package/apps/daemon/src/lib/middleware-auth.ts +0 -52
  107. package/apps/daemon/src/lib/scheduler.ts +0 -294
  108. package/apps/daemon/src/routes/agents.ts +0 -772
  109. package/apps/daemon/src/routes/auth-login.ts +0 -193
  110. package/apps/daemon/src/routes/config.ts +0 -267
  111. package/apps/daemon/src/routes/groups.ts +0 -133
  112. package/apps/daemon/src/routes/messages.ts +0 -29
  113. package/apps/daemon/src/routes/misc.ts +0 -239
  114. package/apps/daemon/src/routes/profiles.ts +0 -197
  115. package/apps/daemon/src/routes/skills.ts +0 -123
  116. package/apps/daemon/src/routes/triggers.ts +0 -29
  117. package/apps/daemon/src/runtime/auth/openai-codex.ts +0 -121
  118. package/apps/daemon/src/runtime/auto-reply/heartbeat.ts +0 -31
  119. package/apps/daemon/src/runtime/index.ts +0 -77
  120. package/apps/daemon/src/runtime/memory/files.ts +0 -103
  121. package/apps/daemon/src/runtime/memory/qmd.ts +0 -152
  122. package/apps/daemon/src/runtime/memory/types.ts +0 -16
  123. package/apps/daemon/src/runtime/pi/events.ts +0 -173
  124. package/apps/daemon/src/runtime/pi/session.ts +0 -536
  125. package/apps/daemon/src/runtime/pi/tools.ts +0 -85
  126. package/apps/daemon/src/runtime/providers/catalog.ts +0 -145
  127. package/apps/daemon/src/runtime/providers/pi-adapter.ts +0 -272
  128. package/apps/daemon/src/runtime/providers/registry.ts +0 -374
  129. package/apps/daemon/src/runtime/providers/retry.ts +0 -176
  130. package/apps/daemon/src/runtime/providers/types.ts +0 -33
  131. package/apps/daemon/src/runtime/session/prompt.ts +0 -83
  132. package/apps/daemon/src/runtime/tools/bootstrap.ts +0 -22
  133. package/apps/daemon/src/runtime/tools/home.ts +0 -114
  134. package/apps/daemon/src/runtime/tools/memory.ts +0 -81
  135. package/apps/daemon/src/runtime/tools/messaging.ts +0 -127
  136. package/apps/daemon/src/runtime/tools/registry.ts +0 -29
  137. package/apps/daemon/src/runtime/tools/types.ts +0 -13
  138. package/apps/daemon/src/runtime/tools/web-extract.ts +0 -110
  139. package/apps/daemon/src/runtime/tools/web-ssrf.ts +0 -245
  140. package/apps/daemon/src/runtime/tools/web.ts +0 -273
  141. package/apps/daemon/src/runtime/worker/entry.ts +0 -221
  142. package/apps/daemon/src/runtime/worker/ipc-protocol.ts +0 -75
  143. package/apps/daemon/src/runtime/worker/spawn.ts +0 -249
  144. package/apps/daemon/test/core/agents.test.ts +0 -319
  145. package/apps/daemon/test/core/available-models.test.ts +0 -63
  146. package/apps/daemon/test/core/config.test.ts +0 -99
  147. package/apps/daemon/test/core/groups.test.ts +0 -63
  148. package/apps/daemon/test/core/helpers.ts +0 -50
  149. package/apps/daemon/test/core/identity.test.ts +0 -85
  150. package/apps/daemon/test/core/migrations.test.ts +0 -83
  151. package/apps/daemon/test/core/profiles.test.ts +0 -182
  152. package/apps/daemon/test/core/provider-models.test.ts +0 -57
  153. package/apps/daemon/test/core/provider-state.test.ts +0 -36
  154. package/apps/daemon/test/core/skill-meta.test.ts +0 -45
  155. package/apps/daemon/test/core/skills.test.ts +0 -271
  156. package/apps/daemon/test/core/triggers.test.ts +0 -182
  157. package/apps/daemon/test/core/web-tokens.test.ts +0 -79
  158. package/apps/daemon/test/cron.test.ts +0 -90
  159. package/apps/daemon/test/runtime/heartbeat.test.ts +0 -34
  160. package/apps/daemon/test/runtime/memory-qmd.test.ts +0 -97
  161. package/apps/daemon/test/runtime/memory.test.ts +0 -78
  162. package/apps/daemon/test/runtime/messaging.test.ts +0 -213
  163. package/apps/daemon/test/runtime/mock-server.ts +0 -65
  164. package/apps/daemon/test/runtime/openai-codex-auth.test.ts +0 -116
  165. package/apps/daemon/test/runtime/providers.test.ts +0 -306
  166. package/apps/daemon/test/runtime/retry.test.ts +0 -191
  167. package/apps/daemon/test/runtime/session-head.test.ts +0 -90
  168. package/apps/daemon/test/runtime/tools-home.test.ts +0 -102
  169. package/apps/daemon/test/runtime/tools-web.test.ts +0 -206
  170. package/apps/daemon/tsconfig.json +0 -4
  171. package/apps/mobile/README.md +0 -60
  172. package/apps/mobile/app/_layout.tsx +0 -58
  173. package/apps/mobile/app/agents/[id]/chat.tsx +0 -486
  174. package/apps/mobile/app/agents/[id]/index.tsx +0 -166
  175. package/apps/mobile/app/agents/index.tsx +0 -212
  176. package/apps/mobile/app/index.tsx +0 -21
  177. package/apps/mobile/app/pair.tsx +0 -226
  178. package/apps/mobile/app/settings.tsx +0 -419
  179. package/apps/mobile/app.json +0 -49
  180. package/apps/mobile/assets/adaptive-icon.png +0 -0
  181. package/apps/mobile/assets/favicon.png +0 -0
  182. package/apps/mobile/assets/icon.png +0 -0
  183. package/apps/mobile/assets/splash-icon.png +0 -0
  184. package/apps/mobile/babel.config.js +0 -6
  185. package/apps/mobile/metro.config.js +0 -28
  186. package/apps/mobile/package.json +0 -44
  187. package/apps/mobile/src/auth.ts +0 -66
  188. package/apps/mobile/src/pair-url.ts +0 -48
  189. package/apps/mobile/src/theme-context.tsx +0 -88
  190. package/apps/mobile/src/theme.ts +0 -135
  191. package/apps/mobile/test/pair-url.test.ts +0 -46
  192. package/apps/mobile/tsconfig.json +0 -23
  193. package/apps/web/components.json +0 -25
  194. package/apps/web/package.json +0 -39
  195. package/apps/web/public/baziu.svg +0 -8
  196. package/apps/web/src/components/AgentTabs.tsx +0 -45
  197. package/apps/web/src/components/BaziuLogo.tsx +0 -21
  198. package/apps/web/src/components/ChatPane.tsx +0 -1033
  199. package/apps/web/src/components/ConfigTabs.tsx +0 -29
  200. package/apps/web/src/components/CopyButton.tsx +0 -68
  201. package/apps/web/src/components/CreateGroupDialog.tsx +0 -127
  202. package/apps/web/src/components/FieldRow.tsx +0 -94
  203. package/apps/web/src/components/Footer.tsx +0 -10
  204. package/apps/web/src/components/PawIcon.tsx +0 -15
  205. package/apps/web/src/components/Sidebar.tsx +0 -287
  206. package/apps/web/src/components/SpawnDialog.tsx +0 -129
  207. package/apps/web/src/components/ThemeToggle.tsx +0 -75
  208. package/apps/web/src/components/TopNav.tsx +0 -34
  209. package/apps/web/src/components/ui/button.tsx +0 -67
  210. package/apps/web/src/components/ui/card.tsx +0 -103
  211. package/apps/web/src/components/ui/checkbox.tsx +0 -31
  212. package/apps/web/src/components/ui/dialog.tsx +0 -168
  213. package/apps/web/src/components/ui/input.tsx +0 -19
  214. package/apps/web/src/components/ui/label.tsx +0 -22
  215. package/apps/web/src/components/ui/radio-group.tsx +0 -44
  216. package/apps/web/src/components/ui/select.tsx +0 -192
  217. package/apps/web/src/components/ui/separator.tsx +0 -26
  218. package/apps/web/src/components/ui/table.tsx +0 -116
  219. package/apps/web/src/components/ui/tabs.tsx +0 -88
  220. package/apps/web/src/components/ui/textarea.tsx +0 -18
  221. package/apps/web/src/lib/auth.ts +0 -50
  222. package/apps/web/src/lib/daemon-client.ts +0 -34
  223. package/apps/web/src/lib/md.ts +0 -45
  224. package/apps/web/src/lib/utils.ts +0 -6
  225. package/apps/web/src/lib/wire-constants.ts +0 -27
  226. package/apps/web/src/routeTree.gen.ts +0 -408
  227. package/apps/web/src/router.tsx +0 -20
  228. package/apps/web/src/routes/__root.tsx +0 -123
  229. package/apps/web/src/routes/agents/$id/inbox.tsx +0 -207
  230. package/apps/web/src/routes/agents/$id/index.tsx +0 -527
  231. package/apps/web/src/routes/agents/$id/triggers.tsx +0 -239
  232. package/apps/web/src/routes/agents/index.tsx +0 -265
  233. package/apps/web/src/routes/api/$.ts +0 -88
  234. package/apps/web/src/routes/config/index.tsx +0 -315
  235. package/apps/web/src/routes/config/services.tsx +0 -49
  236. package/apps/web/src/routes/config/tokens.tsx +0 -192
  237. package/apps/web/src/routes/groups/$id/index.tsx +0 -153
  238. package/apps/web/src/routes/groups/$id/memory.tsx +0 -321
  239. package/apps/web/src/routes/groups/index.tsx +0 -191
  240. package/apps/web/src/routes/index.tsx +0 -133
  241. package/apps/web/src/routes/login.tsx +0 -63
  242. package/apps/web/src/routes/profiles/$id.tsx +0 -549
  243. package/apps/web/src/routes/profiles/index.tsx +0 -458
  244. package/apps/web/src/routes/skills/index.tsx +0 -297
  245. package/apps/web/src/routes/welcome.tsx +0 -61
  246. package/apps/web/src/styles.css +0 -449
  247. package/apps/web/tsconfig.json +0 -25
  248. package/apps/web/vite.config.ts +0 -25
  249. package/biome.json +0 -23
  250. package/docs/agent-engine.md +0 -219
  251. package/docs/architecture.md +0 -627
  252. package/docs/backlog/README.md +0 -42
  253. package/docs/backlog/draft/BAZ-001-a2a-federation-spike.md +0 -125
  254. package/docs/openclaw-reference.md +0 -210
  255. package/packages/api-types/package.json +0 -11
  256. package/packages/api-types/src/entities.ts +0 -146
  257. package/packages/api-types/src/events.ts +0 -55
  258. package/packages/api-types/src/index.ts +0 -488
  259. package/packages/api-types/src/memory.ts +0 -15
  260. package/packages/client/package.json +0 -13
  261. package/packages/client/src/index.ts +0 -117
  262. package/pnpm-workspace.yaml +0 -3
  263. package/tsconfig.base.json +0 -23
  264. package/tsconfig.json +0 -11
  265. package/vitest.config.ts +0 -22
@@ -1,166 +0,0 @@
1
- import type { ResolvedAgent } from '@bazilion/api-types'
2
- import { ApiClientError } from '@bazilion/client'
3
- import { router, useLocalSearchParams } from 'expo-router'
4
- import { useCallback, useEffect, useMemo, useState } from 'react'
5
- import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native'
6
- import { clearCredentials, clientFor, loadCredentials } from '@/src/auth'
7
- import { useColors } from '@/src/theme-context'
8
- import { type Colors, fonts, radii } from '@/src/theme'
9
-
10
- type Load =
11
- | { kind: 'loading' }
12
- | { kind: 'ready'; agent: ResolvedAgent }
13
- | { kind: 'error'; message: string }
14
-
15
- export default function AgentDetail() {
16
- const { id } = useLocalSearchParams<{ id: string }>()
17
- const [load, setLoad] = useState<Load>({ kind: 'loading' })
18
- const colors = useColors()
19
- const styles = useMemo(() => makeStyles(colors), [colors])
20
-
21
- const fetchAgent = useCallback(async () => {
22
- setLoad({ kind: 'loading' })
23
- const creds = await loadCredentials()
24
- if (!creds) {
25
- router.replace('/pair')
26
- return
27
- }
28
- try {
29
- const agent = await clientFor(creds).get<ResolvedAgent>(`/api/agents/${id}`)
30
- setLoad({ kind: 'ready', agent })
31
- } catch (err) {
32
- if (err instanceof ApiClientError && err.status === 401) {
33
- await clearCredentials()
34
- router.replace('/pair')
35
- return
36
- }
37
- const message = err instanceof Error ? err.message : 'unknown error'
38
- setLoad({ kind: 'error', message })
39
- }
40
- }, [id])
41
-
42
- useEffect(() => {
43
- fetchAgent()
44
- }, [fetchAgent])
45
-
46
- if (load.kind === 'loading') {
47
- return (
48
- <View style={styles.centered}>
49
- <ActivityIndicator />
50
- </View>
51
- )
52
- }
53
-
54
- if (load.kind === 'error') {
55
- return (
56
- <View style={styles.centered}>
57
- <Text style={styles.errorTitle}>Couldn't load agent</Text>
58
- <Text style={styles.errorBody}>{load.message}</Text>
59
- <Pressable style={styles.primaryBtn} onPress={fetchAgent}>
60
- <Text style={styles.primaryBtnText}>Retry</Text>
61
- </Pressable>
62
- </View>
63
- )
64
- }
65
-
66
- const a = load.agent
67
- return (
68
- <ScrollView style={styles.screen} contentContainerStyle={styles.content}>
69
- <Text style={styles.name}>{a.agent.name}</Text>
70
- <Text style={styles.subtitle}>{a.agent.id}</Text>
71
-
72
- <Section label="status">
73
- <Text style={styles.mono}>{a.agent.status}</Text>
74
- </Section>
75
-
76
- <Section label="model">
77
- <Text style={styles.mono}>{a.model}</Text>
78
- </Section>
79
-
80
- <Section label="profile">
81
- <Text style={styles.mono}>{a.agent.profileId}</Text>
82
- </Section>
83
-
84
- <Section label="reasoning">
85
- <Text style={styles.mono}>{a.reasoningLevel}</Text>
86
- </Section>
87
-
88
- <Section label="group">
89
- <Text style={styles.mono}>{a.group.name}</Text>
90
- <Text style={styles.dim}>{a.group.path}</Text>
91
- </Section>
92
-
93
- <Section label={`skills (${a.skills.length})`}>
94
- {a.skills.length === 0 ? (
95
- <Text style={styles.dim}>(none attached)</Text>
96
- ) : (
97
- a.skills.map((name) => (
98
- <Text key={name} style={styles.mono}>
99
- {name}
100
- </Text>
101
- ))
102
- )}
103
- </Section>
104
-
105
- <Pressable
106
- style={({ pressed }) => [styles.primaryBtn, pressed && styles.primaryBtnPressed]}
107
- onPress={() => router.push(`/agents/${a.agent.id}/chat`)}
108
- >
109
- <Text style={styles.primaryBtnText}>Open chat</Text>
110
- </Pressable>
111
- </ScrollView>
112
- )
113
- }
114
-
115
- function Section({ label, children }: { label: string; children: React.ReactNode }) {
116
- const colors = useColors()
117
- const styles = useMemo(() => makeStyles(colors), [colors])
118
- return (
119
- <View style={styles.section}>
120
- <Text style={styles.sectionLabel}>{label}</Text>
121
- <View style={styles.sectionBody}>{children}</View>
122
- </View>
123
- )
124
- }
125
-
126
- const makeStyles = (colors: Colors) =>
127
- StyleSheet.create({
128
- screen: { flex: 1, backgroundColor: colors.background },
129
- content: { padding: 20, gap: 8 },
130
- centered: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24, gap: 12 },
131
- name: { fontSize: 26, fontFamily: fonts.display, color: colors.foreground },
132
- subtitle: { fontFamily: fonts.mono, fontSize: 12, color: colors.mochaLight, marginBottom: 8 },
133
- section: { marginTop: 12 },
134
- sectionLabel: {
135
- fontSize: 11,
136
- color: colors.mocha,
137
- textTransform: 'uppercase',
138
- letterSpacing: 0.5,
139
- marginBottom: 4,
140
- fontFamily: fonts.bodyMedium,
141
- },
142
- sectionBody: { gap: 2 },
143
- mono: { fontFamily: fonts.mono, fontSize: 13, color: colors.charcoal },
144
- dim: { color: colors.mochaLight, fontSize: 13, fontFamily: fonts.body },
145
- placeholder: {
146
- marginTop: 32,
147
- padding: 16,
148
- borderRadius: radii.md,
149
- backgroundColor: colors.ivory,
150
- gap: 6,
151
- },
152
- placeholderTitle: { fontSize: 14, fontFamily: fonts.bodyMedium, color: colors.mocha },
153
- placeholderBody: { fontSize: 12, color: colors.mochaLight, lineHeight: 18, fontFamily: fonts.body },
154
- errorTitle: { fontSize: 18, fontFamily: fonts.bodyBold, color: colors.foreground },
155
- errorBody: { color: colors.destructive, textAlign: 'center', fontFamily: fonts.body },
156
- primaryBtn: {
157
- marginTop: 24,
158
- paddingHorizontal: 20,
159
- paddingVertical: 12,
160
- borderRadius: radii.md,
161
- backgroundColor: colors.sapphire,
162
- alignItems: 'center',
163
- },
164
- primaryBtnPressed: { backgroundColor: colors.sapphireDeep },
165
- primaryBtnText: { color: colors.primaryForeground, fontSize: 15, fontFamily: fonts.bodyMedium },
166
- })
@@ -1,212 +0,0 @@
1
- import type { Agent } from '@bazilion/api-types'
2
- import { ApiClientError } from '@bazilion/client'
3
- import { router, useFocusEffect } from 'expo-router'
4
- import { useCallback, useMemo, useRef, useState } from 'react'
5
- import {
6
- ActivityIndicator,
7
- FlatList,
8
- Pressable,
9
- RefreshControl,
10
- StyleSheet,
11
- Text,
12
- View,
13
- } from 'react-native'
14
- import {
15
- clearCredentials,
16
- clientFor,
17
- type Credentials,
18
- loadCredentials,
19
- } from '@/src/auth'
20
- import { useColors } from '@/src/theme-context'
21
- import { type Colors, fonts, radii } from '@/src/theme'
22
-
23
- type Load =
24
- | { kind: 'loading' }
25
- | { kind: 'ready'; agents: Agent[]; creds: Credentials }
26
- | { kind: 'error'; message: string }
27
-
28
- export default function AgentsList() {
29
- const [load, setLoad] = useState<Load>({ kind: 'loading' })
30
- const [refreshing, setRefreshing] = useState(false)
31
- // Skip the loading-spinner on re-focus (navigating back from chat /
32
- // settings) — show the stale list while the background refetch runs so
33
- // the screen doesn't flash empty every time.
34
- const hasLoaded = useRef(false)
35
- const colors = useColors()
36
- const styles = useMemo(() => makeStyles(colors), [colors])
37
-
38
- const fetchAgents = useCallback(async (initial: boolean) => {
39
- if (initial) setLoad({ kind: 'loading' })
40
- const creds = await loadCredentials()
41
- if (!creds) {
42
- router.replace('/pair')
43
- return
44
- }
45
- try {
46
- const agents = await clientFor(creds).get<Agent[]>('/api/agents')
47
- setLoad({ kind: 'ready', agents, creds })
48
- } catch (err) {
49
- if (err instanceof ApiClientError && err.status === 401) {
50
- // Token was revoked or the daemon's auth was rotated. Force re-pair.
51
- await clearCredentials()
52
- router.replace('/pair')
53
- return
54
- }
55
- const message = err instanceof Error ? err.message : 'unknown error'
56
- setLoad({ kind: 'error', message })
57
- }
58
- }, [])
59
-
60
- useFocusEffect(
61
- useCallback(() => {
62
- fetchAgents(!hasLoaded.current)
63
- hasLoaded.current = true
64
- }, [fetchAgents]),
65
- )
66
-
67
- const onRefresh = useCallback(async () => {
68
- setRefreshing(true)
69
- try {
70
- await fetchAgents(false)
71
- } finally {
72
- setRefreshing(false)
73
- }
74
- }, [fetchAgents])
75
-
76
- const onUnpair = useCallback(async () => {
77
- await clearCredentials()
78
- router.replace('/pair')
79
- }, [])
80
-
81
- if (load.kind === 'loading') {
82
- return (
83
- <View style={styles.centered}>
84
- <ActivityIndicator />
85
- </View>
86
- )
87
- }
88
-
89
- if (load.kind === 'error') {
90
- return (
91
- <View style={styles.centered}>
92
- <Text style={styles.errorTitle}>Couldn't load agents</Text>
93
- <Text style={styles.errorBody}>{load.message}</Text>
94
- <Pressable style={styles.primaryBtn} onPress={() => fetchAgents(true)}>
95
- <Text style={styles.primaryBtnText}>Retry</Text>
96
- </Pressable>
97
- <Pressable style={styles.linkBtn} onPress={onUnpair}>
98
- <Text style={styles.linkBtnText}>Unpair</Text>
99
- </Pressable>
100
- </View>
101
- )
102
- }
103
-
104
- return (
105
- <View style={styles.screen}>
106
- <View style={styles.header}>
107
- <Text style={styles.headerServer}>{load.creds.server}</Text>
108
- <Pressable onPress={() => router.push('/settings')} hitSlop={10}>
109
- <Text style={styles.headerSettings}>Settings</Text>
110
- </Pressable>
111
- </View>
112
- <FlatList
113
- data={load.agents}
114
- keyExtractor={(a) => a.id}
115
- refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
116
- ListEmptyComponent={
117
- <View style={styles.empty}>
118
- <Text style={styles.emptyTitle}>No agents yet</Text>
119
- <Text style={styles.emptyBody}>
120
- Spawn one from the web UI or `bazilion agent spawn` on the server.
121
- </Text>
122
- </View>
123
- }
124
- renderItem={({ item }) => <AgentRow agent={item} />}
125
- ItemSeparatorComponent={() => <View style={styles.separator} />}
126
- />
127
- </View>
128
- )
129
- }
130
-
131
- function AgentRow({ agent }: { agent: Agent }) {
132
- const colors = useColors()
133
- const styles = useMemo(() => makeStyles(colors), [colors])
134
- return (
135
- <Pressable
136
- style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
137
- onPress={() => router.push(`/agents/${agent.id}/chat`)}
138
- onLongPress={() => router.push(`/agents/${agent.id}`)}
139
- >
140
- <View style={styles.rowMain}>
141
- <Text style={styles.rowName} numberOfLines={1}>
142
- {agent.name}
143
- </Text>
144
- <Text style={styles.rowModel} numberOfLines={1}>
145
- {agent.modelOverride ?? '(profile default)'}
146
- </Text>
147
- </View>
148
- <View style={[styles.pill, agent.status === 'archived' ? styles.pillArchived : styles.pillActive]}>
149
- <Text style={styles.pillText}>{agent.status}</Text>
150
- </View>
151
- </Pressable>
152
- )
153
- }
154
-
155
- const makeStyles = (colors: Colors) =>
156
- StyleSheet.create({
157
- screen: { flex: 1, backgroundColor: colors.background },
158
- header: {
159
- flexDirection: 'row',
160
- justifyContent: 'space-between',
161
- alignItems: 'center',
162
- paddingHorizontal: 16,
163
- paddingVertical: 10,
164
- borderBottomWidth: StyleSheet.hairlineWidth,
165
- borderBottomColor: colors.border,
166
- backgroundColor: colors.ivory,
167
- },
168
- headerServer: {
169
- fontFamily: fonts.mono,
170
- fontSize: 12,
171
- color: colors.mocha,
172
- flex: 1,
173
- },
174
- headerSettings: { color: colors.sapphireDeep, fontSize: 14, fontFamily: fonts.bodyMedium },
175
- centered: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24, gap: 12 },
176
- errorTitle: { fontSize: 18, fontFamily: fonts.bodyBold, color: colors.foreground },
177
- errorBody: { color: colors.destructive, textAlign: 'center', fontFamily: fonts.body },
178
- primaryBtn: {
179
- marginTop: 12,
180
- paddingHorizontal: 20,
181
- paddingVertical: 10,
182
- borderRadius: radii.md,
183
- backgroundColor: colors.sapphire,
184
- },
185
- primaryBtnText: { color: colors.primaryForeground, fontSize: 14, fontFamily: fonts.bodyMedium },
186
- linkBtn: { marginTop: 4, padding: 8 },
187
- linkBtnText: { color: colors.mocha, fontSize: 13, fontFamily: fonts.body },
188
- row: {
189
- flexDirection: 'row',
190
- alignItems: 'center',
191
- paddingHorizontal: 16,
192
- paddingVertical: 14,
193
- backgroundColor: colors.card,
194
- },
195
- rowPressed: { backgroundColor: colors.frost },
196
- rowMain: { flex: 1, marginRight: 12 },
197
- rowName: { fontSize: 16, fontFamily: fonts.bodyMedium, color: colors.foreground },
198
- rowModel: { fontSize: 12, color: colors.mochaLight, marginTop: 2, fontFamily: fonts.mono },
199
- separator: { height: StyleSheet.hairlineWidth, backgroundColor: colors.frost, marginLeft: 16 },
200
- pill: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: radii.md },
201
- pillActive: { backgroundColor: colors.sapphireGlow },
202
- pillArchived: { backgroundColor: colors.frost },
203
- pillText: {
204
- fontSize: 11,
205
- fontFamily: fonts.bodyMedium,
206
- textTransform: 'lowercase',
207
- color: colors.mocha,
208
- },
209
- empty: { padding: 32, alignItems: 'center', gap: 8 },
210
- emptyTitle: { fontSize: 16, fontFamily: fonts.bodyMedium, color: colors.foreground },
211
- emptyBody: { color: colors.mocha, textAlign: 'center', fontSize: 13, fontFamily: fonts.body },
212
- })
@@ -1,21 +0,0 @@
1
- import { Redirect } from 'expo-router'
2
- import { useEffect, useState } from 'react'
3
- import { loadCredentials } from '@/src/auth'
4
-
5
- type Gate = { kind: 'loading' } | { kind: 'unpaired' } | { kind: 'paired' }
6
-
7
- export default function Index() {
8
- const [gate, setGate] = useState<Gate>({ kind: 'loading' })
9
-
10
- useEffect(() => {
11
- loadCredentials()
12
- .then((creds) => setGate({ kind: creds ? 'paired' : 'unpaired' }))
13
- .catch(() => setGate({ kind: 'unpaired' }))
14
- }, [])
15
-
16
- // Render nothing while SecureStore resolves. The native splash is still up
17
- // at this point on cold launch; rendering an ActivityIndicator briefly
18
- // produced a visible flash between splash dismissal and the redirect.
19
- if (gate.kind === 'loading') return null
20
- return <Redirect href={gate.kind === 'paired' ? '/agents' : '/pair'} />
21
- }
@@ -1,226 +0,0 @@
1
- import { CameraView, useCameraPermissions } from 'expo-camera'
2
- import { router } from 'expo-router'
3
- import { useCallback, useMemo, useRef, useState } from 'react'
4
- import {
5
- ActivityIndicator,
6
- Alert,
7
- Button,
8
- Platform,
9
- Pressable,
10
- StyleSheet,
11
- Text,
12
- TextInput,
13
- View,
14
- } from 'react-native'
15
- import { saveCredentials, verifyCredentials } from '@/src/auth'
16
- import { PairUrlError, parsePairingUrl } from '@/src/pair-url'
17
- import { useColors } from '@/src/theme-context'
18
- import { type Colors, fonts, radii } from '@/src/theme'
19
-
20
- /**
21
- * Browsers require a secure context (HTTPS or localhost) for
22
- * `navigator.mediaDevices.getUserMedia`. Over LAN / Tailscale on http://,
23
- * `requestPermission()` silently rejects without ever prompting. Detect
24
- * that up front so the user doesn't tap a button that does nothing.
25
- */
26
- function webCameraBlockedReason(): string | null {
27
- if (Platform.OS !== 'web') return null
28
- if (typeof window === 'undefined') return null
29
- const { protocol, hostname } = window.location
30
- if (protocol === 'https:') return null
31
- if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1') return null
32
- return `Camera access on the web requires HTTPS. You are on ${protocol}//${hostname} — use the manual-paste flow below, or open this page from a phone via Expo Go.`
33
- }
34
-
35
- type Mode = 'scan' | 'paste'
36
-
37
- export default function PairScreen() {
38
- const [mode, setMode] = useState<Mode>('scan')
39
- const [permission, requestPermission] = useCameraPermissions()
40
- const [busy, setBusy] = useState(false)
41
- const [error, setError] = useState<string | null>(null)
42
- const [pasteValue, setPasteValue] = useState('')
43
- // Expo fires the barcode callback repeatedly on every frame — dedupe.
44
- const handled = useRef(false)
45
- const colors = useColors()
46
- const styles = useMemo(() => makeStyles(colors), [colors])
47
-
48
- const handlePairingUrl = useCallback(async (raw: string) => {
49
- if (handled.current) return
50
- handled.current = true
51
- setBusy(true)
52
- setError(null)
53
- try {
54
- const creds = parsePairingUrl(raw)
55
- await verifyCredentials(creds)
56
- await saveCredentials(creds)
57
- router.replace('/agents')
58
- } catch (err) {
59
- handled.current = false
60
- const msg =
61
- err instanceof PairUrlError
62
- ? `QR content is not a pairing URL: ${err.message}`
63
- : err instanceof Error
64
- ? err.message
65
- : 'unknown error'
66
- setError(msg)
67
- Alert.alert('Pairing failed', msg)
68
- } finally {
69
- setBusy(false)
70
- }
71
- }, [])
72
-
73
- if (mode === 'paste') {
74
- return (
75
- <View style={styles.container}>
76
- <Text style={styles.title}>Paste pairing URL</Text>
77
- <Text style={styles.hint}>
78
- Run `bazilion token create &lt;label&gt; --qr` on your server to generate one.
79
- </Text>
80
- <TextInput
81
- value={pasteValue}
82
- onChangeText={setPasteValue}
83
- placeholder="bazilion://pair?server=…&token=…"
84
- autoCapitalize="none"
85
- autoCorrect={false}
86
- style={styles.input}
87
- multiline
88
- />
89
- {error ? <Text style={styles.error}>{error}</Text> : null}
90
- <View style={styles.row}>
91
- <Button
92
- title={busy ? 'Verifying…' : 'Pair'}
93
- onPress={() => handlePairingUrl(pasteValue.trim())}
94
- disabled={busy || !pasteValue.trim()}
95
- />
96
- <Button title="Scan instead" onPress={() => setMode('scan')} disabled={busy} />
97
- </View>
98
- </View>
99
- )
100
- }
101
-
102
- if (!permission) {
103
- return (
104
- <View style={[styles.container, styles.centered]}>
105
- <ActivityIndicator />
106
- </View>
107
- )
108
- }
109
-
110
- if (!permission.granted) {
111
- const webBlocked = webCameraBlockedReason()
112
- return (
113
- <View style={[styles.container, styles.centered]}>
114
- <Text style={styles.title}>Camera access needed</Text>
115
- <Text style={styles.hint}>
116
- Bazilion uses the camera only to scan pairing QR codes. Nothing is recorded.
117
- </Text>
118
- <Text style={styles.diag}>
119
- status: {permission.status} · canAskAgain: {String(permission.canAskAgain)}
120
- </Text>
121
- {webBlocked ? <Text style={styles.error}>{webBlocked}</Text> : null}
122
- {!permission.canAskAgain && !webBlocked ? (
123
- <Text style={styles.error}>
124
- The OS won't prompt again — camera was denied earlier. Grant it in Settings → Expo Go
125
- → Camera, then restart Expo Go.
126
- </Text>
127
- ) : null}
128
- <Button
129
- title="Grant camera access"
130
- onPress={async () => {
131
- try {
132
- const r = await requestPermission()
133
- if (!r.granted) {
134
- Alert.alert(
135
- 'Camera not granted',
136
- `status=${r.status} canAskAgain=${r.canAskAgain}`,
137
- )
138
- }
139
- } catch (err) {
140
- Alert.alert('requestPermission threw', String(err))
141
- }
142
- }}
143
- disabled={!!webBlocked}
144
- />
145
- <View style={{ height: 16 }} />
146
- <Button title="Paste URL instead" onPress={() => setMode('paste')} />
147
- </View>
148
- )
149
- }
150
-
151
- return (
152
- <View style={styles.container}>
153
- <CameraView
154
- style={styles.camera}
155
- facing="back"
156
- barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
157
- onBarcodeScanned={busy || handled.current ? undefined : ({ data }) => handlePairingUrl(data)}
158
- >
159
- <View style={styles.overlay}>
160
- <Text style={styles.overlayTitle}>Scan pairing QR</Text>
161
- <Text style={styles.overlayHint}>
162
- Point the camera at the QR code emitted by `bazilion token create --qr`.
163
- </Text>
164
- {busy ? <ActivityIndicator style={{ marginTop: 12 }} /> : null}
165
- {error ? <Text style={[styles.error, styles.onCamera]}>{error}</Text> : null}
166
- </View>
167
- </CameraView>
168
- <Pressable style={styles.fallback} onPress={() => setMode('paste')}>
169
- <Text style={styles.fallbackText}>Paste URL instead</Text>
170
- </Pressable>
171
- </View>
172
- )
173
- }
174
-
175
- const makeStyles = (colors: Colors) =>
176
- StyleSheet.create({
177
- container: { flex: 1, backgroundColor: colors.background },
178
- centered: { justifyContent: 'center', alignItems: 'center', padding: 24, gap: 12 },
179
- title: {
180
- fontSize: 22,
181
- fontFamily: fonts.display,
182
- color: colors.foreground,
183
- marginBottom: 8,
184
- },
185
- hint: { color: colors.mocha, marginBottom: 16, textAlign: 'center', fontFamily: fonts.body },
186
- input: {
187
- margin: 16,
188
- padding: 12,
189
- borderWidth: 1,
190
- borderColor: colors.border,
191
- borderRadius: radii.md,
192
- minHeight: 80,
193
- fontFamily: fonts.mono,
194
- color: colors.foreground,
195
- backgroundColor: colors.ivory,
196
- },
197
- row: { flexDirection: 'row', gap: 12, justifyContent: 'center', marginTop: 8 },
198
- error: { color: colors.destructive, margin: 16, textAlign: 'center', fontFamily: fonts.body },
199
- diag: { color: colors.mochaLight, fontFamily: fonts.mono, fontSize: 12, marginBottom: 12 },
200
- // Camera-overlay backdrop is intentionally theme-independent: sits on top
201
- // of live camera video, needs to read as a translucent dark scrim regardless
202
- // of light/dark theme.
203
- onCamera: { backgroundColor: 'rgba(0,0,0,0.6)', padding: 8, borderRadius: 4 },
204
- camera: { flex: 1 },
205
- overlay: {
206
- flex: 1,
207
- justifyContent: 'flex-end',
208
- padding: 24,
209
- paddingBottom: 80,
210
- },
211
- overlayTitle: {
212
- color: '#FFFFFF',
213
- fontSize: 20,
214
- fontFamily: fonts.display,
215
- marginBottom: 4,
216
- },
217
- overlayHint: { color: '#ddd', fontFamily: fonts.body },
218
- fallback: {
219
- position: 'absolute',
220
- bottom: 24,
221
- left: 0,
222
- right: 0,
223
- alignItems: 'center',
224
- },
225
- fallbackText: { color: '#FFFFFF', textDecorationLine: 'underline', fontFamily: fonts.body },
226
- })