bazilion 0.0.0 → 0.1.1

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 +6460 -0
  5. package/dist/daemon.js.map +1 -0
  6. package/dist/worker.js +2176 -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,182 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from 'vitest'
2
- import * as agentRepo from '../../src/core/repos/agents.ts'
3
- import * as profileRepo from '../../src/core/repos/profiles.ts'
4
- import * as triggerRepo from '../../src/core/repos/triggers.ts'
5
- import { makeTestEnv, type TestEnv } from './helpers.ts'
6
-
7
- let env: TestEnv
8
- let agentId: string
9
-
10
- beforeEach(() => {
11
- env = makeTestEnv()
12
- profileRepo.insert(env.db, {
13
- id: 'p',
14
- name: 'p',
15
- dir: env.paths.profileDir('p'),
16
- defaultModel: 'lmstudio:x',
17
- skillsMode: 'selected',
18
- })
19
- const a = agentRepo.insert(env.db, {
20
- id: 'a1',
21
- profileId: 'p',
22
- name: 'A',
23
- modelOverride: null,
24
- reasoningLevel: 'medium',
25
- status: 'idle',
26
- dir: env.paths.agentDir('a1'),
27
- groupId: env.groupId,
28
- })
29
- agentId = a.id
30
- })
31
- afterEach(() => env.cleanup())
32
-
33
- test('insert + get + listForAgent round-trip for interval trigger', () => {
34
- const t = triggerRepo.insert(env.db, {
35
- agentId,
36
- kind: 'interval',
37
- intervalSec: 60,
38
- cronExpr: null,
39
- message: 'tick',
40
- })
41
- expect(t.kind).toBe('interval')
42
- expect(t.intervalSec).toBe(60)
43
- expect(t.enabled).toBe(true)
44
- expect(t.lastFiredAt).toBeNull()
45
-
46
- const fetched = triggerRepo.get(env.db, t.id)
47
- expect(fetched?.message).toBe('tick')
48
-
49
- const list = triggerRepo.listForAgent(env.db, agentId)
50
- expect(list).toHaveLength(1)
51
- expect(list[0]?.id).toBe(t.id)
52
- })
53
-
54
- test('cron triggers store cronExpr and null intervalSec', () => {
55
- const t = triggerRepo.insert(env.db, {
56
- agentId,
57
- kind: 'cron',
58
- intervalSec: null,
59
- cronExpr: '*/5 * * * *',
60
- message: 'tick',
61
- })
62
- expect(t.cronExpr).toBe('*/5 * * * *')
63
- expect(t.intervalSec).toBeNull()
64
- })
65
-
66
- test('enabled=false disables at insert', () => {
67
- const t = triggerRepo.insert(env.db, {
68
- agentId,
69
- kind: 'interval',
70
- intervalSec: 30,
71
- cronExpr: null,
72
- message: 'tick',
73
- enabled: false,
74
- })
75
- expect(t.enabled).toBe(false)
76
- })
77
-
78
- test('setEnabled toggles the enabled flag', () => {
79
- const t = triggerRepo.insert(env.db, {
80
- agentId,
81
- kind: 'interval',
82
- intervalSec: 30,
83
- cronExpr: null,
84
- message: 'tick',
85
- })
86
- triggerRepo.setEnabled(env.db, t.id, false)
87
- expect(triggerRepo.get(env.db, t.id)?.enabled).toBe(false)
88
- triggerRepo.setEnabled(env.db, t.id, true)
89
- expect(triggerRepo.get(env.db, t.id)?.enabled).toBe(true)
90
- })
91
-
92
- test('markFired populates lastFiredAt', () => {
93
- const t = triggerRepo.insert(env.db, {
94
- agentId,
95
- kind: 'interval',
96
- intervalSec: 30,
97
- cronExpr: null,
98
- message: 'tick',
99
- })
100
- const when = Date.now() + 10_000
101
- triggerRepo.markFired(env.db, t.id, when)
102
- expect(triggerRepo.get(env.db, t.id)?.lastFiredAt).toBe(when)
103
- })
104
-
105
- test('remove deletes the trigger', () => {
106
- const t = triggerRepo.insert(env.db, {
107
- agentId,
108
- kind: 'interval',
109
- intervalSec: 30,
110
- cronExpr: null,
111
- message: 'tick',
112
- })
113
- triggerRepo.remove(env.db, t.id)
114
- expect(triggerRepo.get(env.db, t.id)).toBeNull()
115
- })
116
-
117
- test('listEnabled filters out disabled rows', () => {
118
- triggerRepo.insert(env.db, {
119
- agentId,
120
- kind: 'interval',
121
- intervalSec: 30,
122
- cronExpr: null,
123
- message: 'on',
124
- })
125
- triggerRepo.insert(env.db, {
126
- agentId,
127
- kind: 'interval',
128
- intervalSec: 60,
129
- cronExpr: null,
130
- message: 'off',
131
- enabled: false,
132
- })
133
- const enabled = triggerRepo.listEnabled(env.db)
134
- expect(enabled).toHaveLength(1)
135
- expect(enabled[0]?.message).toBe('on')
136
- })
137
-
138
- test('listEnabled excludes triggers on archived agents', () => {
139
- const other = agentRepo.insert(env.db, {
140
- id: 'a2',
141
- profileId: 'p',
142
- name: 'B',
143
- modelOverride: null,
144
- reasoningLevel: 'medium',
145
- status: 'idle',
146
- dir: env.paths.agentDir('a2'),
147
- groupId: env.groupId,
148
- })
149
- triggerRepo.insert(env.db, {
150
- agentId,
151
- kind: 'interval',
152
- intervalSec: 30,
153
- cronExpr: null,
154
- message: 'live',
155
- })
156
- triggerRepo.insert(env.db, {
157
- agentId: other.id,
158
- kind: 'interval',
159
- intervalSec: 30,
160
- cronExpr: null,
161
- message: 'archived',
162
- })
163
- agentRepo.archive(env.db, other.id)
164
- const enabled = triggerRepo.listEnabled(env.db)
165
- expect(enabled).toHaveLength(1)
166
- expect(enabled[0]?.message).toBe('live')
167
- })
168
-
169
- describe('ON DELETE CASCADE', () => {
170
- test('deleting the agent removes its triggers', () => {
171
- triggerRepo.insert(env.db, {
172
- agentId,
173
- kind: 'interval',
174
- intervalSec: 30,
175
- cronExpr: null,
176
- message: 'tick',
177
- })
178
- expect(triggerRepo.listForAgent(env.db, agentId)).toHaveLength(1)
179
- agentRepo.remove(env.db, agentId)
180
- expect(triggerRepo.listForAgent(env.db, agentId)).toHaveLength(0)
181
- })
182
- })
@@ -1,79 +0,0 @@
1
- import { beforeEach, describe, expect, test } from 'vitest'
2
- import {
3
- type BazilionDb,
4
- openInMemoryDb,
5
- runMigrations,
6
- webTokenRepo,
7
- } from '../../src/core/index.ts'
8
-
9
- let db: BazilionDb
10
- beforeEach(() => {
11
- db = openInMemoryDb()
12
- runMigrations(db)
13
- })
14
-
15
- describe('webTokenRepo', () => {
16
- test('create returns plaintext + metadata; plaintext is never re-queryable', () => {
17
- const out = webTokenRepo.create(db, 'laptop')
18
- expect(out.token).toMatch(/^[0-9a-f]{48}$/)
19
- expect(out.meta.label).toBe('laptop')
20
- expect(out.meta.revokedAt).toBe(null)
21
- expect(out.meta.lastUsedAt).toBe(null)
22
-
23
- // list() returns meta only — no plaintext
24
- const listed = webTokenRepo.list(db)
25
- expect(listed).toHaveLength(1)
26
- expect((listed[0] as unknown as { token?: unknown }).token).toBeUndefined()
27
- })
28
-
29
- test('findActiveByToken matches the plaintext and excludes revoked rows', () => {
30
- const { token, meta } = webTokenRepo.create(db, 'laptop')
31
- const match = webTokenRepo.findActiveByToken(db, token)
32
- expect(match?.id).toBe(meta.id)
33
-
34
- webTokenRepo.revoke(db, meta.id)
35
- expect(webTokenRepo.findActiveByToken(db, token)).toBe(null)
36
- })
37
-
38
- test('findActiveByToken returns null for unknown tokens', () => {
39
- webTokenRepo.create(db, 'laptop')
40
- expect(webTokenRepo.findActiveByToken(db, 'wrong')).toBe(null)
41
- })
42
-
43
- test('markUsed updates last_used_at', () => {
44
- const { meta } = webTokenRepo.create(db, 'laptop')
45
- const when = Date.now() + 10_000
46
- webTokenRepo.markUsed(db, meta.id, when)
47
- expect(webTokenRepo.get(db, meta.id)?.lastUsedAt).toBe(when)
48
- })
49
-
50
- test('revoke is idempotent — second revoke reports no change', () => {
51
- const { meta } = webTokenRepo.create(db, 'laptop')
52
- expect(webTokenRepo.revoke(db, meta.id)).toBe(true)
53
- expect(webTokenRepo.revoke(db, meta.id)).toBe(false)
54
- expect(webTokenRepo.get(db, meta.id)?.revokedAt).toBeTruthy()
55
- })
56
-
57
- test('list hides revoked tokens by default but reveals them with includeRevoked', () => {
58
- webTokenRepo.create(db, 'a')
59
- const b = webTokenRepo.create(db, 'b')
60
- webTokenRepo.revoke(db, b.meta.id)
61
- expect(webTokenRepo.list(db).map((t) => t.label)).toEqual(['a'])
62
- expect(webTokenRepo.list(db, { includeRevoked: true }).map((t) => t.label)).toEqual(['a', 'b'])
63
- })
64
-
65
- test('plaintext token is stored as a hash, not in the clear', () => {
66
- const { token } = webTokenRepo.create(db, 'laptop')
67
- const row = db.raw
68
- .query<{ token_hash: string }, []>('SELECT token_hash FROM web_tokens LIMIT 1')
69
- .get()
70
- expect(row?.token_hash).not.toBe(token)
71
- expect(row?.token_hash).toBe(webTokenRepo.hashToken(token))
72
- })
73
-
74
- test('two tokens with the same label coexist (label is not a primary key)', () => {
75
- webTokenRepo.create(db, 'laptop')
76
- expect(() => webTokenRepo.create(db, 'laptop')).not.toThrow()
77
- expect(webTokenRepo.list(db)).toHaveLength(2)
78
- })
79
- })
@@ -1,90 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { matchesCron, parseCron, validateCron } from '../src/lib/cron.ts'
3
-
4
- function at(y: number, mo: number, d: number, h: number, mi: number, dow?: number): Date {
5
- // Local time — matches what matchesCron reads via getMinutes / getHours / etc.
6
- // dow is ignored; JS computes it from the date itself.
7
- void dow
8
- return new Date(y, mo - 1, d, h, mi, 0, 0)
9
- }
10
-
11
- describe('parseCron syntax', () => {
12
- test('star-only', () => {
13
- expect(() => parseCron('* * * * *')).not.toThrow()
14
- })
15
- test('step', () => {
16
- const p = parseCron('*/15 * * * *')
17
- expect(p.minute.has(0)).toBe(true)
18
- expect(p.minute.has(15)).toBe(true)
19
- expect(p.minute.has(30)).toBe(true)
20
- expect(p.minute.has(45)).toBe(true)
21
- expect(p.minute.has(10)).toBe(false)
22
- })
23
- test('list', () => {
24
- const p = parseCron('0,30 * * * *')
25
- expect(p.minute.has(0)).toBe(true)
26
- expect(p.minute.has(30)).toBe(true)
27
- expect(p.minute.has(15)).toBe(false)
28
- })
29
- test('range', () => {
30
- const p = parseCron('10-15 * * * *')
31
- expect(p.minute.has(10)).toBe(true)
32
- expect(p.minute.has(15)).toBe(true)
33
- expect(p.minute.has(16)).toBe(false)
34
- })
35
- test('range with step', () => {
36
- const p = parseCron('0-30/10 * * * *')
37
- expect(p.minute.has(0)).toBe(true)
38
- expect(p.minute.has(10)).toBe(true)
39
- expect(p.minute.has(20)).toBe(true)
40
- expect(p.minute.has(30)).toBe(true)
41
- expect(p.minute.has(40)).toBe(false)
42
- })
43
- test('Sunday normalization (7 → 0)', () => {
44
- const p = parseCron('0 0 * * 7')
45
- expect(p.dow.has(0)).toBe(true)
46
- })
47
- test('rejects 4 fields', () => {
48
- expect(() => parseCron('* * * *')).toThrow(/5 fields/)
49
- })
50
- test('rejects out-of-range minute', () => {
51
- expect(() => parseCron('60 * * * *')).toThrow(/out of range/)
52
- })
53
- test('rejects garbage', () => {
54
- expect(() => parseCron('foo * * * *')).toThrow()
55
- })
56
- test('validateCron throws on bad input', () => {
57
- expect(() => validateCron('* * * *')).toThrow()
58
- })
59
- })
60
-
61
- describe('matchesCron semantics', () => {
62
- test('every minute matches any minute', () => {
63
- const p = parseCron('* * * * *')
64
- expect(matchesCron(p, at(2026, 4, 17, 14, 37))).toBe(true)
65
- })
66
- test('every 5 minutes matches minute 25', () => {
67
- const p = parseCron('*/5 * * * *')
68
- expect(matchesCron(p, at(2026, 4, 17, 14, 25))).toBe(true)
69
- expect(matchesCron(p, at(2026, 4, 17, 14, 26))).toBe(false)
70
- })
71
- test('hour-restricted fires only in that hour', () => {
72
- const p = parseCron('0 9 * * *')
73
- expect(matchesCron(p, at(2026, 4, 17, 9, 0))).toBe(true)
74
- expect(matchesCron(p, at(2026, 4, 17, 9, 1))).toBe(false)
75
- expect(matchesCron(p, at(2026, 4, 17, 10, 0))).toBe(false)
76
- })
77
- test('dow-only fires on that weekday', () => {
78
- // 2026-04-17 is a Friday (dow=5).
79
- const p = parseCron('0 0 * * 5')
80
- expect(matchesCron(p, at(2026, 4, 17, 0, 0))).toBe(true)
81
- expect(matchesCron(p, at(2026, 4, 18, 0, 0))).toBe(false)
82
- })
83
- test('dom+dow restricted => OR semantics (standard cron)', () => {
84
- // Every Friday OR the 15th. 2026-04-17 = Friday, 2026-04-15 = 15th (Wed).
85
- const p = parseCron('0 0 15 * 5')
86
- expect(matchesCron(p, at(2026, 4, 17, 0, 0))).toBe(true) // Fri
87
- expect(matchesCron(p, at(2026, 4, 15, 0, 0))).toBe(true) // 15th
88
- expect(matchesCron(p, at(2026, 4, 16, 0, 0))).toBe(false)
89
- })
90
- })
@@ -1,34 +0,0 @@
1
- import { expect, test } from 'vitest'
2
- import {
3
- HEARTBEAT_PROMPT,
4
- isHeartbeatContentEffectivelyEmpty,
5
- resolveHeartbeatPrompt,
6
- } from '../../src/runtime/auto-reply/heartbeat.ts'
7
-
8
- test('resolveHeartbeatPrompt falls back to the canned prompt when raw is empty', () => {
9
- expect(resolveHeartbeatPrompt()).toBe(HEARTBEAT_PROMPT)
10
- expect(resolveHeartbeatPrompt('')).toBe(HEARTBEAT_PROMPT)
11
- expect(resolveHeartbeatPrompt(' \n ')).toBe(HEARTBEAT_PROMPT)
12
- expect(resolveHeartbeatPrompt(null)).toBe(HEARTBEAT_PROMPT)
13
- })
14
-
15
- test('resolveHeartbeatPrompt preserves a custom non-empty prompt', () => {
16
- expect(resolveHeartbeatPrompt('do a thing')).toBe('do a thing')
17
- })
18
-
19
- test('isHeartbeatContentEffectivelyEmpty treats comments/bullets as empty', () => {
20
- expect(isHeartbeatContentEffectivelyEmpty('')).toBe(true)
21
- expect(isHeartbeatContentEffectivelyEmpty('# only header\n\n## subheader\n')).toBe(true)
22
- expect(isHeartbeatContentEffectivelyEmpty('- [ ]\n- [x]\n* [ ]\n+ \n')).toBe(true)
23
- })
24
-
25
- test('isHeartbeatContentEffectivelyEmpty detects actionable content', () => {
26
- expect(isHeartbeatContentEffectivelyEmpty('- [ ] check inbox')).toBe(false)
27
- expect(isHeartbeatContentEffectivelyEmpty('follow up with user')).toBe(false)
28
- expect(isHeartbeatContentEffectivelyEmpty('#TODO sneaky')).toBe(false) // not an ATX header (no space)
29
- })
30
-
31
- test('isHeartbeatContentEffectivelyEmpty treats non-strings as non-empty (let the LLM decide)', () => {
32
- expect(isHeartbeatContentEffectivelyEmpty(null)).toBe(false)
33
- expect(isHeartbeatContentEffectivelyEmpty(undefined)).toBe(false)
34
- })
@@ -1,97 +0,0 @@
1
- import { existsSync, mkdtempSync, rmSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import { afterEach, beforeEach, expect, test } from 'vitest'
5
- import { qmdBackend } from '../../src/runtime/memory/qmd.ts'
6
- import type { MemoryBackend } from '../../src/runtime/memory/types.ts'
7
-
8
- let root: string
9
- let mem: MemoryBackend
10
-
11
- beforeEach(async () => {
12
- root = mkdtempSync(join(tmpdir(), 'bazilion-mem-qmd-'))
13
- mem = qmdBackend(root)
14
- await mem.init()
15
- })
16
- afterEach(() => rmSync(root, { recursive: true, force: true }))
17
-
18
- test('write then read returns the content', async () => {
19
- await mem.write('notes.md', 'hello world')
20
- const entry = await mem.read('notes.md')
21
- expect(entry.content).toBe('hello world')
22
- expect(entry.key).toBe('notes.md')
23
- })
24
-
25
- test('write to nested key creates directories', async () => {
26
- await mem.write('daily/2026-04-11.md', 'today')
27
- expect(existsSync(join(root, 'daily', '2026-04-11.md'))).toBe(true)
28
- const entry = await mem.read('daily/2026-04-11.md')
29
- expect(entry.content).toBe('today')
30
- })
31
-
32
- test('read missing key throws', async () => {
33
- await expect(mem.read('ghost.md')).rejects.toThrow(/not found/)
34
- })
35
-
36
- test('list returns all entries sorted by key', async () => {
37
- await mem.write('b.md', 'two')
38
- await mem.write('a.md', 'one')
39
- await mem.write('nested/c.md', 'three')
40
- const all = await mem.list()
41
- expect(all.map((e) => e.key)).toEqual(['a.md', 'b.md', 'nested/c.md'])
42
- })
43
-
44
- test('list ignores the .qmd-index.sqlite file', async () => {
45
- await mem.write('a.md', 'one')
46
- // After init(), the index file exists alongside the markdown
47
- expect(existsSync(join(root, '.qmd-index.sqlite'))).toBe(true)
48
- const all = await mem.list()
49
- expect(all.map((e) => e.key)).toEqual(['a.md'])
50
- })
51
-
52
- test('search returns matching entries via BM25', async () => {
53
- await mem.write('colors.md', 'My favorite color is blue.')
54
- await mem.write('food.md', 'I like pasta and pizza.')
55
- await mem.write('other.md', 'unrelated content')
56
-
57
- const hits = await mem.search('color')
58
- expect(hits.length).toBeGreaterThanOrEqual(1)
59
- expect(hits[0]?.key).toBe('colors.md')
60
- expect(hits[0]?.snippet.toLowerCase()).toContain('color')
61
- })
62
-
63
- test('search scores more relevant documents higher', async () => {
64
- await mem.write('a.md', 'pizza pizza pizza')
65
- await mem.write('b.md', 'I once ate pizza years ago')
66
- const hits = await mem.search('pizza')
67
- expect(hits.length).toBeGreaterThanOrEqual(2)
68
- // BM25 should rank the term-dense doc first.
69
- expect(hits[0]?.key).toBe('a.md')
70
- })
71
-
72
- test('remove deletes the entry and drops it from search', async () => {
73
- await mem.write('temp.md', 'tmp content with pizza')
74
- let hits = await mem.search('pizza')
75
- expect(hits.length).toBe(1)
76
-
77
- await mem.remove('temp.md')
78
- expect(existsSync(join(root, 'temp.md'))).toBe(false)
79
-
80
- hits = await mem.search('pizza')
81
- expect(hits.length).toBe(0)
82
- })
83
-
84
- test('rejects unsafe keys with path traversal', async () => {
85
- await expect(mem.write('../../../etc/passwd', 'x')).rejects.toThrow(/unsafe/)
86
- await expect(mem.write('/abs/path', 'x')).rejects.toThrow(/unsafe/)
87
- })
88
-
89
- test('persistence: a new backend instance sees previously written entries', async () => {
90
- await mem.write('persist.md', 'survives restart')
91
- const fresh = qmdBackend(root)
92
- await fresh.init()
93
- const entry = await fresh.read('persist.md')
94
- expect(entry.content).toBe('survives restart')
95
- const hits = await fresh.search('survives')
96
- expect(hits.length).toBeGreaterThanOrEqual(1)
97
- })
@@ -1,78 +0,0 @@
1
- import { existsSync, mkdtempSync, rmSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import { afterEach, beforeEach, expect, test } from 'vitest'
5
- import { filesBackend } from '../../src/runtime/memory/files.ts'
6
- import type { MemoryBackend } from '../../src/runtime/memory/types.ts'
7
-
8
- let root: string
9
- let mem: MemoryBackend
10
-
11
- beforeEach(async () => {
12
- root = mkdtempSync(join(tmpdir(), 'bazilion-mem-'))
13
- mem = filesBackend(root)
14
- await mem.init()
15
- })
16
- afterEach(() => rmSync(root, { recursive: true, force: true }))
17
-
18
- test('write then read returns the content', async () => {
19
- await mem.write('notes.md', 'hello world')
20
- const entry = await mem.read('notes.md')
21
- expect(entry.content).toBe('hello world')
22
- expect(entry.key).toBe('notes.md')
23
- })
24
-
25
- test('write to nested key creates directories', async () => {
26
- await mem.write('daily/2026-04-11.md', 'today')
27
- expect(existsSync(join(root, 'daily', '2026-04-11.md'))).toBe(true)
28
- const entry = await mem.read('daily/2026-04-11.md')
29
- expect(entry.content).toBe('today')
30
- })
31
-
32
- test('read missing key throws', async () => {
33
- await expect(mem.read('ghost.md')).rejects.toThrow(/not found/)
34
- })
35
-
36
- test('list returns all entries sorted by key', async () => {
37
- await mem.write('b.md', 'two')
38
- await mem.write('a.md', 'one')
39
- await mem.write('nested/c.md', 'three')
40
- const all = await mem.list()
41
- expect(all.map((e) => e.key)).toEqual(['a.md', 'b.md', 'nested/c.md'])
42
- })
43
-
44
- test('search returns matching entries with snippets', async () => {
45
- await mem.write('colors.md', 'My favorite color is blue.')
46
- await mem.write('food.md', 'I like pasta and pizza.')
47
- await mem.write('other.md', 'unrelated content')
48
-
49
- const hits = await mem.search('color')
50
- expect(hits.length).toBe(1)
51
- expect(hits[0]?.key).toBe('colors.md')
52
- expect(hits[0]?.snippet).toContain('color')
53
- })
54
-
55
- test('search is case-insensitive', async () => {
56
- await mem.write('x.md', 'BLUE is a color')
57
- const hits = await mem.search('blue')
58
- expect(hits.length).toBe(1)
59
- })
60
-
61
- test('remove deletes the entry', async () => {
62
- await mem.write('temp.md', 'tmp')
63
- await mem.remove('temp.md')
64
- expect(existsSync(join(root, 'temp.md'))).toBe(false)
65
- })
66
-
67
- test('rejects unsafe keys with path traversal', async () => {
68
- await expect(mem.write('../../../etc/passwd', 'x')).rejects.toThrow(/unsafe/)
69
- await expect(mem.write('/abs/path', 'x')).rejects.toThrow(/unsafe/)
70
- })
71
-
72
- test('persistence: a new backend instance sees previously written entries', async () => {
73
- await mem.write('persist.md', 'survives')
74
- const fresh = filesBackend(root)
75
- await fresh.init()
76
- const entry = await fresh.read('persist.md')
77
- expect(entry.content).toBe('survives')
78
- })