Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问许可证需确认审计通过

web-app-architecturesWeb 应用程序架构

Agent Skill

web-app-architectures 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

303

周安装

13

GitHub Stars

34

下载量

106
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:web-app-architectures(Web 应用程序架构)
来源仓库:https://github.com/farming-labs/fm-skills
仓库路径:skills/web-app-architectures
安装命令:
npx skills add https://github.com/farming-labs/fm-skills --skill web-app-architectures
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/farming-labs/fm-skills --skill web-app-architectures

简介

用于查找、检索和筛选相关信息,支持关键词或任务场景快速定位候选结果。

  • 适合在需要根据来源线索定位技术方案时使用,如架构选型或模式参考。
  • 安装命令:npx skills add https://github.com/farming-labs/fm-skills --skill web-app-architectures。
  • 当前维护状态未知,建议核对仓库活跃度与权限边界后再使用。
  • 使用前建议确认是否会触发联网、命令执行或文件读写操作。

SKILL.md

Web Application Architectures

Overview

Web applications fall into three main architectural patterns, each with distinct characteristics for navigation, state management, and user experience.

Multi Page Application (MPA)

The traditional web model - each navigation triggers a full page request to the server.

How It Works

User clicks link → Browser requests new HTML → Server renders full page → Browser loads entire page

Characteristics

AspectBehavior
NavigationFull page reload on each route change
Initial LoadFast - only current page HTML
Subsequent NavigationSlower - full round trip
StateLost on navigation (unless stored in cookies/sessions)
SEOExcellent - each page is a complete HTML document
ServerHandles routing and rendering

When to Use MPA

  • Content-heavy sites (blogs, documentation, news)
  • SEO is critical
  • Users have slow connections (less JS to download)
  • Simple interactivity requirements
  • Progressive enhancement is important

Example Flow

/home → Server renders home.html
/about → Server renders about.html (full page reload)
/products/123 → Server renders product.html (full page reload)

Single Page Application (SPA)

The modern app model - one HTML shell, JavaScript handles all routing and rendering.

How It Works

Initial: Browser loads shell HTML + JS bundle
Navigation: JS intercepts clicks → Updates URL → Renders new view (no server request for HTML)
Data: Fetch API calls for JSON data only

Characteristics

AspectBehavior
NavigationInstant (no page reload)
Initial LoadSlower - must download JS bundle
Subsequent NavigationFast - only fetch data, render client-side
StatePreserved across navigation
SEOChallenging - requires additional strategies
ServerAPI endpoints only (JSON responses)

The SPA Tradeoffs

Advantages:

  • App-like user experience
  • Smooth transitions and animations
  • Persistent UI state (music players, forms, etc.)
  • Reduced server load after initial load

Disadvantages:

  • Large initial JavaScript bundle
  • SEO requires workarounds (SSR, prerendering)
  • Memory management complexity
  • Back button/deep linking need explicit handling
  • Time to Interactive (TTI) can be slow

Example Flow

/home → JS renders Home component
/about → JS renders About component (no server request)
/products/123 → JS fetches product data → Renders Product component

Hybrid Architectures

Modern meta-frameworks blur the line between SPA and MPA.

Multi Page App with Islands

MPA foundation with interactive "islands" of JavaScript.

Server renders full HTML → JS hydrates only interactive components

Examples: Astro, Fresh (Deno)

SPA with Server-Side Rendering

SPA that pre-renders on server for initial load.

First request: Server renders full HTML + hydrates to SPA
Subsequent: Client-side navigation (SPA behavior)

Examples: Next.js, Nuxt, SvelteKit, Remix

Streaming/Progressive Rendering

Server streams HTML as it becomes available.

Server starts sending HTML → Browser renders progressively → JS hydrates as content arrives

Architecture Decision Matrix

RequirementRecommended
Content site, SEO criticalMPA or Hybrid with SSR
Dashboard, authenticated appSPA or Hybrid
E-commerce (SEO + interactivity)Hybrid with SSR
Minimal JS, fast initial loadMPA with Islands
Rich interactions, app-like UXSPA or Hybrid
Limited team, simple stackMPA
Offline support neededSPA with Service Workers

Key Concepts to Understand

Client-Side Routing

SPAs intercept navigation using the History API:

// Instead of browser navigation
window.history.pushState({}, '', '/new-route');
// App renders new view without page reload

Code Splitting

Breaking JS bundle into smaller chunks loaded on demand:

Initial: core.js (router, framework)
/dashboard: dashboard.chunk.js (loaded when needed)
/settings: settings.chunk.js (loaded when needed)

State Persistence

SPAs maintain state in memory; MPAs must serialize state:

SPA: Component state survives navigation
MPA: State stored in URL params, cookies, localStorage, or server sessions

Deep Dive: Understanding the Fundamentals

The Browser's Request-Response Cycle

To truly understand SPA vs MPA, you must understand how browsers work at a fundamental level.

Traditional Web (MPA) - How the browser was designed:

1. USER ACTION: Click a link <a href="/about">

2. BROWSER BEHAVIOR:
   - Stops current page execution
   - Clears current DOM
   - Sends HTTP GET request to server
   - Shows loading indicator

3. SERVER RESPONSE:
   - Server receives request for "/about"
   - Server executes backend code (PHP, Ruby, Python, Node)
   - Server queries database if needed
   - Server generates complete HTML document
   - Server sends HTML back with Content-Type: text/html

4. BROWSER RENDERING:
   - Browser receives HTML
   - Parses HTML, builds DOM tree
   - Discovers CSS/JS, fetches them
   - Renders page to screen
   - Page is interactive

This is how the web worked from 1991 until ~2010. Every navigation = full cycle.

SPA - Hijacking the browser's default behavior:

SPAs work by *preventing* the browser's natural behavior:

// The core SPA trick: prevent default browser navigation
document.addEventListener('click', (event) => {
  const link = event.target.closest('a');

  if (link && link.href.startsWith(window.location.origin)) {
    // STOP the browser from doing its normal thing
    event.preventDefault();

    // Instead, WE handle navigation with JavaScript
    const path = new URL(link.href).pathname;

    // Update the URL bar (without page reload)
    window.history.pushState({}, '', path);

    // Render the new "page" ourselves
    renderRoute(path);
  }
});

This is why SPAs feel "app-like" - the page never actually reloads.

Why Does SPA Navigation Feel Instant?

MPA Navigation Time Breakdown:

DNS Lookup:           ~20-100ms (if not cached)
TCP Connection:       ~50-200ms (round trip)
TLS Handshake:        ~50-150ms (HTTPS)
Server Processing:    ~50-500ms (database, rendering)
Response Transfer:    ~50-200ms (HTML size dependent)
Browser Parsing:      ~50-100ms
CSS/JS Fetch:         ~100-300ms (even if cached, verification)
Render:               ~50-100ms
─────────────────────────────────
TOTAL:                ~400-1600ms minimum

SPA Navigation Time Breakdown:

JavaScript Execution: ~5-50ms (route matching, component rendering)
DOM Update:           ~5-20ms (virtual DOM diff, real DOM update)
─────────────────────────────────
TOTAL:                ~10-70ms

Data Fetch (if needed): +100-500ms (but can show skeleton immediately)

The SPA is 10-100x faster for navigation because it skips the entire HTTP round-trip.

The Cost of SPA Speed: Initial Load

But there's a tradeoff. Before ANY navigation can happen, the SPA must:

1. Download the HTML shell (small, ~5KB)
2. Download the JavaScript bundle (often 200KB-2MB+)
3. Parse the JavaScript (CPU intensive)
4. Execute the JavaScript (initialize framework, router, stores)
5. Render the initial route

MPA First Page:  ~400-1600ms to content
SPA First Page:  ~800-3000ms to content (must wait for JS)

This is why "Time to Interactive" (TTI) is a problem for SPAs.

Understanding Browser APIs That Enable SPAs

The History API (HTML5, 2010):

Before HTML5, the only way to change the URL was to trigger a page load. The History API changed everything:

// Push a new entry to browser history (URL changes, no reload)
history.pushState(stateObject, title, '/new-url');

// Replace current entry (URL changes, no reload, no new history entry)
history.replaceState(stateObject, title, '/new-url');

// Listen for back/forward button clicks
window.addEventListener('popstate', (event) => {
  // event.state contains the stateObject from pushState
  // Your app must now render the appropriate content
  renderRoute(window.location.pathname);
});

Without the History API, SPAs would only work with hash URLs (/#/about).

The Fetch API:

SPAs separate data from presentation. Instead of getting HTML, they get JSON:

// MPA: Server returns complete HTML page
// <html><body><h1>Product: Shoes</h1><p>Price: $99</p>...</body></html>

// SPA: Server returns just data
// {"name": "Shoes", "price": 99, "description": "..."}

// SPA renders data into components
const response = await fetch('/api/products/123');
const product = await response.json();
renderProduct(product);  // JavaScript creates the HTML

Memory and State: The Fundamental Difference

MPA State Management:

Page Load → JavaScript runs → State created in memory
Navigation → Page destroyed → ALL MEMORY FREED → New page loads → Fresh state

Each page is a clean slate. No memory leaks possible (page is destroyed).
State that must persist: cookies, localStorage, URL parameters, server sessions.

SPA State Management:

App Load → JavaScript runs → State created in memory
Navigation → State PERSISTS → Components mount/unmount → State grows
... hours later ...
Navigation → State still in memory → Potential memory leaks

The app NEVER gets a clean slate. Memory management is YOUR responsibility.

This is why SPAs can have memory leaks and why tools like React DevTools have memory profilers.

The Document Object Model (DOM) and Why It Matters

The DOM is a tree structure representing your HTML:

document
└── html
    ├── head
    │   ├── title
    │   └── link (CSS)
    └── body
        ├── header
        │   └── nav
        ├── main
        │   ├── h1
        │   └── p
        └── footer

MPA DOM Lifecycle:

1. Browser builds DOM from HTML
2. User interacts with page
3. Navigation → ENTIRE DOM DESTROYED
4. New DOM built from new HTML

SPA DOM Lifecycle:

1. Browser builds initial DOM (shell only)
2. JavaScript modifies DOM to add content
3. Navigation → JavaScript MODIFIES DOM (adds/removes nodes)
4. DOM is never destroyed, only mutated

SPAs must be careful about DOM manipulation efficiency. This is why frameworks use:

  • Virtual DOM (React)
  • Compiler-based reactivity (Svelte)
  • Fine-grained reactivity (Solid)

HTTP/2 and Why It Changed the Equation

HTTP/1.1 had a major limitation: one request at a time per connection (or 6 parallel connections max).

HTTP/1.1 MPA:
Request 1: HTML ────────────────►
Request 2: CSS  ─────────────────► (waits or new connection)
Request 3: JS   ──────────────────► (waits or new connection)
Request 4: Image ───────────────────► (max 6 parallel)

HTTP/2 introduced multiplexing: unlimited parallel requests on one connection.

HTTP/2 MPA:
Request 1: HTML  ───►
Request 2: CSS   ───►
Request 3: JS    ───►  All sent simultaneously!
Request 4: Image ───►

This made MPAs much faster and reduced the SPA advantage for initial load.

Server Load: Understanding the Scale Implications

MPA Server Load:

Each request:
- Parse request
- Route to handler
- Query database
- Execute template engine
- Generate HTML string
- Send response

CPU: High (template rendering per request)
Memory: Moderate (per-request state)
Bandwidth: High (sending full HTML each time)

SPA Server Load:

Initial request:
- Serve static HTML file (cached by CDN)
- Serve static JS bundle (cached by CDN)

API requests:
- Parse request
- Query database
- Return JSON (smaller than HTML)

CPU: Lower (no template rendering)
Memory: Lower (stateless API)
Bandwidth: Lower (JSON smaller than HTML)

SPAs can scale more easily because static assets are cached at the edge (CDN).

SEO: Why Crawlers Struggle with SPAs

Google's crawler has two phases:

Phase 1: Crawling (fast, cheap)
- HTTP request to URL
- Receive HTML response
- Extract links for further crawling
- Index the text content

Phase 2: Rendering (slow, expensive)
- Load page in headless Chrome
- Execute JavaScript
- Wait for content to appear
- Index the rendered content

MPA Crawling:

GET /products/shoes → Receives complete HTML with all content
                    → Indexed immediately in Phase 1

SPA Crawling:

GET /products/shoes → Receives: <div id="root"></div>
                    → No content to index in Phase 1
                    → Must wait for Phase 2 (delayed, not guaranteed)

Google DOES execute JavaScript, but:

  • It's delayed (crawl budget prioritization)
  • It's expensive (limited render budget)
  • Some pages may never get rendered
  • Dynamic content may timeout

This is why SSR exists: serve complete HTML to crawlers, hydrate to SPA for users.

Progressive Enhancement: The MPA Philosophy

MPAs embrace progressive enhancement:

Layer 1: HTML (content, accessible to all)
       ↓
Layer 2: CSS (styling, enhances presentation)
       ↓
Layer 3: JavaScript (interactivity, enhances experience)

Each layer is optional. The page works without JS.

SPAs invert this:

Layer 1: JavaScript (required for anything to work)
       ↓
Layer 2: Content rendered by JavaScript
       ↓
Layer 3: Everything depends on JS

If JS fails (network error, parsing error, old browser), SPA shows nothing.

When to Choose What: The Real Decision Framework

Choose MPA when:

  • Content is the product (blogs, news, documentation)
  • SEO is non-negotiable
  • Users may have JS disabled
  • Team is small/unfamiliar with frontend complexity
  • Server-side languages are the team's strength

Choose SPA when:

  • It's an "application" not a "website" (dashboards, tools)
  • Users are authenticated (SEO irrelevant)
  • Rich interactivity is core to the experience
  • Offline support is needed
  • Real-time updates are frequent

Choose Hybrid when:

  • You need both SEO and interactivity (e-commerce)
  • Different parts of the site have different needs
  • Performance is critical for both initial and subsequent loads
  • You want the best of both worlds (most modern apps)

For Framework Authors: Building Web Architectures

Implementation Note: The patterns and code examples below represent one proven approach to building these systems. There are many valid ways to implement web architectures—the direction shown here is based on patterns used by popular frameworks like React Router, Vue Router, and Astro. Use these as a starting point and adapt based on your framework's specific requirements, constraints, and design philosophy.

Implementing a Minimal SPA Router

If you're building a framework, here's how to implement client-side routing:

// MINIMAL SPA ROUTER IMPLEMENTATION

class Router {
  constructor() {
    this.routes = new Map();
    this.currentRoute = null;
    this.outlet = null;

    // Listen for browser back/forward
    window.addEventListener('popstate', () => this.handleNavigation());

    // Intercept link clicks
    document.addEventListener('click', (e) => {
      const link = e.target.closest('a');
      if (link && link.href.startsWith(location.origin)) {
        e.preventDefault();
        this.navigate(link.pathname);
      }
    });
  }

  // Register a route with pattern and handler
  route(pattern, handler) {
    // Convert /users/:id to regex with named groups
    const paramNames = [];
    const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {
      paramNames.push(name);
      return '([^/]+)';
    });

    this.routes.set(new RegExp(`^${regexPattern}$`), {
      handler,
      paramNames,
    });
  }

  // Programmatic navigation
  navigate(path, { replace = false } = {}) {
    if (replace) {
      history.replaceState({ path }, '', path);
    } else {
      history.pushState({ path }, '', path);
    }
    this.handleNavigation();
  }

  // Match current URL and render
  async handleNavigation() {
    const path = location.pathname;

    for (const [regex, { handler, paramNames }] of this.routes) {
      const match = path.match(regex);
      if (match) {
        // Extract route params
        const params = {};
        paramNames.forEach((name, i) => {
          params[name] = match[i + 1];
        });

        // Call route handler
        const content = await handler({ params, path });

        // Render to outlet
        if (this.outlet) {
          this.outlet.innerHTML = '';
          this.outlet.appendChild(content);
        }
        return;
      }
    }

    // 404 handling
    console.error('No route matched:', path);
  }

  // Set render target
  mount(element) {
    this.outlet = element;
    this.handleNavigation();
  }
}

// Usage
const router = new Router();
router.route('/', () => createElement('h1', 'Home'));
router.route('/users/:id', ({ params }) =>
  createElement('h1', `User ${params.id}`)
);
router.mount(document.getElementById('app'));

Building a File-Based Router (Build Time)

Meta-frameworks use file system as routing config:

// FILE-BASED ROUTING IMPLEMENTATION (build tool)

import { glob } from 'glob';
import path from 'path';

function generateRoutes(pagesDir) {
  // Find all page files
  const files = glob.sync('**/*.{js,jsx,ts,tsx}', { cwd: pagesDir });

  const routes = files.map(file => {
    // Remove extension
    let route = file.replace(/\.(js|jsx|ts|tsx)$/, '');

    // Handle index files
    route = route.replace(/\/index$/, '') || '/';

    // Convert [param] to :param
    route = route.replace(/\[([^\]]+)\]/g, ':$1');

    // Convert [...slug] to *
    route = route.replace(/\[\.\.\.([^\]]+)\]/g, '*');

    return {
      path: '/' + route,
      component: path.join(pagesDir, file),
      // Generate regex for matching
      regex: pathToRegex('/' + route),
    };
  });

  // Sort routes: static before dynamic, specific before catch-all
  return routes.sort((a, b) => {
    const aScore = routeScore(a.path);
    const bScore = routeScore(b.path);
    return bScore - aScore;
  });
}

function routeScore(path) {
  let score = 0;
  // Static segments are worth more
  const segments = path.split('/').filter(Boolean);
  for (const seg of segments) {
    if (seg.startsWith(':')) score += 1;      // Dynamic: low
    else if (seg === '*') score += 0;          // Catch-all: lowest
    else score += 10;                          // Static: high
  }
  return score;
}

// Generate route manifest at build time
const routes = generateRoutes('./src/pages');
writeFileSync('./dist/routes.json', JSON.stringify(routes, null, 2));

Implementing Nested Layouts

Layouts require component composition:

// NESTED LAYOUT SYSTEM

// Layout discovery at build time
function buildLayoutTree(routePath, pagesDir) {
  const segments = routePath.split('/').filter(Boolean);
  const layouts = [];

  // Walk up the tree finding layouts
  let currentPath = pagesDir;

  // Check root layout
  if (existsSync(path.join(currentPath, '_layout.tsx'))) {
    layouts.push(path.join(currentPath, '_layout.tsx'));
  }

  // Check each segment
  for (const segment of segments) {
    currentPath = path.join(currentPath, segment);
    if (existsSync(path.join(currentPath, '_layout.tsx'))) {
      layouts.push(path.join(currentPath, '_layout.tsx'));
    }
  }

  return layouts;  // Ordered from root to leaf
}

// Runtime rendering with layouts
async function renderWithLayouts(layouts, pageComponent, props) {
  // Start from innermost (page) and wrap outward
  let content = await pageComponent(props);

  // Wrap with each layout, inside-out
  for (let i = layouts.length - 1; i >= 0; i--) {
    const Layout = await import(layouts[i]);
    content = await Layout.default({ children: content, ...props });
  }

  return content;
}

State Preservation Across Navigation

SPAs must preserve state during navigation:

// STATE PRESERVATION STRATEGIES

class NavigationStateManager {
  constructor() {
    this.componentStates = new Map();
    this.scrollPositions = new Map();
  }

  // Save state before navigation
  saveState(routeKey, componentTree) {
    // Serialize component state
    const state = this.extractState(componentTree);
    this.componentStates.set(routeKey, state);

    // Save scroll position
    this.scrollPositions.set(routeKey, {
      x: window.scrollX,
      y: window.scrollY,
    });
  }

  // Restore state after navigation
  restoreState(routeKey) {
    const state = this.componentStates.get(routeKey);
    const scroll = this.scrollPositions.get(routeKey);

    return { state, scroll };
  }

  // Extract serializable state from component tree
  extractState(tree) {
    // Framework-specific: walk component tree
    // Extract useState values, refs, etc.
    // Must handle circular references
  }
}

// Integration with router
router.beforeNavigate((from, to) => {
  stateManager.saveState(from.path, currentComponentTree);
});

router.afterNavigate((to) => {
  const { state, scroll } = stateManager.restoreState(to.path);
  if (state) {
    restoreComponentState(state);
  }
  if (scroll) {
    window.scrollTo(scroll.x, scroll.y);
  }
});

Memory Management for Long-Running SPAs

// MEMORY LEAK PREVENTION

class ComponentRegistry {
  constructor() {
    this.mounted = new Set();
    this.cleanupFns = new Map();
  }

  mount(component, cleanup) {
    this.mounted.add(component);
    if (cleanup) {
      this.cleanupFns.set(component, cleanup);
    }
  }

  unmount(component) {
    // Run cleanup functions
    const cleanup = this.cleanupFns.get(component);
    if (cleanup) {
      cleanup();
      this.cleanupFns.delete(component);
    }

    this.mounted.delete(component);
  }

  // Called on route change
  unmountRoute(routeComponents) {
    for (const component of routeComponents) {
      this.unmount(component);
    }

    // Force garbage collection hint
    if (global.gc) global.gc();
  }
}

// Event listener cleanup pattern
class EventManager {
  constructor() {
    this.listeners = new WeakMap();
  }

  addListener(element, event, handler) {
    element.addEventListener(event, handler);

    // Track for cleanup
    if (!this.listeners.has(element)) {
      this.listeners.set(element, []);
    }
    this.listeners.get(element).push({ event, handler });
  }

  removeAllListeners(element) {
    const handlers = this.listeners.get(element);
    if (handlers) {
      for (const { event, handler } of handlers) {
        element.removeEventListener(event, handler);
      }
      this.listeners.delete(element);
    }
  }
}

Building MPA with Partial Hydration

// PARTIAL HYDRATION IMPLEMENTATION

// 1. Mark interactive components at build time
// <Button client:load>Click me</Button>

// 2. Extract islands during SSR
function extractIslands(html, components) {
  const islands = [];

  // Find island markers in HTML
  const regex = /<island-(\w+) props="([^"]+)">/g;
  let match;

  while ((match = regex.exec(html)) !== null) {
    islands.push({
      id: match[1],
      props: JSON.parse(decodeURIComponent(match[2])),
      component: components[match[1]],
    });
  }

  return islands;
}

// 3. Hydrate only islands on client
function hydrateIslands(islands) {
  for (const island of islands) {
    const element = document.querySelector(`[data-island="${island.id}"]`);
    if (element) {
      // Load component code
      const Component = await import(island.component);

      // Hydrate this specific element
      hydrateRoot(element, <Component {...island.props} />);
    }
  }
}

// 4. Island web component wrapper
class IslandElement extends HTMLElement {
  async connectedCallback() {
    // Defer hydration based on strategy
    const strategy = this.getAttribute('client');

    switch (strategy) {
      case 'load':
        await this.hydrate();
        break;
      case 'idle':
        requestIdleCallback(() => this.hydrate());
        break;
      case 'visible':
        const observer = new IntersectionObserver(async ([entry]) => {
          if (entry.isIntersecting) {
            observer.disconnect();
            await this.hydrate();
          }
        });
        observer.observe(this);
        break;
    }
  }

  async hydrate() {
    const component = this.getAttribute('component');
    const props = JSON.parse(this.getAttribute('props') || '{}');

    const Component = await import(`/components/${component}.js`);
    hydrateRoot(this, createElement(Component.default, props));
  }
}

customElements.define('island-component', IslandElement);

Related Skills

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.41%
按下载量换算36

Claude

29.77%
按下载量换算32

Cursor

20.99%
按下载量换算22

Gemini CLI

9.23%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills