@aiyiran/myclaw 1.1.76 → 1.1.78

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.
@@ -1055,13 +1055,9 @@
1055
1055
  + '&path=' + encodeURIComponent(filePath);
1056
1056
 
1057
1057
  if (['html', 'htm'].indexOf(ext) !== -1) {
1058
- // HTML → iframe srcdoc
1058
+ // HTML → iframe src (CDN)
1059
1059
  previewIframe.style.display = 'block';
1060
- previewIframe.srcdoc = '<body style="font:13px monospace;padding:20px;color:#888">加载中…</body>';
1061
- fetch(apiUrl)
1062
- .then(function (r) { return r.ok ? r.text() : Promise.reject('HTTP ' + r.status); })
1063
- .then(function (text) { previewIframe.srcdoc = text; })
1064
- .catch(function (e) { previewIframe.srcdoc = '<body style="font:13px monospace;padding:20px;color:#c00">加载失败: ' + e + '</body>'; });
1060
+ previewIframe.src = buildPreviewUrl(null, versionDir + '/' + filePath);
1065
1061
 
1066
1062
  } else if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico'].indexOf(ext) !== -1) {
1067
1063
  // 图片 → <img> src 直接指向 API URL(浏览器可直接加载二进制)
@@ -1664,7 +1660,11 @@
1664
1660
  entryDefaultOpt.value = '';
1665
1661
  entryDefaultOpt.textContent = '选择作品的网页入口文件';
1666
1662
  entrySelect.appendChild(entryDefaultOpt);
1667
- var htmlAssets = (cachedData.assets || []).filter(function (a) { return a.type && a.type.toLowerCase() === 'html'; });
1663
+ var htmlAssets = (cachedData.assets || []).filter(function (a) {
1664
+ if (!(a.type && a.type.toLowerCase() === 'html')) return false;
1665
+ var filename = a.path.split('/').pop();
1666
+ return !filename.startsWith('__');
1667
+ });
1668
1668
  htmlAssets.forEach(function (asset) {
1669
1669
  var opt = document.createElement('option');
1670
1670
  opt.value = asset.path;
@@ -313,507 +313,10 @@
313
313
  } catch (e) {}
314
314
  }
315
315
 
316
- // ═══ 3. Prompt 小助手按钮 ═══
317
-
318
- var promptOpen = false;
319
- var modalVoiceDestroy = null; // 弹框内语音组件的销毁函数
316
+ // ═══ 3. Prompt 小助手按钮(实现见 myclaw-iteration.js) ═══
320
317
 
321
318
  function createPromptButton() {
322
- var btn = document.createElement("button");
323
- btn.id = "myclaw-prompt-btn";
324
- btn.className = "agent-chat__input-btn";
325
- btn.title = "\u63d0\u95ee prompt \u5c0f\u52a9\u624b";
326
- btn.setAttribute("aria-label", "\u63d0\u95ee prompt \u5c0f\u52a9\u624b");
327
- btn.innerHTML = [
328
- '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18"',
329
- ' viewBox="0 0 24 24" fill="none" stroke="currentColor"',
330
- ' stroke-width="2" stroke-linecap="round" stroke-linejoin="round">',
331
- ' <circle cx="12" cy="12" r="10"/>',
332
- ' <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>',
333
- ' <line x1="12" y1="17" x2="12.01" y2="17"/>',
334
- '</svg>',
335
- ].join("");
336
-
337
- btn.addEventListener("click", function (e) {
338
- e.stopPropagation();
339
- if (promptOpen) {
340
- closePromptModal();
341
- } else {
342
- openPromptModal();
343
- }
344
- });
345
-
346
- return btn;
347
- }
348
-
349
- // ── 文案配置(集中管理,方便后续修改) ──
350
-
351
- var ITERATION_CONFIG = {
352
- problems: ["不好看", "不好玩", "太简单", "不清楚", "没反应", "不像我想的", "太乱了", "不知道接下来做什么"],
353
- actions: ["加一个新东西", "改一下样子", "改一下内容", "改一下功能", "让它动起来", "让它更有趣", "让它更清楚", "先做一个最简单的新版本"],
354
- };
355
-
356
- function openPromptModal() {
357
- if (document.querySelector("#myclaw-prompt-modal")) return;
358
- promptOpen = true;
359
-
360
- var iconBtn = document.querySelector("#myclaw-prompt-btn");
361
- if (iconBtn) iconBtn.style.color = "#6366f1";
362
-
363
- // ── 状态(关闭即清空) ──
364
- var state = { problem: "", action: "", note: "" };
365
-
366
- // ── 文本生成 ──
367
- function buildText() {
368
- if (!state.problem || !state.action) return "";
369
- var t = "我现在这个作品的问题是【" + state.problem + "】。\n"
370
- + "我下一步想先【" + state.action + "】。\n"
371
- + "请根据我当前正在做的内容,帮我只改一个点,给我一个最简单、最容易成功的下一步方案。";
372
- if (state.note.trim()) t += "\n补充说明:" + state.note.trim();
373
- return t;
374
- }
375
-
376
- function buildPayload() {
377
- return {
378
- type: "iteration_helper",
379
- problem: state.problem,
380
- next_action: state.action,
381
- extra_note: state.note,
382
- generated_text: buildText(),
383
- };
384
- }
385
-
386
- // ── 刷新预览 & 按钮可用性 ──
387
- var previewEl, actionSendBtn, actionInsertBtn;
388
- function refresh() {
389
- var text = buildText();
390
- var ready = !!(state.problem && state.action);
391
- if (previewEl) {
392
- previewEl.textContent = text || "先选上面两项,这里会自动生成要发给 AI 的内容 ✨";
393
- previewEl.style.color = ready ? "#cdd6f4" : "#555";
394
- }
395
- if (actionSendBtn) {
396
- actionSendBtn.disabled = !ready;
397
- actionSendBtn.style.opacity = ready ? "1" : "0.4";
398
- actionSendBtn.style.cursor = ready ? "pointer" : "not-allowed";
399
- }
400
- if (actionInsertBtn) {
401
- actionInsertBtn.disabled = !ready;
402
- actionInsertBtn.style.opacity = ready ? "1" : "0.4";
403
- actionInsertBtn.style.cursor = ready ? "pointer" : "not-allowed";
404
- }
405
- }
406
-
407
- // ── 芯片选择组(单选,再点可取消) ──
408
- function makeChipGroup(items, activeColor, onChange) {
409
- var wrap = document.createElement("div");
410
- wrap.style.cssText = "display:flex;flex-wrap:wrap;gap:7px;";
411
- var chips = [];
412
- items.forEach(function (label) {
413
- var chip = document.createElement("button");
414
- chip.textContent = label;
415
- chip.dataset.selected = "0";
416
- chip.style.cssText = [
417
- "padding:6px 13px",
418
- "border-radius:20px",
419
- "border:1.5px solid #3d3d5c",
420
- "background:#252536",
421
- "color:#888",
422
- "font-size:13px",
423
- "font-family:-apple-system,sans-serif",
424
- "cursor:pointer",
425
- "transition:all 0.15s",
426
- "white-space:nowrap",
427
- ].join(";");
428
-
429
- function applyStyle(sel) {
430
- if (sel) {
431
- chip.style.background = activeColor;
432
- chip.style.borderColor = activeColor;
433
- chip.style.color = "#fff";
434
- chip.style.fontWeight = "bold";
435
- } else {
436
- chip.style.background = "#252536";
437
- chip.style.borderColor = "#3d3d5c";
438
- chip.style.color = "#888";
439
- chip.style.fontWeight = "normal";
440
- }
441
- }
442
-
443
- chip.onmouseenter = function () {
444
- if (chip.dataset.selected !== "1") chip.style.borderColor = activeColor;
445
- };
446
- chip.onmouseleave = function () {
447
- if (chip.dataset.selected !== "1") chip.style.borderColor = "#3d3d5c";
448
- };
449
- chip.onclick = function () {
450
- var nowOn = chip.dataset.selected !== "1";
451
- // 取消同组其他
452
- chips.forEach(function (c) { c.dataset.selected = "0"; applyStyle.call({chip:c}, false); });
453
- // 重新用当前 chip 的 applyStyle(通过闭包拿到正确 chip)
454
- chips.forEach(function (c) {
455
- if (c !== chip) {
456
- c.style.background = "#252536";
457
- c.style.borderColor = "#3d3d5c";
458
- c.style.color = "#888";
459
- c.style.fontWeight = "normal";
460
- c.dataset.selected = "0";
461
- }
462
- });
463
- chip.dataset.selected = nowOn ? "1" : "0";
464
- applyStyle(nowOn);
465
- onChange(nowOn ? label : "");
466
- };
467
-
468
- chips.push(chip);
469
- wrap.appendChild(chip);
470
- });
471
- return wrap;
472
- }
473
-
474
- // ── 区域标题 ──
475
- function makeLabel(text) {
476
- var el = document.createElement("div");
477
- el.textContent = text;
478
- el.style.cssText = "font-size:13px;font-weight:bold;color:#cdd6f4;margin-bottom:8px;font-family:-apple-system,sans-serif;";
479
- return el;
480
- }
481
-
482
- // ══════════ DOM 组装 ══════════
483
-
484
- // 遮罩
485
- var overlay = document.createElement("div");
486
- overlay.id = "myclaw-prompt-modal";
487
- overlay.style.cssText = [
488
- "position:fixed", "top:0", "left:0",
489
- "width:100vw", "height:100vh",
490
- "background:rgba(0,0,0,0.45)",
491
- "z-index:99998",
492
- "display:flex", "align-items:center", "justify-content:center",
493
- "animation:myclaw-fade-in 0.15s ease",
494
- ].join(";");
495
-
496
- // 弹框
497
- var box = document.createElement("div");
498
- box.style.cssText = [
499
- "width:560px", "max-width:96vw", "max-height:92vh",
500
- "background:#1e1e2e",
501
- "border-radius:12px",
502
- "overflow:hidden",
503
- "display:flex", "flex-direction:column",
504
- "box-shadow:0 12px 48px rgba(0,0,0,0.6)",
505
- ].join(";");
506
-
507
- // 标题栏
508
- var header = document.createElement("div");
509
- header.style.cssText = [
510
- "display:flex", "align-items:center", "justify-content:space-between",
511
- "padding:13px 18px",
512
- "background:linear-gradient(135deg,#6366f1,#8b5cf6)",
513
- "color:#fff",
514
- "font-size:15px", "font-weight:bold",
515
- "font-family:-apple-system,sans-serif",
516
- "user-select:none", "flex-shrink:0",
517
- ].join(";");
518
- header.innerHTML = "<span>🤔 我卡住了,帮我继续改</span>";
519
- var closeX = document.createElement("span");
520
- closeX.textContent = "✕";
521
- closeX.style.cssText = "cursor:pointer;padding:2px 8px;border-radius:4px;font-size:15px;transition:background 0.15s;";
522
- closeX.onmouseenter = function () { closeX.style.background = "rgba(255,255,255,0.2)"; };
523
- closeX.onmouseleave = function () { closeX.style.background = "none"; };
524
- closeX.onclick = function () { closePromptModal(); };
525
- header.appendChild(closeX);
526
-
527
- // 滚动内容区
528
- var scroll = document.createElement("div");
529
- scroll.style.cssText = "flex:1;overflow-y:auto;padding:20px 20px 8px;display:flex;flex-direction:column;gap:20px;";
530
-
531
- // ── 第1区:问题 ──
532
- var sec1 = document.createElement("div");
533
- sec1.appendChild(makeLabel("现在最想改的问题是?"));
534
- sec1.appendChild(makeChipGroup(ITERATION_CONFIG.problems, "#f59e0b", function (val) {
535
- state.problem = val; refresh();
536
- }));
537
- scroll.appendChild(sec1);
538
-
539
- // ── 第2区:行动 ──
540
- var sec2 = document.createElement("div");
541
- sec2.appendChild(makeLabel("你下一步想先改什么?"));
542
- sec2.appendChild(makeChipGroup(ITERATION_CONFIG.actions, "#6366f1", function (val) {
543
- state.action = val; refresh();
544
- }));
545
- scroll.appendChild(sec2);
546
-
547
- // ── 第3区:补充(带语音输入) ──
548
- var sec3 = document.createElement("div");
549
- sec3.appendChild(makeLabel("可以补充一点点(可不填)"));
550
- var placeholders = ["比如:我想做成飞行射击", "比如:我想更像小猫主题", "比如:按钮点了以后想有变化"];
551
- var noteField = makeVoiceInputField(
552
- placeholders[Math.floor(Math.random() * placeholders.length)],
553
- 60,
554
- function (val) { state.note = val; refresh(); }
555
- );
556
- modalVoiceDestroy = noteField.destroy;
557
- sec3.appendChild(noteField.el);
558
- scroll.appendChild(sec3);
559
-
560
- // ── 预览区 ──
561
- var previewWrap = document.createElement("div");
562
- previewWrap.style.cssText = [
563
- "padding:12px 14px",
564
- "background:#252536",
565
- "border-radius:8px",
566
- "border-left:3px solid #6366f1",
567
- ].join(";");
568
- var previewLabel = document.createElement("div");
569
- previewLabel.textContent = "将要发给 AI 的内容:";
570
- previewLabel.style.cssText = "font-size:11px;color:#6366f1;font-weight:bold;margin-bottom:6px;font-family:monospace;letter-spacing:0.3px;";
571
- previewEl = document.createElement("div");
572
- previewEl.style.cssText = "font-size:13px;line-height:1.7;white-space:pre-wrap;font-family:-apple-system,sans-serif;word-break:break-all;";
573
- previewWrap.appendChild(previewLabel);
574
- previewWrap.appendChild(previewEl);
575
- scroll.appendChild(previewWrap);
576
-
577
- // ── 底部按钮区 ──
578
- var footer = document.createElement("div");
579
- footer.style.cssText = [
580
- "display:flex", "gap:10px",
581
- "padding:14px 20px",
582
- "border-top:1px solid #2d2d3f",
583
- "flex-shrink:0",
584
- "background:#1e1e2e",
585
- ].join(";");
586
-
587
- actionSendBtn = document.createElement("button");
588
- actionSendBtn.textContent = "➤ 直接发给 AI";
589
- actionSendBtn.disabled = true;
590
- actionSendBtn.style.cssText = [
591
- "flex:1", "padding:11px 0",
592
- "background:#10b981", "color:#fff",
593
- "border:none", "border-radius:8px",
594
- "font-size:14px", "font-weight:bold",
595
- "font-family:-apple-system,sans-serif",
596
- "cursor:not-allowed", "transition:all 0.15s", "opacity:0.4",
597
- ].join(";");
598
- actionSendBtn.onmouseenter = function () { if (!actionSendBtn.disabled) actionSendBtn.style.background = "#059669"; };
599
- actionSendBtn.onmouseleave = function () { if (!actionSendBtn.disabled) actionSendBtn.style.background = "#10b981"; };
600
- actionSendBtn.onclick = function () {
601
- if (actionSendBtn.disabled) return;
602
- var payload = buildPayload();
603
- console.log("[myclaw-prompt] onSendDirect", payload);
604
- insertPromptText(payload.generated_text);
605
- closePromptModal();
606
- setTimeout(function () { trySend(); }, 50);
607
- };
608
-
609
- actionInsertBtn = document.createElement("button");
610
- actionInsertBtn.textContent = "⬇ 先放到聊天框";
611
- actionInsertBtn.disabled = true;
612
- actionInsertBtn.style.cssText = [
613
- "flex:1", "padding:11px 0",
614
- "background:#6366f1", "color:#fff",
615
- "border:none", "border-radius:8px",
616
- "font-size:14px", "font-weight:bold",
617
- "font-family:-apple-system,sans-serif",
618
- "cursor:not-allowed", "transition:all 0.15s", "opacity:0.4",
619
- ].join(";");
620
- actionInsertBtn.onmouseenter = function () { if (!actionInsertBtn.disabled) actionInsertBtn.style.background = "#4f46e5"; };
621
- actionInsertBtn.onmouseleave = function () { if (!actionInsertBtn.disabled) actionInsertBtn.style.background = "#6366f1"; };
622
- actionInsertBtn.onclick = function () {
623
- if (actionInsertBtn.disabled) return;
624
- var payload = buildPayload();
625
- console.log("[myclaw-prompt] onInsertToInput", payload);
626
- insertPromptText(payload.generated_text);
627
- closePromptModal();
628
- };
629
-
630
- footer.appendChild(actionSendBtn);
631
- footer.appendChild(actionInsertBtn);
632
-
633
- // ── 拼装 ──
634
- box.appendChild(header);
635
- box.appendChild(scroll);
636
- box.appendChild(footer);
637
- overlay.appendChild(box);
638
- overlay.onclick = function (e) { if (e.target === overlay) closePromptModal(); };
639
- document.body.appendChild(overlay);
640
-
641
- refresh();
642
- }
643
-
644
- function closePromptModal() {
645
- if (modalVoiceDestroy) { modalVoiceDestroy(); modalVoiceDestroy = null; }
646
- var modal = document.querySelector("#myclaw-prompt-modal");
647
- if (modal) modal.remove();
648
- promptOpen = false;
649
-
650
- var btn = document.querySelector("#myclaw-prompt-btn");
651
- if (btn) { btn.style.color = ""; }
652
- }
653
-
654
- /**
655
- * 在 textarea 光标处插入 prompt 文字
656
- */
657
- function insertPromptText(text) {
658
- var ta = document.querySelector(".agent-chat__input textarea");
659
- if (!ta) return;
660
-
661
- var start = ta.selectionStart || 0;
662
- var end = ta.selectionEnd || 0;
663
- var current = ta.value;
664
- var newValue = current.substring(0, start) + text + current.substring(end);
665
-
666
- var setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value").set;
667
- setter.call(ta, newValue);
668
- ta.dispatchEvent(new Event("input", { bubbles: true }));
669
-
670
- var newCursor = start + text.length;
671
- try { ta.setSelectionRange(newCursor, newCursor); } catch (e) {}
672
- ta.focus();
673
- }
674
-
675
- // ═══ 3.6 带语音的输入框组件 ═══
676
-
677
- /**
678
- * makeVoiceInputField(placeholder, maxLength, onChange)
679
- * 返回 { el, getValue, setValue, destroy }
680
- *
681
- * 完全独立:有自己的 VoiceInput 实例和录音状态,
682
- * 不污染主 recording / voice 全局变量。
683
- */
684
- function makeVoiceInputField(placeholder, maxLength, onChange) {
685
- var lVoice = null; // 本组件的 VoiceInput 实例
686
- var lRecording = false; // 本组件的录音状态
687
- var lStopping = false; // 本组件的 stopping 窗口
688
-
689
- // ── 容器 ──
690
- var wrap = document.createElement("div");
691
- wrap.style.cssText = "display:flex;gap:8px;align-items:center;width:100%;box-sizing:border-box;";
692
-
693
- // ── 输入框 ──
694
- var input = document.createElement("input");
695
- input.type = "text";
696
- input.maxLength = maxLength || 60;
697
- input.placeholder = placeholder || "";
698
- input.style.cssText = [
699
- "flex:1", "min-width:0", "padding:9px 12px",
700
- "background:#252536",
701
- "border:1.5px solid #3d3d5c",
702
- "border-radius:8px",
703
- "color:#cdd6f4",
704
- "font-size:13px",
705
- "font-family:-apple-system,sans-serif",
706
- "outline:none",
707
- "transition:border-color 0.15s, border-left-width 0.1s",
708
- ].join(";");
709
- input.onfocus = function () { if (!lRecording) input.style.borderColor = "#6366f1"; };
710
- input.onblur = function () { if (!lRecording) input.style.borderColor = "#3d3d5c"; };
711
- input.oninput = function () { if (onChange) onChange(input.value); };
712
-
713
- // ── 麦克风按钮 ──
714
- var micBtn = document.createElement("button");
715
- micBtn.type = "button";
716
- micBtn.title = "语音输入";
717
- micBtn.style.cssText = [
718
- "width:34px", "height:34px", "flex-shrink:0",
719
- "border-radius:50%",
720
- "border:1.5px solid #3d3d5c",
721
- "background:#252536",
722
- "color:#888",
723
- "cursor:pointer",
724
- "display:flex", "align-items:center", "justify-content:center",
725
- "transition:all 0.15s",
726
- "position:relative",
727
- ].join(";");
728
- micBtn.innerHTML = [
729
- '<svg width="14" height="14" viewBox="0 0 24 24" fill="none"',
730
- ' stroke="currentColor" stroke-width="2"',
731
- ' stroke-linecap="round" stroke-linejoin="round">',
732
- ' <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/>',
733
- ' <path d="M19 10v2a7 7 0 0 1-14 0v-2"/>',
734
- ' <line x1="12" x2="12" y1="19" y2="22"/>',
735
- '</svg>',
736
- ].join("");
737
-
738
- // ── UI 状态切换 ──
739
- function setUI(recording) {
740
- if (recording) {
741
- micBtn.style.background = "#ff4444";
742
- micBtn.style.borderColor = "#ff4444";
743
- micBtn.style.color = "#fff";
744
- micBtn.title = "停止录音";
745
- input.style.borderColor = "#ff4444";
746
- input.style.borderLeftWidth = "3px";
747
- } else {
748
- micBtn.style.background = "#252536";
749
- micBtn.style.borderColor = "#3d3d5c";
750
- micBtn.style.color = "#888";
751
- micBtn.title = "语音输入";
752
- input.style.borderColor = "#3d3d5c";
753
- input.style.borderLeftWidth = "1.5px";
754
- }
755
- }
756
-
757
- // ── 初始化本组件的 VoiceInput 实例 ──
758
- function initLVoice() {
759
- if (typeof window.VoiceInput === "undefined") return false;
760
- lVoice = new window.VoiceInput({
761
- onResult: function (text) {
762
- if (!lRecording && !lStopping) return;
763
- input.value = text;
764
- if (onChange) onChange(text);
765
- },
766
- onStatusChange: function (oldS, newS) {
767
- // 讯飞 60s 断开 → 自动重连
768
- if (newS === "idle" && lRecording && !lStopping) {
769
- setTimeout(function () {
770
- if (lRecording && lVoice) lVoice.start();
771
- }, 300);
772
- }
773
- },
774
- onError: function (err) {
775
- console.error("[voice-input-field] error:", err);
776
- lRecording = false; lStopping = false;
777
- setUI(false);
778
- },
779
- });
780
- return true;
781
- }
782
-
783
- function startLocal() {
784
- if (!lVoice && !initLVoice()) {
785
- console.warn("[voice-input-field] VoiceInput SDK 未加载");
786
- return;
787
- }
788
- lRecording = true;
789
- setUI(true);
790
- lVoice.start();
791
- }
792
-
793
- function stopLocal() {
794
- if (!lRecording) return;
795
- lStopping = true;
796
- lRecording = false;
797
- setUI(false);
798
- setTimeout(function () {
799
- lStopping = false;
800
- if (lVoice) lVoice.stop();
801
- }, 1500);
802
- }
803
-
804
- micBtn.onclick = function () {
805
- if (lRecording) { stopLocal(); } else { startLocal(); }
806
- };
807
-
808
- wrap.appendChild(input);
809
- wrap.appendChild(micBtn);
810
-
811
- return {
812
- el: wrap,
813
- getValue: function () { return input.value; },
814
- setValue: function (v) { input.value = v; if (onChange) onChange(v); },
815
- destroy: function () { if (lRecording) stopLocal(); },
816
- };
319
+ return window.myclawIteration.createButton();
817
320
  }
818
321
 
819
322
  // ═══ 3.5 语音按钮 ═══
@@ -1013,6 +516,10 @@ btn.addEventListener("click", function () {
1013
516
  var toolbar = document.querySelector(".agent-chat__toolbar-left");
1014
517
  if (!toolbar || document.querySelector("#myclaw-voice-btn")) return;
1015
518
 
519
+ if (window.myclawIteration) {
520
+ window.myclawIteration.init({ trySend: trySend });
521
+ }
522
+
1016
523
  var voiceBtn = createVoiceButton();
1017
524
  var promptBtn = createPromptButton();
1018
525