aws-security-mcp 0.7.5 → 0.7.6

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.
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-950:oklch(25.7% .09 281.288);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-tight:1.25;--leading-relaxed:1.625;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-16{top:calc(var(--spacing) * 16)}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-\[300px\]{height:300px}.min-h-screen{min-height:100vh}.w-5{width:calc(var(--spacing) * 5)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[200px\]{min-width:200px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/30{border-color:color-mix(in oklab, var(--color-blue-500) 30%, transparent)}}.border-current{border-color:currentColor}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab, red, red)){.border-green-500\/30{border-color:color-mix(in oklab, var(--color-green-500) 30%, transparent)}}.border-indigo-700\/50{border-color:#432dd780}@supports (color:color-mix(in lab, red, red)){.border-indigo-700\/50{border-color:color-mix(in oklab, var(--color-indigo-700) 50%, transparent)}}.border-orange-500\/30{border-color:#fe6e004d}@supports (color:color-mix(in lab, red, red)){.border-orange-500\/30{border-color:color-mix(in oklab, var(--color-orange-500) 30%, transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab, red, red)){.border-red-500\/30{border-color:color-mix(in oklab, var(--color-red-500) 30%, transparent)}}.border-slate-600{border-color:var(--color-slate-600)}.border-slate-700{border-color:var(--color-slate-700)}.border-transparent{border-color:#0000}.border-yellow-500\/20{border-color:#edb20033}@supports (color:color-mix(in lab, red, red)){.border-yellow-500\/20{border-color:color-mix(in oklab, var(--color-yellow-500) 20%, transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab, red, red)){.border-yellow-500\/30{border-color:color-mix(in oklab, var(--color-yellow-500) 30%, transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/20{background-color:color-mix(in oklab, var(--color-blue-500) 20%, transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab, red, red)){.bg-green-500\/20{background-color:color-mix(in oklab, var(--color-green-500) 20%, transparent)}}.bg-orange-500\/20{background-color:#fe6e0033}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/20{background-color:color-mix(in oklab, var(--color-orange-500) 20%, transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/20{background-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.bg-slate-700{background-color:var(--color-slate-700)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-800\/30{background-color:#1d293d4d}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/30{background-color:color-mix(in oklab, var(--color-slate-800) 30%, transparent)}}.bg-slate-800\/50{background-color:#1d293d80}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/50{background-color:color-mix(in oklab, var(--color-slate-800) 50%, transparent)}}.bg-slate-800\/80{background-color:#1d293dcc}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/80{background-color:color-mix(in oklab, var(--color-slate-800) 80%, transparent)}}.bg-slate-900{background-color:var(--color-slate-900)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab, red, red)){.bg-yellow-500\/5{background-color:color-mix(in oklab, var(--color-yellow-500) 5%, transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab, red, red)){.bg-yellow-500\/20{background-color:color-mix(in oklab, var(--color-yellow-500) 20%, transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-slate-800{--tw-gradient-from:var(--color-slate-800);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-indigo-950{--tw-gradient-to:var(--color-indigo-950);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-8{padding-block:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-indigo-300{color:var(--color-indigo-300)}.text-orange-400{color:var(--color-orange-400)}.text-red-400{color:var(--color-red-400)}.text-slate-50{color:var(--color-slate-50)}.text-slate-100{color:var(--color-slate-100)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-yellow-400{color:var(--color-yellow-400)}.text-yellow-400\/80{color:#fac800cc}@supports (color:color-mix(in lab, red, red)){.text-yellow-400\/80{color:color-mix(in oklab, var(--color-yellow-400) 80%, transparent)}}.text-yellow-500\/60{color:#edb20099}@supports (color:color-mix(in lab, red, red)){.text-yellow-500\/60{color:color-mix(in oklab, var(--color-yellow-500) 60%, transparent)}}.placeholder-slate-500::placeholder{color:var(--color-slate-500)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:border-slate-400:hover{border-color:var(--color-slate-400)}.hover\:border-slate-500:hover{border-color:var(--color-slate-500)}.hover\:bg-slate-700\/50:hover{background-color:#31415880}@supports (color:color-mix(in lab, red, red)){.hover\:bg-slate-700\/50:hover{background-color:color-mix(in oklab, var(--color-slate-700) 50%, transparent)}}.hover\:text-slate-200:hover{color:var(--color-slate-200)}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}@media (width>=40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=64rem){.lg\:mt-0{margin-top:calc(var(--spacing) * 0)}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}}body{color:#f8fafc;background-color:#0f172a;margin:0;font-family:Inter,system-ui,-apple-system,sans-serif}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#1e293b}::-webkit-scrollbar-thumb{background:#475569;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#64748b}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>AWS Security Dashboard</title>
8
- <script type="module" crossorigin src="/assets/index-DsWFAp9v.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-BXloWmhE.css">
8
+ <script type="module" crossorigin src="/assets/index-BoNhDdVm.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-DY4x_jab.css">
10
10
  </head>
11
11
  <body class="bg-slate-900 text-slate-50">
12
12
  <div id="root"></div>
@@ -205,7 +205,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
205
205
  import { z } from "zod";
206
206
 
207
207
  // src/version.ts
208
- var VERSION = "0.7.5";
208
+ var VERSION = "0.7.6";
209
209
 
210
210
  // src/utils/aws-client.ts
211
211
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -280,8 +280,7 @@ async function listOrgAccounts(region) {
280
280
  return accounts;
281
281
  }
282
282
 
283
- // src/scanners/runner.ts
284
- var DEFAULT_CONCURRENCY = 5;
283
+ // src/utils/concurrency.ts
285
284
  async function runWithConcurrency(tasks, limit) {
286
285
  const results = [];
287
286
  const executing = /* @__PURE__ */ new Set();
@@ -300,6 +299,9 @@ async function runWithConcurrency(tasks, limit) {
300
299
  await Promise.all(executing);
301
300
  return results;
302
301
  }
302
+
303
+ // src/scanners/runner.ts
304
+ var DEFAULT_CONCURRENCY = 5;
303
305
  var AGGREGATION_MODULES = /* @__PURE__ */ new Set([
304
306
  "security_hub_findings",
305
307
  "guardduty_findings",
@@ -870,24 +872,6 @@ import {
870
872
  DescribeInstanceAttributeCommand
871
873
  } from "@aws-sdk/client-ec2";
872
874
  var USERDATA_CONCURRENCY = 5;
873
- async function runWithConcurrency2(tasks, limit) {
874
- const results = [];
875
- const executing = /* @__PURE__ */ new Set();
876
- for (let i = 0; i < tasks.length; i++) {
877
- const idx = i;
878
- const p = tasks[idx]().then((value) => {
879
- results[idx] = { status: "fulfilled", value };
880
- }).catch((reason) => {
881
- results[idx] = { status: "rejected", reason };
882
- }).finally(() => {
883
- executing.delete(p);
884
- });
885
- executing.add(p);
886
- if (executing.size >= limit) await Promise.race(executing);
887
- }
888
- await Promise.all(executing);
889
- return results;
890
- }
891
875
  var SECRET_PATTERNS = [
892
876
  { name: "AWS Access Key", pattern: /AKIA[0-9A-Z]{16}/, matchType: "value" },
893
877
  { name: "Private Key", pattern: /-----BEGIN.*PRIVATE KEY-----/, matchType: "value" },
@@ -998,7 +982,7 @@ var SecretExposureScanner = class {
998
982
  const raw = attrResp.UserData?.Value;
999
983
  return { instId, userData: raw ? Buffer.from(raw, "base64").toString("utf-8") : void 0 };
1000
984
  });
1001
- const settled = await runWithConcurrency2(userDataTasks, USERDATA_CONCURRENCY);
985
+ const settled = await runWithConcurrency(userDataTasks, USERDATA_CONCURRENCY);
1002
986
  for (let i = 0; i < instances.length; i++) {
1003
987
  const result = settled[i];
1004
988
  const inst = instances[i];
@@ -1978,7 +1962,8 @@ async function getBucketRegion(client, bucketName, defaultRegion, warnings) {
1978
1962
  const resp = await client.send(
1979
1963
  new GetBucketLocationCommand({ Bucket: bucketName })
1980
1964
  );
1981
- const loc = String(resp.LocationConstraint ?? "") || "us-east-1";
1965
+ const rawLoc = String(resp.LocationConstraint ?? "") || "us-east-1";
1966
+ const loc = rawLoc === "EU" ? "eu-west-1" : rawLoc;
1982
1967
  return loc;
1983
1968
  } catch (e) {
1984
1969
  const msg = e instanceof Error ? e.message : String(e);
@@ -3934,6 +3919,7 @@ var zhI18n = {
3934
3919
  // Extended — MLPS extras
3935
3920
  // Markdown report
3936
3921
  executiveSummary: "\u6267\u884C\u6458\u8981",
3922
+ aiSummaryTitle: "AI \u5B89\u5168\u6001\u52BF\u603B\u7ED3",
3937
3923
  totalFindingsLabel: "\u53D1\u73B0\u603B\u6570",
3938
3924
  description: "\u63CF\u8FF0",
3939
3925
  priority: "\u4F18\u5148\u7EA7",
@@ -4243,6 +4229,7 @@ var enI18n = {
4243
4229
  // Extended \u2014 MLPS extras
4244
4230
  // Markdown report
4245
4231
  executiveSummary: "Executive Summary",
4232
+ aiSummaryTitle: "AI Security Summary",
4246
4233
  totalFindingsLabel: "Total Findings",
4247
4234
  description: "Description",
4248
4235
  priority: "Priority",
@@ -4504,6 +4491,14 @@ function generateMarkdownReport(scanResults, lang) {
4504
4491
  `- **${t.totalFindingsLabel}:** ${summary.totalFindings} (${SEVERITY_ICON.CRITICAL} ${summary.critical} ${t.critical} | ${SEVERITY_ICON.HIGH} ${summary.high} ${t.high} | ${SEVERITY_ICON.MEDIUM} ${summary.medium} ${t.medium} | ${SEVERITY_ICON.LOW} ${summary.low} ${t.low})`
4505
4492
  );
4506
4493
  lines.push("");
4494
+ if (scanResults.aiSummary && scanResults.aiSummary.trim()) {
4495
+ lines.push(`> \u2728 **${t.aiSummaryTitle}**`);
4496
+ lines.push(">");
4497
+ for (const ln of scanResults.aiSummary.trim().split(/\r?\n/)) {
4498
+ lines.push(`> ${ln}`);
4499
+ }
4500
+ lines.push("");
4501
+ }
4507
4502
  if (summary.totalFindings === 0) {
4508
4503
  lines.push(`## ${t.findingsBySeverity}`);
4509
4504
  lines.push("");
@@ -7281,6 +7276,14 @@ function generateMlps3Report(scanResults, lang) {
7281
7276
  lines.push(`## ${t.accountInfo}`);
7282
7277
  lines.push(`- ${t.account}: ${accountId} | ${t.region}: ${region} | ${t.scanTime}: ${scanTime}`);
7283
7278
  lines.push("");
7279
+ if (scanResults.aiSummary && scanResults.aiSummary.trim()) {
7280
+ lines.push(`> \u2728 **${t.aiSummaryTitle}**`);
7281
+ lines.push(">");
7282
+ for (const ln of scanResults.aiSummary.trim().split(/\r?\n/)) {
7283
+ lines.push(`> ${ln}`);
7284
+ }
7285
+ lines.push("");
7286
+ }
7284
7287
  lines.push(`## ${t.preCheckOverview}`);
7285
7288
  lines.push(`- ${t.checkedCount(checkedTotal, autoClean, autoIssues)}`);
7286
7289
  if (autoUnknown > 0) {
@@ -7383,6 +7386,14 @@ function escWithLinks(s) {
7383
7386
  return esc(part);
7384
7387
  }).join("");
7385
7388
  }
7389
+ function aiSummaryBlock(summary, title) {
7390
+ const text = (summary ?? "").trim();
7391
+ if (!text) return "";
7392
+ return `<div class="ai-summary">
7393
+ <div class="ai-summary-title">\u2728 ${esc(title)}</div>
7394
+ <div class="ai-summary-body">${esc(text)}</div>
7395
+ </div>`;
7396
+ }
7386
7397
  function calcScore(summary) {
7387
7398
  const raw = 100 - summary.critical * 15 - summary.high * 5 - summary.medium * 2 - summary.low * 0.5;
7388
7399
  return Math.max(0, Math.min(100, Math.round(raw)));
@@ -7627,7 +7638,13 @@ function sharedCss() {
7627
7638
  details{display:block}
7628
7639
  details>summary{display:block}
7629
7640
  details>:not(summary){display:block !important}
7641
+ .ai-summary{background:#f5f3ff !important;border-color:#c7d2fe !important}
7642
+ .ai-summary-title{color:#4338ca !important}
7643
+ .ai-summary-body{color:#1e293b !important}
7630
7644
  }
7645
+ .ai-summary{background:linear-gradient(135deg,#1e293b,#1e1b4b);border:1px solid #4338ca;border-radius:10px;padding:16px 20px;margin:0 0 28px}
7646
+ .ai-summary-title{font-size:14px;font-weight:700;color:#a5b4fc;margin-bottom:8px}
7647
+ .ai-summary-body{font-size:14px;line-height:1.7;color:#cbd5e1;white-space:pre-wrap}
7631
7648
  `;
7632
7649
  }
7633
7650
  function donutChart(summary) {
@@ -8179,6 +8196,8 @@ ${remaining.map(renderRec).join("\n")}
8179
8196
  <div class="meta">${esc(t.account)}: ${esc(accountId)} | ${esc(t.region)}: ${esc(region)} | ${esc(date)} | ${esc(t.duration)}: ${esc(duration)}</div>
8180
8197
  </header>
8181
8198
 
8199
+ ${aiSummaryBlock(scanResults.aiSummary, t.aiSummaryTitle)}
8200
+
8182
8201
  <section class="summary">
8183
8202
  <div class="score-card">
8184
8203
  <div class="score-value" style="color:${scoreColor(score)}">${score}</div>
@@ -8526,6 +8545,8 @@ ${mlpsRemaining.map(renderMlpsRec).join("\n")}
8526
8545
  <div class="meta">${esc(t.account)}: ${esc(accountId)} | ${esc(t.region)}: ${esc(region)} | ${esc(t.scanTime)}: ${esc(scanTime)}</div>
8527
8546
  </header>
8528
8547
 
8548
+ ${aiSummaryBlock(scanResults.aiSummary, t.aiSummaryTitle)}
8549
+
8529
8550
  <section class="summary" style="display:block;text-align:center">
8530
8551
  <div style="font-size:36px;font-weight:700;margin-bottom:12px">
8531
8552
  <span style="color:#22c55e">${autoClean}</span> <span style="color:#94a3b8;font-size:18px">${esc(t.noIssues)}</span>
@@ -8574,6 +8595,14 @@ function safeUrl2(url) {
8574
8595
  return null;
8575
8596
  }
8576
8597
  }
8598
+ function aiSummaryBlock2(summary, title) {
8599
+ const text = (summary ?? "").trim();
8600
+ if (!text) return "";
8601
+ return `<div class="ai-summary">
8602
+ <div class="ai-summary-title">\u2728 ${esc2(title)}</div>
8603
+ <div class="ai-summary-body">${esc2(text)}</div>
8604
+ </div>`;
8605
+ }
8577
8606
  function escWithLinks2(s) {
8578
8607
  const parts = s.split(/(https?:\/\/\S+)/);
8579
8608
  return parts.map((part, i) => {
@@ -8709,7 +8738,13 @@ function hwCss() {
8709
8738
  details{display:block}
8710
8739
  details>summary{display:block}
8711
8740
  details>:not(summary){display:block !important}
8741
+ .ai-summary{background:#f5f3ff !important;border-color:#c7d2fe !important}
8742
+ .ai-summary-title{color:#4338ca !important}
8743
+ .ai-summary-body{color:#1e293b !important}
8712
8744
  }
8745
+ .ai-summary{background:linear-gradient(135deg,#1e293b,#1e1b4b);border:1px solid #4338ca;border-radius:10px;padding:16px 20px;margin:0 0 28px}
8746
+ .ai-summary-title{font-size:14px;font-weight:700;color:#a5b4fc;margin-bottom:8px}
8747
+ .ai-summary-body{font-size:14px;line-height:1.7;color:#cbd5e1;white-space:pre-wrap}
8713
8748
  `;
8714
8749
  }
8715
8750
  function generateHwDefenseHtmlReport(scanResults, lang) {
@@ -8910,6 +8945,8 @@ function generateHwDefenseHtmlReport(scanResults, lang) {
8910
8945
  <div class="meta">${esc2(t.account)}: ${esc2(accountId)} | ${esc2(t.region)}: ${esc2(region)} | ${esc2(t.scanTime)}: ${esc2(scanTime)}</div>
8911
8946
  </header>
8912
8947
 
8948
+ ${aiSummaryBlock2(scanResults.aiSummary, t.aiSummaryTitle)}
8949
+
8913
8950
  <section class="summary-cards">
8914
8951
  <div class="summary-card"><div class="stat-count" style="color:${findingsColor}">${totalFindings}</div><div class="stat-label">${esc2(t.hwTotalFindings)}</div></div>
8915
8952
  <div class="summary-card"><div class="stat-count" style="color:#60a5fa">${sectionsChecked}</div><div class="stat-label">${esc2(t.hwSectionsChecked)}</div></div>
@@ -8929,6 +8966,137 @@ ${sectionsHtml}
8929
8966
  </html>`;
8930
8967
  }
8931
8968
 
8969
+ // src/tools/ai-summary-prompt.ts
8970
+ function buildFindingsDigest(scan, lang, topN = 12) {
8971
+ const zh = lang === "zh";
8972
+ const all = scan.modules.flatMap(
8973
+ (m) => m.findings.map((f) => ({ ...f, module: f.module ?? m.module }))
8974
+ );
8975
+ const s = scan.summary;
8976
+ const byModule = [...scan.modules].filter((m) => m.findingsCount > 0).sort((a, b) => b.findingsCount - a.findingsCount).slice(0, 19).map((m) => `${m.module}=${m.findingsCount}`).join(", ");
8977
+ const top = [...all].sort((a, b) => b.riskScore - a.riskScore).slice(0, topN);
8978
+ const topLines = top.map(
8979
+ (f, i) => `${i + 1}. [${f.severity}/${f.priority}] ${f.title} \u2014 ${f.resourceType} ${f.resourceId} (${f.region}) risk=${f.riskScore}`
8980
+ ).join("\n");
8981
+ const head = zh ? `\u8D26\u53F7: ${scan.accountId} | \u533A\u57DF: ${scan.region}
8982
+ \u98CE\u9669\u603B\u6570: ${s.totalFindings} (CRITICAL ${s.critical} / HIGH ${s.high} / MEDIUM ${s.medium} / LOW ${s.low})
8983
+ \u6A21\u5757\u5206\u5E03: ${byModule || "\u65E0"}
8984
+
8985
+ \u9AD8\u98CE\u9669 Top ${top.length}:
8986
+ ${topLines || "\u65E0"}` : `Account: ${scan.accountId} | Region: ${scan.region}
8987
+ Total findings: ${s.totalFindings} (CRITICAL ${s.critical} / HIGH ${s.high} / MEDIUM ${s.medium} / LOW ${s.low})
8988
+ Module breakdown: ${byModule || "none"}
8989
+
8990
+ Top ${top.length} by risk:
8991
+ ${topLines || "none"}`;
8992
+ return head;
8993
+ }
8994
+ function getProfile(type, lang) {
8995
+ const zh = lang === "zh";
8996
+ switch (type) {
8997
+ case "dashboard":
8998
+ return zh ? {
8999
+ persona: "\u4F60\u5728\u4E3A\u5B89\u5168\u8FD0\u8425\u4EEA\u8868\u76D8\u5199\u4E00\u6BB5\u9AD8\u7BA1\u901F\u89C8\u3002\u8BFB\u8005\u662F CISO / \u7BA1\u7406\u5C42\uFF0C\u65F6\u95F4\u5F88\u5C11\u3002",
9000
+ focus: "\u6574\u4F53\u5B89\u5168\u6001\u52BF\u4E00\u53E5\u8BDD\u5B9A\u8C03 + \u5B89\u5168\u8BC4\u5206\u89E3\u8BFB + \u6B64\u523B\u6700\u8BE5\u5173\u6CE8\u7684 3 \u4EF6\u4E8B\uFF08\u6309\u4E1A\u52A1\u5F71\u54CD\u6392\u5E8F\uFF09\u3002\u4E0D\u8981\u7F57\u5217\u6240\u6709 finding\u3002",
9001
+ format: "3-5 \u53E5\u8BDD\uFF0C\u5F00\u5934\u4E00\u53E5\u7ED3\u8BBA\u5148\u884C\u3002\u4E2D\u6587\u3002\u4E0D\u7528 Markdown \u6807\u9898\uFF0C\u53EF\u7528\u7B80\u77ED\u5206\u53F7\u6216\u6362\u884C\u3002\u8BED\u6C14\u4E13\u4E1A\u3001\u514B\u5236\u3001\u53EF\u6267\u884C\u3002"
9002
+ } : {
9003
+ persona: "You are writing an executive at-a-glance summary for a security operations dashboard. Readers are CISO/leadership with little time.",
9004
+ focus: "One-line overall posture verdict + interpretation of the security score + the top 3 things to focus on right now (ordered by business impact). Do NOT list every finding.",
9005
+ format: "3-5 sentences, conclusion first. English. No Markdown headings; short line breaks ok. Professional, restrained, actionable tone."
9006
+ };
9007
+ case "html":
9008
+ return zh ? {
9009
+ persona: "\u4F60\u5728\u4E3A\u4E00\u4EFD\u5B8C\u6574\u7684 AWS \u5B89\u5168\u626B\u63CF\u62A5\u544A\u5199\u6267\u884C\u6458\u8981\u3002\u8BFB\u8005\u65E2\u6709\u7BA1\u7406\u5C42\u4E5F\u6709\u6280\u672F\u8D1F\u8D23\u4EBA\u3002",
9010
+ focus: "\u6574\u4F53\u98CE\u9669\u5168\u666F + Top \u98CE\u9669\u7684\u5171\u6027\u6839\u56E0\uFF08\u5982\u516C\u7F51\u66B4\u9732\u9762\u3001IAM \u8FC7\u6743\u3001\u52A0\u5BC6/\u65E5\u5FD7\u7F3A\u5931\u7B49\uFF09+ \u5206\u4F18\u5148\u7EA7(P0\u2192P2)\u7684\u4FEE\u590D\u8DEF\u7EBF\u5EFA\u8BAE\u3002\u70B9\u51FA\u7CFB\u7EDF\u6027\u95EE\u9898\u800C\u975E\u9010\u6761\u590D\u8FF0\u3002",
9011
+ format: "1 \u6BB5\u6982\u8FF0 + 3-5 \u6761\u8981\u70B9\u3002\u4E2D\u6587\u3002\u53EF\u7528\u8981\u70B9\u5217\u8868\u3002\u6280\u672F\u4E0E\u7BA1\u7406\u53CC\u89C6\u89D2\uFF0C\u7ED9\u51FA\u53EF\u843D\u5730\u7684\u4E0B\u4E00\u6B65\u3002"
9012
+ } : {
9013
+ persona: "You are writing the executive summary for a full AWS security scan report. Readers include both management and technical leads.",
9014
+ focus: "Overall risk landscape + common root causes behind the top risks (public exposure, over-privileged IAM, missing encryption/logging, etc.) + a prioritized (P0\u2192P2) remediation roadmap. Surface systemic issues rather than restating each finding.",
9015
+ format: "1 overview paragraph + 3-5 bullet points. English. Bullet list ok. Both technical and management lens, with concrete next steps."
9016
+ };
9017
+ case "hw_defense":
9018
+ return zh ? {
9019
+ persona: "\u4F60\u662F\u62A4\u7F51\u884C\u52A8(\u7F51\u7EDC\u5B89\u5168\u653B\u9632\u6F14\u7EC3)\u7684\u84DD\u961F\u6307\u6325\u3002\u8FD9\u662F\u4E00\u4EFD\u62A4\u7F51\u5907\u6218\u8BC4\u4F30\u62A5\u544A\u3002\u6CE8\u610F\uFF1AHW=\u62A4\u7F51\uFF0C\u4E0E\u534E\u4E3A\u65E0\u5173\u3002",
9020
+ focus: "\u4ECE\u653B\u51FB\u8005\u89C6\u89D2\u4E32\u8054 findings \u6210\u653B\u51FB\u94FE(kill-chain)\uFF1A\u54EA\u4E9B\u662F\u5916\u90E8\u53EF\u8FBE\u7684\u521D\u59CB\u7A81\u7834\u53E3\u3001\u6A2A\u5411\u79FB\u52A8/\u63D0\u6743\u8DEF\u5F84\u3001\u53EF\u80FD\u7684\u5F71\u54CD\u9762\uFF1B\u7136\u540E\u7ED9\u51FA\u5907\u6218\u6536\u655B\u6E05\u5355(\u5148\u5173\u4EC0\u4E48\u3001\u5148\u76EF\u4EC0\u4E48)\u3002\u5F3A\u8C03\u66B4\u9732\u9762\u6536\u655B\u4E0E\u76D1\u63A7\u52A0\u56FA\u3002",
9021
+ format: "\u5148\u4E00\u53E5\u7814\u5224\u7ED3\u8BBA(\u5F53\u524D\u66B4\u9732\u9762/\u88AB\u6253\u7A7F\u98CE\u9669)\uFF0C\u518D\u7ED9\u300E\u653B\u51FB\u94FE\u89C6\u89D2\u300F\u548C\u300E\u5907\u6218\u6574\u6539\u4F18\u5148\u7EA7\u300F\u4E24\u5757\u3002\u4E2D\u6587\u3002\u8BED\u6C14\u8D34\u62A4\u7F51\u5B9E\u6218\u8BED\u5883\uFF0C\u7D27\u8FEB\u4F46\u4E0D\u5938\u5F20\u3002"
9022
+ } : {
9023
+ persona: "You are the blue-team lead for an HW Defense exercise (cybersecurity attack-defense drill). This is a pre-exercise readiness report. Note: HW = HuWang/\u62A4\u7F51, unrelated to Huawei.",
9024
+ focus: "From an attacker's perspective, chain findings into a kill-chain: external initial footholds, lateral movement/privilege-escalation paths, likely blast radius; then a hardening checklist (what to close/watch first). Emphasize attack-surface reduction and monitoring.",
9025
+ format: "Lead with a one-line verdict (current exposure / breach risk), then two blocks: 'Attack-chain view' and 'Readiness remediation priorities'. English. Combat-readiness tone, urgent but not alarmist."
9026
+ };
9027
+ case "mlps3":
9028
+ return zh ? {
9029
+ persona: "\u4F60\u662F\u7B49\u4FDD\u6D4B\u8BC4\u987E\u95EE\u3002\u8FD9\u662F\u4E00\u4EFD\u7B49\u4FDD\u4E09\u7EA7(GB/T 22239-2019)\u5408\u89C4\u9884\u68C0\u62A5\u544A\u3002",
9030
+ focus: "\u4ECE\u5408\u89C4\u89C6\u89D2\u603B\u7ED3\uFF1A\u5F53\u524D\u5BF9\u7167\u7B49\u4FDD\u4E09\u7EA7\u63A7\u5236\u9879\u7684\u603B\u4F53\u8FBE\u6807\u60C5\u51B5\u3001\u54EA\u4E9B\u63A7\u5236\u57DF\u5B58\u5728\u660E\u663E\u4E0D\u8FBE\u6807\u9879(\u5982\u8BBF\u95EE\u63A7\u5236\u3001\u5B89\u5168\u5BA1\u8BA1\u3001\u5165\u4FB5\u9632\u8303\u3001\u6570\u636E\u5B8C\u6574\u6027/\u4FDD\u5BC6\u6027\u7B49)\u3001\u6574\u6539\u7D27\u8FEB\u5EA6\u4E0E\u8FC7\u4FDD\u5EFA\u8BAE\u3002\u628A\u6280\u672F finding \u6620\u5C04\u5230\u5408\u89C4\u8BED\u8A00\u3002",
9031
+ format: "1 \u6BB5\u5408\u89C4\u7ED3\u8BBA + \u6309\u63A7\u5236\u57DF\u5206\u7EC4\u7684\u4E0D\u8FBE\u6807\u8981\u70B9 + \u6574\u6539\u4F18\u5148\u7EA7\u3002\u4E2D\u6587\u3002\u5F15\u7528\u63A7\u5236\u57DF\u540D\u79F0\u3002\u8BED\u6C14\u4E25\u8C28\u3001\u9762\u5411\u6D4B\u8BC4\u3002"
9032
+ } : {
9033
+ persona: "You are an MLPS assessment advisor. This is an MLPS Level 3 (GB/T 22239-2019) compliance pre-check report.",
9034
+ focus: "Summarize from a compliance lens: overall conformance against MLPS L3 controls, which control domains have clear gaps (access control, security audit, intrusion prevention, data integrity/confidentiality, etc.), remediation urgency, and certification-readiness advice. Map technical findings to compliance language.",
9035
+ format: "1 compliance verdict paragraph + non-conformance points grouped by control domain + remediation priority. English. Reference control-domain names. Rigorous, assessment-oriented tone."
9036
+ };
9037
+ }
9038
+ }
9039
+ var TYPE_LABEL = {
9040
+ dashboard: { zh: "\u5B89\u5168\u8FD0\u8425\u4EEA\u8868\u76D8", en: "Security Operations Dashboard" },
9041
+ html: { zh: "AWS \u5B89\u5168\u626B\u63CF\u62A5\u544A", en: "AWS Security Scan Report" },
9042
+ hw_defense: { zh: "\u62A4\u7F51\u884C\u52A8\u8BC4\u4F30\u62A5\u544A", en: "HW Defense (\u62A4\u7F51) Readiness Report" },
9043
+ mlps3: { zh: "\u7B49\u4FDD\u4E09\u7EA7\u5408\u89C4\u9884\u68C0\u62A5\u544A", en: "MLPS Level 3 Compliance Pre-check" }
9044
+ };
9045
+ function buildAiSummaryPrompt(type, scan, lang) {
9046
+ const zh = lang === "zh";
9047
+ const p = getProfile(type, lang);
9048
+ const label = TYPE_LABEL[type][zh ? "zh" : "en"];
9049
+ const digest = buildFindingsDigest(scan, lang);
9050
+ if (zh) {
9051
+ return [
9052
+ `# \u4EFB\u52A1\uFF1A\u4E3A\u300C${label}\u300D\u751F\u6210\u9488\u5BF9\u6027\u7684 AI \u5B89\u5168\u603B\u7ED3`,
9053
+ ``,
9054
+ `## \u89D2\u8272`,
9055
+ p.persona,
9056
+ ``,
9057
+ `## \u603B\u7ED3\u91CD\u70B9`,
9058
+ p.focus,
9059
+ ``,
9060
+ `## \u8F93\u51FA\u683C\u5F0F`,
9061
+ p.format,
9062
+ ``,
9063
+ `## \u7EA6\u675F`,
9064
+ `- \u53EA\u4F9D\u636E\u4E0B\u9762\u7684\u626B\u63CF\u6570\u636E\uFF0C\u4E0D\u8981\u7F16\u9020\u4E0D\u5B58\u5728\u7684\u8D44\u6E90\u6216 finding\u3002`,
9065
+ `- \u4E0D\u8981\u9010\u6761\u590D\u8FF0\u6240\u6709 finding\uFF1B\u63D0\u70BC\u6A21\u5F0F\u4E0E\u4F18\u5148\u7EA7\u3002`,
9066
+ `- \u76F4\u63A5\u8F93\u51FA\u603B\u7ED3\u6B63\u6587\u672C\u8EAB\uFF08\u4E0D\u8981\u5E26\u300C\u4EE5\u4E0B\u662F\u603B\u7ED3\u300D\u4E4B\u7C7B\u7684\u524D\u8A00\uFF0C\u4E0D\u8981 code fence\uFF09\u3002`,
9067
+ `- \u8BED\u8A00\uFF1A\u4E2D\u6587\u3002`,
9068
+ ``,
9069
+ `## \u626B\u63CF\u6570\u636E\u6458\u8981`,
9070
+ digest,
9071
+ ``,
9072
+ `\u8BF7\u73B0\u5728\u8F93\u51FA\u603B\u7ED3\u6B63\u6587\u3002\u751F\u6210\u540E\uFF0C\u628A\u8FD9\u6BB5\u6587\u672C\u901A\u8FC7\u5BF9\u5E94\u62A5\u544A\u5DE5\u5177\u7684 ai_summary \u53C2\u6570\u56DE\u4F20\u5373\u53EF\u3002`
9073
+ ].join("\n");
9074
+ }
9075
+ return [
9076
+ `# Task: Produce a tailored AI security summary for the "${label}"`,
9077
+ ``,
9078
+ `## Role`,
9079
+ p.persona,
9080
+ ``,
9081
+ `## Summary focus`,
9082
+ p.focus,
9083
+ ``,
9084
+ `## Output format`,
9085
+ p.format,
9086
+ ``,
9087
+ `## Constraints`,
9088
+ `- Base it ONLY on the scan data below; do not invent resources or findings.`,
9089
+ `- Do not restate every finding; distill patterns and priorities.`,
9090
+ `- Output the summary body itself (no preamble like "Here is the summary", no code fences).`,
9091
+ `- Language: English.`,
9092
+ ``,
9093
+ `## Scan data digest`,
9094
+ digest,
9095
+ ``,
9096
+ `Now output the summary body. After generating it, pass the text back via the ai_summary parameter of the corresponding report tool.`
9097
+ ].join("\n");
9098
+ }
9099
+
8932
9100
  // src/tools/save-results.ts
8933
9101
  import { writeFileSync, readFileSync, mkdirSync, existsSync } from "fs";
8934
9102
  import { join } from "path";
@@ -8985,7 +9153,8 @@ function saveResults(scanResults, outputDir) {
8985
9153
  })),
8986
9154
  findings: scanResults.modules.flatMap(
8987
9155
  (m) => m.findings.map((f) => ({ ...f, module: m.module }))
8988
- )
9156
+ ),
9157
+ aiSummary: scanResults.aiSummary
8989
9158
  },
8990
9159
  history,
8991
9160
  meta: {
@@ -9601,11 +9770,13 @@ function createServer(defaultRegion) {
9601
9770
  "Generate a Markdown security report from scan results. Read-only. Does not modify any AWS resources.",
9602
9771
  {
9603
9772
  scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
9604
- lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
9773
+ lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
9774
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
9605
9775
  },
9606
- async ({ scan_results, lang }) => {
9776
+ async ({ scan_results, lang, ai_summary }) => {
9607
9777
  try {
9608
9778
  const parsed = JSON.parse(scan_results);
9779
+ if (ai_summary) parsed.aiSummary = ai_summary;
9609
9780
  const report = generateMarkdownReport(parsed, lang ?? "zh");
9610
9781
  return { content: [{ type: "text", text: report }] };
9611
9782
  } catch (err) {
@@ -9618,11 +9789,13 @@ function createServer(defaultRegion) {
9618
9789
  "Generate a GB/T 22239-2019 \u7B49\u4FDD\u4E09\u7EA7 compliance pre-check report from scan results. Best used with scan_group mlps3_precheck results. Read-only.",
9619
9790
  {
9620
9791
  scan_results: z.string().describe("JSON string of FullScanResult from scan_group mlps3_precheck or scan_all"),
9621
- lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
9792
+ lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
9793
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
9622
9794
  },
9623
- async ({ scan_results, lang }) => {
9795
+ async ({ scan_results, lang, ai_summary }) => {
9624
9796
  try {
9625
9797
  const parsed = JSON.parse(scan_results);
9798
+ if (ai_summary) parsed.aiSummary = ai_summary;
9626
9799
  const report = generateMlps3Report(parsed, lang ?? "zh");
9627
9800
  return { content: [{ type: "text", text: report }] };
9628
9801
  } catch (err) {
@@ -9636,11 +9809,13 @@ function createServer(defaultRegion) {
9636
9809
  {
9637
9810
  scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
9638
9811
  history: z.string().optional().describe("JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts"),
9639
- lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
9812
+ lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
9813
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
9640
9814
  },
9641
- async ({ scan_results, history, lang }) => {
9815
+ async ({ scan_results, history, lang, ai_summary }) => {
9642
9816
  try {
9643
9817
  const parsed = JSON.parse(scan_results);
9818
+ if (ai_summary) parsed.aiSummary = ai_summary;
9644
9819
  const historyData = history ? JSON.parse(history) : void 0;
9645
9820
  const report = generateHtmlReport(parsed, historyData, lang ?? "zh");
9646
9821
  return { content: [{ type: "text", text: report }] };
@@ -9655,11 +9830,13 @@ function createServer(defaultRegion) {
9655
9830
  {
9656
9831
  scan_results: z.string().describe("JSON string of FullScanResult from scan_group mlps3_precheck or scan_all"),
9657
9832
  history: z.string().optional().describe("JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts"),
9658
- lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
9833
+ lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
9834
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
9659
9835
  },
9660
- async ({ scan_results, history, lang }) => {
9836
+ async ({ scan_results, history, lang, ai_summary }) => {
9661
9837
  try {
9662
9838
  const parsed = JSON.parse(scan_results);
9839
+ if (ai_summary) parsed.aiSummary = ai_summary;
9663
9840
  const historyData = history ? JSON.parse(history) : void 0;
9664
9841
  const report = generateMlps3HtmlReport(parsed, historyData, lang ?? "zh");
9665
9842
  return { content: [{ type: "text", text: report }] };
@@ -9668,16 +9845,36 @@ function createServer(defaultRegion) {
9668
9845
  }
9669
9846
  }
9670
9847
  );
9848
+ server.tool(
9849
+ "get_ai_summary_prompt",
9850
+ "Return a report-type-tailored prompt (with a grounded findings digest) that the CALLING AI should run to produce an AI security summary. Then pass the generated text back via the `ai_summary` parameter of the matching report tool (or scan_and_report). The server performs no LLM calls. Use this to make each summary specific to the report type (dashboard / security scan / HW Defense \u62A4\u7F51 / MLPS3 \u7B49\u4FDD).",
9851
+ {
9852
+ report_type: z.enum(["dashboard", "html", "hw_defense", "mlps3"]).describe("Target report type the summary is for: dashboard (overview), html (AWS security scan report), hw_defense (\u62A4\u7F51 attack-defense drill), mlps3 (\u7B49\u4FDD\u4E09\u7EA7 compliance)"),
9853
+ scan_results: z.string().describe("JSON string of FullScanResult from scan_all / scan_group"),
9854
+ lang: z.enum(["zh", "en"]).optional().describe("Summary language (default: zh)")
9855
+ },
9856
+ async ({ report_type, scan_results, lang }) => {
9857
+ try {
9858
+ const parsed = JSON.parse(scan_results);
9859
+ const prompt = buildAiSummaryPrompt(report_type, parsed, lang ?? "zh");
9860
+ return { content: [{ type: "text", text: prompt }] };
9861
+ } catch (err) {
9862
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
9863
+ }
9864
+ }
9865
+ );
9671
9866
  server.tool(
9672
9867
  "generate_hw_defense_report",
9673
9868
  "Generate an HTML report organized by HW Defense (\u62A4\u7F51) SOP checklist categories. Save as .html file.",
9674
9869
  {
9675
9870
  scan_results: z.string().describe("JSON string of FullScanResult from scan_group hw_defense or scan_all"),
9676
- lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
9871
+ lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
9872
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
9677
9873
  },
9678
- async ({ scan_results, lang }) => {
9874
+ async ({ scan_results, lang, ai_summary }) => {
9679
9875
  try {
9680
9876
  const parsed = JSON.parse(scan_results);
9877
+ if (ai_summary) parsed.aiSummary = ai_summary;
9681
9878
  const report = generateHwDefenseHtmlReport(parsed, lang ?? "zh");
9682
9879
  return { content: [{ type: "text", text: report }] };
9683
9880
  } catch (err) {
@@ -9806,11 +10003,13 @@ function createServer(defaultRegion) {
9806
10003
  "Saves scan results to local disk or S3 for dashboard display. Does not modify any AWS resources.",
9807
10004
  {
9808
10005
  scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
9809
- output_dir: z.string().optional().describe("Output directory (default: ~/.aws-security)")
10006
+ output_dir: z.string().optional().describe("Output directory (default: ~/.aws-security)"),
10007
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (from get_ai_summary_prompt with report_type=dashboard). Persisted into dashboard data and rendered on the Overview; omit to hide.")
9810
10008
  },
9811
- async ({ scan_results, output_dir }) => {
10009
+ async ({ scan_results, output_dir, ai_summary }) => {
9812
10010
  try {
9813
10011
  const parsed = JSON.parse(scan_results);
10012
+ if (ai_summary) parsed.aiSummary = ai_summary;
9814
10013
  const dataPath = saveResults(parsed, output_dir);
9815
10014
  return {
9816
10015
  content: [
@@ -9908,9 +10107,10 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
9908
10107
  role_name: z.string().optional().describe("IAM role name for cross-account scanning"),
9909
10108
  account_ids: z.array(z.string()).optional().describe("Filter to specific account IDs"),
9910
10109
  reports: z.array(z.enum(["html", "hw_defense", "mlps3", "markdown", "all"])).optional().describe("Report types to generate (default: all)"),
9911
- lang: z.enum(["zh", "en"]).optional().describe("Language: zh or en (default: zh)")
10110
+ lang: z.enum(["zh", "en"]).optional().describe("Language: zh or en (default: zh)"),
10111
+ ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered in reports + dashboard if present; omit to hide.")
9912
10112
  },
9913
- async ({ region, org_mode, role_name, account_ids, reports, lang }) => {
10113
+ async ({ region, org_mode, role_name, account_ids, reports, lang, ai_summary }) => {
9914
10114
  try {
9915
10115
  const r = region ?? defaultRegion;
9916
10116
  const l = lang ?? "zh";
@@ -9926,6 +10126,7 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
9926
10126
  } else {
9927
10127
  result = await runAllScanners(allScanners, r);
9928
10128
  }
10129
+ if (ai_summary) result.aiSummary = ai_summary;
9929
10130
  const baseDir = join2(homedir2(), ".aws-security", "reports", (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
9930
10131
  mkdirSync2(baseDir, { recursive: true });
9931
10132
  const savedFiles = [];