hyper-scheduler 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/{devtools-ByJU-Gv1.js → devtools-B029_YOS.js} +99 -67
  3. package/dist/devtools-CRTqUH_8.cjs +1 -0
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.umd.cjs +1 -1
  7. package/package.json +2 -2
  8. package/public/logo.svg +54 -0
  9. package/dist/devtools-Bxtz0rO_.cjs +0 -1
  10. package/docs/.vitepress/cache/deps/_metadata.json +0 -31
  11. package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js +0 -12798
  12. package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js.map +0 -7
  13. package/docs/.vitepress/cache/deps/package.json +0 -3
  14. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -4505
  15. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
  16. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -9731
  17. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
  18. package/docs/.vitepress/cache/deps/vue.js +0 -347
  19. package/docs/.vitepress/cache/deps/vue.js.map +0 -7
  20. package/docs/.vitepress/config.ts +0 -56
  21. package/docs/.vitepress/theme/components/DemoFrame.vue +0 -111
  22. package/docs/.vitepress/theme/custom.css +0 -6
  23. package/docs/.vitepress/theme/index.ts +0 -10
  24. package/docs/README.md +0 -120
  25. package/docs/api/devtools.md +0 -245
  26. package/docs/api/index.md +0 -178
  27. package/docs/api/scheduler.md +0 -342
  28. package/docs/api/task.md +0 -439
  29. package/docs/api/types.md +0 -365
  30. package/docs/examples/index.md +0 -342
  31. package/docs/guide/best-practices.md +0 -436
  32. package/docs/guide/core-concepts.md +0 -363
  33. package/docs/guide/getting-started.md +0 -176
  34. package/docs/index.md +0 -33
  35. /package/{docs/public → dist}/logo.svg +0 -0
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="docs/public/logo.svg" width="120" height="120" alt="Hyper Scheduler Logo">
2
+ <img src="public/logo.svg" width="120" height="120" alt="Hyper Scheduler Logo">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Hyper Scheduler</h1>
@@ -407,9 +407,12 @@ class FloatingTrigger extends HTMLElement {
407
407
  __publicField(this, "_offsetX", 0);
408
408
  __publicField(this, "_offsetY", 0);
409
409
  __publicField(this, "_isCollapsed", false);
410
+ // 新增:收起状态
411
+ // 内部状态:保存展开时的位置
412
+ __publicField(this, "_savedX", 0);
413
+ __publicField(this, "_savedY", 0);
410
414
  this._shadow = this.attachShadow({ mode: "open" });
411
415
  }
412
- // 新增:收起状态
413
416
  static get observedAttributes() {
414
417
  return ["position", "bg-color", "text-color"];
415
418
  }
@@ -417,7 +420,9 @@ class FloatingTrigger extends HTMLElement {
417
420
  this.loadState();
418
421
  this.render();
419
422
  this.addEventListeners();
420
- this.applyPosition();
423
+ requestAnimationFrame(() => {
424
+ this.applyPosition();
425
+ });
421
426
  window.addEventListener("resize", this.onResize.bind(this));
422
427
  }
423
428
  disconnectedCallback() {
@@ -429,7 +434,9 @@ class FloatingTrigger extends HTMLElement {
429
434
  attributeChangedCallback(name, _oldVal, newVal) {
430
435
  if (name === "position") {
431
436
  this._position = newVal || "bottom-right";
432
- this.applyPosition();
437
+ if (!this.style.getPropertyValue("--hs-trigger-position-set")) {
438
+ this.resetPositionToDefault();
439
+ }
433
440
  } else if (name === "bg-color") {
434
441
  this._bgColor = newVal || "";
435
442
  this.updateStyles();
@@ -443,9 +450,11 @@ class FloatingTrigger extends HTMLElement {
443
450
  const savedPos = localStorage.getItem(STORAGE_KEY_POS);
444
451
  if (savedPos) {
445
452
  const { x, y } = JSON.parse(savedPos);
446
- this.style.setProperty("--hs-trigger-left", `${x}px`);
447
- this.style.setProperty("--hs-trigger-top", `${y}px`);
453
+ this._savedX = parseFloat(x);
454
+ this._savedY = parseFloat(y);
448
455
  this.style.setProperty("--hs-trigger-position-set", "true");
456
+ } else {
457
+ this.resetPositionToDefault();
449
458
  }
450
459
  const savedCollapsed = localStorage.getItem(STORAGE_KEY_COLLAPSED);
451
460
  if (savedCollapsed === "true") {
@@ -453,38 +462,45 @@ class FloatingTrigger extends HTMLElement {
453
462
  }
454
463
  } catch (e) {
455
464
  console.warn("[FloatingTrigger] Failed to load state:", e);
465
+ this.resetPositionToDefault();
456
466
  }
457
467
  }
468
+ resetPositionToDefault() {
469
+ const width = 48;
470
+ const height = 48;
471
+ const padding = 20;
472
+ if (this._position.includes("left")) this._savedX = padding;
473
+ else this._savedX = window.innerWidth - width - padding;
474
+ if (this._position.includes("top")) this._savedY = padding;
475
+ else this._savedY = window.innerHeight - height - padding;
476
+ }
458
477
  saveState() {
459
- const button = this._shadow.querySelector("button");
460
- if (!button) return;
461
- const rect = button.getBoundingClientRect();
462
- localStorage.setItem(STORAGE_KEY_POS, JSON.stringify({ x: rect.left, y: rect.top }));
478
+ localStorage.setItem(STORAGE_KEY_POS, JSON.stringify({ x: this._savedX, y: this._savedY }));
463
479
  localStorage.setItem(STORAGE_KEY_COLLAPSED, String(this._isCollapsed));
464
480
  }
465
481
  applyPosition() {
466
482
  const button = this._shadow.querySelector("button");
467
483
  if (!button) return;
468
- const maxX = window.innerWidth - button.offsetWidth;
469
- const maxY = window.innerHeight - button.offsetHeight;
470
- if (!this.style.getPropertyValue("--hs-trigger-position-set")) {
471
- const pos = this._position;
472
- button.style.top = pos.includes("top") ? "20px" : "auto";
473
- button.style.bottom = pos.includes("bottom") ? "20px" : "auto";
474
- button.style.left = pos.includes("left") ? "20px" : "auto";
475
- button.style.right = pos.includes("right") ? "20px" : "auto";
484
+ const width = this._isCollapsed ? 24 : 48;
485
+ const height = 48;
486
+ const maxX = window.innerWidth - width;
487
+ const maxY = window.innerHeight - height;
488
+ let targetX, targetY;
489
+ if (this._isCollapsed) {
490
+ targetX = maxX;
491
+ targetY = Math.max(0, Math.min(this._savedY, maxY));
476
492
  } else {
477
- let currentX = parseFloat(this.style.getPropertyValue("--hs-trigger-left") || "0");
478
- let currentY = parseFloat(this.style.getPropertyValue("--hs-trigger-top") || "0");
479
- currentX = Math.max(0, Math.min(currentX, maxX));
480
- currentY = Math.max(0, Math.min(currentY, maxY));
481
- this.style.setProperty("--hs-trigger-left", `${currentX}px`);
482
- this.style.setProperty("--hs-trigger-top", `${currentY}px`);
483
- button.style.left = `${currentX}px`;
484
- button.style.top = `${currentY}px`;
485
- button.style.right = "auto";
486
- button.style.bottom = "auto";
493
+ targetX = Math.max(0, Math.min(this._savedX, maxX));
494
+ targetY = Math.max(0, Math.min(this._savedY, maxY));
495
+ if (targetX !== this._savedX || targetY !== this._savedY) {
496
+ this._savedX = targetX;
497
+ this._savedY = targetY;
498
+ }
487
499
  }
500
+ button.style.left = `${targetX}px`;
501
+ button.style.top = `${targetY}px`;
502
+ this.style.setProperty("--hs-trigger-left", `${targetX}px`);
503
+ this.style.setProperty("--hs-trigger-top", `${targetY}px`);
488
504
  this.updateCollapsedState();
489
505
  }
490
506
  updateStyles() {
@@ -526,14 +542,14 @@ class FloatingTrigger extends HTMLElement {
526
542
  e.stopPropagation();
527
543
  e.preventDefault();
528
544
  this._isCollapsed = !this._isCollapsed;
529
- this.updateCollapsedState();
545
+ this.applyPosition();
530
546
  this.saveState();
531
547
  });
532
548
  btn.addEventListener("dblclick", (e) => {
533
549
  if (this._isCollapsed) {
534
550
  e.stopPropagation();
535
551
  this._isCollapsed = false;
536
- this.updateCollapsedState();
552
+ this.applyPosition();
537
553
  this.saveState();
538
554
  }
539
555
  });
@@ -542,33 +558,38 @@ class FloatingTrigger extends HTMLElement {
542
558
  if (e.target.closest(".collapse-btn")) return;
543
559
  this._isDragging = true;
544
560
  this._wasDragging = false;
545
- this._offsetX = e.clientX - btn.getBoundingClientRect().left;
546
- this._offsetY = e.clientY - btn.getBoundingClientRect().top;
561
+ const rect = btn.getBoundingClientRect();
562
+ this._offsetX = e.clientX - rect.left;
563
+ this._offsetY = e.clientY - rect.top;
547
564
  const startX = e.clientX;
548
565
  const startY = e.clientY;
549
566
  let hasMoved = false;
567
+ btn.style.transition = "none";
550
568
  const onMouseMove = (moveEvent) => {
551
569
  if (!this._isDragging) return;
552
570
  if (!hasMoved && (Math.abs(moveEvent.clientX - startX) > 2 || Math.abs(moveEvent.clientY - startY) > 2)) {
553
571
  hasMoved = true;
554
572
  this._wasDragging = true;
555
573
  btn.style.cursor = "grabbing";
556
- btn.style.transition = "none";
557
574
  }
558
575
  if (hasMoved) {
559
576
  let newX = moveEvent.clientX - this._offsetX;
560
577
  let newY = moveEvent.clientY - this._offsetY;
561
- const maxX = window.innerWidth - btn.offsetWidth;
562
- const maxY = window.innerHeight - btn.offsetHeight;
578
+ const width = this._isCollapsed ? 24 : 48;
579
+ const height = 48;
580
+ const maxX = window.innerWidth - width;
581
+ const maxY = window.innerHeight - height;
563
582
  newX = Math.max(0, Math.min(newX, maxX));
564
583
  newY = Math.max(0, Math.min(newY, maxY));
584
+ if (this._isCollapsed) {
585
+ newX = window.innerWidth - 24;
586
+ this._savedY = newY;
587
+ } else {
588
+ this._savedX = newX;
589
+ this._savedY = newY;
590
+ }
565
591
  btn.style.left = `${newX}px`;
566
592
  btn.style.top = `${newY}px`;
567
- btn.style.right = "auto";
568
- btn.style.bottom = "auto";
569
- this.style.setProperty("--hs-trigger-position-set", "true");
570
- this.style.setProperty("--hs-trigger-left", `${newX}px`);
571
- this.style.setProperty("--hs-trigger-top", `${newY}px`);
572
593
  }
573
594
  };
574
595
  const onMouseUp = () => {
@@ -593,11 +614,9 @@ class FloatingTrigger extends HTMLElement {
593
614
  }
594
615
  render() {
595
616
  const posStyles = `
596
- top: var(--hs-trigger-top, ${this._position.includes("top") ? "20px" : "auto"});
597
- bottom: var(--hs-trigger-bottom, ${this._position.includes("bottom") ? "20px" : "auto"});
598
- left: var(--hs-trigger-left, ${this._position.includes("left") ? "20px" : "auto"});
599
- right: var(--hs-trigger-right, ${this._position.includes("right") ? "20px" : "auto"});
600
- transform: ${this._isCollapsed ? "translateX(calc(100% - 12px))" : "translateX(0)"};
617
+ left: 0;
618
+ top: 0;
619
+ transform: translateZ(0); /* 开启硬件加速 */
601
620
  `;
602
621
  const bgStyle = this._bgColor ? `background: ${this._bgColor};` : "";
603
622
  const colorStyle = this._textColor ? `color: ${this._textColor};` : "";
@@ -609,28 +628,40 @@ class FloatingTrigger extends HTMLElement {
609
628
  ${posStyles}
610
629
  width: 48px;
611
630
  height: 48px;
612
- border-radius: 12px; /* 更现代的圆角 */
631
+ border-radius: 12px;
613
632
  background: var(--hs-primary);
614
633
  color: white;
615
634
  ${bgStyle}
616
635
  ${colorStyle}
617
636
  border: none;
618
- box-shadow: 0 4px 12px rgba(0,0,0,0.15); /* 更柔和的阴影 */
637
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
619
638
  cursor: pointer;
620
639
  display: flex;
621
640
  align-items: center;
622
641
  justify-content: center;
623
642
  font-family: var(--hs-font-family);
624
643
  z-index: var(--hs-z-index);
625
- transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), background 0.2s, box-shadow 0.2s;
626
- overflow: visible; /* 允许子元素(收起按钮)溢出或显示 */
644
+ /* 添加平滑过渡动画 */
645
+ transition: width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
646
+ left 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
647
+ top 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
648
+ border-radius 0.3s,
649
+ background 0.2s,
650
+ box-shadow 0.2s;
651
+ overflow: visible;
652
+ }
653
+ .icon {
654
+ transition: transform 0.2s;
655
+ display: flex;
627
656
  }
628
657
  button:hover {
629
658
  ${this._bgColor ? `background: ${this._bgColor}; filter: brightness(1.1);` : "background: var(--hs-primary-hover);"}
630
- transform: scale(1.05);
631
659
  box-shadow: 0 6px 16px rgba(0,0,0,0.2);
632
660
  }
633
- button:active {
661
+ button:hover .icon {
662
+ transform: scale(1.1);
663
+ }
664
+ button:active .icon {
634
665
  transform: scale(0.95);
635
666
  }
636
667
 
@@ -642,17 +673,18 @@ class FloatingTrigger extends HTMLElement {
642
673
  width: 20px;
643
674
  height: 20px;
644
675
  background: rgba(0,0,0,0.1);
645
- border-bottom-left-radius: 8px;
676
+ border-top-right-radius: 12px;
646
677
  display: flex;
647
678
  align-items: center;
648
679
  justify-content: center;
649
- opacity: 1; /* 默认可见 */
680
+ opacity: 1;
650
681
  transition: opacity 0.2s, background 0.2s;
651
682
  color: white;
652
683
  font-weight: bold;
684
+ z-index: 2;
653
685
  }
654
686
  .collapse-btn::before {
655
- content: '—'; /* 最小化图标 */
687
+ content: '—';
656
688
  font-size: 12px;
657
689
  color: currentColor;
658
690
  }
@@ -665,26 +697,29 @@ class FloatingTrigger extends HTMLElement {
665
697
 
666
698
  /* 收起状态样式 */
667
699
  button.collapsed {
668
- width: 36px;
669
- height: 36px;
670
- border-radius: 18px 0 0 18px;
671
- transform: translateX(calc(100% - 12px));
672
- opacity: 0.8;
700
+ width: 24px;
701
+ height: 48px;
702
+ border-radius: 12px 0 0 12px;
703
+ /* 不再强制 left/right,由 JS 控制 left 实现动画 */
673
704
  }
674
705
  button.collapsed:hover {
675
- transform: translateX(calc(100% - 24px)); /* hover 时稍微伸出一点 */
676
- opacity: 1;
706
+ width: 28px;
677
707
  }
708
+
678
709
  button.collapsed .icon {
679
710
  display: none;
680
711
  }
681
712
  button.collapsed .collapse-btn {
682
- right: auto;
683
- left: 0;
684
- border-radius: 0 12px 12px 0;
713
+ position: static;
714
+ width: 100%;
715
+ height: 100%;
716
+ border-radius: 0;
717
+ background: transparent;
685
718
  }
686
719
  button.collapsed .collapse-btn::before {
687
- content: ''; /* 展开图标 */
720
+ content: '';
721
+ font-size: 20px;
722
+ line-height: 48px;
688
723
  }
689
724
  </style>
690
725
  <button title="Toggle Hyper Scheduler DevTools">
@@ -692,9 +727,6 @@ class FloatingTrigger extends HTMLElement {
692
727
  <span class="icon">${ICONS.chart}</span>
693
728
  </button>
694
729
  `;
695
- this.applyPosition();
696
- this.updateCollapsedState();
697
- this.updateStyles();
698
730
  }
699
731
  }
700
732
  customElements.define("hs-floating-trigger", FloatingTrigger);
@@ -0,0 +1 @@
1
+ "use strict";var t=Object.defineProperty,e=(e,s,n)=>((e,s,n)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[s]=n)(e,"symbol"!=typeof s?s+"":s,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./index.cjs"),n={header:{title:"DevTools",searchPlaceholder:"Search IDs/Tags... 🔍",toggleDock:"Toggle Dock Position",toggleTheme:"Toggle Theme",close:"Close"},stats:{loading:"Loading...",fps:"FPS",status:"Status",active:"Active",total:"Total",mainThread:"Main Thread",scheduler:"Scheduler",running:"Running",stopped:"Stopped"},tabs:{tasks:"Tasks List",timeline:"Timeline"},list:{idTags:"ID / Tags",status:"Status",driver:"Driver",driverWorker:"Worker (Web Worker)",driverMain:"Main (setTimeout)",schedule:"Schedule",count:"Count",lastRun:"Last Run",actions:"Actions",noTags:"(No Tags)",tip:"✨ Tip: Click a row for details & history."},detail:{back:"Back",details:"Task Details",config:"Config",history:"Execution History",lastRuns:"Last {n} runs",avgDuration:"Avg Duration",startTime:"Start Time",duration:"Duration",drift:"Drift",status:"Status",noHistory:"No execution history",noTask:"No task selected",success:"Success",failed:"Failed",error:"Error"},timeline:{zoom:"Zoom",timeRange:"Time Range: Last {n}s",legend:"Legend",instant:"Instant",duration:"Duration",workerDriver:"Worker Driver",mainDriver:"Main Driver"},status:{running:"Running",paused:"Paused",stopped:"Stopped",idle:"Scheduled",error:"Error"},actions:{trigger:"Trigger now",start:"Start task",stop:"Stop task",remove:"Remove task"}},i={header:{title:"调试工具",searchPlaceholder:"搜索 ID/标签... 🔍",toggleDock:"切换停靠位置",toggleTheme:"切换主题",close:"关闭"},stats:{loading:"加载中...",fps:"帧率",status:"状态",active:"活跃",total:"总数",mainThread:"主线程",scheduler:"调度器",running:"运行中",stopped:"已停止"},tabs:{tasks:"任务列表",timeline:"时间线"},list:{idTags:"ID / 标签",status:"状态",driver:"驱动",driverWorker:"Worker (Web Worker)",driverMain:"主线程 (setTimeout)",schedule:"调度规则",count:"次数",lastRun:"最后运行",actions:"操作",noTags:"(无标签)",tip:"✨ 提示: 点击行查看详情和历史记录。"},detail:{back:"返回",details:"任务详情",config:"配置",history:"执行历史",lastRuns:"最近 {n} 次运行",avgDuration:"平均耗时",startTime:"开始时间",duration:"耗时",drift:"偏差",status:"状态",noHistory:"暂无执行历史",noTask:"未选择任务",success:"成功",failed:"失败",error:"错误"},timeline:{zoom:"缩放",timeRange:"时间范围: 最近 {n}秒",legend:"图例",instant:"瞬间",duration:"耗时",workerDriver:"Worker 驱动",mainDriver:"主线程 驱动"},status:{running:"执行中",paused:"已暂停",stopped:"已停止",idle:"调度中",error:"错误"},actions:{trigger:"立即触发",start:"启动任务",stop:"停止任务",remove:"删除任务"}};let o=n;function a(t){o="zh"===t?i:n}function r(t,e){const s=t.split(".");let n=o;for(const i of s){if(!n||"object"!=typeof n||!(i in n))return t;n=n[i]}return"string"!=typeof n?t:e?n.replace(/\{(\w+)\}/g,(t,s)=>void 0!==e[s]?String(e[s]):`{${s}}`):n}class h{constructor(){e(this,"state"),e(this,"listeners"),e(this,"scheduler"),this.state={isOpen:!1,activeTab:"tasks",theme:"auto",dockPosition:"right",panelSize:{width:500,height:500},language:"en",filterText:"",selectedTaskId:null,tasks:new Map,history:new Map,fps:0,schedulerRunning:!1},this.listeners=new Map}setScheduler(t){this.scheduler=t}getState(){return this.state}subscribe(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>{var s;null==(s=this.listeners.get(t))||s.delete(e)}}notify(t,e){var s;null==(s=this.listeners.get(t))||s.forEach(t=>t(e))}toggle(){this.state.isOpen=!this.state.isOpen,this.notify("isOpen",this.state.isOpen)}setTheme(t){this.state.theme=t,this.notify("theme",this.state.theme)}setLanguageSync(t){a(t),this.state.language=t}setLanguage(t){a(t),this.state.language=t,this.notify("language",this.state.language)}setPanelSize(t){this.state.panelSize={...this.state.panelSize,...t};try{localStorage.setItem("hs-panel-size",JSON.stringify(this.state.panelSize))}catch(e){}this.notify("panelSize",this.state.panelSize)}setTab(t){this.state.activeTab=t,this.notify("activeTab",this.state.activeTab)}setDockPosition(t){this.state.dockPosition=t,this.notify("dockPosition",this.state.dockPosition)}setFilterText(t){this.state.filterText=t,this.notify("filterText",this.state.filterText)}updateTask(t){const e=new Map(this.state.tasks);if(e.set(t.id,t),this.state.tasks=e,this.notify("tasks",this.state.tasks),"history"in t&&Array.isArray(t.history)){const e=new Map(this.state.history);e.set(t.id,t.history),this.state.history=e,this.notify("history",this.state.history)}}selectTask(t){this.state.selectedTaskId=t,this.notify("selectedTaskId",t)}addHistory(t,e){const s=[...this.state.history.get(t)||[]];s.push(e),s.length>50&&s.splice(0,s.length-50);const n=new Map(this.state.history);n.set(t,s),this.state.history=n,this.notify("history",n)}async triggerTask(t){this.scheduler&&await this.scheduler.trigger(t)}stopTask(t){console.log("[DevToolsStore] stopTask:",t),this.scheduler&&this.scheduler.pause(t)}startTask(t){console.log("[DevToolsStore] startTask:",t),this.scheduler&&this.scheduler.resume(t)}removeTask(t){if(this.scheduler){this.scheduler.remove(t);const e=new Map(this.state.tasks);e.delete(t),this.state.tasks=e,this.notify("tasks",this.state.tasks)}}setSchedulerRunning(t){this.state.schedulerRunning=t,this.notify("schedulerRunning",t)}}const l='\n :host {\n --hs-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;\n --hs-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n --hs-font-size: 12px;\n --hs-line-height: 1.5;\n --hs-panel-width: 400px;\n --hs-panel-height: 300px;\n \n /* 等宽数字字体 */\n --hs-font-monospaced-num: var(--hs-font-mono);\n\n /* Light Theme (Default) */\n --hs-bg: #ffffff;\n --hs-bg-secondary: #f3f4f6;\n --hs-text: #1f2937;\n --hs-text-secondary: #6b7280;\n --hs-border: #e5e7eb;\n --hs-primary: #3b82f6;\n --hs-primary-hover: #2563eb;\n --hs-danger: #ef4444;\n --hs-danger-hover: #dc2626;\n --hs-success: #10b981;\n --hs-warning: #f59e0b;\n \n --hs-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n --hs-radius: 6px;\n --hs-header-height: 40px;\n --hs-z-index: 9999;\n --hs-z-index-overlay: 9998;\n\n /* Default display styles for the host itself */\n background: var(--hs-bg);\n color: var(--hs-text);\n font-family: var(--hs-font-family);\n font-size: var(--hs-font-size);\n line-height: var(--hs-line-height);\n }\n\n :host([theme="dark"]) {\n --hs-bg: #111827;\n --hs-bg-secondary: #1f2937;\n --hs-text: #f9fafb;\n --hs-text-secondary: #9ca3af;\n --hs-border: #374151;\n --hs-primary: #60a5fa;\n --hs-primary-hover: #3b82f6;\n --hs-danger: #f87171;\n --hs-danger-hover: #ef4444;\n --hs-success: #34d399;\n --hs-warning: #fbbf24;\n \n --hs-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);\n }\n\n :host {\n background: var(--hs-bg);\n color: var(--hs-text);\n }\n',d={back:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>',trigger:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>',pause:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>',resume:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>',remove:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>',close:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>',sun:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>',moon:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>',dock:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="18" rx="2" ry="2"></rect><line x1="2" y1="15" x2="22" y2="15"></line></svg>',dockRight:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="18" rx="2" ry="2"></rect><line x1="15" y1="3" x2="15" y2="21"></line></svg>',chart:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>'},c="hs-trigger-position",p="hs-trigger-collapsed";class g extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_position","bottom-right"),e(this,"_bgColor",""),e(this,"_textColor",""),e(this,"_isDragging",!1),e(this,"_wasDragging",!1),e(this,"_offsetX",0),e(this,"_offsetY",0),e(this,"_isCollapsed",!1),e(this,"_savedX",0),e(this,"_savedY",0),this._shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["position","bg-color","text-color"]}connectedCallback(){this.loadState(),this.render(),this.addEventListeners(),requestAnimationFrame(()=>{this.applyPosition()}),window.addEventListener("resize",this.onResize.bind(this))}disconnectedCallback(){window.removeEventListener("resize",this.onResize.bind(this))}onResize(){this.applyPosition()}attributeChangedCallback(t,e,s){"position"===t?(this._position=s||"bottom-right",this.style.getPropertyValue("--hs-trigger-position-set")||this.resetPositionToDefault()):"bg-color"===t?(this._bgColor=s||"",this.updateStyles()):"text-color"===t&&(this._textColor=s||"",this.updateStyles())}loadState(){try{const t=localStorage.getItem(c);if(t){const{x:e,y:s}=JSON.parse(t);this._savedX=parseFloat(e),this._savedY=parseFloat(s),this.style.setProperty("--hs-trigger-position-set","true")}else this.resetPositionToDefault();"true"===localStorage.getItem(p)&&(this._isCollapsed=!0)}catch(t){console.warn("[FloatingTrigger] Failed to load state:",t),this.resetPositionToDefault()}}resetPositionToDefault(){this._position.includes("left")?this._savedX=20:this._savedX=window.innerWidth-48-20,this._position.includes("top")?this._savedY=20:this._savedY=window.innerHeight-48-20}saveState(){localStorage.setItem(c,JSON.stringify({x:this._savedX,y:this._savedY})),localStorage.setItem(p,String(this._isCollapsed))}applyPosition(){const t=this._shadow.querySelector("button");if(!t)return;const e=this._isCollapsed?24:48,s=window.innerWidth-e,n=window.innerHeight-48;let i,o;this._isCollapsed?(i=s,o=Math.max(0,Math.min(this._savedY,n))):(i=Math.max(0,Math.min(this._savedX,s)),o=Math.max(0,Math.min(this._savedY,n)),i===this._savedX&&o===this._savedY||(this._savedX=i,this._savedY=o)),t.style.left=`${i}px`,t.style.top=`${o}px`,this.style.setProperty("--hs-trigger-left",`${i}px`),this.style.setProperty("--hs-trigger-top",`${o}px`),this.updateCollapsedState()}updateStyles(){const t=this._shadow.querySelector("button");t&&(t.style.background=this._bgColor||"var(--hs-primary)",t.style.color=this._textColor||"white",this._bgColor?t.style.setProperty("--hs-trigger-bg-hover",`${this._bgColor}; filter: brightness(1.1);`):t.style.removeProperty("--hs-trigger-bg-hover"))}updateCollapsedState(){const t=this._shadow.querySelector("button");t&&(this._isCollapsed?t.classList.add("collapsed"):t.classList.remove("collapsed"))}addEventListeners(){const t=this._shadow.querySelector("button");if(!t)return;t.addEventListener("click",t=>{if(this._wasDragging)return t.preventDefault(),t.stopPropagation(),void(this._wasDragging=!1);this.dispatchEvent(new CustomEvent("toggle",{bubbles:!0,composed:!0}))});const e=this._shadow.querySelector(".collapse-btn");null==e||e.addEventListener("click",t=>{t.stopPropagation(),t.preventDefault(),this._isCollapsed=!this._isCollapsed,this.applyPosition(),this.saveState()}),t.addEventListener("dblclick",t=>{this._isCollapsed&&(t.stopPropagation(),this._isCollapsed=!1,this.applyPosition(),this.saveState())}),t.addEventListener("mousedown",e=>{if(0!==e.button)return;if(e.target.closest(".collapse-btn"))return;this._isDragging=!0,this._wasDragging=!1;const s=t.getBoundingClientRect();this._offsetX=e.clientX-s.left,this._offsetY=e.clientY-s.top;const n=e.clientX,i=e.clientY;let o=!1;t.style.transition="none";const a=e=>{if(this._isDragging&&(!o&&(Math.abs(e.clientX-n)>2||Math.abs(e.clientY-i)>2)&&(o=!0,this._wasDragging=!0,t.style.cursor="grabbing"),o)){let s=e.clientX-this._offsetX,n=e.clientY-this._offsetY;const i=this._isCollapsed?24:48,o=48,a=window.innerWidth-i,r=window.innerHeight-o;s=Math.max(0,Math.min(s,a)),n=Math.max(0,Math.min(n,r)),this._isCollapsed?(s=window.innerWidth-24,this._savedY=n):(this._savedX=s,this._savedY=n),t.style.left=`${s}px`,t.style.top=`${n}px`}},r=()=>{if(this._isDragging){if(this._isDragging=!1,t.style.cursor="pointer",t.style.transition="",o){this.saveState();const t=t=>{t.stopPropagation(),t.preventDefault()};window.addEventListener("click",t,{capture:!0,once:!0})}window.removeEventListener("mousemove",a),window.removeEventListener("mouseup",r)}};window.addEventListener("mousemove",a),window.addEventListener("mouseup",r)})}render(){const t=this._bgColor?`background: ${this._bgColor};`:"",e=this._textColor?`color: ${this._textColor};`:"";this._shadow.innerHTML=`\n <style>\n ${l}\n button {\n position: fixed;\n \n left: 0;\n top: 0;\n transform: translateZ(0); /* 开启硬件加速 */\n \n width: 48px;\n height: 48px;\n border-radius: 12px;\n background: var(--hs-primary);\n color: white;\n ${t}\n ${e}\n border: none;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: var(--hs-font-family);\n z-index: var(--hs-z-index);\n /* 添加平滑过渡动画 */\n transition: width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n left 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n top 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n border-radius 0.3s,\n background 0.2s, \n box-shadow 0.2s;\n overflow: visible;\n }\n .icon {\n transition: transform 0.2s;\n display: flex;\n }\n button:hover {\n ${this._bgColor?`background: ${this._bgColor}; filter: brightness(1.1);`:"background: var(--hs-primary-hover);"}\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\n }\n button:hover .icon {\n transform: scale(1.1);\n }\n button:active .icon {\n transform: scale(0.95);\n }\n\n /* 显式收起按钮 */\n .collapse-btn {\n position: absolute;\n top: 0;\n right: 0;\n width: 20px;\n height: 20px;\n background: rgba(0,0,0,0.1);\n border-top-right-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 1; \n transition: opacity 0.2s, background 0.2s;\n color: white;\n font-weight: bold;\n z-index: 2;\n }\n .collapse-btn::before {\n content: '—'; \n font-size: 12px;\n color: currentColor;\n }\n button:hover .collapse-btn {\n opacity: 1;\n }\n .collapse-btn:hover {\n background: rgba(0,0,0,0.3);\n }\n\n /* 收起状态样式 */\n button.collapsed {\n width: 24px;\n height: 48px;\n border-radius: 12px 0 0 12px;\n /* 不再强制 left/right,由 JS 控制 left 实现动画 */\n }\n button.collapsed:hover {\n width: 28px; \n }\n \n button.collapsed .icon {\n display: none;\n }\n button.collapsed .collapse-btn {\n position: static;\n width: 100%;\n height: 100%;\n border-radius: 0;\n background: transparent;\n }\n button.collapsed .collapse-btn::before {\n content: '‹'; \n font-size: 20px;\n line-height: 48px;\n }\n </style>\n <button title="Toggle Hyper Scheduler DevTools">\n <div class="collapse-btn" title="Minimize"></div>\n <span class="icon">${d.chart}</span>\n </button>\n `}}customElements.define("hs-floating-trigger",g);class u extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_fps",0),e(this,"_stats",{active:0,total:0}),e(this,"_theme","auto"),e(this,"_activeTab","tasks"),e(this,"_language","en"),e(this,"_schedulerRunning",!1),e(this,"$fps"),e(this,"$stats"),e(this,"$schedulerStatus"),e(this,"$themeIcon"),e(this,"$dockIcon"),e(this,"$tabs"),e(this,"$searchInput"),e(this,"$title"),e(this,"$langBtn"),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.cacheDom(),this.addEventListeners(),this.updateView()}set fps(t){if(this._fps=Math.round(t),this.$fps){const t=this._fps<30?"var(--hs-danger)":this._fps<50?"var(--hs-warning)":"var(--hs-success)";this.$fps.innerHTML=`⚡ ${r("stats.fps")}: <span style="color:${t}; font-family:var(--hs-font-monospaced-num);">${this._fps}</span> (${r("stats.mainThread")})`}}set stats(t){this._stats=t,this.$stats&&(this.$stats.innerHTML=`📊 ${r("stats.status")}: <span style="color:var(--hs-success)">🟢 ${r("stats.active")}: ${t.active}</span> <span style="margin-left:12px;color:var(--hs-text-secondary)">⚪ ${r("stats.total")}: ${t.total}</span>`)}set schedulerRunning(t){if(this._schedulerRunning=t,this.$schedulerStatus){const e=r(t?"stats.running":"stats.stopped"),s=t?"var(--hs-success)":"var(--hs-danger)",n=t?"▶️":"⏹️";this.$schedulerStatus.innerHTML=`${n} ${r("stats.scheduler")}: <span style="color:${s}">${e}</span>`}}set theme(t){this._theme=t,this.setAttribute("theme",t),this.updateThemeIcon()}set language(t){this._language=t,this.updateTexts()}set dockPosition(t){var e;this.$dockIcon&&(this.$dockIcon.innerHTML="right"===t?d.dock:d.dockRight,null==(e=this.$dockIcon.parentElement)||e.setAttribute("title",r("header.toggleDock")))}set activeTab(t){this._activeTab=t,this.updateTabs()}cacheDom(){this.$fps=this._shadow.querySelector(".fps"),this.$stats=this._shadow.querySelector(".stats"),this.$schedulerStatus=this._shadow.querySelector(".scheduler-status"),this.$themeIcon=this._shadow.querySelector(".theme-btn span"),this.$dockIcon=this._shadow.querySelector(".dock-btn"),this.$tabs=this._shadow.querySelectorAll(".tab"),this.$searchInput=this._shadow.querySelector(".search-input"),this.$title=this._shadow.querySelector(".title"),this.$langBtn=this._shadow.querySelector(".lang-btn")}addEventListeners(){var t,e,s,n,i;null==(t=this._shadow.querySelector(".dock-btn"))||t.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("dock-toggle"))}),null==(e=this._shadow.querySelector(".theme-btn"))||e.addEventListener("click",()=>{const t="dark"===this._theme?"light":"dark";this.dispatchEvent(new CustomEvent("theme-toggle",{detail:t}))}),null==(s=this._shadow.querySelector(".lang-btn"))||s.addEventListener("click",()=>{const t="en"===this._language?"zh":"en";this.dispatchEvent(new CustomEvent("lang-toggle",{detail:t}))}),null==(n=this._shadow.querySelector(".close-btn"))||n.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("close"))}),this.$tabs.forEach(t=>{t.addEventListener("click",t=>{const e=t.currentTarget.dataset.tab;this.dispatchEvent(new CustomEvent("tab-change",{detail:e}))})}),null==(i=this.$searchInput)||i.addEventListener("input",t=>{const e=t.target.value;this.dispatchEvent(new CustomEvent("search",{detail:e}))})}updateThemeIcon(){this.$themeIcon&&(this.$themeIcon.innerHTML="dark"===this._theme?d.moon:d.sun)}updateTabs(){this.$tabs.forEach(t=>{t.dataset.tab===this._activeTab?t.classList.add("active"):t.classList.remove("active")})}updateTexts(){this.$title&&(this.$title.innerHTML=`🕒 ${r("header.title")}`),this.$searchInput&&(this.$searchInput.placeholder=r("header.searchPlaceholder")),this.$langBtn&&(this.$langBtn.textContent="en"===this._language?"中":"EN"),this.$tabs.forEach(t=>{const e=t.dataset.tab;"tasks"===e&&(t.innerHTML=`📌 ${r("tabs.tasks")}`),"timeline"===e&&(t.innerHTML=`📈 ${r("tabs.timeline")}`)}),this.stats=this._stats,this.fps=this._fps,this.schedulerRunning=this._schedulerRunning}updateView(){this.updateThemeIcon(),this.updateTabs(),this.updateTexts()}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n background: var(--hs-bg);\n border-bottom: 1px solid var(--hs-border);\n padding: 0 16px;\n height: var(--hs-header-height);\n height: auto; \n }\n .top-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n height: 40px;\n border-bottom: 1px solid var(--hs-border);\n }\n .title {\n font-weight: 600;\n font-size: 13px;\n color: var(--hs-text);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .search-box {\n flex: 1;\n max-width: 300px;\n margin: 0px 32px 0 16px;\n }\n .search-input {\n width: 100%;\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 12px;\n }\n .search-input::placeholder {\n color: var(--hs-text-secondary);\n }\n .controls {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n button {\n background: transparent;\n border: none;\n color: var(--hs-text-secondary);\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n width: 28px;\n height: 28px;\n }\n .theme-btn span {\n margin-top: 4px;\n }\n button:hover {\n background: var(--hs-bg-secondary);\n color: var(--hs-text);\n }\n button svg {\n width: 16px;\n height: 16px;\n }\n .lang-btn {\n font-weight: 600;\n }\n .stats-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n height: 30px;\n font-size: 11px;\n color: var(--hs-text-secondary);\n border-bottom: 1px solid var(--hs-border);\n gap: 16px;\n }\n .stats-left {\n display: flex;\n gap: 16px;\n }\n .tabs-bar {\n display: flex;\n height: 36px;\n gap: 0;\n }\n .tab {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--hs-text-secondary);\n cursor: pointer;\n border-bottom: 3px solid transparent;\n padding: 0 16px;\n transition: all 0.2s;\n }\n .tab:hover {\n color: var(--hs-text);\n background: var(--hs-bg-secondary);\n }\n .tab.active {\n color: var(--hs-text);\n font-weight: 600;\n border-bottom-color: var(--hs-primary);\n background: var(--hs-bg-secondary);\n }\n </style>\n \n <div class="top-bar">\n <div class="title"></div>\n <div class="search-box">\n <input type="text" class="search-input">\n </div>\n <div class="controls">\n <button class="lang-btn" title="Switch Language">EN</button>\n <button class="dock-btn" title="Toggle Dock">${d.dock}</button>\n <button class="theme-btn" title="Toggle Theme"><span>${d.sun}</span></button>\n <button class="close-btn" title="Close">${d.close}</button>\n </div>\n </div>\n \n <div class="stats-bar">\n <div class="stats-left">\n <div class="scheduler-status"></div>\n <div class="stats"></div>\n </div>\n <div class="fps"></div>\n </div>\n \n <div class="tabs-bar">\n <div class="tab active" data-tab="tasks"></div>\n <div class="tab" data-tab="timeline"></div>\n </div>\n `}}customElements.define("hs-task-header",u);class b extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_tasks",[]),e(this,"_lastExecutionTimes",new Map),e(this,"_expandedNamespaces",new Set(["default"])),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render()}set tasks(t){const e=Array.from(t.values());e.forEach(t=>{const e=this._tasks.find(e=>e.id===t.id);e&&t.executionCount>e.executionCount&&this._lastExecutionTimes.set(t.id,Date.now())}),this._tasks=e,this.renderRows()}groupTasksByNamespace(t){const e=new Map;return t.forEach(t=>{const s=t.namespace||"default";e.has(s)||e.set(s,[]),e.get(s).push(t)}),e}filter(t,e){const s=Array.from(e.values());if(t){const e=t.toLowerCase();this._tasks=s.filter(t=>t.id.toLowerCase().includes(e)||t.tags.some(t=>t.toLowerCase().includes(e))||t.namespace&&t.namespace.toLowerCase().includes(e))}else this._tasks=s;this.renderRows()}updateHeaders(){const t=this._shadow.querySelector("thead");t&&(t.innerHTML=`\n <tr>\n <th style="width:40px">#</th>\n <th style="min-width:150px">${r("list.idTags")}</th>\n <th style="width:150px">${r("list.status")}</th>\n <th style="width:70px">${r("list.driver")}</th>\n <th style="width:100px">${r("list.schedule")}</th>\n <th style="width:60px">${r("list.count")}</th>\n <th style="width:100px">${r("list.lastRun")}</th>\n <th style="width:100px">${r("list.actions")}</th>\n </tr>\n `);const e=this._shadow.querySelector(".tip");e&&(e.textContent=r("list.tip")),this.renderRows()}getStatusIcon(t,e){const n=this._lastExecutionTimes.get(e),i=n&&Date.now()-n<1e3;switch(t){case s.TaskStatus.RUNNING:return`<span style="color:var(--hs-primary)">🔵</span> <strong>${r("status.running")}</strong>`;case s.TaskStatus.STOPPED:return`<span style="color:var(--hs-text-secondary)">⚪</span> ${r("status.stopped")}`;case s.TaskStatus.IDLE:return i?`<span class="status-flash" style="color:var(--hs-success)">🟢</span> ${r("status.idle")}`:`<span style="color:var(--hs-success)">🟢</span> ${r("status.idle")}`;case s.TaskStatus.ERROR:return`<span style="color:var(--hs-warning)">🟠</span> ${r("status.error")}`;default:return t}}formatSchedule(t){return"number"==typeof t?`${t}ms`:t&&(t.includes("*")||t.includes(" "))?t.length>15?t.substring(0,12)+"...":t:t||"-"}formatTime(t){if(!t)return"-";const e=new Date(t);return e.toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})+"."+e.getMilliseconds().toString().padStart(3,"0")}getDriverBadge(t){return"worker"===(t||"worker")?`<span class="driver-badge worker" title="${r("list.driverWorker")}">W</span>`:`<span class="driver-badge main" title="${r("list.driverMain")}">M</span>`}renderTaskRow(t,e,n=!1){const i=this._lastExecutionTimes.get(t.id),o=i&&Date.now()-i<1e3?"recently-executed":"",a=n?"nested-task":"";return`\n <tr data-id="${t.id}" class="${o} ${a}">\n <td class="col-num">\n ${n?"":e+1}\n </td>\n <td class="col-id">\n <div class="task-id">\n ${t.id}\n ${t.namespace&&"default"!==t.namespace&&!n?`<span class="namespace-badge" title="Namespace">${t.namespace}</span>`:""}\n </div>\n <div class="tags">\n ${t.tags&&t.tags.length>0?t.tags.map(t=>`<span class="tag">${t}</span>`).join(""):`<span class="no-tags">${r("list.noTags")}</span>`}\n </div>\n </td>\n <td>${this.getStatusIcon(t.status,t.id)}</td>\n <td>${this.getDriverBadge(t.driver)}</td>\n <td>${this.formatSchedule(t.schedule)}</td>\n <td>${t.executionCount||0}</td>\n <td>${this.formatTime(t.lastRun)}</td>\n <td class="col-actions">\n <div class="action-group">\n <button class="btn-icon" data-action="trigger" title="${r("actions.trigger")}" ${t.status===s.TaskStatus.RUNNING?"disabled":""}>${d.trigger}</button>\n ${t.status===s.TaskStatus.STOPPED||t.status===s.TaskStatus.ERROR?`<button class="btn-icon success" data-action="start" title="${r("actions.start")}">${d.resume}</button>`:`<button class="btn-icon warning" data-action="stop" title="${r("actions.stop")}" ${t.status===s.TaskStatus.RUNNING?"disabled":""}>${d.pause}</button>`}\n <button class="btn-icon danger" data-action="remove" title="${r("actions.remove")}">${d.remove}</button>\n </div>\n </td>\n </tr>\n `}renderRows(){const t=this._shadow.querySelector("tbody");if(!t)return;const e=this.groupTasksByNamespace(this._tasks);let s="",n=0;const i=e.get("default");i&&i.length>0&&(s+=i.map(t=>this.renderTaskRow(t,++n,!1)).join("")),e.delete("default");Array.from(e.keys()).sort((t,e)=>t.localeCompare(e)).forEach(t=>{const i=e.get(t),o=this._expandedNamespaces.has(t);s+=`\n <tr class="namespace-row ${o?"ns-expanded":""}" data-ns="${t}">\n <td colspan="8">\n <span class="ns-toggle">${o?"▼":"▶"}</span>\n <span class="ns-icon">📂</span>\n <span class="ns-name">${t}</span>\n <span class="ns-count">(${i.length})</span>\n </td>\n </tr>\n `,o&&(s+=i.map(t=>this.renderTaskRow(t,++n,!0)).join(""))}),t.innerHTML=s}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--hs-bg);\n }\n .table-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overflow-x: auto;\n position: relative;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--hs-font-size);\n color: var(--hs-text);\n }\n thead {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--hs-bg);\n }\n th {\n text-align: left;\n padding: 8px 12px;\n border-bottom: 2px solid var(--hs-border);\n color: var(--hs-text-secondary);\n font-weight: 600;\n background: var(--hs-bg);\n font-size: 11px;\n text-transform: uppercase;\n white-space: nowrap;\n }\n th:last-child {\n position: sticky;\n right: 0;\n background: var(--hs-bg);\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n }\n td {\n padding: 8px 12px;\n border-bottom: 1px solid var(--hs-border);\n vertical-align: middle;\n }\n tr:hover {\n background: var(--hs-bg-secondary);\n cursor: pointer;\n }\n tr.recently-executed {\n animation: flash-row 1s ease-out;\n }\n @keyframes flash-row {\n 0% { background: rgba(34, 197, 94, 0.2); }\n 100% { background: transparent; }\n }\n .status-flash {\n animation: flash-icon 1s ease-out;\n }\n @keyframes flash-icon {\n 0%, 50% { opacity: 1; }\n 25%, 75% { opacity: 0.3; }\n }\n .tip {\n padding: 12px;\n text-align: center;\n font-size: 11px;\n color: var(--hs-text-secondary);\n border-top: 1px solid var(--hs-border);\n background: var(--hs-bg);\n }\n .task-id {\n font-weight: 600;\n }\n .namespace-badge {\n display: inline-block;\n background: var(--hs-bg-secondary);\n color: var(--hs-text-secondary);\n border: 1px solid var(--hs-border);\n border-radius: 4px;\n padding: 0 4px;\n font-size: 9px;\n margin-left: 6px;\n font-family: monospace;\n vertical-align: middle;\n }\n .tags {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n .tag {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n border-radius: 10px;\n padding: 2px 8px;\n font-size: 10px;\n color: var(--hs-text-secondary);\n }\n .no-tags {\n font-size: 10px;\n color: var(--hs-text-secondary);\n font-style: italic;\n }\n .driver-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n font-family: monospace;\n }\n .driver-badge.worker {\n background: rgba(34, 197, 94, 0.15);\n color: var(--hs-success);\n border: 1px solid var(--hs-success);\n }\n .driver-badge.main {\n background: rgba(245, 158, 11, 0.15);\n color: var(--hs-warning);\n border: 1px solid var(--hs-warning);\n }\n .col-num {\n width: 40px;\n color: var(--hs-text-secondary);\n font-size: 11px;\n }\n .col-actions {\n width: 100px;\n position: sticky;\n right: 0;\n background: var(--hs-bg);\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n }\n .action-group {\n display: flex;\n gap: 4px;\n }\n .btn-icon {\n background: transparent;\n border: 1px solid var(--hs-border);\n color: var(--hs-text-secondary);\n border-radius: 4px;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n padding: 0;\n flex-shrink: 0;\n }\n .btn-icon svg {\n width: 14px;\n height: 14px;\n display: block;\n }\n .btn-icon:hover {\n background: var(--hs-primary);\n color: white;\n border-color: var(--hs-primary);\n }\n .btn-trigger:hover {\n background: var(--hs-success);\n border-color: var(--hs-success);\n }\n .btn-pause:hover {\n background: var(--hs-warning);\n border-color: var(--hs-warning);\n }\n .btn-resume:hover {\n background: var(--hs-success);\n border-color: var(--hs-success);\n }\n .btn-remove:hover {\n color: white;\n background: var(--hs-danger);\n border-color: var(--hs-danger);\n }\n .btn-icon:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n .btn-icon:disabled:hover {\n background: transparent;\n color: var(--hs-text-secondary);\n border-color: var(--hs-border);\n }\n /* Namespace Styles */\n .namespace-row {\n background: var(--hs-bg-secondary);\n cursor: pointer;\n font-weight: 600;\n user-select: none;\n }\n .namespace-row:hover {\n background: var(--hs-border);\n }\n .namespace-row td {\n padding: 8px 12px;\n border-bottom: 1px solid var(--hs-border);\n }\n .ns-toggle {\n display: inline-block;\n width: 20px;\n text-align: center;\n font-size: 10px;\n color: var(--hs-text-secondary);\n transition: transform 0.2s;\n }\n .ns-icon {\n margin-right: 4px;\n }\n .ns-count {\n font-weight: normal;\n color: var(--hs-text-secondary);\n font-size: 11px;\n margin-left: 4px;\n }\n .nested-task .col-id {\n padding-left: 32px !important;\n }\n </style>\n <div class="table-container">\n <table>\n <thead>\n <tr>\n <th style="width:40px">#</th>\n <th style="min-width:150px">${r("list.idTags")}</th>\n <th style="width:150px">${r("list.status")}</th>\n <th style="width:70px">${r("list.driver")}</th>\n <th style="width:100px">${r("list.schedule")}</th>\n <th style="width:60px">${r("list.count")}</th>\n <th style="width:100px">${r("list.lastRun")}</th>\n <th style="width:100px">${r("list.actions")}</th>\n </tr>\n </thead>\n <tbody>\n \x3c!-- Rows --\x3e\n </tbody>\n </table>\n </div>\n <div class="tip">\n ${r("list.tip")}\n </div>\n `,this._shadow.addEventListener("click",t=>{const e=t.target,s=e.closest(".namespace-row");if(s){const t=s.dataset.ns;return void(t&&(this._expandedNamespaces.has(t)?this._expandedNamespaces.delete(t):this._expandedNamespaces.add(t),this.renderRows()))}const n=e.closest("button");if(n){const t=n.dataset.action,e=n.closest("tr");if(!t||!e)return;const s=e.dataset.id;return void this.dispatchEvent(new CustomEvent("task-action",{detail:{action:t,id:s},bubbles:!0,composed:!0}))}const i=e.closest("tr");if(i&&!e.closest(".col-actions")&&!i.classList.contains("namespace-row")){const t=i.dataset.id;this.dispatchEvent(new CustomEvent("task-select",{detail:t,bubbles:!0,composed:!0}))}})}}customElements.define("hs-task-list",b);class v extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_task",null),e(this,"_history",[]),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this._shadow.addEventListener("click",t=>{t.target.closest(".back-btn")&&this.dispatchEvent(new CustomEvent("back"))})}set task(t){this._task=t,this.renderContent()}set history(t){this._history=t||[],this.renderContent()}updateTexts(){this.renderContent()}renderContent(){const t=this._shadow.querySelector(".content");if(!t)return;if(!this._task)return void(t.innerHTML=`<div class="empty">${r("detail.noTask")}</div>`);const e=this._task,s={id:e.id,schedule:e.schedule,tags:e.tags},n=this._history.length>0?Math.round(this._history.reduce((t,e)=>t+e.duration,0)/this._history.length):0;t.innerHTML=`\n <div class="header">\n <button class="back-btn" title="${r("detail.back")}">${d.back}</button>\n <h2>📂 ${e.id}</h2>\n </div>\n \n <div class="section">\n <div class="config-label">${r("detail.config")}:</div>\n <pre>${JSON.stringify(s,null,2)}</pre>\n </div>\n\n <div class="section">\n <h3>📜 ${r("detail.history")} (${r("detail.lastRuns",{n:this._history.length})}) ${n>0?`- ${r("detail.avgDuration")}: ${n}ms`:""}</h3>\n <table class="history-table">\n <thead>\n <tr>\n <th>#</th>\n <th>${r("detail.startTime")}</th>\n <th>${r("detail.duration")}</th>\n <th>${r("detail.drift")}</th>\n <th>${r("detail.status")}</th>\n </tr>\n </thead>\n <tbody>\n ${0===this._history.length?`<tr><td colspan="5" class="no-data">${r("detail.noHistory")}</td></tr>`:""}\n ${this._history.slice().reverse().map((t,e)=>{const s=t.success?`✅ ${r("detail.success")}`:t.error?`❌ ${r("detail.error")}: ${t.error}`:`⚠️ ${r("detail.failed")}`,n=t.duration>100?"slow":"";return`\n <tr class="${t.success?"success":"error"}">\n <td class="col-num">${this._history.length-e}</td>\n <td>${new Date(t.timestamp).toLocaleTimeString("en-US",{hour12:!1})}</td>\n <td class="${n}">${t.duration}ms</td>\n <td>0ms</td>\n <td class="status-cell">${s}</td>\n </tr>\n `}).join("")}\n </tbody>\n </table>\n </div>\n `}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n height: 100%;\n background: var(--hs-bg);\n overflow-y: auto;\n }\n .content {\n padding: 16px;\n }\n .header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 16px;\n border-bottom: 2px solid var(--hs-border);\n }\n .back-btn {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n }\n .back-btn:hover {\n background: var(--hs-primary);\n color: white;\n border-color: var(--hs-primary);\n }\n h2 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n }\n h3 {\n font-size: 13px;\n color: var(--hs-text);\n margin-bottom: 12px;\n font-weight: 600;\n }\n .section {\n margin-bottom: 32px;\n }\n .config-label {\n font-size: 12px;\n color: var(--hs-text-secondary);\n margin-bottom: 8px;\n }\n pre {\n background: var(--hs-bg-secondary);\n padding: 12px;\n border-radius: 6px;\n border: 1px solid var(--hs-border);\n font-family: 'Monaco', 'Menlo', monospace;\n font-size: 11px;\n overflow-x: auto;\n line-height: 1.5;\n }\n .history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 11px;\n }\n .history-table th {\n text-align: left;\n padding: 8px;\n border-bottom: 2px solid var(--hs-border);\n color: var(--hs-text-secondary);\n font-weight: 600;\n background: var(--hs-bg-secondary);\n }\n .history-table td {\n padding: 8px;\n border-bottom: 1px solid var(--hs-border);\n }\n .history-table tr.success {\n background: rgba(34, 197, 94, 0.05);\n }\n .history-table tr.error {\n background: rgba(239, 68, 68, 0.05);\n }\n .history-table tr:hover {\n background: var(--hs-bg-secondary);\n }\n .col-num {\n width: 40px;\n color: var(--hs-text-secondary);\n }\n .slow {\n color: var(--hs-warning);\n font-weight: 600;\n }\n .status-cell {\n font-size: 11px;\n }\n .no-data {\n color: var(--hs-text-secondary);\n font-style: italic;\n text-align: center;\n padding: 24px;\n }\n </style>\n <div class="content"></div>\n `}}customElements.define("hs-task-detail",v);class m extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_tasks",new Map),e(this,"_history",new Map),e(this,"$canvas"),e(this,"ctx"),e(this,"timeRange",6e4),e(this,"zoom",1),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){if(this.render(),this.$canvas=this._shadow.querySelector("canvas"),!this.$canvas)return void console.error("[Timeline] Canvas not found");if(this.ctx=this.$canvas.getContext("2d"),!this.ctx)return void console.error("[Timeline] Canvas context not available");this.setupZoom(),this.startLoop();const t=this._shadow.querySelector(".canvas-container");if(t){new ResizeObserver(()=>{requestAnimationFrame(()=>this.draw())}).observe(t)}}set data(t){this._tasks=t.tasks,this._history=t.history}set defaultZoom(t){if(t>=.5&&t<=5){this.zoom=t,this.timeRange=6e4/this.zoom;const e=this._shadow.querySelector(".zoom-slider");e&&(e.value=t.toString()),this.updateZoomLabel()}}updateTexts(){this.updateZoomLabel()}updateZoomLabel(){const t=this._shadow.querySelector(".zoom-label");t&&(t.textContent=`${r("timeline.zoom")}: ${this.zoom}x (${Math.round(this.timeRange/1e3)}s)`)}setupZoom(){const t=this._shadow.querySelector(".zoom-slider"),e=this._shadow.querySelector(".zoom-out"),s=this._shadow.querySelector(".zoom-in"),n=t=>{this.zoom=t,this.timeRange=6e4/this.zoom,this.updateZoomLabel()};null==t||t.addEventListener("input",t=>{const e=parseFloat(t.target.value);n(e)}),null==e||e.addEventListener("click",()=>{const e=Math.max(.5,this.zoom-.5);t&&(t.value=e.toString()),n(e)}),null==s||s.addEventListener("click",()=>{const e=Math.min(5,this.zoom+.5);t&&(t.value=e.toString()),n(e)}),this.updateZoomLabel()}startLoop(){const t=()=>{this.isConnected&&(this.draw(),requestAnimationFrame(t))};requestAnimationFrame(t)}draw(){if(!this.ctx||!this.$canvas)return;const t=this._shadow.querySelector(".canvas-container");if(!t)return;const e=window.devicePixelRatio||1,s=t.clientWidth;if(0===s)return;const n=Array.from(this._tasks.keys()),i=t.clientHeight||300,o=40*n.length+60+40,a=Math.max(i,o);this.$canvas.width=s*e,this.$canvas.height=a*e,this.$canvas.style.width=`${s}px`,this.$canvas.style.height=`${a}px`,this.ctx.setTransform(e,0,0,e,0,0);const r=Date.now(),h=r-this.timeRange,l=getComputedStyle(this),d=l.getPropertyValue("--hs-bg").trim()||"#1e1e1e",c=l.getPropertyValue("--hs-text").trim()||"#fff",p=l.getPropertyValue("--hs-text-secondary").trim()||"#888",g=l.getPropertyValue("--hs-border").trim()||"#333",u=l.getPropertyValue("--hs-success").trim()||"#22c55e",b=l.getPropertyValue("--hs-danger").trim()||"#ef4444";this.ctx.fillStyle=d,this.ctx.fillRect(0,0,s,a),this.drawTimeAxis(s,150,h,p,g),n.forEach((t,e)=>{const n=40*e+60;this.drawTaskRow(t,n,s,150,h,r,c,p,g,u,b)}),this.drawLegend(s,a,p,u)}drawTimeAxis(t,e,s,n,i){const o=this.ctx,a=t-e-20;o.fillStyle=n,o.font="10px monospace",o.textAlign="center";for(let r=0;r<=4;r++){const t=e+a/4*r,n=s+this.timeRange/4*r,h=new Date(n).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});o.fillText(h,t,30),o.strokeStyle=i,o.beginPath(),o.moveTo(t,40),o.lineTo(t,this.$canvas.clientHeight-40),o.stroke()}o.textAlign="left",o.fillText(r("timeline.timeRange",{n:Math.round(this.timeRange/1e3)}),10,15)}drawTaskRow(t,e,s,n,i,o,a,r,h,l,d){const c=this.ctx,p=s-n-20;c.fillStyle=a,c.font="11px sans-serif",c.textAlign="left",c.fillText(t,10,e+15);const g=this._tasks.get(t),u="main"===(null==g?void 0:g.driver)?"M":"W",b="W"===u?"#22c55e":"#f59e0b";c.fillStyle=b,c.font="9px monospace",c.fillText(`[${u}]`,10,e+28),c.strokeStyle=h,c.beginPath(),c.moveTo(0,e+35),c.lineTo(s,e+35),c.stroke();(this._history.get(t)||[]).forEach(t=>{if(t.timestamp<i||t.timestamp>o)return;const s=n+(t.timestamp-i)/this.timeRange*p,a=t.duration;if(a<10)c.fillStyle=t.success?l:d,c.beginPath(),c.arc(s,e+15,3,0,2*Math.PI),c.fill();else{const n=Math.max(2,a/this.timeRange*p);c.fillStyle=t.success?l:d,c.globalAlpha=.7,c.fillRect(s,e+5,n,20),c.globalAlpha=1}})}drawLegend(t,e,s,n){const i=this.ctx,o=e-25;i.font="10px sans-serif",i.textAlign="left",i.fillStyle=s;let a=10;i.fillText(`${r("timeline.legend")}:`,a,o),a+=50,i.fillStyle=n,i.beginPath(),i.arc(a,o-4,3,0,2*Math.PI),i.fill(),i.fillStyle=s,i.fillText(r("timeline.instant"),a+10,o),a+=60,i.fillStyle=n,i.globalAlpha=.7,i.fillRect(a,o-8,15,10),i.globalAlpha=1,i.fillStyle=s,i.fillText(r("timeline.duration"),a+20,o),a+=80,i.fillText(`[W] ${r("timeline.workerDriver")}`,a,o),a+=110,i.fillText(`[M] ${r("timeline.mainDriver")}`,a,o)}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--hs-bg);\n overflow: hidden;\n }\n .controls {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n padding: 12px 16px;\n gap: 8px;\n border-bottom: 1px solid var(--hs-border);\n flex-shrink: 0;\n }\n .zoom-label {\n font-size: 11px;\n color: var(--hs-text-secondary);\n }\n .zoom-btn {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n width: 24px;\n height: 24px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .zoom-btn:hover {\n background: var(--hs-primary);\n color: white;\n }\n .zoom-slider {\n width: 100px;\n }\n .canvas-container {\n flex: 1;\n overflow: auto;\n position: relative;\n }\n canvas {\n display: block;\n }\n </style>\n <div class="controls">\n <span class="zoom-label">Zoom:</span>\n <button class="zoom-btn zoom-out">-</button>\n <input type="range" class="zoom-slider" min="0.5" max="5" step="0.5" value="1">\n <button class="zoom-btn zoom-in">+</button>\n </div>\n <div class="canvas-container">\n <canvas></canvas>\n </div>\n `}}customElements.define("hs-timeline",m);class y extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"startX",0),e(this,"startY",0),e(this,"startWidth",0),e(this,"startHeight",0),e(this,"panel",null),e(this,"mode","right"),this._shadow=this.attachShadow({mode:"open"})}isMobile(){return window.innerWidth<=480}connectedCallback(){this.render(),this.addEventListeners(),this.panel=this.closest(".panel"),this.panel&&this.panel.classList.contains("dock-bottom")&&(this.mode="bottom")}addEventListeners(){const t=this._shadow.querySelector(".handle"),e=t=>{if(this.panel&&!this.isMobile())if("right"===this.mode){const e=this.startX-t.clientX,s=Math.max(300,Math.min(window.innerWidth-50,this.startWidth+e));this.panel.style.width=`${s}px`,this.dispatchEvent(new CustomEvent("resize",{detail:{width:s},bubbles:!0,composed:!0}))}else{const e=Math.max(200,Math.min(window.innerHeight-50,this.startHeight+(this.startY-t.clientY)));this.panel.style.height=`${e}px`,this.dispatchEvent(new CustomEvent("resize",{detail:{height:e},bubbles:!0,composed:!0}))}},s=()=>{document.removeEventListener("mousemove",e),document.removeEventListener("mouseup",s),document.body.style.userSelect="",document.body.style.cursor=""};t.addEventListener("mousedown",t=>{this.isMobile()||(this.startX=t.clientX,this.startY=t.clientY,this.panel&&(this.panel.classList.contains("dock-bottom")?(this.mode="bottom",this.startHeight=this.panel.offsetHeight):(this.mode="right",this.startWidth=this.panel.offsetWidth)),document.addEventListener("mousemove",e),document.addEventListener("mouseup",s),document.body.style.userSelect="none",document.body.style.cursor="right"===this.mode?"col-resize":"row-resize")})}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n z-index: 100;\n }\n .handle {\n background: transparent;\n transition: background 0.2s;\n }\n .handle:hover {\n background: var(--hs-primary);\n }\n \n /* Right Dock Mode (Vertical Handle on Left) */\n :host-context(.dock-right) .handle {\n width: 4px;\n height: 100%;\n cursor: col-resize;\n position: absolute;\n left: 0;\n top: 0;\n }\n\n /* Bottom Dock Mode (Horizontal Handle on Top) */\n :host-context(.dock-bottom) .handle {\n width: 100%;\n height: 4px;\n cursor: row-resize;\n position: absolute;\n top: 0;\n left: 0;\n }\n \n /* 移动端隐藏拖拽手柄 */\n @media (max-width: 480px) {\n .handle {\n display: none;\n }\n }\n </style>\n <div class="handle"></div>\n `}}customElements.define("hs-resizer",y);class x extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"store"),e(this,"scheduler"),e(this,"rAFId"),e(this,"lastTime",0),e(this,"$panel"),e(this,"$header"),e(this,"$taskList"),e(this,"$taskDetail"),e(this,"$timeline"),e(this,"$trigger"),e(this,"$overlay"),this._shadow=this.attachShadow({mode:"open"}),this.store=new h}connectedCallback(){const t=this.getAttribute("language");"en"!==t&&"zh"!==t||this.store.setLanguageSync(t),this.render(),this.cacheDom(),this.bindStore();const e=this.getAttribute("dock");console.log("[DevTools] dock attribute:",e),"bottom"===e&&this.store.setDockPosition("bottom");const s=this.getAttribute("theme");"light"!==s&&"dark"!==s&&"auto"!==s||this.store.setTheme(s),"en"!==t&&"zh"!==t||this.store.setLanguage(t);const n=this.getAttribute("trigger-bg"),i=this.getAttribute("trigger-color"),o=this.getAttribute("trigger-position");console.log("[DevTools] trigger attrs:",{triggerBg:n,triggerColor:i,triggerPosition:o}),n&&this.$trigger.setAttribute("bg-color",n),i&&this.$trigger.setAttribute("text-color",i),o&&this.$trigger.setAttribute("position",o);const a=this.getAttribute("default-zoom");if(a){const t=parseFloat(a);!isNaN(t)&&t>=.5&&t<=5&&(this.$timeline.defaultZoom=t)}this.addEventListeners(),this.startLoop()}disconnectedCallback(){this.rAFId&&cancelAnimationFrame(this.rAFId)}setScheduler(t){this.scheduler=t,this.store.setScheduler(t);this.scheduler.getTasks().forEach(t=>this.store.updateTask(t));const e=this.scheduler.isRunning();this.store.setSchedulerRunning(e);const n=()=>{var t;((null==(t=this.scheduler)?void 0:t.getTasks())||[]).forEach(t=>this.store.updateTask(t))};this.scheduler.on(s.SchedulerEvents.TASK_REGISTERED,n),this.scheduler.on(s.SchedulerEvents.TASK_UPDATED,t=>{console.log("[DevTools] task_updated event:",t),n()}),this.scheduler.on(s.SchedulerEvents.TASK_STARTED,n),this.scheduler.on(s.SchedulerEvents.TASK_REMOVED,n),this.scheduler.on(s.SchedulerEvents.TASK_STOPPED,t=>{console.log("[DevTools] task_stopped event:",t),n()}),this.scheduler.on(s.SchedulerEvents.SCHEDULER_STARTED,()=>{console.log("[DevTools] scheduler_started event"),this.store.setSchedulerRunning(!0),n()}),this.scheduler.on(s.SchedulerEvents.SCHEDULER_STOPPED,()=>{console.log("[DevTools] scheduler_stopped event"),this.store.setSchedulerRunning(!1),n()}),this.scheduler.on(s.SchedulerEvents.TASK_COMPLETED,t=>{var e;n(),t&&t.taskId&&this.store.addHistory(t.taskId,{timestamp:(null==(e=t.task)?void 0:e.lastRun)||Date.now(),duration:t.duration||0,success:!0,error:null})}),this.scheduler.on(s.SchedulerEvents.TASK_FAILED,t=>{var e;n(),t&&t.taskId&&this.store.addHistory(t.taskId,{timestamp:(null==(e=t.task)?void 0:e.lastRun)||Date.now(),duration:t.duration||0,success:!1,error:t.error||"Unknown error"})}),setInterval(()=>{this.store.getState().isOpen&&n()},500)}cacheDom(){this.$panel=this._shadow.querySelector(".panel"),this.$header=this._shadow.querySelector("hs-task-header"),this.$taskList=this._shadow.querySelector("hs-task-list"),this.$taskDetail=this._shadow.querySelector("hs-task-detail"),this.$timeline=this._shadow.querySelector("hs-timeline"),this.$trigger=this._shadow.querySelector("hs-floating-trigger"),this.$overlay=this._shadow.querySelector(".overlay")}bindStore(){try{const t=localStorage.getItem("hs-panel-size");t&&this.store.setPanelSize(JSON.parse(t))}catch(t){}this.store.subscribe("isOpen",t=>{const e=this.store.getState().dockPosition,s=this.store.getState().panelSize;t?(this.$panel.classList.add("open"),this.$trigger.style.display="none",this.$overlay.style.display="block","right"===e?this.$panel.style.right="0":this.$panel.style.bottom="0"):(this.$panel.classList.remove("open"),this.$trigger.style.display="block",this.$overlay.style.display="none","right"===e?this.$panel.style.right=`-${s.width}px`:this.$panel.style.bottom=`-${s.height}px`)}),this.store.subscribe("theme",t=>{const e="auto"===t?"light":t;this.setAttribute("theme",e),this.$header.setAttribute("theme",e),this.$taskList.setAttribute("theme",e),this.$taskDetail.setAttribute("theme",e),this.$timeline.setAttribute("theme",e),this.$header.theme=t}),this.store.subscribe("tasks",t=>{this.$taskList.tasks=t,this.$timeline.data={tasks:t,history:this.store.getState().history};let e=0;t.forEach(t=>{"idle"!==t.status&&"running"!==t.status||e++}),this.$header.stats={active:e,total:t.size};const s=this.store.getState().selectedTaskId;s&&t.has(s)&&(this.$taskDetail.task=t.get(s)||null)}),this.store.subscribe("history",t=>{this.$timeline.data={tasks:this.store.getState().tasks,history:t};const e=this.store.getState().selectedTaskId;e&&(this.$taskDetail.history=t.get(e)||[])}),this.store.subscribe("selectedTaskId",t=>{if("tasks"===this.store.getState().activeTab)if(t){this.$taskList.style.display="none",this.$taskDetail.style.display="block";const e=this.store.getState().tasks.get(t),s=this.store.getState().history.get(t);this.$taskDetail.task=e||null,this.$taskDetail.history=s||[]}else this.$taskList.style.display="block",this.$taskDetail.style.display="none"}),this.store.subscribe("activeTab",t=>{this.$header.activeTab=t,"tasks"===t?(this.$taskList.style.display="block",this.$timeline.style.display="none",this.store.getState().selectedTaskId?(this.$taskList.style.display="none",this.$taskDetail.style.display="block"):(this.$taskList.style.display="block",this.$taskDetail.style.display="none")):(this.$taskList.style.display="none",this.$taskDetail.style.display="none",this.$timeline.style.display="block")}),this.store.subscribe("dockPosition",t=>{this.$header.dockPosition=t;const e=this.store.getState().panelSize,s=this.store.getState().isOpen,n=window.innerWidth<=480;if("right"===t){this.$panel.classList.add("dock-right"),this.$panel.classList.remove("dock-bottom");const t=n?window.innerWidth:e.width;this.$panel.style.width=n?"100vw":`${t}px`,this.$panel.style.height="100vh",this.$panel.style.bottom="",this.$panel.style.right=s?"0":`-${t}px`}else{this.$panel.classList.add("dock-bottom"),this.$panel.classList.remove("dock-right"),this.$panel.style.width="100%";const t=n?"50vh":`${e.height}px`;this.$panel.style.height=t,this.$panel.style.right="",this.$panel.style.bottom=s?"0":n?"-50vh":`-${e.height}px`}}),this.store.subscribe("panelSize",t=>{const e=this.store.getState().dockPosition;"right"===e&&t.width?(this.$panel.style.width=`${t.width}px`,this.$panel.style.right=this.store.getState().isOpen?"0":`-${t.width}px`):"bottom"===e&&t.height&&(this.$panel.style.height=`${t.height}px`,this.$panel.style.bottom=this.store.getState().isOpen?"0":`-${t.height}px`)}),this.store.subscribe("language",t=>{var e,s,n,i;this.$header.language=t,this.$taskList.updateHeaders(),null==(s=(e=this.$taskDetail).updateTexts)||s.call(e),null==(i=(n=this.$timeline).updateTexts)||i.call(n)}),this.store.subscribe("filterText",t=>{const e=this.store.getState().tasks;this.$taskList.filter(t,e)}),this.store.subscribe("schedulerRunning",t=>{this.$header.schedulerRunning=t})}addEventListeners(){this.$trigger.addEventListener("toggle",()=>{this.store.toggle()}),this.$header.addEventListener("close",t=>{t.stopPropagation(),this.store.toggle()}),this.$header.addEventListener("dock-toggle",()=>{const t=this.store.getState().dockPosition;this.store.setDockPosition("right"===t?"bottom":"right")}),this.$header.addEventListener("theme-toggle",t=>{const e=t.detail;this.store.setTheme(e)}),this.$header.addEventListener("lang-toggle",t=>{const e=t.detail;this.store.setLanguage(e)}),this.$header.addEventListener("tab-change",t=>{const e=t.detail;this.store.setTab(e)}),this.$header.addEventListener("search",t=>{const e=t.detail;this.store.setFilterText(e)}),this.$overlay.addEventListener("click",()=>{this.store.toggle()}),this.$taskList.addEventListener("task-select",t=>{const e=t.detail;this.store.selectTask(e)}),this.$taskDetail.addEventListener("back",()=>{this.store.selectTask(null)}),this.$taskList.addEventListener("task-action",t=>{const{action:e,id:s}=t.detail;switch(console.log("[DevTools] task-action:",e,s),e){case"trigger":this.store.triggerTask(s);break;case"stop":this.store.stopTask(s);break;case"start":this.store.startTask(s);break;case"remove":confirm(`Remove task "${s}"?`)&&this.store.removeTask(s)}})}startLoop(){const t=e=>{const s=e-this.lastTime;this.lastTime=e;const n=1e3/s;this.$header&&(this.$header.fps=n),this.rAFId=requestAnimationFrame(t)};this.rAFId=requestAnimationFrame(t)}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n font-family: var(--hs-font-family);\n font-size: var(--hs-font-size);\n color: var(--hs-text);\n line-height: var(--hs-line-height);\n }\n .overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.5);\n z-index: calc(var(--hs-z-index) - 1); /* 确保在面板之下,但在应用之上 */\n display: none; /* 默认隐藏 */\n }\n .panel {\n position: fixed;\n background: var(--hs-bg);\n box-shadow: var(--hs-shadow);\n z-index: var(--hs-z-index);\n transition: all 0.3s ease;\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--hs-border);\n }\n /* Default Right Dock */\n .panel.dock-right {\n top: 0;\n right: -500px;\n width: 500px;\n height: 100vh;\n border-left: 1px solid var(--hs-border);\n border-top: none;\n }\n \n /* Bottom Dock */\n .panel.dock-bottom {\n bottom: -50vh;\n left: 0;\n width: 100%;\n height: 50vh;\n max-height: 50vh;\n border-top: 1px solid var(--hs-border);\n border-left: none;\n }\n\n .content {\n flex: 1;\n overflow: hidden;\n position: relative;\n display: flex;\n flex-direction: column;\n }\n .content > * {\n flex: 1;\n min-height: 0;\n }\n \n /* Mobile - 固定尺寸,禁用拖拽 */\n @media (max-width: 480px) {\n .panel.dock-right {\n width: 100vw !important;\n right: -100vw;\n }\n .panel.dock-right.open {\n right: 0;\n }\n .panel.dock-bottom {\n height: 50vh !important;\n max-height: 50vh !important;\n bottom: -50vh;\n }\n .panel.dock-bottom.open {\n bottom: 0;\n }\n }\n </style>\n \n <div class="overlay"></div>\n <hs-floating-trigger></hs-floating-trigger>\n \n <div class="panel dock-right">\n <hs-resizer></hs-resizer>\n <hs-task-header></hs-task-header>\n <div class="content">\n <hs-task-list></hs-task-list>\n <hs-task-detail style="display:none"></hs-task-detail>\n <hs-timeline style="display:none"></hs-timeline>\n </div>\n </div>\n `}}customElements.define("hs-devtools",x),exports.DevTools=x;
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),e(this,"namespaceIndex"),this.tasks=new Map,this.namespaceIndex=new Map}addTask(t){var e,s;if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t);const i=(null==(e=t.options)?void 0:e.namespace)||"default";this.namespaceIndex.has(i)||this.namespaceIndex.set(i,new Set),null==(s=this.namespaceIndex.get(i))||s.add(t.id)}getTask(t){return this.tasks.get(t)}deleteTask(t){var e,s,i;const r=this.tasks.get(t);if(!r)return!1;const n=(null==(e=r.options)?void 0:e.namespace)||"default";return null==(s=this.namespaceIndex.get(n))||s.delete(t),0===(null==(i=this.namespaceIndex.get(n))?void 0:i.size)&&this.namespaceIndex.delete(n),this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}getTasksByNamespace(t){const e=this.namespaceIndex.get(t);return e?Array.from(e).map(t=>this.tasks.get(t)).filter(Boolean):[]}clear(){this.tasks.clear(),this.namespaceIndex.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){var e,s,i;const r=o(t);let n=new Date((new Date).getTime()+1e3);n.setMilliseconds(0);let l=0;for(;l<126144e3;){if(a(n,r))return n;const t=n.getSeconds(),o=n.getMinutes(),c=n.getHours();if(!r.second.includes(t)){const s=null!=(e=r.second.find(e=>e>t))?e:r.second[0];s>t?n.setSeconds(s):n.setMinutes(o+1,s),n.setMilliseconds(0),l++;continue}if(!r.minute.includes(o)){const t=null!=(s=r.minute.find(t=>t>o))?s:r.minute[0];t>o?n.setMinutes(t,r.second[0]):n.setHours(c+1,t,r.second[0]),n.setMilliseconds(0),l++;continue}if(!r.hour.includes(c)){const t=null!=(i=r.hour.find(t=>t>c))?i:r.hour[0];t>c||n.setDate(n.getDate()+1),n.setHours(t,r.minute[0],r.second[0]),n.setMilliseconds(0),l++;continue}n=new Date(n.getTime()+1e3),l++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){var e;!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const r={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(r),this.log(`Task created: ${r.id}`),this.emit(i.TASK_REGISTERED,{taskId:r.id,task:r}),this.notify(),this.running&&(r.status=s.IDLE,(null==(e=r.options)?void 0:e.runImmediately)&&this.triggerTask(r.id),this.scheduleTask(r))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(t){return t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(t){if(!t&&this.running)return;this.log(t?`Scheduler starting for scope: ${t}`:"Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{var e;t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&((null==(e=t.options)?void 0:e.runImmediately)&&this.triggerTask(t.id),this.scheduleTask(t))}),t||(this.running=!0),this.notify()}stop(t){if(!t&&!this.running)return;this.log(t?`Scheduler stopping for scope: ${t}`:"Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{const e=this.timers.get(t.id);e&&(this.getTimerStrategy(t).cancel(e),this.timers.delete(t.id)),t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),t||(this.running=!1),this.notify()}scheduleTask(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!r&&t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function f(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class T{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==f?new f:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class p{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const y="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-Bxtz0rO_.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>{var i;return{id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id),namespace:(null==(i=e.options)?void 0:i.namespace)||"default"}}),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(y)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new p),S):(E||(E=new T),E);return new h}(t),t,function(){if(y)return t=>"main"===t?(S||(S=new p),S):(E||(E=new T),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
1
+ "use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),e(this,"namespaceIndex"),this.tasks=new Map,this.namespaceIndex=new Map}addTask(t){var e,s;if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t);const i=(null==(e=t.options)?void 0:e.namespace)||"default";this.namespaceIndex.has(i)||this.namespaceIndex.set(i,new Set),null==(s=this.namespaceIndex.get(i))||s.add(t.id)}getTask(t){return this.tasks.get(t)}deleteTask(t){var e,s,i;const r=this.tasks.get(t);if(!r)return!1;const n=(null==(e=r.options)?void 0:e.namespace)||"default";return null==(s=this.namespaceIndex.get(n))||s.delete(t),0===(null==(i=this.namespaceIndex.get(n))?void 0:i.size)&&this.namespaceIndex.delete(n),this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}getTasksByNamespace(t){const e=this.namespaceIndex.get(t);return e?Array.from(e).map(t=>this.tasks.get(t)).filter(Boolean):[]}clear(){this.tasks.clear(),this.namespaceIndex.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){var e,s,i;const r=o(t);let n=new Date((new Date).getTime()+1e3);n.setMilliseconds(0);let l=0;for(;l<126144e3;){if(a(n,r))return n;const t=n.getSeconds(),o=n.getMinutes(),c=n.getHours();if(!r.second.includes(t)){const s=null!=(e=r.second.find(e=>e>t))?e:r.second[0];s>t?n.setSeconds(s):n.setMinutes(o+1,s),n.setMilliseconds(0),l++;continue}if(!r.minute.includes(o)){const t=null!=(s=r.minute.find(t=>t>o))?s:r.minute[0];t>o?n.setMinutes(t,r.second[0]):n.setHours(c+1,t,r.second[0]),n.setMilliseconds(0),l++;continue}if(!r.hour.includes(c)){const t=null!=(i=r.hour.find(t=>t>c))?i:r.hour[0];t>c||n.setDate(n.getDate()+1),n.setHours(t,r.minute[0],r.second[0]),n.setMilliseconds(0),l++;continue}n=new Date(n.getTime()+1e3),l++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){var e;!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const r={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(r),this.log(`Task created: ${r.id}`),this.emit(i.TASK_REGISTERED,{taskId:r.id,task:r}),this.notify(),this.running&&(r.status=s.IDLE,(null==(e=r.options)?void 0:e.runImmediately)&&this.triggerTask(r.id),this.scheduleTask(r))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(t){return t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(t){if(!t&&this.running)return;this.log(t?`Scheduler starting for scope: ${t}`:"Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{var e;t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&((null==(e=t.options)?void 0:e.runImmediately)&&this.triggerTask(t.id),this.scheduleTask(t))}),t||(this.running=!0),this.notify()}stop(t){if(!t&&!this.running)return;this.log(t?`Scheduler stopping for scope: ${t}`:"Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{const e=this.timers.get(t.id);e&&(this.getTimerStrategy(t).cancel(e),this.timers.delete(t.id)),t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),t||(this.running=!1),this.notify()}scheduleTask(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!r&&t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function f(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class T{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==f?new f:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class p{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const y="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-CRTqUH_8.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>{var i;return{id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id),namespace:(null==(i=e.options)?void 0:i.namespace)||"default"}}),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(y)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new p),S):(E||(E=new T),E);return new h}(t),t,function(){if(y)return t=>"main"===t?(S||(S=new p),S):(E||(E=new T),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
package/dist/index.js CHANGED
@@ -936,7 +936,7 @@ class DevTools {
936
936
  }
937
937
  async mount(scheduler) {
938
938
  try {
939
- await import("./devtools-ByJU-Gv1.js");
939
+ await import("./devtools-B029_YOS.js");
940
940
  await customElements.whenDefined("hs-devtools");
941
941
  this.setupElement(scheduler);
942
942
  } catch (e) {