@aiyiran/myclaw 1.0.227 → 1.0.229

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.
@@ -62,7 +62,7 @@
62
62
  btn.id = 'myclaw-artifacts-btn';
63
63
  btn.style.cssText = [
64
64
  'position: fixed',
65
- 'top: 200px',
65
+ 'top: 0px',
66
66
  'right: 0',
67
67
  'padding: 3px 10px',
68
68
  'background: rgba(100, 100, 100, 0.7)',
@@ -107,10 +107,10 @@
107
107
  panel.id = 'myclaw-artifacts-panel';
108
108
  panel.style.cssText = [
109
109
  'position: fixed',
110
- 'top: 230px',
110
+ 'top: 30px',
111
111
  'right: 0',
112
112
  'width: 380px',
113
- 'max-height: calc(100vh - 250px)',
113
+ 'max-height: calc(100vh - 550px)',
114
114
  'background: #1e1e2e',
115
115
  'border-radius: 8px 0 0 8px',
116
116
  'overflow: hidden',
@@ -627,14 +627,18 @@
627
627
  body: JSON.stringify(payload),
628
628
  })
629
629
  .then(function (res) { return res.json(); })
630
- .then(function (data) {
631
- console.log('[myclaw-artifacts-publish]', payload, data);
630
+ .then(function (result) {
631
+ console.log('[myclaw-artifacts-publish]', payload, result);
632
+ if (result.code !== 0) {
633
+ throw new Error(result.msg || '\u53D1\u5E03\u5931\u8D25');
634
+ }
632
635
  localStorage.setItem('myclaw-publish-cache', JSON.stringify({
633
636
  title: titleVal,
634
637
  cover_path: coverSelect.value || '',
635
638
  entry_path: entrySelect.value || '',
636
639
  }));
637
640
  closePublishModal();
641
+ openPublishSuccessModal(result.data);
638
642
  })
639
643
  .catch(function (err) {
640
644
  console.error('[myclaw-artifacts-publish] \u53D1\u5E03\u5931\u8D25:', err);
@@ -650,6 +654,579 @@
650
654
  document.body.appendChild(overlay);
651
655
  }
652
656
 
657
+ // ═══ 发布成功弹框 ═══
658
+ function openPublishSuccessModal(data) {
659
+ if (document.querySelector('#myclaw-publish-success')) return;
660
+
661
+ var overlay = document.createElement('div');
662
+ overlay.id = 'myclaw-publish-success';
663
+ overlay.style.cssText = [
664
+ 'position: fixed',
665
+ 'top: 0',
666
+ 'left: 0',
667
+ 'width: 100vw',
668
+ 'height: 100vh',
669
+ 'background: rgba(0, 0, 0, 0.5)',
670
+ 'z-index: 99999',
671
+ 'display: flex',
672
+ 'align-items: center',
673
+ 'justify-content: center',
674
+ 'animation: myclaw-fade-in 0.2s ease',
675
+ ].join(';');
676
+
677
+ var box = document.createElement('div');
678
+ box.style.cssText = [
679
+ 'width: 440px',
680
+ 'background: #1e1e2e',
681
+ 'border-radius: 12px',
682
+ 'overflow: hidden',
683
+ 'display: flex',
684
+ 'flex-direction: column',
685
+ 'box-shadow: 0 12px 48px rgba(0,0,0,0.6)',
686
+ 'animation: myclaw-success-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1)',
687
+ ].join(';');
688
+
689
+ // 头部:庆祝动画区
690
+ var hero = document.createElement('div');
691
+ hero.style.cssText = [
692
+ 'padding: 28px 24px 18px',
693
+ 'text-align: center',
694
+ 'background: linear-gradient(135deg, #2d2d5f 0%, #1e1e2e 100%)',
695
+ ].join(';');
696
+
697
+ // emoji 庆祝
698
+ var emoji = document.createElement('div');
699
+ emoji.style.cssText = 'font-size: 48px;margin-bottom:8px;';
700
+ emoji.textContent = '\uD83C\uDF89';
701
+ hero.appendChild(emoji);
702
+
703
+ // 版本号大字
704
+ var versionNum = document.createElement('div');
705
+ versionNum.style.cssText = [
706
+ 'font-size: 52px',
707
+ 'font-weight: 900',
708
+ 'font-family: monospace',
709
+ 'color: #a78bfa',
710
+ 'line-height: 1',
711
+ 'text-shadow: 0 0 20px rgba(167,139,250,0.4)',
712
+ ].join(';');
713
+ versionNum.textContent = 'v' + (data.version || '?');
714
+ hero.appendChild(versionNum);
715
+
716
+ var versionLabel = document.createElement('div');
717
+ versionLabel.style.cssText = 'font-size:12px;color:#888;margin-top:4px;font-family:monospace;';
718
+ versionLabel.textContent = '\u53D1\u5E03\u6210\u529F\uFF01';
719
+ hero.appendChild(versionLabel);
720
+
721
+ box.appendChild(hero);
722
+
723
+ // 信息区
724
+ var info = document.createElement('div');
725
+ info.style.cssText = 'padding:20px 24px;display:flex;flex-direction:column;gap:14px;';
726
+
727
+ // 作品标题
728
+ if (data.title) {
729
+ var titleRow = createInfoRow('\uD83C\uDFA8 \u4F5C\u54C1', data.title);
730
+ info.appendChild(titleRow);
731
+ }
732
+
733
+ // 封面
734
+ if (data.cover_path) {
735
+ var coverRow = createInfoRow('\uD83D\uDCF7 \u5C01\u9762', data.cover_path);
736
+ info.appendChild(coverRow);
737
+ }
738
+
739
+ // 入口文件
740
+ if (data.entry_path) {
741
+ var entryRow = createInfoRow('\uD83D\uDD17 \u5165\u53E3', data.entry_path);
742
+ info.appendChild(entryRow);
743
+ }
744
+
745
+ // 分割线
746
+ var divider = document.createElement('div');
747
+ divider.style.cssText = 'border-top:1px solid #3d3d5c;';
748
+ info.appendChild(divider);
749
+
750
+ // 分享链接区
751
+ var shareSection = document.createElement('div');
752
+ shareSection.style.cssText = 'display:flex;flex-direction:column;gap:8px;';
753
+
754
+ var shareLabel = document.createElement('div');
755
+ shareLabel.style.cssText = 'font-size:12px;color:#888;font-family:monospace;';
756
+ shareLabel.textContent = '\uD83D\uDD17 \u6C38\u4E45\u94FE\u63A5';
757
+ shareSection.appendChild(shareLabel);
758
+
759
+ var shareRow = document.createElement('div');
760
+ shareRow.style.cssText = 'display:flex;gap:8px;align-items:center;';
761
+
762
+ var urlInput = document.createElement('input');
763
+ urlInput.type = 'text';
764
+ urlInput.readOnly = true;
765
+ urlInput.value = data.permanent_url || '';
766
+ urlInput.style.cssText = [
767
+ 'flex: 1',
768
+ 'padding: 8px 10px',
769
+ 'background: #252536',
770
+ 'border: 1px solid #3d3d5c',
771
+ 'border-radius: 4px',
772
+ 'color: #cdd6f4',
773
+ 'font-size: 11px',
774
+ 'font-family: monospace',
775
+ 'outline: none',
776
+ 'overflow: hidden',
777
+ 'text-overflow: ellipsis',
778
+ ].join(';');
779
+ shareRow.appendChild(urlInput);
780
+
781
+ var copyBtn = document.createElement('button');
782
+ copyBtn.textContent = '\u590D\u5236\u94FE\u63A5';
783
+ copyBtn.style.cssText = [
784
+ 'padding: 8px 14px',
785
+ 'background: #a78bfa',
786
+ 'border: none',
787
+ 'border-radius: 4px',
788
+ 'color: #fff',
789
+ 'font-size: 12px',
790
+ 'font-family: monospace',
791
+ 'font-weight: bold',
792
+ 'cursor: pointer',
793
+ 'white-space: nowrap',
794
+ 'transition: background 0.15s',
795
+ ].join(';');
796
+ copyBtn.onmouseenter = function () { copyBtn.style.background = '#8b5cf6'; };
797
+ copyBtn.onmouseleave = function () { copyBtn.style.background = '#a78bfa'; };
798
+ copyBtn.onclick = function () {
799
+ navigator.clipboard.writeText(data.permanent_url || '').then(function () {
800
+ copyBtn.textContent = '\u2713 \u5DF2\u590D\u5236';
801
+ copyBtn.style.background = '#10b981';
802
+ setTimeout(function () {
803
+ copyBtn.textContent = '\u590D\u5236\u94FE\u63A5';
804
+ copyBtn.style.background = '#a78bfa';
805
+ }, 2000);
806
+ });
807
+ };
808
+ shareRow.appendChild(copyBtn);
809
+
810
+ shareSection.appendChild(shareRow);
811
+ info.appendChild(shareSection);
812
+
813
+ // 二维码区
814
+ if (data.permanent_url) {
815
+ var qrSection = document.createElement('div');
816
+ qrSection.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:6px;padding-top:4px;';
817
+
818
+ var qrCanvas = document.createElement('canvas');
819
+ qrCanvas.style.cssText = 'width:140px;height:140px;border-radius:6px;background:#fff;padding:8px;';
820
+ try {
821
+ generateQR(qrCanvas, data.permanent_url, 140);
822
+ } catch (e) {
823
+ console.warn('[myclaw-artifacts] QR generate error:', e);
824
+ qrCanvas.style.display = 'none';
825
+ }
826
+ qrSection.appendChild(qrCanvas);
827
+
828
+ var qrHint = document.createElement('div');
829
+ qrHint.style.cssText = 'font-size:11px;color:#888;font-family:monospace;';
830
+ qrHint.textContent = '\u626B\u7801\u67E5\u770B\u4F5C\u54C1';
831
+ qrSection.appendChild(qrHint);
832
+
833
+ info.appendChild(qrSection);
834
+ }
835
+
836
+ box.appendChild(info);
837
+
838
+ // 关闭按钮
839
+ var footer = document.createElement('div');
840
+ footer.style.cssText = 'padding: 0 24px 20px;text-align:center;';
841
+
842
+ var closeSuccessBtn = document.createElement('button');
843
+ closeSuccessBtn.textContent = '\u5F00\u5FC3\uFF01';
844
+ closeSuccessBtn.style.cssText = [
845
+ 'padding: 10px 40px',
846
+ 'background: #4a4a7a',
847
+ 'border: none',
848
+ 'border-radius: 6px',
849
+ 'color: #cdd6f4',
850
+ 'font-size: 14px',
851
+ 'font-family: monospace',
852
+ 'cursor: pointer',
853
+ 'transition: background 0.15s',
854
+ ].join(';');
855
+ closeSuccessBtn.onmouseenter = function () { closeSuccessBtn.style.background = '#5a5a9a'; };
856
+ closeSuccessBtn.onmouseleave = function () { closeSuccessBtn.style.background = '#4a4a7a'; };
857
+ closeSuccessBtn.onclick = function () {
858
+ var m = document.querySelector('#myclaw-publish-success');
859
+ if (m) m.remove();
860
+ };
861
+ footer.appendChild(closeSuccessBtn);
862
+ box.appendChild(footer);
863
+
864
+ overlay.appendChild(box);
865
+ document.body.appendChild(overlay);
866
+ }
867
+
868
+ function createInfoRow(label, value) {
869
+ var row = document.createElement('div');
870
+ row.style.cssText = 'display:flex;align-items:baseline;gap:8px;font-family:monospace;font-size:13px;';
871
+ var lbl = document.createElement('span');
872
+ lbl.style.cssText = 'color:#888;white-space:nowrap;flex-shrink:0;min-width:80px;';
873
+ lbl.textContent = label;
874
+ var val = document.createElement('span');
875
+ val.style.cssText = 'color:#cdd6f4;word-break:break-all;';
876
+ val.textContent = value;
877
+ row.appendChild(lbl);
878
+ row.appendChild(val);
879
+ return row;
880
+ }
881
+
882
+ // ═══ 轻量 QR 码生成(纯 JS,无依赖) ═══
883
+ // 基于 qrcode-generator (MIT) 的核心算法精简版
884
+ function generateQR(canvas, text, size) {
885
+ // 使用 Google Charts API 的轻量替代:用 img 加载 QR 码
886
+ // 但为了避免外部依赖,这里使用内嵌的极简 QR 生成
887
+ var QR = (function() {
888
+ // QR Code Model 2 - 极简实现
889
+ var ErrorCorrectionLevel = { L: 1, M: 0, Q: 3, H: 2 };
890
+
891
+ function QRCode(typeNumber, errorCorrectionLevel) {
892
+ this.typeNumber = typeNumber;
893
+ this.errorCorrectionLevel = errorCorrectionLevel;
894
+ this.modules = null;
895
+ this.moduleCount = 0;
896
+ this.dataCache = null;
897
+ this.dataList = [];
898
+ }
899
+
900
+ QRCode.prototype = {
901
+ addData: function(data) { this.dataList.push(new QR8bitByte(data)); this.dataCache = null; },
902
+ isDark: function(row, col) { if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) throw new Error(row + "," + col); return this.modules[row][col]; },
903
+ getModuleCount: function() { return this.moduleCount; },
904
+ make: function() { this.makeImpl(false, this.getBestMaskPattern()); },
905
+ makeImpl: function(test, maskPattern) {
906
+ this.moduleCount = this.typeNumber * 4 + 17;
907
+ this.modules = new Array(this.moduleCount);
908
+ for (var row = 0; row < this.moduleCount; row++) {
909
+ this.modules[row] = new Array(this.moduleCount);
910
+ for (var col = 0; col < this.moduleCount; col++) { this.modules[row][col] = null; }
911
+ }
912
+ this.setupPositionProbePattern(0, 0);
913
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
914
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
915
+ this.setupPositionAdjustPattern();
916
+ this.setupTimingPattern();
917
+ this.setupTypeInfo(test, maskPattern);
918
+ if (this.typeNumber >= 7) this.setupTypeNumber(test);
919
+ if (this.dataCache == null) this.dataCache = createData(this.typeNumber, this.errorCorrectionLevel, this.dataList);
920
+ this.mapData(this.dataCache, maskPattern);
921
+ },
922
+ setupPositionProbePattern: function(row, col) {
923
+ for (var r = -1; r <= 7; r++) {
924
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
925
+ for (var c = -1; c <= 7; c++) {
926
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
927
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
928
+ this.modules[row + r][col + c] = true;
929
+ } else {
930
+ this.modules[row + r][col + c] = false;
931
+ }
932
+ }
933
+ }
934
+ },
935
+ getBestMaskPattern: function() {
936
+ var minLostPoint = 0, pattern = 0;
937
+ for (var i = 0; i < 8; i++) {
938
+ this.makeImpl(true, i);
939
+ var lostPoint = QRUtil.getLostPoint(this);
940
+ if (i == 0 || minLostPoint > lostPoint) { minLostPoint = lostPoint; pattern = i; }
941
+ }
942
+ return pattern;
943
+ },
944
+ setupTimingPattern: function() {
945
+ for (var r = 8; r < this.moduleCount - 8; r++) { if (this.modules[r][6] != null) continue; this.modules[r][6] = (r % 2 == 0); }
946
+ for (var c = 8; c < this.moduleCount - 8; c++) { if (this.modules[6][c] != null) continue; this.modules[6][c] = (c % 2 == 0); }
947
+ },
948
+ setupPositionAdjustPattern: function() {
949
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
950
+ for (var i = 0; i < pos.length; i++) {
951
+ for (var j = 0; j < pos.length; j++) {
952
+ var row = pos[i], col = pos[j];
953
+ if (this.modules[row][col] != null) continue;
954
+ for (var r = -2; r <= 2; r++) {
955
+ for (var c = -2; c <= 2; c++) {
956
+ if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
957
+ this.modules[row + r][col + c] = true;
958
+ } else {
959
+ this.modules[row + r][col + c] = false;
960
+ }
961
+ }
962
+ }
963
+ }
964
+ }
965
+ },
966
+ setupTypeNumber: function(test) {
967
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
968
+ for (var i = 0; i < 18; i++) {
969
+ var mod = (!test && ((bits >> i) & 1) == 1);
970
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
971
+ }
972
+ for (var i = 0; i < 18; i++) {
973
+ var mod = (!test && ((bits >> i) & 1) == 1);
974
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
975
+ }
976
+ },
977
+ setupTypeInfo: function(test, maskPattern) {
978
+ var data = (this.errorCorrectionLevel << 3) | maskPattern;
979
+ var bits = QRUtil.getBCHTypeInfo(data);
980
+ for (var i = 0; i < 15; i++) {
981
+ var mod = (!test && ((bits >> i) & 1) == 1);
982
+ if (i < 6) { this.modules[i][8] = mod; }
983
+ else if (i < 8) { this.modules[i + 1][8] = mod; }
984
+ else { this.modules[this.moduleCount - 15 + i][8] = mod; }
985
+ }
986
+ for (var i = 0; i < 15; i++) {
987
+ var mod = (!test && ((bits >> i) & 1) == 1);
988
+ if (i < 8) { this.modules[8][this.moduleCount - i - 1] = mod; }
989
+ else if (i < 9) { this.modules[8][15 - i - 1 + 1] = mod; }
990
+ else { this.modules[8][15 - i - 1] = mod; }
991
+ }
992
+ this.modules[this.moduleCount - 8][8] = (!test);
993
+ },
994
+ mapData: function(data, maskPattern) {
995
+ var inc = -1, row = this.moduleCount - 1, bitIndex = 7, byteIndex = 0;
996
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
997
+ if (col == 6) col--;
998
+ while (true) {
999
+ for (var c = 0; c < 2; c++) {
1000
+ if (this.modules[row][col - c] == null) {
1001
+ var dark = false;
1002
+ if (byteIndex < data.length) { dark = (((data[byteIndex] >>> bitIndex) & 1) == 1); }
1003
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
1004
+ if (mask) dark = !dark;
1005
+ this.modules[row][col - c] = dark;
1006
+ bitIndex--;
1007
+ if (bitIndex == -1) { byteIndex++; bitIndex = 7; }
1008
+ }
1009
+ }
1010
+ row += inc;
1011
+ if (row < 0 || this.moduleCount <= row) { row -= inc; inc = -inc; break; }
1012
+ }
1013
+ }
1014
+ }
1015
+ };
1016
+
1017
+ var QRUtil = {
1018
+ PATTERN_POSITION_TABLE: [[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],
1019
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
1020
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
1021
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
1022
+ getBCHTypeInfo: function(data) {
1023
+ var d = data << 10;
1024
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15))); }
1025
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
1026
+ },
1027
+ getBCHTypeNumber: function(data) {
1028
+ var d = data << 12;
1029
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18))); }
1030
+ return (data << 12) | d;
1031
+ },
1032
+ getBCHDigit: function(data) { var digit = 0; while (data != 0) { digit++; data >>>= 1; } return digit; },
1033
+ getPatternPosition: function(typeNumber) { return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; },
1034
+ getMask: function(maskPattern, i, j) {
1035
+ switch (maskPattern) {
1036
+ case 0: return (i + j) % 2 == 0;
1037
+ case 1: return i % 2 == 0;
1038
+ case 2: return j % 3 == 0;
1039
+ case 3: return (i + j) % 3 == 0;
1040
+ case 4: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
1041
+ case 5: return (i * j) % 2 + (i * j) % 3 == 0;
1042
+ case 6: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
1043
+ case 7: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
1044
+ default: throw new Error("bad maskPattern:" + maskPattern);
1045
+ }
1046
+ },
1047
+ getErrorCorrectPolynomial: function(errorCorrectLength) {
1048
+ var a = new QRPolynomial([1], 0);
1049
+ for (var i = 0; i < errorCorrectLength; i++) { a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)); }
1050
+ return a;
1051
+ },
1052
+ getLengthInBits: function(mode, type) {
1053
+ if (1 <= type && type < 10) { switch(mode) { case 1: return 10; case 2: return 9; case 4: return 8; case 8: return 8; default: throw new Error("mode:" + mode); } }
1054
+ else if (type < 27) { switch(mode) { case 1: return 12; case 2: return 11; case 4: return 16; case 8: return 10; default: throw new Error("mode:" + mode); } }
1055
+ else if (type < 41) { switch(mode) { case 1: return 14; case 2: return 13; case 4: return 16; case 8: return 12; default: throw new Error("mode:" + mode); } }
1056
+ else { throw new Error("type:" + type); }
1057
+ },
1058
+ getLostPoint: function(qrCode) {
1059
+ var moduleCount = qrCode.getModuleCount(), lostPoint = 0;
1060
+ for (var row = 0; row < moduleCount; row++) { for (var col = 0; col < moduleCount; col++) { var sameCount = 0, dark = qrCode.isDark(row, col); for (var r = -1; r <= 1; r++) { if (row + r < 0 || moduleCount <= row + r) continue; for (var c = -1; c <= 1; c++) { if (col + c < 0 || moduleCount <= col + c) continue; if (r == 0 && c == 0) continue; if (dark == qrCode.isDark(row + r, col + c)) sameCount++; } } if (sameCount > 5) lostPoint += (3 + sameCount - 5); } }
1061
+ for (var row = 0; row < moduleCount - 1; row++) { for (var col = 0; col < moduleCount - 1; col++) { var count = 0; if (qrCode.isDark(row, col)) count++; if (qrCode.isDark(row + 1, col)) count++; if (qrCode.isDark(row, col + 1)) count++; if (qrCode.isDark(row + 1, col + 1)) count++; if (count == 0 || count == 4) lostPoint += 3; } }
1062
+ for (var row = 0; row < moduleCount; row++) { for (var col = 0; col < moduleCount - 6; col++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) lostPoint += 40; } }
1063
+ for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount - 6; row++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) lostPoint += 40; } }
1064
+ var darkCount = 0; for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount; row++) { if (qrCode.isDark(row, col)) darkCount++; } } var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; lostPoint += ratio * 10;
1065
+ return lostPoint;
1066
+ }
1067
+ };
1068
+
1069
+ var QRMath = {
1070
+ glog: function(n) { if (n < 1) throw new Error("glog(" + n + ")"); var r = QRMath.LOG_TABLE[n]; if (r == null) throw new Error("glog(" + n + ")"); return r; },
1071
+ gexp: function(n) { while (n < 0) n += 255; while (n >= 256) n -= 255; return QRMath.EXP_TABLE[n]; },
1072
+ EXP_TABLE: new Array(256), LOG_TABLE: new Array(256)
1073
+ };
1074
+ for (var i = 0; i < 8; i++) QRMath.EXP_TABLE[i] = 1 << i;
1075
+ for (var i = 8; i < 256; i++) QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
1076
+ for (var i = 0; i < 255; i++) QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
1077
+
1078
+ function QRPolynomial(num, shift) {
1079
+ if (num.length == undefined) throw new Error(num.length + "/" + shift);
1080
+ var offset = 0;
1081
+ while (offset < num.length && num[offset] == 0) offset++;
1082
+ this.num = new Array(num.length - offset + shift);
1083
+ for (var i = 0; i < num.length - offset; i++) this.num[i] = num[i + offset];
1084
+ }
1085
+ QRPolynomial.prototype = {
1086
+ get: function(index) { return this.num[index]; },
1087
+ getLength: function() { return this.num.length; },
1088
+ multiply: function(e) {
1089
+ var num = new Array(this.getLength() + e.getLength() - 1);
1090
+ for (var i = 0; i < this.getLength(); i++) for (var j = 0; j < e.getLength(); j++) num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
1091
+ return new QRPolynomial(num, 0);
1092
+ },
1093
+ mod: function(e) {
1094
+ if (this.getLength() - e.getLength() < 0) return this;
1095
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
1096
+ var num = new Array(this.getLength());
1097
+ for (var i = 0; i < this.getLength(); i++) num[i] = this.get(i);
1098
+ for (var i = 0; i < e.getLength(); i++) num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
1099
+ return new QRPolynomial(num, 0).mod(e);
1100
+ }
1101
+ };
1102
+
1103
+ function QR8bitByte(data) { this.mode = 4; this.data = data; }
1104
+ QR8bitByte.prototype = {
1105
+ getLength: function() { return this.data.length; },
1106
+ write: function(buffer) {
1107
+ for (var i = 0; i < this.data.length; i++) {
1108
+ var c = this.data.charCodeAt(i);
1109
+ if (c < 0x80) { buffer.put(c, 8); }
1110
+ else if (c < 0x800) { buffer.put(0xC0 | (c >> 6), 8); buffer.put(0x80 | (c & 0x3F), 8); }
1111
+ else if (c >= 0xD800 && c <= 0xDBFF) {
1112
+ var c2 = this.data.charCodeAt(++i);
1113
+ if (isNaN(c2)) throw new Error("invalid utf8");
1114
+ var code = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
1115
+ buffer.put(0xF0 | (code >> 18), 8); buffer.put(0x80 | ((code >> 12) & 0x3F), 8);
1116
+ buffer.put(0x80 | ((code >> 6) & 0x3F), 8); buffer.put(0x80 | (code & 0x3F), 8);
1117
+ } else {
1118
+ buffer.put(0xE0 | (c >> 12), 8); buffer.put(0x80 | ((c >> 6) & 0x3F), 8); buffer.put(0x80 | (c & 0x3F), 8);
1119
+ }
1120
+ }
1121
+ }
1122
+ };
1123
+
1124
+ var QRCodeLimitCount = [[0,26,44,70,100,134,172,196,242,292,346],[0,22,38,60,84,108,132,154,180,213,251],[0,16,32,48,68,88,112,136,160,192,224]];
1125
+
1126
+ function createData(typeNumber, errorCorrectionLevel, dataList) {
1127
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel);
1128
+ var buffer = new QRBitBuffer();
1129
+ for (var i = 0; i < dataList.length; i++) {
1130
+ var data = dataList[i];
1131
+ buffer.put(data.mode, 4);
1132
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
1133
+ data.write(buffer);
1134
+ }
1135
+ var totalDataCount = 0;
1136
+ for (var i = 0; i < rsBlocks.length; i++) totalDataCount += rsBlocks[i].dataCount;
1137
+ if (buffer.getLengthInBits() > totalDataCount * 8) throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
1138
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) buffer.put(0, 4);
1139
+ while (buffer.getLengthInBits() % 8 != 0) buffer.putBit(false);
1140
+ while (true) {
1141
+ if (buffer.getLengthInBits() >= totalDataCount * 8) break;
1142
+ buffer.put(0xEC, 8);
1143
+ if (buffer.getLengthInBits() >= totalDataCount * 8) break;
1144
+ buffer.put(0x11, 8);
1145
+ }
1146
+ return createBytes(buffer, rsBlocks);
1147
+ }
1148
+
1149
+ function createBytes(buffer, rsBlocks) {
1150
+ var offset = 0, maxDcCount = 0, maxEcCount = 0, dcdata = new Array(rsBlocks.length), ecdata = new Array(rsBlocks.length);
1151
+ for (var r = 0; r < rsBlocks.length; r++) {
1152
+ var dcCount = rsBlocks[r].dataCount, ecCount = rsBlocks[r].totalCount - dcCount;
1153
+ maxDcCount = Math.max(maxDcCount, dcCount);
1154
+ maxEcCount = Math.max(maxEcCount, ecCount);
1155
+ dcdata[r] = new Array(dcCount);
1156
+ for (var i = 0; i < dcdata[r].length; i++) dcdata[r][i] = 0xff & buffer.buffer[i + offset];
1157
+ offset += dcCount;
1158
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
1159
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
1160
+ var modPoly = rawPoly.mod(rsPoly);
1161
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
1162
+ for (var i = 0; i < ecdata[r].length; i++) {
1163
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
1164
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
1165
+ }
1166
+ }
1167
+ var totalCodeCount = 0;
1168
+ for (var i = 0; i < rsBlocks.length; i++) totalCodeCount += rsBlocks[i].totalCount;
1169
+ var data = new Array(totalCodeCount), index = 0;
1170
+ for (var i = 0; i < maxDcCount; i++) for (var r = 0; r < rsBlocks.length; r++) if (i < dcdata[r].length) data[index++] = dcdata[r][i];
1171
+ for (var i = 0; i < maxEcCount; i++) for (var r = 0; r < rsBlocks.length; r++) if (i < ecdata[r].length) data[index++] = ecdata[r][i];
1172
+ return data;
1173
+ }
1174
+
1175
+ var QR_RS_BLOCK_TABLE = [[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];
1176
+
1177
+ var QRRSBlock = {
1178
+ getRSBlocks: function(typeNumber, errorCorrectionLevel) {
1179
+ var rsBlock = QR_RS_BLOCK_TABLE[(typeNumber - 1) * 4 + errorCorrectionLevel];
1180
+ if (rsBlock == undefined) throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectionLevel:" + errorCorrectionLevel);
1181
+ var length = rsBlock.length / 3, list = [];
1182
+ for (var i = 0; i < length; i++) {
1183
+ var count = rsBlock[i * 3 + 0], totalCount = rsBlock[i * 3 + 1], dataCount = rsBlock[i * 3 + 2];
1184
+ for (var j = 0; j < count; j++) list.push({ totalCount: totalCount, dataCount: dataCount });
1185
+ }
1186
+ return list;
1187
+ }
1188
+ };
1189
+
1190
+ function QRBitBuffer() { this.buffer = []; this.length = 0; }
1191
+ QRBitBuffer.prototype = {
1192
+ get: function(index) { var bufIndex = Math.floor(index / 8); return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1; },
1193
+ put: function(num, length) { for (var i = 0; i < length; i++) this.putBit(((num >>> (length - i - 1)) & 1) == 1); },
1194
+ getLengthInBits: function() { return this.length; },
1195
+ putBit: function(bit) { var bufIndex = Math.floor(this.length / 8); if (this.buffer.length <= bufIndex) this.buffer.push(0); if (bit) this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)); this.length++; }
1196
+ };
1197
+
1198
+ return QRCode;
1199
+ })();
1200
+
1201
+ // 自动选择合适的 typeNumber
1202
+ var qr;
1203
+ for (var tn = 1; tn <= 40; tn++) {
1204
+ try {
1205
+ qr = new QR(tn, 0); // M level
1206
+ qr.addData(text);
1207
+ qr.make();
1208
+ break;
1209
+ } catch (e) { qr = null; }
1210
+ }
1211
+ if (!qr) throw new Error("QR code too large");
1212
+
1213
+ var moduleCount = qr.getModuleCount();
1214
+ var cellSize = size / moduleCount;
1215
+ canvas.width = size;
1216
+ canvas.height = size;
1217
+ var ctx = canvas.getContext('2d');
1218
+ ctx.fillStyle = '#ffffff';
1219
+ ctx.fillRect(0, 0, size, size);
1220
+ ctx.fillStyle = '#1e1e2e';
1221
+ for (var row = 0; row < moduleCount; row++) {
1222
+ for (var col = 0; col < moduleCount; col++) {
1223
+ if (qr.isDark(row, col)) {
1224
+ ctx.fillRect(Math.floor(col * cellSize), Math.floor(row * cellSize), Math.ceil(cellSize), Math.ceil(cellSize));
1225
+ }
1226
+ }
1227
+ }
1228
+ }
1229
+
653
1230
  function closePublishModal() {
654
1231
  var modal = document.querySelector('#myclaw-artifacts-publish-modal');
655
1232
  if (modal) modal.remove();
@@ -669,6 +1246,10 @@
669
1246
  ' from { opacity: 0; }',
670
1247
  ' to { opacity: 1; }',
671
1248
  '}',
1249
+ '@keyframes myclaw-success-pop {',
1250
+ ' from { transform: scale(0.7); opacity: 0; }',
1251
+ ' to { transform: scale(1); opacity: 1; }',
1252
+ '}',
672
1253
  ].join('\n');
673
1254
  document.head.appendChild(style);
674
1255
  }
@@ -581,11 +581,237 @@
581
581
  console.log("[myclaw-send] 📋 已复制(fallback)");
582
582
  }
583
583
 
584
+ // ═══ 7. Socket.IO 命令工具 ═══
585
+
586
+ var cmdSocket = null;
587
+ var cmdSocketReady = false;
588
+
589
+ function ensureSocketIO(callback) {
590
+ if (cmdSocketReady) { callback(); return; }
591
+ if (window.io) { connectCmdSocket(callback); return; }
592
+
593
+ var s = document.createElement("script");
594
+ s.src = window.location.origin + "/cmd/socket.io/socket.io.js";
595
+ s.onload = function () { connectCmdSocket(callback); };
596
+ s.onerror = function () { console.error("[myclaw-cmd] socket.io-client 加载失败"); };
597
+ document.head.appendChild(s);
598
+ }
599
+
600
+ function connectCmdSocket(callback) {
601
+ if (cmdSocket) { cmdSocketReady = true; callback(); return; }
602
+ cmdSocket = window.io("/cmd", { path: "/cmd/socket.io/", transports: ["websocket", "polling"] });
603
+ cmdSocket.on("connect", function () {
604
+ cmdSocketReady = true;
605
+ console.log("[myclaw-cmd] Socket.IO 已连接, sid=" + cmdSocket.id);
606
+ callback();
607
+ });
608
+ cmdSocket.on("disconnect", function () {
609
+ cmdSocketReady = false;
610
+ console.log("[myclaw-cmd] Socket.IO 已断开");
611
+ });
612
+ }
613
+
614
+ function runCommand(cmd) {
615
+ ensureSocketIO(function () {
616
+ cmdSocket.emit("run_command", { cmd: cmd, runId: Date.now() });
617
+ console.log("[myclaw-cmd] 已发送: " + cmd);
618
+ });
619
+ }
620
+
621
+ // ═══ 8. 右下角"命令"按钮 ═══
622
+
623
+ var commandOpen = false;
624
+
625
+ function createCommandButton() {
626
+ if (document.querySelector("#myclaw-command-btn")) return;
627
+
628
+ var btn = document.createElement("div");
629
+ btn.id = "myclaw-command-btn";
630
+ btn.style.cssText = [
631
+ "position: fixed",
632
+ "bottom: 8px",
633
+ "right: 260px",
634
+ "padding: 3px 10px",
635
+ "background: rgba(16, 185, 129, 0.85)",
636
+ "color: #fff",
637
+ "font-size: 11px",
638
+ "font-weight: bold",
639
+ "font-family: monospace",
640
+ "border-radius: 4px",
641
+ "z-index: 99999",
642
+ "user-select: none",
643
+ "cursor: pointer",
644
+ "transition: all 0.2s",
645
+ "letter-spacing: 0.5px",
646
+ ].join(";");
647
+ btn.textContent = "\u2795 \u547D\u4EE4";
648
+ btn.title = "\u5FEB\u6377\u547D\u4EE4";
649
+
650
+ btn.onmouseenter = function () { btn.style.background = "rgba(5, 150, 105, 1)"; btn.style.transform = "scale(1.05)"; };
651
+ btn.onmouseleave = function () { if (!commandOpen) { btn.style.background = "rgba(16, 185, 129, 0.85)"; } btn.style.transform = "scale(1)"; };
652
+ btn.onclick = function (e) {
653
+ e.stopPropagation();
654
+ if (commandOpen) {
655
+ closeCommandModal();
656
+ } else {
657
+ openCommandModal();
658
+ }
659
+ };
660
+
661
+ document.body.appendChild(btn);
662
+ }
663
+
664
+ function openCommandModal() {
665
+ if (document.querySelector("#myclaw-command-modal")) return;
666
+ commandOpen = true;
667
+
668
+ var btn = document.querySelector("#myclaw-command-btn");
669
+ if (btn) btn.style.background = "rgba(5, 150, 105, 1)";
670
+
671
+ // 遮罩
672
+ var overlay = document.createElement("div");
673
+ overlay.id = "myclaw-command-modal";
674
+ overlay.style.cssText = [
675
+ "position: fixed",
676
+ "top: 0",
677
+ "left: 0",
678
+ "width: 100vw",
679
+ "height: 100vh",
680
+ "background: rgba(0, 0, 0, 0.4)",
681
+ "z-index: 99998",
682
+ "display: flex",
683
+ "align-items: center",
684
+ "justify-content: center",
685
+ "animation: myclaw-fade-in 0.15s ease",
686
+ ].join(";");
687
+
688
+ var box = document.createElement("div");
689
+ box.style.cssText = [
690
+ "width: 400px",
691
+ "background: #1e1e2e",
692
+ "border-radius: 8px",
693
+ "overflow: hidden",
694
+ "box-shadow: 0 8px 32px rgba(0,0,0,0.5)",
695
+ ].join(";");
696
+
697
+ // 标题栏
698
+ var header = document.createElement("div");
699
+ header.style.cssText = [
700
+ "display: flex",
701
+ "align-items: center",
702
+ "justify-content: space-between",
703
+ "padding: 10px 14px",
704
+ "background: #2d2d3f",
705
+ "color: #cdd6f4",
706
+ "font-size: 13px",
707
+ "font-family: monospace",
708
+ "user-select: none",
709
+ ].join(";");
710
+ header.innerHTML = '<span>\u2795 \u547D\u4EE4</span>';
711
+
712
+ var closeBtn = document.createElement("span");
713
+ closeBtn.textContent = "\u2715";
714
+ closeBtn.style.cssText = "cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;";
715
+ closeBtn.onmouseenter = function () { closeBtn.style.background = "rgba(255,255,255,0.1)"; };
716
+ closeBtn.onmouseleave = function () { closeBtn.style.background = "none"; };
717
+ closeBtn.onclick = function () { closeCommandModal(); };
718
+ header.appendChild(closeBtn);
719
+
720
+ // 内容区
721
+ var form = document.createElement("div");
722
+ form.style.cssText = "padding: 20px;display:flex;flex-direction:column;gap:14px;color:#cdd6f4;font-family:monospace;font-size:13px;";
723
+
724
+ // 添加对话
725
+ var addGroup = document.createElement("div");
726
+ addGroup.style.cssText = "display:flex;flex-direction:column;gap:6px;";
727
+
728
+ var addLabel = document.createElement("div");
729
+ addLabel.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
730
+ addLabel.style.cssText = "font-size:13px;font-weight:bold;color:#10b981;";
731
+ addGroup.appendChild(addLabel);
732
+
733
+ var addDesc = document.createElement("div");
734
+ addDesc.textContent = "\u8F93\u5165 agent-name\uFF0C\u70B9\u51FB\u6267\u884C mc tui <name>";
735
+ addDesc.style.cssText = "font-size:11px;color:#888;";
736
+ addGroup.appendChild(addDesc);
737
+
738
+ var addRow = document.createElement("div");
739
+ addRow.style.cssText = "display:flex;gap:8px;";
740
+
741
+ var agentInput = document.createElement("input");
742
+ agentInput.type = "text";
743
+ agentInput.placeholder = "agent-name";
744
+ agentInput.style.cssText = "flex:1;padding:8px 10px;background:#252536;border:1px solid #3d3d5c;border-radius:4px;color:#cdd6f4;font-size:13px;font-family:monospace;outline:none;";
745
+ agentInput.onfocus = function () { agentInput.style.borderColor = "#10b981"; };
746
+ agentInput.onblur = function () { agentInput.style.borderColor = "#3d3d5c"; };
747
+
748
+ var addBtn = document.createElement("button");
749
+ addBtn.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
750
+ addBtn.style.cssText = "padding:8px 16px;background:#10b981;border:none;border-radius:4px;color:#fff;font-size:12px;font-family:monospace;cursor:pointer;transition:background 0.15s;white-space:nowrap;";
751
+ addBtn.onmouseenter = function () { addBtn.style.background = "#059669"; };
752
+ addBtn.onmouseleave = function () { addBtn.style.background = "#10b981"; };
753
+ addBtn.onclick = function () {
754
+ var val = agentInput.value.trim();
755
+ if (!val) {
756
+ agentInput.style.borderColor = "#ff4444";
757
+ agentInput.focus();
758
+ return;
759
+ }
760
+ // 只允许字母、数字、连字符
761
+ if (!/^[a-zA-Z0-9\-]+$/.test(val)) {
762
+ agentInput.style.borderColor = "#ff4444";
763
+ agentInput.focus();
764
+ return;
765
+ }
766
+ addBtn.disabled = true;
767
+ addBtn.textContent = "\u6267\u884C\u4E2D...";
768
+ runCommand("mc tui " + val);
769
+ setTimeout(function () {
770
+ addBtn.disabled = false;
771
+ addBtn.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
772
+ agentInput.value = "";
773
+ }, 1000);
774
+ };
775
+
776
+ // 回车也触发
777
+ agentInput.onkeydown = function (e) {
778
+ if (e.key === "Enter") { addBtn.click(); }
779
+ };
780
+
781
+ addRow.appendChild(agentInput);
782
+ addRow.appendChild(addBtn);
783
+ addGroup.appendChild(addRow);
784
+ form.appendChild(addGroup);
785
+
786
+ box.appendChild(header);
787
+ box.appendChild(form);
788
+ overlay.appendChild(box);
789
+
790
+ overlay.onclick = function (e) {
791
+ if (e.target === overlay) closeCommandModal();
792
+ };
793
+
794
+ document.body.appendChild(overlay);
795
+
796
+ // 自动聚焦
797
+ setTimeout(function () { agentInput.focus(); }, 100);
798
+ }
799
+
800
+ function closeCommandModal() {
801
+ var modal = document.querySelector("#myclaw-command-modal");
802
+ if (modal) modal.remove();
803
+ commandOpen = false;
804
+
805
+ var btn = document.querySelector("#myclaw-command-btn");
806
+ if (btn) btn.style.background = "rgba(16, 185, 129, 0.85)";
807
+ }
808
+
584
809
  // ═══ 启动 ═══
585
810
  function init() {
586
811
  createVersionBar();
587
812
  createDocButton();
588
813
  createCmdButton();
814
+ createCommandButton();
589
815
  injectStyles();
590
816
 
591
817
  // 初始化 VoiceInput SDK
package/gateway.js CHANGED
@@ -149,6 +149,17 @@ function start() {
149
149
  console.log('[启动] ' + colors.green + 'Gateway 启动成功!' + colors.nc);
150
150
  console.log('');
151
151
  console.log('控制台: ' + colors.yellow + 'http://127.0.0.1:' + PORT + colors.nc);
152
+
153
+ // 重新注册 LaunchAgent 作为守卫(崩溃自动重启、开机自启)
154
+ if (!isWin) {
155
+ try {
156
+ execSync('openclaw gateway install', { stdio: 'pipe', timeout: 10000 });
157
+ console.log('[守卫] ' + colors.green + 'LaunchAgent 已注册,崩溃/重启会自动拉起' + colors.nc);
158
+ } catch {
159
+ // 注册失败不影响正常使用,静默忽略
160
+ }
161
+ }
162
+
152
163
  return true;
153
164
  } catch {
154
165
  console.log('[启动] ' + colors.yellow + 'Gateway 正在启动中...' + colors.nc);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.227",
3
+ "version": "1.0.229",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {