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,245 +0,0 @@
1
- import { createServer, type ServerResponse } from 'node:http'
2
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
3
- import { extractAgentId } from './helpers.ts'
4
- import { startTestServer, type TestServer } from './server-fixture.ts'
5
-
6
- interface MockLlm {
7
- url: string
8
- push(responses: unknown[]): void
9
- reset(): void
10
- stop(): Promise<void>
11
- callCount(): number
12
- }
13
-
14
- interface Canned {
15
- choices: Array<{
16
- message: { role?: string; content?: string | null }
17
- finish_reason?: string
18
- }>
19
- }
20
-
21
- function writeSse(res: ServerResponse, canned: Canned): void {
22
- res.writeHead(200, {
23
- 'content-type': 'text/event-stream',
24
- 'cache-control': 'no-cache',
25
- connection: 'keep-alive',
26
- })
27
- const msg = canned.choices[0]?.message ?? {}
28
- const finish = canned.choices[0]?.finish_reason ?? 'stop'
29
- res.write(
30
- `data: ${JSON.stringify({
31
- id: 'mock',
32
- object: 'chat.completion.chunk',
33
- choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }],
34
- })}\n\n`,
35
- )
36
- if (typeof msg.content === 'string' && msg.content.length > 0) {
37
- res.write(
38
- `data: ${JSON.stringify({
39
- id: 'mock',
40
- object: 'chat.completion.chunk',
41
- choices: [{ index: 0, delta: { content: msg.content }, finish_reason: null }],
42
- })}\n\n`,
43
- )
44
- }
45
- res.write(
46
- `data: ${JSON.stringify({
47
- id: 'mock',
48
- object: 'chat.completion.chunk',
49
- choices: [{ index: 0, delta: {}, finish_reason: finish }],
50
- })}\n\n`,
51
- )
52
- res.write('data: [DONE]\n\n')
53
- res.end()
54
- }
55
-
56
- function startLmStudioMock(): Promise<MockLlm> {
57
- const queue: unknown[] = []
58
- let calls = 0
59
- const server = createServer((_req, res) => {
60
- calls++
61
- if (queue.length === 0) {
62
- // Default response so we never block — the scheduler may fire more times
63
- // than the test pushed responses for, and we don't want to deadlock.
64
- writeSse(res, {
65
- choices: [
66
- { message: { role: 'assistant', content: 'default-pong' }, finish_reason: 'stop' },
67
- ],
68
- })
69
- return
70
- }
71
- const item = queue.shift() as Canned
72
- writeSse(res, item)
73
- })
74
- return new Promise((resolve) => {
75
- server.listen(0, () => {
76
- const addr = server.address()
77
- if (!addr || typeof addr === 'string') throw new Error('unexpected server address')
78
- resolve({
79
- url: `http://localhost:${addr.port}/v1`,
80
- push(items) {
81
- queue.push(...items)
82
- },
83
- reset() {
84
- queue.length = 0
85
- calls = 0
86
- },
87
- stop: () => new Promise<void>((r) => server.close(() => r())),
88
- callCount: () => calls,
89
- })
90
- })
91
- })
92
- }
93
-
94
- let mock: MockLlm
95
- let server: TestServer
96
-
97
- beforeAll(async () => {
98
- mock = await startLmStudioMock()
99
- server = await startTestServer({
100
- LMSTUDIO_URL: mock.url,
101
- // Drive the scheduler fast so the test doesn't wait 5s per tick.
102
- BAZILION_SCHEDULER_TICK_MS: '200',
103
- })
104
- })
105
- afterAll(async () => {
106
- await server.stop()
107
- await mock.stop()
108
- })
109
- // Reset order matters: wipe DB (kills any active triggers) *before* zeroing
110
- // the mock's call counter, so a tick mid-reset can't increment `calls` after
111
- // we've cleared it. The scheduler has nothing to fire after the DB wipe.
112
- beforeEach(() => {
113
- server.reset()
114
- mock.reset()
115
- })
116
-
117
- async function spawnAgent(): Promise<string> {
118
- await server.cli(['profile', 'create', 'p', '--model', 'lmstudio:test-model'])
119
- const r = await server.cli(['agent', 'spawn', '--profile', 'p'])
120
- return extractAgentId(r.stdout)
121
- }
122
-
123
- test('trigger add/list round-trip', async () => {
124
- const agentId = await spawnAgent()
125
- const add = await server.cli([
126
- 'trigger',
127
- 'add',
128
- agentId,
129
- '--every',
130
- '60',
131
- '--message',
132
- 'tick',
133
- '--disabled',
134
- ])
135
- expect(add.exitCode).toBe(0)
136
- expect(add.stdout).toMatch(/every 60s\tdisabled/)
137
-
138
- const list = await server.cli(['trigger', 'list', agentId])
139
- expect(list.exitCode).toBe(0)
140
- expect(list.stdout).toMatch(/every 60s/)
141
- expect(list.stdout).toMatch(/last: \(never\)/)
142
- })
143
-
144
- test('trigger enable/disable toggles state', async () => {
145
- const agentId = await spawnAgent()
146
- const add = await server.cli([
147
- 'trigger',
148
- 'add',
149
- agentId,
150
- '--every',
151
- '60',
152
- '--message',
153
- 'tick',
154
- '--disabled',
155
- ])
156
- const [id] = add.stdout.trim().split('\t') as [string]
157
- expect(id).toBeTruthy()
158
-
159
- await server.cli(['trigger', 'enable', id])
160
- let list = await server.cli(['trigger', 'list', agentId])
161
- expect(list.stdout).toMatch(/enabled/)
162
-
163
- await server.cli(['trigger', 'disable', id])
164
- list = await server.cli(['trigger', 'list', agentId])
165
- expect(list.stdout).toMatch(/disabled/)
166
- })
167
-
168
- test('trigger rm deletes the trigger', async () => {
169
- const agentId = await spawnAgent()
170
- const add = await server.cli([
171
- 'trigger',
172
- 'add',
173
- agentId,
174
- '--every',
175
- '60',
176
- '--message',
177
- 'tick',
178
- '--disabled',
179
- ])
180
- const [id] = add.stdout.trim().split('\t') as [string]
181
- await server.cli(['trigger', 'rm', id])
182
- const list = await server.cli(['trigger', 'list', agentId])
183
- expect(list.stdout).toContain('(no triggers)')
184
- })
185
-
186
- test('enabled interval trigger fires and updates last_fired_at', async () => {
187
- const agentId = await spawnAgent()
188
-
189
- // intervalSec=1 → first fire happens ~1s after creation, scheduler ticks every 200ms.
190
- const add = await server.cli([
191
- 'trigger',
192
- 'add',
193
- agentId,
194
- '--every',
195
- '1',
196
- '--message',
197
- 'hello from cron',
198
- ])
199
- expect(add.exitCode).toBe(0)
200
-
201
- // Wait up to 15s for `last_fired_at` to flip from never to a timestamp —
202
- // the scheduler bumps it before it kicks the worker.
203
- let fired = false
204
- for (let i = 0; i < 150; i++) {
205
- const list = await server.cli(['trigger', 'list', agentId])
206
- if (!/last: \(never\)/.test(list.stdout)) {
207
- fired = true
208
- break
209
- }
210
- await new Promise((r) => setTimeout(r, 100))
211
- }
212
- expect(fired).toBe(true)
213
- })
214
-
215
- test('cron trigger with invalid expression is rejected', async () => {
216
- const agentId = await spawnAgent()
217
- const r = await server.cli([
218
- 'trigger',
219
- 'add',
220
- agentId,
221
- '--cron',
222
- 'not-a-cron',
223
- '--message',
224
- 'nope',
225
- ])
226
- expect(r.exitCode).not.toBe(0)
227
- expect(r.stderr + r.stdout).toMatch(/invalid cron/i)
228
- })
229
-
230
- test('trigger add rejects both --every and --cron', async () => {
231
- const agentId = await spawnAgent()
232
- const r = await server.cli([
233
- 'trigger',
234
- 'add',
235
- agentId,
236
- '--every',
237
- '60',
238
- '--cron',
239
- '* * * * *',
240
- '--message',
241
- 'hi',
242
- ])
243
- expect(r.exitCode).not.toBe(0)
244
- expect(r.stderr + r.stdout).toMatch(/exactly one of --every/)
245
- })
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "include": ["src/**/*"]
4
- }
@@ -1,31 +0,0 @@
1
- {
2
- "name": "@bazilion/daemon",
3
- "version": "0.0.0",
4
- "private": true,
5
- "type": "module",
6
- "bin": {
7
- "bazilion-daemon": "./src/index.ts"
8
- },
9
- "scripts": {
10
- "dev": "tsx src/index.ts",
11
- "start": "node --experimental-strip-types src/index.ts"
12
- },
13
- "dependencies": {
14
- "@bazilion/api-types": "workspace:*",
15
- "@hono/node-server": "^1.13.0",
16
- "@mariozechner/pi-agent-core": "^0.69.0",
17
- "@mariozechner/pi-ai": "^0.69.0",
18
- "@mariozechner/pi-coding-agent": "^0.69.0",
19
- "@mozilla/readability": "^0.6.0",
20
- "@tobilu/qmd": "^2.1.0",
21
- "adm-zip": "^0.5.17",
22
- "hono": "^4.6.0",
23
- "linkedom": "^0.18.12",
24
- "typebox": "^1.1.32",
25
- "undici": "^8.1.0",
26
- "yaml": "^2.6.0"
27
- },
28
- "devDependencies": {
29
- "@types/adm-zip": "^0.5.8"
30
- }
31
- }
@@ -1,41 +0,0 @@
1
- // Hono app factory.
2
- //
3
- // Returns a fully-wired Hono app: middleware (auth + first-run gate) +
4
- // routes. Kept as a factory so tests can build one with a dedicated DB
5
- // without touching the global ctx singleton.
6
-
7
- import { Hono } from 'hono'
8
- import { authMiddleware } from './lib/middleware-auth.ts'
9
- import { agentsRouter } from './routes/agents.ts'
10
- import { authRouter } from './routes/auth-login.ts'
11
- import { configRouter } from './routes/config.ts'
12
- import { groupsRouter } from './routes/groups.ts'
13
- import { messagesRouter } from './routes/messages.ts'
14
- import { miscRouter } from './routes/misc.ts'
15
- import { profilesRouter } from './routes/profiles.ts'
16
- import { skillsRouter } from './routes/skills.ts'
17
- import { triggersRouter } from './routes/triggers.ts'
18
-
19
- export function createApp(): Hono {
20
- const app = new Hono()
21
-
22
- // Auth + first-run gate runs before every route. Public paths (/api/login,
23
- // /api/health) and the setup-open prefixes (/api/config, /api/auth) are
24
- // whitelisted inside the middleware itself.
25
- app.use('*', authMiddleware)
26
-
27
- app.route('/api/agents', agentsRouter)
28
- app.route('/api/groups', groupsRouter)
29
- app.route('/api/profiles', profilesRouter)
30
- app.route('/api/skills', skillsRouter)
31
- app.route('/api/triggers', triggersRouter)
32
- app.route('/api/messages', messagesRouter)
33
- app.route('/api/config', configRouter)
34
- // miscRouter exposes /backup, /tokens, /tokens/:id directly under /api —
35
- // mounted at the API root so each handler can use its full path.
36
- // authRouter likewise: /auth/openai*, /providers/test, /login.
37
- app.route('/api', miscRouter)
38
- app.route('/api', authRouter)
39
-
40
- return app
41
- }
@@ -1,8 +0,0 @@
1
- import type { BazilionDb } from '../db/client.ts'
2
- import * as agentRepo from '../repos/agents.ts'
3
-
4
- export function archiveAgent(db: BazilionDb, id: string): void {
5
- const agent = agentRepo.get(db, id)
6
- if (!agent) throw new Error(`agent not found: ${id}`)
7
- agentRepo.archive(db, agent.id)
8
- }
@@ -1,30 +0,0 @@
1
- import { existsSync, rmSync } from 'node:fs'
2
- import type { BazilionDb } from '../db/client.ts'
3
- import * as agentRepo from '../repos/agents.ts'
4
-
5
- export function deleteAgent(db: BazilionDb, id: string): void {
6
- const agent = agentRepo.get(db, id)
7
- if (!agent) throw new Error(`agent not found: ${id}`)
8
- const fullId = agent.id
9
-
10
- db.raw.transaction(() => {
11
- // messages.from_agent_id and to_agent_id reference agents(id) with no ON
12
- // DELETE rule, and messages.reply_to references messages(id) the same way,
13
- // so a naive DELETE of the agent fails if it has any mailbox history.
14
- // Null out inbound reply pointers to this agent's messages, then purge the
15
- // messages themselves, then let agentRepo.remove cascade the rest
16
- // (agent_skills, runs, events). agents.group_id is `ON DELETE RESTRICT`
17
- // from the group side, but the agent row itself goes away freely.
18
- db.raw.run(
19
- `UPDATE messages SET reply_to = NULL
20
- WHERE reply_to IN (SELECT id FROM messages WHERE from_agent_id = ? OR to_agent_id = ?)`,
21
- [fullId, fullId],
22
- )
23
- db.raw.run('DELETE FROM messages WHERE from_agent_id = ? OR to_agent_id = ?', [fullId, fullId])
24
- agentRepo.remove(db, fullId)
25
- })()
26
-
27
- if (existsSync(agent.dir)) {
28
- rmSync(agent.dir, { recursive: true, force: true })
29
- }
30
- }
@@ -1,31 +0,0 @@
1
- import type { ResolvedAgent } from '@bazilion/api-types'
2
- import type { BazilionDb } from '../db/client.ts'
3
- import type { Paths } from '../paths.ts'
4
- import * as agentRepo from '../repos/agents.ts'
5
- import * as groupRepo from '../repos/groups.ts'
6
- import * as profileRepo from '../repos/profiles.ts'
7
-
8
- export function resolveAgent(db: BazilionDb, paths: Paths, agentId: string): ResolvedAgent {
9
- // `agentRepo.get` accepts either a full UUID or an unambiguous prefix.
10
- const agent = agentRepo.get(db, agentId)
11
- if (!agent) throw new Error(`agent not found: ${agentId}`)
12
-
13
- const profile = profileRepo.get(db, agent.profileId)
14
- if (!profile) {
15
- throw new Error(`profile not found for agent ${agentId}: ${agent.profileId}`)
16
- }
17
-
18
- const group = groupRepo.get(db, agent.groupId, paths)
19
- if (!group) {
20
- throw new Error(`group not found for agent ${agentId}: ${agent.groupId}`)
21
- }
22
-
23
- return {
24
- agent,
25
- profile,
26
- model: agent.modelOverride ?? profile.defaultModel,
27
- reasoningLevel: agent.reasoningLevel,
28
- group,
29
- skills: agentRepo.listAttachedSkills(db, agentId),
30
- }
31
- }
@@ -1,95 +0,0 @@
1
- import { randomUUID } from 'node:crypto'
2
- import { mkdirSync, writeFileSync } from 'node:fs'
3
- import { join } from 'node:path'
4
- import type { Agent, ReasoningLevel } from '@bazilion/api-types'
5
- import type { BazilionDb } from '../db/client.ts'
6
- import type { Paths } from '../paths.ts'
7
- import { loadProfile } from '../profile/load.ts'
8
- import { DEFAULT_GROUP_ID } from '../profile/seed.ts'
9
- import * as agentRepo from '../repos/agents.ts'
10
- import * as groupRepo from '../repos/groups.ts'
11
- import { discoverSkills } from '../skills/discover.ts'
12
-
13
- export interface SpawnAgentInput {
14
- profileId: string
15
- name?: string
16
- modelOverride?: string | null
17
- reasoningLevel?: ReasoningLevel
18
- /**
19
- * Group the new agent joins. One agent belongs to exactly one group. When
20
- * omitted, falls back to the seeded 'default' group — the same fallback
21
- * used everywhere we need a sensible cwd. Must refer to an existing group.
22
- */
23
- groupId?: string
24
- }
25
-
26
- export function spawnAgent(db: BazilionDb, paths: Paths, input: SpawnAgentInput): Agent {
27
- const loaded = loadProfile(db, input.profileId)
28
- const id = randomUUID()
29
- const dir = paths.agentDir(id)
30
- // Agent's private home: identity files + sessions. Memory now lives at
31
- // the group level (`groups/<slug>/memory/`), shared by all member agents,
32
- // so we no longer create per-agent memory dirs here.
33
- mkdirSync(dir, { recursive: true })
34
- mkdirSync(join(dir, 'sessions'), { recursive: true })
35
-
36
- // Copy profile templates so the agent can diverge per-instance.
37
- writeFileSync(join(dir, 'SOUL.md'), loaded.files.soul)
38
- writeFileSync(join(dir, 'IDENTITY.md'), loaded.files.identity)
39
- if (loaded.files.bootstrap !== null) {
40
- writeFileSync(join(dir, 'BOOTSTRAP.md'), loaded.files.bootstrap)
41
- }
42
- if (loaded.files.agents !== null) {
43
- writeFileSync(join(dir, 'AGENTS.md'), loaded.files.agents)
44
- }
45
- if (loaded.files.tools !== null) {
46
- writeFileSync(join(dir, 'TOOLS.md'), loaded.files.tools)
47
- }
48
- if (loaded.files.heartbeat !== null) {
49
- writeFileSync(join(dir, 'HEARTBEAT.md'), loaded.files.heartbeat)
50
- }
51
-
52
- const reasoningLevel: ReasoningLevel = input.reasoningLevel ?? 'medium'
53
-
54
- // Resolve group: explicit input wins; otherwise fall back to the seeded
55
- // 'default'. If neither exists, error out — an agent can't live without a
56
- // group (the FK `agents.group_id REFERENCES groups(id)` enforces it too).
57
- const groupId = input.groupId ?? DEFAULT_GROUP_ID
58
- const group = groupRepo.get(db, groupId, paths)
59
- if (!group) {
60
- throw new Error(
61
- `spawnAgent: group "${groupId}" does not exist. Pass an explicit --group or complete first-run setup first.`,
62
- )
63
- }
64
-
65
- const agentJson = {
66
- profileId: input.profileId,
67
- name: input.name ?? loaded.profile.name,
68
- modelOverride: input.modelOverride ?? null,
69
- reasoningLevel,
70
- groupId: group.id,
71
- }
72
- writeFileSync(join(dir, 'agent.json'), `${JSON.stringify(agentJson, null, 2)}\n`)
73
-
74
- const agent = agentRepo.insert(db, {
75
- id,
76
- profileId: input.profileId,
77
- name: agentJson.name,
78
- modelOverride: agentJson.modelOverride,
79
- reasoningLevel,
80
- status: 'idle',
81
- dir,
82
- groupId: group.id,
83
- })
84
-
85
- // Skills come from the profile only — `skills_mode='all'` attaches every
86
- // installed skill, `'selected'` attaches the profile's default list.
87
- // Per-agent skill changes happen post-spawn via `agent skill add/rm`.
88
- const skills =
89
- loaded.profile.skillsMode === 'all'
90
- ? discoverSkills(paths).map((s) => s.name)
91
- : loaded.defaultSkills
92
- for (const s of skills) agentRepo.attachSkill(db, id, s)
93
-
94
- return agent
95
- }
@@ -1,11 +0,0 @@
1
- import type { BazilionDb } from '../db/client.ts'
2
- import * as agentRepo from '../repos/agents.ts'
3
-
4
- export function unarchiveAgent(db: BazilionDb, id: string): void {
5
- const agent = agentRepo.get(db, id)
6
- if (!agent) throw new Error(`agent not found: ${id}`)
7
- if (agent.status !== 'archived') {
8
- throw new Error(`agent is not archived (status: ${agent.status})`)
9
- }
10
- agentRepo.unarchive(db, agent.id)
11
- }
@@ -1,58 +0,0 @@
1
- // Enumerates models that agents are actually allowed to use right now:
2
- // every curated model of every currently-enabled provider. Drives the model
3
- // dropdowns on the profile and agent forms.
4
- //
5
- // A provider must be both (a) toggled on in `provider_state` AND (b) have
6
- // at least one curated entry in `provider_models` to show up here. Drop a
7
- // provider off either side and it disappears from the list without a UI
8
- // edit — the dropdowns are entirely data-driven.
9
-
10
- import type { BazilionDb } from './db/client.ts'
11
- import * as providerModelRepo from './repos/providerModels.ts'
12
- import * as providerStateRepo from './repos/providerState.ts'
13
-
14
- export interface AvailableModel {
15
- provider: string
16
- model: string
17
- /** The `provider:model` string used as the form value and in model resolution. */
18
- value: string
19
- }
20
-
21
- /**
22
- * Flat list of `{provider, model, value}` for every curated model of every
23
- * enabled provider. Iteration order: providers as they're stored in
24
- * `provider_state` (by insertion time), models as curated (preserving the
25
- * admin's ordering from the textarea).
26
- */
27
- export function listAvailableModels(db: BazilionDb): AvailableModel[] {
28
- const enabled = providerStateRepo.listEnabled(db)
29
- const out: AvailableModel[] = []
30
- for (const provider of enabled) {
31
- for (const model of providerModelRepo.list(db, provider)) {
32
- out.push({ provider, model, value: `${provider}:${model}` })
33
- }
34
- }
35
- return out
36
- }
37
-
38
- /**
39
- * Same as `listAvailableModels` but grouped by provider — the shape the web
40
- * dropdowns consume directly via `<optgroup>`.
41
- */
42
- export function groupAvailableModels(db: BazilionDb): { provider: string; models: string[] }[] {
43
- const enabled = providerStateRepo.listEnabled(db)
44
- const groups: { provider: string; models: string[] }[] = []
45
- for (const provider of enabled) {
46
- const models = providerModelRepo.list(db, provider)
47
- if (models.length > 0) groups.push({ provider, models })
48
- }
49
- return groups
50
- }
51
-
52
- /**
53
- * True once the user has at least one usable model — i.e. at least one enabled
54
- * provider with at least one curated model. Gates the first-run flow.
55
- */
56
- export function isSetupComplete(db: BazilionDb): boolean {
57
- return listAvailableModels(db).length > 0
58
- }
@@ -1,113 +0,0 @@
1
- import { DatabaseSync, type SQLInputValue } from 'node:sqlite'
2
-
3
- export interface QueryStmt<RowType, ParamsType extends unknown[]> {
4
- get(...params: ParamsType): RowType | null
5
- all(...params: ParamsType): RowType[]
6
- run(...params: ParamsType): { changes: number; lastInsertRowid: number | bigint }
7
- }
8
-
9
- export interface QueryableDatabase {
10
- query<RowType, ParamsType extends unknown[]>(sql: string): QueryStmt<RowType, ParamsType>
11
- run(sql: string, params?: unknown[]): { changes: number; lastInsertRowid: number | bigint }
12
- exec(sql: string): void
13
- transaction<T>(fn: () => T): () => T
14
- }
15
-
16
- export interface BazilionDb {
17
- raw: QueryableDatabase
18
- close(): void
19
- }
20
-
21
- function wrap(rawDb: DatabaseSync): QueryableDatabase {
22
- const cache = new Map<string, ReturnType<DatabaseSync['prepare']>>()
23
- function getStmt(sql: string) {
24
- let s = cache.get(sql)
25
- if (!s) {
26
- s = rawDb.prepare(sql)
27
- cache.set(sql, s)
28
- }
29
- return s
30
- }
31
-
32
- return {
33
- query<R, P extends unknown[]>(sql: string): QueryStmt<R, P> {
34
- const stmt = getStmt(sql)
35
- return {
36
- get(...params: P): R | null {
37
- const result = stmt.get(...(params as SQLInputValue[]))
38
- return (result as R | undefined) ?? null
39
- },
40
- all(...params: P): R[] {
41
- return stmt.all(...(params as SQLInputValue[])) as R[]
42
- },
43
- run(...params: P) {
44
- return stmt.run(...(params as SQLInputValue[])) as {
45
- changes: number
46
- lastInsertRowid: number | bigint
47
- }
48
- },
49
- }
50
- },
51
- run(sql, params) {
52
- const stmt = getStmt(sql)
53
- return stmt.run(...((params ?? []) as SQLInputValue[])) as {
54
- changes: number
55
- lastInsertRowid: number | bigint
56
- }
57
- },
58
- exec(sql) {
59
- rawDb.exec(sql)
60
- },
61
- // node:sqlite has no callable `transaction` wrapper; use manual BEGIN/COMMIT/ROLLBACK.
62
- transaction<T>(fn: () => T): () => T {
63
- return () => {
64
- rawDb.exec('BEGIN')
65
- try {
66
- const result = fn()
67
- rawDb.exec('COMMIT')
68
- return result
69
- } catch (err) {
70
- rawDb.exec('ROLLBACK')
71
- throw err
72
- }
73
- }
74
- },
75
- }
76
- }
77
-
78
- function applyPragmas(rawDb: DatabaseSync, includeWal: boolean): void {
79
- if (includeWal) {
80
- try {
81
- rawDb.exec('PRAGMA journal_mode = WAL')
82
- } catch {
83
- // some sqlite builds reject WAL on :memory: — ignore
84
- }
85
- }
86
- rawDb.exec('PRAGMA foreign_keys = ON')
87
- }
88
-
89
- export function openDb(path: string): BazilionDb {
90
- const raw = new DatabaseSync(path)
91
- applyPragmas(raw, true)
92
- return {
93
- raw: wrap(raw),
94
- close() {
95
- raw.close()
96
- },
97
- }
98
- }
99
-
100
- export function openInMemoryDb(): BazilionDb {
101
- const raw = new DatabaseSync(':memory:')
102
- applyPragmas(raw, false)
103
- return {
104
- raw: wrap(raw),
105
- close() {
106
- raw.close()
107
- },
108
- }
109
- }
110
-
111
- export function inTx<T>(db: BazilionDb, fn: () => T): T {
112
- return db.raw.transaction(fn)()
113
- }