@mstar-harness/cli 2.2.0 → 2.3.0

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 (2) hide show
  1. package/dist/mstar-harness.js +405 -371
  2. package/package.json +4 -4
@@ -2546,267 +2546,267 @@ function isUnicodeSupported() {
2546
2546
  var common = {
2547
2547
  circleQuestionMark: "(?)",
2548
2548
  questionMarkPrefix: "(?)",
2549
- square: "",
2550
- squareDarkShade: "",
2551
- squareMediumShade: "",
2552
- squareLightShade: "",
2553
- squareTop: "",
2554
- squareBottom: "",
2555
- squareLeft: "",
2556
- squareRight: "",
2557
- squareCenter: "",
2558
- bullet: "",
2559
- dot: "",
2560
- ellipsis: "",
2561
- pointerSmall: "",
2562
- triangleUp: "",
2563
- triangleUpSmall: "",
2564
- triangleDown: "",
2565
- triangleDownSmall: "",
2566
- triangleLeftSmall: "",
2567
- triangleRightSmall: "",
2568
- home: "",
2569
- heart: "",
2570
- musicNote: "",
2571
- musicNoteBeamed: "",
2572
- arrowUp: "",
2573
- arrowDown: "",
2574
- arrowLeft: "",
2575
- arrowRight: "",
2576
- arrowLeftRight: "",
2577
- arrowUpDown: "",
2578
- almostEqual: "",
2579
- notEqual: "",
2580
- lessOrEqual: "",
2581
- greaterOrEqual: "",
2582
- identical: "",
2583
- infinity: "",
2584
- subscriptZero: "",
2585
- subscriptOne: "",
2586
- subscriptTwo: "",
2587
- subscriptThree: "",
2588
- subscriptFour: "",
2589
- subscriptFive: "",
2590
- subscriptSix: "",
2591
- subscriptSeven: "",
2592
- subscriptEight: "",
2593
- subscriptNine: "",
2594
- oneHalf: "½",
2595
- oneThird: "",
2596
- oneQuarter: "¼",
2597
- oneFifth: "",
2598
- oneSixth: "",
2599
- oneEighth: "",
2600
- twoThirds: "",
2601
- twoFifths: "",
2602
- threeQuarters: "¾",
2603
- threeFifths: "",
2604
- threeEighths: "",
2605
- fourFifths: "",
2606
- fiveSixths: "",
2607
- fiveEighths: "",
2608
- sevenEighths: "",
2609
- line: "",
2610
- lineBold: "",
2611
- lineDouble: "",
2612
- lineDashed0: "",
2613
- lineDashed1: "",
2614
- lineDashed2: "",
2615
- lineDashed3: "",
2616
- lineDashed4: "",
2617
- lineDashed5: "",
2618
- lineDashed6: "",
2619
- lineDashed7: "",
2620
- lineDashed8: "",
2621
- lineDashed9: "",
2622
- lineDashed10: "",
2623
- lineDashed11: "",
2624
- lineDashed12: "",
2625
- lineDashed13: "",
2626
- lineDashed14: "",
2627
- lineDashed15: "",
2628
- lineVertical: "",
2629
- lineVerticalBold: "",
2630
- lineVerticalDouble: "",
2631
- lineVerticalDashed0: "",
2632
- lineVerticalDashed1: "",
2633
- lineVerticalDashed2: "",
2634
- lineVerticalDashed3: "",
2635
- lineVerticalDashed4: "",
2636
- lineVerticalDashed5: "",
2637
- lineVerticalDashed6: "",
2638
- lineVerticalDashed7: "",
2639
- lineVerticalDashed8: "",
2640
- lineVerticalDashed9: "",
2641
- lineVerticalDashed10: "",
2642
- lineVerticalDashed11: "",
2643
- lineDownLeft: "",
2644
- lineDownLeftArc: "",
2645
- lineDownBoldLeftBold: "",
2646
- lineDownBoldLeft: "",
2647
- lineDownLeftBold: "",
2648
- lineDownDoubleLeftDouble: "",
2649
- lineDownDoubleLeft: "",
2650
- lineDownLeftDouble: "",
2651
- lineDownRight: "",
2652
- lineDownRightArc: "",
2653
- lineDownBoldRightBold: "",
2654
- lineDownBoldRight: "",
2655
- lineDownRightBold: "",
2656
- lineDownDoubleRightDouble: "",
2657
- lineDownDoubleRight: "",
2658
- lineDownRightDouble: "",
2659
- lineUpLeft: "",
2660
- lineUpLeftArc: "",
2661
- lineUpBoldLeftBold: "",
2662
- lineUpBoldLeft: "",
2663
- lineUpLeftBold: "",
2664
- lineUpDoubleLeftDouble: "",
2665
- lineUpDoubleLeft: "",
2666
- lineUpLeftDouble: "",
2667
- lineUpRight: "",
2668
- lineUpRightArc: "",
2669
- lineUpBoldRightBold: "",
2670
- lineUpBoldRight: "",
2671
- lineUpRightBold: "",
2672
- lineUpDoubleRightDouble: "",
2673
- lineUpDoubleRight: "",
2674
- lineUpRightDouble: "",
2675
- lineUpDownLeft: "",
2676
- lineUpBoldDownBoldLeftBold: "",
2677
- lineUpBoldDownBoldLeft: "",
2678
- lineUpDownLeftBold: "",
2679
- lineUpBoldDownLeftBold: "",
2680
- lineUpDownBoldLeftBold: "",
2681
- lineUpDownBoldLeft: "",
2682
- lineUpBoldDownLeft: "",
2683
- lineUpDoubleDownDoubleLeftDouble: "",
2684
- lineUpDoubleDownDoubleLeft: "",
2685
- lineUpDownLeftDouble: "",
2686
- lineUpDownRight: "",
2687
- lineUpBoldDownBoldRightBold: "",
2688
- lineUpBoldDownBoldRight: "",
2689
- lineUpDownRightBold: "",
2690
- lineUpBoldDownRightBold: "",
2691
- lineUpDownBoldRightBold: "",
2692
- lineUpDownBoldRight: "",
2693
- lineUpBoldDownRight: "",
2694
- lineUpDoubleDownDoubleRightDouble: "",
2695
- lineUpDoubleDownDoubleRight: "",
2696
- lineUpDownRightDouble: "",
2697
- lineDownLeftRight: "",
2698
- lineDownBoldLeftBoldRightBold: "",
2699
- lineDownLeftBoldRightBold: "",
2700
- lineDownBoldLeftRight: "",
2701
- lineDownBoldLeftBoldRight: "",
2702
- lineDownBoldLeftRightBold: "",
2703
- lineDownLeftRightBold: "",
2704
- lineDownLeftBoldRight: "",
2705
- lineDownDoubleLeftDoubleRightDouble: "",
2706
- lineDownDoubleLeftRight: "",
2707
- lineDownLeftDoubleRightDouble: "",
2708
- lineUpLeftRight: "",
2709
- lineUpBoldLeftBoldRightBold: "",
2710
- lineUpLeftBoldRightBold: "",
2711
- lineUpBoldLeftRight: "",
2712
- lineUpBoldLeftBoldRight: "",
2713
- lineUpBoldLeftRightBold: "",
2714
- lineUpLeftRightBold: "",
2715
- lineUpLeftBoldRight: "",
2716
- lineUpDoubleLeftDoubleRightDouble: "",
2717
- lineUpDoubleLeftRight: "",
2718
- lineUpLeftDoubleRightDouble: "",
2719
- lineUpDownLeftRight: "",
2720
- lineUpBoldDownBoldLeftBoldRightBold: "",
2721
- lineUpDownBoldLeftBoldRightBold: "",
2722
- lineUpBoldDownLeftBoldRightBold: "",
2723
- lineUpBoldDownBoldLeftRightBold: "",
2724
- lineUpBoldDownBoldLeftBoldRight: "",
2725
- lineUpBoldDownLeftRight: "",
2726
- lineUpDownBoldLeftRight: "",
2727
- lineUpDownLeftBoldRight: "",
2728
- lineUpDownLeftRightBold: "",
2729
- lineUpBoldDownBoldLeftRight: "",
2730
- lineUpDownLeftBoldRightBold: "",
2731
- lineUpBoldDownLeftBoldRight: "",
2732
- lineUpBoldDownLeftRightBold: "",
2733
- lineUpDownBoldLeftBoldRight: "",
2734
- lineUpDownBoldLeftRightBold: "",
2735
- lineUpDoubleDownDoubleLeftDoubleRightDouble: "",
2736
- lineUpDoubleDownDoubleLeftRight: "",
2737
- lineUpDownLeftDoubleRightDouble: "",
2738
- lineCross: "",
2739
- lineBackslash: "",
2740
- lineSlash: ""
2549
+ square: "\u2588",
2550
+ squareDarkShade: "\u2593",
2551
+ squareMediumShade: "\u2592",
2552
+ squareLightShade: "\u2591",
2553
+ squareTop: "\u2580",
2554
+ squareBottom: "\u2584",
2555
+ squareLeft: "\u258c",
2556
+ squareRight: "\u2590",
2557
+ squareCenter: "\u25a0",
2558
+ bullet: "\u25cf",
2559
+ dot: "\u2024",
2560
+ ellipsis: "\u2026",
2561
+ pointerSmall: "\u203a",
2562
+ triangleUp: "\u25b2",
2563
+ triangleUpSmall: "\u25b4",
2564
+ triangleDown: "\u25bc",
2565
+ triangleDownSmall: "\u25be",
2566
+ triangleLeftSmall: "\u25c2",
2567
+ triangleRightSmall: "\u25b8",
2568
+ home: "\u2302",
2569
+ heart: "\u2665",
2570
+ musicNote: "\u266a",
2571
+ musicNoteBeamed: "\u266b",
2572
+ arrowUp: "\u2191",
2573
+ arrowDown: "\u2193",
2574
+ arrowLeft: "\u2190",
2575
+ arrowRight: "\u2192",
2576
+ arrowLeftRight: "\u2194",
2577
+ arrowUpDown: "\u2195",
2578
+ almostEqual: "\u2248",
2579
+ notEqual: "\u2260",
2580
+ lessOrEqual: "\u2264",
2581
+ greaterOrEqual: "\u2265",
2582
+ identical: "\u2261",
2583
+ infinity: "\u221e",
2584
+ subscriptZero: "\u2080",
2585
+ subscriptOne: "\u2081",
2586
+ subscriptTwo: "\u2082",
2587
+ subscriptThree: "\u2083",
2588
+ subscriptFour: "\u2084",
2589
+ subscriptFive: "\u2085",
2590
+ subscriptSix: "\u2086",
2591
+ subscriptSeven: "\u2087",
2592
+ subscriptEight: "\u2088",
2593
+ subscriptNine: "\u2089",
2594
+ oneHalf: "\u00bd",
2595
+ oneThird: "\u2153",
2596
+ oneQuarter: "\u00bc",
2597
+ oneFifth: "\u2155",
2598
+ oneSixth: "\u2159",
2599
+ oneEighth: "\u215b",
2600
+ twoThirds: "\u2154",
2601
+ twoFifths: "\u2156",
2602
+ threeQuarters: "\u00be",
2603
+ threeFifths: "\u2157",
2604
+ threeEighths: "\u215c",
2605
+ fourFifths: "\u2158",
2606
+ fiveSixths: "\u215a",
2607
+ fiveEighths: "\u215d",
2608
+ sevenEighths: "\u215e",
2609
+ line: "\u2500",
2610
+ lineBold: "\u2501",
2611
+ lineDouble: "\u2550",
2612
+ lineDashed0: "\u2504",
2613
+ lineDashed1: "\u2505",
2614
+ lineDashed2: "\u2508",
2615
+ lineDashed3: "\u2509",
2616
+ lineDashed4: "\u254c",
2617
+ lineDashed5: "\u254d",
2618
+ lineDashed6: "\u2574",
2619
+ lineDashed7: "\u2576",
2620
+ lineDashed8: "\u2578",
2621
+ lineDashed9: "\u257a",
2622
+ lineDashed10: "\u257c",
2623
+ lineDashed11: "\u257e",
2624
+ lineDashed12: "\u2212",
2625
+ lineDashed13: "\u2013",
2626
+ lineDashed14: "\u2010",
2627
+ lineDashed15: "\u2043",
2628
+ lineVertical: "\u2502",
2629
+ lineVerticalBold: "\u2503",
2630
+ lineVerticalDouble: "\u2551",
2631
+ lineVerticalDashed0: "\u2506",
2632
+ lineVerticalDashed1: "\u2507",
2633
+ lineVerticalDashed2: "\u250a",
2634
+ lineVerticalDashed3: "\u250b",
2635
+ lineVerticalDashed4: "\u254e",
2636
+ lineVerticalDashed5: "\u254f",
2637
+ lineVerticalDashed6: "\u2575",
2638
+ lineVerticalDashed7: "\u2577",
2639
+ lineVerticalDashed8: "\u2579",
2640
+ lineVerticalDashed9: "\u257b",
2641
+ lineVerticalDashed10: "\u257d",
2642
+ lineVerticalDashed11: "\u257f",
2643
+ lineDownLeft: "\u2510",
2644
+ lineDownLeftArc: "\u256e",
2645
+ lineDownBoldLeftBold: "\u2513",
2646
+ lineDownBoldLeft: "\u2512",
2647
+ lineDownLeftBold: "\u2511",
2648
+ lineDownDoubleLeftDouble: "\u2557",
2649
+ lineDownDoubleLeft: "\u2556",
2650
+ lineDownLeftDouble: "\u2555",
2651
+ lineDownRight: "\u250c",
2652
+ lineDownRightArc: "\u256d",
2653
+ lineDownBoldRightBold: "\u250f",
2654
+ lineDownBoldRight: "\u250e",
2655
+ lineDownRightBold: "\u250d",
2656
+ lineDownDoubleRightDouble: "\u2554",
2657
+ lineDownDoubleRight: "\u2553",
2658
+ lineDownRightDouble: "\u2552",
2659
+ lineUpLeft: "\u2518",
2660
+ lineUpLeftArc: "\u256f",
2661
+ lineUpBoldLeftBold: "\u251b",
2662
+ lineUpBoldLeft: "\u251a",
2663
+ lineUpLeftBold: "\u2519",
2664
+ lineUpDoubleLeftDouble: "\u255d",
2665
+ lineUpDoubleLeft: "\u255c",
2666
+ lineUpLeftDouble: "\u255b",
2667
+ lineUpRight: "\u2514",
2668
+ lineUpRightArc: "\u2570",
2669
+ lineUpBoldRightBold: "\u2517",
2670
+ lineUpBoldRight: "\u2516",
2671
+ lineUpRightBold: "\u2515",
2672
+ lineUpDoubleRightDouble: "\u255a",
2673
+ lineUpDoubleRight: "\u2559",
2674
+ lineUpRightDouble: "\u2558",
2675
+ lineUpDownLeft: "\u2524",
2676
+ lineUpBoldDownBoldLeftBold: "\u252b",
2677
+ lineUpBoldDownBoldLeft: "\u2528",
2678
+ lineUpDownLeftBold: "\u2525",
2679
+ lineUpBoldDownLeftBold: "\u2529",
2680
+ lineUpDownBoldLeftBold: "\u252a",
2681
+ lineUpDownBoldLeft: "\u2527",
2682
+ lineUpBoldDownLeft: "\u2526",
2683
+ lineUpDoubleDownDoubleLeftDouble: "\u2563",
2684
+ lineUpDoubleDownDoubleLeft: "\u2562",
2685
+ lineUpDownLeftDouble: "\u2561",
2686
+ lineUpDownRight: "\u251c",
2687
+ lineUpBoldDownBoldRightBold: "\u2523",
2688
+ lineUpBoldDownBoldRight: "\u2520",
2689
+ lineUpDownRightBold: "\u251d",
2690
+ lineUpBoldDownRightBold: "\u2521",
2691
+ lineUpDownBoldRightBold: "\u2522",
2692
+ lineUpDownBoldRight: "\u251f",
2693
+ lineUpBoldDownRight: "\u251e",
2694
+ lineUpDoubleDownDoubleRightDouble: "\u2560",
2695
+ lineUpDoubleDownDoubleRight: "\u255f",
2696
+ lineUpDownRightDouble: "\u255e",
2697
+ lineDownLeftRight: "\u252c",
2698
+ lineDownBoldLeftBoldRightBold: "\u2533",
2699
+ lineDownLeftBoldRightBold: "\u252f",
2700
+ lineDownBoldLeftRight: "\u2530",
2701
+ lineDownBoldLeftBoldRight: "\u2531",
2702
+ lineDownBoldLeftRightBold: "\u2532",
2703
+ lineDownLeftRightBold: "\u252e",
2704
+ lineDownLeftBoldRight: "\u252d",
2705
+ lineDownDoubleLeftDoubleRightDouble: "\u2566",
2706
+ lineDownDoubleLeftRight: "\u2565",
2707
+ lineDownLeftDoubleRightDouble: "\u2564",
2708
+ lineUpLeftRight: "\u2534",
2709
+ lineUpBoldLeftBoldRightBold: "\u253b",
2710
+ lineUpLeftBoldRightBold: "\u2537",
2711
+ lineUpBoldLeftRight: "\u2538",
2712
+ lineUpBoldLeftBoldRight: "\u2539",
2713
+ lineUpBoldLeftRightBold: "\u253a",
2714
+ lineUpLeftRightBold: "\u2536",
2715
+ lineUpLeftBoldRight: "\u2535",
2716
+ lineUpDoubleLeftDoubleRightDouble: "\u2569",
2717
+ lineUpDoubleLeftRight: "\u2568",
2718
+ lineUpLeftDoubleRightDouble: "\u2567",
2719
+ lineUpDownLeftRight: "\u253c",
2720
+ lineUpBoldDownBoldLeftBoldRightBold: "\u254b",
2721
+ lineUpDownBoldLeftBoldRightBold: "\u2548",
2722
+ lineUpBoldDownLeftBoldRightBold: "\u2547",
2723
+ lineUpBoldDownBoldLeftRightBold: "\u254a",
2724
+ lineUpBoldDownBoldLeftBoldRight: "\u2549",
2725
+ lineUpBoldDownLeftRight: "\u2540",
2726
+ lineUpDownBoldLeftRight: "\u2541",
2727
+ lineUpDownLeftBoldRight: "\u253d",
2728
+ lineUpDownLeftRightBold: "\u253e",
2729
+ lineUpBoldDownBoldLeftRight: "\u2542",
2730
+ lineUpDownLeftBoldRightBold: "\u253f",
2731
+ lineUpBoldDownLeftBoldRight: "\u2543",
2732
+ lineUpBoldDownLeftRightBold: "\u2544",
2733
+ lineUpDownBoldLeftBoldRight: "\u2545",
2734
+ lineUpDownBoldLeftRightBold: "\u2546",
2735
+ lineUpDoubleDownDoubleLeftDoubleRightDouble: "\u256c",
2736
+ lineUpDoubleDownDoubleLeftRight: "\u256b",
2737
+ lineUpDownLeftDoubleRightDouble: "\u256a",
2738
+ lineCross: "\u2573",
2739
+ lineBackslash: "\u2572",
2740
+ lineSlash: "\u2571"
2741
2741
  };
2742
2742
  var specialMainSymbols = {
2743
- tick: "",
2744
- info: "",
2745
- warning: "",
2746
- cross: "",
2747
- squareSmall: "",
2748
- squareSmallFilled: "",
2749
- circle: "",
2750
- circleFilled: "",
2751
- circleDotted: "",
2752
- circleDouble: "",
2753
- circleCircle: "",
2754
- circleCross: "",
2755
- circlePipe: "",
2756
- radioOn: "",
2757
- radioOff: "",
2758
- checkboxOn: "",
2759
- checkboxOff: "",
2760
- checkboxCircleOn: "",
2761
- checkboxCircleOff: "",
2762
- pointer: "",
2763
- triangleUpOutline: "",
2764
- triangleLeft: "",
2765
- triangleRight: "",
2766
- lozenge: "",
2767
- lozengeOutline: "",
2768
- hamburger: "",
2769
- smiley: "",
2770
- mustache: "",
2771
- star: "",
2772
- play: "",
2773
- nodejs: "",
2774
- oneSeventh: "",
2775
- oneNinth: "",
2776
- oneTenth: ""
2743
+ tick: "\u2714",
2744
+ info: "\u2139",
2745
+ warning: "\u26a0",
2746
+ cross: "\u2718",
2747
+ squareSmall: "\u25fb",
2748
+ squareSmallFilled: "\u25fc",
2749
+ circle: "\u25ef",
2750
+ circleFilled: "\u25c9",
2751
+ circleDotted: "\u25cc",
2752
+ circleDouble: "\u25ce",
2753
+ circleCircle: "\u24de",
2754
+ circleCross: "\u24e7",
2755
+ circlePipe: "\u24be",
2756
+ radioOn: "\u25c9",
2757
+ radioOff: "\u25ef",
2758
+ checkboxOn: "\u2612",
2759
+ checkboxOff: "\u2610",
2760
+ checkboxCircleOn: "\u24e7",
2761
+ checkboxCircleOff: "\u24be",
2762
+ pointer: "\u276f",
2763
+ triangleUpOutline: "\u25b3",
2764
+ triangleLeft: "\u25c0",
2765
+ triangleRight: "\u25b6",
2766
+ lozenge: "\u25c6",
2767
+ lozengeOutline: "\u25c7",
2768
+ hamburger: "\u2630",
2769
+ smiley: "\u32e1",
2770
+ mustache: "\u0df4",
2771
+ star: "\u2605",
2772
+ play: "\u25b6",
2773
+ nodejs: "\u2b22",
2774
+ oneSeventh: "\u2150",
2775
+ oneNinth: "\u2151",
2776
+ oneTenth: "\u2152"
2777
2777
  };
2778
2778
  var specialFallbackSymbols = {
2779
- tick: "",
2779
+ tick: "\u221a",
2780
2780
  info: "i",
2781
- warning: "",
2782
- cross: "×",
2783
- squareSmall: "",
2784
- squareSmallFilled: "",
2781
+ warning: "\u203c",
2782
+ cross: "\u00d7",
2783
+ squareSmall: "\u25a1",
2784
+ squareSmallFilled: "\u25a0",
2785
2785
  circle: "( )",
2786
2786
  circleFilled: "(*)",
2787
2787
  circleDotted: "( )",
2788
2788
  circleDouble: "( )",
2789
- circleCircle: "()",
2790
- circleCross: "(×)",
2791
- circlePipe: "()",
2789
+ circleCircle: "(\u25cb)",
2790
+ circleCross: "(\u00d7)",
2791
+ circlePipe: "(\u2502)",
2792
2792
  radioOn: "(*)",
2793
2793
  radioOff: "( )",
2794
- checkboxOn: "[×]",
2794
+ checkboxOn: "[\u00d7]",
2795
2795
  checkboxOff: "[ ]",
2796
- checkboxCircleOn: "(×)",
2796
+ checkboxCircleOn: "(\u00d7)",
2797
2797
  checkboxCircleOff: "( )",
2798
2798
  pointer: ">",
2799
- triangleUpOutline: "",
2800
- triangleLeft: "",
2801
- triangleRight: "",
2802
- lozenge: "",
2803
- lozengeOutline: "",
2804
- hamburger: "",
2805
- smiley: "",
2806
- mustache: "┌─┐",
2807
- star: "",
2808
- play: "",
2809
- nodejs: "",
2799
+ triangleUpOutline: "\u2206",
2800
+ triangleLeft: "\u25c4",
2801
+ triangleRight: "\u25ba",
2802
+ lozenge: "\u2666",
2803
+ lozengeOutline: "\u25ca",
2804
+ hamburger: "\u2261",
2805
+ smiley: "\u263a",
2806
+ mustache: "\u250c\u2500\u2510",
2807
+ star: "\u2736",
2808
+ play: "\u25ba",
2809
+ nodejs: "\u2666",
2810
2810
  oneSeventh: "1/7",
2811
2811
  oneNinth: "1/9",
2812
2812
  oneTenth: "1/10"
@@ -2832,7 +2832,7 @@ var defaultTheme = {
2832
2832
  },
2833
2833
  spinner: {
2834
2834
  interval: 80,
2835
- frames: ["", "", "", "", "", "", "", "", "", ""].map((frame) => styleText("yellow", frame))
2835
+ frames: ["\u280b", "\u2819", "\u2839", "\u2838", "\u283c", "\u2834", "\u2826", "\u2827", "\u2807", "\u280f"].map((frame) => styleText("yellow", frame))
2836
2836
  },
2837
2837
  keybindings: [],
2838
2838
  style: {
@@ -3078,7 +3078,7 @@ var dist_default3 = fastStringWidth;
3078
3078
 
3079
3079
  // ../../node_modules/fast-wrap-ansi/lib/main.js
3080
3080
  var ESC = "\x1B";
3081
- var CSI = "›";
3081
+ var CSI = "\u009b";
3082
3082
  var END_CODE = 39;
3083
3083
  var ANSI_ESCAPE_BELL = "\x07";
3084
3084
  var ANSI_CSI = "[";
@@ -3808,7 +3808,7 @@ var selectTheme = {
3808
3808
  style: {
3809
3809
  disabled: (text) => styleText3("dim", text),
3810
3810
  description: (text) => styleText3("cyan", text),
3811
- keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText3("bold", key)} ${styleText3("dim", action)}`).join(styleText3("dim", " "))
3811
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText3("bold", key)} ${styleText3("dim", action)}`).join(styleText3("dim", " \u2022 "))
3812
3812
  },
3813
3813
  i18n: { disabledError: "This option is disabled and cannot be selected." },
3814
3814
  indexMode: "hidden"
@@ -3933,8 +3933,8 @@ var dist_default4 = createPrompt((config, done) => {
3933
3933
  }, []);
3934
3934
  const message = theme.style.message(config.message, status);
3935
3935
  const helpLine = theme.style.keysHelpTip([
3936
- ["↑↓", "navigate"],
3937
- ["", "select"]
3936
+ ["\u2191\u2193", "navigate"],
3937
+ ["\u23ce", "select"]
3938
3938
  ]);
3939
3939
  let separatorCount = 0;
3940
3940
  const page = usePagination({
@@ -4109,7 +4109,7 @@ function resolveSpecsDir(harnessDir, opts = {}) {
4109
4109
  }
4110
4110
  function assertSafePathComponent(value, what) {
4111
4111
  if (value === "" || value === "." || value === ".." || !/^[A-Za-z0-9._-]+$/.test(value)) {
4112
- throw new Error(`${what} must be a single safe path component ([A-Za-z0-9._-]+; not "", ".", "..", or containing "/" or "\\") got ${JSON.stringify(value)}`);
4112
+ throw new Error(`${what} must be a single safe path component ([A-Za-z0-9._-]+; not "", ".", "..", or containing "/" or "\\") \u2014 got ${JSON.stringify(value)}`);
4113
4113
  }
4114
4114
  }
4115
4115
  function resolveSddDir(harnessDir, planId) {
@@ -4126,7 +4126,7 @@ var GITIGNORE_SNIPPET = `# Morning Star harness (.mstar/)
4126
4126
  !.mstar/specs/
4127
4127
  !.mstar/specs/**
4128
4128
  `;
4129
- var GITIGNORE_SNIPPET_AGENTS = `# Morning Star harness (.agents/) legacy
4129
+ var GITIGNORE_SNIPPET_AGENTS = `# Morning Star harness (.agents/) \u2014 legacy
4130
4130
  # Default-ignore everything under .agents/, then re-include the tracked results.
4131
4131
  .agents/**
4132
4132
  !.agents/AGENTS.md
@@ -4171,7 +4171,7 @@ async function withStatusWriteLock(statusPath, fn, opts = {}) {
4171
4171
  const lockDir = join3(dirname3(resolve3(statusPath)), STATUS_WRITE_LOCKDIR);
4172
4172
  const held = heldLockDirs.getStore();
4173
4173
  if (held !== undefined && held.has(lockDir)) {
4174
- throw new Error(`${lockDir} is already held by this process in this async context withStatusWriteLock is not reentrant; a nested acquisition on the same status.json is a bug`);
4174
+ throw new Error(`${lockDir} is already held by this process in this async context \u2014 withStatusWriteLock is not reentrant; a nested acquisition on the same status.json is a bug`);
4175
4175
  }
4176
4176
  const timeoutMs = opts.timeoutMs ?? 30000;
4177
4177
  const pollMs = opts.pollMs ?? 25;
@@ -4187,7 +4187,7 @@ async function withStatusWriteLock(statusPath, fn, opts = {}) {
4187
4187
  if (error.code !== "EEXIST")
4188
4188
  throw error;
4189
4189
  if (Date.now() >= deadline) {
4190
- throw new Error(`${lockDir} already exists another writer holds the status write lock; Blocked (same-host exclusive lock; status-and-residuals.md § Same-host exclusive write lock). ` + `Recovery: remove ${lockDir} if no writer is alive (holder.pid inside names the acquiring process)`);
4190
+ throw new Error(`${lockDir} already exists \u2014 another writer holds the status write lock; Blocked (same-host exclusive lock; status-and-residuals.md \u00a7 Same-host exclusive write lock). ` + `Recovery: remove ${lockDir} if no writer is alive (holder.pid inside names the acquiring process)`);
4191
4191
  }
4192
4192
  await sleep(pollMs);
4193
4193
  }
@@ -4212,7 +4212,7 @@ async function withStatusWriteLock(statusPath, fn, opts = {}) {
4212
4212
  } catch {}
4213
4213
  }
4214
4214
  }
4215
- var BRANCH_FORMS_HINT = '"Working branch: <existing>" | "Working branch: create <new> from <base>" | "Branch policy: direct on <branch> <reason>"';
4215
+ var BRANCH_FORMS_HINT = '"Working branch: <existing>" | "Working branch: create <new> from <base>" | "Branch policy: direct on <branch> \u2014 <reason>"';
4216
4216
  var REQUIRED_FIELDS = [
4217
4217
  { key: "executeAs", label: "Execute as", code: "execute-as" },
4218
4218
  { key: "delegation", label: "Delegation", code: "delegation" },
@@ -4279,7 +4279,7 @@ function parseAssignmentBranchForms(assignmentText) {
4279
4279
  if (fields.branchPolicy !== undefined && fields.branchPolicy !== "") {
4280
4280
  const direct = fields.branchPolicy.match(/^direct\s+on\s+(\S+)/i);
4281
4281
  if (direct) {
4282
- const strict = fields.branchPolicy.match(/^direct\s+on\s+(\S+)(?:\s*(?:[—–]|--|-)\s*(.+))?$/);
4282
+ const strict = fields.branchPolicy.match(/^direct\s+on\s+(\S+)(?:\s*(?:[\u2014\u2013]|--|-)\s*(.+))?$/);
4283
4283
  forms.directOn = { branch: direct[1].trim(), reason: strict ? (strict[2] ?? "").trim() : "" };
4284
4284
  }
4285
4285
  }
@@ -4308,7 +4308,7 @@ function validateAssignmentFields(assignmentText, opts = {}) {
4308
4308
  if (formCount === 0) {
4309
4309
  violations.push(violation2("high", "assignment.field.branch-missing", "writable assignment must contain exactly one branch form", `add exactly one of: ${BRANCH_FORMS_HINT}`));
4310
4310
  } else if (formCount > 1) {
4311
- violations.push(violation2("high", "assignment.field.branch-multiple", `writable assignment contains ${formCount} branch forms (Working branch + Branch policy) exactly one required`, `keep exactly one of: ${BRANCH_FORMS_HINT}`));
4311
+ violations.push(violation2("high", "assignment.field.branch-multiple", `writable assignment contains ${formCount} branch forms (Working branch + Branch policy) \u2014 exactly one required`, `keep exactly one of: ${BRANCH_FORMS_HINT}`));
4312
4312
  } else if (workingPresent) {
4313
4313
  const create = forms.createForm;
4314
4314
  if (create !== undefined && (create.base === undefined || create.base.trim() === "" || create.name.trim() === "")) {
@@ -4317,9 +4317,9 @@ function validateAssignmentFields(assignmentText, opts = {}) {
4317
4317
  } else if (policyPresent) {
4318
4318
  const direct = forms.directOn;
4319
4319
  if (direct === undefined) {
4320
- violations.push(violation2("high", "assignment.field.branch-policy-missing-branch", `unparseable Branch policy: "${fields.branchPolicy}" (expected "direct on <branch> <reason>")`, "start the field with `direct on <branch>`"));
4320
+ violations.push(violation2("high", "assignment.field.branch-policy-missing-branch", `unparseable Branch policy: "${fields.branchPolicy}" (expected "direct on <branch> \u2014 <reason>")`, "start the field with `direct on <branch>`"));
4321
4321
  } else if (direct.reason === "") {
4322
- violations.push(violation2("high", "assignment.field.branch-policy-missing-reason", `Branch policy "direct on ${direct.branch}" is missing the reason`, 'append " <reason>" after the branch name'));
4322
+ violations.push(violation2("high", "assignment.field.branch-policy-missing-reason", `Branch policy "direct on ${direct.branch}" is missing the reason`, 'append "\u2014 <reason>" after the branch name'));
4323
4323
  }
4324
4324
  }
4325
4325
  }
@@ -4330,7 +4330,7 @@ function assertDefaultBranchProtected(branch, opts = {}) {
4330
4330
  const violations = [];
4331
4331
  const normalized = branch.trim();
4332
4332
  if (normalized !== "" && defaultBranches.includes(normalized) && opts.directOnException !== true) {
4333
- violations.push(violation2("high", "dispatch.default-branch.protected", `writable work on default protected branch "${normalized}" requires an explicit direct-on exception`, `add "Branch policy: direct on ${normalized} <reason>" to the Assignment, or use a feature branch`));
4333
+ violations.push(violation2("high", "dispatch.default-branch.protected", `writable work on default protected branch "${normalized}" requires an explicit direct-on exception`, `add "Branch policy: direct on ${normalized} \u2014 <reason>" to the Assignment, or use a feature branch`));
4334
4334
  }
4335
4335
  return { ok: violations.length === 0, violations };
4336
4336
  }
@@ -4347,9 +4347,9 @@ function executionModeToN(executionMode, opts = {}) {
4347
4347
  } else if (mode === "targeted") {
4348
4348
  const seats = [...new Set((opts.seats ?? []).map((s) => s.trim()).filter((s) => s !== ""))];
4349
4349
  if (seats.length === 0) {
4350
- violations.push(violation2("high", "dispatch.execution-mode.missing-seats", 'execution mode "targeted" requires listed reviewer seats', 'add "QC re-review: targeted reviewers: <role-id>, " to the Assignment and pass the seats'));
4350
+ violations.push(violation2("high", "dispatch.execution-mode.missing-seats", 'execution mode "targeted" requires listed reviewer seats', 'add "QC re-review: targeted \u2014 reviewers: <role-id>, \u2026" to the Assignment and pass the seats'));
4351
4351
  } else if (seats.length > 3) {
4352
- violations.push(violation2("high", "dispatch.execution-mode.too-many-seats", `execution mode "targeted" lists ${seats.length} reviewer seats at most 3 (targeted re-review seats are the tri seats, N = 1–3)`, "list at most three reviewer seats for the targeted re-review"));
4352
+ violations.push(violation2("high", "dispatch.execution-mode.too-many-seats", `execution mode "targeted" lists ${seats.length} reviewer seats \u2014 at most 3 (targeted re-review seats are the tri seats, N = 1\u20133)`, "list at most three reviewer seats for the targeted re-review"));
4353
4353
  } else {
4354
4354
  n = seats.length;
4355
4355
  }
@@ -4416,7 +4416,7 @@ function validatePlanRow(row) {
4416
4416
  validateNonEmptyString2(violations, planId, "plan_id", "status.plan-row.missing-plan-id", "status.plan-row.invalid-plan-id");
4417
4417
  }
4418
4418
  if (id !== undefined && planId !== undefined && id !== planId) {
4419
- violations.push(violation3("medium", "status.plan-row.dual-id", "row has both id and plan_id with different values write one canonical key (prefer id)"));
4419
+ violations.push(violation3("medium", "status.plan-row.dual-id", "row has both id and plan_id with different values \u2014 write one canonical key (prefer id)"));
4420
4420
  }
4421
4421
  }
4422
4422
  validateNonEmptyString2(violations, title, "title", "status.plan-row.missing-title", "status.plan-row.invalid-title");
@@ -4424,7 +4424,7 @@ function validatePlanRow(row) {
4424
4424
  if (status === undefined) {
4425
4425
  violations.push(violation3("high", "status.plan-row.missing-status", "missing required field: status"));
4426
4426
  } else if (typeof status !== "string" || !PLAN_STATUSES.includes(status)) {
4427
- violations.push(violation3("medium", "status.plan-row.invalid-status", `status must be one of ${PLAN_STATUSES.join(" | ")} got ${JSON.stringify(status)}`));
4427
+ violations.push(violation3("medium", "status.plan-row.invalid-status", `status must be one of ${PLAN_STATUSES.join(" | ")} \u2014 got ${JSON.stringify(status)}`));
4428
4428
  }
4429
4429
  if (metadata !== undefined && !isPlainObject2(metadata)) {
4430
4430
  violations.push(violation3("medium", "status.plan-row.invalid-metadata", "metadata must be an object"));
@@ -4433,7 +4433,7 @@ function validatePlanRow(row) {
4433
4433
  violations.push(violation3("medium", "status.plan-row.invalid-execution-lease", "execution_lease must be an object"));
4434
4434
  }
4435
4435
  if (status === "Done" && execution_lease !== undefined) {
4436
- violations.push(violation3("medium", "status.plan-row.done-with-lease", 'plan status Done must not carry an execution_lease the Done authority deletes the lease in the same complete-file update as status: "Done" (status-and-residuals.md § Hold, release, and override)', 'delete plans[].execution_lease in the same update that sets status: "Done"'));
4436
+ violations.push(violation3("medium", "status.plan-row.done-with-lease", 'plan status Done must not carry an execution_lease \u2014 the Done authority deletes the lease in the same complete-file update as status: "Done" (status-and-residuals.md \u00a7 Hold, release, and override)', 'delete plans[].execution_lease in the same update that sets status: "Done"'));
4437
4437
  }
4438
4438
  return { ok: violations.length === 0, violations };
4439
4439
  }
@@ -4451,14 +4451,14 @@ function validateResidual(entry) {
4451
4451
  if (severity === undefined) {
4452
4452
  violations.push(violation3("high", "status.residual.missing-severity", "missing required field: severity"));
4453
4453
  } else if (typeof severity !== "string" || !SEVERITY_ORDER.includes(severity) && severity !== "warning") {
4454
- violations.push(violation3("medium", "status.residual.invalid-severity", `severity must be one of ${SEVERITY_ORDER.join(" | ")} got ${JSON.stringify(severity)}`));
4454
+ violations.push(violation3("medium", "status.residual.invalid-severity", `severity must be one of ${SEVERITY_ORDER.join(" | ")} \u2014 got ${JSON.stringify(severity)}`));
4455
4455
  } else if (severity === "warning") {
4456
- violations.push(violation3("low", "status.residual.legacy-warning", `severity "warning" is legacy forbidden on new entries; read paths normalize it to "low"`, `use "low" (normalizeSeverity maps 'warning' 'low')`));
4456
+ violations.push(violation3("low", "status.residual.legacy-warning", `severity "warning" is legacy \u2014 forbidden on new entries; read paths normalize it to "low"`, `use "low" (normalizeSeverity maps 'warning' \u2192 'low')`));
4457
4457
  }
4458
4458
  if (decision === undefined) {
4459
4459
  violations.push(violation3("high", "status.residual.missing-decision", "missing required field: decision"));
4460
4460
  } else if (typeof decision !== "string" || !RESIDUAL_DECISIONS.includes(decision)) {
4461
- violations.push(violation3("medium", "status.residual.invalid-decision", `decision must be one of ${RESIDUAL_DECISIONS.join(" | ")} got ${JSON.stringify(decision)}`));
4461
+ violations.push(violation3("medium", "status.residual.invalid-decision", `decision must be one of ${RESIDUAL_DECISIONS.join(" | ")} \u2014 got ${JSON.stringify(decision)}`));
4462
4462
  }
4463
4463
  if (target === undefined) {
4464
4464
  violations.push(violation3("high", "status.residual.missing-target", "missing required field: target"));
@@ -4478,7 +4478,7 @@ function validateResidual(entry) {
4478
4478
  }
4479
4479
  if (lifecycle !== undefined) {
4480
4480
  if (typeof lifecycle !== "string" || !RESIDUAL_LIFECYCLES.includes(lifecycle)) {
4481
- violations.push(violation3("medium", "status.residual.invalid-lifecycle", `lifecycle must be one of ${RESIDUAL_LIFECYCLES.join(" | ")} got ${JSON.stringify(lifecycle)}`));
4481
+ violations.push(violation3("medium", "status.residual.invalid-lifecycle", `lifecycle must be one of ${RESIDUAL_LIFECYCLES.join(" | ")} \u2014 got ${JSON.stringify(lifecycle)}`));
4482
4482
  } else if (lifecycle !== "open") {
4483
4483
  if (closed_at === undefined) {
4484
4484
  violations.push(violation3("high", "status.residual.closed-missing-closed-at", `lifecycle "${lifecycle}" requires closed_at (YYYY-MM-DD)`, 'set closed_at (e.g. "2026-08-08")'));
@@ -4511,7 +4511,7 @@ function validateStatus(docOrPath) {
4511
4511
  } else if (typeof version !== "number" || !Number.isInteger(version)) {
4512
4512
  violations.push(violation3("high", "status.invalid-version", "version must be an integer"));
4513
4513
  } else if (version !== 1) {
4514
- violations.push(violation3("medium", "status.unsupported-version", `unsupported status.json schema version ${version} expected 1`));
4514
+ violations.push(violation3("medium", "status.unsupported-version", `unsupported status.json schema version ${version} \u2014 expected 1`));
4515
4515
  }
4516
4516
  if (updated_at === undefined) {
4517
4517
  violations.push(violation3("high", "status.missing-updated-at", "missing required field: updated_at"));
@@ -4536,7 +4536,7 @@ function validateStatus(docOrPath) {
4536
4536
  if (!Array.isArray(list)) {
4537
4537
  violations.push(violation3("high", "status.residual.invalid-list", `residual_findings["${planId}"] must be an array`));
4538
4538
  } else if (list.length === 0) {
4539
- violations.push(violation3("low", "status.residual.empty-key", `residual_findings["${planId}"] is empty delete the key (no "plan-id": [])`));
4539
+ violations.push(violation3("low", "status.residual.empty-key", `residual_findings["${planId}"] is empty \u2014 delete the key (no "plan-id": [])`));
4540
4540
  } else {
4541
4541
  for (const entry of list) {
4542
4542
  violations.push(...validateResidual(entry).violations);
@@ -4549,14 +4549,14 @@ function validateStatus(docOrPath) {
4549
4549
  } else if (!isPlainObject2(metadata)) {
4550
4550
  violations.push(violation3("high", "status.invalid-metadata", "metadata must be an object"));
4551
4551
  } else if (Object.prototype.hasOwnProperty.call(metadata, "residual_findings")) {
4552
- violations.push(violation3("medium", "status.dual-write-residuals", "residual_findings must be root-only metadata.residual_findings is legacy read-only; remove it (no dual-write)", "move entries to root residual_findings and delete metadata.residual_findings"));
4552
+ violations.push(violation3("medium", "status.dual-write-residuals", "residual_findings must be root-only \u2014 metadata.residual_findings is legacy read-only; remove it (no dual-write)", "move entries to root residual_findings and delete metadata.residual_findings"));
4553
4553
  }
4554
4554
  return { ok: violations.length === 0, violations };
4555
4555
  }
4556
4556
  async function archiveResiduals(planId, harnessDir) {
4557
4557
  const dir = harnessDir !== undefined ? resolve4(harnessDir) : resolveHarnessDir();
4558
4558
  if (dir === null) {
4559
- throw new Error(`harness dir not found from ${process.cwd()} pass harnessDir or set MSTAR_HARNESS_DIR`);
4559
+ throw new Error(`harness dir not found from ${process.cwd()} \u2014 pass harnessDir or set MSTAR_HARNESS_DIR`);
4560
4560
  }
4561
4561
  assertSafePathComponent(planId, "planId");
4562
4562
  const statusPath = join4(dir, "status.json");
@@ -4633,16 +4633,16 @@ function l1PreDispatchCheck(input, opts = {}) {
4633
4633
  const violations = [];
4634
4634
  const { controlWorktreePath, leaseWorktreePath, leaseWorkingBranch, planId } = input;
4635
4635
  if (controlWorktreePath.trim() === "") {
4636
- violations.push(violation4("high", "worktree.l1.control-missing", "metadata.control_worktree_path is not recorded the L1 control worktree (integration-branch checkout) must be recorded in status.json before writable dispatch", "record the control worktree path in status.json metadata.control_worktree_path"));
4636
+ violations.push(violation4("high", "worktree.l1.control-missing", "metadata.control_worktree_path is not recorded \u2014 the L1 control worktree (integration-branch checkout) must be recorded in status.json before writable dispatch", "record the control worktree path in status.json metadata.control_worktree_path"));
4637
4637
  }
4638
4638
  if (leaseWorktreePath.trim() === "") {
4639
- violations.push(violation4("high", "worktree.l1.lease-missing", `execution_lease.worktree_path is empty for plan "${planId}" no verified execution_lease to dispatch against`, "claim the execution_lease with an absolute feature worktree path before dispatch"));
4639
+ violations.push(violation4("high", "worktree.l1.lease-missing", `execution_lease.worktree_path is empty for plan "${planId}" \u2014 no verified execution_lease to dispatch against`, "claim the execution_lease with an absolute feature worktree path before dispatch"));
4640
4640
  }
4641
4641
  if (leaseWorkingBranch.trim() === "") {
4642
4642
  violations.push(violation4("high", "worktree.l1.lease-branch-missing", `execution_lease.working_branch is empty for plan "${planId}"`, "record the lease working_branch before dispatch"));
4643
4643
  }
4644
4644
  if (controlWorktreePath !== "" && leaseWorktreePath !== "" && resolve5(controlWorktreePath) === resolve5(leaseWorktreePath)) {
4645
- violations.push(violation4("critical", "worktree.l1.lease-equals-control", `execution_lease.worktree_path "${leaseWorktreePath}" equals metadata.control_worktree_path the feature worktree MUST differ from the control worktree (L1 isolation; product edits never land in the control checkout)`, "use a distinct feature worktree for the plan (git worktree add <path> <branch>) and update the lease"));
4645
+ violations.push(violation4("critical", "worktree.l1.lease-equals-control", `execution_lease.worktree_path "${leaseWorktreePath}" equals metadata.control_worktree_path \u2014 the feature worktree MUST differ from the control worktree (L1 isolation; product edits never land in the control checkout)`, "use a distinct feature worktree for the plan (git worktree add <path> <branch>) and update the lease"));
4646
4646
  }
4647
4647
  if (leaseWorktreePath !== "" && !existsSync3(leaseWorktreePath)) {
4648
4648
  violations.push(violation4("high", "worktree.l1.feature-missing", `feature worktree directory "${leaseWorktreePath}" does not exist for plan "${planId}"`, `create it before dispatch: git worktree add ${leaseWorktreePath} <working-branch>`));
@@ -4661,7 +4661,7 @@ function l2PreDispatchCheck(input, opts = {}) {
4661
4661
  const tracks = input.tracks ?? [];
4662
4662
  const seenPaths = new Set;
4663
4663
  if (tracks.length < 1) {
4664
- violations.push(violation4("high", "worktree.l2.no-tracks", "no parallel writable tracks the L2 pre-dispatch checklist requires at least one track with an absolute worktreePath and Working branch", "pass each track's absolute Worktree path and PM-approved Working branch"));
4664
+ violations.push(violation4("high", "worktree.l2.no-tracks", "no parallel writable tracks \u2014 the L2 pre-dispatch checklist requires at least one track with an absolute worktreePath and Working branch", "pass each track's absolute Worktree path and PM-approved Working branch"));
4665
4665
  }
4666
4666
  tracks.forEach((track, index) => {
4667
4667
  if (track.worktreePath.trim() === "" || track.workingBranch.trim() === "") {
@@ -4669,12 +4669,12 @@ function l2PreDispatchCheck(input, opts = {}) {
4669
4669
  return;
4670
4670
  }
4671
4671
  if (!isAbsolute3(track.worktreePath)) {
4672
- violations.push(violation4("high", "worktree.l2.track-path-relative", `track ${index + 1} worktreePath "${track.worktreePath}" is not an absolute path L2 tracks MUST use absolute worktree checkout paths (consistent with the lease validator's absolute worktree_path enforcement)`, `use an absolute path for track ${index + 1} (e.g. /Users/<you>/worktrees/<branch>)`));
4672
+ violations.push(violation4("high", "worktree.l2.track-path-relative", `track ${index + 1} worktreePath "${track.worktreePath}" is not an absolute path \u2014 L2 tracks MUST use absolute worktree checkout paths (consistent with the lease validator's absolute worktree_path enforcement)`, `use an absolute path for track ${index + 1} (e.g. /Users/<you>/worktrees/<branch>)`));
4673
4673
  return;
4674
4674
  }
4675
4675
  const normalized = resolve5(track.worktreePath);
4676
4676
  if (seenPaths.has(normalized)) {
4677
- violations.push(violation4("high", "worktree.l2.track-path-collision", `duplicate worktreePath "${track.worktreePath}" across parallel tracks L2 parallel-writable isolation requires a distinct absolute Worktree path per track (N parallel invokes isolation)`, "give every parallel track its own git worktree checkout"));
4677
+ violations.push(violation4("high", "worktree.l2.track-path-collision", `duplicate worktreePath "${track.worktreePath}" across parallel tracks \u2014 L2 parallel-writable isolation requires a distinct absolute Worktree path per track (N parallel invokes \u2260 isolation)`, "give every parallel track its own git worktree checkout"));
4678
4678
  return;
4679
4679
  }
4680
4680
  seenPaths.add(normalized);
@@ -4771,7 +4771,7 @@ function sddWorkspace(planId, opts = {}) {
4771
4771
  throw new SddScriptError(`mstar sdd workspace: linked worktree at ${root} has no {HARNESS_DIR}/status.json (default gitignore).
4772
4772
  ` + ` Refusing to create a second SDD tree under the feature checkout.
4773
4773
  ` + ` Re-run with MSTAR_CONTROL_ROOT=<control_worktree_path> or: mstar sdd workspace ${planId} <control_worktree_path>
4774
- ` + ` See mstar-branch-worktree «Harness path SSOT under default gitignore».`, 1);
4774
+ ` + ` See mstar-branch-worktree \u00abHarness path SSOT under default gitignore\u00bb.`, 1);
4775
4775
  }
4776
4776
  const harnessOverride = opts.harnessDir ?? (process.env.MSTAR_HARNESS_DIR || undefined);
4777
4777
  let harnessDir;
@@ -4973,7 +4973,7 @@ function validateCompassFrontmatter(doc) {
4973
4973
  return {
4974
4974
  ok: false,
4975
4975
  violations: [
4976
- violation5("medium", "COMPASS_INVALID_FIELD", "Compass frontmatter must be a YAML object with iteration_id / start_date / status / iteration_base_branch / target_branch (template: mstar-iteration §1.3)", "Fix the frontmatter of {ITERATION_DIR}/<iteration-id>/delivery-compass.md")
4976
+ violation5("medium", "COMPASS_INVALID_FIELD", "Compass frontmatter must be a YAML object with iteration_id / start_date / status / iteration_base_branch / target_branch (template: mstar-iteration \u00a71.3)", "Fix the frontmatter of {ITERATION_DIR}/<iteration-id>/delivery-compass.md")
4977
4977
  ]
4978
4978
  };
4979
4979
  }
@@ -4983,17 +4983,17 @@ function validateCompassFrontmatter(doc) {
4983
4983
  ok: false,
4984
4984
  violations: parsed.issues.map((issue) => {
4985
4985
  const field = issue.path.join(".") || "(root)";
4986
- return violation5("medium", "COMPASS_INVALID_FIELD", `Compass frontmatter field '${field}' is invalid: ${issue.message}`, `Fix '${field}' in {ITERATION_DIR}/<iteration-id>/delivery-compass.md frontmatter (template: mstar-iteration §1.3)`);
4986
+ return violation5("medium", "COMPASS_INVALID_FIELD", `Compass frontmatter field '${field}' is invalid: ${issue.message}`, `Fix '${field}' in {ITERATION_DIR}/<iteration-id>/delivery-compass.md frontmatter (template: mstar-iteration \u00a71.3)`);
4987
4987
  })
4988
4988
  };
4989
4989
  }
4990
4990
  const violations = [];
4991
4991
  const { status, end_date } = parsed.data;
4992
4992
  if (status === "completed" && end_date === undefined) {
4993
- violations.push(violation5("high", "COMPASS_END_DATE_REQUIRED", "Compass frontmatter status is 'completed' but end_date is missing end_date is required at iteration-close (mstar-iteration §3.4, template Fields guide)", "Add `end_date: YYYY-MM-DD` to the frontmatter"));
4993
+ violations.push(violation5("high", "COMPASS_END_DATE_REQUIRED", "Compass frontmatter status is 'completed' but end_date is missing \u2014 end_date is required at iteration-close (mstar-iteration \u00a73.4, template Fields guide)", "Add `end_date: YYYY-MM-DD` to the frontmatter"));
4994
4994
  }
4995
4995
  if (status !== "completed" && end_date !== undefined) {
4996
- violations.push(violation5("medium", "COMPASS_END_DATE_NOT_ALLOWED", `Compass frontmatter sets end_date while status is '${status}' end_date is only written at iteration-close (mstar-iteration §3.4)`, "Remove end_date until iteration-close"));
4996
+ violations.push(violation5("medium", "COMPASS_END_DATE_NOT_ALLOWED", `Compass frontmatter sets end_date while status is '${status}' \u2014 end_date is only written at iteration-close (mstar-iteration \u00a73.4)`, "Remove end_date until iteration-close"));
4997
4997
  }
4998
4998
  return { ok: violations.length === 0, violations };
4999
4999
  }
@@ -5017,17 +5017,17 @@ function findPlanRow(statusDoc, planId) {
5017
5017
  function entryPlansAllDone(statusDoc, registered) {
5018
5018
  const violations = [];
5019
5019
  if (registered.length === 0) {
5020
- violations.push(violation5("medium", "COMPASS_NO_PLANS", "Compass frontmatter registers no plans the all-plans-Done transition cannot be verified (mstar-iteration §1.3 / Phase transition gates)", "List the iteration's plan ids in the compass frontmatter `plans`"));
5020
+ violations.push(violation5("medium", "COMPASS_NO_PLANS", "Compass frontmatter registers no plans \u2014 the all-plans-Done transition cannot be verified (mstar-iteration \u00a71.3 / Phase transition gates)", "List the iteration's plan ids in the compass frontmatter `plans`"));
5021
5021
  return violations;
5022
5022
  }
5023
5023
  for (const planId of registered) {
5024
5024
  const row = findPlanRow(statusDoc, planId);
5025
5025
  if (row === null) {
5026
- violations.push(violation5("high", "PLAN_NOT_IN_STATUS", `Plan '${planId}' is registered in the compass frontmatter but has no row in status.json plans[] (mstar-iteration §3.1 entry item 1)`, "Add the plan row to {HARNESS_DIR}/status.json"));
5026
+ violations.push(violation5("high", "PLAN_NOT_IN_STATUS", `Plan '${planId}' is registered in the compass frontmatter but has no row in status.json plans[] (mstar-iteration \u00a73.1 entry item 1)`, "Add the plan row to {HARNESS_DIR}/status.json"));
5027
5027
  continue;
5028
5028
  }
5029
5029
  if (row.status !== PLAN_STATUS_DONE) {
5030
- violations.push(violation5("high", "PLAN_NOT_DONE", `Plan '${planId}' status is ${JSON.stringify(row.status)} in status.json all compass-registered plans must be 'Done' before iteration-close (mstar-iteration §3.1 entry item 1)`));
5030
+ violations.push(violation5("high", "PLAN_NOT_DONE", `Plan '${planId}' status is ${JSON.stringify(row.status)} in status.json \u2014 all compass-registered plans must be 'Done' before iteration-close (mstar-iteration \u00a73.1 entry item 1)`));
5031
5031
  }
5032
5032
  }
5033
5033
  return violations;
@@ -5038,14 +5038,14 @@ function entryResidualsOpen(statusDoc, planId) {
5038
5038
  if (residualRoot === undefined || residualRoot === null)
5039
5039
  return violations;
5040
5040
  if (!isPlainObject3(residualRoot)) {
5041
- violations.push(violation5("medium", "RESIDUAL_MALFORMED", "status.json residual_findings must be a plan-id entries object (mstar-iteration §3.1 entry item 2)"));
5041
+ violations.push(violation5("medium", "RESIDUAL_MALFORMED", "status.json residual_findings must be a plan-id \u2192 entries object (mstar-iteration \u00a73.1 entry item 2)"));
5042
5042
  return violations;
5043
5043
  }
5044
5044
  const entries = residualRoot[planId];
5045
5045
  if (entries === undefined)
5046
5046
  return violations;
5047
5047
  if (!Array.isArray(entries)) {
5048
- violations.push(violation5("medium", "RESIDUAL_MALFORMED", `status.json residual_findings['${planId}'] must be an array of residual entries (mstar-iteration §3.1 entry item 2)`));
5048
+ violations.push(violation5("medium", "RESIDUAL_MALFORMED", `status.json residual_findings['${planId}'] must be an array of residual entries (mstar-iteration \u00a73.1 entry item 2)`));
5049
5049
  return violations;
5050
5050
  }
5051
5051
  const openIds = [];
@@ -5058,7 +5058,7 @@ function entryResidualsOpen(statusDoc, planId) {
5058
5058
  openIds.push(typeof entry.id === "string" ? entry.id : "<unnamed>");
5059
5059
  }
5060
5060
  if (openIds.length > 0) {
5061
- violations.push(violation5("high", "OPEN_RESIDUALS", `Plan '${planId}' has ${openIds.length} open residual finding(s) not exempted as blocker-defers (${openIds.join(", ")}) residuals must be closed/archived before iteration-close; only zero-residual blocker-defers (decision: defer + target) may stay open (mstar-iteration §3.1 entry item 2)`, "Close or archive the open residuals, or convert them into blocker-defers (decision: defer + non-empty target) per mstar-plan-artifacts Findings cleanup modes"));
5061
+ violations.push(violation5("high", "OPEN_RESIDUALS", `Plan '${planId}' has ${openIds.length} open residual finding(s) not exempted as blocker-defers (${openIds.join(", ")}) \u2014 residuals must be closed/archived before iteration-close; only zero-residual blocker-defers (decision: defer + target) may stay open (mstar-iteration \u00a73.1 entry item 2)`, "Close or archive the open residuals, or convert them into blocker-defers (decision: defer + non-empty target) per mstar-plan-artifacts Findings cleanup modes"));
5062
5062
  }
5063
5063
  return violations;
5064
5064
  }
@@ -5068,11 +5068,11 @@ function entryFrontmatterComplete(compassDoc) {
5068
5068
  function exitFrontmatterClosed(compassDoc) {
5069
5069
  const violations = [];
5070
5070
  if (compassDoc.status !== "completed") {
5071
- violations.push(violation5("high", "EXIT_STATUS_NOT_COMPLETED", `Compass frontmatter status must be 'completed' at close exit current: ${JSON.stringify(compassDoc.status)} (mstar-iteration §3.4 / §3.5 exit item 4)`));
5071
+ violations.push(violation5("high", "EXIT_STATUS_NOT_COMPLETED", `Compass frontmatter status must be 'completed' at close exit \u2014 current: ${JSON.stringify(compassDoc.status)} (mstar-iteration \u00a73.4 / \u00a73.5 exit item 4)`));
5072
5072
  }
5073
5073
  const endDate = compassDoc.end_date;
5074
5074
  if (typeof endDate !== "string" || !DATE_RE2.test(endDate)) {
5075
- violations.push(violation5("high", "EXIT_END_DATE_REQUIRED", "Compass frontmatter end_date (YYYY-MM-DD) is required when closing (mstar-iteration §3.4 / §3.5 exit item 4)"));
5075
+ violations.push(violation5("high", "EXIT_END_DATE_REQUIRED", "Compass frontmatter end_date (YYYY-MM-DD) is required when closing (mstar-iteration \u00a73.4 / \u00a73.5 exit item 4)"));
5076
5076
  }
5077
5077
  return violations;
5078
5078
  }
@@ -5080,9 +5080,9 @@ function exitBranchCheck(opts) {
5080
5080
  const violations = [];
5081
5081
  const { currentBranch, specIntegrationBranch } = opts;
5082
5082
  if (currentBranch === undefined || specIntegrationBranch === undefined) {
5083
- violations.push(violation5("medium", "EXIT_BRANCH_UNVERIFIABLE", "Cannot verify the current branch is spec_integration_branch missing currentBranch / specIntegrationBranch probe inputs (mstar-iteration §3.5 exit item 5)"));
5083
+ violations.push(violation5("medium", "EXIT_BRANCH_UNVERIFIABLE", "Cannot verify the current branch is spec_integration_branch \u2014 missing currentBranch / specIntegrationBranch probe inputs (mstar-iteration \u00a73.5 exit item 5)"));
5084
5084
  } else if (currentBranch !== specIntegrationBranch) {
5085
- violations.push(violation5("high", "EXIT_BRANCH_MISMATCH", `Current branch '${currentBranch}' is not the spec_integration_branch '${specIntegrationBranch}' (mstar-iteration §3.5 exit item 5)`));
5085
+ violations.push(violation5("high", "EXIT_BRANCH_MISMATCH", `Current branch '${currentBranch}' is not the spec_integration_branch '${specIntegrationBranch}' (mstar-iteration \u00a73.5 exit item 5)`));
5086
5086
  }
5087
5087
  return violations;
5088
5088
  }
@@ -5091,9 +5091,9 @@ function exitPrBaseCheck(compassDoc, opts) {
5091
5091
  const target = compassDoc.target_branch;
5092
5092
  const { prBaseBranch } = opts;
5093
5093
  if (prBaseBranch === undefined) {
5094
- violations.push(violation5("medium", "EXIT_PR_BASE_UNVERIFIABLE", "Cannot verify the PR base missing prBaseBranch probe input (mstar-iteration §3.5 exit item 6)"));
5094
+ violations.push(violation5("medium", "EXIT_PR_BASE_UNVERIFIABLE", "Cannot verify the PR base \u2014 missing prBaseBranch probe input (mstar-iteration \u00a73.5 exit item 6)"));
5095
5095
  } else if (typeof target !== "string" || prBaseBranch !== target) {
5096
- violations.push(violation5("high", "EXIT_PR_BASE_MISMATCH", `PR base '${prBaseBranch}' must equal the compass target_branch '${String(target)}' not an undocumented branch (mstar-iteration §3.5 exit item 6)`));
5096
+ violations.push(violation5("high", "EXIT_PR_BASE_MISMATCH", `PR base '${prBaseBranch}' must equal the compass target_branch '${String(target)}' \u2014 not an undocumented branch (mstar-iteration \u00a73.5 exit item 6)`));
5097
5097
  }
5098
5098
  return violations;
5099
5099
  }
@@ -5135,10 +5135,10 @@ function evaluatePhaseGate(statusDoc, compassDoc, opts = {}) {
5135
5135
  function pushCadenceProbe(ciRunning, reviewWaveActive) {
5136
5136
  const violations = [];
5137
5137
  if (ciRunning) {
5138
- violations.push(violation5("high", "PUSH_BLOCKED_CI", "CI checks are still queued/in_progress on the current head do not push until the wave completes (mstar-iteration §5.1a push gate 1)", "Wait for CI to settle, then push once with the whole local batch"));
5138
+ violations.push(violation5("high", "PUSH_BLOCKED_CI", "CI checks are still queued/in_progress on the current head \u2014 do not push until the wave completes (mstar-iteration \u00a75.1a push gate 1)", "Wait for CI to settle, then push once with the whole local batch"));
5139
5139
  }
5140
5140
  if (reviewWaveActive) {
5141
- violations.push(violation5("high", "PUSH_BLOCKED_REVIEW_WAVE", "An AI/bot review wave is still running on the current head do not push until it settles (mstar-iteration §5.1a push gate 2)", "Wait for the review wave, then push once"));
5141
+ violations.push(violation5("high", "PUSH_BLOCKED_REVIEW_WAVE", "An AI/bot review wave is still running on the current head \u2014 do not push until it settles (mstar-iteration \u00a75.1a push gate 2)", "Wait for the review wave, then push once"));
5142
5142
  }
5143
5143
  return { ok: violations.length === 0, violations };
5144
5144
  }
@@ -5179,7 +5179,7 @@ function parseCompassFrontmatter(filePath) {
5179
5179
  function parseFlowArray(raw, filePath) {
5180
5180
  const inner = raw.slice(1, -1);
5181
5181
  if (/[[\]]/.test(inner)) {
5182
- throw new Error(`nested flow-style array in ${filePath}: ${JSON.stringify(raw)} only flat scalar items are supported (e.g. [a, b])`);
5182
+ throw new Error(`nested flow-style array in ${filePath}: ${JSON.stringify(raw)} \u2014 only flat scalar items are supported (e.g. [a, b])`);
5183
5183
  }
5184
5184
  let quote = null;
5185
5185
  for (const ch of inner) {
@@ -5189,7 +5189,7 @@ function parseFlowArray(raw, filePath) {
5189
5189
  else if (quote === ch)
5190
5190
  quote = null;
5191
5191
  } else if (ch === "," && quote !== null) {
5192
- throw new Error(`ambiguous flow-style array in ${filePath}: ${JSON.stringify(raw)} quoted item containing comma cannot be split unambiguously (flat scalar items only)`);
5192
+ throw new Error(`ambiguous flow-style array in ${filePath}: ${JSON.stringify(raw)} \u2014 quoted item containing comma cannot be split unambiguously (flat scalar items only)`);
5193
5193
  }
5194
5194
  }
5195
5195
  if (quote !== null) {
@@ -5317,7 +5317,7 @@ function validateDesignTokenFrontmatter(frontmatterText) {
5317
5317
  const violations = [];
5318
5318
  const fm = parseDesignFrontmatter(frontmatterText);
5319
5319
  if (fm === null) {
5320
- violations.push(violation6("medium", "design-md.tokens.missing-frontmatter", "no `---` YAML frontmatter block found DESIGN.md must open with a fenced frontmatter holding the token SSOT (design-md-spec §1.5)", "add a `---` fenced frontmatter with version, name, description, and the colors/typography/spacing/rounded groups"));
5320
+ violations.push(violation6("medium", "design-md.tokens.missing-frontmatter", "no `---` YAML frontmatter block found \u2014 DESIGN.md must open with a fenced frontmatter holding the token SSOT (design-md-spec \u00a71.5)", "add a `---` fenced frontmatter with version, name, description, and the colors/typography/spacing/rounded groups"));
5321
5321
  return { ok: false, violations };
5322
5322
  }
5323
5323
  const groupEntries = (group) => {
@@ -5332,61 +5332,61 @@ function validateDesignTokenFrontmatter(frontmatterText) {
5332
5332
  };
5333
5333
  for (const group of ["colors", "typography", "spacing", "rounded"]) {
5334
5334
  if (!isMap(fm[group])) {
5335
- violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "${group}" must be a YAML map, not a scalar (design-md-spec §1.5)`, `rewrite \`${group}\` as a nested map`));
5335
+ violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "${group}" must be a YAML map, not a scalar (design-md-spec \u00a71.5)`, `rewrite \`${group}\` as a nested map`));
5336
5336
  } else if (!groupIsMap(group)) {
5337
- violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "${group}" must be a YAML map, not a scalar (design-md-spec §1.5)`, `rewrite \`${group}\` as a nested map`));
5337
+ violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "${group}" must be a YAML map, not a scalar (design-md-spec \u00a71.5)`, `rewrite \`${group}\` as a nested map`));
5338
5338
  } else if (groupEntries(group).length === 0) {
5339
- violations.push(violation6("medium", "design-md.tokens.missing-group", `missing required token group "${group}" colors/typography/spacing/rounded are required by the frontmatter SSOT (design-md-spec §1.5)`, `add an active \`${group}:\` block with concrete token values`));
5339
+ violations.push(violation6("medium", "design-md.tokens.missing-group", `missing required token group "${group}" \u2014 colors/typography/spacing/rounded are required by the frontmatter SSOT (design-md-spec \u00a71.5)`, `add an active \`${group}:\` block with concrete token values`));
5340
5340
  }
5341
5341
  }
5342
5342
  if (!isMap(fm.components) || !groupIsMap("components")) {
5343
- violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "components" must be a YAML map, not a scalar (design-md-spec §1.5)`, `rewrite \`components\` as a nested map`));
5343
+ violations.push(violation6("medium", "design-md.tokens.group-not-map", `token group "components" must be a YAML map, not a scalar (design-md-spec \u00a71.5)`, `rewrite \`components\` as a nested map`));
5344
5344
  }
5345
- const placeholder = (group, name, value) => violations.push(violation6("low", "design-md.tokens.placeholder", `token "${group}.${name}" uses a "[...]" template value placeholders never count as concrete tokens (completeness-checklist § How to use item 5)`, `replace \`${value}\` with a concrete value`));
5345
+ const placeholder = (group, name, value) => violations.push(violation6("low", "design-md.tokens.placeholder", `token "${group}.${name}" uses a "[...]" template value \u2014 placeholders never count as concrete tokens (completeness-checklist \u00a7 How to use item 5)`, `replace \`${value}\` with a concrete value`));
5346
5346
  for (const [name, value] of groupEntries("colors")) {
5347
5347
  if (typeof value !== "string") {
5348
- violations.push(violation6("medium", "design-md.tokens.color-format", `color "${name}" must be a string value (design-md-spec §2.2)`, "quote the color value"));
5348
+ violations.push(violation6("medium", "design-md.tokens.color-format", `color "${name}" must be a string value (design-md-spec \u00a72.2)`, "quote the color value"));
5349
5349
  continue;
5350
5350
  }
5351
5351
  if (isPlaceholder(value)) {
5352
5352
  placeholder("colors", name, value);
5353
5353
  } else if (!HEX_RE.test(value) && !OKLCH_RE.test(value)) {
5354
- violations.push(violation6("medium", "design-md.tokens.color-format", `color "${name}" = "${value}" is not a hex (\`#rrggbb\`/\`#rrggbbaa\`) or oklch() value (design-md-spec §2.2)`, "use an sRGB hex value, optionally with a `-p3` oklch() twin"));
5354
+ violations.push(violation6("medium", "design-md.tokens.color-format", `color "${name}" = "${value}" is not a hex (\`#rrggbb\`/\`#rrggbbaa\`) or oklch() value (design-md-spec \u00a72.2)`, "use an sRGB hex value, optionally with a `-p3` oklch() twin"));
5355
5355
  }
5356
5356
  }
5357
5357
  for (const [name, value] of groupEntries("typography")) {
5358
5358
  if (!isMap(value)) {
5359
- violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" must be a map of the five properties (design-md-spec §1.5)`, "give it fontFamily/fontSize/fontWeight/lineHeight/letterSpacing"));
5359
+ violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" must be a map of the five properties (design-md-spec \u00a71.5)`, "give it fontFamily/fontSize/fontWeight/lineHeight/letterSpacing"));
5360
5360
  continue;
5361
5361
  }
5362
5362
  const keys = Object.keys(value);
5363
5363
  const missing = TYPOGRAPHY_PROPS.filter((p) => !keys.includes(p));
5364
5364
  const extra = keys.filter((k) => !TYPOGRAPHY_PROPS.includes(k));
5365
5365
  if (missing.length > 0 || extra.length > 0) {
5366
- violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" must have exactly the five properties fontFamily/fontSize/fontWeight/lineHeight/letterSpacing (design-md-spec §1.5)${missing.length > 0 ? ` missing: ${missing.join(", ")}` : ""}${extra.length > 0 ? ` extra: ${extra.join(", ")}` : ""}`, "align the token with the five-property shape"));
5366
+ violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" must have exactly the five properties fontFamily/fontSize/fontWeight/lineHeight/letterSpacing (design-md-spec \u00a71.5)${missing.length > 0 ? ` \u2014 missing: ${missing.join(", ")}` : ""}${extra.length > 0 ? ` \u2014 extra: ${extra.join(", ")}` : ""}`, "align the token with the five-property shape"));
5367
5367
  }
5368
5368
  for (const prop of ["fontFamily", "fontSize"]) {
5369
5369
  const v = value[prop];
5370
5370
  if (typeof v === "string" && isPlaceholder(v))
5371
5371
  placeholder("typography", name, v);
5372
5372
  else if (typeof v !== "string" || v.trim() === "") {
5373
- violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" has an empty \`${prop}\` (design-md-spec §1.5)`, `fill \`${prop}\` with a concrete value`));
5373
+ violations.push(violation6("medium", "design-md.tokens.typography-shape", `typography token "${name}" has an empty \`${prop}\` (design-md-spec \u00a71.5)`, `fill \`${prop}\` with a concrete value`));
5374
5374
  }
5375
5375
  }
5376
5376
  }
5377
5377
  if (groupIsMap("spacing")) {
5378
5378
  const spacing = fm.spacing;
5379
5379
  if (!Object.prototype.hasOwnProperty.call(spacing, "base")) {
5380
- violations.push(violation6("medium", "design-md.tokens.spacing-base", "spacing must declare the base unit as `base` (design-md-spec §2.4)", "add `base: 4px` (or 8px) to the spacing group"));
5380
+ violations.push(violation6("medium", "design-md.tokens.spacing-base", "spacing must declare the base unit as `base` (design-md-spec \u00a72.4)", "add `base: 4px` (or 8px) to the spacing group"));
5381
5381
  }
5382
5382
  for (const [name, value] of Object.entries(spacing)) {
5383
5383
  if (name !== "base" && name !== RAW_GROUP && !/^\d+$/.test(name)) {
5384
- violations.push(violation6("medium", "design-md.tokens.spacing-key", `spacing key "${name}" must be \`base\` or a numeric multiplier (design-md-spec §1.5)`, "use numeric scale-step keys or `base`"));
5384
+ violations.push(violation6("medium", "design-md.tokens.spacing-key", `spacing key "${name}" must be \`base\` or a numeric multiplier (design-md-spec \u00a71.5)`, "use numeric scale-step keys or `base`"));
5385
5385
  }
5386
5386
  if (typeof value === "string" && isPlaceholder(value)) {
5387
5387
  placeholder("spacing", name, value);
5388
5388
  } else if (typeof value !== "string" || !PX_RE.test(value)) {
5389
- violations.push(violation6("medium", "design-md.tokens.spacing-format", `spacing value "${name}" = "${String(value)}" is not a px length (design-md-spec §1.5)`, "use a pixel value like `4px`"));
5389
+ violations.push(violation6("medium", "design-md.tokens.spacing-format", `spacing value "${name}" = "${String(value)}" is not a px length (design-md-spec \u00a71.5)`, "use a pixel value like `4px`"));
5390
5390
  }
5391
5391
  }
5392
5392
  }
@@ -5394,12 +5394,12 @@ function validateDesignTokenFrontmatter(frontmatterText) {
5394
5394
  if (typeof value === "string" && isPlaceholder(value)) {
5395
5395
  placeholder("rounded", name, value);
5396
5396
  } else if (typeof value !== "string" || !PX_RE.test(value)) {
5397
- violations.push(violation6("medium", "design-md.tokens.rounded-format", `rounded value "${name}" = "${String(value)}" is not a px length (design-md-spec §1.5)`, "use a pixel value like `6px`"));
5397
+ violations.push(violation6("medium", "design-md.tokens.rounded-format", `rounded value "${name}" = "${String(value)}" is not a px length (design-md-spec \u00a71.5)`, "use a pixel value like `6px`"));
5398
5398
  }
5399
5399
  }
5400
5400
  for (const [name, value] of groupEntries("components")) {
5401
5401
  if (!isMap(value)) {
5402
- violations.push(violation6("medium", "design-md.tokens.components-shape", `component token "${name}" must be a map of properties (design-md-spec §2.8)`, "give it backgroundColor/textColor/typography/rounded/padding/height"));
5402
+ violations.push(violation6("medium", "design-md.tokens.components-shape", `component token "${name}" must be a map of properties (design-md-spec \u00a72.8)`, "give it backgroundColor/textColor/typography/rounded/padding/height"));
5403
5403
  continue;
5404
5404
  }
5405
5405
  for (const [prop, v] of Object.entries(value)) {
@@ -5415,7 +5415,7 @@ function validateDesignTokenFrontmatter(frontmatterText) {
5415
5415
  const [, refGroup, refKey] = ref;
5416
5416
  const resolves = REF_GROUPS.includes(refGroup) && groupIsMap(refGroup) && Object.prototype.hasOwnProperty.call(fm[refGroup], refKey);
5417
5417
  if (!resolves) {
5418
- violations.push(violation6("medium", "design-md.tokens.ref-unresolved", `component "${name}" references "${v}" which does not resolve to an active token in this frontmatter (design-md-spec §6 {path} refs MUST trace back to a key)`, `add the referenced token or use a literal value`));
5418
+ violations.push(violation6("medium", "design-md.tokens.ref-unresolved", `component "${name}" references "${v}" which does not resolve to an active token in this frontmatter (design-md-spec \u00a76 \u2014 {path} refs MUST trace back to a key)`, `add the referenced token or use a literal value`));
5419
5419
  }
5420
5420
  }
5421
5421
  }
@@ -5427,7 +5427,7 @@ function assertLightDarkParity(lightFm, darkFm) {
5427
5427
  const light = parseDesignFrontmatter(lightFm);
5428
5428
  const dark = parseDesignFrontmatter(darkFm);
5429
5429
  if (light === null || dark === null) {
5430
- violations.push(violation6("medium", "design-md.parity.missing-frontmatter", `light/dark parity needs a YAML frontmatter in both files ${light === null ? "DESIGN.md" : "DESIGN.dark.md"} has none (design-md-spec §4 rules 1–2)`, "add the fenced frontmatter to both theme files"));
5430
+ violations.push(violation6("medium", "design-md.parity.missing-frontmatter", `light/dark parity needs a YAML frontmatter in both files \u2014 ${light === null ? "DESIGN.md" : "DESIGN.dark.md"} has none (design-md-spec \u00a74 rules 1\u20132)`, "add the fenced frontmatter to both theme files"));
5431
5431
  return { ok: false, violations };
5432
5432
  }
5433
5433
  const activeKeys = (fm) => {
@@ -5445,12 +5445,12 @@ function assertLightDarkParity(lightFm, darkFm) {
5445
5445
  const darkKeys = activeKeys(dark);
5446
5446
  for (const key of lightKeys) {
5447
5447
  if (!darkKeys.has(key)) {
5448
- violations.push(violation6("medium", "design-md.parity.missing-dark", `token "${key}" is active in DESIGN.md but missing from DESIGN.dark.md both files must define the same token set (design-md-spec §4 rule 3)`, "add the token to DESIGN.dark.md with a dark-appropriate value"));
5448
+ violations.push(violation6("medium", "design-md.parity.missing-dark", `token "${key}" is active in DESIGN.md but missing from DESIGN.dark.md \u2014 both files must define the same token set (design-md-spec \u00a74 rule 3)`, "add the token to DESIGN.dark.md with a dark-appropriate value"));
5449
5449
  }
5450
5450
  }
5451
5451
  for (const key of darkKeys) {
5452
5452
  if (!lightKeys.has(key)) {
5453
- violations.push(violation6("medium", "design-md.parity.missing-light", `token "${key}" is active in DESIGN.dark.md but missing from DESIGN.md DESIGN.md is the SSOT for token names (design-md-spec §4 rules 3–4)`, "add the token to DESIGN.md, or remove it from the dark file"));
5453
+ violations.push(violation6("medium", "design-md.parity.missing-light", `token "${key}" is active in DESIGN.dark.md but missing from DESIGN.md \u2014 DESIGN.md is the SSOT for token names (design-md-spec \u00a74 rules 3\u20134)`, "add the token to DESIGN.md, or remove it from the dark file"));
5454
5454
  }
5455
5455
  }
5456
5456
  return { ok: violations.length === 0, violations };
@@ -5643,7 +5643,7 @@ function slugify(title) {
5643
5643
  return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5644
5644
  }
5645
5645
  var escapeCell = (value) => value.replace(/\|/g, "\\|");
5646
- var truncate = (value, max) => value.length > max ? `${value.slice(0, max)}…` : value;
5646
+ var truncate = (value, max) => value.length > max ? `${value.slice(0, max)}\u2026` : value;
5647
5647
  function renderPlanFile(finding, plannedAt) {
5648
5648
  const sections = [
5649
5649
  `# ${finding.title}`,
@@ -5682,14 +5682,14 @@ function renderIndex(params) {
5682
5682
  const { date, repoName, repoShortSha, rows, rejected } = params;
5683
5683
  const findingsRows = rows.map((r) => `| ${r.num} | ${escapeCell(r.title)} | ${r.category} | ${escapeCell(truncate(r.impact, 80))} | ${r.effort} | ${r.risk} | ${r.confidence} | ${escapeCell(truncate(r.evidence, 80))} |`).join(`
5684
5684
  `);
5685
- const directionRows = rows.filter((r) => r.category === "direction").map((r) => `- ${escapeCell(r.title)} ${escapeCell(truncate(r.impact, 120))}`).join(`
5685
+ const directionRows = rows.filter((r) => r.category === "direction").map((r) => `- ${escapeCell(r.title)} \u2014 ${escapeCell(truncate(r.impact, 120))}`).join(`
5686
5686
  `);
5687
5687
  const executionRows = rows.map((r) => `| ${r.num} | ${escapeCell(r.title)} | ${r.priority} | ${r.effort} | ${r.dependsOn} | TODO |`).join(`
5688
5688
  `);
5689
5689
  const rejectedRows = rejected.map((r) => `- ${escapeCell(r.title)}: ${escapeCell(r.reason)}`).join(`
5690
5690
  `);
5691
5691
  const sections = [
5692
- `# Audit Report ${repoName} @ ${repoShortSha} (${date})`,
5692
+ `# Audit Report \u2014 ${repoName} @ ${repoShortSha} (${date})`,
5693
5693
  "",
5694
5694
  "## Findings",
5695
5695
  "",
@@ -5704,6 +5704,7 @@ function renderIndex(params) {
5704
5704
  if (rejectedRows !== "") {
5705
5705
  sections.push("", "## Findings considered and rejected", "", rejectedRows);
5706
5706
  }
5707
+ sections.push("", "## Red-team dispositions", "", "- <finding>: <survived / refuted / hallucination-dropped / uncovered-kept>, <one-line reason>");
5707
5708
  return `${sections.join(`
5708
5709
  `)}
5709
5710
  `;
@@ -5738,14 +5739,14 @@ function scaffoldAuditPlan(outDir, findings, options = {}) {
5738
5739
  return {
5739
5740
  num: file.slice(0, 3),
5740
5741
  title: summary.title,
5741
- category: fields.get("Category") ?? "",
5742
+ category: fields.get("Category") ?? "\u2014",
5742
5743
  impact: "see plan file",
5743
- effort: fields.get("Effort") ?? "",
5744
- risk: fields.get("Risk") ?? "",
5745
- confidence: "",
5746
- evidence: fields.get("Evidence") ?? "",
5747
- priority: fields.get("Priority") ?? "",
5748
- dependsOn: fields.get("Depends on") ?? ""
5744
+ effort: fields.get("Effort") ?? "\u2014",
5745
+ risk: fields.get("Risk") ?? "\u2014",
5746
+ confidence: "\u2014",
5747
+ evidence: fields.get("Evidence") ?? "\u2014",
5748
+ priority: fields.get("Priority") ?? "\u2014",
5749
+ dependsOn: fields.get("Depends on") ?? "\u2014"
5749
5750
  };
5750
5751
  });
5751
5752
  const byNum = new Map(rows.map((r) => [r.num, r]));
@@ -5939,7 +5940,7 @@ function validateSchemaYaml(frontmatterText) {
5939
5940
  const violations = [];
5940
5941
  const doc = parseYamlLite(frontmatterText);
5941
5942
  if (doc === null) {
5942
- violations.push(violation8("medium", "compound.schema.missing-frontmatter", "no `---` YAML frontmatter block found knowledge docs must open with the schema.yaml contract (mstar-compound/references/schema.yaml)", "add the fenced frontmatter with module, date, problem_type, category, severity"));
5943
+ violations.push(violation8("medium", "compound.schema.missing-frontmatter", "no `---` YAML frontmatter block found \u2014 knowledge docs must open with the schema.yaml contract (mstar-compound/references/schema.yaml)", "add the fenced frontmatter with module, date, problem_type, category, severity"));
5943
5944
  return { ok: false, violations };
5944
5945
  }
5945
5946
  const isStr = (v) => typeof v === "string";
@@ -5953,14 +5954,14 @@ function validateSchemaYaml(frontmatterText) {
5953
5954
  }
5954
5955
  const problemType = doc.problem_type;
5955
5956
  if (problemType !== undefined && !isStr(problemType)) {
5956
- violations.push(violation8("medium", "compound.schema.invalid-problem-type", `problem_type "${String(problemType)}" must be a string one of the schema.yaml enum values (bug: build_error…config_error; knowledge: developer_experience…testing_pattern)`, "pick the narrowest applicable problem_type from schema.yaml"));
5957
+ violations.push(violation8("medium", "compound.schema.invalid-problem-type", `problem_type "${String(problemType)}" must be a string \u2014 one of the schema.yaml enum values (bug: build_error\u2026config_error; knowledge: developer_experience\u2026testing_pattern)`, "pick the narrowest applicable problem_type from schema.yaml"));
5957
5958
  }
5958
5959
  const problemTypeValid = isStr(problemType) && KNOWLEDGE_PROBLEM_TYPES.includes(problemType);
5959
5960
  if (isStr(problemType) && !problemTypeValid) {
5960
- violations.push(violation8("medium", "compound.schema.invalid-problem-type", `problem_type "${problemType}" is not one of the schema.yaml enum values (bug: build_error…config_error; knowledge: developer_experience…testing_pattern)`, "pick the narrowest applicable problem_type from schema.yaml"));
5961
+ violations.push(violation8("medium", "compound.schema.invalid-problem-type", `problem_type "${problemType}" is not one of the schema.yaml enum values (bug: build_error\u2026config_error; knowledge: developer_experience\u2026testing_pattern)`, "pick the narrowest applicable problem_type from schema.yaml"));
5961
5962
  }
5962
5963
  if (doc.severity !== undefined && !isStr(doc.severity)) {
5963
- violations.push(violation8("medium", "compound.schema.invalid-severity", `severity "${String(doc.severity)}" must be a string critical | high | medium | low (schema.yaml required_fields.severity)`, "use one of the four severity values"));
5964
+ violations.push(violation8("medium", "compound.schema.invalid-severity", `severity "${String(doc.severity)}" must be a string \u2014 critical | high | medium | low (schema.yaml required_fields.severity)`, "use one of the four severity values"));
5964
5965
  }
5965
5966
  if (isStr(doc.severity) && !KNOWLEDGE_SEVERITIES.includes(doc.severity)) {
5966
5967
  violations.push(violation8("medium", "compound.schema.invalid-severity", `severity "${doc.severity}" must be critical | high | medium | low (schema.yaml required_fields.severity)`, "use one of the four severity values"));
@@ -5968,7 +5969,7 @@ function validateSchemaYaml(frontmatterText) {
5968
5969
  if (problemTypeValid && isStr(doc.category)) {
5969
5970
  const expected = KNOWLEDGE_CATEGORY_MAP[problemType];
5970
5971
  if (doc.category !== expected) {
5971
- violations.push(violation8("medium", "compound.schema.category-mismatch", `category "${doc.category}" does not match problem_type "${problemType}" category-mapping.md rule 1 maps it to "${expected}"`, `set \`category: ${expected}\` (the directory name under {KNOWLEDGE_DIR})`));
5972
+ violations.push(violation8("medium", "compound.schema.category-mismatch", `category "${doc.category}" does not match problem_type "${problemType}" \u2014 category-mapping.md rule 1 maps it to "${expected}"`, `set \`category: ${expected}\` (the directory name under {KNOWLEDGE_DIR})`));
5972
5973
  }
5973
5974
  }
5974
5975
  if (problemTypeValid) {
@@ -5999,7 +6000,7 @@ function validateSchemaYaml(frontmatterText) {
5999
6000
  if (!Array.isArray(doc.tags)) {
6000
6001
  violations.push(violation8("low", "compound.schema.invalid-tags", "optional `tags` must be a YAML list (schema.yaml optional_fields.tags)", "list lowercase, hyphen-separated keywords"));
6001
6002
  } else if (doc.tags.length > 8) {
6002
- violations.push(violation8("low", "compound.schema.tags-too-many", `tags has ${doc.tags.length} entries max 8 (schema.yaml optional_fields.tags.max_items)`, "trim the tag list to at most 8 keywords"));
6003
+ violations.push(violation8("low", "compound.schema.tags-too-many", `tags has ${doc.tags.length} entries \u2014 max 8 (schema.yaml optional_fields.tags.max_items)`, "trim the tag list to at most 8 keywords"));
6003
6004
  }
6004
6005
  }
6005
6006
  if (doc.last_updated !== undefined && (!isStr(doc.last_updated) || !DATE_RE3.test(doc.last_updated))) {
@@ -6047,7 +6048,7 @@ function assertIndexRows(knowledgeDir) {
6047
6048
  const violations = [];
6048
6049
  const readmePath = join8(knowledgeDir, "README.md");
6049
6050
  if (!existsSync5(readmePath)) {
6050
- violations.push(violation8("medium", "compound.index.missing-readme", `missing ${readmePath} the knowledge index is required (mstar-compound Phase 6: every doc gets a README.md row)`, "create knowledge/README.md with a Document / Source Plan / Description / Status table"));
6051
+ violations.push(violation8("medium", "compound.index.missing-readme", `missing ${readmePath} \u2014 the knowledge index is required (mstar-compound Phase 6: every doc gets a README.md row)`, "create knowledge/README.md with a Document / Source Plan / Description / Status table"));
6051
6052
  return { ok: false, violations };
6052
6053
  }
6053
6054
  const docs = collectKnowledgeDocs(knowledgeDir);
@@ -6086,7 +6087,7 @@ function scopeGuard(path2, allowedRoots) {
6086
6087
  return {
6087
6088
  ok: false,
6088
6089
  violations: [
6089
- violation8("medium", "compound.scope.outside", `path "${path2}" is outside the compound-refresh scope (allowed: ${allowedRoots.join(", ")}) compound-refresh operates only on {HARNESS_DIR}/knowledge/**, {HARNESS_DIR}/knowledge/README.md, <repo-root>/CONCEPTS.md, {HARNESS_DIR}/status.json (mstar-compound-refresh SKILL.md § 产物与操作路径)`, "point the operation at one of the allowed paths")
6090
+ violation8("medium", "compound.scope.outside", `path "${path2}" is outside the compound-refresh scope (allowed: ${allowedRoots.join(", ")}) \u2014 compound-refresh operates only on {HARNESS_DIR}/knowledge/**, {HARNESS_DIR}/knowledge/README.md, <repo-root>/CONCEPTS.md, {HARNESS_DIR}/status.json (mstar-compound-refresh SKILL.md \u00a7 \u4ea7\u7269\u4e0e\u64cd\u4f5c\u8def\u5f84)`, "point the operation at one of the allowed paths")
6090
6091
  ]
6091
6092
  };
6092
6093
  }
@@ -6133,16 +6134,36 @@ function findTemporaryMarkers(fileText) {
6133
6134
  }
6134
6135
  markers.push({ line: i + 1, text, removalPath });
6135
6136
  if (removalPath === null) {
6136
- violations.push(violation9("medium", "lint.temporary.no-removal-path", `temporary marker at line ${i + 1} records no removal path (plan/status artifact reference) record one before claiming the task complete (mstar-coding-behavior § Simplification markers)`, 'add a plan/status reference to the marker, e.g. "removal tracked in status.json" or "plan 20260808-slice2 removes this"'));
6137
+ violations.push(violation9("medium", "lint.temporary.no-removal-path", `temporary marker at line ${i + 1} records no removal path (plan/status artifact reference) \u2014 record one before claiming the task complete (mstar-coding-behavior \u00a7 Simplification markers)`, 'add a plan/status reference to the marker, e.g. "removal tracked in status.json" or "plan 20260808-slice2 removes this"'));
6137
6138
  }
6138
6139
  }
6139
6140
  return { ok: violations.length === 0, violations, markers };
6140
6141
  }
6142
+ var TASK_ARTIFACT_RE = /\btask-\d+(?:-(?:brief|report|fix-report|diff)|\.diff)\b/g;
6143
+ var SDD_DEEPLINK_RE = /\.(?:mstar|agents)\/sdd\/([^\s/<>{}\[\]"'\*\?]+)/g;
6144
+ function findEphemeralCitations(skillText) {
6145
+ const citations = [];
6146
+ const lines = skillText.split(/\r?\n/);
6147
+ for (let i = 0;i < lines.length; i++) {
6148
+ const found = [];
6149
+ for (const m of lines[i].matchAll(TASK_ARTIFACT_RE)) {
6150
+ found.push({ index: m.index, match: m[0], kind: "task-artifact" });
6151
+ }
6152
+ for (const m of lines[i].matchAll(SDD_DEEPLINK_RE)) {
6153
+ found.push({ index: m.index, match: m[0], kind: "sdd-deeplink" });
6154
+ }
6155
+ found.sort((a, b) => a.index - b.index);
6156
+ for (const f of found) {
6157
+ citations.push({ line: i + 1, match: f.match, kind: f.kind });
6158
+ }
6159
+ }
6160
+ return citations;
6161
+ }
6141
6162
  var TEST_FILE_PATH_RE = /[\w./-]+\.(?:test|spec)\.[a-z0-9]+/i;
6142
6163
  var TEST_FILE_PHRASE_RE = /\btest files?\b/i;
6143
6164
  var COMMAND_PROMPT_RE = /^\s*[$>]\s*\S/;
6144
6165
  var RUNNER_RE = /\b(?:bun|pnpm|npm|yarn|npx|bunx)\s+(?:test|run|exec)\b|\b(?:npx|bunx)\s+[\w./-]+\b|\b(?:tsc|vitest|jest|mocha|pytest)\b|\bgo\s+test\b|\bcargo\s+test\b/i;
6145
- var OUTPUT_TOKEN_RE = /[✓✔✗✘]|\b(?:PASS|FAIL)\b|\b\d+\s+(?:pass(?:es|ed)?|fail(?:s|ed|ing)?|skipped|tests?|ok)\b|\bok\s+\d+\b|\ball\s+ok\b|exit(?:ed)?\s+(?:with\s+)?(?:code\s+)?\d+/i;
6166
+ var OUTPUT_TOKEN_RE = /[\u2713\u2714\u2717\u2718]|\b(?:PASS|FAIL)\b|\b\d+\s+(?:pass(?:es|ed)?|fail(?:s|ed|ing)?|skipped|tests?|ok)\b|\bok\s+\d+\b|\ball\s+ok\b|exit(?:ed)?\s+(?:with\s+)?(?:code\s+)?\d+/i;
6146
6167
  function assertSddTddTriple(reportText) {
6147
6168
  const violations = [];
6148
6169
  const lines = reportText.split(/\r?\n/);
@@ -6160,13 +6181,13 @@ function assertSddTddTriple(reportText) {
6160
6181
  break;
6161
6182
  }
6162
6183
  if (!hasTests) {
6163
- violations.push(violation9("medium", "lint.sdd-tdd.missing-tests", "task report carries no test file reference the TDD triple needs covering test file(s) (mstar-coding-behavior § Integration Notes; mstar-sdd/references/file-handoffs.md)", 'add a "Covering test file(s): <path>.test.ts" line or a `.test.<ext>` path to the report'));
6184
+ violations.push(violation9("medium", "lint.sdd-tdd.missing-tests", "task report carries no test file reference \u2014 the TDD triple needs covering test file(s) (mstar-coding-behavior \u00a7 Integration Notes; mstar-sdd/references/file-handoffs.md)", 'add a "Covering test file(s): <path>.test.ts" line or a `.test.<ext>` path to the report'));
6164
6185
  }
6165
6186
  if (!hasCommand) {
6166
- violations.push(violation9("medium", "lint.sdd-tdd.missing-command", "task report carries no command the TDD triple needs the exact command run (mstar-coding-behavior § Integration Notes; mstar-sdd/references/file-handoffs.md)", 'add a "Command run: `bun test <file>`" line to the report'));
6187
+ violations.push(violation9("medium", "lint.sdd-tdd.missing-command", "task report carries no command \u2014 the TDD triple needs the exact command run (mstar-coding-behavior \u00a7 Integration Notes; mstar-sdd/references/file-handoffs.md)", 'add a "Command run: `bun test <file>`" line to the report'));
6167
6188
  }
6168
6189
  if (!hasOutput) {
6169
- violations.push(violation9("medium", "lint.sdd-tdd.missing-output", "task report carries no output evidence the TDD triple needs the run output (pass/fail counts or exit code) (mstar-coding-behavior § Integration Notes; mstar-sdd/references/file-handoffs.md)", 'paste the test-run output (e.g. "12 pass / 0 fail") into the report'));
6190
+ violations.push(violation9("medium", "lint.sdd-tdd.missing-output", "task report carries no output evidence \u2014 the TDD triple needs the run output (pass/fail counts or exit code) (mstar-coding-behavior \u00a7 Integration Notes; mstar-sdd/references/file-handoffs.md)", 'paste the test-run output (e.g. "12 pass / 0 fail") into the report'));
6170
6191
  }
6171
6192
  return { ok: violations.length === 0, violations };
6172
6193
  }
@@ -6219,18 +6240,18 @@ function lintSkillFrontmatter(frontmatterText) {
6219
6240
  const violations = [];
6220
6241
  const fm = parseFrontmatter(frontmatterText);
6221
6242
  if (fm === null) {
6222
- violations.push(violation9("medium", "lint.frontmatter.missing", "no YAML frontmatter block found a skill file must open with a `---` fenced frontmatter (mstar-skill-authoring § Frontmatter Contract)", "add a frontmatter block with `name` and `description` at the top of the file"));
6243
+ violations.push(violation9("medium", "lint.frontmatter.missing", "no YAML frontmatter block found \u2014 a skill file must open with a `---` fenced frontmatter (mstar-skill-authoring \u00a7 Frontmatter Contract)", "add a frontmatter block with `name` and `description` at the top of the file"));
6223
6244
  return { ok: false, violations };
6224
6245
  }
6225
6246
  const name = fm.name ?? "";
6226
6247
  if (name === "") {
6227
- violations.push(violation9("medium", "lint.frontmatter.name.missing", "frontmatter `name` is missing required (mstar-skill-authoring § Frontmatter Contract)", "add `name: <lowercase-hyphen-id>` to the frontmatter"));
6248
+ violations.push(violation9("medium", "lint.frontmatter.name.missing", "frontmatter `name` is missing \u2014 required (mstar-skill-authoring \u00a7 Frontmatter Contract)", "add `name: <lowercase-hyphen-id>` to the frontmatter"));
6228
6249
  } else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) {
6229
- violations.push(violation9("medium", "lint.frontmatter.name.format", `frontmatter \`name\` must be lowercase-hyphen ("${name}") e.g. example-skill (mstar-skill-authoring § Frontmatter Contract)`, "rename to a stable lowercase-hyphen id, e.g. `name: example-skill`"));
6250
+ violations.push(violation9("medium", "lint.frontmatter.name.format", `frontmatter \`name\` must be lowercase-hyphen ("${name}") \u2014 e.g. example-skill (mstar-skill-authoring \u00a7 Frontmatter Contract)`, "rename to a stable lowercase-hyphen id, e.g. `name: example-skill`"));
6230
6251
  }
6231
6252
  const description = fm.description ?? "";
6232
6253
  if (description === "") {
6233
- violations.push(violation9("medium", "lint.frontmatter.description.missing", "frontmatter `description` is missing the trigger contract is required (mstar-skill-authoring § Frontmatter Contract)", "add a `description:` that states when the skill loads (symptoms, context, roles, exclusions)"));
6254
+ violations.push(violation9("medium", "lint.frontmatter.description.missing", "frontmatter `description` is missing \u2014 the trigger contract is required (mstar-skill-authoring \u00a7 Frontmatter Contract)", "add a `description:` that states when the skill loads (symptoms, context, roles, exclusions)"));
6234
6255
  } else {
6235
6256
  const stripped = description.replace(/`[^`]*`/g, " ").replace(/'[^']*'/g, " ").replace(/"[^"]*"/g, " ");
6236
6257
  let pronoun = null;
@@ -6241,15 +6262,15 @@ function lintSkillFrontmatter(frontmatterText) {
6241
6262
  break;
6242
6263
  }
6243
6264
  if (pronoun !== null) {
6244
- violations.push(violation9("low", "lint.frontmatter.description.person", `description uses first/second-person pronoun "${pronoun[0]}" keep the trigger contract third person (mstar-skill-authoring § Frontmatter Contract)`, 'rewrite without I/we/you/my/our/your/us, e.g. "Use when the user asks "'));
6265
+ violations.push(violation9("low", "lint.frontmatter.description.person", `description uses first/second-person pronoun "${pronoun[0]}" \u2014 keep the trigger contract third person (mstar-skill-authoring \u00a7 Frontmatter Contract)`, 'rewrite without I/we/you/my/our/your/us, e.g. "Use when the user asks \u2026"'));
6245
6266
  }
6246
6267
  const start = description.trim().replace(/^[*_#>]+/, "").replace(/^["'`]+/, "").trim();
6247
6268
  if (WORKFLOW_VERB_START_RE.test(start)) {
6248
- violations.push(violation9("low", "lint.frontmatter.description.workflow", 'description reads as a workflow summary ("Explains/Describes/Covers ") the description is the trigger contract, not a summary of steps (mstar-skill-authoring § Frontmatter Contract)', "describe when to load the skill (symptoms, context, roles, exclusions) instead of summarizing its steps"));
6269
+ violations.push(violation9("low", "lint.frontmatter.description.workflow", 'description reads as a workflow summary ("Explains/Describes/Covers \u2026") \u2014 the description is the trigger contract, not a summary of steps (mstar-skill-authoring \u00a7 Frontmatter Contract)', "describe when to load the skill (symptoms, context, roles, exclusions) instead of summarizing its steps"));
6249
6270
  } else {
6250
6271
  const words = description.trim().split(/\s+/).filter(Boolean).length;
6251
6272
  if (words > DESCRIPTION_MAX_WORDS) {
6252
- violations.push(violation9("low", "lint.frontmatter.description.workflow", `description is ${words} words paragraph-length summaries bury the trigger contract (threshold ${DESCRIPTION_MAX_WORDS}, above the longest corpus description at 114 words, mstar-design-md; mstar-skill-authoring § Frontmatter Contract)`, "trim the description to a scannable trigger contract and move detail into the body"));
6273
+ violations.push(violation9("low", "lint.frontmatter.description.workflow", `description is ${words} words \u2014 paragraph-length summaries bury the trigger contract (threshold ${DESCRIPTION_MAX_WORDS}, above the longest corpus description at 114 words, mstar-design-md; mstar-skill-authoring \u00a7 Frontmatter Contract)`, "trim the description to a scannable trigger contract and move detail into the body"));
6253
6274
  }
6254
6275
  }
6255
6276
  }
@@ -6296,7 +6317,7 @@ function lintStrategySections(docText) {
6296
6317
  }
6297
6318
  for (const required of REQUIRED_STRATEGY_SECTIONS) {
6298
6319
  if (!headings.has(required.toLowerCase())) {
6299
- violations.push(violation9("medium", "lint.strategy.missing-section", `missing required section "${required}" (mstar-strategy § STRATEGY.md structure)`, "add a `## <Section>` heading; required: Vision, What we build, What we don't build, Guiding Principles, Technology Direction, Decision Log"));
6320
+ violations.push(violation9("medium", "lint.strategy.missing-section", `missing required section "${required}" (mstar-strategy \u00a7 STRATEGY.md structure)`, "add a `## <Section>` heading; required: Vision, What we build, What we don't build, Guiding Principles, Technology Direction, Decision Log"));
6300
6321
  }
6301
6322
  }
6302
6323
  return { ok: violations.length === 0, violations };
@@ -6337,7 +6358,7 @@ function lintFiveQuestion(bodyText) {
6337
6358
  const label = section.label.toLowerCase();
6338
6359
  const covered = headings.some((heading) => heading.includes(label));
6339
6360
  if (!covered) {
6340
- violations.push(violation11("low", `skill-authoring.five-question.${section.key}`, `body does not answer "${section.question}" no "${section.label}" section (mstar-skill-authoring § Body 必须回答的 5 / § 默认 Body 结构)`, `add a "## ${section.label}" section covering ${section.question}`));
6361
+ violations.push(violation11("low", `skill-authoring.five-question.${section.key}`, `body does not answer "${section.question}" \u2014 no "${section.label}" section (mstar-skill-authoring \u00a7 Body \u5fc5\u987b\u56de\u7b54\u7684 5 \u95ee / \u00a7 \u9ed8\u8ba4 Body \u7ed3\u6784)`, `add a "## ${section.label}" section covering ${section.question}`));
6341
6362
  }
6342
6363
  }
6343
6364
  return { ok: violations.length === 0, violations };
@@ -6434,7 +6455,7 @@ var GITIGNORE_SNIPPET2 = `# Morning Star harness (.mstar/)
6434
6455
  !.mstar/specs/
6435
6456
  !.mstar/specs/**
6436
6457
  `;
6437
- var GITIGNORE_SNIPPET_AGENTS2 = `# Morning Star harness (.agents/) legacy
6458
+ var GITIGNORE_SNIPPET_AGENTS2 = `# Morning Star harness (.agents/) \u2014 legacy
6438
6459
  # Default-ignore everything under .agents/, then re-include the tracked results.
6439
6460
  .agents/**
6440
6461
  !.agents/AGENTS.md
@@ -6472,7 +6493,7 @@ function validateExecutionLease(lease) {
6472
6493
  return {
6473
6494
  ok: false,
6474
6495
  violations: [
6475
- violation("high", "lease.execution-lease.invalid", "execution_lease must be an object null and tombstone objects are invalid; writers delete the key on release")
6496
+ violation("high", "lease.execution-lease.invalid", "execution_lease must be an object \u2014 null and tombstone objects are invalid; writers delete the key on release")
6476
6497
  ]
6477
6498
  };
6478
6499
  }
@@ -6487,11 +6508,11 @@ function validateExecutionLease(lease) {
6487
6508
  } else if (typeof lease.worktree_path !== "string" || lease.worktree_path.trim() === "") {
6488
6509
  violations.push(violation("medium", "lease.execution-lease.invalid-worktree-path", "worktree_path must be a non-empty string"));
6489
6510
  } else if (!isAbsolute22(lease.worktree_path)) {
6490
- violations.push(violation("medium", "lease.execution-lease.invalid-worktree-path", "worktree_path must be an absolute path it identifies the dedicated feature-worktree root (and MUST differ from metadata.control_worktree_path)"));
6511
+ violations.push(violation("medium", "lease.execution-lease.invalid-worktree-path", "worktree_path must be an absolute path \u2014 it identifies the dedicated feature-worktree root (and MUST differ from metadata.control_worktree_path)"));
6491
6512
  }
6492
6513
  validateNonEmptyString(violations, lease.working_branch, "working_branch", "lease.execution-lease.missing-working-branch", "lease.execution-lease.invalid-working-branch");
6493
6514
  if (lease.session_label !== undefined && typeof lease.session_label !== "string") {
6494
- violations.push(violation("medium", "lease.execution-lease.invalid-session-label", "session_label must be a string (display only never used for ownership comparison)"));
6515
+ violations.push(violation("medium", "lease.execution-lease.invalid-session-label", "session_label must be a string (display only \u2014 never used for ownership comparison)"));
6495
6516
  }
6496
6517
  return { ok: violations.length === 0, violations };
6497
6518
  }
@@ -6508,7 +6529,7 @@ function verifyPlanExecutionLease(row, planId) {
6508
6529
  return {
6509
6530
  ok: false,
6510
6531
  violations: [
6511
- violation("high", "lease.verify.orphan", "plan is InProgress without an execution_lease orphan: STOP, no writable dispatch until recovery (status-and-residuals.md § Orphan recovery)")
6532
+ violation("high", "lease.verify.orphan", "plan is InProgress without an execution_lease \u2014 orphan: STOP, no writable dispatch until recovery (status-and-residuals.md \u00a7 Orphan recovery)")
6512
6533
  ]
6513
6534
  };
6514
6535
  }
@@ -6521,9 +6542,9 @@ function verifyPlanExecutionLease(row, planId) {
6521
6542
  }
6522
6543
  const violations = [];
6523
6544
  if (rowLease !== undefined && metadataLease !== undefined) {
6524
- violations.push(violation("high", "lease.verify.dual-write", "execution_lease present in BOTH plans[].execution_lease (SSOT) and plans[].metadata.execution_lease the row-level lease wins; delete the metadata copy to remove the dual write"));
6545
+ violations.push(violation("high", "lease.verify.dual-write", "execution_lease present in BOTH plans[].execution_lease (SSOT) and plans[].metadata.execution_lease \u2014 the row-level lease wins; delete the metadata copy to remove the dual write"));
6525
6546
  } else if (rowLease === undefined) {
6526
- violations.push(violation("high", "lease.verify.non-ssot-location", "execution_lease found only under plans[].metadata.execution_lease the SSOT location is plans[].execution_lease; the metadata location is a legacy/hand-written read-compat fallback, not equivalent to SSOT success (migrate the lease to the plan row)"));
6547
+ violations.push(violation("high", "lease.verify.non-ssot-location", "execution_lease found only under plans[].metadata.execution_lease \u2014 the SSOT location is plans[].execution_lease; the metadata location is a legacy/hand-written read-compat fallback, not equivalent to SSOT success (migrate the lease to the plan row)"));
6527
6548
  }
6528
6549
  violations.push(...validateExecutionLease(lease).violations);
6529
6550
  return { ok: violations.length === 0, violations, lease };
@@ -6701,11 +6722,11 @@ function validateManifest(manifest, errors2, warnings) {
6701
6722
  }
6702
6723
  if (doc.extensions !== undefined) {
6703
6724
  if (!isPlainObject6(doc.extensions)) {
6704
- warnings.push('plugin.json: "extensions" is not an object ignored');
6725
+ warnings.push('plugin.json: "extensions" is not an object \u2014 ignored');
6705
6726
  } else {
6706
6727
  for (const [namespace, value] of Object.entries(doc.extensions)) {
6707
6728
  if (!isPlainObject6(value)) {
6708
- warnings.push(`plugin.json: "extensions.${namespace}" is not an object ignored`);
6729
+ warnings.push(`plugin.json: "extensions.${namespace}" is not an object \u2014 ignored`);
6709
6730
  }
6710
6731
  }
6711
6732
  }
@@ -6766,7 +6787,7 @@ function validateMcpServer(name, entry, errors2) {
6766
6787
  } else {
6767
6788
  const remainder = stripMcpPathPrefix(server.cwd);
6768
6789
  if (remainder === null) {
6769
- errors2.push(`${prefix}: "cwd" must be "./…", "${"${PLUGIN_ROOT}"}", or "${"${PLUGIN_DATA}"}"`);
6790
+ errors2.push(`${prefix}: "cwd" must be "./\u2026", "${"${PLUGIN_ROOT}"}\u2026", or "${"${PLUGIN_DATA}"}\u2026"`);
6770
6791
  } else if (escapesPluginRoot(remainder)) {
6771
6792
  errors2.push(`${prefix}: "cwd" must remain within the plugin root (got "${server.cwd}")`);
6772
6793
  }
@@ -7341,7 +7362,7 @@ function ensureIterationSkillLinks(dryRun) {
7341
7362
  }
7342
7363
  const gitignoreEntries = CODEX_PROJECT_COMMAND_NAMES.map(iterationSkillGitignoreEntry);
7343
7364
  notes.push(...appendGitignore(projectRoot, gitignoreEntries, dryRun));
7344
- notes.push("Installed Codex project-scoped command skills under .agents/skills/ (iteration-start, iteration-drive, iteration-loop, codebase-audit) symlinked to harness commands/*.md.");
7365
+ notes.push("Installed Codex project-scoped command skills under .agents/skills/ (iteration-start, iteration-drive, iteration-loop, codebase-audit) \u2014 symlinked to harness commands/*.md.");
7345
7366
  return notes;
7346
7367
  }
7347
7368
  function validateIterationSkillLinks() {
@@ -7657,7 +7678,7 @@ function runInit2(scope, dryRun) {
7657
7678
  }
7658
7679
  notes.push("Verify with: omp plugin list");
7659
7680
  notes.push("Enter PM with /skill:pm ; commands: /iteration-start /iteration-drive /iteration-loop /codebase-audit");
7660
- notes.push(`Host adapter: mstar-host references/omp.md (skill://mstar-host/references/omp.md)`);
7681
+ notes.push(`Host adapter: mstar-host \u2192 references/omp.md (skill://mstar-host/references/omp.md)`);
7661
7682
  notes.push(`Alternate install without CLI link: omp plugin install ${REPO_URL.replace("https://github.com/", "github:").replace(/\.git$/, "")}`);
7662
7683
  return {
7663
7684
  location: HARNESS_REPO_PATH,
@@ -7782,10 +7803,10 @@ function getDoctorWarnings(config) {
7782
7803
  const hasNpm = strings.some(isMstarHarnessOpencodePlugin);
7783
7804
  const hasLegacy = strings.some(isLegacyMorningStarGitPlugin);
7784
7805
  if (hasLegacy && !hasNpm) {
7785
- warnings.push("Plugin list uses legacy `morning-star@git+…` for this harness; run `mstar-harness init --target opencode` to rewrite to `@mstar-harness/opencode@latest`.");
7806
+ warnings.push("Plugin list uses legacy `morning-star@git+\u2026` for this harness; run `mstar-harness init --target opencode` to rewrite to `@mstar-harness/opencode@latest`.");
7786
7807
  }
7787
7808
  if (hasLegacy && hasNpm) {
7788
- warnings.push("Both legacy `morning-star@git+…` and `@mstar-harness/opencode` appear in `plugin`; run `init` again to dedupe and keep a single npm plugin line.");
7809
+ warnings.push("Both legacy `morning-star@git+\u2026` and `@mstar-harness/opencode` appear in `plugin`; run `init` again to dedupe and keep a single npm plugin line.");
7789
7810
  }
7790
7811
  const agent = ensureObject(config.agent);
7791
7812
  const missingModels = ALL_ROLES.filter((roleId) => {
@@ -7793,7 +7814,7 @@ function getDoctorWarnings(config) {
7793
7814
  return typeof role.model !== "string" || !role.model.trim();
7794
7815
  });
7795
7816
  if (missingModels.length) {
7796
- warnings.push(`${missingModels.length} role(s) have no explicit agent.<role>.model OpenCode default model will be used (recommended for fastest setup).`);
7817
+ warnings.push(`${missingModels.length} role(s) have no explicit agent.<role>.model \u2014 OpenCode default model will be used (recommended for fastest setup).`);
7797
7818
  }
7798
7819
  return warnings;
7799
7820
  }
@@ -7981,7 +8002,7 @@ function runInit3(scope, dryRun) {
7981
8002
  if (!dryRun)
7982
8003
  writeJson2(KNOWN_MARKETPLACES_PATH, knownNext);
7983
8004
  notes.push(`Registered ${MARKETPLACE_ID} marketplace in ${KNOWN_MARKETPLACES_PATH}`);
7984
- notes.push(`Then in ZCode: Settings Plugin Management Discover install ${PLUGIN_NAME} from the ${MARKETPLACE_ID} marketplace.`);
8005
+ notes.push(`Then in ZCode: Settings \u2192 Plugin Management \u2192 Discover \u2192 install ${PLUGIN_NAME} from the ${MARKETPLACE_ID} marketplace.`);
7985
8006
  return {
7986
8007
  location: KNOWN_MARKETPLACES_PATH,
7987
8008
  notes
@@ -8950,7 +8971,7 @@ hostCommand.command("detect").description("Detect the active host from --signals
8950
8971
  }
8951
8972
  });
8952
8973
  var skillCommand = program2.command("skill").description("skill-authoring lints (engine-backed)");
8953
- skillCommand.command("lint").description("Lint <skill-dir>/SKILL.md: frontmatter contract (name lowercase-hyphen, description trigger contract) " + "+ the five-question body (exit 1 on violations, 2 on usage)").argument("[skill-dir]", "Skill directory containing SKILL.md").action((skillDir) => {
8974
+ skillCommand.command("lint").description("Lint <skill-dir>/SKILL.md: frontmatter contract (name lowercase-hyphen, description trigger contract) " + "+ the five-question body + ephemeral-citation scan (task-<digits>-* artifacts and .mstar/sdd/\u2026 deeplinks \u2014 " + "exit 1 on violations, 2 on usage)").argument("[skill-dir]", "Skill directory containing SKILL.md").action((skillDir) => {
8954
8975
  try {
8955
8976
  if (!skillDir)
8956
8977
  throw new SddScriptError("usage: skill lint <skill-dir>", 2);
@@ -8965,6 +8986,19 @@ skillCommand.command("lint").description("Lint <skill-dir>/SKILL.md: frontmatter
8965
8986
  const fiveQuestion = lintFiveQuestion(stripFrontmatter(text));
8966
8987
  printChecklist("skill lint (five questions)", fiveQuestion);
8967
8988
  violations.push(...fiveQuestion.violations);
8989
+ const ephemeral = findEphemeralCitations(text);
8990
+ const ephemeralGate = {
8991
+ ok: ephemeral.length === 0,
8992
+ violations: ephemeral.map((citation) => ({
8993
+ ok: false,
8994
+ severity: "medium",
8995
+ code: `skill.ephemeral.${citation.kind}`,
8996
+ message: `ephemeral ${citation.kind} citation at line ${citation.line}: "${citation.match}" \u2014 task artifacts and SDD deeplinks survive nothing; durable skill text cites in-repo artifacts only (knowledge conventions/skill-content-porting-discipline.md \xA73)`,
8997
+ fix: `rewrite "${citation.match}" as a placeholder form (e.g. task-N-report, <plan-id>, {SDD_DIR}/task-N-report.md) or cite a stable in-repo artifact instead`
8998
+ }))
8999
+ };
9000
+ printChecklist("skill lint (ephemeral citations)", ephemeralGate);
9001
+ violations.push(...ephemeralGate.violations);
8968
9002
  if (violations.length > 0)
8969
9003
  process.exitCode = 1;
8970
9004
  } catch (error) {