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.
- package/README.md +53 -152
- package/dist/cli.js +2730 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon.js +5888 -0
- package/dist/daemon.js.map +1 -0
- package/dist/worker.js +1830 -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,83 +0,0 @@
|
|
|
1
|
-
import type { Profile, SkillsMode } from '@bazilion/api-types'
|
|
2
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
3
|
-
|
|
4
|
-
interface RawProfile {
|
|
5
|
-
id: string
|
|
6
|
-
name: string
|
|
7
|
-
dir: string
|
|
8
|
-
default_model: string
|
|
9
|
-
skills_mode: string
|
|
10
|
-
created_at: number
|
|
11
|
-
updated_at: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function toProfile(r: RawProfile): Profile {
|
|
15
|
-
return {
|
|
16
|
-
id: r.id,
|
|
17
|
-
name: r.name,
|
|
18
|
-
dir: r.dir,
|
|
19
|
-
defaultModel: r.default_model,
|
|
20
|
-
skillsMode: r.skills_mode as SkillsMode,
|
|
21
|
-
createdAt: r.created_at,
|
|
22
|
-
updatedAt: r.updated_at,
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function insert(db: BazilionDb, p: Omit<Profile, 'createdAt' | 'updatedAt'>): Profile {
|
|
27
|
-
const now = Date.now()
|
|
28
|
-
db.raw.run(
|
|
29
|
-
`INSERT INTO profiles (id, name, dir, default_model, skills_mode, created_at, updated_at)
|
|
30
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
31
|
-
[p.id, p.name, p.dir, p.defaultModel, p.skillsMode, now, now],
|
|
32
|
-
)
|
|
33
|
-
return { ...p, createdAt: now, updatedAt: now }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function get(db: BazilionDb, id: string): Profile | null {
|
|
37
|
-
const row = db.raw.query<RawProfile, [string]>('SELECT * FROM profiles WHERE id = ?').get(id)
|
|
38
|
-
return row ? toProfile(row) : null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function list(db: BazilionDb): Profile[] {
|
|
42
|
-
return db.raw
|
|
43
|
-
.query<RawProfile, []>('SELECT * FROM profiles ORDER BY created_at ASC')
|
|
44
|
-
.all()
|
|
45
|
-
.map(toProfile)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function remove(db: BazilionDb, id: string): void {
|
|
49
|
-
db.raw.run('DELETE FROM profiles WHERE id = ?', [id])
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function update(
|
|
53
|
-
db: BazilionDb,
|
|
54
|
-
id: string,
|
|
55
|
-
fields: { name: string; defaultModel: string; skillsMode: SkillsMode },
|
|
56
|
-
): void {
|
|
57
|
-
db.raw.run(
|
|
58
|
-
`UPDATE profiles
|
|
59
|
-
SET name = ?, default_model = ?, skills_mode = ?, updated_at = ?
|
|
60
|
-
WHERE id = ?`,
|
|
61
|
-
[fields.name, fields.defaultModel, fields.skillsMode, Date.now(), id],
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function setDefaultSkills(db: BazilionDb, profileId: string, skills: string[]): void {
|
|
66
|
-
const tx = db.raw.transaction(() => {
|
|
67
|
-
db.raw.run('DELETE FROM profile_default_skills WHERE profile_id = ?', [profileId])
|
|
68
|
-
const stmt = db.raw.query(
|
|
69
|
-
'INSERT INTO profile_default_skills (profile_id, skill_name) VALUES (?, ?)',
|
|
70
|
-
)
|
|
71
|
-
for (const s of skills) stmt.run(profileId, s)
|
|
72
|
-
})
|
|
73
|
-
tx()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function getDefaultSkills(db: BazilionDb, profileId: string): string[] {
|
|
77
|
-
return db.raw
|
|
78
|
-
.query<{ skill_name: string }, [string]>(
|
|
79
|
-
'SELECT skill_name FROM profile_default_skills WHERE profile_id = ? ORDER BY skill_name',
|
|
80
|
-
)
|
|
81
|
-
.all(profileId)
|
|
82
|
-
.map((r) => r.skill_name)
|
|
83
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
2
|
-
|
|
3
|
-
interface RawRow {
|
|
4
|
-
provider: string
|
|
5
|
-
model: string
|
|
6
|
-
added_at: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** Curated model names for one provider, in insertion order. */
|
|
10
|
-
export function list(db: BazilionDb, provider: string): string[] {
|
|
11
|
-
return db.raw
|
|
12
|
-
.query<RawRow, [string]>(
|
|
13
|
-
'SELECT * FROM provider_models WHERE provider = ? ORDER BY added_at ASC',
|
|
14
|
-
)
|
|
15
|
-
.all(provider)
|
|
16
|
-
.map((r) => r.model)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** All curated models grouped by provider. Empty providers are omitted. */
|
|
20
|
-
export function listAll(db: BazilionDb): Record<string, string[]> {
|
|
21
|
-
const out: Record<string, string[]> = {}
|
|
22
|
-
for (const row of db.raw
|
|
23
|
-
.query<RawRow, []>('SELECT * FROM provider_models ORDER BY provider ASC, added_at ASC')
|
|
24
|
-
.all()) {
|
|
25
|
-
const bucket = out[row.provider] ?? []
|
|
26
|
-
bucket.push(row.model)
|
|
27
|
-
out[row.provider] = bucket
|
|
28
|
-
}
|
|
29
|
-
return out
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Replace the curated list for one provider atomically. Empty `models` clears
|
|
34
|
-
* the list. De-dupes (case-sensitive) and preserves incoming order.
|
|
35
|
-
*/
|
|
36
|
-
export function replace(db: BazilionDb, provider: string, models: string[]): void {
|
|
37
|
-
const seen = new Set<string>()
|
|
38
|
-
const clean = models
|
|
39
|
-
.map((m) => m.trim())
|
|
40
|
-
.filter((m) => m.length > 0 && !seen.has(m) && seen.add(m))
|
|
41
|
-
db.raw.transaction(() => {
|
|
42
|
-
db.raw.run('DELETE FROM provider_models WHERE provider = ?', [provider])
|
|
43
|
-
const now = Date.now()
|
|
44
|
-
for (let i = 0; i < clean.length; i++) {
|
|
45
|
-
// Offset by index so ordering is preserved by added_at.
|
|
46
|
-
db.raw.run('INSERT INTO provider_models (provider, model, added_at) VALUES (?, ?, ?)', [
|
|
47
|
-
provider,
|
|
48
|
-
clean[i] as string,
|
|
49
|
-
now + i,
|
|
50
|
-
])
|
|
51
|
-
}
|
|
52
|
-
})()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** Remove a single curated model. No-op if not present. */
|
|
56
|
-
export function remove(db: BazilionDb, provider: string, model: string): void {
|
|
57
|
-
db.raw.run('DELETE FROM provider_models WHERE provider = ? AND model = ?', [provider, model])
|
|
58
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
2
|
-
|
|
3
|
-
interface RawRow {
|
|
4
|
-
provider_id: string
|
|
5
|
-
enabled: number
|
|
6
|
-
updated_at: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function isEnabled(db: BazilionDb, providerId: string): boolean {
|
|
10
|
-
const row = db.raw
|
|
11
|
-
.query<RawRow, [string]>('SELECT * FROM provider_state WHERE provider_id = ?')
|
|
12
|
-
.get(providerId)
|
|
13
|
-
return row?.enabled === 1
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function setEnabled(db: BazilionDb, providerId: string, enabled: boolean): void {
|
|
17
|
-
db.raw.run(
|
|
18
|
-
`INSERT INTO provider_state (provider_id, enabled, updated_at)
|
|
19
|
-
VALUES (?, ?, ?)
|
|
20
|
-
ON CONFLICT (provider_id) DO UPDATE SET
|
|
21
|
-
enabled = excluded.enabled,
|
|
22
|
-
updated_at = excluded.updated_at`,
|
|
23
|
-
[providerId, enabled ? 1 : 0, Date.now()],
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Set of provider ids currently toggled on. Convenience for batch checks. */
|
|
28
|
-
export function listEnabled(db: BazilionDb): Set<string> {
|
|
29
|
-
return new Set(
|
|
30
|
-
db.raw
|
|
31
|
-
.query<{ provider_id: string }, []>(
|
|
32
|
-
'SELECT provider_id FROM provider_state WHERE enabled = 1',
|
|
33
|
-
)
|
|
34
|
-
.all()
|
|
35
|
-
.map((r) => r.provider_id),
|
|
36
|
-
)
|
|
37
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// Encrypted secrets store, backed by the `secrets` table.
|
|
2
|
-
//
|
|
3
|
-
// Layout: one row per env-var-shaped key (`ANTHROPIC_API_KEY`,
|
|
4
|
-
// `OPENAI_CODEX_OAUTH`, …). Each value is an AES-256-GCM envelope (salt +
|
|
5
|
-
// iv + tag + data, hex-encoded JSON), with the key derived from the
|
|
6
|
-
// bootstrap token via PBKDF2-SHA256 (100k iterations). The crypto matches
|
|
7
|
-
// the previous `secrets.enc` file format byte-for-byte — only the storage
|
|
8
|
-
// medium changed.
|
|
9
|
-
//
|
|
10
|
-
// Why encrypt at all when the password lives in `~/.bazilion/auth.json`
|
|
11
|
-
// next to the DB? Same reason as before: it's defense against accidental
|
|
12
|
-
// exposure (cat'd dumps, screenshares, naive backups), not against an
|
|
13
|
-
// attacker with filesystem read. Anyone who can read both files wins.
|
|
14
|
-
//
|
|
15
|
-
// Caching: `deriveKey` runs PBKDF2 once per (password, salt) pair and the
|
|
16
|
-
// salt is per-row, so a busy daemon does ~one PBKDF2 per secret read. The
|
|
17
|
-
// `secretCache` keeps decrypted values in-memory keyed by row id so repeated
|
|
18
|
-
// reads inside one process don't repeat the work; mutations clear the cache
|
|
19
|
-
// row.
|
|
20
|
-
|
|
21
|
-
import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from 'node:crypto'
|
|
22
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
23
|
-
|
|
24
|
-
const ALGORITHM = 'aes-256-gcm'
|
|
25
|
-
const KEY_LEN = 32
|
|
26
|
-
const ITERATIONS = 100_000
|
|
27
|
-
const DIGEST = 'sha256'
|
|
28
|
-
|
|
29
|
-
interface EncryptedEnvelope {
|
|
30
|
-
salt: string
|
|
31
|
-
iv: string
|
|
32
|
-
tag: string
|
|
33
|
-
data: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function deriveKey(password: string, salt: Buffer): Buffer {
|
|
37
|
-
return pbkdf2Sync(password, salt, ITERATIONS, KEY_LEN, DIGEST)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function encrypt(plaintext: string, password: string): EncryptedEnvelope {
|
|
41
|
-
const salt = randomBytes(16)
|
|
42
|
-
const key = deriveKey(password, salt)
|
|
43
|
-
const iv = randomBytes(12)
|
|
44
|
-
const cipher = createCipheriv(ALGORITHM, key, iv)
|
|
45
|
-
let data = cipher.update(plaintext, 'utf8', 'hex')
|
|
46
|
-
data += cipher.final('hex')
|
|
47
|
-
const tag = cipher.getAuthTag()
|
|
48
|
-
return {
|
|
49
|
-
salt: salt.toString('hex'),
|
|
50
|
-
iv: iv.toString('hex'),
|
|
51
|
-
tag: tag.toString('hex'),
|
|
52
|
-
data,
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function decrypt(envelope: EncryptedEnvelope, password: string): string {
|
|
57
|
-
const salt = Buffer.from(envelope.salt, 'hex')
|
|
58
|
-
const key = deriveKey(password, salt)
|
|
59
|
-
const iv = Buffer.from(envelope.iv, 'hex')
|
|
60
|
-
const tag = Buffer.from(envelope.tag, 'hex')
|
|
61
|
-
const decipher = createDecipheriv(ALGORITHM, key, iv)
|
|
62
|
-
decipher.setAuthTag(tag)
|
|
63
|
-
let plaintext = decipher.update(envelope.data, 'hex', 'utf8')
|
|
64
|
-
plaintext += decipher.final('utf8')
|
|
65
|
-
return plaintext
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface RawRow {
|
|
69
|
-
key: string
|
|
70
|
-
envelope: string
|
|
71
|
-
updated_at: number
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface SecretsStore {
|
|
75
|
-
get(key: string): string | undefined
|
|
76
|
-
set(key: string, value: string): void
|
|
77
|
-
remove(key: string): void
|
|
78
|
-
has(key: string): boolean
|
|
79
|
-
list(): { key: string; preview: string }[]
|
|
80
|
-
getAll(): Record<string, string>
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Open the encrypted secrets store. `password` is the bootstrap token
|
|
85
|
-
* (read from `auth.json` by the caller). Throws on individual-row decrypt
|
|
86
|
-
* failures only when actively reading that row — bad rows show as
|
|
87
|
-
* `undefined` from `get`, the caller can `set` to overwrite.
|
|
88
|
-
*/
|
|
89
|
-
export function openSecrets(db: BazilionDb, password: string): SecretsStore {
|
|
90
|
-
function getRow(key: string): RawRow | null {
|
|
91
|
-
return db.raw.query<RawRow, [string]>('SELECT * FROM secrets WHERE key = ?').get(key)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function listAll(): RawRow[] {
|
|
95
|
-
return db.raw.query<RawRow, []>('SELECT * FROM secrets ORDER BY key ASC').all()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function tryDecrypt(row: RawRow): string | undefined {
|
|
99
|
-
try {
|
|
100
|
-
const envelope = JSON.parse(row.envelope) as EncryptedEnvelope
|
|
101
|
-
return decrypt(envelope, password)
|
|
102
|
-
} catch {
|
|
103
|
-
return undefined
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
get(key) {
|
|
109
|
-
const row = getRow(key)
|
|
110
|
-
if (!row) return undefined
|
|
111
|
-
return tryDecrypt(row)
|
|
112
|
-
},
|
|
113
|
-
set(key, value) {
|
|
114
|
-
const envelope = JSON.stringify(encrypt(value, password))
|
|
115
|
-
db.raw.run(
|
|
116
|
-
`INSERT INTO secrets (key, envelope, updated_at) VALUES (?, ?, ?)
|
|
117
|
-
ON CONFLICT(key) DO UPDATE SET envelope = excluded.envelope, updated_at = excluded.updated_at`,
|
|
118
|
-
[key, envelope, Date.now()],
|
|
119
|
-
)
|
|
120
|
-
},
|
|
121
|
-
remove(key) {
|
|
122
|
-
db.raw.run('DELETE FROM secrets WHERE key = ?', [key])
|
|
123
|
-
},
|
|
124
|
-
has(key) {
|
|
125
|
-
return getRow(key) !== null
|
|
126
|
-
},
|
|
127
|
-
list() {
|
|
128
|
-
return listAll().map((r) => {
|
|
129
|
-
const value = tryDecrypt(r)
|
|
130
|
-
return {
|
|
131
|
-
key: r.key,
|
|
132
|
-
preview: value ? (value.length > 8 ? `${value.slice(0, 6)}…` : '***') : '(unreadable)',
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
},
|
|
136
|
-
getAll() {
|
|
137
|
-
const out: Record<string, string> = {}
|
|
138
|
-
for (const r of listAll()) {
|
|
139
|
-
const v = tryDecrypt(r)
|
|
140
|
-
if (v !== undefined) out[r.key] = v
|
|
141
|
-
}
|
|
142
|
-
return out
|
|
143
|
-
},
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { SkillMeta } from '@bazilion/api-types'
|
|
2
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
3
|
-
|
|
4
|
-
interface RawMeta {
|
|
5
|
-
name: string
|
|
6
|
-
source: string | null
|
|
7
|
-
imported_at: number | null
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function toMeta(r: RawMeta): SkillMeta {
|
|
11
|
-
return {
|
|
12
|
-
name: r.name,
|
|
13
|
-
source: r.source,
|
|
14
|
-
importedAt: r.imported_at,
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function get(db: BazilionDb, name: string): SkillMeta | null {
|
|
19
|
-
const row = db.raw.query<RawMeta, [string]>('SELECT * FROM skill_meta WHERE name = ?').get(name)
|
|
20
|
-
return row ? toMeta(row) : null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function listAll(db: BazilionDb): SkillMeta[] {
|
|
24
|
-
return db.raw.query<RawMeta, []>('SELECT * FROM skill_meta ORDER BY name ASC').all().map(toMeta)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface UpsertInput {
|
|
28
|
-
name: string
|
|
29
|
-
source?: string | null
|
|
30
|
-
importedAt?: number | null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function upsert(db: BazilionDb, input: UpsertInput): SkillMeta {
|
|
34
|
-
const existing = get(db, input.name)
|
|
35
|
-
const source = input.source !== undefined ? input.source : (existing?.source ?? null)
|
|
36
|
-
const importedAt =
|
|
37
|
-
input.importedAt !== undefined ? input.importedAt : (existing?.importedAt ?? null)
|
|
38
|
-
db.raw.run(
|
|
39
|
-
`INSERT INTO skill_meta (name, source, imported_at)
|
|
40
|
-
VALUES (?, ?, ?)
|
|
41
|
-
ON CONFLICT(name) DO UPDATE SET source = excluded.source, imported_at = excluded.imported_at`,
|
|
42
|
-
[input.name, source, importedAt],
|
|
43
|
-
)
|
|
44
|
-
return { name: input.name, source, importedAt }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function remove(db: BazilionDb, name: string): void {
|
|
48
|
-
db.raw.run('DELETE FROM skill_meta WHERE name = ?', [name])
|
|
49
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto'
|
|
2
|
-
import type { AgentTrigger, TriggerKind } from '@bazilion/api-types'
|
|
3
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
4
|
-
|
|
5
|
-
interface RawTrigger {
|
|
6
|
-
id: string
|
|
7
|
-
agent_id: string
|
|
8
|
-
kind: string
|
|
9
|
-
interval_sec: number | null
|
|
10
|
-
cron_expr: string | null
|
|
11
|
-
message: string
|
|
12
|
-
enabled: number
|
|
13
|
-
last_fired_at: number | null
|
|
14
|
-
created_at: number
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function toTrigger(r: RawTrigger): AgentTrigger {
|
|
18
|
-
return {
|
|
19
|
-
id: r.id,
|
|
20
|
-
agentId: r.agent_id,
|
|
21
|
-
kind: r.kind as TriggerKind,
|
|
22
|
-
intervalSec: r.interval_sec,
|
|
23
|
-
cronExpr: r.cron_expr,
|
|
24
|
-
message: r.message,
|
|
25
|
-
enabled: r.enabled === 1,
|
|
26
|
-
lastFiredAt: r.last_fired_at,
|
|
27
|
-
createdAt: r.created_at,
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface InsertTriggerInput {
|
|
32
|
-
agentId: string
|
|
33
|
-
kind: TriggerKind
|
|
34
|
-
intervalSec: number | null
|
|
35
|
-
cronExpr: string | null
|
|
36
|
-
message: string
|
|
37
|
-
enabled?: boolean
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function insert(db: BazilionDb, input: InsertTriggerInput): AgentTrigger {
|
|
41
|
-
const id = randomUUID()
|
|
42
|
-
const now = Date.now()
|
|
43
|
-
const enabled = input.enabled === false ? 0 : 1
|
|
44
|
-
db.raw.run(
|
|
45
|
-
`INSERT INTO agent_triggers
|
|
46
|
-
(id, agent_id, kind, interval_sec, cron_expr, message, enabled, last_fired_at, created_at)
|
|
47
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?)`,
|
|
48
|
-
[id, input.agentId, input.kind, input.intervalSec, input.cronExpr, input.message, enabled, now],
|
|
49
|
-
)
|
|
50
|
-
return {
|
|
51
|
-
id,
|
|
52
|
-
agentId: input.agentId,
|
|
53
|
-
kind: input.kind,
|
|
54
|
-
intervalSec: input.intervalSec,
|
|
55
|
-
cronExpr: input.cronExpr,
|
|
56
|
-
message: input.message,
|
|
57
|
-
enabled: enabled === 1,
|
|
58
|
-
lastFiredAt: null,
|
|
59
|
-
createdAt: now,
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function get(db: BazilionDb, id: string): AgentTrigger | null {
|
|
64
|
-
const row = db.raw
|
|
65
|
-
.query<RawTrigger, [string]>('SELECT * FROM agent_triggers WHERE id = ?')
|
|
66
|
-
.get(id)
|
|
67
|
-
return row ? toTrigger(row) : null
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function listForAgent(db: BazilionDb, agentId: string): AgentTrigger[] {
|
|
71
|
-
return db.raw
|
|
72
|
-
.query<RawTrigger, [string]>(
|
|
73
|
-
'SELECT * FROM agent_triggers WHERE agent_id = ? ORDER BY created_at ASC',
|
|
74
|
-
)
|
|
75
|
-
.all(agentId)
|
|
76
|
-
.map(toTrigger)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function listEnabled(db: BazilionDb): AgentTrigger[] {
|
|
80
|
-
return db.raw
|
|
81
|
-
.query<RawTrigger, []>(
|
|
82
|
-
`SELECT t.* FROM agent_triggers t
|
|
83
|
-
JOIN agents a ON a.id = t.agent_id
|
|
84
|
-
WHERE t.enabled = 1 AND a.status != 'archived'
|
|
85
|
-
ORDER BY t.created_at ASC`,
|
|
86
|
-
)
|
|
87
|
-
.all()
|
|
88
|
-
.map(toTrigger)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function setEnabled(db: BazilionDb, id: string, enabled: boolean): void {
|
|
92
|
-
db.raw.run('UPDATE agent_triggers SET enabled = ? WHERE id = ?', [enabled ? 1 : 0, id])
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function markFired(db: BazilionDb, id: string, when: number = Date.now()): void {
|
|
96
|
-
db.raw.run('UPDATE agent_triggers SET last_fired_at = ? WHERE id = ?', [when, id])
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function remove(db: BazilionDb, id: string): void {
|
|
100
|
-
db.raw.run('DELETE FROM agent_triggers WHERE id = ?', [id])
|
|
101
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { createHash, randomBytes, randomUUID } from 'node:crypto'
|
|
2
|
-
import type { WebToken } from '@bazilion/api-types'
|
|
3
|
-
import type { BazilionDb } from '../db/client.ts'
|
|
4
|
-
|
|
5
|
-
interface RawToken {
|
|
6
|
-
id: string
|
|
7
|
-
label: string
|
|
8
|
-
token_hash: string
|
|
9
|
-
created_at: number
|
|
10
|
-
last_used_at: number | null
|
|
11
|
-
revoked_at: number | null
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function toToken(r: RawToken): WebToken {
|
|
15
|
-
return {
|
|
16
|
-
id: r.id,
|
|
17
|
-
label: r.label,
|
|
18
|
-
createdAt: r.created_at,
|
|
19
|
-
lastUsedAt: r.last_used_at,
|
|
20
|
-
revokedAt: r.revoked_at,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function hashToken(token: string): string {
|
|
25
|
-
return createHash('sha256').update(token).digest('hex')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface CreatedToken {
|
|
29
|
-
meta: WebToken
|
|
30
|
-
/** Plaintext token — shown exactly once, never re-queryable. */
|
|
31
|
-
token: string
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function create(db: BazilionDb, label: string): CreatedToken {
|
|
35
|
-
const id = randomUUID()
|
|
36
|
-
const token = randomBytes(24).toString('hex')
|
|
37
|
-
const tokenHash = hashToken(token)
|
|
38
|
-
const now = Date.now()
|
|
39
|
-
db.raw.run(
|
|
40
|
-
`INSERT INTO web_tokens (id, label, token_hash, created_at, last_used_at, revoked_at)
|
|
41
|
-
VALUES (?, ?, ?, ?, NULL, NULL)`,
|
|
42
|
-
[id, label, tokenHash, now],
|
|
43
|
-
)
|
|
44
|
-
return {
|
|
45
|
-
token,
|
|
46
|
-
meta: { id, label, createdAt: now, lastUsedAt: null, revokedAt: null },
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function list(db: BazilionDb, opts?: { includeRevoked?: boolean }): WebToken[] {
|
|
51
|
-
const sql = opts?.includeRevoked
|
|
52
|
-
? 'SELECT * FROM web_tokens ORDER BY created_at ASC'
|
|
53
|
-
: 'SELECT * FROM web_tokens WHERE revoked_at IS NULL ORDER BY created_at ASC'
|
|
54
|
-
return db.raw.query<RawToken, []>(sql).all().map(toToken)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function get(db: BazilionDb, id: string): WebToken | null {
|
|
58
|
-
const row = db.raw.query<RawToken, [string]>('SELECT * FROM web_tokens WHERE id = ?').get(id)
|
|
59
|
-
return row ? toToken(row) : null
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Returns the active token row matching the given plaintext, or null.
|
|
64
|
-
* Does NOT bump last_used_at — call markUsed separately once the caller
|
|
65
|
-
* has decided the request is authorized.
|
|
66
|
-
*/
|
|
67
|
-
export function findActiveByToken(db: BazilionDb, token: string): WebToken | null {
|
|
68
|
-
const tokenHash = hashToken(token)
|
|
69
|
-
const row = db.raw
|
|
70
|
-
.query<RawToken, [string]>(
|
|
71
|
-
'SELECT * FROM web_tokens WHERE token_hash = ? AND revoked_at IS NULL',
|
|
72
|
-
)
|
|
73
|
-
.get(tokenHash)
|
|
74
|
-
return row ? toToken(row) : null
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function markUsed(db: BazilionDb, id: string, when: number = Date.now()): void {
|
|
78
|
-
db.raw.run('UPDATE web_tokens SET last_used_at = ? WHERE id = ?', [when, id])
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function revoke(db: BazilionDb, id: string, when: number = Date.now()): boolean {
|
|
82
|
-
const res = db.raw.run(
|
|
83
|
-
'UPDATE web_tokens SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL',
|
|
84
|
-
[when, id],
|
|
85
|
-
)
|
|
86
|
-
return res.changes > 0
|
|
87
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// Auth / secrets entry points keyed off the bootstrap `auth.json` file.
|
|
2
|
-
//
|
|
3
|
-
// `auth.json` carries one mandatory field — `token` — written by the daemon's
|
|
4
|
-
// first-run bootstrap. The daemon uses it as the PBKDF2 seed for the `secrets`
|
|
5
|
-
// table; the CLI uses it as the bearer for loopback HTTP. CLI-side `remote`
|
|
6
|
-
// overrides (set by `bazilion login`) coexist in the same file.
|
|
7
|
-
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
9
|
-
import type { BazilionDb } from './db/client.ts'
|
|
10
|
-
import { openConfig } from './repos/config.ts'
|
|
11
|
-
import { openSecrets } from './repos/secrets.ts'
|
|
12
|
-
|
|
13
|
-
export interface AuthFile {
|
|
14
|
-
token: string
|
|
15
|
-
remote?: { server: string; token: string } | null
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Read `auth.json` and return the parsed contents. Throws when missing or
|
|
20
|
-
* malformed — callers should treat that as "bazilion not initialized."
|
|
21
|
-
*/
|
|
22
|
-
export function readAuthFile(authFile: string): AuthFile {
|
|
23
|
-
if (!existsSync(authFile)) {
|
|
24
|
-
throw new Error(`${authFile} not found. Start the daemon (\`bazilion serve\`) — it auto-bootstraps on first run.`)
|
|
25
|
-
}
|
|
26
|
-
const raw = readFileSync(authFile, 'utf8')
|
|
27
|
-
const parsed = JSON.parse(raw) as Partial<AuthFile>
|
|
28
|
-
if (typeof parsed.token !== 'string' || !parsed.token) {
|
|
29
|
-
throw new Error(`${authFile} is missing the "token" field`)
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
token: parsed.token,
|
|
33
|
-
remote: parsed.remote ?? null,
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Merge plaintext config + decrypted secrets + process env into a single
|
|
39
|
-
* env-shaped record. Precedence (low → high): config → secrets → env. The
|
|
40
|
-
* caller supplies the bootstrap `password` (typically `readAuthFile().token`)
|
|
41
|
-
* because the secrets table is encrypted with it.
|
|
42
|
-
*
|
|
43
|
-
* Either layer may fail to read (corrupt row, wrong key, table absent at
|
|
44
|
-
* fixture-bootstrap time); failures are swallowed per-layer so a single bad
|
|
45
|
-
* value never blocks the merge.
|
|
46
|
-
*/
|
|
47
|
-
export function mergeSecretsIntoEnv(
|
|
48
|
-
db: BazilionDb,
|
|
49
|
-
password: string,
|
|
50
|
-
env: NodeJS.ProcessEnv = process.env,
|
|
51
|
-
): NodeJS.ProcessEnv {
|
|
52
|
-
let configValues: Record<string, string> = {}
|
|
53
|
-
let secretValues: Record<string, string> = {}
|
|
54
|
-
try {
|
|
55
|
-
configValues = openConfig(db).getAll()
|
|
56
|
-
} catch {
|
|
57
|
-
// table missing or unreadable — continue without the layer
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
secretValues = openSecrets(db, password).getAll()
|
|
61
|
-
} catch {
|
|
62
|
-
// table missing or wrong password — continue without the layer
|
|
63
|
-
}
|
|
64
|
-
return { ...configValues, ...secretValues, ...env }
|
|
65
|
-
}
|