bazilion 0.7.0 → 0.9.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 (166) hide show
  1. package/README.md +47 -5
  2. package/dist/cli.js +1257 -638
  3. package/dist/cli.js.map +1 -1
  4. package/dist/daemon.js +5334 -1594
  5. package/dist/daemon.js.map +1 -1
  6. package/dist/migrations/0001_init.sql +318 -88
  7. package/dist/web/client/assets/{FieldRow-CNKma5LE.js → FieldRow-DmwAFfbF.js} +1 -1
  8. package/dist/web/client/assets/ProductionTeamPolicyEditor-1a5jQqUB.js +7 -0
  9. package/dist/web/client/assets/ProductionTeamPolicyEditor-DLioOiRN.css +1 -0
  10. package/dist/web/client/assets/ProfileCommunicationEditor-D1OZ8WE5.js +1 -0
  11. package/dist/web/client/assets/RecoveryState-QfMSuwy3.js +1 -0
  12. package/dist/web/client/assets/TeamTabs-BViZ4sti.js +1 -0
  13. package/dist/web/client/assets/TemplatesTabs-DVcY9pMD.js +1 -0
  14. package/dist/web/client/assets/_id-8P7brhGy.js +1 -0
  15. package/dist/web/client/assets/_id-C3o3MHq8.js +1 -0
  16. package/dist/web/client/assets/_id-DGRrSF1e.js +1 -0
  17. package/dist/web/client/assets/_id-DGyKURCp.js +1 -0
  18. package/dist/web/client/assets/_id-KnJe-aW9.js +1 -0
  19. package/dist/web/client/assets/activity-DJuhhQCb.js +1 -0
  20. package/dist/web/client/assets/activity-WWvJSo4t.js +1 -0
  21. package/dist/web/client/assets/agents-C32T1voV.js +1 -0
  22. package/dist/web/client/assets/agents-nH4m4gZ1.js +1 -0
  23. package/dist/web/client/assets/approvals-DGi0PSx8.js +1 -0
  24. package/dist/web/client/assets/approvals-l8jIZjqz.js +1 -0
  25. package/dist/web/client/assets/{config-BSAVT-17.js → config-C7wvi1nR.js} +2 -2
  26. package/dist/web/client/assets/context-BEGWE3RC.js +1 -0
  27. package/dist/web/client/assets/inbox--4aBaAgG.js +1 -0
  28. package/dist/web/client/assets/index-BCXoh1c8.js +12 -0
  29. package/dist/web/client/assets/{login-D8lNr2SX.js → login-Bk2wwIHQ.js} +1 -1
  30. package/dist/web/client/assets/{mcp-BLnngDsj.js → mcp-vM7xgh9e.js} +1 -1
  31. package/dist/web/client/assets/members-cPKfnrSL.js +1 -0
  32. package/dist/web/client/assets/memory-BOcsaemD.js +1 -0
  33. package/dist/web/client/assets/policy-BGLCJYvS.js +1 -0
  34. package/dist/web/client/assets/policy-K4hIbbIN.js +1 -0
  35. package/dist/web/client/assets/{preload-helper-CvnapA2_.js → preload-helper-eOOCz1Fu.js} +1 -1
  36. package/dist/web/client/assets/routes-DnrP3dwv.js +1 -0
  37. package/dist/web/client/assets/services-C2_O3ifw.js +1 -0
  38. package/dist/web/client/assets/skills-B__fLZjx.js +1 -0
  39. package/dist/web/client/assets/styles-Dn24-ZvP.css +2 -0
  40. package/dist/web/client/assets/team-policy-BdX340m4.js +1 -0
  41. package/dist/web/client/assets/teams-CSNyLz3l.js +1 -0
  42. package/dist/web/client/assets/teams-DZMB4_iw.js +1 -0
  43. package/dist/web/client/assets/teams-rpaYKNIb.js +1 -0
  44. package/dist/web/client/assets/telegram-B1O4Ko0V.js +1 -0
  45. package/dist/web/client/assets/{tokens-D2_O9ARe.js → tokens-D7FH9VgA.js} +1 -1
  46. package/dist/web/client/assets/triggers-3PLy2_Fo.js +1 -0
  47. package/dist/web/client/assets/welcome-B-QQobzq.js +1 -0
  48. package/dist/web/client/assets/{ChatPane-DzEgOEqS.js → wire-constants-BY9Q9Z7d.js} +4 -4
  49. package/dist/web/server/assets/{ChatPane-BvpswYvF.js → ChatPane-Dh3qxzdb.js} +23 -12
  50. package/dist/web/server/assets/ProductionTeamPolicyEditor-Bke5doyl.js +1009 -0
  51. package/dist/web/server/assets/ProfileCommunicationEditor-C2RU-2QB.js +107 -0
  52. package/dist/web/server/assets/RecoveryState-B2SG-mrY.js +37 -0
  53. package/dist/web/server/assets/{Sidebar-DmEiewRN.js → Sidebar-CGmtCnYU.js} +372 -48
  54. package/dist/web/server/assets/TeamTabs-BPxDBfqy.js +50 -0
  55. package/dist/web/server/assets/{TemplatesTabs---7h5GYa.js → TemplatesTabs-zf4YhStd.js} +6 -6
  56. package/dist/web/server/assets/{_id-CXg-Blec.js → _id-5lLzLwcv.js} +52 -40
  57. package/dist/web/server/assets/_id-A8Xiv6Lc.js +11 -0
  58. package/dist/web/server/assets/{_id-BqnDy_Ca.js → _id-B04VaQlh.js} +6 -5
  59. package/dist/web/server/assets/{_id-D0ytyXGY.js → _id-B6g9wmPR.js} +167 -31
  60. package/dist/web/server/assets/_id-ButXHnRH.js +14 -0
  61. package/dist/web/server/assets/_id-C4AOhstq.js +44 -0
  62. package/dist/web/server/assets/{_id-DDixKEud.js → _id-CCHA0gdR.js} +72 -12
  63. package/dist/web/server/assets/{_id-D_Ew11ED.js → _id-CUWgTqMS.js} +8 -8
  64. package/dist/web/server/assets/_id-DJkzwHjM.js +42 -0
  65. package/dist/web/server/assets/{_id-CnQflrRv.js → _id-DdC9wpNN.js} +5 -5
  66. package/dist/web/server/assets/{_id-81NrHA5d.js → _id-DkFgCIb-.js} +9 -1
  67. package/dist/web/server/assets/{_id-D8duqgd5.js → _id-_nFwi9gD.js} +5 -4
  68. package/dist/web/server/assets/{_id-Sjw0zhA6.js → _id-fpFQ9_Ya.js} +4 -4
  69. package/dist/web/server/assets/_tanstack-start-manifest_v-Div-TukY.js +241 -0
  70. package/dist/web/server/assets/activity-C2ZKg1Q9.js +170 -0
  71. package/dist/web/server/assets/activity-CGCf8BQf.js +11 -0
  72. package/dist/web/server/assets/activity-DedraoFj.js +14 -0
  73. package/dist/web/server/assets/activity-GPx8NCeB.js +12 -0
  74. package/dist/web/server/assets/{profiles-CZ5NkmVw.js → agents-B8kinIPW.js} +4 -4
  75. package/dist/web/server/assets/{agents-k5QURC4I.js → agents-BR2qXlXF.js} +4 -4
  76. package/dist/web/server/assets/{agents-ChcAJUI5.js → agents-Bp1nsVs2.js} +1 -1
  77. package/dist/web/server/assets/{profiles-LxcC_L6n.js → agents-CUQmWhTp.js} +36 -10
  78. package/dist/web/server/assets/{agents-C7SBPN0M.js → agents-DU9Hqs58.js} +51 -12
  79. package/dist/web/server/assets/{profiles-C6a3RKgu.js → agents-LHowEI6S.js} +4 -4
  80. package/dist/web/server/assets/approvals-CbFXFvG8.js +11 -0
  81. package/dist/web/server/assets/approvals-DHgARzd8.js +242 -0
  82. package/dist/web/server/assets/approvals-Dw2LJoSA.js +14 -0
  83. package/dist/web/server/assets/approvals-VPc0YpLN.js +12 -0
  84. package/dist/web/server/assets/{auth-DzRAMwVt.js → auth-l-Vf8wlu.js} +5 -1
  85. package/dist/web/server/assets/{config-CdVjqjin.js → config-BvKctDOX.js} +4 -4
  86. package/dist/web/server/assets/{config-Bq3o924J.js → config-QvHaxGlP.js} +1 -1
  87. package/dist/web/server/assets/context-5lrf2ame.js +12 -0
  88. package/dist/web/server/assets/context-CEr4-xiA.js +49 -0
  89. package/dist/web/server/assets/context-D3Egm-vY.js +12 -0
  90. package/dist/web/server/assets/members-40DxRdVj.js +48 -0
  91. package/dist/web/server/assets/members-DlGBKZNl.js +12 -0
  92. package/dist/web/server/assets/members-ksELRsyk.js +12 -0
  93. package/dist/web/server/assets/{memory-Ns2-Z31p.js → memory-B5moRnnp.js} +5 -5
  94. package/dist/web/server/assets/{memory-BaYnfm7K.js → memory-CO0jKGzJ.js} +8 -8
  95. package/dist/web/server/assets/memory-CiTl4cN9.js +289 -0
  96. package/dist/web/server/assets/policy-BYVXqsan.js +11 -0
  97. package/dist/web/server/assets/policy-DNcGZLOB.js +21 -0
  98. package/dist/web/server/assets/policy-Dr55y-Mh.js +496 -0
  99. package/dist/web/server/assets/policy-Dxs78_GO.js +40 -0
  100. package/dist/web/server/assets/{router-BpBZgRwn.js → router-_izWQUeG.js} +156 -101
  101. package/dist/web/server/assets/{routes-Ce2VWrU9.js → routes-BSSKp3Rv.js} +4 -4
  102. package/dist/web/server/assets/{routes-C61gBiXa.js → routes-BrTOoeth.js} +5 -5
  103. package/dist/web/server/assets/{routes-V9URcp1v.js → routes-DOj6ljcm.js} +1 -1
  104. package/dist/web/server/assets/{services-B91w2f-X.js → services-CHe4ihJk.js} +11 -11
  105. package/dist/web/server/assets/{services-Ccc5s2bS.js → services-Pv_V88VA.js} +3 -3
  106. package/dist/web/server/assets/{skills-dLyBZb3B.js → skills-D89ND2kR.js} +67 -7
  107. package/dist/web/server/assets/{skills-CpsyR_WA.js → skills-l2cyQ3zS.js} +1 -1
  108. package/dist/web/server/assets/{start-CYDpZ6cb.js → start-DlHq0RaQ.js} +1 -1
  109. package/dist/web/server/assets/team-policy-Csvc5EDd.js +180 -0
  110. package/dist/web/server/assets/teams-35Oprf6e.js +14 -0
  111. package/dist/web/server/assets/teams-3im0oQnS.js +11 -0
  112. package/dist/web/server/assets/teams-B5IF65p2.js +12 -0
  113. package/dist/web/server/assets/teams-B9O-WDH5.js +108 -0
  114. package/dist/web/server/assets/teams-DFkN7ic7.js +36 -0
  115. package/dist/web/server/assets/teams-DH1CvWmT.js +12 -0
  116. package/dist/web/server/assets/teams-zcm9XaQU.js +174 -0
  117. package/dist/web/server/assets/{telegram-DfAddLdv.js → telegram-C9sQFwWj.js} +7 -7
  118. package/dist/web/server/assets/{telegram-T3l9KtiE.js → telegram-mTnJCOmn.js} +1 -1
  119. package/dist/web/server/assets/{welcome-CP4CZ9B6.js → welcome-CDGE2Sdk.js} +2 -2
  120. package/dist/web/server/assets/{wire-constants-Deb4NxBb.js → wire-constants-C8nBJcU3.js} +3 -3
  121. package/dist/web/server/server.js +64 -42
  122. package/dist/worker.js +180 -128
  123. package/dist/worker.js.map +1 -1
  124. package/package.json +7 -7
  125. package/dist/migrations/0002_profile_groups.sql +0 -38
  126. package/dist/migrations/0003_agent_telegram.sql +0 -40
  127. package/dist/migrations/0004_agent_mirror_mode.sql +0 -17
  128. package/dist/migrations/0005_group_topic_name_format.sql +0 -15
  129. package/dist/migrations/0006_telegram_acl.sql +0 -18
  130. package/dist/migrations/0007_mcp_servers.sql +0 -30
  131. package/dist/migrations/0008_seed_user_md.sql +0 -39
  132. package/dist/web/client/assets/MembersEditor-C6UpqDdV.js +0 -1
  133. package/dist/web/client/assets/SpawnTeamModal-BEkNCKXm.js +0 -1
  134. package/dist/web/client/assets/TemplatesTabs-Da7mg9FI.js +0 -1
  135. package/dist/web/client/assets/_id-BdKmo0gb.js +0 -1
  136. package/dist/web/client/assets/_id-LT6Ejjr0.js +0 -1
  137. package/dist/web/client/assets/_id-MR2XjWh0.js +0 -1
  138. package/dist/web/client/assets/_id-_6jIt0_-.js +0 -1
  139. package/dist/web/client/assets/agents-0arKbVYG.js +0 -1
  140. package/dist/web/client/assets/groups-BqTkhHes.js +0 -1
  141. package/dist/web/client/assets/inbox-ozoCXzr5.js +0 -1
  142. package/dist/web/client/assets/index-iayCEuU2.js +0 -12
  143. package/dist/web/client/assets/memory-D1GQjEvN.js +0 -1
  144. package/dist/web/client/assets/profile-groups-C2yJPTaE.js +0 -1
  145. package/dist/web/client/assets/profiles-BV7AAZjj.js +0 -1
  146. package/dist/web/client/assets/routes-DSHQLA7K.js +0 -1
  147. package/dist/web/client/assets/services-BbCJe1Du.js +0 -1
  148. package/dist/web/client/assets/skills-C6czKR5I.js +0 -1
  149. package/dist/web/client/assets/styles-C06axZZk.css +0 -2
  150. package/dist/web/client/assets/telegram-gE4j8gte.js +0 -1
  151. package/dist/web/client/assets/triggers-WljnfEfJ.js +0 -1
  152. package/dist/web/client/assets/welcome-Dn-zvmBE.js +0 -1
  153. package/dist/web/client/assets/wire-constants-BkT5-597.js +0 -1
  154. package/dist/web/server/assets/MembersEditor-BWQztvrX.js +0 -131
  155. package/dist/web/server/assets/SpawnTeamModal-dSN421k_.js +0 -107
  156. package/dist/web/server/assets/_id-BKev9H1p.js +0 -12
  157. package/dist/web/server/assets/_id-BNwlbWHP.js +0 -24
  158. package/dist/web/server/assets/_id-CRqqi8IE.js +0 -161
  159. package/dist/web/server/assets/_tanstack-start-manifest_v-DBlFH2gg.js +0 -178
  160. package/dist/web/server/assets/groups-CbSwND2r.js +0 -12
  161. package/dist/web/server/assets/groups-CeRRlZaZ.js +0 -150
  162. package/dist/web/server/assets/groups-pk4CYSuf.js +0 -21
  163. package/dist/web/server/assets/memory-CQaqWnyM.js +0 -284
  164. package/dist/web/server/assets/profile-groups-CiU06yN1.js +0 -28
  165. package/dist/web/server/assets/profile-groups-D21MYoLM.js +0 -208
  166. package/dist/web/server/assets/profile-groups-aoJleXHP.js +0 -12
@@ -1,43 +1,10 @@
1
- -- Bazilion initial schema (consolidated, post-IPC + secrets-in-DB cleanup).
2
- --
3
- -- The daemon is the sole owner of `~/.bazilion/`. All state — entity
4
- -- metadata, inbox, scheduler, web tokens, encrypted secrets, plaintext
5
- -- config — lives in this single SQLite file. The only other file at the
6
- -- bazilion home root is `auth.json`: a tiny bootstrap shared by the daemon
7
- -- (which uses its `token` as the PBKDF2 seed for the `secrets` table) and
8
- -- the CLI (which uses the same token as its loopback bearer).
9
- --
10
- -- On-disk layout owned by the daemon:
11
- -- ~/.bazilion/bazilion.db
12
- -- ~/.bazilion/groups/<slug>/ — group root, mounted as cwd; may be a
13
- -- symlink for "agents working on my
14
- -- existing project tree" use cases
15
- -- /memory/ — qmd index for the group (shared by
16
- -- all member agents)
17
- -- ~/.bazilion/agents/<id>/ — agent's private home (NEVER inside
18
- -- the group tree, so the cwd-rooted
19
- -- coding tools can't see/clobber it)
20
- -- /sessions/*.jsonl — pi transcripts
21
- -- ~/.bazilion/profiles/<id>/ — profile templates
22
- -- ~/.bazilion/skills/<name>/ — installed skills
23
- -- ~/.bazilion/logs/ — daemon logs
24
-
25
- -- Groups are collaboration contexts: one filesystem root, one USER.md, one
26
- -- roster of member agents. The id IS the slug IS the directory name under
27
- -- `~/.bazilion/groups/`. No `path` column — paths derive from id.
28
- -- `user_md` is read-only context about the human (edited via web UI; never
29
- -- exposed as a file the agent could clobber via `edit`/`write`).
30
- CREATE TABLE groups (
1
+ -- Canonical clean-install schema. Bazilion is alpha and does not support legacy DB upgrades.
2
+ CREATE TABLE IF NOT EXISTS "teams" (
31
3
  id TEXT PRIMARY KEY,
32
4
  name TEXT NOT NULL,
33
5
  user_md TEXT NOT NULL DEFAULT '',
34
6
  created_at INTEGER NOT NULL
35
- );
36
-
37
- -- Profiles are agent templates. `dir` is the on-disk directory for the
38
- -- profile's SOUL.md / IDENTITY.md / etc. master files, derived from id.
39
- -- `skills_mode = 'all'` attaches every installed skill at spawn;
40
- -- `'selected'` attaches only those listed in `profile_default_skills`.
7
+ , telegram_icon_color INTEGER, telegram_topic_name_format TEXT);
41
8
  CREATE TABLE profiles (
42
9
  id TEXT PRIMARY KEY,
43
10
  name TEXT NOT NULL,
@@ -46,19 +13,12 @@ CREATE TABLE profiles (
46
13
  skills_mode TEXT NOT NULL DEFAULT 'selected' CHECK (skills_mode IN ('all','selected')),
47
14
  created_at INTEGER NOT NULL,
48
15
  updated_at INTEGER NOT NULL
49
- );
50
-
16
+ , telegram_icon_emoji TEXT);
51
17
  CREATE TABLE profile_default_skills (
52
18
  profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
53
19
  skill_name TEXT NOT NULL,
54
20
  PRIMARY KEY (profile_id, skill_name)
55
21
  );
56
-
57
- -- Agents have exactly one group. `dir` is the agent's private home,
58
- -- ~/.bazilion/agents/<id>/ — strictly outside the group tree so that
59
- -- pi's coding tools (rooted at the group dir) can't reach into it.
60
- -- `reasoning_level` feeds pi-ai's streamSimple `reasoning` option;
61
- -- 'medium' is the sensible default.
62
22
  CREATE TABLE agents (
63
23
  id TEXT PRIMARY KEY,
64
24
  profile_id TEXT NOT NULL REFERENCES profiles(id),
@@ -67,27 +27,17 @@ CREATE TABLE agents (
67
27
  status TEXT NOT NULL CHECK (status IN ('idle','running','archived')),
68
28
  dir TEXT NOT NULL,
69
29
  reasoning_level TEXT NOT NULL DEFAULT 'medium',
70
- group_id TEXT NOT NULL REFERENCES groups(id) ON DELETE RESTRICT,
30
+ team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE RESTRICT,
71
31
  created_at INTEGER NOT NULL,
72
32
  archived_at INTEGER
73
- );
74
-
33
+ , telegram_topic_id INTEGER, telegram_topic_name_locked INTEGER NOT NULL DEFAULT 0, telegram_icon_emoji TEXT, telegram_mirror_mode TEXT NOT NULL DEFAULT 'minimal'
34
+ CHECK (telegram_mirror_mode IN ('minimal','verbose')));
75
35
  CREATE TABLE agent_skills (
76
36
  agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
77
37
  skill_name TEXT NOT NULL,
78
38
  attached_at INTEGER NOT NULL,
79
39
  PRIMARY KEY (agent_id, skill_name)
80
40
  );
81
-
82
- -- Periodic / scheduled wake-up triggers. The scheduler picks rows whose
83
- -- next-fire time has elapsed and kicks off a turn with `message` as the
84
- -- user input.
85
- --
86
- -- kind='interval' → interval_sec holds seconds between fires (cron_expr NULL)
87
- -- kind='cron' → cron_expr holds a 5-field cron expression (interval_sec NULL)
88
- --
89
- -- last_fired_at is bumped *before* the run kicks off so a daemon restart
90
- -- mid-fire doesn't double-trigger.
91
41
  CREATE TABLE agent_triggers (
92
42
  id TEXT PRIMARY KEY,
93
43
  agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
@@ -101,10 +51,6 @@ CREATE TABLE agent_triggers (
101
51
  );
102
52
  CREATE INDEX agent_triggers_agent ON agent_triggers(agent_id);
103
53
  CREATE INDEX agent_triggers_enabled ON agent_triggers(enabled) WHERE enabled = 1;
104
-
105
- -- Inter-agent inbox. The scheduler's auto-deliver loop polls
106
- -- `messages_to_unread` to fan out wakeup turns; the messaging tools insert
107
- -- here when one agent sends another a message.
108
54
  CREATE TABLE messages (
109
55
  id TEXT PRIMARY KEY,
110
56
  from_agent_id TEXT NOT NULL REFERENCES agents(id),
@@ -113,23 +59,14 @@ CREATE TABLE messages (
113
59
  payload TEXT NOT NULL,
114
60
  created_at INTEGER NOT NULL,
115
61
  read_at INTEGER
116
- );
62
+ , policy_disposition TEXT NOT NULL DEFAULT 'deliverable'
63
+ CHECK (policy_disposition IN ('deliverable', 'policy_blocked')), policy_blocked_at INTEGER, policy_claimed_at INTEGER, policy_delivered_at INTEGER);
117
64
  CREATE INDEX messages_to_unread ON messages(to_agent_id) WHERE read_at IS NULL;
118
-
119
- -- Per-skill import provenance. Skills live on disk under ~/.bazilion/skills/<name>/;
120
- -- this table records where each was imported from and when.
121
65
  CREATE TABLE skill_meta (
122
66
  name TEXT PRIMARY KEY,
123
67
  source TEXT,
124
68
  imported_at INTEGER
125
69
  );
126
-
127
- -- Per-client web tokens. Each row stores SHA-256(token) hex; the plaintext
128
- -- is returned exactly once at creation time and never persisted in this
129
- -- table. The CLI's bootstrap token is one row here — its plaintext lives
130
- -- in `~/.bazilion/auth.json` so both the daemon (PBKDF2 seed for the
131
- -- secrets table) and the CLI (loopback bearer) can read it.
132
- -- `revoked_at` is a soft-delete marker to keep audit trail intact.
133
70
  CREATE TABLE web_tokens (
134
71
  id TEXT PRIMARY KEY,
135
72
  label TEXT NOT NULL,
@@ -139,9 +76,6 @@ CREATE TABLE web_tokens (
139
76
  revoked_at INTEGER
140
77
  );
141
78
  CREATE INDEX web_tokens_active ON web_tokens(token_hash) WHERE revoked_at IS NULL;
142
-
143
- -- Curated list of models per provider. Drives the model dropdowns in
144
- -- profile creation and agent spawn/edit forms.
145
79
  CREATE TABLE provider_models (
146
80
  provider TEXT NOT NULL,
147
81
  model TEXT NOT NULL,
@@ -149,31 +83,327 @@ CREATE TABLE provider_models (
149
83
  PRIMARY KEY (provider, model)
150
84
  );
151
85
  CREATE INDEX idx_provider_models_provider ON provider_models (provider);
152
-
153
- -- Admin-toggled enabled state per provider.
154
86
  CREATE TABLE provider_state (
155
87
  provider_id TEXT NOT NULL PRIMARY KEY,
156
88
  enabled INTEGER NOT NULL DEFAULT 0,
157
89
  updated_at INTEGER NOT NULL
158
90
  );
159
-
160
- -- Encrypted secrets. AES-256-GCM envelopes (salt+iv+tag+data hex JSON),
161
- -- one row per env-var-shaped key (`ANTHROPIC_API_KEY`, `OPENAI_CODEX_OAUTH`, …).
162
- -- The encryption key is derived from the bootstrap web token (PBKDF2-SHA256,
163
- -- 100k iterations) — same crypto as the previous file-based secrets.enc,
164
- -- now atomic with the rest of the DB.
165
91
  CREATE TABLE secrets (
166
92
  key TEXT PRIMARY KEY,
167
93
  envelope TEXT NOT NULL,
168
94
  updated_at INTEGER NOT NULL
169
95
  );
170
-
171
- -- Plaintext config. Same env-var-shaped keys as secrets, but for values
172
- -- that don't need confidentiality (server URLs, region slugs, project IDs).
173
- -- The application layer enforces a CONFIG_KEYS allowlist on writes so a
174
- -- typo can't put a secret in this table.
175
96
  CREATE TABLE config (
176
97
  key TEXT PRIMARY KEY,
177
98
  value TEXT NOT NULL,
178
99
  updated_at INTEGER NOT NULL
179
100
  );
101
+ CREATE UNIQUE INDEX idx_agents_telegram_topic_id
102
+ ON agents(telegram_topic_id)
103
+ WHERE telegram_topic_id IS NOT NULL;
104
+ CREATE TABLE telegram_allowed_users (
105
+ user_id INTEGER PRIMARY KEY,
106
+ username TEXT,
107
+ label TEXT,
108
+ role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner','member')),
109
+ added_at INTEGER NOT NULL
110
+ );
111
+ CREATE TABLE mcp_servers (
112
+ id TEXT PRIMARY KEY,
113
+ name TEXT NOT NULL UNIQUE,
114
+ transport TEXT NOT NULL CHECK (transport IN ('stdio','http','sse')),
115
+ command TEXT,
116
+ args TEXT NOT NULL DEFAULT '[]',
117
+ url TEXT,
118
+ has_auth INTEGER NOT NULL DEFAULT 0,
119
+ enabled INTEGER NOT NULL DEFAULT 1,
120
+ created_at INTEGER NOT NULL,
121
+ updated_at INTEGER NOT NULL
122
+ );
123
+ CREATE TABLE IF NOT EXISTS "team_templates" (
124
+ id TEXT PRIMARY KEY,
125
+ name TEXT NOT NULL,
126
+ user_md TEXT,
127
+ current_revision INTEGER NOT NULL CHECK (current_revision >= 1),
128
+ deleted_at INTEGER,
129
+ created_at INTEGER NOT NULL,
130
+ updated_at INTEGER NOT NULL
131
+ );
132
+ CREATE TABLE IF NOT EXISTS "team_template_slots" (
133
+ template_id TEXT NOT NULL REFERENCES team_templates(id) ON DELETE CASCADE,
134
+ slot_id TEXT NOT NULL,
135
+ position INTEGER NOT NULL CHECK (position >= 0),
136
+ profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE RESTRICT,
137
+ agent_name TEXT NOT NULL,
138
+ model_override TEXT,
139
+ reasoning_level TEXT CHECK (reasoning_level IS NULL OR reasoning_level IN ('off','minimal','low','medium','high','xhigh')),
140
+ position_x REAL,
141
+ position_y REAL,
142
+ display_json TEXT,
143
+ tombstoned_at INTEGER,
144
+ PRIMARY KEY (template_id, slot_id)
145
+ );
146
+ CREATE TABLE IF NOT EXISTS "team_template_revisions" (
147
+ template_id TEXT NOT NULL REFERENCES team_templates(id) ON DELETE CASCADE,
148
+ revision INTEGER NOT NULL CHECK (revision >= 1),
149
+ name TEXT NOT NULL,
150
+ user_md TEXT,
151
+ created_at INTEGER NOT NULL,
152
+ PRIMARY KEY (template_id, revision)
153
+ );
154
+ CREATE TABLE IF NOT EXISTS "team_template_revision_slots" (
155
+ template_id TEXT NOT NULL,
156
+ revision INTEGER NOT NULL,
157
+ slot_id TEXT NOT NULL,
158
+ position INTEGER NOT NULL CHECK (position >= 0),
159
+ profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE RESTRICT,
160
+ agent_name TEXT NOT NULL,
161
+ model_override TEXT,
162
+ reasoning_level TEXT CHECK (reasoning_level IS NULL OR reasoning_level IN ('off','minimal','low','medium','high','xhigh')),
163
+ position_x REAL,
164
+ position_y REAL,
165
+ display_json TEXT,
166
+ PRIMARY KEY (template_id, revision, slot_id),
167
+ UNIQUE (template_id, revision, position),
168
+ FOREIGN KEY (template_id, revision)
169
+ REFERENCES team_template_revisions(template_id, revision) ON DELETE CASCADE
170
+ );
171
+ CREATE TABLE IF NOT EXISTS "team_policies" (
172
+ team_id TEXT PRIMARY KEY REFERENCES teams(id) ON DELETE CASCADE,
173
+ revision INTEGER NOT NULL CHECK (revision >= 1),
174
+ baseline_instantiation_id TEXT REFERENCES template_instantiations(id) ON DELETE RESTRICT
175
+ DEFERRABLE INITIALLY DEFERRED,
176
+ updated_at INTEGER NOT NULL
177
+ );
178
+ CREATE TABLE template_instantiations (
179
+ id TEXT PRIMARY KEY,
180
+ team_id TEXT NOT NULL REFERENCES team_policies(team_id) ON DELETE CASCADE,
181
+ template_id TEXT NOT NULL,
182
+ template_revision INTEGER NOT NULL,
183
+ created_at INTEGER NOT NULL,
184
+ FOREIGN KEY (template_id, template_revision)
185
+ REFERENCES team_template_revisions(template_id, revision) ON DELETE RESTRICT
186
+ );
187
+ CREATE TABLE source_slot_bindings (
188
+ agent_id TEXT PRIMARY KEY REFERENCES agents(id) ON DELETE CASCADE,
189
+ instantiation_id TEXT NOT NULL REFERENCES template_instantiations(id) ON DELETE CASCADE,
190
+ source_slot_id TEXT NOT NULL,
191
+ UNIQUE (instantiation_id, source_slot_id)
192
+ );
193
+ CREATE TABLE IF NOT EXISTS "team_agent_state" (
194
+ agent_id TEXT PRIMARY KEY REFERENCES agents(id) ON DELETE CASCADE,
195
+ team_id TEXT NOT NULL REFERENCES team_policies(team_id) ON DELETE CASCADE,
196
+ position_x REAL,
197
+ position_y REAL,
198
+ display_json TEXT,
199
+ CHECK ((position_x IS NULL) = (position_y IS NULL))
200
+ );
201
+ CREATE TABLE IF NOT EXISTS "team_policy_block_events" (
202
+ id TEXT PRIMARY KEY,
203
+ attempt_kind TEXT NOT NULL,
204
+ attempt_id TEXT NOT NULL,
205
+ operation TEXT NOT NULL,
206
+ source_kind TEXT NOT NULL,
207
+ source_id TEXT NOT NULL DEFAULT '',
208
+ target_kind TEXT NOT NULL,
209
+ target_id TEXT NOT NULL DEFAULT '',
210
+ source_team_id TEXT,
211
+ target_team_id TEXT,
212
+ channel TEXT NOT NULL,
213
+ origin TEXT NOT NULL,
214
+ reason_code TEXT NOT NULL,
215
+ reason TEXT NOT NULL,
216
+ policy_refs_json TEXT NOT NULL,
217
+ component_outcomes_json TEXT NOT NULL,
218
+ matched_edge_ids_json TEXT NOT NULL,
219
+ required_edge_ids_json TEXT NOT NULL,
220
+ fingerprint TEXT NOT NULL,
221
+ created_at INTEGER NOT NULL,
222
+ UNIQUE (attempt_kind, attempt_id)
223
+ );
224
+ CREATE INDEX messages_policy_delivery_queue
225
+ ON messages(to_agent_id, policy_disposition, read_at, policy_claimed_at, created_at);
226
+ CREATE TABLE communication_approvals (
227
+ id TEXT PRIMARY KEY,
228
+ attempt_kind TEXT NOT NULL,
229
+ attempt_id TEXT NOT NULL,
230
+ fingerprint TEXT NOT NULL,
231
+ operation TEXT NOT NULL,
232
+ source_kind TEXT NOT NULL,
233
+ source_id TEXT NOT NULL DEFAULT '',
234
+ target_kind TEXT NOT NULL,
235
+ target_id TEXT NOT NULL DEFAULT '',
236
+ source_team_id TEXT,
237
+ target_team_id TEXT,
238
+ channel TEXT NOT NULL,
239
+ origin TEXT NOT NULL,
240
+ requester TEXT NOT NULL,
241
+ policy_refs_json TEXT NOT NULL,
242
+ required_edge_ids_json TEXT NOT NULL,
243
+ payload_kind TEXT NOT NULL,
244
+ payload_json TEXT NOT NULL,
245
+ status TEXT NOT NULL
246
+ CHECK (status IN (
247
+ 'pending', 'approved', 'denied', 'expired', 'cancelled',
248
+ 'delivering', 'delivered', 'delivery_failed'
249
+ )),
250
+ expires_at INTEGER NOT NULL,
251
+ decided_at INTEGER,
252
+ decided_by TEXT,
253
+ decision_reason TEXT,
254
+ delivery_error TEXT,
255
+ created_at INTEGER NOT NULL,
256
+ updated_at INTEGER NOT NULL,
257
+ UNIQUE(attempt_kind, attempt_id)
258
+ );
259
+ CREATE INDEX communication_approvals_queue
260
+ ON communication_approvals(status, expires_at, created_at DESC);
261
+ CREATE TABLE communication_approval_events (
262
+ id TEXT PRIMARY KEY,
263
+ approval_id TEXT NOT NULL REFERENCES communication_approvals(id) ON DELETE CASCADE,
264
+ event TEXT NOT NULL
265
+ CHECK (event IN (
266
+ 'requested', 'approved', 'denied', 'expired', 'cancelled',
267
+ 'delivery_started', 'delivered', 'delivery_failed'
268
+ )),
269
+ actor TEXT NOT NULL,
270
+ detail TEXT,
271
+ created_at INTEGER NOT NULL
272
+ );
273
+ CREATE INDEX communication_approval_events_attempt
274
+ ON communication_approval_events(approval_id, created_at ASC);
275
+ CREATE TABLE communication_approval_message_grants (
276
+ approval_id TEXT PRIMARY KEY REFERENCES communication_approvals(id) ON DELETE CASCADE,
277
+ message_id TEXT NOT NULL UNIQUE REFERENCES messages(id) ON DELETE CASCADE,
278
+ created_at INTEGER NOT NULL
279
+ );
280
+ CREATE TABLE profile_communication_defaults (
281
+ profile_id TEXT PRIMARY KEY REFERENCES profiles(id) ON DELETE CASCADE,
282
+ user_input INTEGER NOT NULL CHECK (user_input IN (0, 1)),
283
+ user_output INTEGER NOT NULL CHECK (user_output IN (0, 1)),
284
+ outside_team_input INTEGER NOT NULL CHECK (outside_team_input IN (0, 1)),
285
+ outside_team_output INTEGER NOT NULL CHECK (outside_team_output IN (0, 1)),
286
+ peer_default TEXT NOT NULL CHECK (peer_default IN ('inherit_team_policy','allow_all','deny_all')),
287
+ updated_at INTEGER NOT NULL
288
+ );
289
+ CREATE TABLE team_template_edges (
290
+ template_id TEXT NOT NULL REFERENCES team_templates(id) ON DELETE CASCADE,
291
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('user','outside_team','slot')),
292
+ source_id TEXT NOT NULL DEFAULT '',
293
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('user','outside_team','slot')),
294
+ target_id TEXT NOT NULL DEFAULT '',
295
+ posture TEXT NOT NULL DEFAULT 'allow' CHECK (posture IN ('allow','approval_required')),
296
+ CHECK ((source_kind = 'slot') = (length(source_id) > 0)),
297
+ CHECK ((target_kind = 'slot') = (length(target_id) > 0)),
298
+ CHECK (source_kind = 'slot' OR target_kind = 'slot'),
299
+ CHECK (source_kind != target_kind OR source_id != target_id),
300
+ PRIMARY KEY (template_id, source_kind, source_id, target_kind, target_id)
301
+ );
302
+ CREATE TABLE team_template_revision_edges (
303
+ template_id TEXT NOT NULL,
304
+ revision INTEGER NOT NULL,
305
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('user','outside_team','slot')),
306
+ source_id TEXT NOT NULL DEFAULT '',
307
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('user','outside_team','slot')),
308
+ target_id TEXT NOT NULL DEFAULT '',
309
+ posture TEXT NOT NULL DEFAULT 'allow' CHECK (posture IN ('allow','approval_required')),
310
+ CHECK ((source_kind = 'slot') = (length(source_id) > 0)),
311
+ CHECK ((target_kind = 'slot') = (length(target_id) > 0)),
312
+ CHECK (source_kind = 'slot' OR target_kind = 'slot'),
313
+ CHECK (source_kind != target_kind OR source_id != target_id),
314
+ PRIMARY KEY (template_id, revision, source_kind, source_id, target_kind, target_id),
315
+ FOREIGN KEY (template_id, revision)
316
+ REFERENCES team_template_revisions(template_id, revision) ON DELETE CASCADE
317
+ );
318
+ CREATE TABLE team_policy_edges (
319
+ team_id TEXT NOT NULL REFERENCES team_policies(team_id) ON DELETE CASCADE,
320
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('user','outside_team','agent')),
321
+ source_id TEXT NOT NULL DEFAULT '',
322
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('user','outside_team','agent')),
323
+ target_id TEXT NOT NULL DEFAULT '',
324
+ posture TEXT NOT NULL DEFAULT 'allow' CHECK (posture IN ('allow','approval_required')),
325
+ CHECK ((source_kind = 'agent') = (length(source_id) > 0)),
326
+ CHECK ((target_kind = 'agent') = (length(target_id) > 0)),
327
+ CHECK (source_kind = 'agent' OR target_kind = 'agent'),
328
+ CHECK (source_kind != target_kind OR source_id != target_id),
329
+ PRIMARY KEY (team_id, source_kind, source_id, target_kind, target_id)
330
+ );
331
+ CREATE UNIQUE INDEX team_template_active_position
332
+ ON team_template_slots(template_id, position) WHERE tombstoned_at IS NULL;
333
+ CREATE UNIQUE INDEX team_policy_baseline_owner
334
+ ON team_policies(baseline_instantiation_id) WHERE baseline_instantiation_id IS NOT NULL;
335
+ CREATE INDEX team_policy_blocks_team_time
336
+ ON team_policy_block_events(source_team_id, target_team_id, created_at DESC, id DESC);
337
+ CREATE INDEX communication_approvals_teams
338
+ ON communication_approvals(source_team_id, target_team_id, created_at DESC);
339
+ CREATE TRIGGER create_team_policy
340
+ AFTER INSERT ON teams
341
+ BEGIN
342
+ INSERT INTO team_policies
343
+ (team_id, revision, baseline_instantiation_id, updated_at)
344
+ VALUES (NEW.id, 1, NULL, NEW.created_at);
345
+ END;
346
+ CREATE TRIGGER prevent_detached_team_policy_delete
347
+ BEFORE DELETE ON team_policies
348
+ WHEN EXISTS (SELECT 1 FROM teams t WHERE t.id = OLD.team_id)
349
+ BEGIN
350
+ SELECT RAISE(ABORT, 'Team policy cannot be deleted independently of its Team');
351
+ END;
352
+ CREATE TRIGGER validate_team_template_edge_insert
353
+ BEFORE INSERT ON team_template_edges
354
+ WHEN (NEW.source_kind = 'slot' AND NOT EXISTS (
355
+ SELECT 1 FROM team_template_slots s
356
+ WHERE s.template_id = NEW.template_id AND s.slot_id = NEW.source_id
357
+ AND s.tombstoned_at IS NULL
358
+ ))
359
+ OR (NEW.target_kind = 'slot' AND NOT EXISTS (
360
+ SELECT 1 FROM team_template_slots s
361
+ WHERE s.template_id = NEW.template_id AND s.slot_id = NEW.target_id
362
+ AND s.tombstoned_at IS NULL
363
+ ))
364
+ BEGIN
365
+ SELECT RAISE(ABORT, 'Team Template edge endpoint is not an active slot');
366
+ END;
367
+ CREATE TRIGGER validate_team_policy_edge_insert
368
+ BEFORE INSERT ON team_policy_edges
369
+ WHEN (NEW.source_kind = 'agent' AND NOT EXISTS (
370
+ SELECT 1 FROM agents a WHERE a.id = NEW.source_id AND a.team_id = NEW.team_id
371
+ ))
372
+ OR (NEW.target_kind = 'agent' AND NOT EXISTS (
373
+ SELECT 1 FROM agents a WHERE a.id = NEW.target_id AND a.team_id = NEW.team_id
374
+ ))
375
+ BEGIN
376
+ SELECT RAISE(ABORT, 'Team policy edge endpoint is not a Team member');
377
+ END;
378
+ CREATE TRIGGER validate_source_binding_insert
379
+ BEFORE INSERT ON source_slot_bindings
380
+ WHEN NOT EXISTS (
381
+ SELECT 1
382
+ FROM template_instantiations i
383
+ JOIN team_template_revision_slots s
384
+ ON s.template_id = i.template_id
385
+ AND s.revision = i.template_revision
386
+ AND s.slot_id = NEW.source_slot_id
387
+ JOIN agents a ON a.id = NEW.agent_id AND a.team_id = i.team_id
388
+ WHERE i.id = NEW.instantiation_id
389
+ )
390
+ BEGIN
391
+ SELECT RAISE(ABORT, 'source binding does not match retained revision or Team membership');
392
+ END;
393
+ CREATE TRIGGER validate_team_agent_state_insert
394
+ BEFORE INSERT ON team_agent_state
395
+ WHEN NOT EXISTS (
396
+ SELECT 1 FROM agents a WHERE a.id = NEW.agent_id AND a.team_id = NEW.team_id
397
+ )
398
+ BEGIN
399
+ SELECT RAISE(ABORT, 'Team Agent state does not match agents.team_id');
400
+ END;
401
+ CREATE TRIGGER validate_team_policy_baseline_update
402
+ BEFORE UPDATE OF baseline_instantiation_id ON team_policies
403
+ WHEN NEW.baseline_instantiation_id IS NOT NULL AND NOT EXISTS (
404
+ SELECT 1 FROM template_instantiations i
405
+ WHERE i.id = NEW.baseline_instantiation_id AND i.team_id = NEW.team_id
406
+ )
407
+ BEGIN
408
+ SELECT RAISE(ABORT, 'baseline instantiation belongs to another Team');
409
+ END;
@@ -1 +1 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";var i=e(n(),1),a=t();function o({field:e}){let t=r(),[n,o]=(0,i.useState)(e.kind===`config`?e.value??``:``),[s,c]=(0,i.useState)(!1),[l,u]=(0,i.useState)(null),[d,f]=(0,i.useState)(null);async function p(r){r.preventDefault(),c(!0),u(null);try{let r=await fetch(`/api/config/fields/${encodeURIComponent(e.envVar)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({value:n})});if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error??`${r.status} ${r.statusText}`)}f(Date.now()),e.kind===`secret`&&o(``),await t.invalidate()}catch(e){u(e.message)}finally{c(!1)}}return(0,a.jsxs)(`form`,{onSubmit:p,className:`grid grid-cols-[12rem_minmax(14rem,1fr)_auto_auto] gap-2 items-center py-2 border-b last:border-0`,children:[(0,a.jsxs)(`div`,{className:`min-w-0`,children:[(0,a.jsx)(`div`,{className:`text-sm`,children:e.label}),(0,a.jsx)(`div`,{className:`font-mono text-xs text-muted-foreground`,children:e.envVar}),e.description&&(0,a.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:e.description})]}),e.kind===`config`?(0,a.jsx)(`input`,{type:`text`,value:n,onChange:e=>o(e.target.value),placeholder:e.placeholder??``,className:`rounded-md border bg-background px-2 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring/30`}):(0,a.jsx)(`input`,{type:`password`,value:n,onChange:e=>o(e.target.value),placeholder:e.set?`(replace — blank clears)`:e.placeholder??`paste key…`,autoComplete:`off`,className:`rounded-md border bg-background px-2 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring/30`}),(0,a.jsxs)(`span`,{className:`text-xs`,children:[e.kind===`secret`&&e.set&&(0,a.jsx)(`span`,{className:`rounded-full bg-emerald-100 text-emerald-800 px-1.5 py-0.5`,title:`preview: ${e.preview??``}`,children:`set`}),d&&Date.now()-d<2e3&&(0,a.jsx)(`span`,{className:`text-emerald-700 ml-2`,children:`saved ✓`})]}),(0,a.jsx)(`button`,{type:`submit`,disabled:s,className:`unstyled rounded-md border bg-background px-2 py-1.5 text-xs text-foreground hover:bg-accent disabled:opacity-50`,children:`save`}),l&&(0,a.jsx)(`p`,{className:`col-span-4 text-xs text-rose-700`,children:l})]})}export{o as t};
1
+ import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{$ as n,d as r}from"./preload-helper-eOOCz1Fu.js";var i=e(n(),1),a=t();function o({field:e}){let t=r(),[n,o]=(0,i.useState)(e.kind===`config`?e.value??``:``),[s,c]=(0,i.useState)(!1),[l,u]=(0,i.useState)(null),[d,f]=(0,i.useState)(null);async function p(r){r.preventDefault(),c(!0),u(null);try{let r=await fetch(`/api/config/fields/${encodeURIComponent(e.envVar)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({value:n})});if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error??`${r.status} ${r.statusText}`)}f(Date.now()),e.kind===`secret`&&o(``),await t.invalidate()}catch(e){u(e.message)}finally{c(!1)}}return(0,a.jsxs)(`form`,{onSubmit:p,className:`grid grid-cols-[12rem_minmax(14rem,1fr)_auto_auto] gap-2 items-center py-2 border-b last:border-0`,children:[(0,a.jsxs)(`div`,{className:`min-w-0`,children:[(0,a.jsx)(`div`,{className:`text-sm`,children:e.label}),(0,a.jsx)(`div`,{className:`font-mono text-xs text-muted-foreground`,children:e.envVar}),e.description&&(0,a.jsx)(`div`,{className:`text-xs text-muted-foreground mt-0.5`,children:e.description})]}),e.kind===`config`?(0,a.jsx)(`input`,{type:`text`,value:n,onChange:e=>o(e.target.value),placeholder:e.placeholder??``,className:`rounded-md border bg-background px-2 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring/30`}):(0,a.jsx)(`input`,{type:`password`,value:n,onChange:e=>o(e.target.value),placeholder:e.set?`(replace — blank clears)`:e.placeholder??`paste key…`,autoComplete:`off`,className:`rounded-md border bg-background px-2 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring/30`}),(0,a.jsxs)(`span`,{className:`text-xs`,children:[e.kind===`secret`&&e.set&&(0,a.jsx)(`span`,{className:`rounded-full bg-emerald-100 text-emerald-800 px-1.5 py-0.5`,title:`preview: ${e.preview??``}`,children:`set`}),d&&Date.now()-d<2e3&&(0,a.jsx)(`span`,{className:`text-emerald-700 ml-2`,children:`saved ✓`})]}),(0,a.jsx)(`button`,{type:`submit`,disabled:s,className:`unstyled rounded-md border bg-background px-2 py-1.5 text-xs text-foreground hover:bg-accent disabled:opacity-50`,children:`save`}),l&&(0,a.jsx)(`p`,{className:`col-span-4 text-xs text-rose-700`,children:l})]})}export{o as t};