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,10 +1,10 @@
1
- import "./wire-constants-Deb4NxBb.js";
2
- import { t as SpawnTeamModal } from "./SpawnTeamModal-dSN421k_.js";
3
- import { useState } from "react";
1
+ import "./wire-constants-C8nBJcU3.js";
2
+ import { t as Button } from "./Button-Dsnw22OF.js";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import { Link, useNavigate, useRouter } from "@tanstack/react-router";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- //#region src/components/CreateGroupDialog.tsx
7
- function CreateGroupDialog({ onClose }) {
6
+ //#region src/components/CreateTeamDialog.tsx
7
+ function CreateTeamDialog({ onClose }) {
8
8
  const router = useRouter();
9
9
  const [id, setId] = useState("");
10
10
  const [name, setName] = useState("");
@@ -23,7 +23,7 @@ function CreateGroupDialog({ onClose }) {
23
23
  const body = { id: id.trim() };
24
24
  if (name.trim()) body.name = name.trim();
25
25
  if (link.trim()) body.link = link.trim();
26
- const res = await fetch("/api/groups", {
26
+ const res = await fetch("/api/teams", {
27
27
  method: "POST",
28
28
  headers: { "content-type": "application/json" },
29
29
  body: JSON.stringify(body)
@@ -49,15 +49,15 @@ function CreateGroupDialog({ onClose }) {
49
49
  children: [
50
50
  /* @__PURE__ */ jsx("h3", {
51
51
  className: "font-serif text-xl text-foreground mb-1",
52
- children: "Create a new group"
52
+ children: "Create a new team"
53
53
  }),
54
54
  /* @__PURE__ */ jsxs("p", {
55
55
  className: "text-sm text-muted-foreground mb-4",
56
56
  children: [
57
- "A group is a collaboration context — one filesystem root, one USER.md, one roster. The slot lives at ",
57
+ "A team is a collaboration context — one filesystem root, one USER.md, one roster. The slot lives at ",
58
58
  /* @__PURE__ */ jsx("code", {
59
59
  className: "font-mono",
60
- children: "~/.bazilion/groups/<slug>/"
60
+ children: "~/.bazilion/teams/<slug>/"
61
61
  }),
62
62
  "."
63
63
  ]
@@ -139,20 +139,65 @@ function CreateGroupDialog({ onClose }) {
139
139
  }
140
140
  //#endregion
141
141
  //#region src/components/SpawnDialog.tsx
142
- function SpawnDialog({ profileId, groupHint, groups, onClose }) {
142
+ function SpawnDialog({ profileId, teamHint, teams, onClose }) {
143
143
  const navigate = useNavigate();
144
144
  const [name, setName] = useState("");
145
- const [groupId, setGroupId] = useState(groupHint ?? "default");
145
+ const [teamId, setTeamId] = useState(teamHint ?? teams.find((team) => team.id === "default")?.id ?? teams[0]?.id ?? "");
146
+ const [placement, setPlacement] = useState("profile_defaults");
146
147
  const [busy, setBusy] = useState(false);
147
148
  const [err, setErr] = useState(null);
149
+ const [preview, setPreview] = useState(null);
150
+ async function requestBody() {
151
+ const policy = await fetch(`/api/teams/${encodeURIComponent(teamId)}/policy`);
152
+ if (!policy.ok) throw new Error("The selected Team policy is unavailable. Reload and try again.");
153
+ const current = await policy.json();
154
+ return {
155
+ current,
156
+ body: {
157
+ profileId,
158
+ teamId,
159
+ teamExpectedRevision: current.teamPolicy.revision,
160
+ placement
161
+ }
162
+ };
163
+ }
164
+ async function review() {
165
+ setErr(null);
166
+ setBusy(true);
167
+ try {
168
+ const { body } = await requestBody();
169
+ const response = await fetch("/api/agents/placement-preview", {
170
+ method: "POST",
171
+ headers: { "content-type": "application/json" },
172
+ body: JSON.stringify(body)
173
+ });
174
+ if (!response.ok) {
175
+ const value = await response.json().catch(() => null);
176
+ throw new Error(value?.error ?? `Preview failed (${response.status})`);
177
+ }
178
+ setPreview(await response.json());
179
+ } catch (cause) {
180
+ setErr(cause.message);
181
+ } finally {
182
+ setBusy(false);
183
+ }
184
+ }
148
185
  async function submit(e) {
149
186
  e.preventDefault();
150
187
  setErr(null);
151
188
  setBusy(true);
152
189
  try {
153
- const body = { profile: profileId };
190
+ if (!preview) {
191
+ await review();
192
+ return;
193
+ }
194
+ const body = {
195
+ profile: profileId,
196
+ teamExpectedRevision: preview.currentRevision,
197
+ placement
198
+ };
154
199
  if (name.trim()) body.name = name.trim();
155
- if (groupId) body.groupId = groupId;
200
+ if (teamId) body.teamId = teamId;
156
201
  const res = await fetch("/api/agents", {
157
202
  method: "POST",
158
203
  headers: { "content-type": "application/json" },
@@ -162,7 +207,7 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
162
207
  const e = await res.json().catch(() => ({}));
163
208
  throw new Error(e.error ?? `${res.status} ${res.statusText}`);
164
209
  }
165
- const created = await res.json();
210
+ const created = (await res.json()).agent;
166
211
  onClose();
167
212
  await navigate({
168
213
  to: "/",
@@ -176,11 +221,15 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
176
221
  return /* @__PURE__ */ jsx(Backdrop, {
177
222
  onClose,
178
223
  children: /* @__PURE__ */ jsxs("form", {
224
+ role: "dialog",
225
+ "aria-modal": "true",
226
+ "aria-labelledby": "spawn-agent-title",
179
227
  onSubmit: submit,
180
228
  className: "w-full max-w-md rounded-2xl border bg-card p-6 shadow-lg",
181
229
  onClick: (e) => e.stopPropagation(),
182
230
  children: [
183
231
  /* @__PURE__ */ jsx("h3", {
232
+ id: "spawn-agent-title",
184
233
  className: "font-serif text-xl text-foreground mb-1",
185
234
  children: "Spawn a new agent"
186
235
  }),
@@ -212,11 +261,46 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
212
261
  }),
213
262
  /* @__PURE__ */ jsxs("label", {
214
263
  className: "block text-sm text-foreground mb-3",
215
- children: ["Group", /* @__PURE__ */ jsx("select", {
216
- value: groupId,
217
- onChange: (e) => setGroupId(e.target.value),
264
+ children: [
265
+ "Initial policy placement",
266
+ /* @__PURE__ */ jsxs("select", {
267
+ value: placement,
268
+ onChange: (e) => {
269
+ setPlacement(e.target.value);
270
+ setPreview(null);
271
+ },
272
+ className: "mt-1 block w-full rounded-md border bg-background px-3 py-2",
273
+ children: [
274
+ /* @__PURE__ */ jsx("option", {
275
+ value: "profile_defaults",
276
+ children: "agent-template defaults"
277
+ }),
278
+ /* @__PURE__ */ jsx("option", {
279
+ value: "isolated",
280
+ children: "isolated"
281
+ }),
282
+ /* @__PURE__ */ jsx("option", {
283
+ value: "open",
284
+ children: "open to current members and boundaries"
285
+ })
286
+ ]
287
+ }),
288
+ /* @__PURE__ */ jsx("span", {
289
+ className: "mt-1 block text-xs text-muted-foreground",
290
+ children: "The current Team revision is checked again when you submit."
291
+ })
292
+ ]
293
+ }),
294
+ /* @__PURE__ */ jsxs("label", {
295
+ className: "block text-sm text-foreground mb-3",
296
+ children: ["Team", /* @__PURE__ */ jsx("select", {
297
+ value: teamId,
298
+ onChange: (e) => {
299
+ setTeamId(e.target.value);
300
+ setPreview(null);
301
+ },
218
302
  className: "mt-1 block w-full rounded-md border bg-background px-3 py-2 outline-none focus:ring-2 focus:ring-ring/30",
219
- children: groups.map((g) => /* @__PURE__ */ jsxs("option", {
303
+ children: teams.map((g) => /* @__PURE__ */ jsxs("option", {
220
304
  value: g.id,
221
305
  children: [g.name, g.id === "default" ? " (default)" : ""]
222
306
  }, g.id))
@@ -226,6 +310,36 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
226
310
  className: "mt-2 text-sm text-rose-700",
227
311
  children: err
228
312
  }),
313
+ preview && /* @__PURE__ */ jsxs("div", {
314
+ className: "mt-3 rounded-md border border-sapphire-light bg-sapphire-glow p-3 text-sm",
315
+ children: [
316
+ /* @__PURE__ */ jsxs("p", { children: [
317
+ "Creating this Agent advances Team revision ",
318
+ preview.currentRevision,
319
+ " → ",
320
+ /* @__PURE__ */ jsx("strong", { children: preview.resultingRevision }),
321
+ " and adds ",
322
+ /* @__PURE__ */ jsx("strong", { children: preview.addedEdges.length }),
323
+ " directed edges to the existing ",
324
+ preview.existingEdges.length,
325
+ "."
326
+ ] }),
327
+ /* @__PURE__ */ jsx("ul", {
328
+ className: "mt-2 max-h-36 overflow-auto",
329
+ children: preview.addedEdges.map((edge, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("code", { children: [
330
+ edge.sourceKind,
331
+ edge.sourceId ? `:${edge.sourceId}` : "",
332
+ " → ",
333
+ edge.targetKind,
334
+ edge.targetId ? `:${edge.targetId}` : ""
335
+ ] }) }, `${edge.sourceKind}:${edge.sourceId ?? ""}>${edge.targetKind}:${edge.targetId ?? ""}:${index}`))
336
+ }),
337
+ preview.addedEdges.length === 0 && /* @__PURE__ */ jsx("p", {
338
+ className: "mt-2",
339
+ children: "The new Agent starts isolated."
340
+ })
341
+ ]
342
+ }),
229
343
  /* @__PURE__ */ jsxs("div", {
230
344
  className: "mt-5 flex justify-end gap-2",
231
345
  children: [/* @__PURE__ */ jsx("button", {
@@ -237,7 +351,7 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
237
351
  type: "submit",
238
352
  disabled: busy,
239
353
  className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50",
240
- children: busy ? "Creating…" : "Create"
354
+ children: busy ? "Working…" : preview ? "Commit reviewed creation" : "Review exact policy"
241
355
  })]
242
356
  })
243
357
  ]
@@ -247,11 +361,209 @@ function SpawnDialog({ profileId, groupHint, groups, onClose }) {
247
361
  function Backdrop({ children, onClose }) {
248
362
  return /* @__PURE__ */ jsx("div", {
249
363
  onClick: onClose,
364
+ onKeyDown: (event) => {
365
+ if (event.key === "Escape") onClose();
366
+ },
250
367
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black/30 backdrop-blur-[1px]",
251
368
  children
252
369
  });
253
370
  }
254
371
  //#endregion
372
+ //#region src/components/SpawnTeamModal.tsx
373
+ function SpawnTeamModal({ profileGroup: team, teams, onClose, onSpawned }) {
374
+ const [teamId, setTeamId] = useState("");
375
+ const [userMd, setUserMd] = useState("");
376
+ const [error, setError] = useState(null);
377
+ const [busy, setBusy] = useState(false);
378
+ const [preview, setPreview] = useState(null);
379
+ const dialogRef = useRef(null);
380
+ useEffect(() => {
381
+ dialogRef.current?.focus();
382
+ }, []);
383
+ async function requestBody() {
384
+ const target = teamId.trim();
385
+ if (!target) throw new Error("target Team slug is required");
386
+ const existing = teams.find((team) => team.id === target);
387
+ let teamExpectedRevision;
388
+ if (existing) {
389
+ const policyResponse = await fetch(`/api/teams/${encodeURIComponent(target)}/policy`);
390
+ if (!policyResponse.ok) throw new Error("The target Team policy is unavailable.");
391
+ teamExpectedRevision = (await policyResponse.json()).teamPolicy.revision;
392
+ }
393
+ return {
394
+ target,
395
+ body: {
396
+ templateExpectedRevision: team.currentRevision,
397
+ teamId: target,
398
+ ...teamExpectedRevision ? { teamExpectedRevision } : {},
399
+ mode: existing ? "append" : "initialize",
400
+ ...userMd ? { userMd } : {}
401
+ }
402
+ };
403
+ }
404
+ async function review() {
405
+ setBusy(true);
406
+ setError(null);
407
+ setPreview(null);
408
+ try {
409
+ const { body } = await requestBody();
410
+ const response = await fetch(`/api/team-templates/${encodeURIComponent(team.id)}/spawn/preview`, {
411
+ method: "POST",
412
+ headers: { "content-type": "application/json" },
413
+ body: JSON.stringify(body)
414
+ });
415
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.error ?? response.statusText);
416
+ setPreview(await response.json());
417
+ } catch (cause) {
418
+ setError(cause.message);
419
+ } finally {
420
+ setBusy(false);
421
+ }
422
+ }
423
+ async function spawn() {
424
+ const target = teamId.trim();
425
+ if (!target) {
426
+ setError("target Team slug is required");
427
+ return;
428
+ }
429
+ setBusy(true);
430
+ setError(null);
431
+ try {
432
+ const { body } = await requestBody();
433
+ const response = await fetch(`/api/team-templates/${encodeURIComponent(team.id)}/spawn`, {
434
+ method: "POST",
435
+ headers: { "content-type": "application/json" },
436
+ body: JSON.stringify(body)
437
+ });
438
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.error ?? response.statusText);
439
+ onSpawned(target);
440
+ } catch (cause) {
441
+ setError(cause.message);
442
+ } finally {
443
+ setBusy(false);
444
+ }
445
+ }
446
+ return /* @__PURE__ */ jsx("div", {
447
+ role: "dialog",
448
+ "aria-modal": "true",
449
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50",
450
+ onClick: onClose,
451
+ onKeyDown: (event) => {
452
+ if (event.key === "Escape") onClose();
453
+ },
454
+ children: /* @__PURE__ */ jsxs("div", {
455
+ ref: dialogRef,
456
+ tabIndex: -1,
457
+ className: "card w-full max-w-lg",
458
+ role: "document",
459
+ onClick: (event) => event.stopPropagation(),
460
+ onKeyDown: (event) => {
461
+ if (event.key !== "Escape") event.stopPropagation();
462
+ },
463
+ children: [
464
+ /* @__PURE__ */ jsxs("h3", { children: ["spawn team — ", team.name] }),
465
+ error && /* @__PURE__ */ jsx("div", {
466
+ className: "err",
467
+ children: error
468
+ }),
469
+ /* @__PURE__ */ jsxs("p", {
470
+ className: "muted",
471
+ children: [
472
+ "Uses immutable Team revision ",
473
+ team.currentRevision,
474
+ ". Existing Teams append at their current reviewed revision; a new Team initializes at revision 1. Conflicts never overwrite newer state."
475
+ ]
476
+ }),
477
+ /* @__PURE__ */ jsxs("label", { children: [
478
+ "target Team slug",
479
+ /* @__PURE__ */ jsx("input", {
480
+ value: teamId,
481
+ onChange: (event) => {
482
+ setTeamId(event.target.value);
483
+ setPreview(null);
484
+ },
485
+ list: "canonical-teams",
486
+ required: true
487
+ }),
488
+ /* @__PURE__ */ jsx("datalist", {
489
+ id: "canonical-teams",
490
+ children: teams.map((team) => /* @__PURE__ */ jsx("option", {
491
+ value: team.id,
492
+ children: team.name
493
+ }, team.id))
494
+ })
495
+ ] }),
496
+ /* @__PURE__ */ jsxs("label", { children: ["starter USER.md (new Team only)", /* @__PURE__ */ jsx("textarea", {
497
+ rows: 3,
498
+ value: userMd,
499
+ onChange: (event) => {
500
+ setUserMd(event.target.value);
501
+ setPreview(null);
502
+ },
503
+ className: "font-mono text-[0.88em] leading-[1.55]"
504
+ })] }),
505
+ preview && /* @__PURE__ */ jsxs("div", {
506
+ className: "mt-4 rounded-md border border-sapphire-light bg-sapphire-glow p-3 text-sm",
507
+ children: [
508
+ /* @__PURE__ */ jsxs("p", { children: [
509
+ /* @__PURE__ */ jsx("strong", { children: preview.mode === "initialize" ? "Initialize" : "Append" }),
510
+ " produces Team revision ",
511
+ preview.resultingRevision,
512
+ ", adds ",
513
+ preview.newMembers.length,
514
+ " Agents, and results in ",
515
+ preview.edges.length,
516
+ " directed allow edges."
517
+ ] }),
518
+ /* @__PURE__ */ jsx("ul", {
519
+ className: "mt-2 max-h-40 overflow-auto",
520
+ children: preview.newMembers.map((member) => /* @__PURE__ */ jsxs("li", { children: [
521
+ member.agentName,
522
+ " · stable source slot ",
523
+ /* @__PURE__ */ jsx("code", { children: member.slotId })
524
+ ] }, member.slotId))
525
+ }),
526
+ /* @__PURE__ */ jsxs("details", {
527
+ className: "mt-2",
528
+ children: [/* @__PURE__ */ jsx("summary", {
529
+ className: "cursor-pointer",
530
+ children: "Review exact edge topology"
531
+ }), /* @__PURE__ */ jsx("ul", {
532
+ className: "mt-2 max-h-40 overflow-auto",
533
+ children: preview.edges.map((edge, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("code", { children: [
534
+ edge.sourceKind,
535
+ edge.sourceId ? `:${edge.sourceId}` : "",
536
+ " → ",
537
+ edge.targetKind,
538
+ edge.targetId ? `:${edge.targetId}` : ""
539
+ ] }) }, `${edge.sourceKind}:${edge.sourceId ?? ""}>${edge.targetKind}:${edge.targetId ?? ""}:${index}`))
540
+ })]
541
+ })
542
+ ]
543
+ }),
544
+ /* @__PURE__ */ jsxs("div", {
545
+ className: "mt-4 flex justify-end gap-2",
546
+ children: [/* @__PURE__ */ jsx(Button, {
547
+ variant: "ghost",
548
+ onClick: onClose,
549
+ children: "cancel"
550
+ }), preview ? /* @__PURE__ */ jsx(Button, {
551
+ variant: "primary",
552
+ onClick: spawn,
553
+ disabled: busy,
554
+ children: busy ? "spawning…" : `commit ${preview.mode}`
555
+ }) : /* @__PURE__ */ jsx(Button, {
556
+ variant: "primary",
557
+ onClick: review,
558
+ disabled: busy || team.slotCount === 0,
559
+ children: busy ? "reviewing…" : "review exact result"
560
+ })]
561
+ })
562
+ ]
563
+ })
564
+ });
565
+ }
566
+ //#endregion
255
567
  //#region src/components/Sidebar.tsx
256
568
  var SIDEBAR_OPEN_GROUPS_COOKIE = "bz_sidebar_open_groups";
257
569
  function writeOpenGroupsCookie(map) {
@@ -259,12 +571,14 @@ function writeOpenGroupsCookie(map) {
259
571
  const value = encodeURIComponent(JSON.stringify(map));
260
572
  document.cookie = `${SIDEBAR_OPEN_GROUPS_COOKIE}=${value}; Path=/; Max-Age=31536000; SameSite=Lax`;
261
573
  }
262
- function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, initialOpenGroups }) {
574
+ function Sidebar({ agents, teams, profiles, profileGroups, selectedAgentId, initialOpenGroups }) {
263
575
  const router = useRouter();
264
576
  const [spawnFor, setSpawnFor] = useState(null);
265
577
  const [spawnTeamFor, setSpawnTeamFor] = useState(null);
266
578
  const [createGroupOpen, setCreateGroupOpen] = useState(false);
267
579
  const [menuOpen, setMenuOpen] = useState(false);
580
+ const newButtonRef = useRef(null);
581
+ const restoreNewButton = () => window.requestAnimationFrame(() => newButtonRef.current?.focus());
268
582
  const [openGroups, setOpenGroups] = useState(() => initialOpenGroups ?? {});
269
583
  async function rename(a) {
270
584
  const next = window.prompt(`rename "${a.name}" to:`, a.name)?.trim();
@@ -295,18 +609,18 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
295
609
  if (b.id === "default") return 1;
296
610
  return 0;
297
611
  });
298
- const sortedGroups = [...groups].sort((a, b) => {
612
+ const sortedGroups = [...teams].sort((a, b) => {
299
613
  if (a.id === "default") return -1;
300
614
  if (b.id === "default") return 1;
301
615
  return 0;
302
616
  });
303
617
  const agentsByGroup = /* @__PURE__ */ new Map();
304
618
  for (const a of agents) {
305
- const list = agentsByGroup.get(a.groupId) ?? [];
619
+ const list = agentsByGroup.get(a.teamId) ?? [];
306
620
  list.push(a);
307
- agentsByGroup.set(a.groupId, list);
621
+ agentsByGroup.set(a.teamId, list);
308
622
  }
309
- const selectedGroupId = agents.find((a) => a.id === selectedAgentId)?.groupId ?? null;
623
+ const selectedTeamId = agents.find((a) => a.id === selectedAgentId)?.teamId ?? null;
310
624
  return /* @__PURE__ */ jsxs("aside", {
311
625
  className: "flex h-full flex-col rounded-lg border bg-card overflow-hidden",
312
626
  children: [
@@ -318,6 +632,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
318
632
  }), /* @__PURE__ */ jsxs("div", {
319
633
  className: "relative",
320
634
  children: [/* @__PURE__ */ jsx("button", {
635
+ ref: newButtonRef,
321
636
  type: "button",
322
637
  onClick: () => setMenuOpen((v) => !v),
323
638
  className: "rounded-md border px-2 py-1 text-xs text-muted-foreground hover:text-foreground hover:border-foreground/30",
@@ -333,7 +648,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
333
648
  "No profiles yet.",
334
649
  /* @__PURE__ */ jsx("br", {}),
335
650
  /* @__PURE__ */ jsx("a", {
336
- href: "/profiles",
651
+ href: "/templates/agents",
337
652
  className: "text-primary underline",
338
653
  children: "Create one"
339
654
  }),
@@ -359,7 +674,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
359
674
  /* @__PURE__ */ jsx("div", { className: "my-1 h-px bg-border" }),
360
675
  /* @__PURE__ */ jsx("div", {
361
676
  className: "px-3 pt-1 pb-0.5 text-[0.7em] uppercase tracking-wide text-muted-foreground",
362
- children: "spawn group from template"
677
+ children: "spawn team from template"
363
678
  }),
364
679
  profileGroups.length === 0 ? /* @__PURE__ */ jsxs("div", {
365
680
  className: "px-3 py-1.5 text-xs text-muted-foreground",
@@ -367,7 +682,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
367
682
  "No team templates yet.",
368
683
  " ",
369
684
  /* @__PURE__ */ jsx("a", {
370
- href: "/profile-groups",
685
+ href: "/templates/teams",
371
686
  className: "text-primary underline",
372
687
  children: "Create one"
373
688
  }),
@@ -376,8 +691,8 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
376
691
  }) : profileGroups.map((pg) => /* @__PURE__ */ jsxs("button", {
377
692
  type: "button",
378
693
  role: "menuitem",
379
- disabled: pg.memberCount === 0,
380
- title: pg.memberCount === 0 ? "add at least one member before spawning" : void 0,
694
+ disabled: pg.slotCount === 0,
695
+ title: pg.slotCount === 0 ? "add at least one member before spawning" : void 0,
381
696
  onClick: () => {
382
697
  setMenuOpen(false);
383
698
  setSpawnTeamFor(pg);
@@ -385,7 +700,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
385
700
  className: "flex w-full items-center justify-between rounded-sm px-3 py-1.5 text-sm hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent",
386
701
  children: [/* @__PURE__ */ jsx("span", { children: pg.name || pg.id }), /* @__PURE__ */ jsx("span", {
387
702
  className: "font-mono text-[0.7em] text-muted-foreground",
388
- children: pg.memberCount
703
+ children: pg.slotCount
389
704
  })]
390
705
  }, pg.id)),
391
706
  /* @__PURE__ */ jsx("div", { className: "my-1 h-px bg-border" }),
@@ -396,7 +711,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
396
711
  setCreateGroupOpen(true);
397
712
  },
398
713
  className: "block w-full text-left rounded-sm px-3 py-1.5 text-xs text-muted-foreground hover:bg-accent",
399
- children: "+ create group"
714
+ children: "+ create team"
400
715
  })
401
716
  ]
402
717
  })]
@@ -404,7 +719,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
404
719
  }),
405
720
  /* @__PURE__ */ jsx("nav", {
406
721
  className: "flex-1 overflow-y-auto p-1",
407
- children: agents.length === 0 && groups.length === 0 ? /* @__PURE__ */ jsxs("div", {
722
+ children: agents.length === 0 && teams.length === 0 ? /* @__PURE__ */ jsxs("div", {
408
723
  className: "p-4 text-sm text-muted-foreground",
409
724
  children: [
410
725
  "No agents yet.",
@@ -418,8 +733,8 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
418
733
  "to start chatting."
419
734
  ]
420
735
  }) : sortedGroups.map((g) => {
421
- const groupAgents = agentsByGroup.get(g.id) ?? [];
422
- const containsSelected = selectedGroupId === g.id;
736
+ const teamAgents = agentsByGroup.get(g.id) ?? [];
737
+ const containsSelected = selectedTeamId === g.id;
423
738
  const stored = openGroups[g.id];
424
739
  return /* @__PURE__ */ jsxs("details", {
425
740
  open: stored !== void 0 ? stored : containsSelected || g.id === "default",
@@ -434,12 +749,12 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
434
749
  setOpenGroups(merged);
435
750
  router.invalidate();
436
751
  },
437
- className: "group/details mb-1 last:mb-0",
752
+ className: "team/details mb-1 last:mb-0",
438
753
  children: [/* @__PURE__ */ jsxs("summary", {
439
754
  className: "flex cursor-pointer list-none items-center gap-1.5 rounded-sm px-2 py-1.5 text-xs uppercase tracking-wide text-muted-foreground hover:bg-accent",
440
755
  children: [
441
756
  /* @__PURE__ */ jsx("span", {
442
- className: "w-3 text-xs transition-transform group-open/details:rotate-90 inline-block",
757
+ className: "w-3 text-xs transition-transform team-open/details:rotate-90 inline-block",
443
758
  children: "▸"
444
759
  }),
445
760
  /* @__PURE__ */ jsx("span", {
@@ -448,16 +763,16 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
448
763
  }),
449
764
  /* @__PURE__ */ jsx("span", {
450
765
  className: "font-mono text-xs rounded bg-muted px-1 min-w-[1.4em] text-center",
451
- children: groupAgents.length
766
+ children: teamAgents.length
452
767
  })
453
768
  ]
454
- }), groupAgents.length === 0 ? /* @__PURE__ */ jsx("div", {
769
+ }), teamAgents.length === 0 ? /* @__PURE__ */ jsx("div", {
455
770
  className: "pl-6 py-1 text-xs italic text-muted-foreground",
456
771
  children: "no agents"
457
772
  }) : /* @__PURE__ */ jsx("div", {
458
773
  className: "pl-2",
459
- children: groupAgents.map((a) => /* @__PURE__ */ jsxs("div", {
460
- className: "group/row relative",
774
+ children: teamAgents.map((a) => /* @__PURE__ */ jsxs("div", {
775
+ className: "team/row relative",
461
776
  children: [/* @__PURE__ */ jsxs(Link, {
462
777
  to: "/",
463
778
  search: { agent: a.id },
@@ -481,7 +796,7 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
481
796
  }), /* @__PURE__ */ jsx("code", { children: a.id.slice(0, 8) })]
482
797
  })]
483
798
  }), /* @__PURE__ */ jsxs("div", {
484
- className: "absolute right-1 top-1 flex gap-0.5 opacity-0 transition-opacity group-hover/row:opacity-100 focus-within:opacity-100",
799
+ className: "absolute right-1 top-1 flex gap-0.5 opacity-0 transition-opacity team-hover/row:opacity-100 focus-within:opacity-100",
485
800
  children: [/* @__PURE__ */ jsx("button", {
486
801
  type: "button",
487
802
  onClick: () => rename(a),
@@ -505,23 +820,32 @@ function Sidebar({ agents, groups, profiles, profileGroups, selectedAgentId, ini
505
820
  }),
506
821
  spawnFor && /* @__PURE__ */ jsx(SpawnDialog, {
507
822
  profileId: spawnFor.profileId,
508
- groupHint: spawnFor.groupHint,
509
- groups: sortedGroups,
510
- onClose: () => setSpawnFor(null)
823
+ teamHint: spawnFor.teamHint,
824
+ teams: sortedGroups,
825
+ onClose: () => {
826
+ setSpawnFor(null);
827
+ restoreNewButton();
828
+ }
511
829
  }),
512
830
  spawnTeamFor && /* @__PURE__ */ jsx(SpawnTeamModal, {
513
831
  profileGroup: spawnTeamFor,
514
- groups: sortedGroups,
515
- onClose: () => setSpawnTeamFor(null),
832
+ teams: sortedGroups,
833
+ onClose: () => {
834
+ setSpawnTeamFor(null);
835
+ restoreNewButton();
836
+ },
516
837
  onSpawned: (slug) => {
517
838
  setSpawnTeamFor(null);
518
839
  router.navigate({
519
- to: "/groups/$id",
840
+ to: "/teams/$id",
520
841
  params: { id: slug }
521
842
  });
522
843
  }
523
844
  }),
524
- createGroupOpen && /* @__PURE__ */ jsx(CreateGroupDialog, { onClose: () => setCreateGroupOpen(false) })
845
+ createGroupOpen && /* @__PURE__ */ jsx(CreateTeamDialog, { onClose: () => {
846
+ setCreateGroupOpen(false);
847
+ restoreNewButton();
848
+ } })
525
849
  ]
526
850
  });
527
851
  }