bazilion 0.5.0 → 0.6.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 (118) hide show
  1. package/README.md +14 -9
  2. package/dist/cli.js +365 -140
  3. package/dist/cli.js.map +1 -1
  4. package/dist/daemon.js +4452 -16989
  5. package/dist/daemon.js.map +1 -1
  6. package/dist/web/client/assets/AgentAvatar-Cq7PVBE_.js +1 -0
  7. package/dist/web/client/assets/AgentTabs-M5K8emJ8.js +1 -0
  8. package/dist/web/client/assets/Button-BefUtjMZ.js +1 -0
  9. package/dist/web/client/assets/ChatPane-C8zQfpzH.js +74 -0
  10. package/dist/web/client/assets/ConfigTabs-DRqAymcN.js +1 -0
  11. package/dist/web/client/assets/FieldRow-BqWnxZiX.js +1 -0
  12. package/dist/web/client/assets/MembersEditor-B-47GLUb.js +1 -0
  13. package/dist/web/client/assets/SpawnTeamModal-DiiC7Nc0.js +1 -0
  14. package/dist/web/client/assets/TemplatesTabs-DB4KERTQ.js +1 -0
  15. package/dist/web/client/assets/_id-B7gv1aPQ.js +1 -0
  16. package/dist/web/client/assets/_id-C7d1AqS0.js +1 -0
  17. package/dist/web/client/assets/_id-DhiwjC8u.js +1 -0
  18. package/dist/web/client/assets/_id-p8lUuNFm.js +1 -0
  19. package/dist/web/client/assets/agents-v8G-wt0M.js +1 -0
  20. package/dist/web/client/assets/config-BdmYpS_y.js +3 -0
  21. package/dist/web/client/assets/groups-DiY_ExGM.js +1 -0
  22. package/dist/web/client/assets/inbox-DtfVx246.js +1 -0
  23. package/dist/web/client/assets/index-BQUL6oyH.js +12 -0
  24. package/dist/web/client/assets/login-CVS70W9g.js +1 -0
  25. package/dist/web/client/assets/mcp-BDLQq8OZ.js +1 -0
  26. package/dist/web/client/assets/memory-6GGuAXwx.js +1 -0
  27. package/dist/web/client/assets/profile-groups-BA8rwZMA.js +1 -0
  28. package/dist/web/client/assets/profiles-C0aAcPZg.js +1 -0
  29. package/dist/web/client/assets/routes-DgAhnKFw.js +1 -0
  30. package/dist/web/client/assets/services-BZ86QEah.js +1 -0
  31. package/dist/web/client/assets/skills-mv_NNNwo.js +1 -0
  32. package/dist/web/client/assets/styles-CmqUskDu.css +2 -0
  33. package/dist/web/client/assets/telegram-5f9WXs3x.js +1 -0
  34. package/dist/web/client/assets/tokens-DHiYsFUh.js +1 -0
  35. package/dist/web/client/assets/triggers-CjC8Ljrz.js +1 -0
  36. package/dist/web/client/assets/welcome-C-Cu-ziL.js +1 -0
  37. package/dist/web/client/assets/wire-constants-BkT5-597.js +1 -0
  38. package/dist/web/client/baziu.svg +8 -0
  39. package/dist/web/server/assets/AgentAvatar-8gTAy_tP.js +37 -0
  40. package/dist/web/server/assets/AgentTabs-BOjTN7QF.js +34 -0
  41. package/dist/web/server/assets/Button-Dsnw22OF.js +17 -0
  42. package/dist/web/server/assets/ChatPane-BvpswYvF.js +1084 -0
  43. package/dist/web/server/assets/ConfigTabs-CyuxzesF.js +41 -0
  44. package/dist/web/server/assets/FieldRow-DwyqycWI.js +94 -0
  45. package/dist/web/server/assets/MembersEditor-BWQztvrX.js +131 -0
  46. package/dist/web/server/assets/Sidebar-DmEiewRN.js +529 -0
  47. package/dist/web/server/assets/SpawnTeamModal-dSN421k_.js +107 -0
  48. package/dist/web/server/assets/TemplatesTabs---7h5GYa.js +30 -0
  49. package/dist/web/server/assets/_id-BZ-YCWSw.js +16 -0
  50. package/dist/web/server/assets/_id-Bm4-_AP-.js +367 -0
  51. package/dist/web/server/assets/_id-C78M9_j9.js +12 -0
  52. package/dist/web/server/assets/_id-CGZbudCl.js +28 -0
  53. package/dist/web/server/assets/_id-CHNm7EAd.js +161 -0
  54. package/dist/web/server/assets/_id-CrQbC5L8.js +16 -0
  55. package/dist/web/server/assets/_id-Crcw2HhT.js +38 -0
  56. package/dist/web/server/assets/_id-CvIGhq4U.js +16 -0
  57. package/dist/web/server/assets/_id-DF3pfi9M.js +27 -0
  58. package/dist/web/server/assets/_id-Dc8P9sy2.js +24 -0
  59. package/dist/web/server/assets/_id-GJk3EYTT.js +662 -0
  60. package/dist/web/server/assets/_id-pd4S7LTi.js +467 -0
  61. package/dist/web/server/assets/_tanstack-start-manifest_v-CPyKYMJg.js +174 -0
  62. package/dist/web/server/assets/agents-70EwQJR6.js +210 -0
  63. package/dist/web/server/assets/agents-Ds4lcREv.js +26 -0
  64. package/dist/web/server/assets/agents-K4Smhnq3.js +14 -0
  65. package/dist/web/server/assets/auth-DpAGLHpA.js +26 -0
  66. package/dist/web/server/assets/config-CMXUx_IF.js +19 -0
  67. package/dist/web/server/assets/config-DQbCsY_l.js +382 -0
  68. package/dist/web/server/assets/config-DxCGYgR9.js +12 -0
  69. package/dist/web/server/assets/createServerRpc-CBTntoKx.js +12 -0
  70. package/dist/web/server/assets/createSsrRpc-DHBVUN8O.js +16 -0
  71. package/dist/web/server/assets/daemon-client-2NRMzlTr.js +96 -0
  72. package/dist/web/server/assets/empty-plugin-adapters-Bos_V2s-.js +5 -0
  73. package/dist/web/server/assets/groups-CXVew7BP.js +150 -0
  74. package/dist/web/server/assets/groups-Cms8cvH5.js +12 -0
  75. package/dist/web/server/assets/groups-Dmcvw5ya.js +21 -0
  76. package/dist/web/server/assets/inbox-0QfwsrGo.js +27 -0
  77. package/dist/web/server/assets/inbox-8HybA2Ws.js +133 -0
  78. package/dist/web/server/assets/inbox-B7UWoICA.js +42 -0
  79. package/dist/web/server/assets/login-CNznncgA.js +58 -0
  80. package/dist/web/server/assets/login-CQybKk7Y.js +74 -0
  81. package/dist/web/server/assets/mcp-42BrkI1I.js +12 -0
  82. package/dist/web/server/assets/mcp-DIa0kIOf.js +268 -0
  83. package/dist/web/server/assets/mcp-DsTjY3uz.js +12 -0
  84. package/dist/web/server/assets/memory-BfrMp8iY.js +284 -0
  85. package/dist/web/server/assets/memory-Dr0lOM2y.js +28 -0
  86. package/dist/web/server/assets/memory-EEgLDfCj.js +16 -0
  87. package/dist/web/server/assets/profile-groups-BW5gU-fG.js +12 -0
  88. package/dist/web/server/assets/profile-groups-B_kIT6BU.js +208 -0
  89. package/dist/web/server/assets/profile-groups-C5isDI2t.js +28 -0
  90. package/dist/web/server/assets/profiles-BP1v-jna.js +453 -0
  91. package/dist/web/server/assets/profiles-BbPTpmyq.js +26 -0
  92. package/dist/web/server/assets/profiles-Cy5auEj8.js +12 -0
  93. package/dist/web/server/assets/router-CL100-Ly.js +460 -0
  94. package/dist/web/server/assets/routes-CzJLQxcS.js +14 -0
  95. package/dist/web/server/assets/routes-D2H1Hnoh.js +57 -0
  96. package/dist/web/server/assets/routes-Dzk8jvIo.js +33 -0
  97. package/dist/web/server/assets/services-Bgj6M2gC.js +12 -0
  98. package/dist/web/server/assets/services-DEgYsWJ4.js +17 -0
  99. package/dist/web/server/assets/services-DFenjiw0.js +94 -0
  100. package/dist/web/server/assets/skills-BASIP_rT.js +12 -0
  101. package/dist/web/server/assets/skills-C-JPRCHh.js +12 -0
  102. package/dist/web/server/assets/skills-DZXN680t.js +261 -0
  103. package/dist/web/server/assets/start-cOXH7eTI.js +4 -0
  104. package/dist/web/server/assets/telegram-BbvqVWxa.js +583 -0
  105. package/dist/web/server/assets/telegram-Bq49AtnP.js +12 -0
  106. package/dist/web/server/assets/telegram-sUckI94O.js +12 -0
  107. package/dist/web/server/assets/tokens-BERRE0wB.js +14 -0
  108. package/dist/web/server/assets/tokens-CImgxhDI.js +193 -0
  109. package/dist/web/server/assets/tokens-Dwn00iV7.js +12 -0
  110. package/dist/web/server/assets/triggers-DtexqbNH.js +16 -0
  111. package/dist/web/server/assets/triggers-TyIjwSYn.js +26 -0
  112. package/dist/web/server/assets/triggers-_iSeahif.js +191 -0
  113. package/dist/web/server/assets/welcome-BkQ9NC5K.js +81 -0
  114. package/dist/web/server/assets/wire-constants-Deb4NxBb.js +16 -0
  115. package/dist/web/server/server.js +5899 -0
  116. package/dist/web-server.js +42 -0
  117. package/dist/web-server.js.map +1 -0
  118. package/package.json +10 -4
@@ -0,0 +1,208 @@
1
+ import { t as Route } from "./profile-groups-BW5gU-fG.js";
2
+ import { t as Button } from "./Button-Dsnw22OF.js";
3
+ import { t as SpawnTeamModal } from "./SpawnTeamModal-dSN421k_.js";
4
+ import { t as MembersEditor } from "./MembersEditor-BWQztvrX.js";
5
+ import { t as TemplatesTabs } from "./TemplatesTabs---7h5GYa.js";
6
+ import { useState } from "react";
7
+ import { useRouter } from "@tanstack/react-router";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/routes/profile-groups/index.tsx?tsr-split=component
10
+ function ProfileGroupsPage() {
11
+ const { profileGroups, groups, profiles, modelGroups, userMdDefault } = Route.useLoaderData();
12
+ const router = useRouter();
13
+ const [spawningId, setSpawningId] = useState(null);
14
+ async function del(id) {
15
+ if (!confirm("delete this profile group? (does not affect spawned agents)")) return;
16
+ const res = await fetch(`/api/profile-groups/${id}`, { method: "DELETE" });
17
+ if (!res.ok && res.status !== 204) {
18
+ const e = await res.json().catch(() => null);
19
+ alert(e?.error ?? res.statusText);
20
+ return;
21
+ }
22
+ await router.invalidate();
23
+ }
24
+ return /* @__PURE__ */ jsxs("div", { children: [
25
+ /* @__PURE__ */ jsx(TemplatesTabs, {}),
26
+ /* @__PURE__ */ jsx("h1", { children: "profile groups" }),
27
+ /* @__PURE__ */ jsx("p", {
28
+ className: "muted",
29
+ children: "A profile group is a reusable team template. Each one holds an ordered list of members — profile + agent-name + optional overrides — that get replayed as a single transactional spawn into a target group."
30
+ }),
31
+ /* @__PURE__ */ jsx(CreateProfileGroupForm, {
32
+ profiles,
33
+ modelGroups,
34
+ userMdDefault,
35
+ onCreated: () => router.invalidate()
36
+ }),
37
+ /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
38
+ /* @__PURE__ */ jsx("th", { children: "id" }),
39
+ /* @__PURE__ */ jsx("th", { children: "name" }),
40
+ /* @__PURE__ */ jsx("th", { children: "members" }),
41
+ /* @__PURE__ */ jsx("th", {})
42
+ ] }) }), /* @__PURE__ */ jsxs("tbody", { children: [profileGroups.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
43
+ colSpan: 4,
44
+ className: "muted",
45
+ children: "no profile groups yet"
46
+ }) }), profileGroups.map((g) => /* @__PURE__ */ jsxs("tr", { children: [
47
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("a", {
48
+ href: `/profile-groups/${g.id}`,
49
+ children: /* @__PURE__ */ jsx("code", { children: g.id })
50
+ }) }),
51
+ /* @__PURE__ */ jsx("td", { children: g.name }),
52
+ /* @__PURE__ */ jsx("td", { children: g.memberCount }),
53
+ /* @__PURE__ */ jsxs("td", {
54
+ className: "flex gap-2",
55
+ children: [/* @__PURE__ */ jsx(Button, {
56
+ variant: "primary",
57
+ disabled: g.memberCount === 0,
58
+ title: g.memberCount === 0 ? "add at least one member before spawning" : void 0,
59
+ onClick: () => setSpawningId(g.id),
60
+ children: "spawn team"
61
+ }), /* @__PURE__ */ jsx(Button, {
62
+ variant: "danger",
63
+ onClick: () => del(g.id),
64
+ children: "delete"
65
+ })]
66
+ })
67
+ ] }, g.id))] })] }),
68
+ spawningId && /* @__PURE__ */ jsx(SpawnTeamModal, {
69
+ profileGroup: profileGroups.find((g) => g.id === spawningId),
70
+ groups,
71
+ onClose: () => setSpawningId(null),
72
+ onSpawned: (slug) => {
73
+ setSpawningId(null);
74
+ router.navigate({
75
+ to: "/groups/$id",
76
+ params: { id: slug }
77
+ });
78
+ }
79
+ })
80
+ ] });
81
+ }
82
+ function CreateProfileGroupForm({ profiles, modelGroups, userMdDefault, onCreated }) {
83
+ const [id, setId] = useState("");
84
+ const [name, setName] = useState("");
85
+ const [userMd, setUserMd] = useState(userMdDefault);
86
+ const [members, setMembers] = useState([]);
87
+ const [err, setErr] = useState(null);
88
+ const [submitting, setSubmitting] = useState(false);
89
+ async function submit(e) {
90
+ e.preventDefault();
91
+ setErr(null);
92
+ if (!id.trim()) {
93
+ setErr("id is required");
94
+ return;
95
+ }
96
+ setSubmitting(true);
97
+ try {
98
+ const createBody = { id: id.trim() };
99
+ if (name.trim()) createBody.name = name.trim();
100
+ if (userMd) createBody.userMd = userMd;
101
+ const createRes = await fetch("/api/profile-groups", {
102
+ method: "POST",
103
+ headers: { "content-type": "application/json" },
104
+ body: JSON.stringify(createBody)
105
+ });
106
+ if (!createRes.ok) {
107
+ const e2 = await createRes.json().catch(() => null);
108
+ throw new Error(e2?.error ?? createRes.statusText);
109
+ }
110
+ if (members.length > 0) {
111
+ const membersRes = await fetch(`/api/profile-groups/${id.trim()}/members`, {
112
+ method: "PUT",
113
+ headers: { "content-type": "application/json" },
114
+ body: JSON.stringify({ members })
115
+ });
116
+ if (!membersRes.ok) {
117
+ const e2 = await membersRes.json().catch(() => null);
118
+ throw new Error(`group created, member save failed: ${e2?.error ?? membersRes.statusText}`);
119
+ }
120
+ }
121
+ setId("");
122
+ setName("");
123
+ setUserMd(userMdDefault);
124
+ setMembers([]);
125
+ onCreated();
126
+ } catch (e2) {
127
+ setErr(e2.message);
128
+ } finally {
129
+ setSubmitting(false);
130
+ }
131
+ }
132
+ return /* @__PURE__ */ jsxs("form", {
133
+ className: "card",
134
+ onSubmit: submit,
135
+ children: [
136
+ /* @__PURE__ */ jsx("h3", { children: "create profile group" }),
137
+ err && /* @__PURE__ */ jsx("div", {
138
+ className: "err",
139
+ children: err
140
+ }),
141
+ /* @__PURE__ */ jsxs("div", {
142
+ className: "flex gap-4",
143
+ children: [/* @__PURE__ */ jsxs("label", {
144
+ className: "flex-1",
145
+ children: ["id (slug)", /* @__PURE__ */ jsx("input", {
146
+ value: id,
147
+ onChange: (e) => setId(e.target.value),
148
+ required: true,
149
+ placeholder: "platform-team"
150
+ })]
151
+ }), /* @__PURE__ */ jsxs("label", {
152
+ className: "flex-1",
153
+ children: ["name", /* @__PURE__ */ jsx("input", {
154
+ value: name,
155
+ onChange: (e) => setName(e.target.value),
156
+ placeholder: "Platform Team"
157
+ })]
158
+ })]
159
+ }),
160
+ /* @__PURE__ */ jsxs("label", { children: ["starter USER.md (seeded into freshly-created target groups; prefilled with the built-in default — edit to customise)", /* @__PURE__ */ jsx("textarea", {
161
+ rows: 3,
162
+ value: userMd,
163
+ onChange: (e) => setUserMd(e.target.value),
164
+ className: "font-mono text-[0.88em] leading-[1.55]"
165
+ })] }),
166
+ /* @__PURE__ */ jsxs("div", {
167
+ className: "mt-4",
168
+ children: [
169
+ /* @__PURE__ */ jsx("h4", {
170
+ className: "mb-1 text-[0.95em] font-medium",
171
+ children: "members"
172
+ }),
173
+ /* @__PURE__ */ jsxs("p", {
174
+ className: "muted mb-2 text-[0.88em]",
175
+ children: [
176
+ "Each member becomes one agent when the team is spawned. You can also configure members later from the detail page.",
177
+ " ",
178
+ profiles.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
179
+ "Available profiles:",
180
+ " ",
181
+ profiles.map((p, i) => /* @__PURE__ */ jsxs("span", { children: [i > 0 && ", ", /* @__PURE__ */ jsx("code", { children: p.id })] }, p.id)),
182
+ "."
183
+ ] })
184
+ ]
185
+ }),
186
+ /* @__PURE__ */ jsx(MembersEditor, {
187
+ members,
188
+ onChange: setMembers,
189
+ profiles,
190
+ modelGroups,
191
+ emptyHint: "No members configured yet — add one to pick a profile for each team member."
192
+ })
193
+ ]
194
+ }),
195
+ /* @__PURE__ */ jsx("div", {
196
+ className: "mt-4",
197
+ children: /* @__PURE__ */ jsx(Button, {
198
+ variant: "primary",
199
+ type: "submit",
200
+ disabled: submitting,
201
+ children: submitting ? "creating…" : "create"
202
+ })
203
+ })
204
+ ]
205
+ });
206
+ }
207
+ //#endregion
208
+ export { ProfileGroupsPage as component };
@@ -0,0 +1,28 @@
1
+ import { t as createServerFn } from "../server.js";
2
+ import { t as createServerRpc } from "./createServerRpc-CBTntoKx.js";
3
+ import { n as daemonClient } from "./daemon-client-2NRMzlTr.js";
4
+ //#region src/routes/profile-groups/index.tsx?tss-serverfn-split
5
+ var fetchProfileGroupsData_createServerFn_handler = createServerRpc({
6
+ id: "be2ab9d2d20bd46baa655e08a8f6f0c2161b01657d0362564a58edeaf2195a31",
7
+ name: "fetchProfileGroupsData",
8
+ filename: "src/routes/profile-groups/index.tsx"
9
+ }, (opts) => fetchProfileGroupsData.__executeServer(opts));
10
+ var fetchProfileGroupsData = createServerFn({ method: "GET" }).handler(fetchProfileGroupsData_createServerFn_handler, async () => {
11
+ const c = daemonClient();
12
+ const [profileGroups, groups, profiles, models, templates] = await Promise.all([
13
+ c.get("/api/profile-groups"),
14
+ c.get("/api/groups"),
15
+ c.get("/api/profiles"),
16
+ c.get("/api/config/available-models"),
17
+ c.get("/api/profiles/_/templates")
18
+ ]);
19
+ return {
20
+ profileGroups,
21
+ groups,
22
+ profiles,
23
+ modelGroups: models.groups,
24
+ userMdDefault: templates.userMd
25
+ };
26
+ });
27
+ //#endregion
28
+ export { fetchProfileGroupsData_createServerFn_handler };
@@ -0,0 +1,453 @@
1
+ import { t as Route } from "./profiles-Cy5auEj8.js";
2
+ import { t as Button } from "./Button-Dsnw22OF.js";
3
+ import { t as TemplatesTabs } from "./TemplatesTabs---7h5GYa.js";
4
+ import { useState } from "react";
5
+ import { useRouter } from "@tanstack/react-router";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/routes/profiles/index.tsx?tsr-split=component
8
+ function ProfilesPage() {
9
+ const { profiles, modelGroups, skills, templates } = Route.useLoaderData();
10
+ const router = useRouter();
11
+ async function del(id) {
12
+ if (!confirm("delete profile and all its files?")) return;
13
+ const res = await fetch(`/api/profiles/${id}`, { method: "DELETE" });
14
+ if (!res.ok && res.status !== 204) {
15
+ const body = await res.json().catch(() => null);
16
+ alert(body?.error ?? res.statusText);
17
+ return;
18
+ }
19
+ await router.invalidate();
20
+ }
21
+ return /* @__PURE__ */ jsxs("div", { children: [
22
+ /* @__PURE__ */ jsx(TemplatesTabs, {}),
23
+ /* @__PURE__ */ jsx("h1", { children: "profiles" }),
24
+ /* @__PURE__ */ jsx("p", {
25
+ className: "muted",
26
+ children: "A profile is a spawn template — SOUL/IDENTITY templates, a default model, a skills policy. Agents choose a group at spawn time, independent of their profile."
27
+ }),
28
+ /* @__PURE__ */ jsx(CreateProfileForm, {
29
+ modelGroups,
30
+ skills,
31
+ templates,
32
+ onCreated: () => router.invalidate()
33
+ }),
34
+ /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
35
+ /* @__PURE__ */ jsx("th", { children: "id" }),
36
+ /* @__PURE__ */ jsx("th", { children: "name" }),
37
+ /* @__PURE__ */ jsx("th", { children: "model" }),
38
+ /* @__PURE__ */ jsx("th", { children: "agents" }),
39
+ /* @__PURE__ */ jsx("th", { children: "skills" }),
40
+ /* @__PURE__ */ jsx("th", {})
41
+ ] }) }), /* @__PURE__ */ jsxs("tbody", { children: [profiles.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
42
+ colSpan: 6,
43
+ className: "muted",
44
+ children: "no profiles yet"
45
+ }) }), profiles.map((p) => {
46
+ const skillsLabel = p.skillsMode === "all" ? "all" : p.defaultSkills.length === 0 ? "—" : p.defaultSkills.join(", ");
47
+ return /* @__PURE__ */ jsxs("tr", { children: [
48
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("a", {
49
+ href: `/profiles/${p.id}`,
50
+ children: /* @__PURE__ */ jsx("code", { children: p.id })
51
+ }) }),
52
+ /* @__PURE__ */ jsx("td", { children: p.name }),
53
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("code", { children: p.defaultModel }) }),
54
+ /* @__PURE__ */ jsx("td", { children: p.agentCount }),
55
+ /* @__PURE__ */ jsx("td", {
56
+ className: "text-xs text-mocha-light",
57
+ children: skillsLabel
58
+ }),
59
+ /* @__PURE__ */ jsx("td", { children: p.agentCount === 0 ? /* @__PURE__ */ jsx(Button, {
60
+ variant: "danger",
61
+ onClick: () => del(p.id),
62
+ children: "delete"
63
+ }) : /* @__PURE__ */ jsx("span", {
64
+ className: "muted",
65
+ title: `${p.agentCount} agent(s) use this profile`,
66
+ children: "in use"
67
+ }) })
68
+ ] }, p.id);
69
+ })] })] })
70
+ ] });
71
+ }
72
+ function CreateProfileForm({ modelGroups, skills, templates, onCreated }) {
73
+ const [tab, setTab] = useState("basics");
74
+ const [id, setId] = useState("");
75
+ const [name, setName] = useState("");
76
+ const [model, setModel] = useState("");
77
+ const [soul, setSoul] = useState(templates.soul);
78
+ const [identity, setIdentity] = useState(templates.identity);
79
+ const [bootstrap, setBootstrap] = useState(templates.bootstrap);
80
+ const [enableBootstrap, setEnableBootstrap] = useState(true);
81
+ const [agentsTpl, setAgentsTpl] = useState(templates.agents);
82
+ const [enableAgents, setEnableAgents] = useState(true);
83
+ const [toolsTpl, setToolsTpl] = useState(templates.tools);
84
+ const [enableTools, setEnableTools] = useState(true);
85
+ const [heartbeatTpl, setHeartbeatTpl] = useState(templates.heartbeat);
86
+ const [enableHeartbeat, setEnableHeartbeat] = useState(false);
87
+ function setTemplateEnabled(key, setter, on) {
88
+ setter(on);
89
+ if (!on && tab === key) setTab("basics");
90
+ }
91
+ const [skillsMode, setSkillsMode] = useState("all");
92
+ const [picked, setPicked] = useState(/* @__PURE__ */ new Set());
93
+ const [error, setError] = useState(null);
94
+ const [submitting, setSubmitting] = useState(false);
95
+ function togglePicked(name) {
96
+ setPicked((prev) => {
97
+ const next = new Set(prev);
98
+ if (next.has(name)) next.delete(name);
99
+ else next.add(name);
100
+ return next;
101
+ });
102
+ }
103
+ async function submit(e) {
104
+ e.preventDefault();
105
+ setError(null);
106
+ if (!id.trim()) {
107
+ setError("id is required");
108
+ return;
109
+ }
110
+ if (!model.trim()) {
111
+ setError("default model is required");
112
+ return;
113
+ }
114
+ setSubmitting(true);
115
+ try {
116
+ const body = {
117
+ id: id.trim(),
118
+ name: name.trim() || void 0,
119
+ model: model.trim(),
120
+ skillsMode,
121
+ defaultSkills: skillsMode === "selected" ? Array.from(picked) : [],
122
+ soul,
123
+ identity,
124
+ bootstrap: enableBootstrap ? bootstrap : null,
125
+ agents: enableAgents ? agentsTpl : null,
126
+ tools: enableTools ? toolsTpl : null,
127
+ heartbeat: enableHeartbeat ? heartbeatTpl : null
128
+ };
129
+ const res = await fetch("/api/profiles", {
130
+ method: "POST",
131
+ headers: { "content-type": "application/json" },
132
+ body: JSON.stringify(body)
133
+ });
134
+ if (!res.ok) {
135
+ const e2 = await res.json().catch(() => null);
136
+ throw new Error(e2?.error ?? res.statusText);
137
+ }
138
+ setId("");
139
+ setName("");
140
+ setModel("");
141
+ setEnableBootstrap(true);
142
+ setAgentsTpl(templates.agents);
143
+ setEnableAgents(true);
144
+ setToolsTpl(templates.tools);
145
+ setEnableTools(true);
146
+ setHeartbeatTpl(templates.heartbeat);
147
+ setEnableHeartbeat(false);
148
+ setPicked(/* @__PURE__ */ new Set());
149
+ setSkillsMode("all");
150
+ setTab("basics");
151
+ onCreated();
152
+ } catch (err) {
153
+ setError(err.message);
154
+ } finally {
155
+ setSubmitting(false);
156
+ }
157
+ }
158
+ return /* @__PURE__ */ jsxs("form", {
159
+ className: "card",
160
+ onSubmit: submit,
161
+ children: [
162
+ /* @__PURE__ */ jsx("h3", { children: "create profile" }),
163
+ error && /* @__PURE__ */ jsx("div", {
164
+ className: "err",
165
+ children: error
166
+ }),
167
+ /* @__PURE__ */ jsx(Tabs, {
168
+ items: [
169
+ {
170
+ id: "basics",
171
+ label: "basics"
172
+ },
173
+ {
174
+ id: "soul",
175
+ label: "SOUL"
176
+ },
177
+ {
178
+ id: "identity",
179
+ label: "IDENTITY"
180
+ },
181
+ {
182
+ id: "bootstrap",
183
+ label: "BOOTSTRAP",
184
+ disabled: !enableBootstrap
185
+ },
186
+ {
187
+ id: "agents",
188
+ label: "AGENTS",
189
+ disabled: !enableAgents
190
+ },
191
+ {
192
+ id: "tools",
193
+ label: "TOOLS",
194
+ disabled: !enableTools
195
+ },
196
+ {
197
+ id: "heartbeat",
198
+ label: "HEARTBEAT",
199
+ disabled: !enableHeartbeat
200
+ },
201
+ {
202
+ id: "skills",
203
+ label: "skills"
204
+ }
205
+ ],
206
+ active: tab,
207
+ onChange: (t) => setTab(t)
208
+ }),
209
+ /* @__PURE__ */ jsxs("fieldset", {
210
+ className: "mb-5 rounded-md border border-frost p-3",
211
+ children: [
212
+ /* @__PURE__ */ jsx("legend", {
213
+ className: "px-1 text-[0.85em] font-medium text-mocha",
214
+ children: "templates to include"
215
+ }),
216
+ /* @__PURE__ */ jsxs("div", {
217
+ className: "flex flex-wrap gap-x-5 gap-y-2 text-[0.9em]",
218
+ children: [
219
+ /* @__PURE__ */ jsxs("label", {
220
+ className: "inline-flex items-center gap-1.5 opacity-60",
221
+ title: "always included",
222
+ children: [/* @__PURE__ */ jsx("input", {
223
+ type: "checkbox",
224
+ defaultChecked: true,
225
+ disabled: true
226
+ }), " SOUL.md"]
227
+ }),
228
+ /* @__PURE__ */ jsxs("label", {
229
+ className: "inline-flex items-center gap-1.5 opacity-60",
230
+ title: "always included",
231
+ children: [/* @__PURE__ */ jsx("input", {
232
+ type: "checkbox",
233
+ defaultChecked: true,
234
+ disabled: true
235
+ }), " IDENTITY.md"]
236
+ }),
237
+ /* @__PURE__ */ jsxs("label", {
238
+ className: "inline-flex cursor-pointer items-center gap-1.5",
239
+ children: [/* @__PURE__ */ jsx("input", {
240
+ type: "checkbox",
241
+ checked: enableBootstrap,
242
+ onChange: (e) => setTemplateEnabled("bootstrap", setEnableBootstrap, e.target.checked)
243
+ }), "BOOTSTRAP.md"]
244
+ }),
245
+ /* @__PURE__ */ jsxs("label", {
246
+ className: "inline-flex cursor-pointer items-center gap-1.5",
247
+ children: [/* @__PURE__ */ jsx("input", {
248
+ type: "checkbox",
249
+ checked: enableAgents,
250
+ onChange: (e) => setTemplateEnabled("agents", setEnableAgents, e.target.checked)
251
+ }), "AGENTS.md"]
252
+ }),
253
+ /* @__PURE__ */ jsxs("label", {
254
+ className: "inline-flex cursor-pointer items-center gap-1.5",
255
+ children: [/* @__PURE__ */ jsx("input", {
256
+ type: "checkbox",
257
+ checked: enableTools,
258
+ onChange: (e) => setTemplateEnabled("tools", setEnableTools, e.target.checked)
259
+ }), "TOOLS.md"]
260
+ }),
261
+ /* @__PURE__ */ jsxs("label", {
262
+ className: "inline-flex cursor-pointer items-center gap-1.5",
263
+ children: [/* @__PURE__ */ jsx("input", {
264
+ type: "checkbox",
265
+ checked: enableHeartbeat,
266
+ onChange: (e) => setTemplateEnabled("heartbeat", setEnableHeartbeat, e.target.checked)
267
+ }), "HEARTBEAT.md"]
268
+ })
269
+ ]
270
+ }),
271
+ /* @__PURE__ */ jsx("p", {
272
+ className: "muted mt-2 text-[0.8em]",
273
+ children: "Disabled files aren't created for this profile. Each spawned agent gets its own copy of the enabled files at spawn time."
274
+ })
275
+ ]
276
+ }),
277
+ tab === "basics" && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
278
+ className: "flex gap-4",
279
+ children: [/* @__PURE__ */ jsxs("label", {
280
+ className: "flex-1",
281
+ children: ["id (slug)", /* @__PURE__ */ jsx("input", {
282
+ value: id,
283
+ onChange: (e) => setId(e.target.value),
284
+ required: true
285
+ })]
286
+ }), /* @__PURE__ */ jsxs("label", {
287
+ className: "flex-1",
288
+ children: ["name", /* @__PURE__ */ jsx("input", {
289
+ value: name,
290
+ onChange: (e) => setName(e.target.value)
291
+ })]
292
+ })]
293
+ }), /* @__PURE__ */ jsxs("label", { children: ["default model", modelGroups.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("select", {
294
+ disabled: true,
295
+ children: /* @__PURE__ */ jsx("option", { children: "(no models available)" })
296
+ }), /* @__PURE__ */ jsxs("span", {
297
+ className: "muted text-[0.85em]",
298
+ children: [
299
+ "Enable a provider and curate models on ",
300
+ /* @__PURE__ */ jsx("a", {
301
+ href: "/config",
302
+ children: "/config"
303
+ }),
304
+ " first."
305
+ ]
306
+ })] }) : /* @__PURE__ */ jsxs("select", {
307
+ value: model,
308
+ onChange: (e) => setModel(e.target.value),
309
+ required: true,
310
+ children: [/* @__PURE__ */ jsx("option", {
311
+ value: "",
312
+ children: "-- pick a model --"
313
+ }), modelGroups.map((g) => /* @__PURE__ */ jsx("optgroup", {
314
+ label: g.provider,
315
+ children: g.models.map((m) => /* @__PURE__ */ jsx("option", {
316
+ value: `${g.provider}:${m}`,
317
+ children: `${g.provider}:${m}`
318
+ }, m))
319
+ }, g.provider))]
320
+ })] })] }),
321
+ tab === "soul" && /* @__PURE__ */ jsx(TemplateTab, {
322
+ label: "SOUL.md",
323
+ hint: "Persona, values, and operating principles. Injected into every session.",
324
+ value: soul,
325
+ onChange: setSoul,
326
+ rows: 16
327
+ }),
328
+ tab === "identity" && /* @__PURE__ */ jsx(TemplateTab, {
329
+ label: "IDENTITY.md",
330
+ hint: "Name, creature, vibe, emoji, avatar — filled in during the bootstrap ritual.",
331
+ value: identity,
332
+ onChange: setIdentity,
333
+ rows: 12
334
+ }),
335
+ tab === "bootstrap" && /* @__PURE__ */ jsx(TemplateTab, {
336
+ label: "BOOTSTRAP.md",
337
+ hint: "One-time first-run ritual. The agent retires it once introductions are done.",
338
+ value: bootstrap,
339
+ onChange: setBootstrap,
340
+ rows: 16
341
+ }),
342
+ tab === "agents" && /* @__PURE__ */ jsx(TemplateTab, {
343
+ label: "AGENTS.md",
344
+ hint: "The workspace operating manual — memory discipline, red lines, channel etiquette.",
345
+ value: agentsTpl,
346
+ onChange: setAgentsTpl,
347
+ rows: 16
348
+ }),
349
+ tab === "tools" && /* @__PURE__ */ jsx(TemplateTab, {
350
+ label: "TOOLS.md",
351
+ hint: "Agent-specific tool notes and environment facts beyond the generic tool descriptions.",
352
+ value: toolsTpl,
353
+ onChange: setToolsTpl,
354
+ rows: 14
355
+ }),
356
+ tab === "heartbeat" && /* @__PURE__ */ jsx(TemplateTab, {
357
+ label: "HEARTBEAT.md",
358
+ hint: "Optional checklist run on scheduled wake-ups. Pair with an interval/cron trigger.",
359
+ value: heartbeatTpl,
360
+ onChange: setHeartbeatTpl,
361
+ rows: 12
362
+ }),
363
+ tab === "skills" && /* @__PURE__ */ jsxs("div", { children: [
364
+ /* @__PURE__ */ jsx("p", {
365
+ className: "muted my-2",
366
+ children: "Choose which skills agents inherit at spawn time. In both modes each agent can still attach or detach skills individually after it's spawned."
367
+ }),
368
+ /* @__PURE__ */ jsxs("label", {
369
+ className: "flex items-start gap-2 my-2 cursor-pointer",
370
+ children: [/* @__PURE__ */ jsx("input", {
371
+ type: "radio",
372
+ name: "skillsMode",
373
+ value: "all",
374
+ checked: skillsMode === "all",
375
+ onChange: () => setSkillsMode("all")
376
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("strong", { children: "allow all skills" }), " — every skill on disk is attached when an agent is spawned."] })]
377
+ }),
378
+ /* @__PURE__ */ jsxs("label", {
379
+ className: "flex items-start gap-2 my-2 cursor-pointer",
380
+ children: [/* @__PURE__ */ jsx("input", {
381
+ type: "radio",
382
+ name: "skillsMode",
383
+ value: "selected",
384
+ checked: skillsMode === "selected",
385
+ onChange: () => setSkillsMode("selected")
386
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("strong", { children: "select skills" }), " — attach only the ones you pick below."] })]
387
+ }),
388
+ /* @__PURE__ */ jsx("div", {
389
+ className: `mt-3 max-h-[22rem] overflow-y-auto rounded-md border border-frost p-3 ${skillsMode === "all" ? "opacity-50 pointer-events-none" : ""}`,
390
+ children: skills.length === 0 ? /* @__PURE__ */ jsxs("p", {
391
+ className: "muted",
392
+ children: [
393
+ "No skills installed yet. Import some on ",
394
+ /* @__PURE__ */ jsx("a", {
395
+ href: "/skills",
396
+ children: "/skills"
397
+ }),
398
+ "."
399
+ ]
400
+ }) : skills.map((s) => /* @__PURE__ */ jsxs("label", {
401
+ className: "my-1.5 flex cursor-pointer items-start gap-2",
402
+ children: [/* @__PURE__ */ jsx("input", {
403
+ type: "checkbox",
404
+ checked: picked.has(s.name),
405
+ onChange: () => togglePicked(s.name)
406
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("code", { children: s.name }), s.description && /* @__PURE__ */ jsxs("span", {
407
+ className: "text-[0.9em] text-mocha-light",
408
+ children: [" — ", s.description]
409
+ })] })]
410
+ }, s.name))
411
+ })
412
+ ] }),
413
+ /* @__PURE__ */ jsx("div", {
414
+ className: "mt-5 flex gap-2",
415
+ children: /* @__PURE__ */ jsx(Button, {
416
+ variant: "primary",
417
+ type: "submit",
418
+ disabled: submitting,
419
+ children: submitting ? "creating…" : "create"
420
+ })
421
+ })
422
+ ]
423
+ });
424
+ }
425
+ function Tabs({ items, active, onChange }) {
426
+ return /* @__PURE__ */ jsx("nav", {
427
+ role: "tablist",
428
+ className: "-mb-px mb-5 flex flex-wrap gap-1 border-b border-frost",
429
+ children: items.map((it) => /* @__PURE__ */ jsx("button", {
430
+ type: "button",
431
+ role: "tab",
432
+ "aria-selected": active === it.id,
433
+ disabled: it.disabled,
434
+ title: it.disabled ? "disabled — enable it in “templates to include”" : void 0,
435
+ onClick: () => onChange(it.id),
436
+ className: `unstyled border-b-2 bg-transparent px-4 py-2 text-[0.9em] font-medium transition-colors ${it.disabled ? "cursor-not-allowed border-transparent text-mocha-light/40" : active === it.id ? "cursor-pointer border-sapphire text-sapphire" : "cursor-pointer border-transparent text-mocha hover:text-sapphire"}`,
437
+ children: it.label
438
+ }, it.id))
439
+ });
440
+ }
441
+ function TemplateTab({ label, hint, value, onChange, rows }) {
442
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
443
+ className: "muted my-2 text-[0.85em]",
444
+ children: hint
445
+ }), /* @__PURE__ */ jsxs("label", { children: [label, /* @__PURE__ */ jsx("textarea", {
446
+ rows,
447
+ value,
448
+ onChange: (e) => onChange(e.target.value),
449
+ className: "font-mono text-[0.88em] leading-[1.55]"
450
+ })] })] });
451
+ }
452
+ //#endregion
453
+ export { ProfilesPage as component };