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,110 +0,0 @@
1
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
5
- import { startTestServer, type TestServer } from './server-fixture.ts'
6
-
7
- let server: TestServer
8
- beforeAll(async () => {
9
- server = await startTestServer()
10
- })
11
- afterAll(() => server.stop())
12
- beforeEach(() => server.reset())
13
-
14
- test('profile create + list + show', async () => {
15
- let r = await server.cli([
16
- 'profile',
17
- 'create',
18
- 'researcher',
19
- '--model',
20
- 'anthropic:claude-opus-4-6',
21
- '--skills-mode',
22
- 'selected',
23
- '--skills',
24
- 's1,s2',
25
- ])
26
- expect(r.exitCode).toBe(0)
27
- expect(r.stdout).toContain('created profile researcher')
28
-
29
- r = await server.cli(['profile', 'list'])
30
- expect(r.stdout).toContain('researcher')
31
- expect(r.stdout).toContain('claude-opus-4-6')
32
-
33
- r = await server.cli(['profile', 'show', 'researcher'])
34
- expect(r.stdout).toContain('researcher')
35
- expect(r.stdout).toContain('default skills: s1, s2')
36
- expect(r.stdout).toContain('skills mode: selected')
37
- expect(r.stdout).toContain('bootstrap: yes')
38
- })
39
-
40
- test('profile create with invalid slug fails', async () => {
41
- const r = await server.cli(['profile', 'create', 'Bad Id', '--model', 'm'])
42
- expect(r.exitCode).not.toBe(0)
43
- expect(r.stderr + r.stdout).toContain('invalid slug')
44
- })
45
-
46
- test('profile update switches model and skills-mode', async () => {
47
- await server.cli(['profile', 'create', 'to-update', '--model', 'anthropic:claude-opus-4-6'])
48
- const r = await server.cli([
49
- 'profile',
50
- 'update',
51
- 'to-update',
52
- '--model',
53
- 'anthropic:claude-opus-4-7',
54
- '--skills-mode',
55
- 'all',
56
- ])
57
- expect(r.exitCode).toBe(0)
58
- const show = await server.cli(['profile', 'show', 'to-update'])
59
- expect(show.stdout).toContain('claude-opus-4-7')
60
- expect(show.stdout).toContain('skills mode: all')
61
-
62
- const json = JSON.parse(
63
- readFileSync(join(server.home, 'profiles', 'to-update', 'profile.json'), 'utf8'),
64
- )
65
- expect(json.defaultModel).toBe('anthropic:claude-opus-4-7')
66
- expect(json.skillsMode).toBe('all')
67
- })
68
-
69
- test('PUT /api/profiles/:id/files/:file edits SOUL.md post-creation', async () => {
70
- await server.cli(['profile', 'create', 'editable', '--model', 'anthropic:claude-opus-4-6'])
71
- const res = await fetch(`${server.url}/api/profiles/editable/files/SOUL.md`, {
72
- method: 'PUT',
73
- headers: {
74
- 'content-type': 'application/json',
75
- cookie: `bz_token=${server.token}`,
76
- origin: server.url,
77
- },
78
- body: JSON.stringify({ content: '# edited post-creation\nnew rules' }),
79
- })
80
- expect(res.status).toBe(204)
81
- const soul = readFileSync(join(server.home, 'profiles', 'editable', 'SOUL.md'), 'utf8')
82
- expect(soul).toBe('# edited post-creation\nnew rules')
83
- })
84
-
85
- test('profile create --soul-file and --skip-bootstrap write custom templates', async () => {
86
- const scratch = mkdtempSync(join(tmpdir(), 'bazilion-tmpl-'))
87
- const soulPath = join(scratch, 'soul.md')
88
- writeFileSync(soulPath, '# custom soul\nmake it yours')
89
- try {
90
- const r = await server.cli([
91
- 'profile',
92
- 'create',
93
- 'custom-tmpl',
94
- '--model',
95
- 'anthropic:claude-opus-4-6',
96
- '--soul-file',
97
- soulPath,
98
- '--skip-bootstrap',
99
- ])
100
- expect(r.exitCode).toBe(0)
101
-
102
- const soul = readFileSync(join(server.home, 'profiles', 'custom-tmpl', 'SOUL.md'), 'utf8')
103
- expect(soul).toBe('# custom soul\nmake it yours')
104
-
105
- const show = await server.cli(['profile', 'show', 'custom-tmpl'])
106
- expect(show.stdout).toContain('bootstrap: no')
107
- } finally {
108
- rmSync(scratch, { recursive: true, force: true })
109
- }
110
- })
@@ -1,30 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
2
- import { extractAgentId } from './helpers.ts'
3
- import { startTestServer, type TestServer } from './server-fixture.ts'
4
-
5
- let server: TestServer
6
- beforeAll(async () => {
7
- server = await startTestServer()
8
- })
9
- afterAll(() => server.stop())
10
- beforeEach(() => server.reset())
11
-
12
- test('send writes a message between two agents', async () => {
13
- await server.cli(['profile', 'create', 'p', '--model', 'm'])
14
-
15
- let r = await server.cli(['agent', 'spawn', '--profile', 'p'])
16
- const a = extractAgentId(r.stdout)
17
- r = await server.cli(['agent', 'spawn', '--profile', 'p'])
18
- const b = extractAgentId(r.stdout)
19
-
20
- r = await server.cli(['send', a, b, 'hello there'])
21
- expect(r.exitCode).toBe(0)
22
- expect(r.stdout).toContain('sent message')
23
- })
24
-
25
- test('send fails when an agent is missing', async () => {
26
- await server.cli(['profile', 'create', 'p', '--model', 'm'])
27
- const r = await server.cli(['send', 'nope1', 'nope2', 'hi'])
28
- expect(r.exitCode).not.toBe(0)
29
- expect(r.stderr + r.stdout).toContain('agent not found')
30
- })
@@ -1,212 +0,0 @@
1
- import { type ChildProcess, spawn } from 'node:child_process'
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
- import { createServer } from 'node:net'
4
- import { tmpdir } from 'node:os'
5
- import { join } from 'node:path'
6
- import {
7
- openDb,
8
- providerModelRepo,
9
- providerStateRepo,
10
- registerGroup,
11
- resolvePaths,
12
- runMigrations,
13
- webTokenRepo,
14
- } from '../../daemon/src/core/index.ts'
15
- import { type CliResult, runCli } from './helpers.ts'
16
-
17
- // Tests now boot the standalone daemon (apps/daemon/src/index.ts) — the
18
- // authority for /api/* — instead of the Astro web app, which only renders
19
- // pages and proxies to the daemon. tsx loader keeps the source-mode
20
- // invocation matching `bazilion serve`.
21
- const daemonEntry = join(import.meta.dirname, '..', '..', 'daemon', 'src', 'index.ts')
22
-
23
- function findFreePort(): Promise<number> {
24
- return new Promise((resolve, reject) => {
25
- const srv = createServer()
26
- srv.listen(0, () => {
27
- const addr = srv.address()
28
- if (!addr || typeof addr === 'string') {
29
- reject(new Error('unexpected server address'))
30
- return
31
- }
32
- const port = addr.port
33
- srv.close((err) => (err ? reject(err) : resolve(port)))
34
- })
35
- srv.on('error', reject)
36
- })
37
- }
38
-
39
- /**
40
- * Create a fresh `~/.bazilion`-shaped home: tempdir + subdirs + migrated db +
41
- * a bootstrap token row in `web_tokens` + an `auth.json` exposing the
42
- * plaintext for the CLI to use as a bearer. Mirrors the daemon's first-run
43
- * bootstrap (`apps/daemon/src/lib/ctx.ts:bootstrap`) without the subprocess
44
- * overhead.
45
- */
46
- function initHome(): { home: string; token: string } {
47
- const home = mkdtempSync(join(tmpdir(), 'bazilion-test-'))
48
- const paths = resolvePaths(home)
49
- for (const d of [
50
- paths.home,
51
- paths.profilesDir,
52
- paths.agentsDir,
53
- paths.skillsDir,
54
- paths.groupsDir,
55
- paths.logsDir,
56
- ]) {
57
- mkdirSync(d, { recursive: true })
58
- }
59
- const db = openDb(paths.db)
60
- runMigrations(db)
61
- // Mint a bootstrap token row + write its plaintext into auth.json.
62
- const created = webTokenRepo.create(db, 'bootstrap')
63
- writeFileSync(paths.authFile, `${JSON.stringify({ token: created.token }, null, 2)}\n`)
64
- // Enable lmstudio + ollama by default for test setup — the integration
65
- // tests mount their mock server via LMSTUDIO_URL and expect model resolution
66
- // to succeed. Real installs default to all providers disabled and require
67
- // the admin to toggle them on via /config.
68
- providerStateRepo.setEnabled(db, 'lmstudio', true)
69
- providerStateRepo.setEnabled(db, 'ollama', true)
70
- // Curate a placeholder model so the first-run middleware gate sees setup
71
- // as complete (isSetupComplete = any enabled provider has ≥1 curated model).
72
- // Tests that care about a specific model still override via --model.
73
- providerModelRepo.replace(db, 'lmstudio', ['test-model'])
74
- providerModelRepo.replace(db, 'ollama', ['test-model'])
75
- // Seed the 'default' group so spawnAgent's default-group fallback works
76
- // without tests having to register one first. Matches the fresh-install
77
- // post-first-run-setup state.
78
- registerGroup(db, { id: 'default', name: 'Default' }, paths)
79
- db.close()
80
- return { home, token: created.token }
81
- }
82
-
83
- async function waitForHttp(url: string, timeoutMs: number): Promise<void> {
84
- const start = Date.now()
85
- while (Date.now() - start < timeoutMs) {
86
- try {
87
- const res = await fetch(url)
88
- if (res.status >= 200 && res.status < 500) return
89
- } catch {
90
- // server not yet listening
91
- }
92
- await new Promise((r) => setTimeout(r, 150))
93
- }
94
- throw new Error(`timeout waiting for ${url}`)
95
- }
96
-
97
- export interface TestServer {
98
- home: string
99
- url: string
100
- token: string
101
- /** Run the CLI as a subprocess against this test server. */
102
- cli(args: string[], extraEnv?: NodeJS.ProcessEnv): Promise<CliResult>
103
- /**
104
- * Wipe per-test state (DB rows + on-disk profiles/agents/skills/groups dirs)
105
- * so the same daemon process can host multiple tests. Lets test files use
106
- * `beforeAll(start)` + `beforeEach(reset)` instead of paying daemon cold
107
- * start per test. The server's cached DB handle reads the post-reset state
108
- * immediately because SQLite WAL + same file. Preserves the bootstrap
109
- * web_tokens row so the CLI's bearer keeps working across tests.
110
- */
111
- reset(): void
112
- stop(): Promise<void>
113
- }
114
-
115
- const WIPE_SQL = `
116
- DELETE FROM messages;
117
- DELETE FROM agent_triggers;
118
- DELETE FROM agent_skills;
119
- DELETE FROM agents;
120
- DELETE FROM profile_default_skills;
121
- DELETE FROM profiles;
122
- DELETE FROM groups;
123
- DELETE FROM skill_meta;
124
- DELETE FROM provider_models;
125
- DELETE FROM provider_state;
126
- DELETE FROM secrets;
127
- DELETE FROM config;
128
- `
129
-
130
- function resetHome(home: string): void {
131
- const paths = resolvePaths(home)
132
- const db = openDb(paths.db)
133
- db.raw.exec(WIPE_SQL)
134
- // Re-enable lmstudio + ollama the same way initHome does — tests that mount
135
- // mock providers expect these enabled.
136
- providerStateRepo.setEnabled(db, 'lmstudio', true)
137
- providerStateRepo.setEnabled(db, 'ollama', true)
138
- // Re-curate the placeholder model so the first-run gate stays open.
139
- providerModelRepo.replace(db, 'lmstudio', ['test-model'])
140
- providerModelRepo.replace(db, 'ollama', ['test-model'])
141
- // Wipe + re-create the groups directory so the auto-seeded slot is fresh.
142
- rmSync(paths.groupsDir, { recursive: true, force: true })
143
- mkdirSync(paths.groupsDir, { recursive: true })
144
- registerGroup(db, { id: 'default', name: 'Default' }, paths)
145
- db.close()
146
- for (const dir of [paths.profilesDir, paths.agentsDir, paths.skillsDir]) {
147
- rmSync(dir, { recursive: true, force: true })
148
- mkdirSync(dir, { recursive: true })
149
- }
150
- }
151
-
152
- /**
153
- * Spawns the daemon on a free port with BAZILION_HOME pointing at a fresh
154
- * tempdir. Resolves once the server answers HTTP. Call `stop()` to kill the
155
- * process and clean up the tempdir.
156
- *
157
- * Additional env vars can be passed (e.g. `LMSTUDIO_URL` pointing at a mock
158
- * provider) — they're merged into the server's env.
159
- */
160
- export async function startTestServer(extraServerEnv: NodeJS.ProcessEnv = {}): Promise<TestServer> {
161
- const { home, token } = initHome()
162
- const port = await findFreePort()
163
- const url = `http://127.0.0.1:${port}`
164
-
165
- const proc: ChildProcess = spawn('node', ['--import', 'tsx/esm', daemonEntry], {
166
- env: {
167
- ...process.env,
168
- BAZILION_HOME: home,
169
- HOST: '127.0.0.1',
170
- PORT: String(port),
171
- ...extraServerEnv,
172
- },
173
- stdio: 'ignore',
174
- })
175
-
176
- try {
177
- // /api/health is unauthenticated — perfect liveness probe. Daemon should
178
- // come up in well under a second; 20s is paranoia headroom.
179
- await waitForHttp(`${url}/api/health`, 20_000)
180
- } catch (err) {
181
- proc.kill()
182
- rmSync(home, { recursive: true, force: true })
183
- throw err
184
- }
185
-
186
- return {
187
- home,
188
- url,
189
- token,
190
- cli(args, extraEnv = {}) {
191
- return runCli(args, home, {
192
- BAZILION_SERVER: url,
193
- BAZILION_TOKEN: token,
194
- ...extraEnv,
195
- })
196
- },
197
- reset() {
198
- resetHome(home)
199
- },
200
- async stop() {
201
- await new Promise<void>((resolve) => {
202
- proc.on('close', () => resolve())
203
- proc.kill('SIGTERM')
204
- // Failsafe: if the process hasn't exited in 5s, force it.
205
- setTimeout(() => {
206
- if (proc.exitCode === null) proc.kill('SIGKILL')
207
- }, 5_000)
208
- })
209
- rmSync(home, { recursive: true, force: true })
210
- },
211
- }
212
- }
@@ -1,45 +0,0 @@
1
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
2
- import { extractAgentId } from './helpers.ts'
3
- import { startTestServer, type TestServer } from './server-fixture.ts'
4
-
5
- let server: TestServer
6
- beforeAll(async () => {
7
- server = await startTestServer({ BAZILION_SCHEDULER: 'off' })
8
- })
9
- afterAll(() => server.stop())
10
- beforeEach(() => server.reset())
11
-
12
- test('agent session-head reports (no session yet) for a fresh agent', async () => {
13
- let r = await server.cli(['profile', 'create', 'p', '--model', 'anthropic:claude-opus-4-6'])
14
- expect(r.exitCode).toBe(0)
15
-
16
- r = await server.cli(['agent', 'spawn', '--profile', 'p', '--name', 'A'])
17
- expect(r.exitCode).toBe(0)
18
- const agentId = extractAgentId(r.stdout)
19
-
20
- r = await server.cli(['agent', 'session-head', agentId])
21
- expect(r.exitCode).toBe(0)
22
- expect(r.stdout).toContain('(no session yet)')
23
- })
24
-
25
- test('agent session-head --json emits the SessionHeadResponse shape', async () => {
26
- let r = await server.cli(['profile', 'create', 'p', '--model', 'anthropic:claude-opus-4-6'])
27
- expect(r.exitCode).toBe(0)
28
-
29
- r = await server.cli(['agent', 'spawn', '--profile', 'p', '--name', 'A'])
30
- expect(r.exitCode).toBe(0)
31
- const agentId = extractAgentId(r.stdout)
32
-
33
- r = await server.cli(['agent', 'session-head', agentId, '--json'])
34
- expect(r.exitCode).toBe(0)
35
- const body = JSON.parse(r.stdout) as { file: string | null; size: number }
36
- expect(body).toEqual({ file: null, size: 0 })
37
- })
38
-
39
- test('agent session-head returns 404 for an unknown agent', async () => {
40
- // Prefix matching needs at least 4 chars; use one that could not resolve.
41
- const r = await server.cli(['agent', 'session-head', 'deadbeef-no-such-agent'])
42
- expect(r.exitCode).not.toBe(0)
43
- // ApiClientError prints "error: agent not found: …"
44
- expect(r.stderr + r.stdout).toMatch(/not found/i)
45
- })
@@ -1,128 +0,0 @@
1
- import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import AdmZip from 'adm-zip'
5
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
6
- import { extractAgentId } from './helpers.ts'
7
- import { startTestServer, type TestServer } from './server-fixture.ts'
8
-
9
- let server: TestServer
10
- beforeAll(async () => {
11
- server = await startTestServer()
12
- })
13
- afterAll(() => server.stop())
14
- beforeEach(() => server.reset())
15
-
16
- function fixtureSkillsDir(skills: string[]): string {
17
- const root = mkdtempSync(join(tmpdir(), 'bazilion-skill-fixture-'))
18
- for (const name of skills) {
19
- const dir = join(root, name)
20
- mkdirSync(dir, { recursive: true })
21
- writeFileSync(
22
- join(dir, 'SKILL.md'),
23
- `---
24
- name: ${name}
25
- description: Test skill ${name}.
26
- ---
27
-
28
- body of ${name}
29
- `,
30
- )
31
- }
32
- return root
33
- }
34
-
35
- test('skill list shows nothing when none installed', async () => {
36
- const r = await server.cli(['skill', 'list'])
37
- expect(r.exitCode).toBe(0)
38
- expect(r.stdout).toContain('no skills installed')
39
- })
40
-
41
- test('skill import + list + rm round-trip', async () => {
42
- const source = fixtureSkillsDir(['alpha', 'beta'])
43
-
44
- let r = await server.cli(['skill', 'import', '--from', source])
45
- expect(r.exitCode).toBe(0)
46
- expect(r.stdout).toContain('imported alpha')
47
- expect(r.stdout).toContain('imported beta')
48
-
49
- r = await server.cli(['skill', 'list'])
50
- expect(r.stdout).toContain('alpha')
51
- expect(r.stdout).toContain('beta')
52
- expect(r.stdout).toContain('Test skill')
53
-
54
- r = await server.cli(['skill', 'rm', 'alpha'])
55
- expect(r.exitCode).toBe(0)
56
-
57
- r = await server.cli(['skill', 'list'])
58
- expect(r.stdout).not.toContain('alpha')
59
- expect(r.stdout).toContain('beta')
60
- })
61
-
62
- test('skill import skips existing without --force', async () => {
63
- const source = fixtureSkillsDir(['dup'])
64
- await server.cli(['skill', 'import', '--from', source])
65
-
66
- const r = await server.cli(['skill', 'import', '--from', source])
67
- expect(r.stdout).toContain('skipped dup')
68
- })
69
-
70
- test('skill import --from openclaw resolves to ~/.openclaw/skills', async () => {
71
- // We don't assume the user actually has skills there. We just check that
72
- // when ~/.openclaw/skills doesn't exist, the error message references the
73
- // path that the server (not the client) would resolve.
74
- const r = await server.cli(['skill', 'import', '--from', 'openclaw'])
75
- if (r.exitCode !== 0) {
76
- expect(r.stderr + r.stdout).toMatch(/\.openclaw/)
77
- }
78
- })
79
-
80
- test('skill list --agent shows attached skills with descriptions', async () => {
81
- const source = fixtureSkillsDir(['s1', 's2'])
82
- await server.cli(['skill', 'import', '--from', source])
83
-
84
- await server.cli(['profile', 'create', 'p', '--model', 'm', '--skills', 's1,s2'])
85
- let r = await server.cli(['agent', 'spawn', '--profile', 'p'])
86
- const id = extractAgentId(r.stdout)
87
-
88
- r = await server.cli(['skill', 'list', '--agent', id])
89
- expect(r.stdout).toContain('s1')
90
- expect(r.stdout).toContain('s2')
91
- expect(r.stdout).toContain('Test skill s1')
92
- })
93
-
94
- test('skill list --agent reports missing skills', async () => {
95
- await server.cli(['profile', 'create', 'p', '--model', 'm', '--skills', 'ghost'])
96
- let r = await server.cli(['agent', 'spawn', '--profile', 'p'])
97
- const id = extractAgentId(r.stdout)
98
-
99
- r = await server.cli(['skill', 'list', '--agent', id])
100
- expect(r.stdout).toContain('missing: ghost')
101
- })
102
-
103
- function fixtureSkillsZip(skills: string[]): string {
104
- const zip = new AdmZip()
105
- for (const name of skills) {
106
- zip.addFile(
107
- `${name}/SKILL.md`,
108
- Buffer.from(`---\nname: ${name}\ndescription: Test skill ${name}.\n---\n\nbody of ${name}\n`),
109
- )
110
- }
111
- const dir = mkdtempSync(join(tmpdir(), 'bazilion-skill-zip-fixture-'))
112
- const zipPath = join(dir, 'skills.zip')
113
- zip.writeZip(zipPath)
114
- return zipPath
115
- }
116
-
117
- test('skill import --from <local.zip> uploads via multipart and installs every skill', async () => {
118
- const zipPath = fixtureSkillsZip(['zapha', 'zbeta'])
119
-
120
- let r = await server.cli(['skill', 'import', '--from', zipPath])
121
- expect(r.exitCode).toBe(0)
122
- expect(r.stdout).toContain('imported zapha')
123
- expect(r.stdout).toContain('imported zbeta')
124
-
125
- r = await server.cli(['skill', 'list'])
126
- expect(r.stdout).toContain('zapha')
127
- expect(r.stdout).toContain('zbeta')
128
- })
@@ -1,109 +0,0 @@
1
- import { readFileSync, writeFileSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'
4
- import { startTestServer, type TestServer } from './server-fixture.ts'
5
-
6
- let server: TestServer
7
-
8
- beforeAll(async () => {
9
- server = await startTestServer()
10
- })
11
-
12
- afterAll(async () => {
13
- await server.stop()
14
- })
15
- beforeEach(() => server.reset())
16
-
17
- test('token show-local prints the bootstrap token from auth.json', async () => {
18
- const raw = readFileSync(join(server.home, 'auth.json'), 'utf8')
19
- const expected = JSON.parse(raw).token as string
20
- expect(typeof expected).toBe('string')
21
-
22
- const res = await server.cli(['token', 'show-local'])
23
- expect(res.exitCode).toBe(0)
24
- expect(res.stdout.trim()).toBe(expected)
25
- })
26
-
27
- test('token create mints a token and prints the plaintext exactly once', async () => {
28
- const res = await server.cli(['token', 'create', 'laptop'])
29
- expect(res.exitCode).toBe(0)
30
- expect(res.stdout).toMatch(/label: laptop/)
31
- expect(res.stdout).toMatch(/token: [0-9a-f]{48}/)
32
- expect(res.stdout).toMatch(/id: /)
33
- })
34
-
35
- test('token list shows active tokens and hides revoked by default', async () => {
36
- const createA = await server.cli(['token', 'create', 'alpha'])
37
- const idA = createA.stdout.match(/id:\s+([\w-]+)/)?.[1] as string
38
- await server.cli(['token', 'create', 'beta'])
39
- const revoke = await server.cli(['token', 'revoke', idA])
40
- expect(revoke.exitCode).toBe(0)
41
-
42
- const activeList = await server.cli(['token', 'list'])
43
- expect(activeList.stdout).not.toContain(idA)
44
- expect(activeList.stdout).toContain('beta')
45
-
46
- const allList = await server.cli(['token', 'list', '--all'])
47
- expect(allList.stdout).toContain(idA)
48
- expect(allList.stdout).toContain('revoked')
49
- })
50
-
51
- test('a minted token authenticates subsequent API calls', async () => {
52
- const create = await server.cli(['token', 'create', 'laptop'])
53
- const token = create.stdout.match(/token:\s+([0-9a-f]+)/)?.[1] as string
54
- expect(token).toBeTruthy()
55
-
56
- const res = await fetch(`${server.url}/api/profiles`, {
57
- headers: { cookie: `bz_token=${token}` },
58
- })
59
- expect(res.status).toBe(200)
60
- })
61
-
62
- test('revoked tokens are rejected', async () => {
63
- const create = await server.cli(['token', 'create', 'burn'])
64
- const token = create.stdout.match(/token:\s+([0-9a-f]+)/)?.[1] as string
65
- const id = create.stdout.match(/id:\s+([\w-]+)/)?.[1] as string
66
- await server.cli(['token', 'revoke', id])
67
-
68
- const res = await fetch(`${server.url}/api/profiles`, {
69
- headers: { cookie: `bz_token=${token}` },
70
- })
71
- expect(res.status).toBe(401)
72
- })
73
-
74
- test('login --server --token verifies and writes remote to auth.json', async () => {
75
- const create = await server.cli(['token', 'create', 'remote'])
76
- const token = create.stdout.match(/token:\s+([0-9a-f]+)/)?.[1] as string
77
-
78
- // login runs against `server.home` — bypass the env-var short-circuit by
79
- // not setting BAZILION_SERVER/TOKEN for this specific invocation.
80
- const login = await server.cli(['login', '--server', server.url, '--token', token], {
81
- BAZILION_SERVER: '',
82
- BAZILION_TOKEN: '',
83
- })
84
- expect(login.exitCode).toBe(0)
85
- expect(login.stdout).toMatch(/saved remote/)
86
-
87
- const configPath = join(server.home, 'auth.json')
88
- const config = JSON.parse(readFileSync(configPath, 'utf8')) as {
89
- remote?: { server: string; token: string }
90
- }
91
- expect(config.remote?.server).toBe(server.url)
92
- expect(config.remote?.token).toBe(token)
93
- })
94
-
95
- test('login --clear removes the stored remote', async () => {
96
- const configPath = join(server.home, 'auth.json')
97
- const existing = JSON.parse(readFileSync(configPath, 'utf8')) as Record<string, unknown>
98
- existing.remote = { server: 'http://example.invalid', token: 'abc' }
99
- writeFileSync(configPath, `${JSON.stringify(existing, null, 2)}\n`)
100
-
101
- const clear = await server.cli(
102
- ['login', '--server', 'http://example.invalid', '--token', 'x', '--clear'],
103
- { BAZILION_SERVER: '', BAZILION_TOKEN: '' },
104
- )
105
- expect(clear.exitCode).toBe(0)
106
-
107
- const after = JSON.parse(readFileSync(configPath, 'utf8')) as { remote?: unknown }
108
- expect(after.remote).toBeUndefined()
109
- })