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.
- package/README.md +53 -152
- package/dist/cli.js +2730 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon.js +6460 -0
- package/dist/daemon.js.map +1 -0
- package/dist/worker.js +2176 -0
- package/dist/worker.js.map +1 -0
- package/package.json +57 -28
- package/.understand-anything/.understandignore +0 -25
- package/.understand-anything/fingerprints.json +0 -14267
- package/.understand-anything/knowledge-graph.json +0 -18128
- package/.understand-anything/meta.json +0 -6
- package/CLAUDE.md +0 -164
- package/apps/cli/package.json +0 -21
- package/apps/cli/src/auth-file.ts +0 -18
- package/apps/cli/src/client.ts +0 -37
- package/apps/cli/src/columnize.ts +0 -32
- package/apps/cli/src/commands/agent.ts +0 -574
- package/apps/cli/src/commands/auth.ts +0 -110
- package/apps/cli/src/commands/backup.ts +0 -135
- package/apps/cli/src/commands/completion.ts +0 -155
- package/apps/cli/src/commands/config.ts +0 -95
- package/apps/cli/src/commands/doctor.ts +0 -131
- package/apps/cli/src/commands/group.ts +0 -132
- package/apps/cli/src/commands/inbox.ts +0 -82
- package/apps/cli/src/commands/login.ts +0 -73
- package/apps/cli/src/commands/memory.ts +0 -106
- package/apps/cli/src/commands/profile.ts +0 -259
- package/apps/cli/src/commands/provider.ts +0 -170
- package/apps/cli/src/commands/send.ts +0 -24
- package/apps/cli/src/commands/serve.ts +0 -89
- package/apps/cli/src/commands/skill.ts +0 -120
- package/apps/cli/src/commands/token.ts +0 -148
- package/apps/cli/src/commands/trigger.ts +0 -129
- package/apps/cli/src/commands/uninstall.ts +0 -156
- package/apps/cli/src/index.ts +0 -196
- package/apps/cli/src/paths.ts +0 -12
- package/apps/cli/test/agent.test.ts +0 -213
- package/apps/cli/test/backup.test.ts +0 -95
- package/apps/cli/test/chat.test.ts +0 -539
- package/apps/cli/test/columnize.test.ts +0 -29
- package/apps/cli/test/completion.test.ts +0 -45
- package/apps/cli/test/config-page.test.ts +0 -151
- package/apps/cli/test/group.test.ts +0 -74
- package/apps/cli/test/helpers.ts +0 -70
- package/apps/cli/test/inbox-autodeliver.test.ts +0 -143
- package/apps/cli/test/inbox.test.ts +0 -147
- package/apps/cli/test/memory.test.ts +0 -69
- package/apps/cli/test/profile.test.ts +0 -110
- package/apps/cli/test/send.test.ts +0 -30
- package/apps/cli/test/server-fixture.ts +0 -212
- package/apps/cli/test/session-head.test.ts +0 -45
- package/apps/cli/test/skill.test.ts +0 -128
- package/apps/cli/test/token.test.ts +0 -109
- package/apps/cli/test/trigger.test.ts +0 -245
- package/apps/cli/tsconfig.json +0 -4
- package/apps/daemon/package.json +0 -31
- package/apps/daemon/src/app.ts +0 -41
- package/apps/daemon/src/core/agent/archive.ts +0 -8
- package/apps/daemon/src/core/agent/delete.ts +0 -30
- package/apps/daemon/src/core/agent/resolve.ts +0 -31
- package/apps/daemon/src/core/agent/spawn.ts +0 -95
- package/apps/daemon/src/core/agent/unarchive.ts +0 -11
- package/apps/daemon/src/core/availableModels.ts +0 -58
- package/apps/daemon/src/core/db/client.ts +0 -113
- package/apps/daemon/src/core/db/migrate.ts +0 -41
- package/apps/daemon/src/core/db/migrations/0001_init.sql +0 -179
- package/apps/daemon/src/core/group/delete.ts +0 -21
- package/apps/daemon/src/core/group/register.ts +0 -68
- package/apps/daemon/src/core/index.ts +0 -71
- package/apps/daemon/src/core/paths.ts +0 -56
- package/apps/daemon/src/core/profile/create.ts +0 -78
- package/apps/daemon/src/core/profile/delete.ts +0 -26
- package/apps/daemon/src/core/profile/identity.ts +0 -70
- package/apps/daemon/src/core/profile/load.ts +0 -45
- package/apps/daemon/src/core/profile/seed.ts +0 -74
- package/apps/daemon/src/core/profile/templates.ts +0 -60
- package/apps/daemon/src/core/profile/update.ts +0 -57
- package/apps/daemon/src/core/profile/validate.ts +0 -9
- package/apps/daemon/src/core/repos/agents.ts +0 -202
- package/apps/daemon/src/core/repos/config.ts +0 -78
- package/apps/daemon/src/core/repos/groups.ts +0 -55
- package/apps/daemon/src/core/repos/messages.ts +0 -127
- package/apps/daemon/src/core/repos/profiles.ts +0 -83
- package/apps/daemon/src/core/repos/providerModels.ts +0 -58
- package/apps/daemon/src/core/repos/providerState.ts +0 -37
- package/apps/daemon/src/core/repos/secrets.ts +0 -145
- package/apps/daemon/src/core/repos/skillMeta.ts +0 -49
- package/apps/daemon/src/core/repos/triggers.ts +0 -101
- package/apps/daemon/src/core/repos/webTokens.ts +0 -87
- package/apps/daemon/src/core/secrets.ts +0 -65
- package/apps/daemon/src/core/services.ts +0 -264
- package/apps/daemon/src/core/skills/discover.ts +0 -28
- package/apps/daemon/src/core/skills/import.ts +0 -136
- package/apps/daemon/src/core/skills/parse.ts +0 -52
- package/apps/daemon/src/core/skills/resolve.ts +0 -50
- package/apps/daemon/src/index.ts +0 -45
- package/apps/daemon/src/lib/agent-cancel.ts +0 -48
- package/apps/daemon/src/lib/agent-id.ts +0 -13
- package/apps/daemon/src/lib/agent-turn.ts +0 -56
- package/apps/daemon/src/lib/api-key.ts +0 -56
- package/apps/daemon/src/lib/auth.ts +0 -41
- package/apps/daemon/src/lib/cron.ts +0 -93
- package/apps/daemon/src/lib/ctx.ts +0 -80
- package/apps/daemon/src/lib/messaging-host.ts +0 -34
- package/apps/daemon/src/lib/middleware-auth.ts +0 -52
- package/apps/daemon/src/lib/scheduler.ts +0 -294
- package/apps/daemon/src/routes/agents.ts +0 -772
- package/apps/daemon/src/routes/auth-login.ts +0 -193
- package/apps/daemon/src/routes/config.ts +0 -267
- package/apps/daemon/src/routes/groups.ts +0 -133
- package/apps/daemon/src/routes/messages.ts +0 -29
- package/apps/daemon/src/routes/misc.ts +0 -239
- package/apps/daemon/src/routes/profiles.ts +0 -197
- package/apps/daemon/src/routes/skills.ts +0 -123
- package/apps/daemon/src/routes/triggers.ts +0 -29
- package/apps/daemon/src/runtime/auth/openai-codex.ts +0 -121
- package/apps/daemon/src/runtime/auto-reply/heartbeat.ts +0 -31
- package/apps/daemon/src/runtime/index.ts +0 -77
- package/apps/daemon/src/runtime/memory/files.ts +0 -103
- package/apps/daemon/src/runtime/memory/qmd.ts +0 -152
- package/apps/daemon/src/runtime/memory/types.ts +0 -16
- package/apps/daemon/src/runtime/pi/events.ts +0 -173
- package/apps/daemon/src/runtime/pi/session.ts +0 -536
- package/apps/daemon/src/runtime/pi/tools.ts +0 -85
- package/apps/daemon/src/runtime/providers/catalog.ts +0 -145
- package/apps/daemon/src/runtime/providers/pi-adapter.ts +0 -272
- package/apps/daemon/src/runtime/providers/registry.ts +0 -374
- package/apps/daemon/src/runtime/providers/retry.ts +0 -176
- package/apps/daemon/src/runtime/providers/types.ts +0 -33
- package/apps/daemon/src/runtime/session/prompt.ts +0 -83
- package/apps/daemon/src/runtime/tools/bootstrap.ts +0 -22
- package/apps/daemon/src/runtime/tools/home.ts +0 -114
- package/apps/daemon/src/runtime/tools/memory.ts +0 -81
- package/apps/daemon/src/runtime/tools/messaging.ts +0 -127
- package/apps/daemon/src/runtime/tools/registry.ts +0 -29
- package/apps/daemon/src/runtime/tools/types.ts +0 -13
- package/apps/daemon/src/runtime/tools/web-extract.ts +0 -110
- package/apps/daemon/src/runtime/tools/web-ssrf.ts +0 -245
- package/apps/daemon/src/runtime/tools/web.ts +0 -273
- package/apps/daemon/src/runtime/worker/entry.ts +0 -221
- package/apps/daemon/src/runtime/worker/ipc-protocol.ts +0 -75
- package/apps/daemon/src/runtime/worker/spawn.ts +0 -249
- package/apps/daemon/test/core/agents.test.ts +0 -319
- package/apps/daemon/test/core/available-models.test.ts +0 -63
- package/apps/daemon/test/core/config.test.ts +0 -99
- package/apps/daemon/test/core/groups.test.ts +0 -63
- package/apps/daemon/test/core/helpers.ts +0 -50
- package/apps/daemon/test/core/identity.test.ts +0 -85
- package/apps/daemon/test/core/migrations.test.ts +0 -83
- package/apps/daemon/test/core/profiles.test.ts +0 -182
- package/apps/daemon/test/core/provider-models.test.ts +0 -57
- package/apps/daemon/test/core/provider-state.test.ts +0 -36
- package/apps/daemon/test/core/skill-meta.test.ts +0 -45
- package/apps/daemon/test/core/skills.test.ts +0 -271
- package/apps/daemon/test/core/triggers.test.ts +0 -182
- package/apps/daemon/test/core/web-tokens.test.ts +0 -79
- package/apps/daemon/test/cron.test.ts +0 -90
- package/apps/daemon/test/runtime/heartbeat.test.ts +0 -34
- package/apps/daemon/test/runtime/memory-qmd.test.ts +0 -97
- package/apps/daemon/test/runtime/memory.test.ts +0 -78
- package/apps/daemon/test/runtime/messaging.test.ts +0 -213
- package/apps/daemon/test/runtime/mock-server.ts +0 -65
- package/apps/daemon/test/runtime/openai-codex-auth.test.ts +0 -116
- package/apps/daemon/test/runtime/providers.test.ts +0 -306
- package/apps/daemon/test/runtime/retry.test.ts +0 -191
- package/apps/daemon/test/runtime/session-head.test.ts +0 -90
- package/apps/daemon/test/runtime/tools-home.test.ts +0 -102
- package/apps/daemon/test/runtime/tools-web.test.ts +0 -206
- package/apps/daemon/tsconfig.json +0 -4
- package/apps/mobile/README.md +0 -60
- package/apps/mobile/app/_layout.tsx +0 -58
- package/apps/mobile/app/agents/[id]/chat.tsx +0 -486
- package/apps/mobile/app/agents/[id]/index.tsx +0 -166
- package/apps/mobile/app/agents/index.tsx +0 -212
- package/apps/mobile/app/index.tsx +0 -21
- package/apps/mobile/app/pair.tsx +0 -226
- package/apps/mobile/app/settings.tsx +0 -419
- package/apps/mobile/app.json +0 -49
- package/apps/mobile/assets/adaptive-icon.png +0 -0
- package/apps/mobile/assets/favicon.png +0 -0
- package/apps/mobile/assets/icon.png +0 -0
- package/apps/mobile/assets/splash-icon.png +0 -0
- package/apps/mobile/babel.config.js +0 -6
- package/apps/mobile/metro.config.js +0 -28
- package/apps/mobile/package.json +0 -44
- package/apps/mobile/src/auth.ts +0 -66
- package/apps/mobile/src/pair-url.ts +0 -48
- package/apps/mobile/src/theme-context.tsx +0 -88
- package/apps/mobile/src/theme.ts +0 -135
- package/apps/mobile/test/pair-url.test.ts +0 -46
- package/apps/mobile/tsconfig.json +0 -23
- package/apps/web/components.json +0 -25
- package/apps/web/package.json +0 -39
- package/apps/web/public/baziu.svg +0 -8
- package/apps/web/src/components/AgentTabs.tsx +0 -45
- package/apps/web/src/components/BaziuLogo.tsx +0 -21
- package/apps/web/src/components/ChatPane.tsx +0 -1033
- package/apps/web/src/components/ConfigTabs.tsx +0 -29
- package/apps/web/src/components/CopyButton.tsx +0 -68
- package/apps/web/src/components/CreateGroupDialog.tsx +0 -127
- package/apps/web/src/components/FieldRow.tsx +0 -94
- package/apps/web/src/components/Footer.tsx +0 -10
- package/apps/web/src/components/PawIcon.tsx +0 -15
- package/apps/web/src/components/Sidebar.tsx +0 -287
- package/apps/web/src/components/SpawnDialog.tsx +0 -129
- package/apps/web/src/components/ThemeToggle.tsx +0 -75
- package/apps/web/src/components/TopNav.tsx +0 -34
- package/apps/web/src/components/ui/button.tsx +0 -67
- package/apps/web/src/components/ui/card.tsx +0 -103
- package/apps/web/src/components/ui/checkbox.tsx +0 -31
- package/apps/web/src/components/ui/dialog.tsx +0 -168
- package/apps/web/src/components/ui/input.tsx +0 -19
- package/apps/web/src/components/ui/label.tsx +0 -22
- package/apps/web/src/components/ui/radio-group.tsx +0 -44
- package/apps/web/src/components/ui/select.tsx +0 -192
- package/apps/web/src/components/ui/separator.tsx +0 -26
- package/apps/web/src/components/ui/table.tsx +0 -116
- package/apps/web/src/components/ui/tabs.tsx +0 -88
- package/apps/web/src/components/ui/textarea.tsx +0 -18
- package/apps/web/src/lib/auth.ts +0 -50
- package/apps/web/src/lib/daemon-client.ts +0 -34
- package/apps/web/src/lib/md.ts +0 -45
- package/apps/web/src/lib/utils.ts +0 -6
- package/apps/web/src/lib/wire-constants.ts +0 -27
- package/apps/web/src/routeTree.gen.ts +0 -408
- package/apps/web/src/router.tsx +0 -20
- package/apps/web/src/routes/__root.tsx +0 -123
- package/apps/web/src/routes/agents/$id/inbox.tsx +0 -207
- package/apps/web/src/routes/agents/$id/index.tsx +0 -527
- package/apps/web/src/routes/agents/$id/triggers.tsx +0 -239
- package/apps/web/src/routes/agents/index.tsx +0 -265
- package/apps/web/src/routes/api/$.ts +0 -88
- package/apps/web/src/routes/config/index.tsx +0 -315
- package/apps/web/src/routes/config/services.tsx +0 -49
- package/apps/web/src/routes/config/tokens.tsx +0 -192
- package/apps/web/src/routes/groups/$id/index.tsx +0 -153
- package/apps/web/src/routes/groups/$id/memory.tsx +0 -321
- package/apps/web/src/routes/groups/index.tsx +0 -191
- package/apps/web/src/routes/index.tsx +0 -133
- package/apps/web/src/routes/login.tsx +0 -63
- package/apps/web/src/routes/profiles/$id.tsx +0 -549
- package/apps/web/src/routes/profiles/index.tsx +0 -458
- package/apps/web/src/routes/skills/index.tsx +0 -297
- package/apps/web/src/routes/welcome.tsx +0 -61
- package/apps/web/src/styles.css +0 -449
- package/apps/web/tsconfig.json +0 -25
- package/apps/web/vite.config.ts +0 -25
- package/biome.json +0 -23
- package/docs/agent-engine.md +0 -219
- package/docs/architecture.md +0 -627
- package/docs/backlog/README.md +0 -42
- package/docs/backlog/draft/BAZ-001-a2a-federation-spike.md +0 -125
- package/docs/openclaw-reference.md +0 -210
- package/packages/api-types/package.json +0 -11
- package/packages/api-types/src/entities.ts +0 -146
- package/packages/api-types/src/events.ts +0 -55
- package/packages/api-types/src/index.ts +0 -488
- package/packages/api-types/src/memory.ts +0 -15
- package/packages/client/package.json +0 -13
- package/packages/client/src/index.ts +0 -117
- package/pnpm-workspace.yaml +0 -3
- package/tsconfig.base.json +0 -23
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -22
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
// /api/auth/openai/* — ChatGPT OAuth provider connection state.
|
|
2
|
-
// /api/providers/test — model smoke-test.
|
|
3
|
-
// /api/login — token-based browser login (sets the bz_token cookie).
|
|
4
|
-
|
|
5
|
-
import { spawn } from 'node:child_process'
|
|
6
|
-
import type { ProviderTestRequest, ProviderTestResponse } from '@bazilion/api-types'
|
|
7
|
-
import { Hono } from 'hono'
|
|
8
|
-
import { setCookie } from 'hono/cookie'
|
|
9
|
-
import { isSetupComplete, mergeSecretsIntoEnv, providerStateRepo } from '../core/index.ts'
|
|
10
|
-
import { isValidToken } from '../lib/auth.ts'
|
|
11
|
-
import { getCtx } from '../lib/ctx.ts'
|
|
12
|
-
import {
|
|
13
|
-
clearOpenAICodexCredentials,
|
|
14
|
-
createProviderRegistry,
|
|
15
|
-
getOpenAICodexStatus,
|
|
16
|
-
loadProviderConfigFromEnv,
|
|
17
|
-
loginOpenAICodex,
|
|
18
|
-
saveOpenAICodexLoginCredentials,
|
|
19
|
-
} from '../runtime/index.ts'
|
|
20
|
-
|
|
21
|
-
export const authRouter = new Hono()
|
|
22
|
-
|
|
23
|
-
// ─── Auth probe ──────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Cheap session validator. Web SSR middleware calls this once per request
|
|
27
|
-
* to translate "is the cookie still good?" + "has setup been finished?"
|
|
28
|
-
* into JSON-status pairs that the Astro middleware turns into redirects.
|
|
29
|
-
*
|
|
30
|
-
* Reaching this handler at all means auth passed (the daemon's own
|
|
31
|
-
* middleware-auth would have 401'd otherwise). The body just exposes the
|
|
32
|
-
* setup-complete bit so the web layer can route accordingly.
|
|
33
|
-
*/
|
|
34
|
-
authRouter.get('/auth/me', (c) => {
|
|
35
|
-
const { db } = getCtx()
|
|
36
|
-
return c.json({ authed: true, setupComplete: isSetupComplete(db) })
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// ─── ChatGPT OAuth ───────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
authRouter.get('/auth/openai', (c) => {
|
|
42
|
-
const { db, authToken } = getCtx()
|
|
43
|
-
return c.json(getOpenAICodexStatus(db, authToken))
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
authRouter.put('/auth/openai', async (c) => {
|
|
47
|
-
const body = (await c.req.json().catch(() => null)) as {
|
|
48
|
-
refresh?: unknown
|
|
49
|
-
access?: unknown
|
|
50
|
-
expires?: unknown
|
|
51
|
-
} | null
|
|
52
|
-
if (
|
|
53
|
-
!body ||
|
|
54
|
-
typeof body.refresh !== 'string' ||
|
|
55
|
-
typeof body.access !== 'string' ||
|
|
56
|
-
typeof body.expires !== 'number'
|
|
57
|
-
) {
|
|
58
|
-
return c.json(
|
|
59
|
-
{ error: 'body must be { refresh: string, access: string, expires: number }' },
|
|
60
|
-
400,
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
const { db, authToken } = getCtx()
|
|
64
|
-
saveOpenAICodexLoginCredentials(db, authToken, {
|
|
65
|
-
refresh: body.refresh,
|
|
66
|
-
access: body.access,
|
|
67
|
-
expires: body.expires,
|
|
68
|
-
})
|
|
69
|
-
return c.json(getOpenAICodexStatus(db, authToken))
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
authRouter.delete('/auth/openai', (c) => {
|
|
73
|
-
const { db, authToken } = getCtx()
|
|
74
|
-
clearOpenAICodexCredentials(db, authToken)
|
|
75
|
-
return c.json({ connected: false, expiresAt: null, accountId: null })
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
authRouter.post('/auth/openai/login', async (c) => {
|
|
79
|
-
const { db, authToken } = getCtx()
|
|
80
|
-
try {
|
|
81
|
-
const creds = await loginOpenAICodex({
|
|
82
|
-
onAuth: ({ url }) => openBrowser(url),
|
|
83
|
-
onPrompt: () =>
|
|
84
|
-
Promise.reject(
|
|
85
|
-
new Error(
|
|
86
|
-
'interactive paste not supported in the web flow — cancel and try again, or use `bazilion auth openai login`',
|
|
87
|
-
),
|
|
88
|
-
),
|
|
89
|
-
onProgress: () => {
|
|
90
|
-
// single blocking POST keeps the UI simple
|
|
91
|
-
},
|
|
92
|
-
})
|
|
93
|
-
saveOpenAICodexLoginCredentials(db, authToken, creds)
|
|
94
|
-
return c.json(getOpenAICodexStatus(db, authToken))
|
|
95
|
-
} catch (err) {
|
|
96
|
-
return c.json({ error: (err as Error).message }, 400)
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
// ─── Provider model smoke-test ───────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
authRouter.post('/providers/test', async (c) => {
|
|
103
|
-
const body = (await c.req.json().catch(() => null)) as ProviderTestRequest | null
|
|
104
|
-
if (!body || typeof body.model !== 'string' || !body.model) {
|
|
105
|
-
return c.json({ error: 'model is required' }, 400)
|
|
106
|
-
}
|
|
107
|
-
const message = typeof body.message === 'string' && body.message ? body.message : 'say hi briefly'
|
|
108
|
-
const { db, paths, authToken } = getCtx()
|
|
109
|
-
const env = mergeSecretsIntoEnv(db, authToken)
|
|
110
|
-
const reg = createProviderRegistry(loadProviderConfigFromEnv(env, { db, authToken }), {
|
|
111
|
-
enabledSet: providerStateRepo.listEnabled(db),
|
|
112
|
-
})
|
|
113
|
-
try {
|
|
114
|
-
const { provider, model } = reg.resolve(body.model)
|
|
115
|
-
const res = await provider.chat({
|
|
116
|
-
model,
|
|
117
|
-
messages: [{ role: 'user', content: message }],
|
|
118
|
-
maxTokens: 256,
|
|
119
|
-
})
|
|
120
|
-
const out: ProviderTestResponse = { content: res.content, usage: res.usage }
|
|
121
|
-
return c.json(out)
|
|
122
|
-
} catch (err) {
|
|
123
|
-
return c.json({ error: (err as Error).message }, 400)
|
|
124
|
-
}
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// ─── Browser login ───────────────────────────────────────────────────────
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Token-based login. Two body shapes accepted:
|
|
131
|
-
* - `application/json`: `{ token: "<value>" }` → returns `{ ok: true }` on
|
|
132
|
-
* success, sets the `bz_token` cookie. Used by clients (web pages, mobile)
|
|
133
|
-
* that prefer JSON.
|
|
134
|
-
* - `application/x-www-form-urlencoded`: `token=<value>` → 302 to `/` on
|
|
135
|
-
* success or `/login?error=1` on failure. Used by the legacy `<form>` on
|
|
136
|
-
* the Astro `/login` page; preserved for compatibility through Stage A.
|
|
137
|
-
*/
|
|
138
|
-
authRouter.post('/login', async (c) => {
|
|
139
|
-
const ct = c.req.header('content-type') ?? ''
|
|
140
|
-
let token: string | null = null
|
|
141
|
-
|
|
142
|
-
if (ct.startsWith('application/json')) {
|
|
143
|
-
const body = (await c.req.json().catch(() => null)) as { token?: unknown } | null
|
|
144
|
-
if (body && typeof body.token === 'string') token = body.token
|
|
145
|
-
} else {
|
|
146
|
-
const form = await c.req.formData().catch(() => null)
|
|
147
|
-
const v = form?.get('token')
|
|
148
|
-
if (typeof v === 'string') token = v
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (!token || !isValidToken(token)) {
|
|
152
|
-
if (ct.startsWith('application/json')) {
|
|
153
|
-
return c.json({ error: 'invalid token' }, 401)
|
|
154
|
-
}
|
|
155
|
-
return c.redirect('/login?error=1', 302)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
setCookie(c, 'bz_token', token, {
|
|
159
|
-
path: '/',
|
|
160
|
-
httpOnly: true,
|
|
161
|
-
sameSite: 'Lax',
|
|
162
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
if (ct.startsWith('application/json')) {
|
|
166
|
-
return c.json({ ok: true })
|
|
167
|
-
}
|
|
168
|
-
return c.redirect('/', 302)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Open `url` in the host's default browser. Only called by the OAuth flow
|
|
173
|
-
* triggered from /config — the user is on the same machine as the daemon in
|
|
174
|
-
* that scenario (loopback-only `bazilion serve`).
|
|
175
|
-
*/
|
|
176
|
-
function openBrowser(url: string): void {
|
|
177
|
-
const platform = process.platform
|
|
178
|
-
const [cmd, ...args] =
|
|
179
|
-
platform === 'darwin'
|
|
180
|
-
? ['open', url]
|
|
181
|
-
: platform === 'win32'
|
|
182
|
-
? ['cmd', '/c', 'start', '""', url]
|
|
183
|
-
: ['xdg-open', url]
|
|
184
|
-
try {
|
|
185
|
-
const child = spawn(cmd as string, args, { stdio: 'ignore', detached: true })
|
|
186
|
-
child.unref()
|
|
187
|
-
child.on('error', () => {
|
|
188
|
-
// xdg-open missing on minimal installs — swallow so the flow still works
|
|
189
|
-
})
|
|
190
|
-
} catch {
|
|
191
|
-
// spawn failed — user will still see the URL in the progress log
|
|
192
|
-
}
|
|
193
|
-
}
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
// /api/config/* — provider matrix, services, per-provider enabled toggle and
|
|
2
|
-
// curated models, and per-field config/secret writes.
|
|
3
|
-
|
|
4
|
-
import type {
|
|
5
|
-
ProviderConfigEntry,
|
|
6
|
-
ProviderConfigResponse,
|
|
7
|
-
ServiceCard,
|
|
8
|
-
ServiceConfigResponse,
|
|
9
|
-
ServiceFieldState,
|
|
10
|
-
SetProviderModelsRequest,
|
|
11
|
-
} from '@bazilion/api-types'
|
|
12
|
-
import { Hono } from 'hono'
|
|
13
|
-
import {
|
|
14
|
-
ensureSetupSeeded,
|
|
15
|
-
findFieldByEnvVar,
|
|
16
|
-
groupAvailableModels,
|
|
17
|
-
mergeSecretsIntoEnv,
|
|
18
|
-
openConfig,
|
|
19
|
-
openSecrets,
|
|
20
|
-
providerModelRepo,
|
|
21
|
-
providerStateRepo,
|
|
22
|
-
type ServiceDef,
|
|
23
|
-
servicesByCategory,
|
|
24
|
-
} from '../core/index.ts'
|
|
25
|
-
import { getCtx } from '../lib/ctx.ts'
|
|
26
|
-
import {
|
|
27
|
-
listAllProviders,
|
|
28
|
-
listCatalogModels,
|
|
29
|
-
listCatalogModelsSync,
|
|
30
|
-
loadProviderConfigFromEnv,
|
|
31
|
-
} from '../runtime/index.ts'
|
|
32
|
-
|
|
33
|
-
export const configRouter = new Hono()
|
|
34
|
-
|
|
35
|
-
// /api/config/providers
|
|
36
|
-
configRouter.get('/providers', async (c) => {
|
|
37
|
-
const { db, paths, authToken } = getCtx()
|
|
38
|
-
const env = mergeSecretsIntoEnv(db, authToken)
|
|
39
|
-
const registryProviders = listAllProviders(loadProviderConfigFromEnv(env, { db, authToken }))
|
|
40
|
-
const registryByName = new Map(registryProviders.map((p) => [p.name, p]))
|
|
41
|
-
|
|
42
|
-
const configValues = readAll(() => openConfig(db).getAll())
|
|
43
|
-
const secretValues = readAll(() => openSecrets(db, authToken).getAll())
|
|
44
|
-
|
|
45
|
-
const providerServices = servicesByCategory('provider')
|
|
46
|
-
const enabledSet = providerStateRepo.listEnabled(db)
|
|
47
|
-
|
|
48
|
-
const entries = await Promise.all(
|
|
49
|
-
providerServices.map(async (svc): Promise<ProviderConfigEntry> => {
|
|
50
|
-
const meta = registryByName.get(svc.id)
|
|
51
|
-
const enabled = enabledSet.has(svc.id)
|
|
52
|
-
const envHint = meta?.envHint ?? ''
|
|
53
|
-
const ac = new AbortController()
|
|
54
|
-
const t = setTimeout(() => ac.abort(), 5_000)
|
|
55
|
-
try {
|
|
56
|
-
const { catalog, live } = enabled
|
|
57
|
-
? await listCatalogModels(svc.id, env, ac.signal)
|
|
58
|
-
: { catalog: listCatalogModelsSync(svc.id), live: undefined }
|
|
59
|
-
return {
|
|
60
|
-
id: svc.id,
|
|
61
|
-
displayName: svc.displayName,
|
|
62
|
-
...(svc.hint ? { hint: svc.hint } : {}),
|
|
63
|
-
enabled,
|
|
64
|
-
envHint,
|
|
65
|
-
fields: resolveFieldStates(svc, configValues, secretValues),
|
|
66
|
-
catalog,
|
|
67
|
-
...(live ? { live } : {}),
|
|
68
|
-
curated: providerModelRepo.list(db, svc.id),
|
|
69
|
-
}
|
|
70
|
-
} finally {
|
|
71
|
-
clearTimeout(t)
|
|
72
|
-
}
|
|
73
|
-
}),
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
const body: ProviderConfigResponse = { providers: entries }
|
|
77
|
-
return c.json(body)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
// /api/config/services — non-provider service cards (e.g. SearXNG, Brave).
|
|
81
|
-
configRouter.get('/services', (c) => {
|
|
82
|
-
const { db, authToken } = getCtx()
|
|
83
|
-
const configValues = readAll(() => openConfig(db).getAll())
|
|
84
|
-
const secretValues = readAll(() => openSecrets(db, authToken).getAll())
|
|
85
|
-
|
|
86
|
-
const services: ServiceCard[] = servicesByCategory('service').map((svc) => ({
|
|
87
|
-
id: svc.id,
|
|
88
|
-
displayName: svc.displayName,
|
|
89
|
-
...(svc.hint ? { hint: svc.hint } : {}),
|
|
90
|
-
fields: resolveFieldStates(svc, configValues, secretValues),
|
|
91
|
-
}))
|
|
92
|
-
|
|
93
|
-
const body: ServiceConfigResponse = { services }
|
|
94
|
-
return c.json(body)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
// /api/config/providers/:name/enabled — flip the admin switch.
|
|
98
|
-
configRouter.put('/providers/:name/enabled', async (c) => {
|
|
99
|
-
const name = c.req.param('name')
|
|
100
|
-
if (!knownProviderIds().has(name)) return c.json({ error: `unknown provider: ${name}` }, 404)
|
|
101
|
-
|
|
102
|
-
const body = (await c.req.json().catch(() => null)) as { enabled?: unknown } | null
|
|
103
|
-
if (!body || (typeof body.enabled !== 'boolean' && typeof body.enabled !== 'string')) {
|
|
104
|
-
return c.json({ error: 'body must be {"enabled": boolean}' }, 400)
|
|
105
|
-
}
|
|
106
|
-
const enabled =
|
|
107
|
-
typeof body.enabled === 'boolean' ? body.enabled : body.enabled.toLowerCase() === 'true'
|
|
108
|
-
|
|
109
|
-
const { db, paths } = getCtx()
|
|
110
|
-
providerStateRepo.setEnabled(db, name, enabled)
|
|
111
|
-
ensureSetupSeeded(db, paths)
|
|
112
|
-
return c.json({ name, enabled })
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// /api/config/providers/:name/models — curated model list.
|
|
116
|
-
configRouter.get('/providers/:name/models', (c) => {
|
|
117
|
-
const name = c.req.param('name')
|
|
118
|
-
if (!knownProviderRegistryNames().has(name))
|
|
119
|
-
return c.json({ error: `unknown provider: ${name}` }, 404)
|
|
120
|
-
const { db } = getCtx()
|
|
121
|
-
return c.json({ models: providerModelRepo.list(db, name) })
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
configRouter.put('/providers/:name/models', async (c) => {
|
|
125
|
-
const name = c.req.param('name')
|
|
126
|
-
if (!knownProviderRegistryNames().has(name))
|
|
127
|
-
return c.json({ error: `unknown provider: ${name}` }, 404)
|
|
128
|
-
const body = (await c.req.json().catch(() => null)) as Partial<SetProviderModelsRequest> | null
|
|
129
|
-
if (!body) return c.json({ error: 'invalid JSON body' }, 400)
|
|
130
|
-
|
|
131
|
-
// Accept textarea-style newline-separated input from web forms in addition
|
|
132
|
-
// to the CLI's array shape.
|
|
133
|
-
let models: string[] = []
|
|
134
|
-
if (Array.isArray(body.models)) {
|
|
135
|
-
models = body.models.filter((m): m is string => typeof m === 'string')
|
|
136
|
-
} else if (typeof (body as Record<string, unknown>).models === 'string') {
|
|
137
|
-
models = ((body as Record<string, unknown>).models as string).split(/\r?\n/)
|
|
138
|
-
} else {
|
|
139
|
-
return c.json(
|
|
140
|
-
{ error: 'models must be an array of strings or a newline-separated string' },
|
|
141
|
-
400,
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const { db, paths } = getCtx()
|
|
146
|
-
providerModelRepo.replace(db, name, models)
|
|
147
|
-
ensureSetupSeeded(db, paths)
|
|
148
|
-
return c.json({ models: providerModelRepo.list(db, name) })
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
// /api/config/fields/:envVar — write-through for any envVar the registry knows.
|
|
152
|
-
configRouter.put('/fields/:envVar', async (c) => {
|
|
153
|
-
const envVar = c.req.param('envVar')
|
|
154
|
-
const found = findFieldByEnvVar(envVar)
|
|
155
|
-
if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)
|
|
156
|
-
|
|
157
|
-
const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null
|
|
158
|
-
if (!body || typeof body.value !== 'string') {
|
|
159
|
-
return c.json({ error: 'body must be {"value": "<string>"}' }, 400)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const { db, authToken } = getCtx()
|
|
163
|
-
if (found.field.kind === 'config') {
|
|
164
|
-
const store = openConfig(db)
|
|
165
|
-
if (body.value === '') store.remove(envVar)
|
|
166
|
-
else store.set(envVar, body.value)
|
|
167
|
-
} else {
|
|
168
|
-
const store = openSecrets(db, authToken)
|
|
169
|
-
if (body.value === '') store.remove(envVar)
|
|
170
|
-
else store.set(envVar, body.value)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return c.json(readFieldState(db, authToken, envVar, found.field.kind))
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// /api/config/available-models — provider-grouped curated models. Drives
|
|
177
|
-
// the model dropdowns on the profile + agent spawn pages.
|
|
178
|
-
configRouter.get('/available-models', (c) => {
|
|
179
|
-
const { db } = getCtx()
|
|
180
|
-
return c.json({ groups: groupAvailableModels(db) })
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
configRouter.delete('/fields/:envVar', (c) => {
|
|
184
|
-
const envVar = c.req.param('envVar')
|
|
185
|
-
const found = findFieldByEnvVar(envVar)
|
|
186
|
-
if (!found) return c.json({ error: `unknown envVar: ${envVar}` }, 404)
|
|
187
|
-
|
|
188
|
-
const { db, authToken } = getCtx()
|
|
189
|
-
if (found.field.kind === 'config') {
|
|
190
|
-
openConfig(db).remove(envVar)
|
|
191
|
-
} else {
|
|
192
|
-
openSecrets(db, authToken).remove(envVar)
|
|
193
|
-
}
|
|
194
|
-
return c.body(null, 204)
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
// ─── helpers ─────────────────────────────────────────────────────────────
|
|
198
|
-
|
|
199
|
-
function mask(value: string): string {
|
|
200
|
-
if (value.length === 0) return ''
|
|
201
|
-
return value.length > 8 ? `${value.slice(0, 6)}…` : '***'
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function resolveFieldStates(
|
|
205
|
-
service: ServiceDef,
|
|
206
|
-
configValues: Record<string, string>,
|
|
207
|
-
secretValues: Record<string, string>,
|
|
208
|
-
): ServiceFieldState[] {
|
|
209
|
-
return service.fields.map((f) => {
|
|
210
|
-
const val = (f.kind === 'config' ? configValues[f.envVar] : secretValues[f.envVar]) ?? ''
|
|
211
|
-
const state: ServiceFieldState = {
|
|
212
|
-
envVar: f.envVar,
|
|
213
|
-
kind: f.kind,
|
|
214
|
-
label: f.label,
|
|
215
|
-
set: val.length > 0,
|
|
216
|
-
...(f.placeholder ? { placeholder: f.placeholder } : {}),
|
|
217
|
-
...(f.description ? { description: f.description } : {}),
|
|
218
|
-
}
|
|
219
|
-
if (f.kind === 'config') {
|
|
220
|
-
state.value = val
|
|
221
|
-
} else if (val.length > 0) {
|
|
222
|
-
state.preview = mask(val)
|
|
223
|
-
}
|
|
224
|
-
return state
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function readAll(read: () => Record<string, string>): Record<string, string> {
|
|
229
|
-
try {
|
|
230
|
-
return read()
|
|
231
|
-
} catch {
|
|
232
|
-
return {}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
interface FieldState {
|
|
237
|
-
envVar: string
|
|
238
|
-
kind: 'secret' | 'config'
|
|
239
|
-
set: boolean
|
|
240
|
-
value?: string
|
|
241
|
-
preview?: string
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function readFieldState(
|
|
245
|
-
db: import('../core/index.ts').BazilionDb,
|
|
246
|
-
authToken: string,
|
|
247
|
-
envVar: string,
|
|
248
|
-
kind: 'secret' | 'config',
|
|
249
|
-
): FieldState {
|
|
250
|
-
if (kind === 'config') {
|
|
251
|
-
const v = openConfig(db).get(envVar) ?? ''
|
|
252
|
-
return { envVar, kind, set: v.length > 0, value: v }
|
|
253
|
-
}
|
|
254
|
-
const v = openSecrets(db, authToken).get(envVar) ?? ''
|
|
255
|
-
return { envVar, kind, set: v.length > 0, ...(v.length > 0 ? { preview: mask(v) } : {}) }
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function knownProviderIds(): Set<string> {
|
|
259
|
-
return new Set(servicesByCategory('provider').map((s) => s.id))
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function knownProviderRegistryNames(): Set<string> {
|
|
263
|
-
const { db, authToken } = getCtx()
|
|
264
|
-
return new Set(
|
|
265
|
-
listAllProviders(loadProviderConfigFromEnv(process.env, { db, authToken })).map((p) => p.name),
|
|
266
|
-
)
|
|
267
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
// /api/groups/* — group registry, per-group USER.md, per-group shared
|
|
2
|
-
// memory. Memory is keyed by the group slug because the qmd index lives at
|
|
3
|
-
// `<group.path>/memory/` and is shared by every agent in the group.
|
|
4
|
-
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import type { RegisterGroupRequest, SetGroupUserMdRequest } from '@bazilion/api-types'
|
|
7
|
-
import { Hono } from 'hono'
|
|
8
|
-
import { deleteGroup, groupRepo, registerGroup } from '../core/index.ts'
|
|
9
|
-
import { getCtx } from '../lib/ctx.ts'
|
|
10
|
-
import { qmdBackend } from '../runtime/index.ts'
|
|
11
|
-
|
|
12
|
-
// 12 KB cap matches OpenClaw's bootstrapMaxChars default — enough for a rich
|
|
13
|
-
// USER.md, small enough that it can't silently blow out the system prompt.
|
|
14
|
-
const USER_MD_MAX_BYTES = 12_000
|
|
15
|
-
|
|
16
|
-
export const groupsRouter = new Hono()
|
|
17
|
-
|
|
18
|
-
groupsRouter.get('/', (c) => {
|
|
19
|
-
const { db, paths } = getCtx()
|
|
20
|
-
return c.json(groupRepo.list(db, paths))
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
groupsRouter.post('/', async (c) => {
|
|
24
|
-
const body = (await c.req.json().catch(() => null)) as RegisterGroupRequest | null
|
|
25
|
-
if (!body || typeof body.id !== 'string') {
|
|
26
|
-
return c.json({ error: 'id is required' }, 400)
|
|
27
|
-
}
|
|
28
|
-
const { db, paths } = getCtx()
|
|
29
|
-
try {
|
|
30
|
-
const g = registerGroup(db, { id: body.id, name: body.name, link: body.link }, paths)
|
|
31
|
-
return c.json(g, 201)
|
|
32
|
-
} catch (err) {
|
|
33
|
-
return c.json({ error: (err as Error).message }, 400)
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
groupsRouter.get('/:id', (c) => {
|
|
38
|
-
const { db, paths } = getCtx()
|
|
39
|
-
const g = groupRepo.get(db, c.req.param('id'), paths)
|
|
40
|
-
if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)
|
|
41
|
-
return c.json(g)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
groupsRouter.delete('/:id', (c) => {
|
|
45
|
-
const { db, paths } = getCtx()
|
|
46
|
-
try {
|
|
47
|
-
deleteGroup(db, paths, c.req.param('id'))
|
|
48
|
-
return c.body(null, 204)
|
|
49
|
-
} catch (err) {
|
|
50
|
-
return c.json({ error: (err as Error).message }, 400)
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
groupsRouter.put('/:id/user-md', async (c) => {
|
|
55
|
-
const body = (await c.req.json().catch(() => null)) as SetGroupUserMdRequest | null
|
|
56
|
-
if (!body || typeof body.userMd !== 'string') {
|
|
57
|
-
return c.json({ error: 'userMd (string) is required' }, 400)
|
|
58
|
-
}
|
|
59
|
-
if (Buffer.byteLength(body.userMd, 'utf8') > USER_MD_MAX_BYTES) {
|
|
60
|
-
return c.json({ error: `userMd exceeds ${USER_MD_MAX_BYTES}-byte cap` }, 413)
|
|
61
|
-
}
|
|
62
|
-
const { db, paths } = getCtx()
|
|
63
|
-
const g = groupRepo.get(db, c.req.param('id'), paths)
|
|
64
|
-
if (!g) return c.json({ error: `group not found: ${c.req.param('id')}` }, 404)
|
|
65
|
-
groupRepo.setUserMd(db, c.req.param('id'), body.userMd)
|
|
66
|
-
return c.json(groupRepo.get(db, c.req.param('id'), paths))
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
// ─── Memory (per-group, shared across all member agents) ──────────────────
|
|
70
|
-
|
|
71
|
-
async function openMemory(rawId: string) {
|
|
72
|
-
const { db, paths } = getCtx()
|
|
73
|
-
const group = groupRepo.get(db, rawId, paths)
|
|
74
|
-
if (!group) throw new Error(`group not found: ${rawId}`)
|
|
75
|
-
const mem = qmdBackend(join(group.path, 'memory'))
|
|
76
|
-
await mem.init()
|
|
77
|
-
return { mem, group }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
groupsRouter.get('/:id/memory', async (c) => {
|
|
81
|
-
try {
|
|
82
|
-
const { mem } = await openMemory(c.req.param('id'))
|
|
83
|
-
return c.json(await mem.list())
|
|
84
|
-
} catch (err) {
|
|
85
|
-
return c.json({ error: (err as Error).message }, 404)
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
groupsRouter.get('/:id/memory/search', async (c) => {
|
|
90
|
-
const q = c.req.query('q')
|
|
91
|
-
if (!q) return c.json({ error: 'q is required' }, 400)
|
|
92
|
-
const limit = Number.parseInt(c.req.query('limit') ?? '10', 10)
|
|
93
|
-
try {
|
|
94
|
-
const { mem } = await openMemory(c.req.param('id'))
|
|
95
|
-
return c.json(await mem.search(q, { limit }))
|
|
96
|
-
} catch (err) {
|
|
97
|
-
return c.json({ error: (err as Error).message }, 404)
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
// `:key{.+}` matches multi-segment paths so memory keys with slashes (e.g.
|
|
102
|
-
// `notes/2026-04-25.md`) survive the routing layer. Without the regex Hono
|
|
103
|
-
// would only capture a single segment.
|
|
104
|
-
groupsRouter.get('/:id/memory/:key{.+}', async (c) => {
|
|
105
|
-
try {
|
|
106
|
-
const { mem } = await openMemory(c.req.param('id'))
|
|
107
|
-
return c.json(await mem.read(c.req.param('key')))
|
|
108
|
-
} catch (err) {
|
|
109
|
-
return c.json({ error: (err as Error).message }, 404)
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
groupsRouter.put('/:id/memory/:key{.+}', async (c) => {
|
|
114
|
-
const body = (await c.req.json().catch(() => null)) as { content?: string } | null
|
|
115
|
-
if (!body || typeof body.content !== 'string')
|
|
116
|
-
return c.json({ error: 'content is required' }, 400)
|
|
117
|
-
try {
|
|
118
|
-
const { mem } = await openMemory(c.req.param('id'))
|
|
119
|
-
return c.json(await mem.write(c.req.param('key'), body.content))
|
|
120
|
-
} catch (err) {
|
|
121
|
-
return c.json({ error: (err as Error).message }, 500)
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
groupsRouter.delete('/:id/memory/:key{.+}', async (c) => {
|
|
126
|
-
try {
|
|
127
|
-
const { mem } = await openMemory(c.req.param('id'))
|
|
128
|
-
await mem.remove(c.req.param('key'))
|
|
129
|
-
return c.body(null, 204)
|
|
130
|
-
} catch (err) {
|
|
131
|
-
return c.json({ error: (err as Error).message }, 500)
|
|
132
|
-
}
|
|
133
|
-
})
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// /api/messages/:id — fetch + mark-read for a single message. (Inbox listing
|
|
2
|
-
// + send is per-agent at /api/agents/:id/messages.)
|
|
3
|
-
|
|
4
|
-
import type { UpdateMessageRequest } from '@bazilion/api-types'
|
|
5
|
-
import { Hono } from 'hono'
|
|
6
|
-
import { messageRepo } from '../core/index.ts'
|
|
7
|
-
import { getCtx } from '../lib/ctx.ts'
|
|
8
|
-
|
|
9
|
-
export const messagesRouter = new Hono()
|
|
10
|
-
|
|
11
|
-
messagesRouter.get('/:id', (c) => {
|
|
12
|
-
const { db } = getCtx()
|
|
13
|
-
const msg = messageRepo.get(db, c.req.param('id'))
|
|
14
|
-
if (!msg) return c.json({ error: `message not found: ${c.req.param('id')}` }, 404)
|
|
15
|
-
return c.json(msg)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
messagesRouter.patch('/:id', async (c) => {
|
|
19
|
-
const id = c.req.param('id')
|
|
20
|
-
const body = (await c.req.json().catch(() => null)) as UpdateMessageRequest | null
|
|
21
|
-
if (!body || body.read !== true) {
|
|
22
|
-
return c.json({ error: 'body must be {read: true}' }, 400)
|
|
23
|
-
}
|
|
24
|
-
const { db } = getCtx()
|
|
25
|
-
const existing = messageRepo.get(db, id)
|
|
26
|
-
if (!existing) return c.json({ error: `message not found: ${id}` }, 404)
|
|
27
|
-
messageRepo.markRead(db, id)
|
|
28
|
-
return c.json(messageRepo.get(db, id))
|
|
29
|
-
})
|