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,121 +0,0 @@
1
- // OpenAI ChatGPT / Codex OAuth — token storage + refresh on top of pi-ai.
2
- //
3
- // Pi-ai ships a complete OAuth flow for the ChatGPT backend (`@mariozechner/pi-ai`
4
- // exports `loginOpenAICodex` + `refreshOpenAICodexToken`), so this module is
5
- // thin: it adapts the credential I/O to Bazilion's encrypted secrets store
6
- // and exposes a single `loadAccessToken(db, authToken)` call that refreshes
7
- // when the token is about to expire.
8
- //
9
- // Storage: the JSON blob `{refresh, access, expires}` lives under the
10
- // secrets key `OPENAI_CODEX_OAUTH` in the `secrets` table. The blob is
11
- // never copied into the env (unlike plain-API-key providers) — refresh is
12
- // stateful, so every call reads and writes through the live secrets store.
13
-
14
- import type { OpenAICodexStatus } from '@bazilion/api-types'
15
- import type { OAuthCredentials } from '@mariozechner/pi-ai'
16
- import { loginOpenAICodex, refreshOpenAICodexToken } from '@mariozechner/pi-ai/oauth'
17
- import { type BazilionDb, openSecrets } from '../../core/index.ts'
18
-
19
- export const OPENAI_CODEX_SECRET_KEY = 'OPENAI_CODEX_OAUTH'
20
-
21
- /** Refresh when the access token has less than this much life left. */
22
- const REFRESH_MARGIN_MS = 60_000
23
-
24
- export interface StoredCredentials {
25
- refresh: string
26
- access: string
27
- expires: number
28
- }
29
-
30
- function readCredentials(db: BazilionDb, authToken: string): StoredCredentials | null {
31
- const raw = openSecrets(db, authToken).get(OPENAI_CODEX_SECRET_KEY)
32
- if (!raw) return null
33
- try {
34
- const parsed = JSON.parse(raw) as Partial<StoredCredentials>
35
- if (
36
- typeof parsed.refresh === 'string' &&
37
- typeof parsed.access === 'string' &&
38
- typeof parsed.expires === 'number'
39
- ) {
40
- return { refresh: parsed.refresh, access: parsed.access, expires: parsed.expires }
41
- }
42
- return null
43
- } catch {
44
- return null
45
- }
46
- }
47
-
48
- function writeCredentials(db: BazilionDb, authToken: string, creds: StoredCredentials): void {
49
- openSecrets(db, authToken).set(OPENAI_CODEX_SECRET_KEY, JSON.stringify(creds))
50
- }
51
-
52
- export function clearCredentials(db: BazilionDb, authToken: string): void {
53
- openSecrets(db, authToken).remove(OPENAI_CODEX_SECRET_KEY)
54
- }
55
-
56
- export function hasCredentials(db: BazilionDb, authToken: string): boolean {
57
- return readCredentials(db, authToken) !== null
58
- }
59
-
60
- function decodeAccountId(accessToken: string): string | null {
61
- const parts = accessToken.split('.')
62
- if (parts.length !== 3) return null
63
- try {
64
- const payload = JSON.parse(Buffer.from(parts[1] as string, 'base64').toString('utf8')) as {
65
- 'https://api.openai.com/auth'?: { chatgpt_account_id?: string }
66
- }
67
- return payload['https://api.openai.com/auth']?.chatgpt_account_id ?? null
68
- } catch {
69
- return null
70
- }
71
- }
72
-
73
- export function getStatus(db: BazilionDb, authToken: string): OpenAICodexStatus {
74
- const creds = readCredentials(db, authToken)
75
- if (!creds) return { connected: false, expiresAt: null, accountId: null }
76
- return {
77
- connected: true,
78
- expiresAt: creds.expires,
79
- accountId: decodeAccountId(creds.access),
80
- }
81
- }
82
-
83
- /**
84
- * Returns a valid access token, refreshing via pi-ai if the stored one is
85
- * within `REFRESH_MARGIN_MS` of expiry. Throws when no credentials are stored
86
- * so callers can surface an actionable "run `bazilion auth openai login`"
87
- * error rather than a 401 from the upstream API.
88
- */
89
- export async function loadAccessToken(db: BazilionDb, authToken: string): Promise<string> {
90
- const creds = readCredentials(db, authToken)
91
- if (!creds) {
92
- throw new Error(
93
- 'OpenAI ChatGPT OAuth not configured — run `bazilion auth openai login` (or use the Connect button on /config)',
94
- )
95
- }
96
- if (creds.expires > Date.now() + REFRESH_MARGIN_MS) return creds.access
97
-
98
- const refreshed = (await refreshOpenAICodexToken(creds.refresh)) as OAuthCredentials
99
- const next: StoredCredentials = {
100
- refresh: refreshed.refresh,
101
- access: refreshed.access,
102
- expires: refreshed.expires,
103
- }
104
- writeCredentials(db, authToken, next)
105
- return next.access
106
- }
107
-
108
- /** Persist credentials fetched by pi-ai's `loginOpenAICodex`. */
109
- export function saveLoginCredentials(
110
- db: BazilionDb,
111
- authToken: string,
112
- creds: OAuthCredentials,
113
- ): void {
114
- writeCredentials(db, authToken, {
115
- refresh: creds.refresh,
116
- access: creds.access,
117
- expires: creds.expires,
118
- })
119
- }
120
-
121
- export { loginOpenAICodex, refreshOpenAICodexToken }
@@ -1,31 +0,0 @@
1
- // Default heartbeat prompt. Users paste this constant as a trigger's
2
- // `message` (or call `resolveHeartbeatPrompt` with a custom one) to wire
3
- // HEARTBEAT.md into a scheduled wake-up without reinventing the framing.
4
- export const HEARTBEAT_PROMPT =
5
- 'Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.'
6
-
7
- export const DEFAULT_HEARTBEAT_EVERY_SEC = 30 * 60
8
-
9
- /**
10
- * A HEARTBEAT.md is "effectively empty" when it has no actionable task lines.
11
- * Whitespace, ATX headers, and stub checklist items (`- [ ]`) all count as
12
- * empty so we can skip a turn when the file has been left as a placeholder.
13
- * Missing content (undefined/null/non-string) returns false — the LLM should
14
- * still get a chance to act.
15
- */
16
- export function isHeartbeatContentEffectivelyEmpty(content: string | undefined | null): boolean {
17
- if (typeof content !== 'string') return false
18
- for (const line of content.split('\n')) {
19
- const trimmed = line.trim()
20
- if (!trimmed) continue
21
- if (/^#+(\s|$)/.test(trimmed)) continue
22
- if (/^[-*+]\s*(\[[\sXx]?\]\s*)?$/.test(trimmed)) continue
23
- return false
24
- }
25
- return true
26
- }
27
-
28
- export function resolveHeartbeatPrompt(raw?: string | null): string {
29
- const trimmed = typeof raw === 'string' ? raw.trim() : ''
30
- return trimmed || HEARTBEAT_PROMPT
31
- }
@@ -1,77 +0,0 @@
1
- export type { OAuthAuthInfo, OAuthPrompt } from '@mariozechner/pi-ai'
2
- export type { StoredCredentials } from './auth/openai-codex.ts'
3
- export {
4
- clearCredentials as clearOpenAICodexCredentials,
5
- getStatus as getOpenAICodexStatus,
6
- hasCredentials as hasOpenAICodexCredentials,
7
- loadAccessToken as loadOpenAICodexAccessToken,
8
- loginOpenAICodex,
9
- OPENAI_CODEX_SECRET_KEY,
10
- refreshOpenAICodexToken,
11
- saveLoginCredentials as saveOpenAICodexLoginCredentials,
12
- } from './auth/openai-codex.ts'
13
- export {
14
- DEFAULT_HEARTBEAT_EVERY_SEC,
15
- HEARTBEAT_PROMPT,
16
- isHeartbeatContentEffectivelyEmpty,
17
- resolveHeartbeatPrompt,
18
- } from './auto-reply/heartbeat.ts'
19
- export { filesBackend } from './memory/files.ts'
20
- export { qmdBackend } from './memory/qmd.ts'
21
- export type { MemoryBackend } from './memory/types.ts'
22
- export {
23
- extractAssistantText,
24
- extractAssistantToolCalls,
25
- extractToolResultText,
26
- piMessagesToProviderView,
27
- translatePiEvent,
28
- } from './pi/events.ts'
29
- export type { BazilionSessionHandle, CreateBazilionSessionOptions } from './pi/session.ts'
30
- export {
31
- countSessionMessagesForTest,
32
- createBazilionSession,
33
- isProviderEnabled,
34
- loadEnabledRegistry,
35
- loadInitialMessages,
36
- loadSessionHead,
37
- seedSessionForTest,
38
- } from './pi/session.ts'
39
- // Pi-coding-agent integration surface. The worker runs inside a
40
- // `BazilionSession` (pi's AgentSession wrapper) and endpoints (/compact,
41
- // /context, /reset) drive pi session operations directly.
42
- export type { BazilionCustomToolsOpts } from './pi/tools.ts'
43
- export { createBazilionCustomTools, ourToolToPiTool } from './pi/tools.ts'
44
- export type { CatalogResult, LiveFetchResult } from './providers/catalog.ts'
45
- export { listCatalogModels, listCatalogModelsSync } from './providers/catalog.ts'
46
- export type { PiProviderConfig } from './providers/pi-adapter.ts'
47
- export { piProvider, resolveModel as resolvePiModel } from './providers/pi-adapter.ts'
48
- export type {
49
- ProviderConfig,
50
- ProviderMeta,
51
- ProviderRegistry,
52
- ResolvedModel,
53
- } from './providers/registry.ts'
54
- export {
55
- createProviderRegistry,
56
- listAllProviders,
57
- loadProviderConfigFromEnv,
58
- } from './providers/registry.ts'
59
- export type { RetryOptions } from './providers/retry.ts'
60
- export { isRetryableError, withRetry } from './providers/retry.ts'
61
- export type {
62
- Provider,
63
- ProviderRequest,
64
- ProviderResponse,
65
- StopReason,
66
- } from './providers/types.ts'
67
- export { buildSystemPrompt } from './session/prompt.ts'
68
- export { bootstrapTool } from './tools/bootstrap.ts'
69
- export { memoryTools } from './tools/memory.ts'
70
- export { messagingTools } from './tools/messaging.ts'
71
- export { createToolRegistry } from './tools/registry.ts'
72
- export type { ToolHandler, ToolRegistry } from './tools/types.ts'
73
- export { webTools } from './tools/web.ts'
74
-
75
- export type { MessagingHost } from './worker/ipc-protocol.ts'
76
- export type { SpawnWorkerOpts } from './worker/spawn.ts'
77
- export { spawnWorkerTurn } from './worker/spawn.ts'
@@ -1,103 +0,0 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readdirSync,
5
- readFileSync,
6
- rmSync,
7
- statSync,
8
- writeFileSync,
9
- } from 'node:fs'
10
- import { dirname, join } from 'node:path'
11
- import type { MemoryEntry, MemoryHit } from '@bazilion/api-types'
12
- import type { MemoryBackend } from './types.ts'
13
-
14
- const SNIPPET_PAD = 60
15
-
16
- /**
17
- * Filesystem-backed memory: every entry is a file under `root`. Search is
18
- * substring matching across all files. Index = the filesystem itself.
19
- */
20
- export function filesBackend(root: string): MemoryBackend {
21
- function safe(key: string): string {
22
- if (key.includes('..') || key.startsWith('/') || key.includes('\0')) {
23
- throw new Error(`unsafe memory key: ${key}`)
24
- }
25
- return join(root, key)
26
- }
27
-
28
- function walk(dir: string, prefix: string, out: MemoryEntry[]): void {
29
- if (!existsSync(dir)) return
30
- for (const e of readdirSync(dir, { withFileTypes: true })) {
31
- const full = join(dir, e.name)
32
- const key = prefix ? `${prefix}/${e.name}` : e.name
33
- if (e.isDirectory()) {
34
- walk(full, key, out)
35
- } else if (e.isFile()) {
36
- const stats = statSync(full)
37
- out.push({
38
- key,
39
- content: readFileSync(full, 'utf8'),
40
- updatedAt: stats.mtimeMs,
41
- })
42
- }
43
- }
44
- }
45
-
46
- return {
47
- async init() {
48
- mkdirSync(root, { recursive: true })
49
- },
50
-
51
- async read(key) {
52
- const path = safe(key)
53
- if (!existsSync(path)) {
54
- throw new Error(`memory entry not found: ${key}`)
55
- }
56
- const stats = statSync(path)
57
- return {
58
- key,
59
- content: readFileSync(path, 'utf8'),
60
- updatedAt: stats.mtimeMs,
61
- }
62
- },
63
-
64
- async write(key, content) {
65
- const path = safe(key)
66
- mkdirSync(dirname(path), { recursive: true })
67
- writeFileSync(path, content)
68
- const stats = statSync(path)
69
- return { key, content, updatedAt: stats.mtimeMs }
70
- },
71
-
72
- async search(query, opts) {
73
- const limit = opts?.limit ?? 10
74
- const all: MemoryEntry[] = []
75
- walk(root, '', all)
76
- const q = query.toLowerCase()
77
- const hits: MemoryHit[] = []
78
- for (const entry of all) {
79
- const idx = entry.content.toLowerCase().indexOf(q)
80
- if (idx === -1) continue
81
- const start = Math.max(0, idx - SNIPPET_PAD)
82
- const end = Math.min(entry.content.length, idx + query.length + SNIPPET_PAD)
83
- hits.push({
84
- key: entry.key,
85
- snippet: entry.content.slice(start, end),
86
- score: 1,
87
- })
88
- }
89
- return hits.slice(0, limit)
90
- },
91
-
92
- async list() {
93
- const out: MemoryEntry[] = []
94
- walk(root, '', out)
95
- return out.sort((a, b) => a.key.localeCompare(b.key))
96
- },
97
-
98
- async remove(key) {
99
- const path = safe(key)
100
- if (existsSync(path)) rmSync(path)
101
- },
102
- }
103
- }
@@ -1,152 +0,0 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readdirSync,
5
- readFileSync,
6
- rmSync,
7
- statSync,
8
- writeFileSync,
9
- } from 'node:fs'
10
- import { dirname, join } from 'node:path'
11
- import type { MemoryEntry, MemoryHit } from '@bazilion/api-types'
12
- import { createStore, extractSnippet, type QMDStore } from '@tobilu/qmd'
13
- import type { MemoryBackend } from './types.ts'
14
-
15
- const INDEX_FILENAME = '.qmd-index.sqlite'
16
- const COLLECTION_NAME = 'memory'
17
- const PATTERN = '**/*.md'
18
-
19
- // One store per memory directory per process. createStore opens a SQLite
20
- // handle; we dedupe so concurrent chat requests for the same agent reuse it.
21
- const storeCache = new Map<string, Promise<QMDStore>>()
22
-
23
- function getStore(dir: string): Promise<QMDStore> {
24
- let p = storeCache.get(dir)
25
- if (!p) {
26
- p = createStore({
27
- dbPath: join(dir, INDEX_FILENAME),
28
- config: {
29
- collections: {
30
- [COLLECTION_NAME]: { path: dir, pattern: PATTERN },
31
- },
32
- },
33
- })
34
- storeCache.set(dir, p)
35
- }
36
- return p
37
- }
38
-
39
- function safeKey(root: string, key: string): string {
40
- if (key.includes('..') || key.startsWith('/') || key.includes('\0')) {
41
- throw new Error(`unsafe memory key: ${key}`)
42
- }
43
- return join(root, key)
44
- }
45
-
46
- function walkMd(dir: string, prefix: string, out: MemoryEntry[]): void {
47
- if (!existsSync(dir)) return
48
- for (const e of readdirSync(dir, { withFileTypes: true })) {
49
- if (e.name.startsWith('.')) continue // skip .qmd-index.sqlite and friends
50
- const full = join(dir, e.name)
51
- const key = prefix ? `${prefix}/${e.name}` : e.name
52
- if (e.isDirectory()) {
53
- walkMd(full, key, out)
54
- } else if (e.isFile() && e.name.endsWith('.md')) {
55
- const stats = statSync(full)
56
- out.push({
57
- key,
58
- content: readFileSync(full, 'utf8'),
59
- updatedAt: stats.mtimeMs,
60
- })
61
- }
62
- }
63
- }
64
-
65
- /**
66
- * Memory backend backed by @tobilu/qmd — BM25 keyword search over markdown
67
- * files under `root`. Writes markdown to disk, then asks qmd to reindex.
68
- *
69
- * Uses `searchLex` only; no embeddings, no LLM rerank, no model download.
70
- * The hybrid `search()` / `searchVector()` paths exist in the qmd SDK and
71
- * can be wired in later if we want semantic search — they'd add a dependency
72
- * on `node-llama-cpp` and several GB of GGUF models.
73
- */
74
- export function qmdBackend(root: string): MemoryBackend {
75
- return {
76
- async init() {
77
- mkdirSync(root, { recursive: true })
78
- // Opening the store + initial scan. update() is idempotent.
79
- const store = await getStore(root)
80
- await store.update()
81
- },
82
-
83
- async read(key) {
84
- const path = safeKey(root, key)
85
- if (!existsSync(path)) {
86
- throw new Error(`memory entry not found: ${key}`)
87
- }
88
- const stats = statSync(path)
89
- return {
90
- key,
91
- content: readFileSync(path, 'utf8'),
92
- updatedAt: stats.mtimeMs,
93
- }
94
- },
95
-
96
- async write(key, content) {
97
- const path = safeKey(root, key)
98
- mkdirSync(dirname(path), { recursive: true })
99
- writeFileSync(path, content)
100
- const stats = statSync(path)
101
- // Reindex so the newly-written file is searchable on the next search().
102
- // update() re-scans the collection; for typical memory sizes (tens of
103
- // files) this is sub-millisecond.
104
- const store = await getStore(root)
105
- await store.update()
106
- return { key, content, updatedAt: stats.mtimeMs }
107
- },
108
-
109
- async search(query, opts) {
110
- const limit = opts?.limit ?? 10
111
- const store = await getStore(root)
112
- const results = await store.searchLex(query, {
113
- limit,
114
- collection: COLLECTION_NAME,
115
- })
116
- const hits: MemoryHit[] = []
117
- for (const r of results) {
118
- // qmd's filepath is a synthetic URI (`qmd://<collection>/<path>`);
119
- // displayPath is collection-prefixed (`<collection>/<path>`). Strip
120
- // the leading `<collection>/` to get the key the caller wrote.
121
- const prefix = `${COLLECTION_NAME}/`
122
- const key = r.displayPath.startsWith(prefix)
123
- ? r.displayPath.slice(prefix.length)
124
- : r.displayPath
125
- let content = r.body ?? ''
126
- if (!content) {
127
- try {
128
- content = readFileSync(join(root, key), 'utf8')
129
- } catch {
130
- content = ''
131
- }
132
- }
133
- const snippet = extractSnippet(content, query).snippet
134
- hits.push({ key, snippet, score: r.score })
135
- }
136
- return hits
137
- },
138
-
139
- async list() {
140
- const out: MemoryEntry[] = []
141
- walkMd(root, '', out)
142
- return out.sort((a, b) => a.key.localeCompare(b.key))
143
- },
144
-
145
- async remove(key) {
146
- const path = safeKey(root, key)
147
- if (existsSync(path)) rmSync(path)
148
- const store = await getStore(root)
149
- await store.update()
150
- },
151
- }
152
- }
@@ -1,16 +0,0 @@
1
- import type { MemoryEntry, MemoryHit } from '@bazilion/api-types'
2
-
3
- export interface MemoryBackend {
4
- /** Initialize storage. Idempotent. */
5
- init(): Promise<void>
6
- /** Read a memory entry by key. Throws if missing. */
7
- read(key: string): Promise<MemoryEntry>
8
- /** Write or overwrite a memory entry. */
9
- write(key: string, content: string): Promise<MemoryEntry>
10
- /** Search memory for matches against a query string. */
11
- search(query: string, opts?: { limit?: number }): Promise<MemoryHit[]>
12
- /** List all entries (sorted by key). */
13
- list(): Promise<MemoryEntry[]>
14
- /** Delete an entry. No-op if missing. */
15
- remove(key: string): Promise<void>
16
- }
@@ -1,173 +0,0 @@
1
- // Translator: pi `AgentSessionEvent` → Bazilion `SessionEvent[]`.
2
- //
3
- // The worker's NDJSON wire format (`ChatFrame`) is still the same discrete
4
- // event stream CLI / browser clients know how to render. This module is the
5
- // adapter at the single choke-point — pi event in, zero-or-more Bazilion
6
- // events out.
7
- //
8
- // Coverage:
9
- // - user message_start → one `user_message`
10
- // - assistant text_delta → one `assistant_delta` per chunk
11
- // - assistant message_end:
12
- // - if the message carries text → one `assistant_message`
13
- // - for every tool-call content → one `tool_call`
14
- // - tool_execution_end → `tool_result` or `tool_error` based on isError
15
- // - message_end with aborted/error stopReason → one `error`
16
- //
17
- // Not surfaced (intentional):
18
- // - agent_start / agent_end — run-row lifecycle, not chat events
19
- // - turn_start / turn_end — too chatty, nothing to render
20
- // - message_start (assistant) — text will come via updates + end
21
- // - message_update (non-text) — thinking deltas etc; left for a later
22
- // pass when UIs render thinking blocks
23
- // - queue_update / compaction_* — session meta, not assistant output
24
- // - auto_retry_* — silently retried, user sees only the
25
- // eventual success or failure
26
-
27
- import type { ProviderMessage, SessionEvent, ToolCall } from '@bazilion/api-types'
28
- import type { AgentMessage, AgentToolResult } from '@mariozechner/pi-agent-core'
29
- import type { AssistantMessage } from '@mariozechner/pi-ai'
30
- import type { AgentSessionEvent } from '@mariozechner/pi-coding-agent'
31
-
32
- export function translatePiEvent(e: AgentSessionEvent): SessionEvent[] {
33
- switch (e.type) {
34
- case 'message_start': {
35
- if (e.message.role === 'user') {
36
- return [{ type: 'user_message', text: stringifyContent(e.message.content) }]
37
- }
38
- return []
39
- }
40
-
41
- case 'message_update': {
42
- const inner = e.assistantMessageEvent
43
- if (inner.type === 'text_delta') {
44
- return [{ type: 'assistant_delta', delta: inner.delta }]
45
- }
46
- return []
47
- }
48
-
49
- case 'message_end': {
50
- const m = e.message
51
- if (m.role !== 'assistant') return []
52
- const out: SessionEvent[] = []
53
- const text = extractAssistantText(m as AssistantMessage)
54
- if (text) out.push({ type: 'assistant_message', text })
55
- for (const block of (m as AssistantMessage).content ?? []) {
56
- if (block.type === 'toolCall') {
57
- out.push({
58
- type: 'tool_call',
59
- id: block.id,
60
- name: block.name,
61
- arguments: JSON.stringify(block.arguments ?? {}),
62
- })
63
- }
64
- }
65
- const stopReason = (m as AssistantMessage).stopReason
66
- if (stopReason === 'aborted' || stopReason === 'error') {
67
- const errText = (m as AssistantMessage).errorMessage ?? stopReason
68
- out.push({ type: 'error', error: errText })
69
- }
70
- return out
71
- }
72
-
73
- case 'tool_execution_end': {
74
- const text = extractToolResultText(e.result)
75
- if (e.isError) {
76
- return [{ type: 'tool_error', id: e.toolCallId, name: e.toolName, error: text }]
77
- }
78
- return [{ type: 'tool_result', id: e.toolCallId, name: e.toolName, result: text }]
79
- }
80
-
81
- default:
82
- return []
83
- }
84
- }
85
-
86
- export function extractAssistantText(m: AssistantMessage): string {
87
- let out = ''
88
- for (const block of m.content ?? []) {
89
- if (block.type === 'text') out += block.text
90
- }
91
- return out
92
- }
93
-
94
- export function extractAssistantToolCalls(m: AssistantMessage): ToolCall[] {
95
- const out: ToolCall[] = []
96
- for (const block of m.content ?? []) {
97
- if (block.type === 'toolCall') {
98
- out.push({ id: block.id, name: block.name, arguments: JSON.stringify(block.arguments ?? {}) })
99
- }
100
- }
101
- return out
102
- }
103
-
104
- /** Flatten `AgentToolResult.content` blocks into a single string — matches the
105
- * shape Bazilion tools always returned before pi adoption. */
106
- export function extractToolResultText(result: unknown): string {
107
- const r = result as AgentToolResult<unknown> | undefined
108
- if (!r?.content) return ''
109
- let out = ''
110
- for (const block of r.content) {
111
- if (block.type === 'text') out += block.text
112
- }
113
- return out
114
- }
115
-
116
- /** Stringify a pi user-message content array. */
117
- function stringifyContent(content: unknown): string {
118
- if (typeof content === 'string') return content
119
- if (!Array.isArray(content)) return ''
120
- let out = ''
121
- for (const block of content as { type: string; text?: string }[]) {
122
- if (block.type === 'text' && typeof block.text === 'string') out += block.text
123
- }
124
- return out
125
- }
126
-
127
- /**
128
- * Convert pi's authoritative `session.state.messages` (AgentMessage[]) into
129
- * Bazilion's ProviderMessage[] shape, so the `done` ChatFrame stays
130
- * compatible with browser + CLI clients that rehydrate from it.
131
- *
132
- * Notes on role mapping: pi uses `"toolResult"` for tool-response messages;
133
- * Bazilion uses `"tool"`. AssistantMessage content arrays become either
134
- * `content` string (text blocks joined) or a `toolCalls` array (toolCall
135
- * blocks converted).
136
- */
137
- export function piMessagesToProviderView(messages: AgentMessage[]): ProviderMessage[] {
138
- const out: ProviderMessage[] = []
139
- for (const m of messages) {
140
- // Custom Bazilion message types would land in this switch too, but we
141
- // don't register any via CustomAgentMessages declaration merging yet.
142
- switch (m.role) {
143
- case 'user': {
144
- out.push({ role: 'user', content: stringifyContent((m as { content: unknown }).content) })
145
- break
146
- }
147
- case 'assistant': {
148
- const am = m as AssistantMessage
149
- const text = extractAssistantText(am)
150
- const toolCalls = extractAssistantToolCalls(am)
151
- const msg: ProviderMessage = { role: 'assistant', content: text }
152
- if (toolCalls.length > 0) msg.toolCalls = toolCalls
153
- out.push(msg)
154
- break
155
- }
156
- case 'toolResult': {
157
- const tr = m as { content: unknown; toolCallId?: string; toolName?: string }
158
- out.push({
159
- role: 'tool',
160
- content: stringifyContent(tr.content),
161
- toolCallId: tr.toolCallId,
162
- toolName: tr.toolName,
163
- })
164
- break
165
- }
166
- default:
167
- // System and other unknown roles are skipped — the runtime's system
168
- // prompt is already wired via pi's settingsManager + our buildSystemPrompt.
169
- break
170
- }
171
- }
172
- return out
173
- }