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
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bazilion",
3
- "version": "0.7.0",
4
- "description": "Multi-agent runtime CLI — spawn LLM agents, manage profiles/groups/skills, and run the local daemon.",
3
+ "version": "0.9.0",
4
+ "description": "Multi-agent runtime CLI — spawn LLM agents, manage profiles/teams/skills, and run the local daemon.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -40,9 +40,9 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@earendil-works/pi-agent-core": "^0.79.10",
44
- "@earendil-works/pi-ai": "^0.79.10",
45
- "@earendil-works/pi-coding-agent": "^0.79.10",
43
+ "@earendil-works/pi-agent-core": "^0.80.6",
44
+ "@earendil-works/pi-ai": "^0.80.6",
45
+ "@earendil-works/pi-coding-agent": "^0.80.6",
46
46
  "@hono/node-server": "^2.0.6",
47
47
  "@mozilla/readability": "^0.6.0",
48
48
  "@tanstack/react-router": "1.170.16",
@@ -65,8 +65,8 @@
65
65
  "devDependencies": {
66
66
  "@types/adm-zip": "^0.5.8",
67
67
  "@types/qrcode-terminal": "^0.12.2",
68
- "@bazilion/api-types": "0.7.0",
69
- "@bazilion/client": "0.7.0"
68
+ "@bazilion/api-types": "0.9.0",
69
+ "@bazilion/client": "0.9.0"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "pnpm --filter @bazilion/web build && tsup"
@@ -1,38 +0,0 @@
1
- -- Profile groups — preconfigured team templates. A ProfileGroup captures
2
- -- the recipe for a team (ordered slots, each pointing at a Profile with
3
- -- optional per-slot overrides) so an operator can replay it with a single
4
- -- spawn call instead of clicking through agent-create N times per project.
5
- --
6
- -- Strictly additive: the single-profile `POST /api/agents` spawn path is
7
- -- untouched. Profile groups bundle existing primitives (profiles, groups,
8
- -- agents), they don't replace them.
9
- --
10
- -- Spawn semantics live in apps/daemon/src/core/profile-group/spawn.ts.
11
-
12
- CREATE TABLE profile_groups (
13
- id TEXT PRIMARY KEY, -- slug, e.g. "platform-team"
14
- name TEXT NOT NULL, -- display name
15
- user_md TEXT, -- optional starter USER.md; seeded only into a freshly-created target group (pre-existing groups are left alone — see Decision #5)
16
- created_at INTEGER NOT NULL,
17
- updated_at INTEGER NOT NULL
18
- );
19
-
20
- -- Member ordering uses an explicit `position` column rather than insertion
21
- -- order so the spawn loop is deterministic and rollback can identify which
22
- -- members succeeded. PK includes position so the same template can have
23
- -- multiple members pointing at the same profile (e.g. "two reviewers" —
24
- -- duplicate agent_name values are intentionally accepted; the spawn op
25
- -- auto-suffixes collisions with `-2`, `-3`, ... at spawn time).
26
- --
27
- -- `ON DELETE RESTRICT` on profile_id prevents deleting a profile that a
28
- -- profile-group member still references; the existing single-profile delete
29
- -- keeps working unchanged because it never had a referrer before.
30
- CREATE TABLE profile_group_members (
31
- profile_group_id TEXT NOT NULL REFERENCES profile_groups(id) ON DELETE CASCADE,
32
- position INTEGER NOT NULL,
33
- profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE RESTRICT,
34
- agent_name TEXT NOT NULL, -- e.g. "planner", "reviewer"
35
- model_override TEXT, -- nullable; falls back to profile.default_model
36
- reasoning_level TEXT, -- nullable; falls back to spawn default 'medium'
37
- PRIMARY KEY (profile_group_id, position)
38
- );
@@ -1,40 +0,0 @@
1
- -- Telegram integration columns. Step 1 of the docs/telegram.md plan adds the
2
- -- schema only; the bot singleton, polling loop, and routing helpers land in
3
- -- subsequent steps. None of these columns are populated yet — they sit empty
4
- -- until the live bot in Step 2 starts persisting topic ids on first traffic.
5
- --
6
- -- agents.telegram_topic_id — forum-topic message_thread_id; one topic per
7
- -- agent. Partial unique index below allows
8
- -- multiple NULLs (unbound agents) but enforces
9
- -- one-to-one once an id is written.
10
- -- agents.telegram_topic_name_locked — sticky bit set when a human renames the
11
- -- topic in Telegram; once set, bazilion stops
12
- -- propagating agent/group renames to that topic.
13
- -- agents.telegram_icon_emoji — per-agent override of the profile-derived
14
- -- custom-emoji sticker id. Lookup at topic
15
- -- creation: agents.* → profiles.* → null.
16
- -- Survives topic delete + recreate, unlike
17
- -- a customization that only lived in Telegram.
18
- -- groups.telegram_icon_color — Telegram's 6-color enum slot allocated to
19
- -- this group on first-traffic. Red is reserved
20
- -- for the service chat, so groups round-robin
21
- -- over the remaining 5.
22
- -- profiles.telegram_icon_emoji — curated default sticker id from
23
- -- getForumTopicIconStickers, per built-in
24
- -- profile. Seeded for built-ins, NULL for
25
- -- custom profiles (which render color-only).
26
-
27
- ALTER TABLE agents ADD COLUMN telegram_topic_id INTEGER;
28
- ALTER TABLE agents ADD COLUMN telegram_topic_name_locked INTEGER NOT NULL DEFAULT 0;
29
- ALTER TABLE agents ADD COLUMN telegram_icon_emoji TEXT;
30
-
31
- ALTER TABLE groups ADD COLUMN telegram_icon_color INTEGER;
32
-
33
- ALTER TABLE profiles ADD COLUMN telegram_icon_emoji TEXT;
34
-
35
- -- Partial unique index: enforces one-to-one mapping between agents and topic
36
- -- ids without blocking many unbound agents (SQLite treats NULLs as distinct
37
- -- in unique indexes, but being explicit avoids surprise if that ever changes).
38
- CREATE UNIQUE INDEX IF NOT EXISTS idx_agents_telegram_topic_id
39
- ON agents(telegram_topic_id)
40
- WHERE telegram_topic_id IS NOT NULL;
@@ -1,17 +0,0 @@
1
- -- Per-agent Telegram outbound-mirror verbosity.
2
- --
3
- -- 'minimal' (default): mirror only the assistant's final message text to
4
- -- the agent's bound forum topic. Cleanest conversation
5
- -- feel; what most operators want.
6
- -- 'verbose': also mirror short tool-call summary lines so the
7
- -- topic shows the agent's reasoning steps. Helpful
8
- -- while iterating on a misbehaving agent; noisy in
9
- -- steady state.
10
- --
11
- -- The column has no effect on agents without a bound topic. Step 6 picks
12
- -- the value up when materializing each ChatFrame; Step 7's CLI + web UI
13
- -- surfaces let operators flip it per-agent.
14
-
15
- ALTER TABLE agents
16
- ADD COLUMN telegram_mirror_mode TEXT NOT NULL DEFAULT 'minimal'
17
- CHECK (telegram_mirror_mode IN ('minimal','verbose'));
@@ -1,15 +0,0 @@
1
- -- Per-group Telegram forum-topic name template.
2
- --
3
- -- NULL (default): bazilion composes topic names the built-in way — bare
4
- -- agent.name for the `default` group, "<group.slug> › <agent.name>" for every
5
- -- other group (see lib/telegram/naming.ts:topicNameFor).
6
- -- Non-NULL: an explicit template rendered with the tokens {agent.name},
7
- -- {group.name}, {group.slug}. Must contain {agent.name} so each agent in the
8
- -- group still gets a distinct topic title. Validated on write
9
- -- (lib/telegram/naming.ts:validateTopicNameFormat).
10
- --
11
- -- Changing the template re-renders every bound, non-locked topic in the group
12
- -- via editForumTopic (lib/telegram/topic-rename.ts:syncGroupTopicNames). Topics
13
- -- a human has renamed (telegram_topic_name_locked = 1) are left untouched.
14
-
15
- ALTER TABLE groups ADD COLUMN telegram_topic_name_format TEXT;
@@ -1,18 +0,0 @@
1
- -- Per-user Telegram allowlist (Phase 7).
2
- --
3
- -- Bootstrap model: TOFU (trust-on-first-use). While this table is empty the
4
- -- bot is open; the first user to message it is auto-added as 'owner' and
5
- -- enforcement begins immediately after. Scope: FLAT — an allowlisted user can
6
- -- do everything (commands + agent chat); anyone not on the list is ignored.
7
- --
8
- -- role: 'owner' can manage the allowlist (/allow, /deny) and cannot be removed;
9
- -- 'member' can use the bot but not manage who else can. At least one owner must
10
- -- always remain (enforced in the repo + routes).
11
-
12
- CREATE TABLE IF NOT EXISTS telegram_allowed_users (
13
- user_id INTEGER PRIMARY KEY,
14
- username TEXT,
15
- label TEXT,
16
- role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner','member')),
17
- added_at INTEGER NOT NULL
18
- );
@@ -1,30 +0,0 @@
1
- -- MCP (Model Context Protocol) servers.
2
- --
3
- -- Each row is one configured server the daemon connects to as an MCP client.
4
- -- Tools discovered on it (`tools/list`) are namespaced `mcp__<name>__<tool>`
5
- -- and injected into agent turns. v0.4.0 scopes servers globally — every agent
6
- -- sees the tools of every enabled server.
7
- --
8
- -- Transports:
9
- -- stdio — local subprocess (`command` + JSON `args`); inherits the daemon's
10
- -- merged secrets env, so a server needing e.g. GITHUB_TOKEN picks it
11
- -- up from the normal secrets table.
12
- -- http — Streamable-HTTP endpoint at `url`.
13
- -- sse — SSE endpoint at `url`.
14
- --
15
- -- Bearer auth for http/sse is NOT stored here: the token lives in the encrypted
16
- -- `secrets` table under key `MCP_TOKEN_<id>`; `has_auth` records whether one is
17
- -- set so the UI/API can show it without decrypting.
18
-
19
- CREATE TABLE IF NOT EXISTS mcp_servers (
20
- id TEXT PRIMARY KEY,
21
- name TEXT NOT NULL UNIQUE,
22
- transport TEXT NOT NULL CHECK (transport IN ('stdio','http','sse')),
23
- command TEXT,
24
- args TEXT NOT NULL DEFAULT '[]',
25
- url TEXT,
26
- has_auth INTEGER NOT NULL DEFAULT 0,
27
- enabled INTEGER NOT NULL DEFAULT 1,
28
- created_at INTEGER NOT NULL,
29
- updated_at INTEGER NOT NULL
30
- );
@@ -1,39 +0,0 @@
1
- -- Backfill USER.md content into pre-existing groups.
2
- --
3
- -- Before this BAZ, groups.user_md was born as '' and stayed empty unless an
4
- -- operator hand-edited it, so the "About the User" section of every system
5
- -- prompt was generic boilerplate. New groups now seed DEFAULT_USER_MD at
6
- -- insert time (core/repos/groups.ts); this one-shot UPDATE gives the same
7
- -- starter content to groups that already exist with an empty user_md.
8
- --
9
- -- The literal below MUST be kept in sync with DEFAULT_USER_MD in
10
- -- core/profile/templates.ts — SQL can't import it. Two copies, one source of
11
- -- truth; flag in review if they drift.
12
- --
13
- -- Tradeoff: the column can't distinguish "never set"
14
- -- from "explicitly cleared", so an operator who deliberately set user_md to ''
15
- -- sees it replaced. bazilion is alpha; the upside (every install gets the new
16
- -- template) beats the downside (a power-user re-clears one file). Idempotent:
17
- -- the WHERE clause matches nothing once every row is non-empty.
18
-
19
- UPDATE groups SET user_md = '# USER.md — About Your Human
20
-
21
- _Learn about the person you''re helping. Update via `user_md_write` as you go
22
- (read with `user_md_get` first for the etag)._
23
-
24
- - **Name:**
25
- - **What to call them:**
26
- - **Pronouns:** _(optional)_
27
- - **Timezone:**
28
- - **Notes:**
29
-
30
- ## Context
31
-
32
- _(What do they care about? What projects are they working on? What''s their
33
- working style? Build this picture over time, a little each session.)_
34
-
35
- ---
36
-
37
- The more you know, the better you can help. But remember — you''re learning
38
- about a person, not building a dossier. Respect the difference.
39
- ' WHERE user_md = '';
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{r as t}from"./wire-constants-BkT5-597.js";import{t as n}from"./Button-ByiV6fpd.js";var r=e();function i({members:e,onChange:i,profiles:a,modelGroups:o,emptyHint:s=`No members yet. Add one to define your first team member.`}){function c(t,n){i(e.map((e,r)=>r===t?{...e,...n}:e))}function l(t,n){let r=t+n;if(r<0||r>=e.length)return;let a=[...e],o=a[t],s=a[r];!o||!s||(a[t]=s,a[r]=o,i(a))}function u(t){i(e.filter((e,n)=>n!==t))}function d(){let t=a[0];t&&i([...e,{profileId:t.id,agentName:`agent`,modelOverride:null,reasoningLevel:null}])}return a.length===0?(0,r.jsxs)(`p`,{className:`muted`,children:[`Create a profile first under `,(0,r.jsx)(`a`,{href:`/profiles`,children:`/profiles`}),` — members reference existing profiles.`]}):(0,r.jsxs)(r.Fragment,{children:[e.length===0?(0,r.jsx)(`p`,{className:`muted`,children:s}):(0,r.jsxs)(`table`,{children:[(0,r.jsx)(`thead`,{children:(0,r.jsxs)(`tr`,{children:[(0,r.jsx)(`th`,{children:`#`}),(0,r.jsx)(`th`,{children:`profile`}),(0,r.jsx)(`th`,{children:`agent name`}),(0,r.jsx)(`th`,{children:`model override`}),(0,r.jsx)(`th`,{children:`reasoning`}),(0,r.jsx)(`th`,{})]})}),(0,r.jsx)(`tbody`,{children:e.map((i,s)=>(0,r.jsxs)(`tr`,{children:[(0,r.jsx)(`td`,{children:s}),(0,r.jsx)(`td`,{children:(0,r.jsx)(`select`,{value:i.profileId,onChange:e=>c(s,{profileId:e.target.value}),children:a.map(e=>(0,r.jsx)(`option`,{value:e.id,children:e.id},e.id))})}),(0,r.jsx)(`td`,{children:(0,r.jsx)(`input`,{value:i.agentName,onChange:e=>c(s,{agentName:e.target.value})})}),(0,r.jsx)(`td`,{children:(0,r.jsxs)(`select`,{value:i.modelOverride??``,onChange:e=>c(s,{modelOverride:e.target.value===``?null:e.target.value}),children:[(0,r.jsx)(`option`,{value:``,children:`(use profile default)`}),o.map(e=>(0,r.jsx)(`optgroup`,{label:e.provider,children:e.models.map(t=>(0,r.jsx)(`option`,{value:`${e.provider}:${t}`,children:`${e.provider}:${t}`},t))},e.provider))]})}),(0,r.jsx)(`td`,{children:(0,r.jsxs)(`select`,{value:i.reasoningLevel??``,onChange:e=>c(s,{reasoningLevel:e.target.value===``?null:e.target.value}),children:[(0,r.jsx)(`option`,{value:``,children:`(default: medium)`}),t.map(e=>(0,r.jsx)(`option`,{value:e,children:e},e))]})}),(0,r.jsxs)(`td`,{className:`flex gap-1`,children:[(0,r.jsx)(n,{variant:`ghost`,onClick:()=>l(s,-1),disabled:s===0,title:`move up`,children:`↑`}),(0,r.jsx)(n,{variant:`ghost`,onClick:()=>l(s,1),disabled:s===e.length-1,title:`move down`,children:`↓`}),(0,r.jsx)(n,{variant:`danger`,onClick:()=>u(s),title:`remove member`,children:`✕`})]})]},s))})]}),(0,r.jsx)(`div`,{className:`mt-3`,children:(0,r.jsx)(n,{variant:`ghost`,onClick:d,children:`+ add member`})})]})}export{i as t};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n}from"./preload-helper-CvnapA2_.js";import{t as r}from"./Button-ByiV6fpd.js";var i=e(n(),1),a=t();function o({profileGroup:e,groups:t,onClose:n,onSpawned:o}){let[s,c]=(0,i.useState)(``),[l,u]=(0,i.useState)(``),[d,f]=(0,i.useState)(null),[p,m]=(0,i.useState)(!1);async function h(){if(f(null),!s.trim()){f(`target group slug is required`);return}m(!0);try{let t={groupSlug:s.trim()};l&&(t.userMd=l);let n=await fetch(`/api/profile-groups/${e.id}/spawn`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}let r=await n.json();r.orphanAgentIds&&r.orphanAgentIds.length>0&&alert(`Spawn completed with warnings: ${r.orphanAgentIds.length} orphan agent dir(s) left on disk.`),o(r.groupSlug)}catch(e){f(e.message)}finally{m(!1)}}return(0,a.jsx)(`div`,{role:`dialog`,"aria-modal":`true`,className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50`,onClick:n,onKeyDown:e=>{e.key===`Escape`&&n()},children:(0,a.jsxs)(`div`,{className:`card w-full max-w-lg`,onClick:e=>e.stopPropagation(),onKeyDown:e=>e.stopPropagation(),role:`document`,children:[(0,a.jsxs)(`h3`,{children:[`spawn team — `,e.name]}),d&&(0,a.jsx)(`div`,{className:`err`,children:d}),(0,a.jsxs)(`p`,{className:`muted`,children:[`Spawns `,e.memberCount,` agent`,e.memberCount===1?``:`s`,` into the target group. If the group doesn't exist, it'll be created on the fly. Failures roll back the whole spawn.`]}),(0,a.jsxs)(`label`,{children:[`target group slug`,(0,a.jsx)(`input`,{value:s,onChange:e=>c(e.target.value),list:`existing-groups`,required:!0}),(0,a.jsx)(`datalist`,{id:`existing-groups`,children:t.map(e=>(0,a.jsx)(`option`,{value:e.id,children:e.name},e.id))})]}),(0,a.jsxs)(`label`,{children:[`override USER.md (optional — only takes effect on a freshly-created target group)`,(0,a.jsx)(`textarea`,{rows:3,value:l,onChange:e=>u(e.target.value),className:`font-mono text-[0.88em] leading-[1.55]`})]}),(0,a.jsxs)(`div`,{className:`mt-4 flex gap-2 justify-end`,children:[(0,a.jsx)(r,{variant:`ghost`,onClick:n,children:`cancel`}),(0,a.jsx)(r,{variant:`primary`,onClick:h,disabled:p,children:p?`spawning…`:`spawn team`})]})]})})}export{o as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{a as t}from"./preload-helper-CvnapA2_.js";import{S as n}from"./index-iayCEuU2.js";var r=e();function i(){let e=n({select:e=>e.location.pathname});return(0,r.jsx)(`nav`,{role:`tablist`,className:`-mb-px mb-5 flex gap-1 border-b border-frost`,children:[{to:`/profiles`,label:`profiles`,match:e=>e.startsWith(`/profiles`)},{to:`/profile-groups`,label:`profile groups`,match:e=>e.startsWith(`/profile-groups`)}].map(n=>{let i=n.match(e);return(0,r.jsx)(t,{to:n.to,role:`tab`,"aria-selected":i,className:`unstyled cursor-pointer border-b-2 bg-transparent px-4 py-2 text-[0.9em] font-medium transition-colors ${i?`border-sapphire text-sapphire`:`border-transparent text-mocha hover:text-sapphire`}`,children:n.label},n.to)})})}export{i as t};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{a as i}from"./index-iayCEuU2.js";import{t as a}from"./AgentTabs-DioGqUVR.js";import{t as o}from"./AgentAvatar-JYijLvZ2.js";import{t as s}from"./ChatPane-DzEgOEqS.js";import{r as c}from"./wire-constants-BkT5-597.js";var l=e(n(),1),u=t();function d({value:e,className:t,ariaLabel:n=`Copy to clipboard`,title:r=`Copy to clipboard`}){let[i,a]=(0,l.useState)(!1);async function o(){if(!e)return;let t=!1;try{navigator.clipboard?.writeText&&(await navigator.clipboard.writeText(e),t=!0)}catch{}if(!t){let n=document.createElement(`textarea`);n.value=e,n.setAttribute(`readonly`,``),n.style.position=`fixed`,n.style.opacity=`0`,document.body.appendChild(n),n.select();try{t=document.execCommand(`copy`)}catch{}n.remove()}t&&(a(!0),setTimeout(()=>a(!1),1e3))}return(0,u.jsx)(`button`,{type:`button`,onClick:o,title:r,"aria-label":n,className:`inline-flex h-[1.3rem] w-[1.6rem] items-center justify-center rounded-sm border border-transparent text-mocha-light transition-colors hover:border-frost hover:bg-snow hover:text-mocha ${i?`border-[#bcd9bc] bg-[#eef7ee] text-[#3b7a3b] hover:border-[#bcd9bc] hover:bg-[#eef7ee] hover:text-[#3b7a3b]`:``} ${t??``}`,children:i?`✓`:`⧉`})}function f(){let{resolved:e,initialMessages:t,sessionHead:n,groups:c,skills:l,modelGroups:f,telegramConfigured:y}=i.useLoaderData(),b=r();async function x(){confirm(`archive "${e.agent.name}"? (reversible)`)&&(await fetch(`/api/agents/${e.agent.id}/archive`,{method:`POST`}),await b.invalidate())}async function S(){await fetch(`/api/agents/${e.agent.id}/unarchive`,{method:`POST`}),await b.invalidate()}async function C(){let t=`Permanently delete agent "${e.agent.name}"?\n\nThis removes the DB rows (messages, triggers, skill attachments) AND the agent's on-disk directory (memory, templates, state, sessions). This cannot be undone.`;if(!confirm(t))return;let n=await fetch(`/api/agents/${e.agent.id}`,{method:`DELETE`});n.ok||n.status===204?window.location.assign(`/agents`):alert(`failed: ${n.statusText}`)}return(0,u.jsxs)(`div`,{children:[(0,u.jsxs)(`header`,{className:`mb-8`,children:[(0,u.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,u.jsx)(o,{identity:e.agent.identity,size:44}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`h1`,{className:`mb-0`,children:e.agent.name}),(e.agent.identity?.creature||e.agent.identity?.vibe)&&(0,u.jsx)(`p`,{className:`muted mt-0.5 text-sm`,children:[e.agent.identity?.creature,e.agent.identity?.vibe].filter(Boolean).join(` · `)})]})]}),(0,u.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-x-5 gap-y-2`,children:[(0,u.jsxs)(m,{children:[(0,u.jsx)(`span`,{className:`px-1.5 font-mono text-[0.95em] text-mocha select-all`,children:e.agent.id}),(0,u.jsx)(d,{value:e.agent.id,ariaLabel:`Copy agent UUID`,title:`Copy UUID to clipboard`})]}),(0,u.jsxs)(m,{children:[`status: `,(0,u.jsx)(`span`,{className:`ml-1`,children:e.agent.status})]}),(0,u.jsxs)(m,{children:[`profile: `,(0,u.jsx)(`code`,{className:`ml-1 bg-transparent px-0`,children:e.profile.id})]}),(0,u.jsxs)(m,{children:[`group:`,` `,(0,u.jsx)(`a`,{href:`/groups/${encodeURIComponent(e.group.id)}`,className:`ml-1 bg-transparent px-0 font-mono underline`,children:e.group.id}),` `,`·`,` `,(0,u.jsx)(`a`,{href:`/groups/${encodeURIComponent(e.group.id)}/memory`,className:`ml-0.5 underline`,children:`shared memory →`})]}),(0,u.jsxs)(m,{children:[`model: `,(0,u.jsx)(`code`,{className:`ml-1 bg-transparent px-0`,children:e.model})]}),(0,u.jsxs)(m,{children:[`reasoning:`,` `,(0,u.jsx)(`code`,{className:`ml-1 bg-transparent px-0`,children:e.reasoningLevel})]})]}),(0,u.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2`,children:[e.agent.status===`archived`?(0,u.jsx)(`button`,{type:`button`,onClick:S,className:`ghost-btn`,children:`unarchive`}):(0,u.jsx)(`button`,{type:`button`,onClick:x,className:`ghost-btn`,children:`archive`}),(0,u.jsx)(`button`,{type:`button`,onClick:C,className:`ghost-btn border-[rgba(196,135,138,0.4)] text-[#9B3D3D] hover:bg-[rgba(196,135,138,0.08)]`,children:`delete permanently`})]}),(0,u.jsx)(h,{agentId:e.agent.id,currentModelOverride:e.agent.modelOverride??null,profileDefaultModel:e.profile.defaultModel,currentReasoning:e.reasoningLevel,modelGroups:f})]}),e.agent.status===`archived`&&(0,u.jsxs)(`div`,{className:`mb-4 rounded-md border border-frost bg-fawn/35 px-4 py-2 text-[0.9em] text-chocolate`,children:[(0,u.jsx)(`strong`,{className:`text-[#7a4e2a]`,children:`This agent is archived.`}),` It's hidden from the default agent list; use `,(0,u.jsx)(`em`,{children:`unarchive`}),` above to bring it back, or`,` `,(0,u.jsx)(`em`,{children:`delete permanently`}),` to remove its data entirely.`]}),(0,u.jsx)(a,{agentId:e.agent.id,active:`chat`,archived:e.agent.status===`archived`}),(0,u.jsx)(p,{children:`Chat`}),(0,u.jsx)(`div`,{className:`h-[70vh]`,children:(0,u.jsx)(s,{agentId:e.agent.id,agentName:e.agent.name,initialMessages:t,initialSessionHead:n})}),(0,u.jsx)(`p`,{className:`mt-2 text-[0.82em] text-mocha-light`,children:`chat history persists in bazilion across navigation and restarts.`}),(0,u.jsxs)(`section`,{className:`mt-10`,children:[(0,u.jsx)(p,{children:`Group`}),(0,u.jsxs)(`p`,{className:`text-[0.9em] text-mocha-light`,children:[`Current group: `,(0,u.jsx)(`code`,{children:e.group.id}),` (`,e.group.name,`) —`,` `,(0,u.jsx)(`code`,{children:e.group.path}),`.`,` `,(0,u.jsx)(`a`,{href:`/groups/${e.group.id}`,children:`view / edit USER.md`})]}),(0,u.jsx)(g,{agentId:e.agent.id,currentGroupId:e.group.id,groups:c})]}),(0,u.jsxs)(`section`,{className:`mt-10`,children:[(0,u.jsx)(p,{children:`Skills`}),(0,u.jsx)(_,{agentId:e.agent.id,attached:new Set(e.skills),all:l})]}),y&&(0,u.jsxs)(`section`,{className:`mt-10`,children:[(0,u.jsx)(p,{children:`Telegram`}),(0,u.jsx)(v,{agent:e.agent})]})]})}function p({children:e}){return(0,u.jsx)(`h3`,{className:`mb-3 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light`,children:e})}function m({children:e}){return(0,u.jsx)(`span`,{className:`inline-flex items-center gap-1 rounded-full border border-frost bg-ivory px-3 py-0.5 text-[0.84em] text-mocha-light`,children:e})}function h({agentId:e,currentModelOverride:t,profileDefaultModel:n,currentReasoning:i,modelGroups:a}){let o=r(),[s,d]=(0,l.useState)(t??``),[f,p]=(0,l.useState)(i),[m,h]=(0,l.useState)(!1),[g,_]=(0,l.useState)(!1),[v,y]=(0,l.useState)(null),b=t!==null&&a.some(e=>e.models.some(n=>`${e.provider}:${n}`===t));async function x(t){t.preventDefault(),h(!0),y(null);try{let t=await fetch(`/api/agents/${encodeURIComponent(e)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({modelOverride:s===``?null:s,reasoningLevel:f})});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}_(!0),setTimeout(()=>_(!1),1500),await o.invalidate()}catch(e){y(e.message)}finally{h(!1)}}return(0,u.jsxs)(`details`,{className:`mt-3 text-[0.9em]`,children:[(0,u.jsx)(`summary`,{className:`cursor-pointer text-mocha-light`,children:`settings`}),(0,u.jsxs)(`form`,{onSubmit:x,className:`mt-2 flex flex-wrap items-end gap-3 border-t border-dashed border-frost py-3`,children:[(0,u.jsxs)(`label`,{className:`flex flex-col gap-1 text-[0.85em] text-mocha-light`,children:[`model override`,(0,u.jsxs)(`select`,{name:`modelOverride`,value:s,onChange:e=>d(e.target.value),className:`min-w-[16rem] rounded-sm border border-frost bg-snow px-2 py-1.5`,children:[(0,u.jsxs)(`option`,{value:``,children:[`inherit from profile (`,n,`)`]}),t!==null&&!b&&(0,u.jsxs)(`option`,{value:t,children:[t,` (not in curated list)`]}),a.map(e=>(0,u.jsx)(`optgroup`,{label:e.provider,children:e.models.map(t=>{let n=`${e.provider}:${t}`;return(0,u.jsx)(`option`,{value:n,children:n},n)})},e.provider))]})]}),(0,u.jsxs)(`label`,{className:`flex flex-col gap-1 text-[0.85em] text-mocha-light`,children:[`reasoning level`,(0,u.jsx)(`select`,{name:`reasoningLevel`,value:f,onChange:e=>p(e.target.value),className:`min-w-[16rem] rounded-sm border border-frost bg-snow px-2 py-1.5`,children:c.map(e=>(0,u.jsx)(`option`,{value:e,children:e},e))})]}),(0,u.jsx)(`button`,{type:`submit`,disabled:m,children:m?`saving…`:`save`}),g&&(0,u.jsx)(`span`,{className:`text-[0.85em] text-[#3b7a3b]`,children:`saved ✓`}),v&&(0,u.jsx)(`span`,{className:`text-[0.85em] text-[#9B3D3D]`,children:v})]})]})}function g({agentId:e,currentGroupId:t,groups:n}){let i=r(),[a,o]=(0,l.useState)(t),[s,c]=(0,l.useState)(!1),[d,f]=(0,l.useState)(null);async function p(n){if(n.preventDefault(),a!==t){c(!0),f(null);try{let t=await fetch(`/api/agents/${encodeURIComponent(e)}/group`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({groupId:a})});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}await i.invalidate()}catch(e){f(e.message)}finally{c(!1)}}}return(0,u.jsxs)(`form`,{onSubmit:p,className:`mt-2 flex flex-wrap items-end gap-2`,children:[(0,u.jsxs)(`label`,{className:`flex flex-col gap-1 text-[0.85em] text-mocha-light`,children:[`move to:`,(0,u.jsx)(`select`,{value:a,onChange:e=>o(e.target.value),className:`min-w-[18rem] rounded-sm border border-frost bg-snow px-2 py-1.5`,children:n.map(e=>(0,u.jsxs)(`option`,{value:e.id,children:[e.id,` — `,e.path]},e.id))})]}),(0,u.jsx)(`button`,{type:`submit`,disabled:s||a===t,children:s?`moving…`:`move`}),d&&(0,u.jsx)(`span`,{className:`text-[0.85em] text-[#9B3D3D]`,children:d})]})}function _({agentId:e,attached:t,all:n}){let i=r(),[a,o]=(0,l.useState)(null),[s,c]=(0,l.useState)(null);async function d(t){o(t),c(null);try{let n=await fetch(`/api/agents/${encodeURIComponent(e)}/skills`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({skill:t})});if(!n.ok){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}await i.invalidate()}catch(e){c(e.message)}finally{o(null)}}async function f(t){o(t),c(null);try{let n=await fetch(`/api/agents/${encodeURIComponent(e)}/skills/${encodeURIComponent(t)}`,{method:`DELETE`});if(!n.ok&&n.status!==204){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}await i.invalidate()}catch(e){c(e.message)}finally{o(null)}}return n.length===0?(0,u.jsx)(`p`,{className:`text-[0.9em] text-mocha-light`,children:`no skills installed`}):(0,u.jsxs)(u.Fragment,{children:[s&&(0,u.jsx)(`p`,{className:`mb-2 text-[0.85em] text-[#9B3D3D]`,children:s}),(0,u.jsxs)(`table`,{children:[(0,u.jsx)(`thead`,{children:(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`th`,{children:`name`}),(0,u.jsx)(`th`,{children:`description`}),(0,u.jsx)(`th`,{})]})}),(0,u.jsx)(`tbody`,{children:n.map(e=>{let n=t.has(e.name),r=a===e.name;return(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`td`,{children:(0,u.jsx)(`code`,{children:e.name})}),(0,u.jsx)(`td`,{children:e.description||(0,u.jsx)(`span`,{className:`text-mocha-light`,children:`—`})}),(0,u.jsx)(`td`,{children:n?(0,u.jsx)(`button`,{type:`button`,className:`ghost-btn`,disabled:r,onClick:()=>f(e.name),children:r?`…`:`detach`}):(0,u.jsx)(`button`,{type:`button`,className:`ghost-btn`,disabled:r,onClick:()=>d(e.name),children:r?`…`:`attach`})})]},e.name)})})]})]})}function v({agent:e}){let t=r(),[n,i]=(0,l.useState)(!1),[a,o]=(0,l.useState)(null),[s,c]=(0,l.useState)(e.telegramMirrorMode),[d,f]=(0,l.useState)(e.telegramIconEmoji??``),p=e.telegramTopicId!==null;async function m(){i(!0),o(null);try{let n=await fetch(`/api/agents/${encodeURIComponent(e.id)}/telegram/bind`,{method:`POST`});if(!n.ok){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}let r=await n.json();window.open(r.deepLink,`_blank`,`noopener`),await t.invalidate()}catch(e){o(e.message)}finally{i(!1)}}async function h(){if(confirm(`Unbind this agent from its Telegram topic? The topic stays in Telegram as an orphan.`)){i(!0),o(null);try{let n=await fetch(`/api/agents/${encodeURIComponent(e.id)}/telegram/binding`,{method:`DELETE`});if(!n.ok)throw Error(n.statusText);await t.invalidate()}catch(e){o(e.message)}finally{i(!1)}}}async function g(n){c(n);try{let r=await fetch(`/api/agents/${encodeURIComponent(e.id)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({telegramMirrorMode:n})});if(!r.ok)throw Error(r.statusText);await t.invalidate()}catch(t){c(e.telegramMirrorMode),o(t.message)}}async function _(){o(null);try{let n=await fetch(`/api/agents/${encodeURIComponent(e.id)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({telegramIconEmoji:d.trim()||null})});if(!n.ok)throw Error(n.statusText);await t.invalidate()}catch(e){o(e.message)}}return(0,u.jsxs)(`div`,{className:`text-[0.9em]`,children:[(0,u.jsx)(`div`,{className:`mb-3 flex items-center gap-3`,children:p?(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`span`,{className:`rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-800`,children:`bound`}),(0,u.jsxs)(`span`,{className:`font-mono text-mocha`,children:[`topic #`,e.telegramTopicId]}),(0,u.jsx)(`button`,{type:`button`,onClick:m,disabled:n,className:`ghost-btn`,title:`Open the topic in Telegram (works on desktop/Android; iOS shows the topic list)`,children:`open in Telegram`}),(0,u.jsx)(`button`,{type:`button`,onClick:h,disabled:n,className:`ghost-btn border-[rgba(196,135,138,0.4)] text-[#9B3D3D] hover:bg-[rgba(196,135,138,0.08)]`,children:`unbind`})]}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`span`,{className:`rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-800`,children:`unbound`}),(0,u.jsx)(`button`,{type:`button`,onClick:m,disabled:n,className:`ghost-btn`,title:`Create a Telegram topic for this agent`,children:n?`binding…`:`bind a topic`})]})}),(0,u.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,u.jsx)(`label`,{htmlFor:`mirror-mode`,className:`text-mocha-light`,children:`mirror mode:`}),(0,u.jsxs)(`select`,{id:`mirror-mode`,value:s,onChange:e=>void g(e.target.value),className:`rounded-md border bg-background px-2 py-1 font-mono text-sm`,disabled:n,children:[(0,u.jsx)(`option`,{value:`minimal`,children:`minimal — assistant messages only`}),(0,u.jsx)(`option`,{value:`verbose`,children:`verbose — also tool calls`})]})]}),(0,u.jsxs)(`div`,{className:`mt-2 flex items-center gap-2`,children:[(0,u.jsx)(`label`,{htmlFor:`topic-icon`,className:`text-mocha-light`,children:`topic icon:`}),(0,u.jsx)(`input`,{id:`topic-icon`,value:d,onChange:e=>f(e.target.value),placeholder:`(profile default)`,maxLength:8,className:`w-32 rounded-md border bg-background px-2 py-1 font-mono text-sm`,disabled:n}),(0,u.jsx)(`button`,{type:`button`,onClick:()=>void _(),disabled:n||d===(e.telegramIconEmoji??``),className:`ghost-btn`,children:`save icon`})]}),a&&(0,u.jsx)(`p`,{className:`mt-2 text-sm text-rose-700`,children:a}),(0,u.jsx)(`p`,{className:`mt-3 text-[0.85em] text-mocha-light`,children:`When bound, every assistant turn for this agent gets mirrored to the topic. Typing in the topic triggers a new turn. iOS Telegram clients have a known limitation that prevents inline link deep-links from opening directly into a topic — bound state is still functional; navigate via the topic list manually.`})]})}export{f as component};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{d as i}from"./index-iayCEuU2.js";var a=e(n()),o=t();function s(){let{loaded:e,modelGroups:t,skills:n}=i.useLoaderData(),[r,s]=(0,a.useState)(`basics`);return(0,o.jsxs)(`div`,{children:[(0,o.jsxs)(`header`,{className:`mb-1`,children:[(0,o.jsx)(`a`,{href:`/profiles`,className:`mb-1 inline-block text-[0.85em] text-mocha-light hover:text-sapphire`,children:`← profiles`}),(0,o.jsx)(`h1`,{children:e.profile.name}),(0,o.jsxs)(`div`,{className:`mt-1 flex flex-wrap items-center gap-2 text-[0.9em] text-mocha-light`,children:[(0,o.jsx)(`code`,{children:e.profile.id}),(0,o.jsx)(`span`,{children:`·`}),(0,o.jsxs)(`span`,{children:[`model: `,(0,o.jsx)(`code`,{children:e.profile.defaultModel})]})]})]}),(0,o.jsxs)(`p`,{className:`muted my-6`,children:[`These settings and files seed every agent spawned from this profile going forward.`,` `,(0,o.jsx)(`strong`,{children:`Existing agents keep their own copies`}),` — edits here don't propagate to already-spawned agents.`]}),(0,o.jsx)(c,{items:[{id:`basics`,label:`1. basics`},{id:`skills`,label:`2. skills`}],active:r,onChange:e=>s(e)}),r===`basics`&&(0,o.jsxs)(`div`,{children:[(0,o.jsx)(p,{profileId:e.profile.id,initialName:e.profile.name,currentModel:e.profile.defaultModel,modelGroups:t}),(0,o.jsx)(d,{profileId:e.profile.id,file:`SOUL.md`,initialContent:e.files.soul,rows:14}),(0,o.jsx)(d,{profileId:e.profile.id,file:`IDENTITY.md`,initialContent:e.files.identity,rows:10}),e.files.bootstrap===null?(0,o.jsxs)(`section`,{className:`file-card`,children:[(0,o.jsx)(`div`,{className:`file-head`,children:(0,o.jsx)(`h3`,{children:`BOOTSTRAP.md`})}),(0,o.jsx)(`p`,{className:`muted`,children:`This profile was created without a bootstrap prompt. Spawned agents won't see a first-run intro message.`})]}):(0,o.jsx)(d,{profileId:e.profile.id,file:`BOOTSTRAP.md`,initialContent:e.files.bootstrap,rows:10}),(0,o.jsx)(f,{profileId:e.profile.id,file:`AGENTS.md`,initialContent:e.files.agents,hint:`Peers and routing notes — who this agent can hand off to.`}),(0,o.jsx)(f,{profileId:e.profile.id,file:`TOOLS.md`,initialContent:e.files.tools,hint:`Tool playbook. Agent-specific usage notes that go beyond the generic tool descriptions.`}),(0,o.jsx)(f,{profileId:e.profile.id,file:`HEARTBEAT.md`,initialContent:e.files.heartbeat,hint:`Tasks the agent should check on scheduled wake-ups. Pair with a trigger whose message is the canned heartbeat prompt.`})]}),r===`skills`&&(0,o.jsx)(m,{profileId:e.profile.id,initialMode:e.profile.skillsMode,initialPicked:new Set(e.defaultSkills),skills:n})]})}function c({items:e,active:t,onChange:n}){return(0,o.jsx)(`nav`,{role:`tablist`,className:`-mb-px mb-5 flex gap-1 border-b border-frost`,children:e.map(e=>(0,o.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":t===e.id,onClick:()=>n(e.id),className:`unstyled cursor-pointer border-b-2 bg-transparent px-4 py-2 text-[0.9em] font-medium transition-colors ${t===e.id?`border-sapphire text-sapphire`:`border-transparent text-mocha hover:text-sapphire`}`,children:e.label},e.id))})}function l(e){return e===`saved`?`text-sapphire`:e===`error`?`text-[#9B3D3D]`:e===`dirty`?`text-mocha`:`text-mocha-light`}function u({title:e,status:t,children:n}){return(0,o.jsxs)(`section`,{className:`file-card mb-5 rounded-[16px] border border-frost bg-snow p-5 shadow-baziu-sm`,children:[(0,o.jsxs)(`div`,{className:`mb-2 flex items-baseline justify-between`,children:[(0,o.jsx)(`h3`,{className:`m-0 font-mono text-[0.95em] font-semibold normal-case tracking-normal text-chocolate`,children:e}),t&&(0,o.jsx)(`span`,{className:`text-[0.82em] ${l(t.kind)}`,children:t.message})]}),n]})}function d({profileId:e,file:t,initialContent:n,rows:r=10}){let[i,s]=(0,a.useState)(n),[c,l]=(0,a.useState)(n),[d,f]=(0,a.useState)({kind:`idle`,message:``}),p=c!==i&&d.kind!==`saving`&&d.kind!==`error`?{kind:`dirty`,message:`unsaved changes`}:d;async function m(){f({kind:`saving`,message:`saving…`});try{let n=await fetch(`/api/profiles/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({content:c})});if(!n.ok&&n.status!==204){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}s(c),f({kind:`saved`,message:`saved`})}catch(e){f({kind:`error`,message:`error: ${e.message}`})}}function h(){l(i),f({kind:`idle`,message:``})}return(0,o.jsxs)(u,{title:t,status:p,children:[(0,o.jsx)(`textarea`,{rows:r,value:c,onChange:e=>l(e.target.value),className:`font-mono text-[0.88em] leading-[1.55]`}),(0,o.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,o.jsx)(`button`,{type:`button`,className:`btn-primary`,onClick:m,disabled:d.kind===`saving`,children:`save`}),(0,o.jsx)(`button`,{type:`button`,className:`ghost-btn`,onClick:h,children:`revert`})]})]})}function f({profileId:e,file:t,initialContent:n,hint:i}){let s=r(),[c,l]=(0,a.useState)(!1),[f,p]=(0,a.useState)({kind:`idle`,message:``});async function m(){l(!0),p({kind:`saving`,message:`creating…`});try{let n=await fetch(`/api/profiles/${encodeURIComponent(e)}/files/${encodeURIComponent(t)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({content:``})});if(!n.ok&&n.status!==204){let e=await n.json().catch(()=>null);throw Error(e?.error??n.statusText)}await s.invalidate()}catch(e){p({kind:`error`,message:`error: ${e.message}`}),l(!1)}}return n===null?(0,o.jsxs)(u,{title:t,status:f,children:[(0,o.jsx)(`p`,{className:`muted my-1`,children:i}),(0,o.jsx)(`div`,{className:`mt-3 flex gap-2`,children:(0,o.jsx)(`button`,{type:`button`,className:`btn-primary`,onClick:m,disabled:c,children:c?`creating…`:`create empty`})})]}):(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`p`,{className:`muted -mb-3 ml-1 mt-2 text-[0.85em]`,children:i}),(0,o.jsx)(d,{profileId:e,file:t,initialContent:n,rows:10})]})}function p({profileId:e,initialName:t,currentModel:n,modelGroups:i}){let s=r(),[c,l]=(0,a.useState)(t),[d,f]=(0,a.useState)(n),[p,m]=(0,a.useState)({kind:`idle`,message:``}),h=!i.flatMap(e=>e.models.map(t=>`${e.provider}:${t}`)).includes(n);async function g(t){t.preventDefault(),m({kind:`saving`,message:`saving…`});try{let t=await fetch(`/api/profiles/${encodeURIComponent(e)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({name:c.trim(),defaultModel:d.trim()})});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}await s.invalidate(),m({kind:`saved`,message:`saved`})}catch(e){m({kind:`error`,message:`error: ${e.message}`})}}return(0,o.jsx)(u,{title:`settings`,status:p,children:(0,o.jsxs)(`form`,{onSubmit:g,children:[(0,o.jsxs)(`div`,{className:`flex gap-4`,children:[(0,o.jsxs)(`label`,{className:`flex-1`,children:[`name`,(0,o.jsx)(`input`,{value:c,onChange:e=>l(e.target.value)})]}),(0,o.jsxs)(`label`,{className:`flex-1`,children:[`default model`,i.length===0?(0,o.jsx)(`select`,{disabled:!0,children:(0,o.jsx)(`option`,{children:`(no models available — enable on /config)`})}):(0,o.jsxs)(`select`,{value:d,onChange:e=>f(e.target.value),children:[h&&(0,o.jsxs)(`option`,{value:n,children:[n,` (not in enabled list)`]}),i.map(e=>(0,o.jsx)(`optgroup`,{label:e.provider,children:e.models.map(t=>(0,o.jsx)(`option`,{value:`${e.provider}:${t}`,children:`${e.provider}:${t}`},t))},e.provider))]})]})]}),(0,o.jsx)(`div`,{className:`mt-3 flex gap-2`,children:(0,o.jsx)(`button`,{type:`submit`,disabled:p.kind===`saving`,children:`save settings`})})]})})}function m({profileId:e,initialMode:t,initialPicked:n,skills:i}){let s=r(),[c,l]=(0,a.useState)(t),[d,f]=(0,a.useState)(n),[p,m]=(0,a.useState)({kind:`idle`,message:``});function h(e){f(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}async function g(t){t.preventDefault(),m({kind:`saving`,message:`saving…`});try{let t=await fetch(`/api/profiles/${encodeURIComponent(e)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({skillsMode:c,defaultSkills:c===`selected`?Array.from(d):[]})});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}await s.invalidate(),m({kind:`saved`,message:`saved`})}catch(e){m({kind:`error`,message:`error: ${e.message}`})}}return(0,o.jsxs)(u,{title:`skills`,status:p,children:[(0,o.jsx)(`p`,{className:`muted my-2`,children:`Choose what agents spawned from this profile inherit. Existing agents aren't affected — they keep whatever skills they were spawned with.`}),(0,o.jsxs)(`form`,{onSubmit:g,children:[(0,o.jsxs)(`label`,{className:`my-2 flex cursor-pointer items-start gap-2`,children:[(0,o.jsx)(`input`,{type:`radio`,checked:c===`all`,onChange:()=>l(`all`)}),(0,o.jsxs)(`span`,{children:[(0,o.jsx)(`strong`,{children:`allow all skills`}),` — every skill on disk is attached at spawn.`]})]}),(0,o.jsxs)(`label`,{className:`my-2 flex cursor-pointer items-start gap-2`,children:[(0,o.jsx)(`input`,{type:`radio`,checked:c===`selected`,onChange:()=>l(`selected`)}),(0,o.jsxs)(`span`,{children:[(0,o.jsx)(`strong`,{children:`select skills`}),` — attach only the ones ticked below.`]})]}),(0,o.jsx)(`div`,{className:`mt-3 max-h-[22rem] overflow-y-auto rounded-md border border-frost p-3 ${c===`all`?`pointer-events-none opacity-50`:``}`,children:i.length===0?(0,o.jsxs)(`p`,{className:`muted`,children:[`No skills installed yet. Import some on `,(0,o.jsx)(`a`,{href:`/skills`,children:`/skills`}),`.`]}):i.map(e=>(0,o.jsxs)(`label`,{className:`my-1.5 flex cursor-pointer items-start gap-2`,children:[(0,o.jsx)(`input`,{type:`checkbox`,checked:d.has(e.name),onChange:()=>h(e.name)}),(0,o.jsxs)(`span`,{children:[(0,o.jsx)(`code`,{children:e.name}),e.description&&(0,o.jsxs)(`span`,{className:`text-[0.9em] text-mocha-light`,children:[` — `,e.description]})]})]},e.name))}),(0,o.jsx)(`div`,{className:`mt-3 flex gap-2`,children:(0,o.jsx)(`button`,{type:`submit`,disabled:p.kind===`saving`,children:`save skills`})})]})]})}export{s as component};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{o as i}from"./index-iayCEuU2.js";import{t as a}from"./Button-ByiV6fpd.js";var o=e(n()),s=t();function c(){let{group:e,members:t,profileGroups:n}=i.useLoaderData(),c=r(),[d,f]=(0,o.useState)(e.userMd),[p,m]=(0,o.useState)(!1),[h,g]=(0,o.useState)(null),[_,v]=(0,o.useState)(null);async function y(){m(!0),g(null);try{let t=await fetch(`/api/groups/${encodeURIComponent(e.id)}/user-md`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({userMd:d})});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??`${t.status} ${t.statusText}`)}v(Date.now()),await c.invalidate()}catch(e){g(e.message)}finally{m(!1)}}return(0,s.jsxs)(`main`,{className:`mx-auto max-w-3xl px-6 py-8`,children:[(0,s.jsxs)(`h1`,{className:`font-serif text-3xl text-foreground`,children:[e.name,` `,(0,s.jsxs)(`span`,{className:`text-muted-foreground text-base`,children:[`(`,e.id,`)`]})]}),(0,s.jsxs)(`p`,{className:`text-muted-foreground text-sm mb-6 mt-1`,children:[(0,s.jsx)(`code`,{className:`font-mono`,children:e.path}),` · `,t.length,` `,`member`,t.length===1?``:`s`,` ·`,` `,(0,s.jsx)(`a`,{href:`/groups/${encodeURIComponent(e.id)}/memory`,className:`text-primary underline`,children:`shared memory →`})]}),(0,s.jsxs)(`section`,{className:`rounded-lg border bg-card p-5 mb-6`,children:[(0,s.jsx)(`h3`,{className:`font-serif text-xl mb-1`,children:`USER.md`}),(0,s.jsx)(`p`,{className:`text-muted-foreground text-sm mb-3`,children:`Read-only context about the human, injected into every member agent's system prompt. 12 KB cap. Agents cannot edit this file — only you can.`}),(0,s.jsx)(`textarea`,{value:d,onChange:e=>f(e.target.value),rows:16,className:`w-full rounded-md border bg-background px-3 py-2 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`,placeholder:`What the agent should know about you in this group context…`}),(0,s.jsxs)(`div`,{className:`flex items-center gap-3 mt-3`,children:[(0,s.jsx)(a,{variant:`primary`,onClick:y,disabled:p||d===e.userMd,children:p?`saving…`:`save`}),(0,s.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[d.length,` / 12000 chars`]}),_&&(0,s.jsx)(`span`,{className:`text-xs text-emerald-700`,children:`✓ saved`}),h&&(0,s.jsx)(`span`,{className:`text-xs text-rose-700`,children:h})]})]}),(0,s.jsx)(l,{group:e,sampleAgent:t[0]?.name??`researcher`,onSaved:()=>c.invalidate()}),t.length===0&&(0,s.jsx)(u,{groupId:e.id,profileGroups:n,onSpawned:()=>c.invalidate()}),(0,s.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,s.jsx)(`h3`,{className:`font-serif text-xl mb-3`,children:`members`}),t.length===0?(0,s.jsx)(`p`,{className:`text-muted-foreground text-sm`,children:`No agents in this group yet.`}):(0,s.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,s.jsx)(`thead`,{className:`text-left text-muted-foreground border-b`,children:(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`th`,{className:`py-2`,children:`name`}),(0,s.jsx)(`th`,{children:`status`}),(0,s.jsx)(`th`,{children:`profile`}),(0,s.jsx)(`th`,{})]})}),(0,s.jsx)(`tbody`,{children:t.map(e=>(0,s.jsxs)(`tr`,{className:`border-b last:border-0`,children:[(0,s.jsx)(`td`,{className:`py-2`,children:(0,s.jsx)(`a`,{href:`/agents/${e.id}`,className:`text-primary underline`,children:e.name})}),(0,s.jsx)(`td`,{children:e.status}),(0,s.jsx)(`td`,{children:(0,s.jsx)(`code`,{className:`font-mono text-xs`,children:e.profileId})}),(0,s.jsx)(`td`,{children:(0,s.jsxs)(`code`,{className:`font-mono text-xs text-muted-foreground`,children:[e.id.slice(0,8),`…`]})})]},e.id))})]})]})]})}function l({group:e,sampleAgent:t,onSaved:n}){let[r,i]=(0,o.useState)(e.telegramTopicNameFormat??``),[c,l]=(0,o.useState)(!1),[u,d]=(0,o.useState)(null),[f,p]=(0,o.useState)(null),m=r.trim(),h=m?m.replaceAll(`{agent.name}`,t).replaceAll(`{group.name}`,e.name).replaceAll(`{group.slug}`,e.id):e.id==="default"?t:`${e.id} › ${t}`,g=(e.telegramTopicNameFormat??``)!==r;async function _(t){l(!0),d(null);try{let a=await fetch(`/api/groups/${encodeURIComponent(e.id)}/topic-format`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({format:t?null:r})});if(!a.ok){let e=await a.json().catch(()=>({}));throw Error(e.error??`${a.status} ${a.statusText}`)}t&&i(``),p(Date.now()),n()}catch(e){d(e.message)}finally{l(!1)}}return(0,s.jsxs)(`section`,{className:`rounded-lg border bg-card p-5 mb-6`,children:[(0,s.jsx)(`h3`,{className:`font-serif text-xl mb-1`,children:`Telegram topic names`}),(0,s.jsxs)(`p`,{className:`text-muted-foreground text-sm mb-3`,children:[`Template for this group's Telegram forum-topic titles. Leave empty for built-in naming. Tokens: `,(0,s.jsx)(`code`,{className:`font-mono`,children:`{agent.name}`}),` `,(0,s.jsx)(`code`,{className:`font-mono`,children:`{group.name}`}),` `,(0,s.jsx)(`code`,{className:`font-mono`,children:`{group.slug}`}),` — must include`,` `,(0,s.jsx)(`code`,{className:`font-mono`,children:`{agent.name}`}),`. Saving renames existing topics that you haven't manually renamed in Telegram.`]}),(0,s.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`{group.name} / {agent.name}`,className:`w-full rounded-md border bg-background px-3 py-2 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`}),(0,s.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-2`,children:[`preview: `,(0,s.jsx)(`span`,{className:`font-mono text-foreground`,children:h})]}),(0,s.jsxs)(`div`,{className:`flex items-center gap-3 mt-3`,children:[(0,s.jsx)(a,{variant:`primary`,onClick:()=>_(!1),disabled:c||!g||m.length===0,children:c?`saving…`:`save`}),e.telegramTopicNameFormat&&(0,s.jsx)(a,{variant:`ghost`,onClick:()=>_(!0),disabled:c,children:`clear`}),f&&(0,s.jsx)(`span`,{className:`text-xs text-emerald-700`,children:`✓ saved`}),u&&(0,s.jsx)(`span`,{className:`text-xs text-rose-700`,children:u})]})]})}function u({groupId:e,profileGroups:t,onSpawned:n}){let r=t.filter(e=>e.memberCount>0),[i,c]=(0,o.useState)(r[0]?.id??``),[l,u]=(0,o.useState)(!1),[d,f]=(0,o.useState)(null);async function p(){if(i){u(!0),f(null);try{let t=await fetch(`/api/profile-groups/${encodeURIComponent(i)}/spawn`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({groupSlug:e})});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??`${t.status} ${t.statusText}`)}let r=await t.json();r.orphanAgentIds&&r.orphanAgentIds.length>0&&alert(`Spawn completed with warnings: ${r.orphanAgentIds.length} orphan agent dir(s) left on disk.`),n()}catch(e){f(e.message)}finally{u(!1)}}}return(0,s.jsxs)(`section`,{className:`rounded-lg border bg-card p-5 mb-6`,children:[(0,s.jsx)(`h3`,{className:`font-serif text-xl mb-1`,children:`spawn a team into this group`}),(0,s.jsx)(`p`,{className:`text-muted-foreground text-sm mb-3`,children:`This group is empty. Pick a profile group template to spawn its entire roster into it in one transactional call.`}),r.length===0?(0,s.jsxs)(`p`,{className:`text-muted-foreground text-sm`,children:[`No profile groups with members yet. Build one on`,` `,(0,s.jsx)(`a`,{href:`/profile-groups`,className:`text-primary underline`,children:`/profile-groups`}),` `,`first.`]}):(0,s.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,s.jsx)(`select`,{value:i,onChange:e=>c(e.target.value),className:`rounded-md border bg-background px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-ring/30`,children:r.map(e=>(0,s.jsxs)(`option`,{value:e.id,children:[e.name,` (`,e.memberCount,` member`,e.memberCount===1?``:`s`,`)`]},e.id))}),(0,s.jsx)(a,{variant:`primary`,onClick:p,disabled:l||!i,children:l?`spawning…`:`spawn team`}),d&&(0,s.jsx)(`span`,{className:`text-xs text-rose-700`,children:d})]})]})}export{c as component};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{u as i}from"./index-iayCEuU2.js";import{t as a}from"./Button-ByiV6fpd.js";import{t as o}from"./MembersEditor-C6UpqDdV.js";var s=e(n()),c=t();function l(e){return{profileId:e.profileId,agentName:e.agentName,modelOverride:e.modelOverride,reasoningLevel:e.reasoningLevel}}function u(){let{detail:e,profiles:t,modelGroups:n}=i.useLoaderData(),a=r(),{group:o}=e;return(0,c.jsxs)(`div`,{children:[(0,c.jsx)(`h1`,{children:o.name}),(0,c.jsxs)(`p`,{className:`muted`,children:[(0,c.jsx)(`code`,{children:o.id}),` · `,e.members.length,` member`,e.members.length===1?``:`s`]}),(0,c.jsx)(d,{group:o,onSaved:()=>a.invalidate()}),(0,c.jsx)(f,{groupId:o.id,initialMembers:e.members.map(l),profiles:t,modelGroups:n,onSaved:()=>a.invalidate()})]})}function d({group:e,onSaved:t}){let[n,r]=(0,s.useState)(e.name),[i,o]=(0,s.useState)(e.userMd??``),[l,u]=(0,s.useState)(null),[d,f]=(0,s.useState)(!1);async function p(){u(null),f(!0);try{let r={name:n};r.userMd=i===``?null:i;let a=await fetch(`/api/profile-groups/${e.id}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify(r)});if(!a.ok){let e=await a.json().catch(()=>null);throw Error(e?.error??a.statusText)}t()}catch(e){u(e.message)}finally{f(!1)}}return(0,c.jsxs)(`div`,{className:`card`,children:[(0,c.jsx)(`h3`,{children:`basics`}),l&&(0,c.jsx)(`div`,{className:`err`,children:l}),(0,c.jsxs)(`label`,{children:[`name`,(0,c.jsx)(`input`,{value:n,onChange:e=>r(e.target.value)})]}),(0,c.jsxs)(`label`,{children:[`starter USER.md (seeded only into freshly-created target groups)`,(0,c.jsx)(`textarea`,{rows:6,value:i,onChange:e=>o(e.target.value),className:`font-mono text-[0.88em] leading-[1.55]`})]}),(0,c.jsx)(a,{variant:`primary`,onClick:p,disabled:d,children:d?`saving…`:`save basics`})]})}function f({groupId:e,initialMembers:t,profiles:n,modelGroups:r,onSaved:i}){let[l,u]=(0,s.useState)(t),[d,f]=(0,s.useState)(null),[p,m]=(0,s.useState)(!1),h=JSON.stringify(l)!==JSON.stringify(t);async function g(){f(null),m(!0);try{let t=await fetch(`/api/profile-groups/${e}/members`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({members:l})});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}i()}catch(e){f(e.message)}finally{m(!1)}}return(0,c.jsxs)(`div`,{className:`card`,children:[(0,c.jsx)(`h3`,{children:`members`}),d&&(0,c.jsx)(`div`,{className:`err`,children:d}),(0,c.jsxs)(`p`,{className:`muted`,children:[`Each member becomes one agent at spawn time. Duplicate agent-names within a template are fine — the spawn op auto-suffixes collisions with `,(0,c.jsx)(`code`,{children:`-2`}),`, `,(0,c.jsx)(`code`,{children:`-3`}),`, …`]}),(0,c.jsx)(o,{members:l,onChange:u,profiles:n,modelGroups:r}),(0,c.jsx)(`div`,{className:`mt-3`,children:(0,c.jsx)(a,{variant:`primary`,onClick:g,disabled:p||!h,children:p?`saving…`:`save members`})})]})}export{u as component};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{f as i}from"./index-iayCEuU2.js";import{t as a}from"./AgentAvatar-JYijLvZ2.js";var o=e(n()),s=t();function c(){let{agents:e,profiles:t,groups:n,modelGroups:o}=i.useLoaderData(),{all:c}=i.useSearch(),u=c===`1`,d=r();async function f(e){confirm(`archive this agent? (reversible)`)&&(await fetch(`/api/agents/${e}/archive`,{method:`POST`}),await d.invalidate())}async function p(e){await fetch(`/api/agents/${e}/unarchive`,{method:`POST`}),await d.invalidate()}async function m(e){confirm(`permanently delete this agent and all its data?`)&&(await fetch(`/api/agents/${e}`,{method:`DELETE`}),await d.invalidate())}return(0,s.jsxs)(`div`,{children:[(0,s.jsx)(`h1`,{children:`agents`}),(0,s.jsx)(l,{profiles:t,groups:n,modelGroups:o,onSpawned:d.invalidate}),(0,s.jsx)(`p`,{children:(0,s.jsx)(`a`,{href:u?`/agents`:`/agents?all=1`,children:u?`hide archived`:`show archived`})}),(0,s.jsxs)(`table`,{children:[(0,s.jsx)(`thead`,{children:(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`th`,{children:`id`}),(0,s.jsx)(`th`,{children:`name`}),(0,s.jsx)(`th`,{children:`profile`}),(0,s.jsx)(`th`,{children:`status`}),(0,s.jsx)(`th`,{})]})}),(0,s.jsxs)(`tbody`,{children:[e.length===0&&(0,s.jsx)(`tr`,{children:(0,s.jsx)(`td`,{colSpan:5,className:`muted`,children:`no agents yet`})}),e.map(e=>(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`td`,{children:(0,s.jsx)(`a`,{href:`/agents/${e.id}`,title:e.id,children:(0,s.jsxs)(`code`,{children:[e.id.slice(0,8),`…`]})})}),(0,s.jsx)(`td`,{children:(0,s.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,s.jsx)(a,{identity:e.identity,size:26}),(0,s.jsxs)(`div`,{className:`leading-tight`,children:[(0,s.jsx)(`div`,{children:e.name}),(e.identity?.creature||e.identity?.vibe)&&(0,s.jsx)(`div`,{className:`muted text-[0.8em]`,children:[e.identity?.creature,e.identity?.vibe].filter(Boolean).join(` · `)})]})]})}),(0,s.jsx)(`td`,{children:(0,s.jsx)(`code`,{children:e.profileId})}),(0,s.jsx)(`td`,{children:e.status}),(0,s.jsx)(`td`,{children:(0,s.jsxs)(`div`,{className:`flex gap-1.5`,children:[e.status===`archived`?(0,s.jsx)(`button`,{type:`button`,className:`ghost-btn`,onClick:()=>p(e.id),children:`unarchive`}):(0,s.jsx)(`button`,{type:`button`,className:`ghost-btn`,onClick:()=>f(e.id),children:`archive`}),(0,s.jsx)(`button`,{type:`button`,className:`ghost-btn`,style:{color:`var(--color-rose-baziu)`},onClick:()=>m(e.id),children:`delete`})]})})]},e.id))]})]})]})}function l({profiles:e,groups:t,modelGroups:n,onSpawned:r}){let[i,a]=(0,o.useState)(``),[c,l]=(0,o.useState)(``),[u,d]=(0,o.useState)(``),[f,p]=(0,o.useState)(t.find(e=>e.id==="default")?.id??``),[m,h]=(0,o.useState)(!1),[g,_]=(0,o.useState)(null);async function v(e){if(e.preventDefault(),!i){_(`profile is required`);return}h(!0),_(null);try{let e={profile:i};c&&(e.name=c),u&&(e.model=u),f&&(e.groupId=f);let t=await fetch(`/api/agents`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)});if(!t.ok){let e=await t.json().catch(()=>null);throw Error(e?.error??t.statusText)}l(``),d(``),r()}catch(e){_(e.message)}finally{h(!1)}}return(0,s.jsxs)(`form`,{className:`card`,onSubmit:v,children:[(0,s.jsx)(`h3`,{children:`spawn agent`}),g&&(0,s.jsx)(`div`,{className:`err`,children:g}),(0,s.jsx)(`p`,{className:`muted my-2 text-[0.85em]`,children:`Skills come from the profile's defaults at spawn time. Tweak per-agent skills after the fact from the agent detail page.`}),(0,s.jsxs)(`div`,{className:`flex gap-4`,children:[(0,s.jsxs)(`label`,{className:`flex-1`,children:[`profile`,(0,s.jsxs)(`select`,{value:i,onChange:e=>a(e.target.value),required:!0,children:[(0,s.jsx)(`option`,{value:``,children:`--`}),e.map(e=>(0,s.jsx)(`option`,{value:e.id,children:e.id},e.id))]})]}),(0,s.jsxs)(`label`,{className:`flex-1`,children:[`name`,(0,s.jsx)(`input`,{value:c,onChange:e=>l(e.target.value)})]})]}),(0,s.jsxs)(`label`,{children:[`model override`,n.length===0?(0,s.jsx)(`input`,{value:``,disabled:!0,placeholder:`(uses profile default — enable models on /config)`}):(0,s.jsxs)(`select`,{value:u,onChange:e=>d(e.target.value),children:[(0,s.jsx)(`option`,{value:``,children:`(uses profile default)`}),n.map(e=>(0,s.jsx)(`optgroup`,{label:e.provider,children:e.models.map(t=>(0,s.jsx)(`option`,{value:`${e.provider}:${t}`,children:`${e.provider}:${t}`},t))},e.provider))]})]}),(0,s.jsxs)(`label`,{children:[`group`,t.length===0?(0,s.jsx)(`select`,{disabled:!0,children:(0,s.jsx)(`option`,{children:`(no groups — register one on /groups)`})}):(0,s.jsx)(`select`,{value:f,onChange:e=>p(e.target.value),children:t.map(e=>(0,s.jsxs)(`option`,{value:e.id,children:[e.id,` (`,e.name,`)`]},e.id))})]}),(0,s.jsx)(`button`,{type:`submit`,disabled:m,children:m?`spawning…`:`spawn`})]})}export{c as component};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{Q as n,u as r}from"./preload-helper-CvnapA2_.js";import{m as i}from"./index-iayCEuU2.js";var a=e(n()),o=t();function s(){let{groups:e,memberCounts:t}=i.useLoaderData(),n=r();async function a(e){if(!confirm(`remove this group registration?`))return;let t=await fetch(`/api/groups/${e}`,{method:`DELETE`});if(!t.ok&&t.status!==204){alert(t.statusText);return}await n.invalidate()}return(0,o.jsxs)(`div`,{children:[(0,o.jsx)(`h1`,{children:`groups`}),(0,o.jsx)(`p`,{className:`muted`,children:`A group is a collaboration context: one filesystem root, one USER.md, one roster. Every agent belongs to exactly one group.`}),(0,o.jsx)(c,{onRegistered:()=>n.invalidate()}),(0,o.jsxs)(`table`,{children:[(0,o.jsx)(`thead`,{children:(0,o.jsxs)(`tr`,{children:[(0,o.jsx)(`th`,{children:`id`}),(0,o.jsx)(`th`,{children:`name`}),(0,o.jsx)(`th`,{children:`path`}),(0,o.jsx)(`th`,{children:`members`}),(0,o.jsx)(`th`,{children:`USER.md`}),(0,o.jsx)(`th`,{})]})}),(0,o.jsxs)(`tbody`,{children:[e.length===0&&(0,o.jsx)(`tr`,{children:(0,o.jsx)(`td`,{colSpan:6,className:`muted`,children:`no groups registered`})}),e.map(e=>{let n=t[e.id]??0,r=e.userMd.length;return(0,o.jsxs)(`tr`,{children:[(0,o.jsx)(`td`,{children:(0,o.jsx)(`code`,{children:e.id})}),(0,o.jsx)(`td`,{children:e.name}),(0,o.jsx)(`td`,{children:(0,o.jsx)(`code`,{children:e.path})}),(0,o.jsx)(`td`,{children:n}),(0,o.jsx)(`td`,{children:(0,o.jsx)(`a`,{href:`/groups/${e.id}`,children:r>0?`${r} chars`:`empty`})}),(0,o.jsx)(`td`,{children:n===0?(0,o.jsx)(`button`,{type:`button`,className:`ghost-btn`,onClick:()=>a(e.id),children:`remove`}):(0,o.jsx)(`span`,{className:`muted`,title:`${n} agent(s) belong to this group`,children:`in use`})})]},e.id)})]})]})]})}function c({onRegistered:e}){let[t,n]=(0,a.useState)(``),[r,i]=(0,a.useState)(``),[s,c]=(0,a.useState)(``),[l,u]=(0,a.useState)(null),[d,f]=(0,a.useState)(!1);async function p(a){if(a.preventDefault(),u(null),!t.trim()){u(`id is required`);return}f(!0);try{let a=await fetch(`/api/groups`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.trim(),name:r.trim()||void 0,link:s.trim()||void 0})});if(!a.ok){let e=await a.json().catch(()=>null);throw Error(e?.error??a.statusText)}n(``),i(``),c(``),e()}catch(e){u(e.message)}finally{f(!1)}}return(0,o.jsxs)(`form`,{className:`card`,onSubmit:p,children:[(0,o.jsx)(`h3`,{children:`register group`}),l&&(0,o.jsx)(`div`,{className:`err`,children:l}),(0,o.jsxs)(`p`,{className:`muted`,children:[`Groups always live under `,(0,o.jsx)(`code`,{children:`~/.bazilion/groups/<slug>/`}),`. Leave the link target blank to create a fresh directory; supply an absolute path to materialize the slot as a symlink to your existing project tree instead.`]}),(0,o.jsxs)(`div`,{className:`flex gap-4`,children:[(0,o.jsxs)(`label`,{className:`flex-1`,children:[`id (slug)`,(0,o.jsx)(`input`,{value:t,onChange:e=>n(e.target.value),required:!0,placeholder:`myproject`})]}),(0,o.jsxs)(`label`,{className:`flex-1`,children:[`name`,(0,o.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`My Project`})]})]}),(0,o.jsxs)(`label`,{children:[`link target (optional, absolute path)`,(0,o.jsx)(`input`,{value:s,onChange:e=>c(e.target.value),placeholder:`/home/user/projects/myproject`})]}),(0,o.jsx)(`button`,{type:`submit`,disabled:d,children:d?`registering…`:`register`})]})}export{s as component};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{t}from"./index-iayCEuU2.js";import{t as n}from"./AgentTabs-DioGqUVR.js";var r=e();function i(e){try{let t=JSON.parse(e);if(typeof t.text==`string`)return t.text}catch{}return e}function a(){let{resolved:e,messages:a,unreadCount:o,selected:s,agentNames:c}=t.useLoaderData(),l=t.useSearch().unread===`1`,u=!!(s&&s.toAgentId!==e.agent.id);function d(e){let t=c[e];return t?`${t} (${e.slice(0,8)})`:e.slice(0,8)}return(0,r.jsxs)(`main`,{className:`mx-auto max-w-5xl px-6 py-8`,children:[(0,r.jsx)(`h1`,{className:`font-serif text-3xl text-foreground mb-1`,children:e.agent.name}),(0,r.jsxs)(`p`,{className:`text-xs text-muted-foreground mb-6`,children:[(0,r.jsxs)(`code`,{className:`font-mono`,children:[e.agent.id.slice(0,8),`…`]}),` · unread: `,o]}),(0,r.jsx)(n,{agentId:e.agent.id,active:`inbox`,archived:e.agent.status===`archived`}),(0,r.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-[360px_1fr] gap-6`,children:[(0,r.jsxs)(`div`,{children:[(0,r.jsxs)(`div`,{className:`flex gap-1 border-b mb-3`,children:[(0,r.jsx)(`a`,{href:`/agents/${e.agent.id}/inbox`,className:`px-3 py-1.5 text-sm border-b-2 -mb-px ${l?`border-transparent text-muted-foreground`:`border-primary text-primary font-semibold`}`,children:`all`}),(0,r.jsx)(`a`,{href:`/agents/${e.agent.id}/inbox?unread=1`,className:`px-3 py-1.5 text-sm border-b-2 -mb-px ${l?`border-primary text-primary font-semibold`:`border-transparent text-muted-foreground`}`,children:`unread`})]}),(0,r.jsx)(`div`,{className:`rounded-lg border bg-card max-h-[640px] overflow-y-auto`,children:a.length===0?(0,r.jsx)(`div`,{className:`p-6 text-center text-muted-foreground italic`,children:l?`no unread messages`:`inbox empty`}):a.map(t=>{let n=i(t.payload),a=n.length>80?`${n.slice(0,80)}…`:n,o=new Date(t.createdAt).toLocaleString(),c=s?.id===t.id,u=t.readAt===null,f=l?`?unread=1&id=${t.id}`:`?id=${t.id}`;return(0,r.jsxs)(`a`,{href:`/agents/${e.agent.id}/inbox${f}`,className:`block border-b last:border-0 px-3 py-2 text-sm hover:bg-accent/30 ${c?`bg-accent/40`:``} ${u?`font-medium`:``}`,children:[(0,r.jsxs)(`div`,{className:`flex justify-between text-xs text-muted-foreground`,children:[(0,r.jsxs)(`span`,{className:`font-mono`,children:[u&&(0,r.jsx)(`span`,{className:`inline-block w-1.5 h-1.5 rounded-full bg-primary mr-1.5 align-middle`}),`from `,d(t.fromAgentId)]}),(0,r.jsx)(`span`,{className:`font-mono`,children:o})]}),(0,r.jsx)(`div`,{className:`text-foreground mt-0.5 truncate`,children:a})]},t.id)})})]}),(0,r.jsxs)(`div`,{children:[s&&!u&&(0,r.jsxs)(`div`,{className:`rounded-lg border bg-card p-5 mb-4`,children:[(0,r.jsxs)(`div`,{className:`font-mono text-xs text-muted-foreground mb-2 space-y-0.5`,children:[(0,r.jsxs)(`div`,{children:[`id: `,(0,r.jsx)(`code`,{children:s.id})]}),(0,r.jsxs)(`div`,{children:[`from: `,(0,r.jsx)(`code`,{children:d(s.fromAgentId)})]}),(0,r.jsxs)(`div`,{children:[`received: `,new Date(s.createdAt).toLocaleString()]}),(0,r.jsxs)(`div`,{children:[`read:`,` `,s.readAt?new Date(s.readAt).toLocaleString():`(unread)`]}),s.replyTo&&(0,r.jsxs)(`div`,{children:[`reply to: `,(0,r.jsx)(`code`,{children:s.replyTo})]})]}),(0,r.jsx)(`div`,{className:`border-t pt-3 font-mono text-sm whitespace-pre-wrap break-words`,children:i(s.payload)})]}),u&&(0,r.jsx)(`div`,{className:`rounded-lg border bg-card p-5 mb-4 text-muted-foreground`,children:`message is not addressed to this agent`}),(0,r.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Agents exchange messages automatically via their`,` `,(0,r.jsx)(`code`,{className:`font-mono`,children:`send_message`}),` tool. An idle recipient's scheduler tick drains unread mail.`]})]})]})]})}export{a as component};