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
@@ -0,0 +1,1009 @@
1
+ import { t as Button } from "./Button-Dsnw22OF.js";
2
+ import { a as applyProfileDefaults, c as endpointFromKey, d as hasTeamPolicyEdge, f as isValidTeamPolicyConnection, i as addTeamPolicyEdge, l as endpointKey, n as OUTSIDE_GROUP_ENDPOINT, o as createPresetPolicy, p as removeTeamPolicyEdge, r as USER_ENDPOINT, s as endpointForMember, u as findTeamPolicyMember } from "./team-policy-Csvc5EDd.js";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { AlertTriangle, Bot, Check, CircleAlert, CircleUserRound, Globe2, ListTree, Minus, Plus, Save, ShieldAlert, TableProperties, X } from "lucide-react";
6
+ import { Background, BackgroundVariant, Controls, Handle, MarkerType, MiniMap, Position, ReactFlow, useNodesState } from "@xyflow/react";
7
+ //#region src/lib/canonical-team.ts
8
+ function position(index, saved) {
9
+ return saved ?? {
10
+ x: 250 + index % 3 * 250,
11
+ y: 40 + Math.floor(index / 3) * 130
12
+ };
13
+ }
14
+ function edge(source, target, posture = "allow") {
15
+ return {
16
+ id: `${endpointKey(source)}>${endpointKey(target)}`,
17
+ source,
18
+ target,
19
+ posture
20
+ };
21
+ }
22
+ function templateDocument(detail) {
23
+ const members = detail.slots.map((slot, index) => ({
24
+ slotId: slot.slotId,
25
+ profileId: slot.profileId,
26
+ name: slot.agentName,
27
+ position: position(index, slot.layoutPosition)
28
+ }));
29
+ const policy = {
30
+ version: 1,
31
+ edges: detail.edges.map((item) => edge(item.sourceKind === "slot" ? {
32
+ kind: "member_slot",
33
+ slotId: item.sourceId ?? ""
34
+ } : { kind: item.sourceKind }, item.targetKind === "slot" ? {
35
+ kind: "member_slot",
36
+ slotId: item.targetId ?? ""
37
+ } : { kind: item.targetKind }, item.posture))
38
+ };
39
+ return {
40
+ id: detail.template.id,
41
+ kind: "template",
42
+ name: detail.template.name,
43
+ preset: inferPreset(members, policy),
44
+ members,
45
+ policy,
46
+ createdAt: detail.template.createdAt,
47
+ updatedAt: detail.template.updatedAt
48
+ };
49
+ }
50
+ function inferPreset(members, policy) {
51
+ const signature = (value) => value.edges.map((item) => `${endpointKey(item.source)}>${endpointKey(item.target)}:${item.posture ?? "allow"}`).sort().join("|");
52
+ const actual = signature(policy);
53
+ for (const preset of [
54
+ "open_team",
55
+ "coordinator",
56
+ "review_pipeline",
57
+ "blank"
58
+ ]) if (signature(createPresetPolicy("template", members, preset)) === actual) return preset;
59
+ return "blank";
60
+ }
61
+ function liveDocument(teamId, detail) {
62
+ const state = new Map(detail.agentState.map((item) => [item.agentId, item.position]));
63
+ return {
64
+ id: teamId,
65
+ kind: "live",
66
+ name: teamId,
67
+ preset: "blank",
68
+ members: detail.members.map((agent, index) => ({
69
+ slotId: `agent:${agent.id}`,
70
+ agentId: agent.id,
71
+ profileId: agent.profileId,
72
+ name: agent.name,
73
+ status: agent.status,
74
+ position: position(index, state.get(agent.id))
75
+ })),
76
+ policy: {
77
+ version: 1,
78
+ edges: detail.edges.map((item) => edge(item.sourceKind === "agent" ? {
79
+ kind: "agent",
80
+ agentId: item.sourceId ?? ""
81
+ } : { kind: item.sourceKind }, item.targetKind === "agent" ? {
82
+ kind: "agent",
83
+ agentId: item.targetId ?? ""
84
+ } : { kind: item.targetKind }, item.posture))
85
+ },
86
+ createdAt: detail.teamPolicy.updatedAt,
87
+ updatedAt: detail.teamPolicy.updatedAt
88
+ };
89
+ }
90
+ function templateDefinition(document, profiles) {
91
+ const profileIds = new Set(profiles.map((profile) => profile.id));
92
+ return {
93
+ slots: document.members.map((member) => {
94
+ if (!profileIds.has(member.profileId)) throw new Error(`Missing Agent template: ${member.profileId}`);
95
+ return {
96
+ ...member.slotId.startsWith("draft:") ? { clientKey: member.slotId } : { slotId: member.slotId },
97
+ profileId: member.profileId,
98
+ agentName: member.name,
99
+ modelOverride: null,
100
+ reasoningLevel: null,
101
+ layoutPosition: member.position,
102
+ display: null
103
+ };
104
+ }),
105
+ edges: document.policy.edges.map((item) => ({
106
+ sourceKind: item.source.kind === "member_slot" ? "slot" : item.source.kind,
107
+ sourceId: item.source.kind === "member_slot" ? item.source.slotId : null,
108
+ targetKind: item.target.kind === "member_slot" ? "slot" : item.target.kind,
109
+ targetId: item.target.kind === "member_slot" ? item.target.slotId : null,
110
+ posture: item.posture ?? "allow"
111
+ }))
112
+ };
113
+ }
114
+ function liveEdges(document) {
115
+ return document.policy.edges.map((item) => ({
116
+ sourceKind: item.source.kind === "member_slot" ? "agent" : item.source.kind,
117
+ sourceId: item.source.kind === "agent" ? item.source.agentId : null,
118
+ targetKind: item.target.kind === "member_slot" ? "agent" : item.target.kind,
119
+ targetId: item.target.kind === "agent" ? item.target.agentId : null,
120
+ posture: item.posture ?? "allow"
121
+ }));
122
+ }
123
+ function sameDocument(left, right) {
124
+ return JSON.stringify(left.members) === JSON.stringify(right.members) && JSON.stringify(left.policy.edges) === JSON.stringify(right.policy.edges);
125
+ }
126
+ //#endregion
127
+ //#region src/lib/team-policy-presenter.ts
128
+ function teamPolicyMemberLabel(member) {
129
+ return member.name || member.agentId || member.slotId;
130
+ }
131
+ function teamPolicyEndpointLabel(teamPolicy, endpoint) {
132
+ if (endpoint.kind === "user") return "User";
133
+ if (endpoint.kind === "outside_team") return "Other teams";
134
+ const member = findTeamPolicyMember(teamPolicy, endpoint);
135
+ return member ? teamPolicyMemberLabel(member) : endpoint.kind === "agent" ? endpoint.agentId : endpoint.slotId;
136
+ }
137
+ //#endregion
138
+ //#region src/components/team-policy/TeamPolicyFlow.tsx
139
+ function AgentNode({ data, selected }) {
140
+ return /* @__PURE__ */ jsxs("div", {
141
+ className: `relative w-[190px] rounded-md border bg-snow px-3 py-2.5 shadow-baziu-sm transition-shadow ${selected ? "border-sapphire shadow-baziu-md" : "border-frost"}`,
142
+ children: [
143
+ /* @__PURE__ */ jsx(Handle, {
144
+ type: "target",
145
+ position: Position.Left,
146
+ className: "!h-3 !w-3 !border-2 !border-snow !bg-sapphire"
147
+ }),
148
+ /* @__PURE__ */ jsxs("div", {
149
+ className: "flex min-w-0 items-center gap-2.5",
150
+ children: [
151
+ /* @__PURE__ */ jsx("span", {
152
+ className: "flex h-8 w-8 flex-none items-center justify-center rounded-md bg-sapphire-glow text-sapphire",
153
+ children: /* @__PURE__ */ jsx(Bot, {
154
+ className: "h-4 w-4",
155
+ "aria-hidden": "true"
156
+ })
157
+ }),
158
+ /* @__PURE__ */ jsxs("span", {
159
+ className: "min-w-0 flex-1",
160
+ children: [/* @__PURE__ */ jsx("span", {
161
+ className: "block truncate text-sm font-semibold text-chocolate",
162
+ children: data.member.name
163
+ }), /* @__PURE__ */ jsx("span", {
164
+ className: "mt-0.5 flex items-center gap-1.5 truncate text-[0.68rem] text-mocha-light",
165
+ children: data.member.role ?? (data.live ? data.member.status ?? "local member" : "member slot")
166
+ })]
167
+ }),
168
+ data.isolated && /* @__PURE__ */ jsx(ShieldAlert, {
169
+ className: "h-4 w-4 flex-none text-[#a56568]",
170
+ "aria-label": "Isolated member"
171
+ }),
172
+ data.incomplete && /* @__PURE__ */ jsx(CircleAlert, {
173
+ className: "h-4 w-4 flex-none text-amber-700 dark:text-amber-300",
174
+ "aria-label": "Incomplete member"
175
+ })
176
+ ]
177
+ }),
178
+ /* @__PURE__ */ jsx(Handle, {
179
+ type: "source",
180
+ position: Position.Right,
181
+ className: "!h-3 !w-3 !border-2 !border-snow !bg-sapphire"
182
+ })
183
+ ]
184
+ });
185
+ }
186
+ function BoundaryNode({ data, selected }) {
187
+ const Icon = data.kind === "user" ? CircleUserRound : Globe2;
188
+ return /* @__PURE__ */ jsxs("div", {
189
+ className: `w-[150px] rounded-md border bg-ivory px-3 py-2.5 shadow-baziu-sm ${selected ? "border-sapphire" : "border-fawn"}`,
190
+ children: [
191
+ /* @__PURE__ */ jsx(Handle, {
192
+ type: "target",
193
+ position: Position.Left,
194
+ className: "!h-3 !w-3 !border-2 !border-ivory !bg-rose-baziu"
195
+ }),
196
+ /* @__PURE__ */ jsxs("div", {
197
+ className: "flex items-center gap-2",
198
+ children: [/* @__PURE__ */ jsx(Icon, {
199
+ className: "h-4 w-4 flex-none text-rose-baziu",
200
+ "aria-hidden": "true"
201
+ }), /* @__PURE__ */ jsxs("span", {
202
+ className: "min-w-0",
203
+ children: [/* @__PURE__ */ jsx("span", {
204
+ className: "block text-sm font-semibold text-chocolate",
205
+ children: data.label
206
+ }), /* @__PURE__ */ jsx("span", {
207
+ className: "block truncate text-[0.66rem] text-mocha-light",
208
+ children: data.detail
209
+ })]
210
+ })]
211
+ }),
212
+ /* @__PURE__ */ jsx(Handle, {
213
+ type: "source",
214
+ position: Position.Right,
215
+ className: "!h-3 !w-3 !border-2 !border-ivory !bg-rose-baziu"
216
+ })
217
+ ]
218
+ });
219
+ }
220
+ var NODE_TYPES = {
221
+ agent: AgentNode,
222
+ boundary: BoundaryNode
223
+ };
224
+ function TeamPolicyFlow({ teamPolicy, selectedId, viewport, incompleteSlotIds, simulatedPath, onSelect, onConnect, onRemoveEdge, onMoveMember, onViewportChange, onOpenMember }) {
225
+ const computedNodes = useMemo(() => {
226
+ const outsideX = Math.max(930, ...teamPolicy.members.map((member) => member.position.x + 280));
227
+ const boundaryNodes = [{
228
+ id: endpointKey(USER_ENDPOINT),
229
+ type: "boundary",
230
+ position: {
231
+ x: 20,
232
+ y: 110
233
+ },
234
+ data: {
235
+ label: "User",
236
+ detail: "Web, CLI, Telegram",
237
+ kind: "user"
238
+ },
239
+ ariaLabel: "User communication boundary",
240
+ selected: selectedId === endpointKey(USER_ENDPOINT),
241
+ draggable: false,
242
+ deletable: false
243
+ }, {
244
+ id: endpointKey(OUTSIDE_GROUP_ENDPOINT),
245
+ type: "boundary",
246
+ position: {
247
+ x: outsideX,
248
+ y: 110
249
+ },
250
+ data: {
251
+ label: "Other teams",
252
+ detail: "Local Bazilion agents",
253
+ kind: "outside_team"
254
+ },
255
+ ariaLabel: "Other local teams communication boundary",
256
+ selected: selectedId === endpointKey(OUTSIDE_GROUP_ENDPOINT),
257
+ draggable: false,
258
+ deletable: false
259
+ }];
260
+ const memberNodes = teamPolicy.members.map((member) => {
261
+ const endpoint = endpointForMember(teamPolicy, member);
262
+ const isolated = !teamPolicy.policy.edges.some((edge) => endpointKey(edge.source) === endpointKey(endpoint) || endpointKey(edge.target) === endpointKey(endpoint));
263
+ return {
264
+ id: endpointKey(endpoint),
265
+ type: "agent",
266
+ position: member.position,
267
+ data: {
268
+ member,
269
+ isolated,
270
+ incomplete: incompleteSlotIds.has(member.slotId),
271
+ live: teamPolicy.kind === "live"
272
+ },
273
+ ariaLabel: `${member.name}, ${isolated ? "isolated" : "configured"}${incompleteSlotIds.has(member.slotId) ? ", incomplete" : ""} ${teamPolicy.kind === "live" ? "agent" : "member slot"}`,
274
+ selected: selectedId === endpointKey(endpoint),
275
+ deletable: false
276
+ };
277
+ });
278
+ return [...boundaryNodes, ...memberNodes];
279
+ }, [
280
+ teamPolicy,
281
+ incompleteSlotIds,
282
+ selectedId
283
+ ]);
284
+ const [nodes, setNodes, onNodesChange] = useNodesState(computedNodes);
285
+ useEffect(() => {
286
+ setNodes((current) => {
287
+ const currentById = new Map(current.map((node) => [node.id, node]));
288
+ return computedNodes.map((node) => ({
289
+ ...currentById.get(node.id),
290
+ ...node
291
+ }));
292
+ });
293
+ }, [computedNodes, setNodes]);
294
+ const edges = useMemo(() => {
295
+ const simulationKey = simulatedPath ? `${endpointKey(simulatedPath.source)}>${endpointKey(simulatedPath.target)}` : null;
296
+ const policyEdges = teamPolicy.policy.edges.map((edge) => {
297
+ const simulated = simulationKey === `${endpointKey(edge.source)}>${endpointKey(edge.target)}`;
298
+ return {
299
+ id: edge.id,
300
+ source: endpointKey(edge.source),
301
+ target: endpointKey(edge.target),
302
+ selected: selectedId === edge.id,
303
+ animated: simulated,
304
+ markerEnd: {
305
+ type: MarkerType.ArrowClosed,
306
+ width: 16,
307
+ height: 16
308
+ },
309
+ style: {
310
+ stroke: simulated ? "var(--color-rose-baziu)" : "var(--color-sapphire)",
311
+ strokeWidth: simulated ? 3 : 1.7
312
+ }
313
+ };
314
+ });
315
+ if (!simulatedPath || simulatedPath.decision === "allow") return policyEdges;
316
+ return [...policyEdges, {
317
+ id: `simulation:${simulationKey}`,
318
+ source: endpointKey(simulatedPath.source),
319
+ target: endpointKey(simulatedPath.target),
320
+ animated: true,
321
+ deletable: false,
322
+ markerEnd: {
323
+ type: MarkerType.ArrowClosed,
324
+ width: 16,
325
+ height: 16,
326
+ color: "var(--color-rose-baziu)"
327
+ },
328
+ style: {
329
+ stroke: "var(--color-rose-baziu)",
330
+ strokeDasharray: "6 5",
331
+ strokeWidth: 2.5
332
+ }
333
+ }];
334
+ }, [
335
+ teamPolicy.policy.edges,
336
+ selectedId,
337
+ simulatedPath
338
+ ]);
339
+ const connect = (connection) => {
340
+ if (!connection.source || !connection.target) return;
341
+ const source = endpointFromKey(connection.source);
342
+ const target = endpointFromKey(connection.target);
343
+ if (source && target) onConnect(source, target);
344
+ };
345
+ return /* @__PURE__ */ jsx("div", {
346
+ className: "h-full min-h-[420px] w-full bg-ivory",
347
+ children: /* @__PURE__ */ jsxs(ReactFlow, {
348
+ nodes,
349
+ edges,
350
+ nodeTypes: NODE_TYPES,
351
+ onConnect: connect,
352
+ onNodesChange,
353
+ onNodeClick: (_event, node) => onSelect(node.id),
354
+ onNodeDoubleClick: (_event, node) => {
355
+ const endpoint = endpointFromKey(node.id);
356
+ if (!endpoint) return;
357
+ const member = endpoint.kind === "agent" ? teamPolicy.members.find((candidate) => (candidate.agentId ?? `prototype:${candidate.slotId}`) === endpoint.agentId) : endpoint.kind === "member_slot" ? teamPolicy.members.find((candidate) => candidate.slotId === endpoint.slotId) : void 0;
358
+ if (member) onOpenMember(member);
359
+ },
360
+ onEdgeClick: (_event, edge) => onSelect(edge.id),
361
+ onPaneClick: () => onSelect(null),
362
+ onEdgesDelete: (deleted) => {
363
+ for (const edge of deleted) {
364
+ const source = endpointFromKey(edge.source);
365
+ const target = endpointFromKey(edge.target);
366
+ if (source && target) onRemoveEdge(source, target);
367
+ }
368
+ },
369
+ onNodeDragStop: (_event, node) => {
370
+ const endpoint = endpointFromKey(node.id);
371
+ if (!endpoint || !("data" in node)) return;
372
+ const member = endpoint.kind === "agent" ? teamPolicy.members.find((candidate) => (candidate.agentId ?? `prototype:${candidate.slotId}`) === endpoint.agentId) : endpoint.kind === "member_slot" ? teamPolicy.members.find((candidate) => candidate.slotId === endpoint.slotId) : void 0;
373
+ if (member) onMoveMember(member.slotId, node.position);
374
+ },
375
+ onMoveEnd: (_event, nextViewport) => onViewportChange(nextViewport),
376
+ defaultViewport: viewport,
377
+ minZoom: .35,
378
+ maxZoom: 1.8,
379
+ edgesReconnectable: false,
380
+ fitView: viewport.x === 0 && viewport.y === 0 && viewport.zoom === 1,
381
+ fitViewOptions: {
382
+ padding: .22,
383
+ maxZoom: 1
384
+ },
385
+ proOptions: { hideAttribution: true },
386
+ className: "teamPolicy-flow",
387
+ children: [
388
+ /* @__PURE__ */ jsx(Background, {
389
+ variant: BackgroundVariant.Dots,
390
+ gap: 20,
391
+ size: 1.2,
392
+ color: "var(--color-fawn)"
393
+ }),
394
+ /* @__PURE__ */ jsx(Controls, {
395
+ position: "bottom-left",
396
+ showInteractive: false,
397
+ className: "!overflow-hidden !rounded-md !border !border-frost !bg-snow !shadow-baziu-sm [&_button]:!border-frost [&_button]:!bg-snow [&_button]:!fill-chocolate"
398
+ }),
399
+ /* @__PURE__ */ jsx(MiniMap, {
400
+ pannable: true,
401
+ zoomable: true,
402
+ position: "bottom-right",
403
+ className: "!hidden !rounded-md !border !border-frost !bg-snow sm:!block",
404
+ nodeColor: (node) => node.type === "boundary" ? "var(--color-rose-baziu)" : "var(--color-sapphire)",
405
+ maskColor: "color-mix(in srgb, var(--color-cream) 70%, transparent)"
406
+ })
407
+ ]
408
+ })
409
+ });
410
+ }
411
+ //#endregion
412
+ //#region src/components/team-policy/TeamPolicyMatrix.tsx
413
+ function TeamPolicyMatrix({ teamPolicy, selectedId, onSelect, onToggle }) {
414
+ const actors = [
415
+ USER_ENDPOINT,
416
+ ...teamPolicy.members.map((member) => endpointForMember(teamPolicy, member)),
417
+ OUTSIDE_GROUP_ENDPOINT
418
+ ];
419
+ return /* @__PURE__ */ jsxs("div", {
420
+ className: "h-full min-h-[420px] overflow-auto bg-ivory p-4 sm:p-6",
421
+ children: [/* @__PURE__ */ jsxs("div", {
422
+ className: "mb-4",
423
+ children: [/* @__PURE__ */ jsx("h2", {
424
+ className: "m-0 font-body text-base font-semibold text-chocolate",
425
+ children: "Communication matrix"
426
+ }), /* @__PURE__ */ jsx("p", {
427
+ className: "mt-1 text-xs text-mocha-light",
428
+ children: "Rows send; columns receive. Every cell edits the same directed edge set as Flow."
429
+ })]
430
+ }), /* @__PURE__ */ jsxs("table", {
431
+ className: "m-0 min-w-[720px] table-fixed overflow-visible rounded-md text-xs",
432
+ children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
433
+ className: "sticky left-0 z-20 w-40 bg-ivory",
434
+ children: "source / target"
435
+ }), actors.map((target) => /* @__PURE__ */ jsx("th", {
436
+ className: "w-24 max-w-24 text-center normal-case tracking-normal",
437
+ children: /* @__PURE__ */ jsx("button", {
438
+ type: "button",
439
+ onClick: () => onSelect(endpointKey(target)),
440
+ className: `w-full truncate rounded-sm px-1 py-1 hover:bg-sapphire-glow ${selectedId === endpointKey(target) ? "text-sapphire" : "text-mocha"}`,
441
+ title: teamPolicyEndpointLabel(teamPolicy, target),
442
+ children: teamPolicyEndpointLabel(teamPolicy, target)
443
+ })
444
+ }, endpointKey(target)))] }) }), /* @__PURE__ */ jsx("tbody", { children: actors.map((source) => /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
445
+ className: "sticky left-0 z-10 max-w-40 bg-snow normal-case tracking-normal",
446
+ children: /* @__PURE__ */ jsx("button", {
447
+ type: "button",
448
+ onClick: () => onSelect(endpointKey(source)),
449
+ className: `w-full truncate rounded-sm px-1 py-1 text-left hover:bg-sapphire-glow ${selectedId === endpointKey(source) ? "text-sapphire" : "text-mocha"}`,
450
+ title: teamPolicyEndpointLabel(teamPolicy, source),
451
+ children: teamPolicyEndpointLabel(teamPolicy, source)
452
+ })
453
+ }), actors.map((target) => {
454
+ const valid = isValidTeamPolicyConnection(source, target);
455
+ const allowed = valid && hasTeamPolicyEdge(teamPolicy.policy, source, target);
456
+ const label = `${teamPolicyEndpointLabel(teamPolicy, source)} to ${teamPolicyEndpointLabel(teamPolicy, target)}`;
457
+ return /* @__PURE__ */ jsx("td", {
458
+ className: "h-14 p-1 text-center",
459
+ children: valid ? /* @__PURE__ */ jsx("button", {
460
+ type: "button",
461
+ onClick: () => onToggle(source, target, !allowed),
462
+ "aria-pressed": allowed,
463
+ "aria-label": `${allowed ? "Deny" : "Allow"} ${label}`,
464
+ title: `${allowed ? "Allowed" : "Denied"}: ${label}`,
465
+ className: `mx-auto flex h-9 w-9 items-center justify-center rounded-md border transition-colors ${allowed ? "border-sapphire bg-sapphire text-snow hover:bg-sapphire-deep" : "border-frost bg-ivory text-mocha-light hover:border-rose-baziu hover:text-rose-baziu"}`,
466
+ children: allowed ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
467
+ }) : /* @__PURE__ */ jsx("span", {
468
+ className: "mx-auto flex h-9 w-9 items-center justify-center text-fawn",
469
+ title: "Not a valid communication path",
470
+ children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" })
471
+ })
472
+ }, endpointKey(target));
473
+ })] }, endpointKey(source))) })]
474
+ })]
475
+ });
476
+ }
477
+ //#endregion
478
+ //#region src/components/team-policy/ProductionTeamPolicyEditor.tsx
479
+ function ProductionTeamPolicyEditor({ source, profiles, initialUi }) {
480
+ const initial = useMemo(() => source.kind === "template" ? templateDocument(source.detail) : liveDocument(source.teamId, source.detail), [source]);
481
+ const [server, setServer] = useState(initial);
482
+ const [draft, setDraft] = useState(initial);
483
+ const [revision, setRevision] = useState(source.kind === "template" ? source.detail.template.currentRevision : source.detail.teamPolicy.revision);
484
+ const [view, setView] = useState(initialUi?.view ?? "flow");
485
+ const [selectedId, setSelectedId] = useState(() => validSelection(initial, initialUi?.selectedId));
486
+ const [viewport, setViewport] = useState(initialUi?.viewport ?? {
487
+ x: 0,
488
+ y: 0,
489
+ zoom: .9
490
+ });
491
+ const [saving, setSaving] = useState(false);
492
+ const [notice, setNotice] = useState(null);
493
+ const [conflict, setConflict] = useState(null);
494
+ const dirty = !sameDocument(server, draft);
495
+ useEffect(() => {
496
+ const warn = (event) => {
497
+ if (!dirty) return;
498
+ event.preventDefault();
499
+ };
500
+ window.addEventListener("beforeunload", warn);
501
+ return () => window.removeEventListener("beforeunload", warn);
502
+ }, [dirty]);
503
+ const mutateEdge = (from, to, allowed) => {
504
+ if (!isValidTeamPolicyConnection(from, to)) return;
505
+ setDraft((current) => ({
506
+ ...current,
507
+ policy: allowed ? addTeamPolicyEdge(current.policy, from, to) : removeTeamPolicyEdge(current.policy, from, to)
508
+ }));
509
+ };
510
+ const setEdgePosture = (from, to, posture) => setDraft((current) => ({
511
+ ...current,
512
+ policy: {
513
+ ...current.policy,
514
+ edges: current.policy.edges.map((item) => endpointKey(item.source) === endpointKey(from) && endpointKey(item.target) === endpointKey(to) ? {
515
+ ...item,
516
+ posture
517
+ } : item)
518
+ }
519
+ }));
520
+ const reloadCurrent = async () => {
521
+ const url = source.kind === "template" ? `/api/team-templates/${encodeURIComponent(source.detail.template.id)}` : `/api/teams/${encodeURIComponent(source.teamId)}/policy`;
522
+ const response = await fetch(url);
523
+ if (!response.ok) throw new Error(await response.text());
524
+ if (source.kind === "template") {
525
+ const detail = await response.json();
526
+ return {
527
+ document: templateDocument(detail),
528
+ revision: detail.template.currentRevision
529
+ };
530
+ }
531
+ const detail = await response.json();
532
+ return {
533
+ document: liveDocument(source.teamId, detail),
534
+ revision: detail.teamPolicy.revision
535
+ };
536
+ };
537
+ const save = async () => {
538
+ setSaving(true);
539
+ setNotice(null);
540
+ try {
541
+ const response = source.kind === "template" ? await fetch(`/api/team-templates/${encodeURIComponent(source.detail.template.id)}/definition`, {
542
+ method: "PUT",
543
+ headers: { "content-type": "application/json" },
544
+ body: JSON.stringify({
545
+ expectedRevision: revision,
546
+ ...templateDefinition(draft, profiles)
547
+ })
548
+ }) : await fetch(`/api/teams/${encodeURIComponent(source.teamId)}/policy`, {
549
+ method: "PUT",
550
+ headers: { "content-type": "application/json" },
551
+ body: JSON.stringify({
552
+ expectedRevision: revision,
553
+ edges: liveEdges(draft)
554
+ })
555
+ });
556
+ if (response.status === 409) {
557
+ const current = await reloadCurrent();
558
+ setConflict(current.document);
559
+ setServer(current.document);
560
+ setRevision(current.revision);
561
+ setNotice("The server changed. Your draft is preserved; compare, reload, or reapply it.");
562
+ return;
563
+ }
564
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.error ?? `Save failed (${response.status})`);
565
+ const current = await reloadCurrent();
566
+ setServer(current.document);
567
+ setDraft(current.document);
568
+ setRevision(current.revision);
569
+ setConflict(null);
570
+ setNotice(`Effective policy saved as revision ${current.revision}.`);
571
+ } catch (error) {
572
+ setNotice(error instanceof Error ? error.message : String(error));
573
+ } finally {
574
+ setSaving(false);
575
+ }
576
+ };
577
+ const selected = selectedId ? endpointFromKey(selectedId) : null;
578
+ const selectedMember = selected ? draft.members.find((member) => endpointKey(endpointForMember(draft, member)) === selectedId) : void 0;
579
+ const incomplete = new Set(draft.members.filter((member) => !profiles.some((profile) => profile.id === member.profileId)).map((member) => member.slotId));
580
+ return /* @__PURE__ */ jsxs("section", {
581
+ className: "overflow-hidden rounded-lg border border-frost bg-snow",
582
+ "aria-label": "Production policy editor",
583
+ children: [
584
+ /* @__PURE__ */ jsxs("header", {
585
+ className: "flex flex-wrap items-center gap-2 border-b border-frost bg-cream p-3",
586
+ children: [
587
+ /* @__PURE__ */ jsxs("div", {
588
+ className: "mr-auto min-w-0",
589
+ children: [/* @__PURE__ */ jsxs("div", {
590
+ className: "flex items-center gap-2",
591
+ children: [/* @__PURE__ */ jsx("h2", {
592
+ className: "m-0 truncate text-lg",
593
+ children: draft.name
594
+ }), /* @__PURE__ */ jsx("span", {
595
+ className: dirty ? "rounded bg-amber-100 px-2 py-0.5 text-xs text-amber-900 dark:bg-amber-900/40 dark:text-amber-100" : "rounded bg-sapphire-glow px-2 py-0.5 text-xs text-sapphire-deep",
596
+ children: dirty ? "Unsaved draft" : `Effective · revision ${revision}`
597
+ })]
598
+ }), /* @__PURE__ */ jsx("p", {
599
+ className: "muted m-0 text-xs",
600
+ children: source.kind === "template" ? "Stable Team slot policy" : "One effective live Team policy"
601
+ })]
602
+ }),
603
+ /* @__PURE__ */ jsxs("div", {
604
+ className: "flex rounded-md border border-frost bg-ivory p-0.5",
605
+ "aria-label": "Policy projection",
606
+ children: [/* @__PURE__ */ jsx(Projection, {
607
+ active: view === "flow",
608
+ label: "Flow",
609
+ icon: /* @__PURE__ */ jsx(ListTree, { className: "h-4 w-4" }),
610
+ onClick: () => setView("flow")
611
+ }), /* @__PURE__ */ jsx(Projection, {
612
+ active: view === "matrix",
613
+ label: "Matrix",
614
+ icon: /* @__PURE__ */ jsx(TableProperties, { className: "h-4 w-4" }),
615
+ onClick: () => setView("matrix")
616
+ })]
617
+ }),
618
+ /* @__PURE__ */ jsx(Button, {
619
+ variant: "ghost",
620
+ disabled: !dirty || saving,
621
+ onClick: () => setDraft(server),
622
+ children: "Discard"
623
+ }),
624
+ /* @__PURE__ */ jsxs(Button, {
625
+ variant: "primary",
626
+ disabled: !dirty || saving || source.kind === "template" && !!source.detail.template.deletedAt,
627
+ onClick: save,
628
+ children: [
629
+ /* @__PURE__ */ jsx(Save, { className: "h-4 w-4" }),
630
+ " ",
631
+ saving ? "Saving…" : "Save effective policy"
632
+ ]
633
+ })
634
+ ]
635
+ }),
636
+ notice && /* @__PURE__ */ jsx("div", {
637
+ role: "status",
638
+ className: "border-b border-frost bg-ivory px-4 py-2 text-sm",
639
+ children: notice
640
+ }),
641
+ conflict && /* @__PURE__ */ jsx(ConflictBanner, {
642
+ draft,
643
+ server: conflict,
644
+ onReload: () => {
645
+ setDraft(conflict);
646
+ setConflict(null);
647
+ },
648
+ onReapply: () => setConflict(null)
649
+ }),
650
+ /* @__PURE__ */ jsxs("div", {
651
+ className: "grid min-h-[620px] grid-cols-1 lg:grid-cols-[minmax(0,1fr)_280px]",
652
+ children: [/* @__PURE__ */ jsx("div", {
653
+ className: "min-h-[480px] overflow-hidden",
654
+ children: view === "flow" ? /* @__PURE__ */ jsx(TeamPolicyFlow, {
655
+ teamPolicy: draft,
656
+ selectedId,
657
+ viewport,
658
+ incompleteSlotIds: incomplete,
659
+ simulatedPath: null,
660
+ onSelect: setSelectedId,
661
+ onConnect: (a, b) => mutateEdge(a, b, true),
662
+ onRemoveEdge: (a, b) => mutateEdge(a, b, false),
663
+ onMoveMember: (slotId, position) => setDraft((current) => ({
664
+ ...current,
665
+ members: current.members.map((m) => m.slotId === slotId ? {
666
+ ...m,
667
+ position
668
+ } : m)
669
+ })),
670
+ onViewportChange: setViewport,
671
+ onOpenMember: (member) => source.kind === "live" && member.agentId ? window.location.assign(`/agents/${encodeURIComponent(member.agentId)}?teamPolicy=${encodeURIComponent(source.teamId)}&view=${view}&selected=${encodeURIComponent(selectedId ?? "")}&vx=${viewport.x}&vy=${viewport.y}&vz=${viewport.zoom}`) : setSelectedId(endpointKey(endpointForMember(draft, member)))
672
+ }) : /* @__PURE__ */ jsx(TeamPolicyMatrix, {
673
+ teamPolicy: draft,
674
+ selectedId,
675
+ onSelect: setSelectedId,
676
+ onToggle: mutateEdge
677
+ })
678
+ }), /* @__PURE__ */ jsx("aside", {
679
+ className: "border-t border-frost p-4 lg:border-l lg:border-t-0",
680
+ children: /* @__PURE__ */ jsx(Inspector, {
681
+ document: draft,
682
+ selected,
683
+ selectedMember,
684
+ profiles,
685
+ source,
686
+ onDraft: setDraft,
687
+ onToggle: mutateEdge,
688
+ onPosture: setEdgePosture
689
+ })
690
+ })]
691
+ })
692
+ ]
693
+ });
694
+ }
695
+ function validSelection(document, selectedId) {
696
+ if (!selectedId) return null;
697
+ if (selectedId === "user" || selectedId === "outside_team") return selectedId;
698
+ if (document.policy.edges.some((edge) => edge.id === selectedId)) return selectedId;
699
+ return document.members.some((member) => endpointKey(endpointForMember(document, member)) === selectedId) ? selectedId : null;
700
+ }
701
+ function Projection({ active, label, icon, onClick }) {
702
+ return /* @__PURE__ */ jsxs("button", {
703
+ type: "button",
704
+ "aria-pressed": active,
705
+ onClick,
706
+ className: `flex items-center gap-1 rounded px-2 py-1 text-xs ${active ? "bg-snow text-sapphire shadow-sm" : "text-mocha"}`,
707
+ children: [icon, label]
708
+ });
709
+ }
710
+ function ConflictBanner({ draft, server, onReload, onReapply }) {
711
+ return /* @__PURE__ */ jsxs("div", {
712
+ role: "alert",
713
+ className: "flex flex-wrap items-center gap-3 border-b border-amber-300 bg-amber-50 p-3 text-sm text-amber-950 dark:bg-amber-950/30 dark:text-amber-100",
714
+ children: [
715
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" }),
716
+ /* @__PURE__ */ jsxs("span", {
717
+ className: "mr-auto",
718
+ children: [
719
+ "Conflict: server has ",
720
+ server.policy.edges.length,
721
+ " edges; your preserved draft has ",
722
+ draft.policy.edges.length,
723
+ "."
724
+ ]
725
+ }),
726
+ /* @__PURE__ */ jsx(Button, {
727
+ variant: "ghost",
728
+ onClick: onReload,
729
+ children: "Reload server"
730
+ }),
731
+ /* @__PURE__ */ jsx(Button, {
732
+ variant: "primary",
733
+ onClick: onReapply,
734
+ children: "Keep draft and reapply"
735
+ })
736
+ ]
737
+ });
738
+ }
739
+ function Inspector({ document, selected, selectedMember, profiles, source, onDraft, onToggle, onPosture }) {
740
+ const [simSource, setSimSource] = useState("user");
741
+ const [simTarget, setSimTarget] = useState(document.members[0] ? endpointKey(endpointForMember(document, document.members[0])) : "outside_team");
742
+ const [result, setResult] = useState(null);
743
+ const actors = [
744
+ {
745
+ key: "user",
746
+ label: "User"
747
+ },
748
+ ...document.members.map((m) => ({
749
+ key: endpointKey(endpointForMember(document, m)),
750
+ label: m.name
751
+ })),
752
+ {
753
+ key: "outside_team",
754
+ label: "Other teams"
755
+ }
756
+ ];
757
+ const selectedProfile = selectedMember ? profiles.find((profile) => profile.id === selectedMember.profileId) : void 0;
758
+ const simulate = async () => {
759
+ const from = endpointFromKey(simSource);
760
+ const to = endpointFromKey(simTarget);
761
+ if (!from || !to) return;
762
+ if (source.kind !== "live") {
763
+ setResult({
764
+ decision: hasTeamPolicyEdge(document.policy, from, to) ? "allow" : "deny",
765
+ channel: "user",
766
+ reasonCode: "draft_preview",
767
+ reason: "Draft-only preview; no audit event was created.",
768
+ policyRefs: [],
769
+ componentOutcomes: [],
770
+ matchedEdgeIds: [],
771
+ requiredEdgeIds: []
772
+ });
773
+ return;
774
+ }
775
+ const endpoint = (value) => value.kind === "agent" ? {
776
+ kind: "agent",
777
+ id: value.agentId
778
+ } : {
779
+ kind: value.kind,
780
+ teamId: source.teamId
781
+ };
782
+ setResult(await (await fetch("/api/communication/evaluate", {
783
+ method: "POST",
784
+ headers: { "content-type": "application/json" },
785
+ body: JSON.stringify({
786
+ source: endpoint(from),
787
+ target: endpoint(to),
788
+ origin: "web",
789
+ attemptKind: "diagnostic",
790
+ attemptId: crypto.randomUUID()
791
+ })
792
+ })).json());
793
+ };
794
+ return /* @__PURE__ */ jsxs("div", {
795
+ className: "space-y-5",
796
+ children: [
797
+ /* @__PURE__ */ jsxs("div", { children: [
798
+ /* @__PURE__ */ jsx("p", {
799
+ className: "text-xs font-semibold uppercase text-mocha-light",
800
+ children: "Inspector"
801
+ }),
802
+ /* @__PURE__ */ jsx("h3", {
803
+ className: "mt-1 text-base",
804
+ children: selected ? teamPolicyEndpointLabel(document, selected) : "Policy summary"
805
+ }),
806
+ /* @__PURE__ */ jsxs("p", {
807
+ className: "muted text-xs",
808
+ children: [
809
+ document.members.length,
810
+ " actors · ",
811
+ document.policy.edges.length,
812
+ " directed allow edges"
813
+ ]
814
+ })
815
+ ] }),
816
+ document.kind === "template" && !selected && /* @__PURE__ */ jsxs("div", {
817
+ className: "space-y-2",
818
+ children: [
819
+ /* @__PURE__ */ jsx("p", {
820
+ className: "text-xs font-semibold",
821
+ children: "Preset preview"
822
+ }),
823
+ /* @__PURE__ */ jsx("p", {
824
+ className: "muted text-xs",
825
+ children: "Applying a preset visibly replaces this draft edge set; it is never effective until saved."
826
+ }),
827
+ /* @__PURE__ */ jsxs("select", {
828
+ "aria-label": "Policy preset",
829
+ value: document.preset,
830
+ onChange: (event) => onDraft((current) => ({
831
+ ...current,
832
+ preset: event.target.value
833
+ })),
834
+ children: [
835
+ /* @__PURE__ */ jsx("option", {
836
+ value: "open_team",
837
+ children: "Open Team"
838
+ }),
839
+ /* @__PURE__ */ jsx("option", {
840
+ value: "coordinator",
841
+ children: "Coordinator"
842
+ }),
843
+ /* @__PURE__ */ jsx("option", {
844
+ value: "review_pipeline",
845
+ children: "Review Pipeline"
846
+ }),
847
+ /* @__PURE__ */ jsx("option", {
848
+ value: "blank",
849
+ children: "Blank"
850
+ })
851
+ ]
852
+ }),
853
+ /* @__PURE__ */ jsx(Button, {
854
+ variant: "ghost",
855
+ onClick: () => onDraft((current) => ({
856
+ ...current,
857
+ policy: createPresetPolicy("template", current.members, current.preset)
858
+ })),
859
+ children: "Apply preset to draft"
860
+ })
861
+ ]
862
+ }),
863
+ selectedMember && document.kind === "template" && /* @__PURE__ */ jsxs("div", {
864
+ className: "space-y-2",
865
+ children: [
866
+ /* @__PURE__ */ jsxs("label", {
867
+ className: "text-xs",
868
+ children: ["Agent name", /* @__PURE__ */ jsx("input", {
869
+ value: selectedMember.name,
870
+ onChange: (e) => onDraft((d) => ({
871
+ ...d,
872
+ members: d.members.map((m) => m.slotId === selectedMember.slotId ? {
873
+ ...m,
874
+ name: e.target.value
875
+ } : m)
876
+ }))
877
+ })]
878
+ }),
879
+ /* @__PURE__ */ jsxs("label", {
880
+ className: "text-xs",
881
+ children: ["Agent template", /* @__PURE__ */ jsx("select", {
882
+ value: selectedMember.profileId,
883
+ onChange: (e) => onDraft((d) => ({
884
+ ...d,
885
+ members: d.members.map((m) => m.slotId === selectedMember.slotId ? {
886
+ ...m,
887
+ profileId: e.target.value
888
+ } : m)
889
+ })),
890
+ children: profiles.map((p) => /* @__PURE__ */ jsx("option", {
891
+ value: p.id,
892
+ children: p.name
893
+ }, p.id))
894
+ })]
895
+ }),
896
+ selectedProfile?.communicationDefaults && /* @__PURE__ */ jsx(Button, {
897
+ variant: "ghost",
898
+ onClick: () => onDraft((current) => ({
899
+ ...current,
900
+ policy: applyProfileDefaults(current.policy, current, selectedMember, selectedProfile.communicationDefaults)
901
+ })),
902
+ children: "Apply Agent-template defaults to draft"
903
+ })
904
+ ]
905
+ }),
906
+ selected && /* @__PURE__ */ jsxs("div", {
907
+ className: "space-y-2",
908
+ children: [/* @__PURE__ */ jsx("p", {
909
+ className: "text-xs font-semibold",
910
+ children: "Directed permissions"
911
+ }), actors.map((actor) => {
912
+ const target = endpointFromKey(actor.key);
913
+ if (!target || !isValidTeamPolicyConnection(selected, target)) return null;
914
+ const allowed = hasTeamPolicyEdge(document.policy, selected, target);
915
+ const current = document.policy.edges.find((item) => endpointKey(item.source) === endpointKey(selected) && endpointKey(item.target) === endpointKey(target));
916
+ return /* @__PURE__ */ jsxs("div", {
917
+ className: "rounded border border-frost p-2 text-xs",
918
+ children: [/* @__PURE__ */ jsxs("button", {
919
+ type: "button",
920
+ "aria-pressed": allowed,
921
+ onClick: () => onToggle(selected, target, !allowed),
922
+ className: "flex w-full items-center justify-between",
923
+ children: [/* @__PURE__ */ jsxs("span", { children: ["Send to ", actor.label] }), allowed ? "Allowed" : "Denied"]
924
+ }), allowed && /* @__PURE__ */ jsx("button", {
925
+ type: "button",
926
+ "aria-pressed": current?.posture === "approval_required",
927
+ onClick: () => onPosture(selected, target, current?.posture === "approval_required" ? "allow" : "approval_required"),
928
+ className: "mt-2 w-full rounded bg-ivory px-2 py-1 text-left",
929
+ children: current?.posture === "approval_required" ? "Approval required" : "Immediate delivery"
930
+ })]
931
+ }, actor.key);
932
+ })]
933
+ }),
934
+ /* @__PURE__ */ jsxs("div", {
935
+ className: "space-y-2 border-t border-frost pt-4",
936
+ children: [
937
+ /* @__PURE__ */ jsx("p", {
938
+ className: "text-xs font-semibold",
939
+ children: "Side-effect-free simulator"
940
+ }),
941
+ /* @__PURE__ */ jsx("select", {
942
+ "aria-label": "Simulation source",
943
+ value: simSource,
944
+ onChange: (e) => setSimSource(e.target.value),
945
+ children: actors.map((a) => /* @__PURE__ */ jsx("option", {
946
+ value: a.key,
947
+ children: a.label
948
+ }, a.key))
949
+ }),
950
+ /* @__PURE__ */ jsx("select", {
951
+ "aria-label": "Simulation target",
952
+ value: simTarget,
953
+ onChange: (e) => setSimTarget(e.target.value),
954
+ children: actors.map((a) => /* @__PURE__ */ jsx("option", {
955
+ value: a.key,
956
+ children: a.label
957
+ }, a.key))
958
+ }),
959
+ /* @__PURE__ */ jsx(Button, {
960
+ variant: "ghost",
961
+ onClick: simulate,
962
+ children: "Evaluate without sending"
963
+ }),
964
+ result && /* @__PURE__ */ jsxs("p", {
965
+ role: "status",
966
+ className: `rounded p-2 text-xs ${result.decision === "allow" ? "bg-sapphire-glow" : "bg-rose-baziu/10"}`,
967
+ children: [
968
+ result.decision.toUpperCase(),
969
+ " · ",
970
+ result.reasonCode,
971
+ /* @__PURE__ */ jsx("br", {}),
972
+ result.reason
973
+ ]
974
+ })
975
+ ]
976
+ }),
977
+ document.kind === "template" && /* @__PURE__ */ jsxs(Button, {
978
+ variant: "ghost",
979
+ onClick: () => onDraft((d) => ({
980
+ ...d,
981
+ members: [...d.members, {
982
+ slotId: `draft:${crypto.randomUUID()}`,
983
+ profileId: profiles[0]?.id ?? "",
984
+ name: `Agent ${d.members.length + 1}`,
985
+ position: {
986
+ x: 250 + d.members.length % 3 * 250,
987
+ y: 40 + Math.floor(d.members.length / 3) * 130
988
+ }
989
+ }]
990
+ })),
991
+ children: [/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }), "Add stable slot"]
992
+ }),
993
+ selectedMember && document.kind === "template" && /* @__PURE__ */ jsxs(Button, {
994
+ variant: "danger",
995
+ onClick: () => onDraft((d) => ({
996
+ ...d,
997
+ members: d.members.filter((m) => m.slotId !== selectedMember.slotId),
998
+ policy: {
999
+ ...d.policy,
1000
+ edges: d.policy.edges.filter((e) => endpointKey(e.source) !== endpointKey(selected) && endpointKey(e.target) !== endpointKey(selected))
1001
+ }
1002
+ })),
1003
+ children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), "Remove slot and incident edges"]
1004
+ })
1005
+ ]
1006
+ });
1007
+ }
1008
+ //#endregion
1009
+ export { ProductionTeamPolicyEditor as t };