openclacky 1.3.11 → 1.4.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +59 -0
- data/lib/clacky/agent/session_serializer.rb +11 -4
- data/lib/clacky/agent/skill_manager.rb +1 -0
- data/lib/clacky/agent.rb +4 -5
- data/lib/clacky/brand_config.rb +53 -3
- data/lib/clacky/default_extensions/ext-studio/api/handler.rb +202 -3
- data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +610 -60
- data/lib/clacky/default_skills/media-gen/SKILL.md +182 -7
- data/lib/clacky/default_skills/media-gen/scripts/video_seq.sh +5 -3
- data/lib/clacky/extension/packager.rb +21 -1
- data/lib/clacky/extension/verifier.rb +1 -1
- data/lib/clacky/media/generator.rb +41 -0
- data/lib/clacky/media/volcengine.rb +394 -0
- data/lib/clacky/platform_http_client.rb +9 -7
- data/lib/clacky/providers.rb +4 -4
- data/lib/clacky/server/http_server.rb +67 -22
- data/lib/clacky/tools/grep.rb +6 -1
- data/lib/clacky/tools/terminal.rb +24 -8
- data/lib/clacky/ui2/layout_manager.rb +4 -0
- data/lib/clacky/ui2/screen_buffer.rb +31 -3
- data/lib/clacky/utils/environment_detector.rb +16 -9
- data/lib/clacky/utils/file_processor.rb +30 -28
- data/lib/clacky/utils/model_pricing.rb +49 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky/web/app.css +229 -31
- data/lib/clacky/web/components/onboard.js +14 -4
- data/lib/clacky/web/features/backup/view.js +4 -3
- data/lib/clacky/web/features/extensions/store.js +2 -2
- data/lib/clacky/web/features/extensions/view.js +37 -7
- data/lib/clacky/web/features/mcp/view.js +5 -2
- data/lib/clacky/web/features/skills/view.js +61 -1
- data/lib/clacky/web/features/workspace/store.js +11 -0
- data/lib/clacky/web/features/workspace/view.js +10 -4
- data/lib/clacky/web/i18n.js +14 -2
- data/lib/clacky/web/index.html +29 -13
- data/lib/clacky/web/sessions.js +45 -8
- data/scripts/uninstall.sh +1 -1
- metadata +2 -1
data/lib/clacky/web/app.css
CHANGED
|
@@ -662,11 +662,15 @@ body {
|
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
/* ── New Session button ──────────────────────────────────────────────────── */
|
|
665
|
+
.btn-split-wrap {
|
|
666
|
+
display: flex;
|
|
667
|
+
align-items: stretch;
|
|
668
|
+
}
|
|
665
669
|
.btn-split-main {
|
|
666
670
|
height: 1.5rem;
|
|
667
|
-
padding: 0 0.
|
|
671
|
+
padding: 0 0.6rem;
|
|
668
672
|
border: none;
|
|
669
|
-
border-radius: 6px;
|
|
673
|
+
border-radius: 6px 0 0 6px;
|
|
670
674
|
background: var(--color-accent-primary);
|
|
671
675
|
color: #fff;
|
|
672
676
|
font-size: 0.75rem;
|
|
@@ -674,12 +678,85 @@ body {
|
|
|
674
678
|
white-space: nowrap;
|
|
675
679
|
line-height: 1;
|
|
676
680
|
cursor: pointer;
|
|
681
|
+
display: flex;
|
|
682
|
+
align-items: center;
|
|
683
|
+
gap: 0.3rem;
|
|
677
684
|
transition: background 0.15s, box-shadow 0.15s;
|
|
678
685
|
}
|
|
679
686
|
.btn-split-main:hover {
|
|
680
687
|
background: var(--color-button-primary-hover);
|
|
681
688
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
|
682
689
|
}
|
|
690
|
+
.btn-split-arrow {
|
|
691
|
+
display: flex;
|
|
692
|
+
align-items: center;
|
|
693
|
+
justify-content: center;
|
|
694
|
+
height: 1.5rem;
|
|
695
|
+
width: 1.375rem;
|
|
696
|
+
padding: 0;
|
|
697
|
+
border: none;
|
|
698
|
+
border-left: 1px solid rgba(255,255,255,0.2);
|
|
699
|
+
border-radius: 0 6px 6px 0;
|
|
700
|
+
background: var(--color-accent-primary);
|
|
701
|
+
color: #fff;
|
|
702
|
+
cursor: pointer;
|
|
703
|
+
transition: background 0.15s, box-shadow 0.15s;
|
|
704
|
+
flex-shrink: 0;
|
|
705
|
+
}
|
|
706
|
+
.btn-split-arrow:hover {
|
|
707
|
+
background: var(--color-button-primary-hover);
|
|
708
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
|
709
|
+
}
|
|
710
|
+
.btn-split-dropdown {
|
|
711
|
+
position: relative;
|
|
712
|
+
display: flex;
|
|
713
|
+
}
|
|
714
|
+
.btn-split-menu {
|
|
715
|
+
display: none;
|
|
716
|
+
position: absolute;
|
|
717
|
+
top: calc(100% + 4px);
|
|
718
|
+
right: 0;
|
|
719
|
+
min-width: 9rem;
|
|
720
|
+
background: var(--color-bg-elevated, var(--color-bg-secondary));
|
|
721
|
+
border: 1px solid var(--color-border-secondary);
|
|
722
|
+
border-radius: 8px;
|
|
723
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
|
|
724
|
+
padding: 0.25rem;
|
|
725
|
+
z-index: 200;
|
|
726
|
+
white-space: nowrap;
|
|
727
|
+
}
|
|
728
|
+
/* Bridge the 4px gap so hover doesn't break when moving to the menu */
|
|
729
|
+
.btn-split-menu::before {
|
|
730
|
+
content: "";
|
|
731
|
+
position: absolute;
|
|
732
|
+
top: -8px;
|
|
733
|
+
left: 0;
|
|
734
|
+
right: 0;
|
|
735
|
+
height: 8px;
|
|
736
|
+
}
|
|
737
|
+
.btn-split-dropdown:hover .btn-split-menu {
|
|
738
|
+
display: block;
|
|
739
|
+
}
|
|
740
|
+
.btn-split-menu-item {
|
|
741
|
+
display: flex;
|
|
742
|
+
align-items: center;
|
|
743
|
+
gap: 7px;
|
|
744
|
+
width: 100%;
|
|
745
|
+
padding: 0.375rem 0.75rem;
|
|
746
|
+
border: none;
|
|
747
|
+
border-radius: 5px;
|
|
748
|
+
background: transparent;
|
|
749
|
+
color: var(--color-text-secondary);
|
|
750
|
+
font-size: 0.8125rem;
|
|
751
|
+
font-family: var(--font-sans);
|
|
752
|
+
text-align: left;
|
|
753
|
+
cursor: pointer;
|
|
754
|
+
transition: background 0.12s, color 0.12s;
|
|
755
|
+
}
|
|
756
|
+
.btn-split-menu-item:hover {
|
|
757
|
+
background: var(--color-bg-tertiary);
|
|
758
|
+
color: var(--color-text-primary);
|
|
759
|
+
}
|
|
683
760
|
|
|
684
761
|
/* ── Session source badge ────────────────────────────────────────────────── */
|
|
685
762
|
/* Design: compact neutral chips — the visual weight is carried by the
|
|
@@ -782,7 +859,7 @@ body {
|
|
|
782
859
|
color: var(--color-accent-primary);
|
|
783
860
|
}
|
|
784
861
|
|
|
785
|
-
/* ── Command-palette search overlay
|
|
862
|
+
/* ── Command-palette search overlay ──────────────────────────────────────── */
|
|
786
863
|
.cmd-palette-overlay {
|
|
787
864
|
position: fixed;
|
|
788
865
|
inset: 0;
|
|
@@ -6484,6 +6561,28 @@ body {
|
|
|
6484
6561
|
overflow-y: auto;
|
|
6485
6562
|
}
|
|
6486
6563
|
|
|
6564
|
+
/* ── Skills search ──────────────────────────────────────────────────────── */
|
|
6565
|
+
.skills-search {
|
|
6566
|
+
font-size: 0.8125rem;
|
|
6567
|
+
padding: 0.375rem 0.75rem;
|
|
6568
|
+
border-radius: 6px;
|
|
6569
|
+
border: 1px solid var(--color-border-primary);
|
|
6570
|
+
background: var(--color-bg-secondary);
|
|
6571
|
+
color: var(--color-text-primary);
|
|
6572
|
+
width: 12rem;
|
|
6573
|
+
}
|
|
6574
|
+
.skills-search::placeholder { color: var(--color-text-tertiary); }
|
|
6575
|
+
.skills-search:focus {
|
|
6576
|
+
outline: none;
|
|
6577
|
+
border-color: var(--color-accent, #6366f1);
|
|
6578
|
+
}
|
|
6579
|
+
.skills-search-empty {
|
|
6580
|
+
padding: 2rem 1rem;
|
|
6581
|
+
text-align: center;
|
|
6582
|
+
color: var(--color-text-tertiary);
|
|
6583
|
+
font-size: 0.875rem;
|
|
6584
|
+
}
|
|
6585
|
+
|
|
6487
6586
|
/* ── My Skills upload area (user-licensed only) ───────────────────────────── */
|
|
6488
6587
|
.my-skills-upload-area {
|
|
6489
6588
|
display: flex;
|
|
@@ -7171,7 +7270,7 @@ body {
|
|
|
7171
7270
|
background: var(--color-bg-secondary);
|
|
7172
7271
|
border: 1px solid var(--color-border-primary);
|
|
7173
7272
|
border-radius: 8px;
|
|
7174
|
-
padding: 0.
|
|
7273
|
+
padding: 0.6rem 1rem;
|
|
7175
7274
|
transition: border-color .15s;
|
|
7176
7275
|
}
|
|
7177
7276
|
.extension-card:hover { border-color: var(--color-text-muted); }
|
|
@@ -7184,13 +7283,25 @@ body {
|
|
|
7184
7283
|
font-size: 1.5rem;
|
|
7185
7284
|
line-height: 1.4;
|
|
7186
7285
|
flex-shrink: 0;
|
|
7286
|
+
display: flex;
|
|
7287
|
+
align-items: flex-start;
|
|
7288
|
+
}
|
|
7289
|
+
.extension-default-icon {
|
|
7290
|
+
width: 2rem;
|
|
7291
|
+
height: 100%;
|
|
7292
|
+
display: block;
|
|
7293
|
+
border-radius: 7px;
|
|
7294
|
+
}
|
|
7295
|
+
.extension-emoji-lg .extension-default-icon {
|
|
7296
|
+
width: 2.75rem;
|
|
7297
|
+
height: 2.75rem;
|
|
7298
|
+
border-radius: 10px;
|
|
7187
7299
|
}
|
|
7188
|
-
.extension-info { flex: 1; min-width: 0; }
|
|
7300
|
+
.extension-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
7189
7301
|
.extension-title {
|
|
7190
7302
|
display: flex;
|
|
7191
7303
|
align-items: center;
|
|
7192
7304
|
gap: 0.5rem;
|
|
7193
|
-
margin-bottom: 0.25rem;
|
|
7194
7305
|
flex-wrap: wrap;
|
|
7195
7306
|
}
|
|
7196
7307
|
.extension-name {
|
|
@@ -7203,7 +7314,6 @@ body {
|
|
|
7203
7314
|
color: var(--color-text-secondary);
|
|
7204
7315
|
background: var(--color-bg-tertiary, rgba(255,255,255,0.05));
|
|
7205
7316
|
border-radius: 4px;
|
|
7206
|
-
padding: 0.0625rem 0.375rem;
|
|
7207
7317
|
}
|
|
7208
7318
|
.extension-units {
|
|
7209
7319
|
font-size: 0.6875rem;
|
|
@@ -7234,11 +7344,10 @@ body {
|
|
|
7234
7344
|
font-size: 0.75rem;
|
|
7235
7345
|
color: var(--color-text-secondary);
|
|
7236
7346
|
line-height: 1.5;
|
|
7237
|
-
margin-bottom: 0.375rem;
|
|
7238
7347
|
}
|
|
7239
7348
|
.extension-desc-detail {
|
|
7240
7349
|
font-size: 0.8125rem;
|
|
7241
|
-
margin-bottom: 0
|
|
7350
|
+
margin-bottom: 0;
|
|
7242
7351
|
}
|
|
7243
7352
|
.extension-detail-author {
|
|
7244
7353
|
font-size: 0.6875rem;
|
|
@@ -7300,8 +7409,13 @@ body {
|
|
|
7300
7409
|
padding-bottom: 1.25rem;
|
|
7301
7410
|
border-bottom: 1px solid var(--color-border-primary);
|
|
7302
7411
|
}
|
|
7303
|
-
.extension-detail-heading { flex: 1; min-width: 0; }
|
|
7412
|
+
.extension-detail-heading { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
7304
7413
|
.extension-emoji-lg { font-size: 2.5rem; line-height: 1; margin-top: 0.125rem; }
|
|
7414
|
+
.extension-emoji-lg .extension-default-icon {
|
|
7415
|
+
width: 3.5rem;
|
|
7416
|
+
height: 3.5rem;
|
|
7417
|
+
border-radius: 12px;
|
|
7418
|
+
}
|
|
7305
7419
|
.extension-name-lg { font-size: 1.125rem; font-weight: 700; }
|
|
7306
7420
|
.extension-detail-block { margin-top: 1.5rem; }
|
|
7307
7421
|
.extension-detail-block-title {
|
|
@@ -7309,9 +7423,40 @@ body {
|
|
|
7309
7423
|
font-weight: 600;
|
|
7310
7424
|
text-transform: uppercase;
|
|
7311
7425
|
letter-spacing: 0.04em;
|
|
7312
|
-
color: var(--color-text-muted);
|
|
7313
7426
|
margin: 0 0 0.75rem;
|
|
7314
7427
|
}
|
|
7428
|
+
/* Readme rendered Markdown */
|
|
7429
|
+
.extension-readme-body {
|
|
7430
|
+
font-size: 0.875rem;
|
|
7431
|
+
line-height: 1.7;
|
|
7432
|
+
color: var(--color-text-primary);
|
|
7433
|
+
overflow-wrap: break-word;
|
|
7434
|
+
}
|
|
7435
|
+
.extension-readme-body h1,
|
|
7436
|
+
.extension-readme-body h2,
|
|
7437
|
+
.extension-readme-body h3 { margin: 1em 0 0.4em; font-weight: 600; }
|
|
7438
|
+
.extension-readme-body h1 { font-size: 1.2em; }
|
|
7439
|
+
.extension-readme-body h2 { font-size: 1.05em; }
|
|
7440
|
+
.extension-readme-body h3 { font-size: 0.95em; }
|
|
7441
|
+
.extension-readme-body p { margin: 0 0 0.75em; }
|
|
7442
|
+
.extension-readme-body ul,
|
|
7443
|
+
.extension-readme-body ol { padding-left: 1.4em; margin: 0 0 0.75em; }
|
|
7444
|
+
.extension-readme-body pre {
|
|
7445
|
+
background: var(--color-bg-secondary);
|
|
7446
|
+
border-radius: 6px;
|
|
7447
|
+
padding: 0.75em 1em;
|
|
7448
|
+
overflow-x: auto;
|
|
7449
|
+
font-size: 0.8em;
|
|
7450
|
+
}
|
|
7451
|
+
.extension-readme-body code {
|
|
7452
|
+
background: var(--color-bg-secondary);
|
|
7453
|
+
padding: 0.1em 0.3em;
|
|
7454
|
+
border-radius: 3px;
|
|
7455
|
+
font-size: 0.85em;
|
|
7456
|
+
}
|
|
7457
|
+
.extension-readme-body pre code { background: none; padding: 0; }
|
|
7458
|
+
.extension-readme-body a { color: var(--color-accent); }
|
|
7459
|
+
.extension-readme-body img { max-width: 100%; height: auto; border-radius: 6px; display: block; margin: 8px 0; }
|
|
7315
7460
|
.extension-detail-section { margin-bottom: 0.875rem; }
|
|
7316
7461
|
.extension-detail-section-title {
|
|
7317
7462
|
font-size: 0.6875rem;
|
|
@@ -7371,13 +7516,17 @@ body {
|
|
|
7371
7516
|
border-bottom: 1px solid var(--color-border-primary);
|
|
7372
7517
|
}
|
|
7373
7518
|
.extension-version-row .extension-version {
|
|
7374
|
-
font-size: 0.
|
|
7519
|
+
font-size: 0.8375rem;
|
|
7375
7520
|
font-weight: 700;
|
|
7376
7521
|
color: var(--color-text-primary);
|
|
7377
7522
|
background: none;
|
|
7378
7523
|
padding: 0;
|
|
7379
7524
|
border-radius: 0;
|
|
7380
7525
|
}
|
|
7526
|
+
.extension-version-separator {
|
|
7527
|
+
font-size: 0.8125rem;
|
|
7528
|
+
color: var(--color-text-secondary);
|
|
7529
|
+
}
|
|
7381
7530
|
.extension-version-date {
|
|
7382
7531
|
font-size: 0.6875rem;
|
|
7383
7532
|
color: var(--color-text-muted);
|
|
@@ -7423,7 +7572,7 @@ body {
|
|
|
7423
7572
|
display: flex;
|
|
7424
7573
|
align-items: center;
|
|
7425
7574
|
gap: 0.5rem;
|
|
7426
|
-
margin-top: 0.
|
|
7575
|
+
margin-top: 0.25rem;
|
|
7427
7576
|
}
|
|
7428
7577
|
.extension-disabled {
|
|
7429
7578
|
font-size: 0.6875rem;
|
|
@@ -7631,7 +7780,7 @@ body {
|
|
|
7631
7780
|
color: #ffffff;
|
|
7632
7781
|
border: 1px solid var(--color-accent-primary);
|
|
7633
7782
|
}
|
|
7634
|
-
.btn-brand-update:hover { background: var(--color-
|
|
7783
|
+
.btn-brand-update:hover { background: var(--color-button-primary-hover); }
|
|
7635
7784
|
.btn-brand-install:disabled,
|
|
7636
7785
|
.btn-brand-update:disabled {
|
|
7637
7786
|
opacity: 0.5;
|
|
@@ -10055,7 +10204,7 @@ body.setup-mode[data-theme="dark"] {
|
|
|
10055
10204
|
|
|
10056
10205
|
.memory-card-actions {
|
|
10057
10206
|
display: flex;
|
|
10058
|
-
align-items:
|
|
10207
|
+
align-items: center;
|
|
10059
10208
|
gap: 0.375rem;
|
|
10060
10209
|
flex-shrink: 0;
|
|
10061
10210
|
}
|
|
@@ -10095,6 +10244,7 @@ body.setup-mode[data-theme="dark"] {
|
|
|
10095
10244
|
|
|
10096
10245
|
.btn-memory-expand {
|
|
10097
10246
|
min-width: 1.75rem;
|
|
10247
|
+
align-self: stretch;
|
|
10098
10248
|
justify-content: center;
|
|
10099
10249
|
color: var(--color-text-muted);
|
|
10100
10250
|
}
|
|
@@ -10608,7 +10758,7 @@ body.setup-mode[data-theme="dark"] {
|
|
|
10608
10758
|
|
|
10609
10759
|
/* ── Model Filter ────────────────────────────────────────────────────── */
|
|
10610
10760
|
.billing-model-filter {
|
|
10611
|
-
padding: 0.4375rem 0.75rem;
|
|
10761
|
+
padding: 0.4375rem 1.75rem 0.4375rem 0.75rem;
|
|
10612
10762
|
border: 1px solid var(--color-border-primary);
|
|
10613
10763
|
border-radius: 8px;
|
|
10614
10764
|
background: var(--color-bg-secondary);
|
|
@@ -10616,6 +10766,23 @@ body.setup-mode[data-theme="dark"] {
|
|
|
10616
10766
|
font-size: 0.8125rem;
|
|
10617
10767
|
cursor: pointer;
|
|
10618
10768
|
min-width: 130px;
|
|
10769
|
+
appearance: none;
|
|
10770
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
10771
|
+
background-repeat: no-repeat;
|
|
10772
|
+
background-position: right 0.625rem center;
|
|
10773
|
+
transition: border-color 0.15s ease;
|
|
10774
|
+
}
|
|
10775
|
+
.billing-model-filter:hover {
|
|
10776
|
+
border-color: var(--color-border-strong);
|
|
10777
|
+
}
|
|
10778
|
+
.billing-model-filter:focus {
|
|
10779
|
+
outline: none;
|
|
10780
|
+
border-color: var(--color-accent-primary);
|
|
10781
|
+
box-shadow: 0 0 0 3px var(--color-accent-soft);
|
|
10782
|
+
}
|
|
10783
|
+
.billing-model-filter option {
|
|
10784
|
+
background: var(--color-bg-secondary);
|
|
10785
|
+
color: var(--color-text-primary);
|
|
10619
10786
|
}
|
|
10620
10787
|
|
|
10621
10788
|
/* ── Action Buttons ──────────────────────────────────────────────────── */
|
|
@@ -11374,12 +11541,11 @@ body.setup-mode[data-theme="dark"] {
|
|
|
11374
11541
|
color: var(--color-danger, #c33);
|
|
11375
11542
|
}
|
|
11376
11543
|
.mcp-tools-header {
|
|
11377
|
-
font-size: 0.
|
|
11544
|
+
font-size: 0.8125rem;
|
|
11378
11545
|
font-weight: 600;
|
|
11379
11546
|
color: var(--color-text-secondary);
|
|
11380
11547
|
margin-bottom: 0.5rem;
|
|
11381
|
-
|
|
11382
|
-
letter-spacing: 0.05em;
|
|
11548
|
+
letter-spacing: 0.01em;
|
|
11383
11549
|
}
|
|
11384
11550
|
.mcp-tool-list {
|
|
11385
11551
|
list-style: none;
|
|
@@ -11391,10 +11557,9 @@ body.setup-mode[data-theme="dark"] {
|
|
|
11391
11557
|
}
|
|
11392
11558
|
.mcp-tool-item {
|
|
11393
11559
|
display: flex;
|
|
11394
|
-
|
|
11395
|
-
gap: 0.
|
|
11396
|
-
|
|
11397
|
-
padding: 0.4375rem 0;
|
|
11560
|
+
flex-direction: column;
|
|
11561
|
+
gap: 0.3rem;
|
|
11562
|
+
padding: 0.625rem 0;
|
|
11398
11563
|
border-bottom: 1px solid var(--color-border-primary, var(--color-border));
|
|
11399
11564
|
}
|
|
11400
11565
|
.mcp-tool-item:last-child {
|
|
@@ -11402,18 +11567,15 @@ body.setup-mode[data-theme="dark"] {
|
|
|
11402
11567
|
}
|
|
11403
11568
|
.mcp-tool-name {
|
|
11404
11569
|
font-family: var(--font-mono);
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
border-radius: 4px;
|
|
11408
|
-
font-size: 0.75rem;
|
|
11570
|
+
font-size: 0.8125rem;
|
|
11571
|
+
font-weight: 600;
|
|
11409
11572
|
color: var(--color-text-primary, var(--color-text));
|
|
11410
|
-
flex-shrink: 0;
|
|
11411
|
-
border: 1px solid var(--color-border-primary, var(--color-border));
|
|
11412
11573
|
}
|
|
11413
11574
|
.mcp-tool-desc {
|
|
11414
11575
|
color: var(--color-text-secondary);
|
|
11415
|
-
flex: 1;
|
|
11416
11576
|
line-height: 1.5;
|
|
11577
|
+
font-size: 0.8125rem;
|
|
11578
|
+
opacity: 0.6;
|
|
11417
11579
|
}
|
|
11418
11580
|
|
|
11419
11581
|
/* ── MCP CTA banner & action buttons ─────────────────────────────────── */
|
|
@@ -12398,11 +12560,48 @@ body.setup-mode[data-theme="dark"] {
|
|
|
12398
12560
|
display: none;
|
|
12399
12561
|
}
|
|
12400
12562
|
|
|
12563
|
+
/* Collapse session search into the right-side header actions */
|
|
12564
|
+
#header-center {
|
|
12565
|
+
justify-content: flex-end;
|
|
12566
|
+
padding: 0;
|
|
12567
|
+
}
|
|
12568
|
+
#header-cmdbar {
|
|
12569
|
+
flex: 0 0 1.875rem;
|
|
12570
|
+
width: 1.875rem;
|
|
12571
|
+
max-width: 1.875rem;
|
|
12572
|
+
padding: 0;
|
|
12573
|
+
border: none;
|
|
12574
|
+
border-radius: var(--radius-sm);
|
|
12575
|
+
background: transparent;
|
|
12576
|
+
justify-content: center;
|
|
12577
|
+
gap: 0;
|
|
12578
|
+
margin-right: 0.125rem;
|
|
12579
|
+
}
|
|
12580
|
+
#header-cmdbar:hover {
|
|
12581
|
+
color: var(--color-text-primary);
|
|
12582
|
+
}
|
|
12583
|
+
#header-cmdbar svg {
|
|
12584
|
+
width: 1rem;
|
|
12585
|
+
height: 1rem;
|
|
12586
|
+
opacity: 1;
|
|
12587
|
+
}
|
|
12588
|
+
#header-cmdbar .cmdbar-ph,
|
|
12589
|
+
#header-cmdbar .cmdbar-kbd,
|
|
12590
|
+
#ext-slot-header-right:empty {
|
|
12591
|
+
display: none;
|
|
12592
|
+
}
|
|
12593
|
+
|
|
12401
12594
|
/* Tighten right-side icon gap on mobile */
|
|
12402
12595
|
#header-right {
|
|
12403
12596
|
gap: 0.125rem;
|
|
12404
12597
|
}
|
|
12405
12598
|
|
|
12599
|
+
@media (max-width: 360px) {
|
|
12600
|
+
#top-header {
|
|
12601
|
+
padding: 0 0.375rem;
|
|
12602
|
+
}
|
|
12603
|
+
}
|
|
12604
|
+
|
|
12406
12605
|
/* Session info bar: single-line, no hover-expand, font smaller */
|
|
12407
12606
|
#session-info-bar {
|
|
12408
12607
|
padding: 0.1875rem 0.5rem;
|
|
@@ -12819,4 +13018,3 @@ body.setup-mode[data-theme="dark"] {
|
|
|
12819
13018
|
background: var(--color-bg-primary);
|
|
12820
13019
|
}
|
|
12821
13020
|
}
|
|
12822
|
-
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
const Onboard = (() => {
|
|
18
18
|
let _providers = [];
|
|
19
19
|
let _selectedLang = I18n.lang(); // language chosen during setup
|
|
20
|
+
let _branded = false; // true when running under a brand license
|
|
20
21
|
|
|
21
22
|
// ── Public API ──────────────────────────────────────────────────────────────
|
|
22
23
|
|
|
@@ -27,6 +28,7 @@ const Onboard = (() => {
|
|
|
27
28
|
if (!data.needs_onboard) return { needsOnboard: false, phase: null };
|
|
28
29
|
|
|
29
30
|
const phase = data.phase;
|
|
31
|
+
_branded = !!data.branded;
|
|
30
32
|
|
|
31
33
|
if (phase === "key_setup") {
|
|
32
34
|
// Mandatory: show full-screen setup panel, block boot.
|
|
@@ -111,9 +113,16 @@ const Onboard = (() => {
|
|
|
111
113
|
$("setup-dot-1").className = "setup-step" + (step === "lang" ? " active" : " done");
|
|
112
114
|
$("setup-dot-2").className = "setup-step" + (step === "key" ? " active" : "");
|
|
113
115
|
if (step === "key") {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
if (_branded) {
|
|
117
|
+
// Brand mode: skip the OpenClacky AI Keys card, go straight to manual config
|
|
118
|
+
$("setup-device-block").style.display = "none";
|
|
119
|
+
$("setup-manual-toggle").style.display = "none";
|
|
120
|
+
$("setup-manual-section").style.display = "";
|
|
121
|
+
} else {
|
|
122
|
+
$("setup-device-block").style.display = "";
|
|
123
|
+
$("setup-manual-toggle").style.display = "";
|
|
124
|
+
$("setup-manual-section").style.display = "none";
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
}
|
|
119
128
|
|
|
@@ -379,7 +388,8 @@ const Onboard = (() => {
|
|
|
379
388
|
});
|
|
380
389
|
|
|
381
390
|
$("setup-btn-back").addEventListener("click", () => {
|
|
382
|
-
if ($("setup-manual-section").style.display !== "none") {
|
|
391
|
+
if (!_branded && $("setup-manual-section").style.display !== "none") {
|
|
392
|
+
// Non-brand: collapse manual section back to device card
|
|
383
393
|
$("setup-device-block").style.display = "";
|
|
384
394
|
$("setup-manual-toggle").style.display = "";
|
|
385
395
|
$("setup-manual-section").style.display = "none";
|
|
@@ -58,7 +58,8 @@ const BackupView = (() => {
|
|
|
58
58
|
a.click();
|
|
59
59
|
a.remove();
|
|
60
60
|
URL.revokeObjectURL(url);
|
|
61
|
-
if (statusEl) { statusEl.textContent =
|
|
61
|
+
if (statusEl) { statusEl.textContent = ""; statusEl.className = "model-test-result"; }
|
|
62
|
+
Modal.toast(I18n.t("settings.backup.downloaded"), "success");
|
|
62
63
|
} else if (statusEl) {
|
|
63
64
|
statusEl.textContent = I18n.t("settings.backup.lastError", { msg: res.error });
|
|
64
65
|
statusEl.className = "model-test-result error";
|
|
@@ -108,8 +109,8 @@ const BackupView = (() => {
|
|
|
108
109
|
if (ev.type !== "_ws_connected" || !_restoreStatusEl) return;
|
|
109
110
|
const el = _restoreStatusEl;
|
|
110
111
|
_restoreStatusEl = null;
|
|
111
|
-
el.textContent =
|
|
112
|
-
|
|
112
|
+
if (el) { el.textContent = ""; el.className = "model-test-result"; }
|
|
113
|
+
Modal.toast(I18n.t("settings.backup.restartOk"), "success");
|
|
113
114
|
if (typeof Settings !== "undefined") Settings.open();
|
|
114
115
|
});
|
|
115
116
|
}
|
|
@@ -22,7 +22,7 @@ const ExtensionsStore = (() => {
|
|
|
22
22
|
let _extensions = []; // [{ id, name, name_zh, description, ..., units }]
|
|
23
23
|
let _allExtensions = []; // unfiltered result from server
|
|
24
24
|
let _query = ""; // current search text
|
|
25
|
-
let _sort = "
|
|
25
|
+
let _sort = "downloads"; // "newest" | "updated" | "downloads"
|
|
26
26
|
let _filterInstalled = false; // when true, show only installed extensions
|
|
27
27
|
let _loading = false;
|
|
28
28
|
let _error = null; // soft warning when the store is unreachable
|
|
@@ -102,7 +102,7 @@ const ExtensionsStore = (() => {
|
|
|
102
102
|
|
|
103
103
|
/** Set the sort order and reload. */
|
|
104
104
|
setSort(sort) {
|
|
105
|
-
_sort = sort || "
|
|
105
|
+
_sort = sort || "downloads";
|
|
106
106
|
return Extensions.load();
|
|
107
107
|
},
|
|
108
108
|
|
|
@@ -77,13 +77,27 @@ const ExtensionsView = (() => {
|
|
|
77
77
|
return parts.join(" · ");
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
function _defaultIcon(name, extraClass) {
|
|
81
|
+
const letter = (name || "?")[0].toUpperCase();
|
|
82
|
+
const colors = [
|
|
83
|
+
["#6366f1","#818cf8"], ["#8b5cf6","#a78bfa"], ["#ec4899","#f472b6"],
|
|
84
|
+
["#f59e0b","#fbbf24"], ["#10b981","#34d399"], ["#3b82f6","#60a5fa"],
|
|
85
|
+
["#ef4444","#f87171"], ["#14b8a6","#2dd4bf"],
|
|
86
|
+
];
|
|
87
|
+
const idx = (name || "").charCodeAt(0) % colors.length;
|
|
88
|
+
const [c1, c2] = colors[idx];
|
|
89
|
+
const gid = `eg-${idx}-${Math.random().toString(36).slice(2,7)}`;
|
|
90
|
+
const cls = extraClass ? `extension-emoji ${extraClass}` : "extension-emoji";
|
|
91
|
+
return `<span class="${cls}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="extension-default-icon"><defs><linearGradient id="${gid}" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="${c1}"/><stop offset="100%" stop-color="${c2}"/></linearGradient></defs><rect width="32" height="32" rx="8" fill="url(#${gid})"/><text x="16" y="22" text-anchor="middle" font-family="system-ui,sans-serif" font-size="16" font-weight="700" fill="white">${letter}</text></svg></span>`;
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
function _renderCard(ext) {
|
|
81
95
|
const currentLang = I18n.lang();
|
|
82
|
-
const name = (currentLang === "zh" && ext.
|
|
96
|
+
const name = (currentLang === "zh" && ext.display_name_zh) ? ext.display_name_zh : (ext.display_name || ext.name);
|
|
83
97
|
const description = (currentLang === "zh" && ext.description_zh)
|
|
84
98
|
? ext.description_zh
|
|
85
99
|
: ext.description || "";
|
|
86
|
-
const
|
|
100
|
+
const emojiHtml = ext.emoji ? `<span class="extension-emoji">${escapeHtml(ext.emoji)}</span>` : _defaultIcon(ext.name);
|
|
87
101
|
|
|
88
102
|
const versionHtml = ext.version
|
|
89
103
|
? `<span class="extension-version">v${escapeHtml(String(ext.version))}</span>` : "";
|
|
@@ -110,7 +124,7 @@ const ExtensionsView = (() => {
|
|
|
110
124
|
card.dataset.extId = ext.id != null ? String(ext.id) : (ext.name || "");
|
|
111
125
|
card.innerHTML = `
|
|
112
126
|
<div class="extension-card-main">
|
|
113
|
-
|
|
127
|
+
${emojiHtml}
|
|
114
128
|
<div class="extension-info">
|
|
115
129
|
<div class="extension-title">
|
|
116
130
|
<span class="extension-name">${escapeHtml(name)}</span>
|
|
@@ -229,11 +243,14 @@ const ExtensionsView = (() => {
|
|
|
229
243
|
|
|
230
244
|
function _detailContent(ext) {
|
|
231
245
|
const currentLang = I18n.lang();
|
|
232
|
-
const name = (currentLang === "zh" && ext.
|
|
246
|
+
const name = (currentLang === "zh" && ext.display_name_zh) ? ext.display_name_zh : (ext.display_name || ext.name);
|
|
233
247
|
const description = (currentLang === "zh" && ext.description_zh)
|
|
234
248
|
? ext.description_zh
|
|
235
249
|
: ext.description || "";
|
|
236
250
|
const emoji = ext.emoji || "🧩";
|
|
251
|
+
const detailEmojiHtml = ext.emoji
|
|
252
|
+
? `<span class="extension-emoji extension-emoji-lg">${escapeHtml(ext.emoji)}</span>`
|
|
253
|
+
: _defaultIcon(ext.name, "extension-emoji-lg");
|
|
237
254
|
|
|
238
255
|
const canUpdate = ext.installed && ext.installed_version && ext.version && ext.installed_version !== ext.version;
|
|
239
256
|
const versionHtml = ext.version
|
|
@@ -258,7 +275,7 @@ const ExtensionsView = (() => {
|
|
|
258
275
|
|
|
259
276
|
return `
|
|
260
277
|
<div class="extension-detail-hero">
|
|
261
|
-
|
|
278
|
+
${detailEmojiHtml}
|
|
262
279
|
<div class="extension-detail-heading">
|
|
263
280
|
<div class="extension-title">
|
|
264
281
|
<span class="extension-name extension-name-lg">${escapeHtml(name)}</span>
|
|
@@ -274,10 +291,23 @@ const ExtensionsView = (() => {
|
|
|
274
291
|
${_renderActions(ext)}
|
|
275
292
|
</div>
|
|
276
293
|
</div>
|
|
277
|
-
${
|
|
294
|
+
${_renderReadme(ext.readme)}
|
|
278
295
|
${_renderVersions(ext.versions)}`;
|
|
279
296
|
}
|
|
280
297
|
|
|
298
|
+
// Renders Markdown readme content. Uses marked.js if available, falls back to plain text.
|
|
299
|
+
function _renderReadme(readme) {
|
|
300
|
+
if (!readme || !readme.trim()) return "";
|
|
301
|
+
const html = typeof marked !== "undefined"
|
|
302
|
+
? marked.parse(readme, { breaks: true, gfm: true })
|
|
303
|
+
: `<pre style="white-space:pre-wrap">${escapeHtml(readme)}</pre>`;
|
|
304
|
+
return `
|
|
305
|
+
<div class="extension-detail-block extension-readme">
|
|
306
|
+
<h3 class="extension-detail-block-title">${escapeHtml(I18n.t("extensions.detail.readme"))}</h3>
|
|
307
|
+
<div class="extension-readme-body">${html}</div>
|
|
308
|
+
</div>`;
|
|
309
|
+
}
|
|
310
|
+
|
|
281
311
|
// Manage buttons for a locally installed extension: enable/disable toggle
|
|
282
312
|
// (always available when installed) plus remove (installed layer only).
|
|
283
313
|
function _renderActions(ext) {
|
|
@@ -365,7 +395,7 @@ const ExtensionsView = (() => {
|
|
|
365
395
|
<li class="extension-version-item">
|
|
366
396
|
<div class="extension-version-row">
|
|
367
397
|
<span class="extension-version">v${escapeHtml(String(v.version || ""))}</span>
|
|
368
|
-
${date ? `<span class="extension-version-date">${escapeHtml(date)}</span>` : ""}
|
|
398
|
+
${date ? `<span class="extension-version-separator">-</span><span class="extension-version-date">${escapeHtml(date)}</span>` : ""}
|
|
369
399
|
</div>
|
|
370
400
|
${v.release_notes ? `<div class="extension-version-notes">${typeof marked !== "undefined" ? marked.parse(String(v.release_notes).replace(/^#{1,3}[^\n]*\n?/, ""), { breaks: true, gfm: true }) : escapeHtml(String(v.release_notes))}</div>` : ""}
|
|
371
401
|
</li>`;
|
|
@@ -84,6 +84,11 @@ const McpView = (() => {
|
|
|
84
84
|
|
|
85
85
|
data.servers.forEach(server => {
|
|
86
86
|
list.appendChild(_renderCard(server));
|
|
87
|
+
// _renderTools uses getElementById which requires the card to already be
|
|
88
|
+
// in the DOM, so we call it after appendChild (not inside _renderCard).
|
|
89
|
+
if (McpStore.state.isExpanded(server.name) && !server.disabled) {
|
|
90
|
+
_renderTools(server.name);
|
|
91
|
+
}
|
|
87
92
|
});
|
|
88
93
|
}
|
|
89
94
|
|
|
@@ -170,8 +175,6 @@ const McpView = (() => {
|
|
|
170
175
|
card.querySelector(`#toggle-mcp-${CSS.escape(server.name)}`)
|
|
171
176
|
?.addEventListener("change", (ev) => _toggle(server.name, ev.target.checked));
|
|
172
177
|
|
|
173
|
-
if (isExpanded && !server.disabled) _renderTools(server.name);
|
|
174
|
-
|
|
175
178
|
return card;
|
|
176
179
|
}
|
|
177
180
|
|