@kevin5251984/guild 0.2.17 → 0.2.19
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.
- package/package.json +1 -1
- package/src/catalog/subagents.ts +2 -1
- package/src/chat-parts.ts +6 -1
- package/src/compact.ts +27 -0
- package/src/db.ts +199 -64
- package/src/generate.ts +58 -27
- package/src/handlers.ts +341 -54
- package/src/harness.ts +21 -8
- package/src/image-gen.ts +2 -1
- package/src/llm.ts +400 -58
- package/src/memory.ts +69 -0
- package/src/mention.ts +119 -12
- package/src/oauth.ts +202 -25
- package/src/opencode-free.ts +247 -0
- package/src/public/buddy.js +432 -0
- package/src/public/chat.css +174 -72
- package/src/public/chat.html +212 -43
- package/src/public/i18n.js +41 -6
- package/src/public/index.html +1 -46
- package/src/public/mobile.css +491 -0
- package/src/public/mobile.html +784 -0
- package/src/public/settings.html +188 -27
- package/src/public/skills-add.html +8 -0
- package/src/public/studio.html +171 -117
- package/src/public/style.css +220 -26
- package/src/public/subagents-add.html +8 -0
- package/src/router.ts +76 -5
- package/src/store.ts +161 -5
- package/src/subagent.ts +233 -6
- package/src/tools.ts +124 -18
- package/src/trajectory.ts +72 -9
- package/src/usage.ts +10 -0
- package/vendor/protocol/src/index.ts +14 -1
package/src/public/style.css
CHANGED
|
@@ -840,23 +840,27 @@ a.btn:active { transform: scale(var(--press)); }
|
|
|
840
840
|
color: var(--text);
|
|
841
841
|
font-size: 0.92rem;
|
|
842
842
|
}
|
|
843
|
-
|
|
844
|
-
.aux-row {
|
|
843
|
+
#aux {
|
|
845
844
|
display: grid;
|
|
846
|
-
grid-template-columns:
|
|
847
|
-
gap:
|
|
845
|
+
grid-template-columns: 10.5rem minmax(0, 1fr) max-content;
|
|
846
|
+
column-gap: 1rem;
|
|
848
847
|
align-items: center;
|
|
849
|
-
padding: 0.8rem 0;
|
|
850
|
-
border-top: 1px solid var(--line);
|
|
851
848
|
}
|
|
852
|
-
.aux-head-row
|
|
853
|
-
|
|
849
|
+
.aux-head-row,
|
|
850
|
+
.aux-row { display: contents; }
|
|
851
|
+
.aux-head-row > span {
|
|
854
852
|
padding: 0 0 0.45rem;
|
|
855
853
|
font-size: 0.7rem;
|
|
856
854
|
letter-spacing: 0.07em;
|
|
857
855
|
text-transform: uppercase;
|
|
858
856
|
color: #8b8b8b;
|
|
859
857
|
}
|
|
858
|
+
.aux-task,
|
|
859
|
+
.aux-now,
|
|
860
|
+
.aux-act {
|
|
861
|
+
padding: 0.8rem 0;
|
|
862
|
+
border-top: 1px solid var(--line);
|
|
863
|
+
}
|
|
860
864
|
.aux-task strong { display: block; font-size: 0.95rem; }
|
|
861
865
|
.aux-row .tag {
|
|
862
866
|
display: inline-block;
|
|
@@ -867,10 +871,12 @@ a.btn:active { transform: scale(var(--press)); }
|
|
|
867
871
|
color: #aaa;
|
|
868
872
|
font-size: 0.72rem;
|
|
869
873
|
}
|
|
874
|
+
.aux-now { min-width: 0; }
|
|
870
875
|
.aux-now b {
|
|
871
876
|
display: block;
|
|
872
877
|
font-weight: 600;
|
|
873
878
|
color: var(--text);
|
|
879
|
+
overflow-wrap: break-word;
|
|
874
880
|
}
|
|
875
881
|
.aux-now .id {
|
|
876
882
|
display: block;
|
|
@@ -878,22 +884,37 @@ a.btn:active { transform: scale(var(--press)); }
|
|
|
878
884
|
color: #8b8b8b;
|
|
879
885
|
font-size: 0.75rem;
|
|
880
886
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
887
|
+
overflow-wrap: anywhere;
|
|
881
888
|
}
|
|
882
889
|
.aux-act {
|
|
883
890
|
display: flex;
|
|
884
891
|
align-items: center;
|
|
885
892
|
justify-content: flex-end;
|
|
886
893
|
gap: 0.55rem;
|
|
887
|
-
flex-wrap:
|
|
894
|
+
flex-wrap: nowrap;
|
|
888
895
|
}
|
|
889
896
|
.aux-act .badge { margin-left: 0; }
|
|
897
|
+
.aux-act .linkish { margin: 0; }
|
|
890
898
|
@media (max-width: 720px) {
|
|
899
|
+
#aux { display: block; }
|
|
891
900
|
.aux-head-row { display: none; }
|
|
892
901
|
.aux-row {
|
|
902
|
+
display: grid;
|
|
893
903
|
grid-template-columns: 1fr;
|
|
894
904
|
gap: 0.35rem;
|
|
905
|
+
padding: 0.8rem 0;
|
|
906
|
+
border-top: 1px solid var(--line);
|
|
907
|
+
}
|
|
908
|
+
.aux-task,
|
|
909
|
+
.aux-now,
|
|
910
|
+
.aux-act {
|
|
911
|
+
padding: 0;
|
|
912
|
+
border-top: 0;
|
|
913
|
+
}
|
|
914
|
+
.aux-act {
|
|
915
|
+
justify-content: flex-start;
|
|
916
|
+
flex-wrap: wrap;
|
|
895
917
|
}
|
|
896
|
-
.aux-act { justify-content: flex-start; }
|
|
897
918
|
}
|
|
898
919
|
.linkish {
|
|
899
920
|
background: none;
|
|
@@ -912,6 +933,38 @@ a.btn:active { transform: scale(var(--press)); }
|
|
|
912
933
|
border-radius: 10px;
|
|
913
934
|
letter-spacing: 0.08em;
|
|
914
935
|
}
|
|
936
|
+
.model-head {
|
|
937
|
+
display: flex;
|
|
938
|
+
align-items: center;
|
|
939
|
+
justify-content: flex-start;
|
|
940
|
+
gap: 0.7rem;
|
|
941
|
+
margin: 0.65rem 0 0.15rem;
|
|
942
|
+
}
|
|
943
|
+
.model-head label { margin: 0; }
|
|
944
|
+
.model-head .sync-free {
|
|
945
|
+
margin: 0;
|
|
946
|
+
padding: 0.45rem 1.05rem;
|
|
947
|
+
min-height: 2.2rem;
|
|
948
|
+
min-width: 5.6rem;
|
|
949
|
+
border: 0;
|
|
950
|
+
border-radius: 999px;
|
|
951
|
+
background: var(--paper);
|
|
952
|
+
color: var(--ink);
|
|
953
|
+
font-weight: 650;
|
|
954
|
+
letter-spacing: 0.03em;
|
|
955
|
+
display: inline-flex;
|
|
956
|
+
align-items: center;
|
|
957
|
+
justify-content: center;
|
|
958
|
+
gap: 0.35rem;
|
|
959
|
+
}
|
|
960
|
+
.model-head .sync-free .sync-ico {
|
|
961
|
+
font-size: 1.1rem;
|
|
962
|
+
line-height: 1;
|
|
963
|
+
}
|
|
964
|
+
.model-head .sync-free:hover:not(:disabled) {
|
|
965
|
+
background: color-mix(in srgb, var(--paper) 88%, white);
|
|
966
|
+
color: var(--ink);
|
|
967
|
+
}
|
|
915
968
|
.model-row {
|
|
916
969
|
display: grid;
|
|
917
970
|
grid-template-columns: 1fr 1fr auto;
|
|
@@ -919,6 +972,10 @@ a.btn:active { transform: scale(var(--press)); }
|
|
|
919
972
|
margin-top: 0.4rem;
|
|
920
973
|
align-items: center;
|
|
921
974
|
}
|
|
975
|
+
.model-row:has(.probe-flag) {
|
|
976
|
+
grid-template-columns: 1fr 1fr auto auto;
|
|
977
|
+
}
|
|
978
|
+
.model-row .probe-flag { margin: 0; }
|
|
922
979
|
.model-row button { margin: 0; min-width: 2.2rem; padding: 0.4rem 0.55rem; }
|
|
923
980
|
.row-2 { display: grid; grid-template-columns: 1fr; gap: 0.6rem; }
|
|
924
981
|
@media (min-width: 720px) {
|
|
@@ -1032,6 +1089,12 @@ dialog.pick.add-provider { width: min(32rem, 92vw); }
|
|
|
1032
1089
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
1033
1090
|
letter-spacing: 0.02em;
|
|
1034
1091
|
}
|
|
1092
|
+
.provider-card input[readonly],
|
|
1093
|
+
.provider-card select:disabled {
|
|
1094
|
+
opacity: 0.72;
|
|
1095
|
+
cursor: default;
|
|
1096
|
+
color: var(--muted);
|
|
1097
|
+
}
|
|
1035
1098
|
.card-head {
|
|
1036
1099
|
display: flex;
|
|
1037
1100
|
justify-content: space-between;
|
|
@@ -1084,15 +1147,28 @@ body.app.bar-page .shell {
|
|
|
1084
1147
|
padding: 0 0 0.4rem;
|
|
1085
1148
|
}
|
|
1086
1149
|
.rpg-screen {
|
|
1150
|
+
display: grid;
|
|
1151
|
+
grid-template-rows: auto auto;
|
|
1087
1152
|
position: relative;
|
|
1088
|
-
aspect-ratio: 16 / 9;
|
|
1089
1153
|
overflow: hidden;
|
|
1090
1154
|
background: #000;
|
|
1091
1155
|
border: 4px solid #0a0a12;
|
|
1092
1156
|
box-shadow: 8px 8px 0 #000;
|
|
1093
1157
|
image-rendering: pixelated;
|
|
1094
1158
|
}
|
|
1095
|
-
.rpg-
|
|
1159
|
+
body.bar-page .rpg-screen {
|
|
1160
|
+
background: #1a1410;
|
|
1161
|
+
border-color: #1a1410;
|
|
1162
|
+
box-shadow: 8px 8px 0 #1a1410;
|
|
1163
|
+
}
|
|
1164
|
+
.rpg-scene {
|
|
1165
|
+
grid-row: 1;
|
|
1166
|
+
grid-column: 1;
|
|
1167
|
+
position: relative;
|
|
1168
|
+
aspect-ratio: 16 / 9;
|
|
1169
|
+
min-height: 0;
|
|
1170
|
+
overflow: hidden;
|
|
1171
|
+
}
|
|
1096
1172
|
.rpg-scene[hidden] { display: none; }
|
|
1097
1173
|
.rpg-bg {
|
|
1098
1174
|
display: block;
|
|
@@ -1213,27 +1289,115 @@ body.app.bar-page .shell {
|
|
|
1213
1289
|
background: #2a1c18;
|
|
1214
1290
|
box-shadow: inset 0 0 0 4px #1a100c, inset 0 0 12px #e07020;
|
|
1215
1291
|
}
|
|
1216
|
-
.inn-actors {
|
|
1217
|
-
|
|
1292
|
+
.inn-actors {
|
|
1293
|
+
position: absolute;
|
|
1294
|
+
top: 56px;
|
|
1295
|
+
left: 56px;
|
|
1296
|
+
right: 56px;
|
|
1297
|
+
bottom: 0;
|
|
1298
|
+
z-index: 2;
|
|
1299
|
+
display: grid;
|
|
1300
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
1301
|
+
align-content: start;
|
|
1302
|
+
justify-items: center;
|
|
1303
|
+
gap: 12px 6px;
|
|
1304
|
+
padding: 22px 0 10px;
|
|
1305
|
+
overflow: auto;
|
|
1306
|
+
}
|
|
1307
|
+
.inn-station {
|
|
1308
|
+
position: relative;
|
|
1309
|
+
display: flex;
|
|
1310
|
+
flex-direction: column;
|
|
1311
|
+
align-items: center;
|
|
1312
|
+
width: 88px;
|
|
1313
|
+
z-index: 2;
|
|
1314
|
+
}
|
|
1315
|
+
.inn-desk {
|
|
1316
|
+
order: 2;
|
|
1317
|
+
position: relative;
|
|
1318
|
+
width: 72px;
|
|
1319
|
+
height: 20px;
|
|
1320
|
+
margin-top: -8px;
|
|
1321
|
+
background: #8a5a32;
|
|
1322
|
+
box-shadow: 0 3px 0 #6a4020, 0 5px 0 #3a2414, inset 0 2px 0 #b07a48;
|
|
1323
|
+
z-index: 1;
|
|
1324
|
+
}
|
|
1325
|
+
.inn-monitor {
|
|
1326
|
+
position: absolute;
|
|
1327
|
+
left: 50%;
|
|
1328
|
+
bottom: 14px;
|
|
1329
|
+
width: 28px;
|
|
1330
|
+
height: 18px;
|
|
1331
|
+
margin-left: -14px;
|
|
1332
|
+
background: #1a1a1a;
|
|
1333
|
+
box-shadow: 0 0 0 2px #111;
|
|
1334
|
+
}
|
|
1335
|
+
.inn-monitor::after {
|
|
1336
|
+
content: "";
|
|
1218
1337
|
position: absolute;
|
|
1338
|
+
inset: 3px 3px 4px;
|
|
1339
|
+
background: repeating-linear-gradient(#7ec8e8 0 2px, #4aa3c8 2px 4px);
|
|
1340
|
+
}
|
|
1341
|
+
.inn-station:has(.rpg-npc.vacant) .inn-monitor::after { background: #2a2a2a; }
|
|
1342
|
+
.rpg-npc {
|
|
1343
|
+
position: relative;
|
|
1219
1344
|
display: flex;
|
|
1220
1345
|
flex-direction: column;
|
|
1221
1346
|
align-items: center;
|
|
1347
|
+
order: 1;
|
|
1222
1348
|
margin: 0;
|
|
1223
1349
|
padding: 0;
|
|
1224
1350
|
border: 0;
|
|
1225
1351
|
background: transparent;
|
|
1226
1352
|
color: inherit;
|
|
1227
|
-
transform: translate(-50%, -88%);
|
|
1228
1353
|
cursor: pointer;
|
|
1229
1354
|
z-index: 2;
|
|
1230
1355
|
}
|
|
1231
|
-
.rpg-npc
|
|
1232
|
-
|
|
1356
|
+
.rpg-npc .npc-bust,
|
|
1357
|
+
.rpg-npc .npc-blank {
|
|
1358
|
+
width: 72px;
|
|
1233
1359
|
height: 72px;
|
|
1360
|
+
box-sizing: border-box;
|
|
1361
|
+
border: 3px solid #1a1410;
|
|
1362
|
+
background: #2a2118;
|
|
1363
|
+
box-shadow: 2px 3px 0 #0006;
|
|
1364
|
+
}
|
|
1365
|
+
.rpg-npc .npc-bust {
|
|
1366
|
+
object-fit: cover;
|
|
1367
|
+
object-position: center 18%;
|
|
1368
|
+
display: block;
|
|
1234
1369
|
image-rendering: pixelated;
|
|
1235
|
-
|
|
1236
|
-
|
|
1370
|
+
}
|
|
1371
|
+
.rpg-npc .npc-blank {
|
|
1372
|
+
display: grid;
|
|
1373
|
+
place-items: center;
|
|
1374
|
+
color: #f0d9a0;
|
|
1375
|
+
font-family: VT323, ui-monospace, monospace;
|
|
1376
|
+
font-size: 28px;
|
|
1377
|
+
line-height: 1;
|
|
1378
|
+
}
|
|
1379
|
+
.rpg-npc.drawing .npc-bust,
|
|
1380
|
+
.rpg-npc.drawing .npc-blank {
|
|
1381
|
+
filter: brightness(1.25) drop-shadow(0 0 6px #f0d060);
|
|
1382
|
+
}
|
|
1383
|
+
.npc-state {
|
|
1384
|
+
position: absolute;
|
|
1385
|
+
top: 0;
|
|
1386
|
+
left: 50%;
|
|
1387
|
+
z-index: 4;
|
|
1388
|
+
padding: 0 5px;
|
|
1389
|
+
background: #f4ead7;
|
|
1390
|
+
color: #1a1410;
|
|
1391
|
+
font-family: VT323, ui-monospace, monospace;
|
|
1392
|
+
font-size: 14px;
|
|
1393
|
+
line-height: 1.2;
|
|
1394
|
+
white-space: nowrap;
|
|
1395
|
+
box-shadow: 2px 2px 0 #1a1410;
|
|
1396
|
+
transform: translate(-50%, calc(-100% - 4px));
|
|
1397
|
+
}
|
|
1398
|
+
.npc-state.live {
|
|
1399
|
+
background: var(--signal);
|
|
1400
|
+
color: #1a1410;
|
|
1237
1401
|
}
|
|
1238
1402
|
.rpg-npc .tag {
|
|
1239
1403
|
margin-top: 2px;
|
|
@@ -1245,10 +1409,22 @@ body.app.bar-page .shell {
|
|
|
1245
1409
|
line-height: 1.1;
|
|
1246
1410
|
white-space: nowrap;
|
|
1247
1411
|
}
|
|
1248
|
-
.rpg-npc:hover
|
|
1249
|
-
.rpg-npc.
|
|
1250
|
-
.rpg-npc.
|
|
1412
|
+
.rpg-npc:hover .npc-bust,
|
|
1413
|
+
.rpg-npc:hover .npc-blank { filter: brightness(1.18) drop-shadow(0 0 6px #f0d060); }
|
|
1414
|
+
.rpg-npc.on .npc-bust,
|
|
1415
|
+
.rpg-npc.on .npc-blank { outline: 2px solid #f0d060; outline-offset: 1px; }
|
|
1416
|
+
.rpg-npc.vacant .npc-blank { opacity: 0.55; }
|
|
1251
1417
|
.rpg-npc.vacant .tag { color: #f0d060; }
|
|
1418
|
+
@media (max-width: 720px) {
|
|
1419
|
+
.inn-actors {
|
|
1420
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
1421
|
+
left: 24px;
|
|
1422
|
+
right: 24px;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
@media (max-width: 520px) {
|
|
1426
|
+
.inn-actors { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
1427
|
+
}
|
|
1252
1428
|
.rpg-exit {
|
|
1253
1429
|
position: absolute;
|
|
1254
1430
|
left: 10px;
|
|
@@ -1270,20 +1446,34 @@ body.app.bar-page .shell {
|
|
|
1270
1446
|
transform: none;
|
|
1271
1447
|
}
|
|
1272
1448
|
.rpg-dialog {
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
right: 3.5%;
|
|
1276
|
-
bottom: 3%;
|
|
1449
|
+
grid-row: 2;
|
|
1450
|
+
position: relative;
|
|
1277
1451
|
z-index: 5;
|
|
1452
|
+
margin: 8px 12px 10px;
|
|
1278
1453
|
padding: 3px;
|
|
1279
1454
|
background: #08080f;
|
|
1280
1455
|
box-shadow: 0 0 0 2px #c9a227, inset 0 0 0 2px #3a4a8a;
|
|
1281
1456
|
}
|
|
1282
1457
|
.rpg-dialog-inner {
|
|
1458
|
+
display: flex;
|
|
1459
|
+
align-items: flex-start;
|
|
1460
|
+
gap: 10px;
|
|
1283
1461
|
min-height: 92px;
|
|
1284
1462
|
padding: 10px 14px 8px;
|
|
1285
1463
|
background: linear-gradient(#2a3668, #1a2248 55%, #141a3a);
|
|
1286
1464
|
}
|
|
1465
|
+
.rpg-face {
|
|
1466
|
+
flex: none;
|
|
1467
|
+
width: 56px;
|
|
1468
|
+
height: 56px;
|
|
1469
|
+
object-fit: cover;
|
|
1470
|
+
object-position: center 18%;
|
|
1471
|
+
border: 3px solid #1a1410;
|
|
1472
|
+
background: #2a2118;
|
|
1473
|
+
image-rendering: pixelated;
|
|
1474
|
+
}
|
|
1475
|
+
.rpg-face[hidden] { display: none; }
|
|
1476
|
+
.rpg-copy { min-width: 0; flex: 1; }
|
|
1287
1477
|
.rpg-name {
|
|
1288
1478
|
margin: 0 0 6px;
|
|
1289
1479
|
color: #f0d060;
|
|
@@ -1298,18 +1488,22 @@ body.app.bar-page .shell {
|
|
|
1298
1488
|
font-family: VT323, ui-monospace, monospace;
|
|
1299
1489
|
font-size: 22px;
|
|
1300
1490
|
line-height: 1.2;
|
|
1491
|
+
overflow-wrap: anywhere;
|
|
1301
1492
|
}
|
|
1302
1493
|
.rpg-acts {
|
|
1303
1494
|
display: flex;
|
|
1495
|
+
flex-wrap: wrap;
|
|
1304
1496
|
gap: 8px;
|
|
1305
1497
|
margin-top: 8px;
|
|
1306
1498
|
min-height: 22px;
|
|
1307
1499
|
}
|
|
1308
1500
|
.rpg-acts a,
|
|
1309
1501
|
.rpg-acts button {
|
|
1502
|
+
appearance: none;
|
|
1310
1503
|
margin: 0;
|
|
1311
1504
|
padding: 3px 8px;
|
|
1312
1505
|
border: 2px solid #c9a227;
|
|
1506
|
+
border-radius: 0;
|
|
1313
1507
|
background: #141a3a;
|
|
1314
1508
|
color: #f4f0e0;
|
|
1315
1509
|
font-family: VT323, ui-monospace, monospace;
|
|
@@ -91,7 +91,12 @@
|
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
const button = document.getElementById("ai-generate");
|
|
94
|
+
if (button.disabled || button.getAttribute("aria-busy") === "true") return;
|
|
94
95
|
button.disabled = true;
|
|
96
|
+
button.setAttribute("aria-busy", "true");
|
|
97
|
+
button.classList.add("is-busy");
|
|
98
|
+
const idle = button.textContent;
|
|
99
|
+
button.textContent = t("studio.generating");
|
|
95
100
|
try {
|
|
96
101
|
const response = await fetch("/generate", {
|
|
97
102
|
method: "POST",
|
|
@@ -115,6 +120,9 @@
|
|
|
115
120
|
setFlash("error", err.message);
|
|
116
121
|
} finally {
|
|
117
122
|
button.disabled = false;
|
|
123
|
+
button.removeAttribute("aria-busy");
|
|
124
|
+
button.classList.remove("is-busy");
|
|
125
|
+
button.textContent = idle;
|
|
118
126
|
}
|
|
119
127
|
});
|
|
120
128
|
document.getElementById("ai-save").addEventListener("click", async () => {
|
package/src/router.ts
CHANGED
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
addChannelMember,
|
|
7
7
|
createBot,
|
|
8
8
|
createChannel,
|
|
9
|
+
createBranch,
|
|
10
|
+
closeBranch,
|
|
9
11
|
deleteBot,
|
|
10
12
|
deleteChannel,
|
|
11
13
|
renameChannel,
|
|
@@ -18,6 +20,7 @@ import {
|
|
|
18
20
|
setChannelMemory,
|
|
19
21
|
generateKind,
|
|
20
22
|
pickBotSkills,
|
|
23
|
+
generateBotLook,
|
|
21
24
|
getBotDetail,
|
|
22
25
|
getLiveTurn,
|
|
23
26
|
abortLiveTurn,
|
|
@@ -25,6 +28,7 @@ import {
|
|
|
25
28
|
importSkills,
|
|
26
29
|
mergeModelsFile,
|
|
27
30
|
publicModels,
|
|
31
|
+
refreshOpenCodeFreeCatalog,
|
|
28
32
|
listBench,
|
|
29
33
|
listLibrary,
|
|
30
34
|
listMcpServers,
|
|
@@ -73,10 +77,13 @@ const PAGES: Record<string, { file: string; type: string }> = {
|
|
|
73
77
|
"/studio": { file: "studio.html", type: "text/html; charset=utf-8" },
|
|
74
78
|
"/skills/add": { file: "skills-add.html", type: "text/html; charset=utf-8" },
|
|
75
79
|
"/chat": { file: "chat.html", type: "text/html; charset=utf-8" },
|
|
80
|
+
"/m": { file: "mobile.html", type: "text/html; charset=utf-8" },
|
|
76
81
|
"/style.css": { file: "style.css", type: "text/css; charset=utf-8" },
|
|
77
82
|
"/chat.css": { file: "chat.css", type: "text/css; charset=utf-8" },
|
|
83
|
+
"/mobile.css": { file: "mobile.css", type: "text/css; charset=utf-8" },
|
|
78
84
|
"/md.js": { file: "md.js", type: "text/javascript; charset=utf-8" },
|
|
79
85
|
"/i18n.js": { file: "i18n.js", type: "text/javascript; charset=utf-8" },
|
|
86
|
+
"/buddy.js": { file: "buddy.js", type: "text/javascript; charset=utf-8" },
|
|
80
87
|
"/favicon.ico": { file: "favicon.ico", type: "image/x-icon" },
|
|
81
88
|
"/favicon.svg": { file: "favicon.svg", type: "image/svg+xml" },
|
|
82
89
|
"/favicon-16.svg": { file: "favicon-16.svg", type: "image/svg+xml" },
|
|
@@ -180,6 +187,16 @@ function strList(record: Record<string, unknown>, key: string): string[] {
|
|
|
180
187
|
return [];
|
|
181
188
|
}
|
|
182
189
|
|
|
190
|
+
function extrasWithMentions(
|
|
191
|
+
extras: HandlerExtras,
|
|
192
|
+
body: Record<string, unknown>,
|
|
193
|
+
): HandlerExtras {
|
|
194
|
+
const mentions = strList(body, "mentions")
|
|
195
|
+
.map((id) => id.trim())
|
|
196
|
+
.filter(Boolean);
|
|
197
|
+
return mentions.length ? { ...extras, mentions } : extras;
|
|
198
|
+
}
|
|
199
|
+
|
|
183
200
|
function skillPickCatalog(
|
|
184
201
|
record: Record<string, unknown>,
|
|
185
202
|
): { id: string; name: string; description?: string; tags?: string[]; slug?: string }[] {
|
|
@@ -258,7 +275,12 @@ export async function handleRequest(
|
|
|
258
275
|
}
|
|
259
276
|
|
|
260
277
|
if (method === "GET" && page) {
|
|
261
|
-
const
|
|
278
|
+
const file = `${PUBLIC}${page.file}`;
|
|
279
|
+
if (!existsSync(file)) {
|
|
280
|
+
json(res, 404, { error: "not_found", path });
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const body = readFileSync(file);
|
|
262
284
|
const extra = page.type.startsWith("image/")
|
|
263
285
|
? { "cache-control": "public, max-age=86400" }
|
|
264
286
|
: {};
|
|
@@ -352,6 +374,36 @@ export async function handleRequest(
|
|
|
352
374
|
json(res, 201, createChannel(store, str(body, "name")));
|
|
353
375
|
return;
|
|
354
376
|
}
|
|
377
|
+
const channelBranch = path.match(/^\/channels\/([^/]+)\/branches$/);
|
|
378
|
+
if (channelBranch && method === "POST") {
|
|
379
|
+
const body = asRecord(await readJson(req));
|
|
380
|
+
json(
|
|
381
|
+
res,
|
|
382
|
+
201,
|
|
383
|
+
createBranch(
|
|
384
|
+
store,
|
|
385
|
+
decodeURIComponent(channelBranch[1]),
|
|
386
|
+
str(body, "messageId"),
|
|
387
|
+
str(body, "name") || undefined,
|
|
388
|
+
),
|
|
389
|
+
);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const channelClose = path.match(/^\/channels\/([^/]+)\/close$/);
|
|
393
|
+
if (channelClose && method === "POST") {
|
|
394
|
+
const body = asRecord(await readJson(req));
|
|
395
|
+
json(
|
|
396
|
+
res,
|
|
397
|
+
200,
|
|
398
|
+
await closeBranch(
|
|
399
|
+
store,
|
|
400
|
+
decodeURIComponent(channelClose[1]),
|
|
401
|
+
body.merge === true,
|
|
402
|
+
env,
|
|
403
|
+
),
|
|
404
|
+
);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
355
407
|
const channelOne = path.match(/^\/channels\/([^/]+)$/);
|
|
356
408
|
if (channelOne && method === "DELETE") {
|
|
357
409
|
json(res, 200, deleteChannel(store, decodeURIComponent(channelOne[1])));
|
|
@@ -480,7 +532,7 @@ export async function handleRequest(
|
|
|
480
532
|
str(body, "body") || undefined,
|
|
481
533
|
env,
|
|
482
534
|
str(body, "assigneeId") || undefined,
|
|
483
|
-
extras,
|
|
535
|
+
extrasWithMentions(extras, body),
|
|
484
536
|
),
|
|
485
537
|
);
|
|
486
538
|
return;
|
|
@@ -502,7 +554,7 @@ export async function handleRequest(
|
|
|
502
554
|
str(body, "body") || undefined,
|
|
503
555
|
env,
|
|
504
556
|
str(body, "assigneeId") || undefined,
|
|
505
|
-
extras,
|
|
557
|
+
extrasWithMentions(extras, body),
|
|
506
558
|
),
|
|
507
559
|
);
|
|
508
560
|
return;
|
|
@@ -639,7 +691,7 @@ export async function handleRequest(
|
|
|
639
691
|
str(body, "replyTo") || undefined,
|
|
640
692
|
parseAttachments(body.attachments),
|
|
641
693
|
str(body, "assigneeId") || undefined,
|
|
642
|
-
extras,
|
|
694
|
+
extrasWithMentions(extras, body),
|
|
643
695
|
),
|
|
644
696
|
);
|
|
645
697
|
return;
|
|
@@ -665,7 +717,7 @@ export async function handleRequest(
|
|
|
665
717
|
str(body, "replyTo") || undefined,
|
|
666
718
|
parseAttachments(body.attachments),
|
|
667
719
|
str(body, "assigneeId") || undefined,
|
|
668
|
-
extras,
|
|
720
|
+
extrasWithMentions(extras, body),
|
|
669
721
|
),
|
|
670
722
|
);
|
|
671
723
|
return;
|
|
@@ -806,9 +858,18 @@ export async function handleRequest(
|
|
|
806
858
|
|
|
807
859
|
if (method === "GET" && path === "/settings/models") {
|
|
808
860
|
await refreshCopilotCatalog(store.dataDir);
|
|
861
|
+
await refreshOpenCodeFreeCatalog(store.dataDir);
|
|
809
862
|
json(res, 200, publicModels(store.dataDir));
|
|
810
863
|
return;
|
|
811
864
|
}
|
|
865
|
+
if (method === "POST" && path === "/settings/models/opencode-free/sync") {
|
|
866
|
+
const refreshed = await refreshOpenCodeFreeCatalog(store.dataDir, true);
|
|
867
|
+
json(res, 200, {
|
|
868
|
+
...publicModels(store.dataDir),
|
|
869
|
+
probe: refreshed.probe ?? [],
|
|
870
|
+
});
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
812
873
|
if (method === "PUT" && path === "/settings/models") {
|
|
813
874
|
const body = asRecord(await readJson(req));
|
|
814
875
|
const providers = body.providers;
|
|
@@ -891,6 +952,12 @@ export async function handleRequest(
|
|
|
891
952
|
return;
|
|
892
953
|
}
|
|
893
954
|
|
|
955
|
+
const lookId = path.match(/^\/bots\/([^/]+)\/look$/)?.[1];
|
|
956
|
+
if (lookId && method === "POST") {
|
|
957
|
+
json(res, 200, await generateBotLook(store, decodeURIComponent(lookId), env));
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
|
|
894
961
|
const botId = path.match(/^\/bots\/([^/]+)$/)?.[1];
|
|
895
962
|
if (botId && method === "GET") {
|
|
896
963
|
json(res, 200, getBotDetail(store, botId));
|
|
@@ -906,6 +973,9 @@ export async function handleRequest(
|
|
|
906
973
|
name: str(body, "name") || undefined,
|
|
907
974
|
handle: str(body, "handle") || undefined,
|
|
908
975
|
oneLiner: str(body, "oneLiner") || undefined,
|
|
976
|
+
...(Object.hasOwn(body, "portrait")
|
|
977
|
+
? { portrait: body.portrait == null ? null : str(body, "portrait") }
|
|
978
|
+
: {}),
|
|
909
979
|
skillIds: Object.hasOwn(body, "skillIds")
|
|
910
980
|
? strList(body, "skillIds")
|
|
911
981
|
: undefined,
|
|
@@ -962,6 +1032,7 @@ export async function handleRequest(
|
|
|
962
1032
|
json(res, error.status, { error: error.message });
|
|
963
1033
|
return;
|
|
964
1034
|
}
|
|
1035
|
+
console.error(error);
|
|
965
1036
|
json(res, 500, { error: "internal_error" });
|
|
966
1037
|
}
|
|
967
1038
|
}
|