diff --git a/404.html b/404.html index 46f0eab..45d4835 100644 --- a/404.html +++ b/404.html @@ -3,9 +3,9 @@ -CmdForge - - +CmdForge + + diff --git a/architecture/index.html b/architecture/index.html index 9a10703..8f1be10 100644 --- a/architecture/index.html +++ b/architecture/index.html @@ -3,17 +3,17 @@ -CmdForge Architecture | CmdForge - - +CmdForge Architecture | CmdForge + + -
Skip to main content

CmdForge Architecture

+

CmdForge Architecture

Module Structure

-
src/cmdforge/
├── cli/ # CLI commands
│ ├── __init__.py
│ ├── tool_commands.py # list, create, edit, delete
│ ├── provider_commands.py # providers management
│ ├── registry_commands.py # publish, install
│ └── collections_commands.py # collections list, info, install
├── registry/ # Registry API
│ ├── app.py # Flask API endpoints
│ ├── db.py # SQLite schema and queries
│ ├── sync.py # Git repo sync
│ └── rate_limit.py
├── web/ # Web UI (cmdforge.brrd.tech)
│ ├── app.py # Flask app factory
│ ├── routes.py # Page routes
│ ├── auth.py # User authentication
│ ├── forum/ # Forum feature
│ ├── templates/ # Jinja2 templates
│ └── static/ # CSS, JS
├── gui/ # Desktop GUI (PySide6)
│ ├── __init__.py # Entry point, run_gui()
│ ├── main_window.py # Main window with sidebar
│ ├── styles.py # QSS stylesheet
│ ├── pages/ # Application pages
│ │ ├── tools_page.py # Tool list and details
│ │ ├── tool_builder_page.py # Create/edit tools
│ │ ├── registry_page.py # Browse/install tools
│ │ └── providers_page.py # Provider management
│ └── dialogs/ # Modal dialogs
│ ├── step_dialog.py # Prompt/code step editors
│ ├── argument_dialog.py
│ ├── provider_dialog.py
│ ├── connect_dialog.py # Registry connect
│ └── publish_dialog.py
├── tool.py # Tool dataclass and loading
├── runner.py # Tool execution engine
└── providers.py # AI provider abstraction
+
src/cmdforge/
├── cli/ # CLI commands
│ ├── __init__.py
│ ├── tool_commands.py # list, create, edit, delete
│ ├── provider_commands.py # providers management
│ ├── registry_commands.py # publish, install
│ └── collections_commands.py # collections create, show, add, remove, delete, publish, status
├── registry/ # Registry API
│ ├── app.py # Flask API endpoints
│ ├── db.py # SQLite schema and queries
│ ├── embeddings.py # Semantic search (Ollama embeddings)
│ ├── settings.py # Admin-configurable settings
│ ├── sync.py # Git repo sync
│ └── rate_limit.py
├── web/ # Web UI (cmdforge.brrd.tech)
│ ├── app.py # Flask app factory
│ ├── routes.py # Page routes
│ ├── auth.py # User authentication
│ ├── forum/ # Forum feature
│ ├── templates/ # Jinja2 templates
│ └── static/ # CSS, JS
├── gui/ # Desktop GUI (PySide6)
│ ├── __init__.py # Entry point, run_gui()
│ ├── main_window.py # Main window with sidebar
│ ├── styles.py # QSS stylesheet
│ ├── pages/ # Application pages
│ │ ├── tools_page.py # Tool list and details
│ │ ├── tool_builder_page.py # Create/edit tools
│ │ ├── registry_page.py # Browse/install tools
│ │ ├── collections_page.py # Local and registry collections
│ │ └── providers_page.py # Provider management
│ └── dialogs/ # Modal dialogs
│ ├── step_dialog.py # Prompt/code step editors
│ ├── argument_dialog.py
│ ├── provider_dialog.py
│ ├── connect_dialog.py # Registry connect
│ └── publish_dialog.py
├── tool.py # Tool dataclass and loading
├── collection.py # Collection dataclass and tool resolution
├── runner.py # Tool execution engine
└── providers.py # AI provider abstraction

Data Flow

CLI Tool Execution

User Input (stdin)


┌─────────────┐
│ runner.py │ ──── Loads tool from ~/.cmdforge/<name>/config.yaml
└─────────────┘


┌─────────────┐
│ Steps │
│ (prompt/ │ ──── For prompt steps, calls providers.py
│ code) │ ──── For code steps, exec() Python
└─────────────┘


Output (stdout)
@@ -26,6 +26,10 @@
@dataclass
class ToolSource:
type: str # "original", "imported", "forked"
license: str
url: str
author: str
original_tool: str # e.g., "fabric/patterns/extract_wisdom"

Provider (providers.py)

@dataclass
class Provider:
name: str # e.g., "opencode-pickle"
command: str # e.g., "$HOME/.opencode/bin/opencode run --model ..."
description: str
+

Collection (collection.py)

+
@dataclass
class Collection:
name: str # Unique identifier (kebab-case)
display_name: str # Human-readable name
description: str
maintainer: str
tools: List[str] # Tool references (local or owner/name)
pinned: Dict[str, str] # Version constraints
tags: List[str]
published: bool # Whether published to registry
registry_name: str # Name in registry (if different)
pending_approval: bool # Awaiting moderation
pending_tools: List[str] # Tools awaiting approval
+

ToolResolutionResult (collection.py)

+
@dataclass
class ToolResolutionResult:
registry_refs: List[str] # Transformed owner/name refs
transformed_pinned: Dict[str, str] # Pinned with transformed keys
local_unpublished: List[str] # Local tools not in registry
local_published: List[tuple] # (name, status, has_approved) tuples
visibility_issues: List[tuple] # (name, visibility) for non-public
registry_tool_issues: List[tuple] # (ref, reason) for invalid refs

Error Handling

The runner provides detailed error messages for debugging:

Code Step Errors

@@ -52,7 +56,10 @@

SQLite schema for published tools:

CREATE TABLE tools (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
category TEXT DEFAULT 'Other',
config_yaml TEXT NOT NULL, -- Full tool YAML
source TEXT, -- Deprecated (type only)
source_url TEXT, -- Deprecated
source_json TEXT, -- Full ToolSource as JSON
published_at TIMESTAMP,
downloads INTEGER DEFAULT 0,
owner_id INTEGER REFERENCES users(id)
);

The source_json column stores the complete ToolSource object, preserving all attribution fields when tools are published.

+

Semantic Search Embeddings

+
CREATE TABLE tool_embeddings (
tool_id INTEGER PRIMARY KEY REFERENCES tools(id) ON DELETE CASCADE,
embedding BLOB NOT NULL, -- Packed float32 vector (768 dims × 4 bytes = 3KB)
dimensions INTEGER NOT NULL, -- Actual vector dimensions
model TEXT NOT NULL, -- Model used (e.g., "nomic-embed-text")
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
+

Embeddings are generated via Ollama (AI-Server, 192.168.0.186:11434) using the nomic-embed-text model. Only public+approved tools are embedded. Vectors are stored as packed binary blobs and compared using pure Python cosine similarity at query time (~100 tools = sub-ms).

Configuration Files

-
FileLocationPurpose
Tool config~/.cmdforge/<name>/config.yamlTool definition
Providers~/.cmdforge/providers.yamlAI provider commands
Main config~/.cmdforge/config.yamlRegistry URL, client ID
+
FileLocationPurpose
Tool config~/.cmdforge/<name>/config.yamlTool definition
Providers~/.cmdforge/providers.yamlAI provider commands
Main config~/.cmdforge/config.yamlRegistry URL, client ID
Collections~/.cmdforge/collections/<name>.yamlLocal collection definitions
\ No newline at end of file diff --git a/assets/css/styles.37cb0314.css b/assets/css/styles.37cb0314.css deleted file mode 100644 index 16f8566..0000000 --- a/assets/css/styles.37cb0314.css +++ /dev/null @@ -1 +0,0 @@ -.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#e94560;--ifm-color-primary-dark:#e52a4a;--ifm-color-primary-darker:#df1f40;--ifm-color-primary-darkest:#b81935;--ifm-color-primary-light:#ed6076;--ifm-color-primary-lighter:#ef6b80;--ifm-color-primary-lightest:#f4919f;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_uzNF .wordWrapButtonIcon_b1P5{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.dropdown__link--active,.dropdown__link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.docCardListItem_W1sv>*,.navbar__logo img,body,html{height:100%}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:1rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#e94560;--ifm-color-primary-dark:#e52a4a;--ifm-color-primary-darker:#df1f40;--ifm-color-primary-darkest:#b81935;--ifm-color-primary-light:#ed6076;--ifm-color-primary-lighter:#ef6b80;--ifm-color-primary-lightest:#f4919f;--ifm-background-color:#1a1a2e;--ifm-background-surface-color:#16213e;--docusaurus-highlighted-code-line-bg:#0000004d}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#__docusaurus-base-url-issue-banner-container,.docSidebarContainer_YfHR,.navbarSearchContainer_Bca1:empty,.sidebarLogo_isFc,.themedComponent_mlkZ,.toggleIcon_g3eP,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;-webkit-text-decoration:underline;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}[data-theme-choice=dark] .darkToggleIcon_wfgR,[data-theme-choice=light] .lightToggleIcon_pyhR,[data-theme-choice=system] .systemToggleIcon_QzmC,[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.categoryLinkLabel_W154,.linkLabel_WmDU{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical}.iconExternalLink_nPIU{margin-left:.3rem}.dropdownNavbarItemMobile_J0Sd{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.buttonGroup_M5ko button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.navbar__items--right>:last-child{padding-right:0}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.linkLabel_WmDU{line-clamp:2;-webkit-line-clamp:2}.categoryLink_byQd{overflow:hidden}.menu__link--sublist-caret:after{margin-left:var(--ifm-menu-link-padding-vertical)}.categoryLinkLabel_W154{flex:1;line-clamp:2;-webkit-line-clamp:2}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.anchorTargetStickyNavbar_Vzrq{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorTargetHideOnScrollNavbar_vjPI{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.docCardListItem_W1sv{margin-bottom:2rem}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:line-count;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(line-count);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_Vdqa{opacity:1!important}.copyButtonIcons_IEyt{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_TrPX,.copyButtonSuccessIcon_cVMy{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_cVMy{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_Vdqa .copyButtonIcon_TrPX{opacity:0;transform:scale(.33)}.copyButtonCopied_Vdqa .copyButtonSuccessIcon_cVMy{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_b1P5{height:1.2rem;width:1.2rem}.buttonGroup_M5ko{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_M5ko button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_M5ko button:focus-visible,.buttonGroup_M5ko button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_M5ko button{opacity:.4}.codeBlockContent_QJqH{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_OeMC{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlockTitle_OeMC+.codeBlockContent_QJqH .codeBlock_a8dz{border-top-left-radius:0;border-top-right-radius:0}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;fill:var(--ifm-alert-foreground-color);height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.navbarSearchContainer_Bca1{padding:0 var(--ifm-navbar-item-padding-horizontal)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block;width:max-content}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.docItemContainer_F8PC{padding:0 .3rem}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.noPrint_WFHX,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/css/styles.6095798e.css b/assets/css/styles.6095798e.css new file mode 100644 index 0000000..6cf70f3 --- /dev/null +++ b/assets/css/styles.6095798e.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#e94560;--ifm-color-primary-dark:#e52a4a;--ifm-color-primary-darker:#df1f40;--ifm-color-primary-darkest:#b81935;--ifm-color-primary-light:#ed6076;--ifm-color-primary-lighter:#ef6b80;--ifm-color-primary-lightest:#f4919f;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_uzNF .wordWrapButtonIcon_b1P5{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.dropdown__link--active,.dropdown__link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:1rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#e94560;--ifm-color-primary-dark:#e52a4a;--ifm-color-primary-darker:#df1f40;--ifm-color-primary-darkest:#b81935;--ifm-color-primary-light:#ed6076;--ifm-color-primary-lighter:#ef6b80;--ifm-color-primary-lightest:#f4919f;--ifm-background-color:#1a1a2e;--ifm-background-surface-color:#16213e;--docusaurus-highlighted-code-line-bg:#0000004d}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}#__docusaurus-base-url-issue-banner-container,.docSidebarContainer_YfHR,.navbarSearchContainer_Bca1:empty,.sidebarLogo_isFc,.themedComponent_mlkZ,.toggleIcon_g3eP,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;-webkit-text-decoration:underline;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}[data-theme-choice=dark] .darkToggleIcon_wfgR,[data-theme-choice=light] .lightToggleIcon_pyhR,[data-theme-choice=system] .systemToggleIcon_QzmC,[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.categoryLinkLabel_W154,.linkLabel_WmDU{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical}.iconExternalLink_nPIU{margin-left:.3rem}.dropdownNavbarItemMobile_J0Sd{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.buttonGroup_M5ko button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.navbar__items--right>:last-child{padding-right:0}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.linkLabel_WmDU{line-clamp:2;-webkit-line-clamp:2}.categoryLink_byQd{overflow:hidden}.menu__link--sublist-caret:after{margin-left:var(--ifm-menu-link-padding-vertical)}.categoryLinkLabel_W154{flex:1;line-clamp:2;-webkit-line-clamp:2}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.anchorTargetStickyNavbar_Vzrq{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorTargetHideOnScrollNavbar_vjPI{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:line-count;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(line-count);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_Vdqa{opacity:1!important}.copyButtonIcons_IEyt{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_TrPX,.copyButtonSuccessIcon_cVMy{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_cVMy{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_Vdqa .copyButtonIcon_TrPX{opacity:0;transform:scale(.33)}.copyButtonCopied_Vdqa .copyButtonSuccessIcon_cVMy{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_b1P5{height:1.2rem;width:1.2rem}.buttonGroup_M5ko{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup_M5ko button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup_M5ko button:focus-visible,.buttonGroup_M5ko button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup_M5ko button{opacity:.4}.codeBlockContent_QJqH{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_OeMC{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlockTitle_OeMC+.codeBlockContent_QJqH .codeBlock_a8dz{border-top-left-radius:0;border-top-right-radius:0}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;fill:var(--ifm-alert-foreground-color);height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.navbarSearchContainer_Bca1{padding:0 var(--ifm-navbar-item-padding-horizontal)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block;width:max-content}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.docItemContainer_F8PC{padding:0 .3rem}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.noPrint_WFHX,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/js/0330220f.41bc8204.js b/assets/js/0330220f.41bc8204.js deleted file mode 100644 index 1fc85de..0000000 --- a/assets/js/0330220f.41bc8204.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[203],{1154(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>a});const s=JSON.parse('{"id":"reference/meta-tools","title":"Meta-Tools: Tools That Call Other Tools","description":"Meta-tools are CmdForge tools that can invoke other tools as steps in their workflow. This enables powerful composition and reuse of existing tools.","source":"@site/docs/reference/meta-tools.md","sourceDirName":"reference","slug":"/reference/meta-tools","permalink":"/rob/CmdForge/reference/meta-tools","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_label":"Meta-Tools","sidebar_position":2,"format":"md"},"sidebar":"docs","previous":{"title":"Registry API","permalink":"/rob/CmdForge/reference/registry-spec"},"next":{"title":"Collections","permalink":"/rob/CmdForge/reference/collections"}}');var o=t(4848),i=t(8453);const l={sidebar_label:"Meta-Tools",sidebar_position:2,format:"md"},r="Meta-Tools: Tools That Call Other Tools",d={},a=[{value:"Step Type: tool",id:"step-type-tool",level:2},{value:"Manifest Format",id:"manifest-format",level:3},{value:"Resolution Order",id:"resolution-order",level:3},{value:"Tool Step Properties",id:"tool-step-properties",level:3},{value:"Execution",id:"execution",level:3},{value:"Error Handling",id:"error-handling",level:3},{value:"Dependency Resolution",id:"dependency-resolution",level:2},{value:"Declaring Dependencies",id:"declaring-dependencies",level:3},{value:"CLI Integration",id:"cli-integration",level:3},{value:"Dependency Checking",id:"dependency-checking",level:3},{value:"Security Considerations",id:"security-considerations",level:2},{value:"Example: Multi-Step Analysis Pipeline",id:"example-multi-step-analysis-pipeline",level:2},{value:"Future Enhancements",id:"future-enhancements",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"meta-tools-tools-that-call-other-tools",children:"Meta-Tools: Tools That Call Other Tools"})}),"\n",(0,o.jsx)(n.p,{children:"Meta-tools are CmdForge tools that can invoke other tools as steps in their workflow. This enables powerful composition and reuse of existing tools."}),"\n",(0,o.jsxs)(n.h2,{id:"step-type-tool",children:["Step Type: ",(0,o.jsx)(n.code,{children:"tool"})]}),"\n",(0,o.jsxs)(n.p,{children:["A step type ",(0,o.jsx)(n.code,{children:"tool"})," allows calling another CmdForge tool from within a tool's workflow."]}),"\n",(0,o.jsx)(n.h3,{id:"manifest-format",children:"Manifest Format"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'name: summarize-and-translate\ndescription: Summarize text then translate the summary\nversion: 1.0.0\ncategory: Text\n\nsteps:\n - type: tool\n tool: official/summarize # Tool to call (owner/name or just name for local)\n input: "{input}" # What to pass as input (supports variable substitution)\n args: # Optional arguments to pass to the tool\n max_words: "100"\n output_var: summary # Variable to store the output\n\n - type: tool\n tool: official/translate\n input: "{summary}" # Use output from previous step\n args:\n target_language: "{language}" # Can use tool\'s own arguments\n output_var: translated\n\noutput: "{translated}"\n\narguments:\n - flag: "--language"\n variable: language\n default: "Spanish"\n description: "Target language for translation"\n'})}),"\n",(0,o.jsx)(n.h3,{id:"resolution-order",children:"Resolution Order"}),"\n",(0,o.jsxs)(n.p,{children:["When resolving a tool reference in a ",(0,o.jsx)(n.code,{children:"tool"})," step:"]}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Fully qualified"}),": ",(0,o.jsx)(n.code,{children:"owner/name"})," - looks up in registry or installed tools"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Local tool"}),": Just ",(0,o.jsx)(n.code,{children:"name"})," - checks local ",(0,o.jsx)(n.code,{children:"~/.cmdforge//config.yaml"})," first"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Registry fallback"}),": If not found locally, checks installed registry tools"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"tool-step-properties",children:"Tool Step Properties"}),"\n",(0,o.jsxs)(n.table,{children:[(0,o.jsx)(n.thead,{children:(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.th,{children:"Property"}),(0,o.jsx)(n.th,{children:"Required"}),(0,o.jsx)(n.th,{children:"Description"})]})}),(0,o.jsxs)(n.tbody,{children:[(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"type"})}),(0,o.jsx)(n.td,{children:"Yes"}),(0,o.jsxs)(n.td,{children:["Must be ",(0,o.jsx)(n.code,{children:'"tool"'})]})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"tool"})}),(0,o.jsx)(n.td,{children:"Yes"}),(0,o.jsx)(n.td,{children:"Tool reference (owner/name or name)"})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"input"})}),(0,o.jsx)(n.td,{children:"No"}),(0,o.jsxs)(n.td,{children:["Input to pass to the tool (default: current ",(0,o.jsx)(n.code,{children:"{input}"}),")"]})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"args"})}),(0,o.jsx)(n.td,{children:"No"}),(0,o.jsx)(n.td,{children:"Dictionary of arguments to pass"})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"output_var"})}),(0,o.jsx)(n.td,{children:"Yes"}),(0,o.jsx)(n.td,{children:"Variable name to store the tool's output"})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:(0,o.jsx)(n.code,{children:"provider"})}),(0,o.jsx)(n.td,{children:"No"}),(0,o.jsx)(n.td,{children:"Override provider for the called tool"})]})]})]}),"\n",(0,o.jsx)(n.h3,{id:"execution",children:"Execution"}),"\n",(0,o.jsxs)(n.p,{children:["When a ",(0,o.jsx)(n.code,{children:"tool"})," step executes:"]}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsx)(n.li,{children:"Resolve the tool reference to find the tool definition"}),"\n",(0,o.jsxs)(n.li,{children:["Substitute variables in ",(0,o.jsx)(n.code,{children:"input"})," and ",(0,o.jsx)(n.code,{children:"args"})," values"]}),"\n",(0,o.jsx)(n.li,{children:"Execute the tool with the resolved input and arguments"}),"\n",(0,o.jsxs)(n.li,{children:["Capture the output in the specified ",(0,o.jsx)(n.code,{children:"output_var"})]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"error-handling",children:"Error Handling"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"If a called tool fails, the parent tool fails with an appropriate error"}),"\n",(0,o.jsx)(n.li,{children:"Tool not found errors include helpful installation suggestions"}),"\n",(0,o.jsx)(n.li,{children:"Circular dependencies are detected and prevented"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"dependency-resolution",children:"Dependency Resolution"}),"\n",(0,o.jsx)(n.h3,{id:"declaring-dependencies",children:"Declaring Dependencies"}),"\n",(0,o.jsx)(n.p,{children:"Tools can declare their dependencies in the config:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"name: my-meta-tool\ndependencies:\n - official/summarize\n - official/translate@^1.0.0 # With version constraint\n"})}),"\n",(0,o.jsx)(n.h3,{id:"cli-integration",children:"CLI Integration"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"# Install a tool and its dependencies\ncmdforge install official/summarize-and-translate\n\n# Check if dependencies are satisfied\ncmdforge check my-meta-tool\n\n# Install missing dependencies\ncmdforge install --deps my-meta-tool\n"})}),"\n",(0,o.jsx)(n.h3,{id:"dependency-checking",children:"Dependency Checking"}),"\n",(0,o.jsx)(n.p,{children:"Before running a meta-tool, the runner verifies all dependencies are installed:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:'def check_dependencies(tool: Tool) -> List[str]:\n """Returns list of missing dependencies."""\n missing = []\n for dep in tool.dependencies:\n if not is_tool_installed(dep):\n missing.append(dep)\n return missing\n'})}),"\n",(0,o.jsx)(n.h2,{id:"security-considerations",children:"Security Considerations"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Sandboxing"}),": Called tools run in the same process context as the parent"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Input validation"}),": All inputs are treated as untrusted strings"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"No shell execution"}),": Tool references cannot contain shell commands"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Depth limit"}),": Maximum nesting depth (default: 10) prevents runaway recursion"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"example-multi-step-analysis-pipeline",children:"Example: Multi-Step Analysis Pipeline"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'name: code-review-pipeline\ndescription: Comprehensive code review using multiple specialized tools\nversion: 1.0.0\ncategory: Developer\n\ndependencies:\n - official/analyze-complexity\n - official/find-bugs\n - official/suggest-improvements\n\nsteps:\n # Step 1: Analyze code complexity\n - type: tool\n tool: official/analyze-complexity\n input: "{input}"\n output_var: complexity_report\n\n # Step 2: Find potential bugs\n - type: tool\n tool: official/find-bugs\n input: "{input}"\n output_var: bug_report\n\n # Step 3: Generate improvement suggestions based on findings\n - type: tool\n tool: official/suggest-improvements\n input: |\n ## Code:\n {input}\n\n ## Complexity Analysis:\n {complexity_report}\n\n ## Bug Report:\n {bug_report}\n output_var: suggestions\n\noutput: |\n # Code Review Results\n\n ## Complexity Analysis\n {complexity_report}\n\n ## Potential Issues\n {bug_report}\n\n ## Improvement Suggestions\n {suggestions}\n'})}),"\n",(0,o.jsx)(n.h2,{id:"future-enhancements",children:"Future Enhancements"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Parallel tool execution"}),": Run independent tool steps concurrently"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Conditional execution"}),": Skip steps based on conditions"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Tool aliases"}),": Define shorthand names for frequently used tools"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Caching"}),": Cache tool outputs for identical inputs"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},8453(e,n,t){t.d(n,{R:()=>l,x:()=>r});var s=t(6540);const o={},i=s.createContext(o);function l(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:l(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/14eb3368.33737677.js b/assets/js/14eb3368.33737677.js deleted file mode 100644 index 8b631b6..0000000 --- a/assets/js/14eb3368.33737677.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[969],{594(e,s,n){n.d(s,{A:()=>j});n(6540);var t=n(4164),r=n(7559),i=n(4718),a=n(9169),l=n(8774),c=n(1312),o=n(6025),d=n(4848);function u(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,d.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const m="breadcrumbHomeIcon_YNFT";function h(){const e=(0,o.Ay)("/");return(0,d.jsx)("li",{className:"breadcrumbs__item",children:(0,d.jsx)(l.A,{"aria-label":(0,c.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,d.jsx)(u,{className:m})})})}var b=n(5260),x=n(4586);function p(e){const s=function({breadcrumbs:e}){const{siteConfig:s}=(0,x.A)();return{"@context":"https://schema.org","@type":"BreadcrumbList",itemListElement:e.filter(e=>e.href).map((e,n)=>({"@type":"ListItem",position:n+1,name:e.label,item:`${s.url}${e.href}`}))}}({breadcrumbs:e.breadcrumbs});return(0,d.jsx)(b.A,{children:(0,d.jsx)("script",{type:"application/ld+json",children:JSON.stringify(s)})})}const g="breadcrumbsContainer_Z_bl";function v({children:e,href:s,isLast:n}){const t="breadcrumbs__link";return n?(0,d.jsx)("span",{className:t,children:e}):s?(0,d.jsx)(l.A,{className:t,href:s,children:(0,d.jsx)("span",{children:e})}):(0,d.jsx)("span",{className:t,children:e})}function f({children:e,active:s}){return(0,d.jsx)("li",{className:(0,t.A)("breadcrumbs__item",{"breadcrumbs__item--active":s}),children:e})}function j(){const e=(0,i.OF)(),s=(0,a.Dt)();return e?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(p,{breadcrumbs:e}),(0,d.jsx)("nav",{className:(0,t.A)(r.G.docs.docBreadcrumbs,g),"aria-label":(0,c.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,d.jsxs)("ul",{className:"breadcrumbs",children:[s&&(0,d.jsx)(h,{}),e.map((s,n)=>{const t=n===e.length-1,r="category"===s.type&&s.linkUnlisted?void 0:s.href;return(0,d.jsx)(f,{active:t,children:(0,d.jsx)(v,{href:r,isLast:t,children:s.label})},n)})]})})]}):null}},1878(e,s,n){n.d(s,{A:()=>p});n(6540);var t=n(4164),r=n(4586),i=n(8774),a=n(1312),l=n(4070),c=n(7559),o=n(3886),d=n(3025),u=n(4848);const m={unreleased:function({siteTitle:e,versionMetadata:s}){return(0,u.jsx)(a.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:s.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function({siteTitle:e,versionMetadata:s}){return(0,u.jsx)(a.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:s.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function h(e){const s=m[e.versionMetadata.banner];return(0,u.jsx)(s,{...e})}function b({versionLabel:e,to:s,onClick:n}){return(0,u.jsx)(a.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:e,latestVersionLink:(0,u.jsx)("b",{children:(0,u.jsx)(i.A,{to:s,onClick:n,children:(0,u.jsx)(a.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function x({className:e,versionMetadata:s}){const{siteConfig:{title:n}}=(0,r.A)(),{pluginId:i}=(0,l.vT)({failfast:!0}),{savePreferredVersionName:a}=(0,o.g1)(i),{latestDocSuggestion:d,latestVersionSuggestion:m}=(0,l.HW)(i),x=d??(p=m).docs.find(e=>e.id===p.mainDocId);var p;return(0,u.jsxs)("div",{className:(0,t.A)(e,c.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,u.jsx)("div",{children:(0,u.jsx)(h,{siteTitle:n,versionMetadata:s})}),(0,u.jsx)("div",{className:"margin-top--md",children:(0,u.jsx)(b,{versionLabel:m.label,to:x.path,onClick:()=>a(m.name)})})]})}function p({className:e}){const s=(0,d.r)();return s.banner?(0,u.jsx)(x,{className:e,versionMetadata:s}):null}},4267(e,s,n){n.d(s,{A:()=>c});n(6540);var t=n(4164),r=n(1312),i=n(7559),a=n(3025),l=n(4848);function c({className:e}){const s=(0,a.r)();return s.badge?(0,l.jsx)("span",{className:(0,t.A)(e,i.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,l.jsx)(r.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:s.label},children:"Version: {versionLabel}"})}):null}},6098(e,s,n){n.r(s),n.d(s,{default:()=>S});var t=n(6540),r=n(5500),i=n(4718),a=n(6025),l=n(4164),c=n(8774),o=n(4586);const d=["zero","one","two","few","many","other"];function u(e){return d.filter(s=>e.includes(s))}const m={locale:"en",pluralForms:u(["one","other"]),select:e=>1===e?"one":"other"};function h(){const{i18n:{currentLocale:e}}=(0,o.A)();return(0,t.useMemo)(()=>{try{return function(e){const s=new Intl.PluralRules(e);return{locale:e,pluralForms:u(s.resolvedOptions().pluralCategories),select:e=>s.select(e)}}(e)}catch(s){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${s.message}\n`),m}},[e])}function b(){const e=h();return{selectMessage:(s,n)=>function(e,s,n){const t=e.split("|");if(1===t.length)return t[0];t.length>n.pluralForms.length&&console.error(`For locale=${n.locale}, a maximum of ${n.pluralForms.length} plural forms are expected (${n.pluralForms.join(",")}), but the message contains ${t.length}: ${e}`);const r=n.select(s),i=n.pluralForms.indexOf(r);return t[Math.min(i,t.length-1)]}(n,s,e)}}var x=n(6654),p=n(1312),g=n(1107);const v="cardContainer_fWXF",f="cardTitle_rnsV",j="cardDescription_PWke";var N=n(4848);function A({className:e,href:s,children:n}){return(0,N.jsx)(c.A,{href:s,className:(0,l.A)("card padding--lg",v,e),children:n})}function _({className:e,href:s,icon:n,title:t,description:r}){return(0,N.jsxs)(A,{href:s,className:e,children:[(0,N.jsxs)(g.A,{as:"h2",className:(0,l.A)("text--truncate",f),title:t,children:[n," ",t]}),r&&(0,N.jsx)("p",{className:(0,l.A)("text--truncate",j),title:r,children:r})]})}function L({item:e}){const s=(0,i.Nr)(e),n=function(){const{selectMessage:e}=b();return s=>e(s,(0,p.T)({message:"1 item|{count} items",id:"theme.docs.DocCard.categoryDescription.plurals",description:"The default description for a category card in the generated index about how many items this category includes"},{count:s}))}();return s?(0,N.jsx)(_,{className:e.className,href:s,icon:"\ud83d\uddc3\ufe0f",title:e.label,description:e.description??n(e.items.length)}):null}function T({item:e}){const s=(0,x.A)(e.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",n=(0,i.cC)(e.docId??void 0);return(0,N.jsx)(_,{className:e.className,href:e.href,icon:s,title:e.label,description:e.description??n?.description})}function k({item:e}){switch(e.type){case"link":return(0,N.jsx)(T,{item:e});case"category":return(0,N.jsx)(L,{item:e});default:throw new Error(`unknown item type ${JSON.stringify(e)}`)}}const y="docCardListItem_W1sv";function w({className:e}){const s=(0,i.a4)();return(0,N.jsx)(C,{items:s,className:e})}function I({item:e}){return(0,N.jsx)("article",{className:(0,l.A)(y,"col col--6"),children:(0,N.jsx)(k,{item:e})})}function C(e){const{items:s,className:n}=e;if(!s)return(0,N.jsx)(w,{...e});const t=(0,i.d1)(s);return(0,N.jsx)("section",{className:(0,l.A)("row",n),children:t.map((e,s)=>(0,N.jsx)(I,{item:e},s))})}var F=n(6929),V=n(1878),M=n(4267),$=n(594);const D={generatedIndexPage:"generatedIndexPage_vN6x",title:"title_kItE"};function P({categoryGeneratedIndex:e}){return(0,N.jsx)(r.be,{title:e.title,description:e.description,keywords:e.keywords,image:(0,a.Ay)(e.image)})}function B({categoryGeneratedIndex:e}){const s=(0,i.$S)();return(0,N.jsxs)("div",{className:D.generatedIndexPage,children:[(0,N.jsx)(V.A,{}),(0,N.jsx)($.A,{}),(0,N.jsx)(M.A,{}),(0,N.jsxs)("header",{children:[(0,N.jsx)(g.A,{as:"h1",className:D.title,children:e.title}),e.description&&(0,N.jsx)("p",{children:e.description})]}),(0,N.jsx)("article",{className:"margin-top--lg",children:(0,N.jsx)(C,{items:s.items,className:D.list})}),(0,N.jsx)("footer",{className:"margin-top--md",children:(0,N.jsx)(F.A,{previous:e.navigation.previous,next:e.navigation.next})})]})}function S(e){return(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)(P,{...e}),(0,N.jsx)(B,{...e})]})}},6929(e,s,n){n.d(s,{A:()=>c});n(6540);var t=n(4164),r=n(1312),i=n(8774),a=n(4848);function l(e){const{permalink:s,title:n,subLabel:r,isNext:l}=e;return(0,a.jsxs)(i.A,{className:(0,t.A)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:s,children:[r&&(0,a.jsx)("div",{className:"pagination-nav__sublabel",children:r}),(0,a.jsx)("div",{className:"pagination-nav__label",children:n})]})}function c(e){const{className:s,previous:n,next:i}=e;return(0,a.jsxs)("nav",{className:(0,t.A)(s,"pagination-nav"),"aria-label":(0,r.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[n&&(0,a.jsx)(l,{...n,subLabel:(0,a.jsx)(r.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),i&&(0,a.jsx)(l,{...i,subLabel:(0,a.jsx)(r.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}}}]); \ No newline at end of file diff --git a/assets/js/17896441.3815ec59.js b/assets/js/17896441.3815ec59.js deleted file mode 100644 index bb6ba38..0000000 --- a/assets/js/17896441.3815ec59.js +++ /dev/null @@ -1 +0,0 @@ -(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[401],{594(e,n,t){"use strict";t.d(n,{A:()=>v});t(6540);var s=t(4164),a=t(7559),i=t(4718),r=t(9169),o=t(8774),c=t(1312),l=t(6025),d=t(4848);function u(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,d.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const m="breadcrumbHomeIcon_YNFT";function h(){const e=(0,l.Ay)("/");return(0,d.jsx)("li",{className:"breadcrumbs__item",children:(0,d.jsx)(o.A,{"aria-label":(0,c.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,d.jsx)(u,{className:m})})})}var f=t(5260),p=t(4586);function x(e){const n=function({breadcrumbs:e}){const{siteConfig:n}=(0,p.A)();return{"@context":"https://schema.org","@type":"BreadcrumbList",itemListElement:e.filter(e=>e.href).map((e,t)=>({"@type":"ListItem",position:t+1,name:e.label,item:`${n.url}${e.href}`}))}}({breadcrumbs:e.breadcrumbs});return(0,d.jsx)(f.A,{children:(0,d.jsx)("script",{type:"application/ld+json",children:JSON.stringify(n)})})}const g="breadcrumbsContainer_Z_bl";function b({children:e,href:n,isLast:t}){const s="breadcrumbs__link";return t?(0,d.jsx)("span",{className:s,children:e}):n?(0,d.jsx)(o.A,{className:s,href:n,children:(0,d.jsx)("span",{children:e})}):(0,d.jsx)("span",{className:s,children:e})}function j({children:e,active:n}){return(0,d.jsx)("li",{className:(0,s.A)("breadcrumbs__item",{"breadcrumbs__item--active":n}),children:e})}function v(){const e=(0,i.OF)(),n=(0,r.Dt)();return e?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(x,{breadcrumbs:e}),(0,d.jsx)("nav",{className:(0,s.A)(a.G.docs.docBreadcrumbs,g),"aria-label":(0,c.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,d.jsxs)("ul",{className:"breadcrumbs",children:[n&&(0,d.jsx)(h,{}),e.map((n,t)=>{const s=t===e.length-1,a="category"===n.type&&n.linkUnlisted?void 0:n.href;return(0,d.jsx)(j,{active:s,children:(0,d.jsx)(b,{href:a,isLast:s,children:n.label})},t)})]})})]}):null}},1878(e,n,t){"use strict";t.d(n,{A:()=>x});t(6540);var s=t(4164),a=t(4586),i=t(8774),r=t(1312),o=t(4070),c=t(7559),l=t(3886),d=t(3025),u=t(4848);const m={unreleased:function({siteTitle:e,versionMetadata:n}){return(0,u.jsx)(r.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:n.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function({siteTitle:e,versionMetadata:n}){return(0,u.jsx)(r.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:e,versionLabel:(0,u.jsx)("b",{children:n.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function h(e){const n=m[e.versionMetadata.banner];return(0,u.jsx)(n,{...e})}function f({versionLabel:e,to:n,onClick:t}){return(0,u.jsx)(r.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:e,latestVersionLink:(0,u.jsx)("b",{children:(0,u.jsx)(i.A,{to:n,onClick:t,children:(0,u.jsx)(r.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function p({className:e,versionMetadata:n}){const{siteConfig:{title:t}}=(0,a.A)(),{pluginId:i}=(0,o.vT)({failfast:!0}),{savePreferredVersionName:r}=(0,l.g1)(i),{latestDocSuggestion:d,latestVersionSuggestion:m}=(0,o.HW)(i),p=d??(x=m).docs.find(e=>e.id===x.mainDocId);var x;return(0,u.jsxs)("div",{className:(0,s.A)(e,c.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,u.jsx)("div",{children:(0,u.jsx)(h,{siteTitle:t,versionMetadata:n})}),(0,u.jsx)("div",{className:"margin-top--md",children:(0,u.jsx)(f,{versionLabel:m.label,to:p.path,onClick:()=>r(m.name)})})]})}function x({className:e}){const n=(0,d.r)();return n.banner?(0,u.jsx)(p,{className:e,versionMetadata:n}):null}},3262(e,n,t){"use strict";t.r(n),t.d(n,{default:()=>gt});var s=t(6540),a=t(5500),i=t(9532),r=t(4848);const o=s.createContext(null);function c({children:e,content:n}){const t=function(e){return(0,s.useMemo)(()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc}),[e])}(n);return(0,r.jsx)(o.Provider,{value:t,children:e})}function l(){const e=(0,s.useContext)(o);if(null===e)throw new i.dV("DocProvider");return e}function d(){const{metadata:e,frontMatter:n,assets:t}=l();return(0,r.jsx)(a.be,{title:e.title,description:e.description,keywords:n.keywords,image:t.image??n.image})}var u=t(4164),m=t(4581),h=t(6929);function f(){const{metadata:e}=l();return(0,r.jsx)(h.A,{className:"docusaurus-mt-lg",previous:e.previous,next:e.next})}var p=t(1878),x=t(4267),g=t(7559),b=t(1312),j=t(8774);const v="tag_zVej",N="tagRegular_sFm0",A="tagWithCount_h2kH";function y({permalink:e,label:n,count:t,description:s}){return(0,r.jsxs)(j.A,{rel:"tag",href:e,title:s,className:(0,u.A)(v,t?A:N),children:[n,t&&(0,r.jsx)("span",{children:t})]})}const C="tags_jXut",L="tag_QGVx";function k({tags:e}){return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("b",{children:(0,r.jsx)(b.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,r.jsx)("ul",{className:(0,u.A)(C,"padding--none","margin-left--sm"),children:e.map(e=>(0,r.jsx)("li",{className:L,children:(0,r.jsx)(y,{...e})},e.permalink))})]})}const _="iconEdit_Z9Sw";function w({className:e,...n}){return(0,r.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.A)(_,e),"aria-hidden":"true",...n,children:(0,r.jsx)("g",{children:(0,r.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function T({editUrl:e}){return(0,r.jsxs)(j.A,{to:e,className:g.G.common.editThisPage,children:[(0,r.jsx)(w,{}),(0,r.jsx)(b.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}var B=t(4586);function H(e={}){const{i18n:{currentLocale:n}}=(0,B.A)(),t=function(){const{i18n:{currentLocale:e,localeConfigs:n}}=(0,B.A)();return n[e].calendar}();return new Intl.DateTimeFormat(n,{calendar:t,...e})}function M({lastUpdatedAt:e}){const n=new Date(e),t=H({day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}).format(n);return(0,r.jsx)(b.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,r.jsx)("b",{children:(0,r.jsx)("time",{dateTime:n.toISOString(),itemProp:"dateModified",children:t})})},children:" on {date}"})}function E({lastUpdatedBy:e}){return(0,r.jsx)(b.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,r.jsx)("b",{children:e})},children:" by {user}"})}function I({lastUpdatedAt:e,lastUpdatedBy:n}){return(0,r.jsxs)("span",{className:g.G.common.lastUpdated,children:[(0,r.jsx)(b.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:e?(0,r.jsx)(M,{lastUpdatedAt:e}):"",byUser:n?(0,r.jsx)(E,{lastUpdatedBy:n}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const V="lastUpdated_JAkA",S="noPrint_WFHX";function U({className:e,editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s}){return(0,r.jsxs)("div",{className:(0,u.A)("row",e),children:[(0,r.jsx)("div",{className:(0,u.A)("col",S),children:n&&(0,r.jsx)(T,{editUrl:n})}),(0,r.jsx)("div",{className:(0,u.A)("col",V),children:(t||s)&&(0,r.jsx)(I,{lastUpdatedAt:t,lastUpdatedBy:s})})]})}function z(){const{metadata:e}=l(),{editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s,tags:a}=e,i=a.length>0,o=!!(n||t||s);return i||o?(0,r.jsxs)("footer",{className:(0,u.A)(g.G.docs.docFooter,"docusaurus-mt-lg"),children:[i&&(0,r.jsx)("div",{className:(0,u.A)("row margin-top--sm",g.G.docs.docFooterTagsRow),children:(0,r.jsx)("div",{className:"col",children:(0,r.jsx)(k,{tags:a})})}),o&&(0,r.jsx)(U,{className:(0,u.A)("margin-top--sm",g.G.docs.docFooterEditMetaRow),editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s})]}):null}var R=t(1422),O=t(6342);function P(e){const n=e.map(e=>({...e,parentIndex:-1,children:[]})),t=Array(7).fill(-1);n.forEach((e,n)=>{const s=t.slice(2,e.level);e.parentIndex=Math.max(...s),t[e.level]=n});const s=[];return n.forEach(e=>{const{parentIndex:t,...a}=e;t>=0?n[t].children.push(a):s.push(a)}),s}function D({toc:e,minHeadingLevel:n,maxHeadingLevel:t}){return e.flatMap(e=>{const s=D({toc:e.children,minHeadingLevel:n,maxHeadingLevel:t});return function(e){return e.level>=n&&e.level<=t}(e)?[{...e,children:s}]:s})}function G(e){const n=e.getBoundingClientRect();return n.top===n.bottom?G(e.parentNode):n}function F(e,{anchorTopOffset:n}){const t=e.find(e=>G(e).top>=n);if(t){return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight},[n]),e}function W(e){const n=(0,s.useRef)(void 0),t=$();(0,s.useEffect)(()=>{if(!e)return()=>{};const{linkClassName:s,linkActiveClassName:a,minHeadingLevel:i,maxHeadingLevel:r}=e;function o(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(s),o=function({minHeadingLevel:e,maxHeadingLevel:n}){const t=[];for(let s=e;s<=n;s+=1)t.push(`h${s}.anchor`);return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:i,maxHeadingLevel:r}),c=F(o,{anchorTopOffset:t.current}),l=e.find(e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e));e.forEach(e=>{!function(e,t){t?(n.current&&n.current!==e&&n.current.classList.remove(a),e.classList.add(a),n.current=e):e.classList.remove(a)}(e,e===l)})}return document.addEventListener("scroll",o),document.addEventListener("resize",o),o(),()=>{document.removeEventListener("scroll",o),document.removeEventListener("resize",o)}},[e,t])}function q({toc:e,className:n,linkClassName:t,isChild:s}){return e.length?(0,r.jsx)("ul",{className:s?void 0:n,children:e.map(e=>(0,r.jsxs)("li",{children:[(0,r.jsx)(j.A,{to:`#${e.id}`,className:t??void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,r.jsx)(q,{isChild:!0,toc:e.children,className:n,linkClassName:t})]},e.id))}):null}const J=s.memo(q);function Z({toc:e,className:n="table-of-contents table-of-contents__left-border",linkClassName:t="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:i,maxHeadingLevel:o,...c}){const l=(0,O.p)(),d=i??l.tableOfContents.minHeadingLevel,u=o??l.tableOfContents.maxHeadingLevel,m=function({toc:e,minHeadingLevel:n,maxHeadingLevel:t}){return(0,s.useMemo)(()=>D({toc:P(e),minHeadingLevel:n,maxHeadingLevel:t}),[e,n,t])}({toc:e,minHeadingLevel:d,maxHeadingLevel:u});return W((0,s.useMemo)(()=>{if(t&&a)return{linkClassName:t,linkActiveClassName:a,minHeadingLevel:d,maxHeadingLevel:u}},[t,a,d,u])),(0,r.jsx)(J,{toc:m,className:n,linkClassName:t,...c})}const X="tocCollapsibleButton_TO0P",Y="tocCollapsibleButtonExpanded_MG3E";function Q({collapsed:e,...n}){return(0,r.jsx)("button",{type:"button",...n,className:(0,u.A)("clean-btn",X,!e&&Y,n.className),children:(0,r.jsx)(b.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const K="tocCollapsible_ETCw",ee="tocCollapsibleContent_vkbj",ne="tocCollapsibleExpanded_sAul";function te({toc:e,className:n,minHeadingLevel:t,maxHeadingLevel:s}){const{collapsed:a,toggleCollapsed:i}=(0,R.u)({initialState:!0});return(0,r.jsxs)("div",{className:(0,u.A)(K,!a&&ne,n),children:[(0,r.jsx)(Q,{collapsed:a,onClick:i}),(0,r.jsx)(R.N,{lazy:!0,className:ee,collapsed:a,children:(0,r.jsx)(Z,{toc:e,minHeadingLevel:t,maxHeadingLevel:s})})]})}const se="tocMobile_ITEo";function ae(){const{toc:e,frontMatter:n}=l();return(0,r.jsx)(te,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:(0,u.A)(g.G.docs.docTocMobile,se)})}const ie="tableOfContents_bqdL";function re({className:e,...n}){return(0,r.jsx)("div",{className:(0,u.A)(ie,"thin-scrollbar",e),children:(0,r.jsx)(Z,{...n,linkClassName:"table-of-contents__link toc-highlight",linkActiveClassName:"table-of-contents__link--active"})})}function oe(){const{toc:e,frontMatter:n}=l();return(0,r.jsx)(re,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:g.G.docs.docTocDesktop})}var ce=t(1107),le=t(8453),de=t(5260),ue=t(2303),me=t(5293);function he(){const{prism:e}=(0,O.p)(),{colorMode:n}=(0,me.G)(),t=e.theme,s=e.darkTheme||t;return"dark"===n?s:t}var fe=t(8426),pe=t.n(fe);const xe=/title=(?["'])(?.*?)\1/,ge=/\{(?<range>[\d,-]+)\}/,be={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},je={...be,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},ve=Object.keys(be);function Ne(e,n){const t=e.map(e=>{const{start:t,end:s}=je[e];return`(?:${t}\\s*(${n.flatMap(e=>[e.line,e.block?.start,e.block?.end].filter(Boolean)).join("|")})\\s*${s})`}).join("|");return new RegExp(`^\\s*(?:${t})\\s*$`)}function Ae({showLineNumbers:e,metastring:n}){return"boolean"==typeof e?e?1:void 0:"number"==typeof e?e:function(e){const n=e?.split(" ").find(e=>e.startsWith("showLineNumbers"));if(n){if(n.startsWith("showLineNumbers=")){const e=n.replace("showLineNumbers=","");return parseInt(e,10)}return 1}}(n)}function ye(e,n){const{language:t,magicComments:s}=n;if(void 0===t)return{lineClassNames:{},code:e};const a=function(e,n){switch(e){case"js":case"javascript":case"ts":case"typescript":return Ne(["js","jsBlock"],n);case"jsx":case"tsx":return Ne(["js","jsBlock","jsx"],n);case"html":return Ne(["js","jsBlock","html"],n);case"python":case"py":case"bash":return Ne(["bash"],n);case"markdown":case"md":return Ne(["html","jsx","bash"],n);case"tex":case"latex":case"matlab":return Ne(["tex"],n);case"lua":case"haskell":return Ne(["lua"],n);case"sql":return Ne(["lua","jsBlock"],n);case"wasm":return Ne(["wasm"],n);case"vb":case"vba":case"visual-basic":return Ne(["vb","rem"],n);case"vbnet":return Ne(["vbnet","rem"],n);case"batch":return Ne(["rem"],n);case"basic":return Ne(["rem","f90"],n);case"fsharp":return Ne(["js","ml"],n);case"ocaml":case"sml":return Ne(["ml"],n);case"fortran":return Ne(["f90"],n);case"cobol":return Ne(["cobol"],n);default:return Ne(ve,n)}}(t,s),i=e.split(/\r?\n/),r=Object.fromEntries(s.map(e=>[e.className,{start:0,range:""}])),o=Object.fromEntries(s.filter(e=>e.line).map(({className:e,line:n})=>[n,e])),c=Object.fromEntries(s.filter(e=>e.block).map(({className:e,block:n})=>[n.start,e])),l=Object.fromEntries(s.filter(e=>e.block).map(({className:e,block:n})=>[n.end,e]));for(let u=0;u<i.length;){const e=i[u].match(a);if(!e){u+=1;continue}const n=e.slice(1).find(e=>void 0!==e);o[n]?r[o[n]].range+=`${u},`:c[n]?r[c[n]].start=u:l[n]&&(r[l[n]].range+=`${r[l[n]].start}-${u-1},`),i.splice(u,1)}const d={};return Object.entries(r).forEach(([e,{range:n}])=>{pe()(n).forEach(n=>{d[n]??=[],d[n].push(e)})}),{code:i.join("\n"),lineClassNames:d}}function Ce(e,n){const t=e.replace(/\r?\n$/,"");return function(e,{metastring:n,magicComments:t}){if(n&&ge.test(n)){const s=n.match(ge).groups.range;if(0===t.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${n}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const a=t[0].className,i=pe()(s).filter(e=>e>0).map(e=>[e-1,[a]]);return{lineClassNames:Object.fromEntries(i),code:e}}return null}(t,{...n})??ye(t,{...n})}function Le(e){const n=function(e){return n=e.language??function(e){if(!e)return;const n=e.split(" ").find(e=>e.startsWith("language-"));return n?.replace(/language-/,"")}(e.className)??e.defaultLanguage,n?.toLowerCase()??"text";var n}({language:e.language,defaultLanguage:e.defaultLanguage,className:e.className}),{lineClassNames:t,code:s}=Ce(e.code,{metastring:e.metastring,magicComments:e.magicComments,language:n}),a=function({className:e,language:n}){return(0,u.A)(e,n&&!e?.includes(`language-${n}`)&&`language-${n}`)}({className:e.className,language:n}),i=(r=e.metastring,(r?.match(xe)?.groups.title??"")||e.title);var r;const o=Ae({showLineNumbers:e.showLineNumbers,metastring:e.metastring});return{codeInput:e.code,code:s,className:a,language:n,title:i,lineNumbersStart:o,lineClassNames:t}}const ke=(0,s.createContext)(null);function _e({metadata:e,wordWrap:n,children:t}){const a=(0,s.useMemo)(()=>({metadata:e,wordWrap:n}),[e,n]);return(0,r.jsx)(ke.Provider,{value:a,children:t})}function we(){const e=(0,s.useContext)(ke);if(null===e)throw new i.dV("CodeBlockContextProvider");return e}const Te="codeBlockContainer_Ckt0";function Be({as:e,...n}){const t=function(e){const n={color:"--prism-color",backgroundColor:"--prism-background-color"},t={};return Object.entries(e.plain).forEach(([e,s])=>{const a=n[e];a&&"string"==typeof s&&(t[a]=s)}),t}(he());return(0,r.jsx)(e,{...n,style:t,className:(0,u.A)(n.className,Te,g.G.common.codeBlock)})}const He="codeBlock_bY9V",Me="codeBlockStandalone_MEMb",Ee="codeBlockLines_e6Vv",Ie="codeBlockLinesWithNumbering_o6Pm";function Ve({children:e,className:n}){return(0,r.jsx)(Be,{as:"pre",tabIndex:0,className:(0,u.A)(Me,"thin-scrollbar",n),children:(0,r.jsx)("code",{className:Ee,children:e})})}const Se={attributes:!0,characterData:!0,childList:!0,subtree:!0};function Ue(e,n){const[t,a]=(0,s.useState)(),r=(0,s.useCallback)(()=>{a(e.current?.closest("[role=tabpanel][hidden]"))},[e,a]);(0,s.useEffect)(()=>{r()},[r]),function(e,n,t=Se){const a=(0,i._q)(n),r=(0,i.Be)(t);(0,s.useEffect)(()=>{const n=new MutationObserver(a);return e&&n.observe(e,r),()=>n.disconnect()},[e,a,r])}(t,e=>{e.forEach(e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(n(),r())})},{attributes:!0,characterData:!1,childList:!1,subtree:!1})}function ze({children:e}){return e}var Re=t(1765);function Oe({line:e,token:n,...t}){return(0,r.jsx)("span",{...t})}const Pe="codeLine_lJS_",De="codeLineNumber_Tfdd",Ge="codeLineContent_feaV";function Fe({line:e,classNames:n,showLineNumbers:t,getLineProps:s,getTokenProps:a}){const i=function(e){const n=1===e.length&&"\n"===e[0].content?e[0]:void 0;return n?[{...n,content:""}]:e}(e),o=s({line:i,className:(0,u.A)(n,t&&Pe)}),c=i.map((e,n)=>{const t=a({token:e});return(0,r.jsx)(Oe,{...t,line:i,token:e,children:t.children},n)});return(0,r.jsxs)("span",{...o,children:[t?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:De}),(0,r.jsx)("span",{className:Ge,children:c})]}):c,(0,r.jsx)("br",{})]})}const $e=s.forwardRef((e,n)=>(0,r.jsx)("pre",{ref:n,tabIndex:0,...e,className:(0,u.A)(e.className,He,"thin-scrollbar")}));function We(e){const{metadata:n}=we();return(0,r.jsx)("code",{...e,className:(0,u.A)(e.className,Ee,void 0!==n.lineNumbersStart&&Ie),style:{...e.style,counterReset:void 0===n.lineNumbersStart?void 0:"line-count "+(n.lineNumbersStart-1)}})}function qe({className:e}){const{metadata:n,wordWrap:t}=we(),s=he(),{code:a,language:i,lineNumbersStart:o,lineClassNames:c}=n;return(0,r.jsx)(Re.f4,{theme:s,code:a,language:i,children:({className:n,style:s,tokens:a,getLineProps:i,getTokenProps:l})=>(0,r.jsx)($e,{ref:t.codeBlockRef,className:(0,u.A)(e,n),style:s,children:(0,r.jsx)(We,{children:a.map((e,n)=>(0,r.jsx)(Fe,{line:e,getLineProps:i,getTokenProps:l,classNames:c[n],showLineNumbers:void 0!==o},n))})})})}function Je({children:e,fallback:n}){return(0,ue.A)()?(0,r.jsx)(r.Fragment,{children:e?.()}):n??null}function Ze({className:e,...n}){return(0,r.jsx)("button",{type:"button",...n,className:(0,u.A)("clean-btn",e)})}function Xe(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function Ye(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const Qe={copyButtonCopied:"copyButtonCopied_Vdqa",copyButtonIcons:"copyButtonIcons_IEyt",copyButtonIcon:"copyButtonIcon_TrPX",copyButtonSuccessIcon:"copyButtonSuccessIcon_cVMy"};function Ke(e){return e?(0,b.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,b.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"})}function en({className:e}){const{copyCode:n,isCopied:t}=function(){const{metadata:{code:e}}=we(),[n,t]=(0,s.useState)(!1),a=(0,s.useRef)(void 0),i=(0,s.useCallback)(()=>{navigator.clipboard.writeText(e).then(()=>{t(!0),a.current=window.setTimeout(()=>{t(!1)},1e3)})},[e]);return(0,s.useEffect)(()=>()=>window.clearTimeout(a.current),[]),{copyCode:i,isCopied:n}}();return(0,r.jsx)(Ze,{"aria-label":Ke(t),title:(0,b.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,u.A)(e,Qe.copyButton,t&&Qe.copyButtonCopied),onClick:n,children:(0,r.jsxs)("span",{className:Qe.copyButtonIcons,"aria-hidden":"true",children:[(0,r.jsx)(Xe,{className:Qe.copyButtonIcon}),(0,r.jsx)(Ye,{className:Qe.copyButtonSuccessIcon})]})})}function nn(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const tn="wordWrapButtonIcon_b1P5",sn="wordWrapButtonEnabled_uzNF";function an({className:e}){const{wordWrap:n}=we();if(!(n.isEnabled||n.isCodeScrollable))return!1;const t=(0,b.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,r.jsx)(Ze,{onClick:()=>n.toggle(),className:(0,u.A)(e,n.isEnabled&&sn),"aria-label":t,title:t,children:(0,r.jsx)(nn,{className:tn,"aria-hidden":"true"})})}const rn="buttonGroup_M5ko";function on({className:e}){return(0,r.jsx)(Je,{children:()=>(0,r.jsxs)("div",{className:(0,u.A)(e,rn),children:[(0,r.jsx)(an,{}),(0,r.jsx)(en,{})]})})}const cn="codeBlockContent_QJqH",ln="codeBlockTitle_OeMC";function dn({className:e}){const{metadata:n}=we();return(0,r.jsxs)(Be,{as:"div",className:(0,u.A)(e,n.className),children:[n.title&&(0,r.jsx)("div",{className:ln,children:(0,r.jsx)(ze,{children:n.title})}),(0,r.jsxs)("div",{className:cn,children:[(0,r.jsx)(qe,{}),(0,r.jsx)(on,{})]})]})}function un(e){const n=function(e){const{prism:n}=(0,O.p)();return Le({code:e.children,className:e.className,metastring:e.metastring,magicComments:n.magicComments,defaultLanguage:n.defaultLanguage,language:e.language,title:e.title,showLineNumbers:e.showLineNumbers})}(e),t=function(){const[e,n]=(0,s.useState)(!1),[t,a]=(0,s.useState)(!1),i=(0,s.useRef)(null),r=(0,s.useCallback)(()=>{const t=i.current.querySelector("code");e?t.removeAttribute("style"):(t.style.whiteSpace="pre-wrap",t.style.overflowWrap="anywhere"),n(e=>!e)},[i,e]),o=(0,s.useCallback)(()=>{const{scrollWidth:e,clientWidth:n}=i.current,t=e>n||i.current.querySelector("code").hasAttribute("style");a(t)},[i]);return Ue(i,o),(0,s.useEffect)(()=>{o()},[e,o]),(0,s.useEffect)(()=>(window.addEventListener("resize",o,{passive:!0}),()=>{window.removeEventListener("resize",o)}),[o]),{codeBlockRef:i,isEnabled:e,isCodeScrollable:t,toggle:r}}();return(0,r.jsx)(_e,{metadata:n,wordWrap:t,children:(0,r.jsx)(dn,{})})}function mn({children:e,...n}){const t=(0,ue.A)(),a=function(e){return s.Children.toArray(e).some(e=>(0,s.isValidElement)(e))?e:Array.isArray(e)?e.join(""):e}(e),i="string"==typeof a?un:Ve;return(0,r.jsx)(i,{...n,children:a},String(t))}function hn(e){return(0,r.jsx)("code",{...e})}var fn=t(3535);var pn=t(3427);const xn="details_lb9f",gn="isBrowser_bmU9",bn="collapsibleContent_i85q";function jn(e){return!!e&&("SUMMARY"===e.tagName||jn(e.parentElement))}function vn(e,n){return!!e&&(e===n||vn(e.parentElement,n))}function Nn({summary:e,children:n,...t}){(0,pn.A)().collectAnchor(t.id);const a=(0,ue.A)(),i=(0,s.useRef)(null),{collapsed:o,setCollapsed:c}=(0,R.u)({initialState:!t.open}),[l,d]=(0,s.useState)(t.open),m=s.isValidElement(e)?e:(0,r.jsx)("summary",{children:e??"Details"});return(0,r.jsxs)("details",{...t,ref:i,open:l,"data-collapsed":o,className:(0,u.A)(xn,a&&gn,t.className),onMouseDown:e=>{jn(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const n=e.target;jn(n)&&vn(n,i.current)&&(e.preventDefault(),o?(c(!1),d(!0)):c(!0))},children:[m,(0,r.jsx)(R.N,{lazy:!1,collapsed:o,onCollapseTransitionEnd:e=>{c(e),d(!e)},children:(0,r.jsx)("div",{className:bn,children:n})})]})}const An="details_b_Ee";function yn({...e}){return(0,r.jsx)(Nn,{...e,className:(0,u.A)("alert alert--info",An,e.className)})}function Cn(e){const n=s.Children.toArray(e.children),t=n.find(e=>s.isValidElement(e)&&"summary"===e.type),a=(0,r.jsx)(r.Fragment,{children:n.filter(e=>e!==t)});return(0,r.jsx)(yn,{...e,summary:t,children:a})}function Ln(e){return(0,r.jsx)(ce.A,{...e})}const kn="containsTaskList_mC6p";function _n(e){if(void 0!==e)return(0,u.A)(e,e?.includes("contains-task-list")&&kn)}const wn="img_ev3q";function Tn(e){const{mdxAdmonitionTitle:n,rest:t}=function(e){const n=s.Children.toArray(e),t=n.find(e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type),a=n.filter(e=>e!==t),i=t?.props.children;return{mdxAdmonitionTitle:i,rest:a.length>0?(0,r.jsx)(r.Fragment,{children:a}):null}}(e.children),a=e.title??n;return{...e,...a&&{title:a},children:t}}const Bn="admonition_xJq3",Hn="admonitionHeading_Gvgb",Mn="admonitionIcon_Rf37",En="admonitionContent_BuS1";function In({type:e,className:n,children:t}){return(0,r.jsx)("div",{className:(0,u.A)(g.G.common.admonition,g.G.common.admonitionType(e),Bn,n),children:t})}function Vn({icon:e,title:n}){return(0,r.jsxs)("div",{className:Hn,children:[(0,r.jsx)("span",{className:Mn,children:e}),n]})}function Sn({children:e}){return e?(0,r.jsx)("div",{className:En,children:e}):null}function Un(e){const{type:n,icon:t,title:s,children:a,className:i}=e;return(0,r.jsxs)(In,{type:n,className:i,children:[s||t?(0,r.jsx)(Vn,{title:s,icon:t}):null,(0,r.jsx)(Sn,{children:a})]})}function zn(e){return(0,r.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const Rn={icon:(0,r.jsx)(zn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function On(e){return(0,r.jsx)(Un,{...Rn,...e,className:(0,u.A)("alert alert--secondary",e.className),children:e.children})}function Pn(e){return(0,r.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const Dn={icon:(0,r.jsx)(Pn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function Gn(e){return(0,r.jsx)(Un,{...Dn,...e,className:(0,u.A)("alert alert--success",e.className),children:e.children})}function Fn(e){return(0,r.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const $n={icon:(0,r.jsx)(Fn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function Wn(e){return(0,r.jsx)(Un,{...$n,...e,className:(0,u.A)("alert alert--info",e.className),children:e.children})}function qn(e){return(0,r.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const Jn={icon:(0,r.jsx)(qn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function Zn(e){return(0,r.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const Xn={icon:(0,r.jsx)(Zn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const Yn={icon:(0,r.jsx)(qn,{}),title:(0,r.jsx)(b.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const Qn={...{note:On,tip:Gn,info:Wn,warning:function(e){return(0,r.jsx)(Un,{...Jn,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,r.jsx)(Un,{...Xn,...e,className:(0,u.A)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,r.jsx)(On,{title:"secondary",...e}),important:e=>(0,r.jsx)(Wn,{title:"important",...e}),success:e=>(0,r.jsx)(Gn,{title:"success",...e}),caution:function(e){return(0,r.jsx)(Un,{...Yn,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})}}};function Kn(e){const n=Tn(e),t=(s=n.type,Qn[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),Qn.info));var s;return(0,r.jsx)(t,{...n})}var et=t(418);const nt={Head:de.A,details:Cn,Details:Cn,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every(e=>"string"==typeof e&&!e.includes("\n"))}(e)?(0,r.jsx)(hn,{...e}):(0,r.jsx)(mn,{...e})},a:function(e){const n=(0,fn.v)(e.id);return(0,r.jsx)(j.A,{...e,className:(0,u.A)(n,e.className)})},pre:function(e){return(0,r.jsx)(r.Fragment,{children:e.children})},ul:function(e){return(0,r.jsx)("ul",{...e,className:_n(e.className)})},li:function(e){(0,pn.A)().collectAnchor(e.id);const n=(0,fn.v)(e.id);return(0,r.jsx)("li",{className:(0,u.A)(n,e.className),...e})},img:function(e){return(0,r.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(n=e.className,(0,u.A)(n,wn))});var n},h1:e=>(0,r.jsx)(Ln,{as:"h1",...e}),h2:e=>(0,r.jsx)(Ln,{as:"h2",...e}),h3:e=>(0,r.jsx)(Ln,{as:"h3",...e}),h4:e=>(0,r.jsx)(Ln,{as:"h4",...e}),h5:e=>(0,r.jsx)(Ln,{as:"h5",...e}),h6:e=>(0,r.jsx)(Ln,{as:"h6",...e}),admonition:Kn,mermaid:et.A};function tt({children:e}){return(0,r.jsx)(le.x,{components:nt,children:e})}function st({children:e}){const n=function(){const{metadata:e,frontMatter:n,contentTitle:t}=l();return n.hide_title||void 0!==t?null:e.title}();return(0,r.jsxs)("div",{className:(0,u.A)(g.G.docs.docMarkdown,"markdown"),children:[n&&(0,r.jsx)("header",{children:(0,r.jsx)(ce.A,{as:"h1",children:n})}),(0,r.jsx)(tt,{children:e})]})}var at=t(594);function it(){return(0,r.jsx)(b.A,{id:"theme.contentVisibility.unlistedBanner.title",description:"The unlisted content banner title",children:"Unlisted page"})}function rt(){return(0,r.jsx)(b.A,{id:"theme.contentVisibility.unlistedBanner.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function ot(){return(0,r.jsx)(de.A,{children:(0,r.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}function ct(){return(0,r.jsx)(b.A,{id:"theme.contentVisibility.draftBanner.title",description:"The draft content banner title",children:"Draft page"})}function lt(){return(0,r.jsx)(b.A,{id:"theme.contentVisibility.draftBanner.message",description:"The draft content banner message",children:"This page is a draft. It will only be visible in dev and be excluded from the production build."})}function dt({className:e}){return(0,r.jsx)(Kn,{type:"caution",title:(0,r.jsx)(ct,{}),className:(0,u.A)(e,g.G.common.draftBanner),children:(0,r.jsx)(lt,{})})}function ut({className:e}){return(0,r.jsx)(Kn,{type:"caution",title:(0,r.jsx)(it,{}),className:(0,u.A)(e,g.G.common.unlistedBanner),children:(0,r.jsx)(rt,{})})}function mt(e){return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(ot,{}),(0,r.jsx)(ut,{...e})]})}function ht({metadata:e}){const{unlisted:n,frontMatter:t}=e;return(0,r.jsxs)(r.Fragment,{children:[(n||t.unlisted)&&(0,r.jsx)(mt,{}),t.draft&&(0,r.jsx)(dt,{})]})}const ft="docItemContainer_Djhp",pt="docItemCol_VOVn";function xt({children:e}){const n=function(){const{frontMatter:e,toc:n}=l(),t=(0,m.l)(),s=e.hide_table_of_contents,a=!s&&n.length>0;return{hidden:s,mobile:a?(0,r.jsx)(ae,{}):void 0,desktop:!a||"desktop"!==t&&"ssr"!==t?void 0:(0,r.jsx)(oe,{})}}(),{metadata:t}=l();return(0,r.jsxs)("div",{className:"row",children:[(0,r.jsxs)("div",{className:(0,u.A)("col",!n.hidden&&pt),children:[(0,r.jsx)(ht,{metadata:t}),(0,r.jsx)(p.A,{}),(0,r.jsxs)("div",{className:ft,children:[(0,r.jsxs)("article",{children:[(0,r.jsx)(at.A,{}),(0,r.jsx)(x.A,{}),n.mobile,(0,r.jsx)(st,{children:e}),(0,r.jsx)(z,{})]}),(0,r.jsx)(f,{})]})]}),n.desktop&&(0,r.jsx)("div",{className:"col col--3",children:n.desktop})]})}function gt(e){const n=`docs-doc-id-${e.content.metadata.id}`,t=e.content;return(0,r.jsx)(c,{content:e.content,children:(0,r.jsxs)(a.e3,{className:n,children:[(0,r.jsx)(d,{}),(0,r.jsx)(xt,{children:(0,r.jsx)(t,{})})]})})}},4267(e,n,t){"use strict";t.d(n,{A:()=>c});t(6540);var s=t(4164),a=t(1312),i=t(7559),r=t(3025),o=t(4848);function c({className:e}){const n=(0,r.r)();return n.badge?(0,o.jsx)("span",{className:(0,s.A)(e,i.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,o.jsx)(a.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label},children:"Version: {versionLabel}"})}):null}},6929(e,n,t){"use strict";t.d(n,{A:()=>c});t(6540);var s=t(4164),a=t(1312),i=t(8774),r=t(4848);function o(e){const{permalink:n,title:t,subLabel:a,isNext:o}=e;return(0,r.jsxs)(i.A,{className:(0,s.A)("pagination-nav__link",o?"pagination-nav__link--next":"pagination-nav__link--prev"),to:n,children:[a&&(0,r.jsx)("div",{className:"pagination-nav__sublabel",children:a}),(0,r.jsx)("div",{className:"pagination-nav__label",children:t})]})}function c(e){const{className:n,previous:t,next:i}=e;return(0,r.jsxs)("nav",{className:(0,s.A)(n,"pagination-nav"),"aria-label":(0,a.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[t&&(0,r.jsx)(o,{...t,subLabel:(0,r.jsx)(a.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),i&&(0,r.jsx)(o,{...i,subLabel:(0,r.jsx)(a.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}},8426(e,n){function t(e){let n,t=[];for(let s of e.split(",").map(e=>e.trim()))if(/^-?\d+$/.test(s))t.push(parseInt(s,10));else if(n=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,a,i]=n;if(s&&i){s=parseInt(s),i=parseInt(i);const e=s<i?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(i+=e);for(let n=s;n!==i;n+=e)t.push(n)}}return t}n.default=t,e.exports=t},8453(e,n,t){"use strict";t.d(n,{R:()=>r,x:()=>o});var s=t(6540);const a={},i=s.createContext(a);function r(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/17896441.a2525508.js b/assets/js/17896441.a2525508.js new file mode 100644 index 0000000..6198797 --- /dev/null +++ b/assets/js/17896441.a2525508.js @@ -0,0 +1 @@ +(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[401],{8252(e,n,t){"use strict";t.r(n),t.d(n,{default:()=>Vt});var s=t(6540),a=t(5500),i=t(9532),r=t(4848);const o=s.createContext(null);function c({children:e,content:n}){const t=function(e){return(0,s.useMemo)(()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc}),[e])}(n);return(0,r.jsx)(o.Provider,{value:t,children:e})}function l(){const e=(0,s.useContext)(o);if(null===e)throw new i.dV("DocProvider");return e}function d(){const{metadata:e,frontMatter:n,assets:t}=l();return(0,r.jsx)(a.be,{title:e.title,description:e.description,keywords:n.keywords,image:t.image??n.image})}var u=t(4164),m=t(4581),h=t(1312),f=t(8774);function p(e){const{permalink:n,title:t,subLabel:s,isNext:a}=e;return(0,r.jsxs)(f.A,{className:(0,u.A)("pagination-nav__link",a?"pagination-nav__link--next":"pagination-nav__link--prev"),to:n,children:[s&&(0,r.jsx)("div",{className:"pagination-nav__sublabel",children:s}),(0,r.jsx)("div",{className:"pagination-nav__label",children:t})]})}function x(e){const{className:n,previous:t,next:s}=e;return(0,r.jsxs)("nav",{className:(0,u.A)(n,"pagination-nav"),"aria-label":(0,h.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[t&&(0,r.jsx)(p,{...t,subLabel:(0,r.jsx)(h.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),s&&(0,r.jsx)(p,{...s,subLabel:(0,r.jsx)(h.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}function g(){const{metadata:e}=l();return(0,r.jsx)(x,{className:"docusaurus-mt-lg",previous:e.previous,next:e.next})}var b=t(4586),j=t(4070),v=t(7559),N=t(3886),A=t(3025);const y={unreleased:function({siteTitle:e,versionMetadata:n}){return(0,r.jsx)(h.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:e,versionLabel:(0,r.jsx)("b",{children:n.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function({siteTitle:e,versionMetadata:n}){return(0,r.jsx)(h.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:e,versionLabel:(0,r.jsx)("b",{children:n.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function C(e){const n=y[e.versionMetadata.banner];return(0,r.jsx)(n,{...e})}function L({versionLabel:e,to:n,onClick:t}){return(0,r.jsx)(h.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:e,latestVersionLink:(0,r.jsx)("b",{children:(0,r.jsx)(f.A,{to:n,onClick:t,children:(0,r.jsx)(h.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function k({className:e,versionMetadata:n}){const{siteConfig:{title:t}}=(0,b.A)(),{pluginId:s}=(0,j.vT)({failfast:!0}),{savePreferredVersionName:a}=(0,N.g1)(s),{latestDocSuggestion:i,latestVersionSuggestion:o}=(0,j.HW)(s),c=i??(l=o).docs.find(e=>e.id===l.mainDocId);var l;return(0,r.jsxs)("div",{className:(0,u.A)(e,v.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,r.jsx)("div",{children:(0,r.jsx)(C,{siteTitle:t,versionMetadata:n})}),(0,r.jsx)("div",{className:"margin-top--md",children:(0,r.jsx)(L,{versionLabel:o.label,to:c.path,onClick:()=>a(o.name)})})]})}function _({className:e}){const n=(0,A.r)();return n.banner?(0,r.jsx)(k,{className:e,versionMetadata:n}):null}function w({className:e}){const n=(0,A.r)();return n.badge?(0,r.jsx)("span",{className:(0,u.A)(e,v.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,r.jsx)(h.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label},children:"Version: {versionLabel}"})}):null}const T="tag_zVej",B="tagRegular_sFm0",H="tagWithCount_h2kH";function M({permalink:e,label:n,count:t,description:s}){return(0,r.jsxs)(f.A,{rel:"tag",href:e,title:s,className:(0,u.A)(T,t?H:B),children:[n,t&&(0,r.jsx)("span",{children:t})]})}const E="tags_jXut",I="tag_QGVx";function V({tags:e}){return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("b",{children:(0,r.jsx)(h.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,r.jsx)("ul",{className:(0,u.A)(E,"padding--none","margin-left--sm"),children:e.map(e=>(0,r.jsx)("li",{className:I,children:(0,r.jsx)(M,{...e})},e.permalink))})]})}const S="iconEdit_Z9Sw";function U({className:e,...n}){return(0,r.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.A)(S,e),"aria-hidden":"true",...n,children:(0,r.jsx)("g",{children:(0,r.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function z({editUrl:e}){return(0,r.jsxs)(f.A,{to:e,className:v.G.common.editThisPage,children:[(0,r.jsx)(U,{}),(0,r.jsx)(h.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}function R(e={}){const{i18n:{currentLocale:n}}=(0,b.A)(),t=function(){const{i18n:{currentLocale:e,localeConfigs:n}}=(0,b.A)();return n[e].calendar}();return new Intl.DateTimeFormat(n,{calendar:t,...e})}function O({lastUpdatedAt:e}){const n=new Date(e),t=R({day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}).format(n);return(0,r.jsx)(h.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,r.jsx)("b",{children:(0,r.jsx)("time",{dateTime:n.toISOString(),itemProp:"dateModified",children:t})})},children:" on {date}"})}function P({lastUpdatedBy:e}){return(0,r.jsx)(h.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,r.jsx)("b",{children:e})},children:" by {user}"})}function D({lastUpdatedAt:e,lastUpdatedBy:n}){return(0,r.jsxs)("span",{className:v.G.common.lastUpdated,children:[(0,r.jsx)(h.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:e?(0,r.jsx)(O,{lastUpdatedAt:e}):"",byUser:n?(0,r.jsx)(P,{lastUpdatedBy:n}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const G="lastUpdated_JAkA",F="noPrint_WFHX";function $({className:e,editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s}){return(0,r.jsxs)("div",{className:(0,u.A)("row",e),children:[(0,r.jsx)("div",{className:(0,u.A)("col",F),children:n&&(0,r.jsx)(z,{editUrl:n})}),(0,r.jsx)("div",{className:(0,u.A)("col",G),children:(t||s)&&(0,r.jsx)(D,{lastUpdatedAt:t,lastUpdatedBy:s})})]})}function W(){const{metadata:e}=l(),{editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s,tags:a}=e,i=a.length>0,o=!!(n||t||s);return i||o?(0,r.jsxs)("footer",{className:(0,u.A)(v.G.docs.docFooter,"docusaurus-mt-lg"),children:[i&&(0,r.jsx)("div",{className:(0,u.A)("row margin-top--sm",v.G.docs.docFooterTagsRow),children:(0,r.jsx)("div",{className:"col",children:(0,r.jsx)(V,{tags:a})})}),o&&(0,r.jsx)($,{className:(0,u.A)("margin-top--sm",v.G.docs.docFooterEditMetaRow),editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s})]}):null}var q=t(1422),J=t(6342);function Z(e){const n=e.map(e=>({...e,parentIndex:-1,children:[]})),t=Array(7).fill(-1);n.forEach((e,n)=>{const s=t.slice(2,e.level);e.parentIndex=Math.max(...s),t[e.level]=n});const s=[];return n.forEach(e=>{const{parentIndex:t,...a}=e;t>=0?n[t].children.push(a):s.push(a)}),s}function X({toc:e,minHeadingLevel:n,maxHeadingLevel:t}){return e.flatMap(e=>{const s=X({toc:e.children,minHeadingLevel:n,maxHeadingLevel:t});return function(e){return e.level>=n&&e.level<=t}(e)?[{...e,children:s}]:s})}function Y(e){const n=e.getBoundingClientRect();return n.top===n.bottom?Y(e.parentNode):n}function Q(e,{anchorTopOffset:n}){const t=e.find(e=>Y(e).top>=n);if(t){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(Y(t))?t:e[e.indexOf(t)-1]??null}return e[e.length-1]??null}function K(){const e=(0,s.useRef)(0),{navbar:{hideOnScroll:n}}=(0,J.p)();return(0,s.useEffect)(()=>{e.current=n?0:document.querySelector(".navbar").clientHeight},[n]),e}function ee(e){const n=(0,s.useRef)(void 0),t=K();(0,s.useEffect)(()=>{if(!e)return()=>{};const{linkClassName:s,linkActiveClassName:a,minHeadingLevel:i,maxHeadingLevel:r}=e;function o(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(s),o=function({minHeadingLevel:e,maxHeadingLevel:n}){const t=[];for(let s=e;s<=n;s+=1)t.push(`h${s}.anchor`);return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:i,maxHeadingLevel:r}),c=Q(o,{anchorTopOffset:t.current}),l=e.find(e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e));e.forEach(e=>{!function(e,t){t?(n.current&&n.current!==e&&n.current.classList.remove(a),e.classList.add(a),n.current=e):e.classList.remove(a)}(e,e===l)})}return document.addEventListener("scroll",o),document.addEventListener("resize",o),o(),()=>{document.removeEventListener("scroll",o),document.removeEventListener("resize",o)}},[e,t])}function ne({toc:e,className:n,linkClassName:t,isChild:s}){return e.length?(0,r.jsx)("ul",{className:s?void 0:n,children:e.map(e=>(0,r.jsxs)("li",{children:[(0,r.jsx)(f.A,{to:`#${e.id}`,className:t??void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,r.jsx)(ne,{isChild:!0,toc:e.children,className:n,linkClassName:t})]},e.id))}):null}const te=s.memo(ne);function se({toc:e,className:n="table-of-contents table-of-contents__left-border",linkClassName:t="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:i,maxHeadingLevel:o,...c}){const l=(0,J.p)(),d=i??l.tableOfContents.minHeadingLevel,u=o??l.tableOfContents.maxHeadingLevel,m=function({toc:e,minHeadingLevel:n,maxHeadingLevel:t}){return(0,s.useMemo)(()=>X({toc:Z(e),minHeadingLevel:n,maxHeadingLevel:t}),[e,n,t])}({toc:e,minHeadingLevel:d,maxHeadingLevel:u});return ee((0,s.useMemo)(()=>{if(t&&a)return{linkClassName:t,linkActiveClassName:a,minHeadingLevel:d,maxHeadingLevel:u}},[t,a,d,u])),(0,r.jsx)(te,{toc:m,className:n,linkClassName:t,...c})}const ae="tocCollapsibleButton_TO0P",ie="tocCollapsibleButtonExpanded_MG3E";function re({collapsed:e,...n}){return(0,r.jsx)("button",{type:"button",...n,className:(0,u.A)("clean-btn",ae,!e&&ie,n.className),children:(0,r.jsx)(h.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const oe="tocCollapsible_ETCw",ce="tocCollapsibleContent_vkbj",le="tocCollapsibleExpanded_sAul";function de({toc:e,className:n,minHeadingLevel:t,maxHeadingLevel:s}){const{collapsed:a,toggleCollapsed:i}=(0,q.u)({initialState:!0});return(0,r.jsxs)("div",{className:(0,u.A)(oe,!a&&le,n),children:[(0,r.jsx)(re,{collapsed:a,onClick:i}),(0,r.jsx)(q.N,{lazy:!0,className:ce,collapsed:a,children:(0,r.jsx)(se,{toc:e,minHeadingLevel:t,maxHeadingLevel:s})})]})}const ue="tocMobile_ITEo";function me(){const{toc:e,frontMatter:n}=l();return(0,r.jsx)(de,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:(0,u.A)(v.G.docs.docTocMobile,ue)})}const he="tableOfContents_bqdL";function fe({className:e,...n}){return(0,r.jsx)("div",{className:(0,u.A)(he,"thin-scrollbar",e),children:(0,r.jsx)(se,{...n,linkClassName:"table-of-contents__link toc-highlight",linkActiveClassName:"table-of-contents__link--active"})})}function pe(){const{toc:e,frontMatter:n}=l();return(0,r.jsx)(fe,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:v.G.docs.docTocDesktop})}var xe=t(1107),ge=t(8453),be=t(5260),je=t(2303),ve=t(5293);function Ne(){const{prism:e}=(0,J.p)(),{colorMode:n}=(0,ve.G)(),t=e.theme,s=e.darkTheme||t;return"dark"===n?s:t}var Ae=t(8426),ye=t.n(Ae);const Ce=/title=(?<quote>["'])(?<title>.*?)\1/,Le=/\{(?<range>[\d,-]+)\}/,ke={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},_e={...ke,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},we=Object.keys(ke);function Te(e,n){const t=e.map(e=>{const{start:t,end:s}=_e[e];return`(?:${t}\\s*(${n.flatMap(e=>[e.line,e.block?.start,e.block?.end].filter(Boolean)).join("|")})\\s*${s})`}).join("|");return new RegExp(`^\\s*(?:${t})\\s*$`)}function Be({showLineNumbers:e,metastring:n}){return"boolean"==typeof e?e?1:void 0:"number"==typeof e?e:function(e){const n=e?.split(" ").find(e=>e.startsWith("showLineNumbers"));if(n){if(n.startsWith("showLineNumbers=")){const e=n.replace("showLineNumbers=","");return parseInt(e,10)}return 1}}(n)}function He(e,n){const{language:t,magicComments:s}=n;if(void 0===t)return{lineClassNames:{},code:e};const a=function(e,n){switch(e){case"js":case"javascript":case"ts":case"typescript":return Te(["js","jsBlock"],n);case"jsx":case"tsx":return Te(["js","jsBlock","jsx"],n);case"html":return Te(["js","jsBlock","html"],n);case"python":case"py":case"bash":return Te(["bash"],n);case"markdown":case"md":return Te(["html","jsx","bash"],n);case"tex":case"latex":case"matlab":return Te(["tex"],n);case"lua":case"haskell":return Te(["lua"],n);case"sql":return Te(["lua","jsBlock"],n);case"wasm":return Te(["wasm"],n);case"vb":case"vba":case"visual-basic":return Te(["vb","rem"],n);case"vbnet":return Te(["vbnet","rem"],n);case"batch":return Te(["rem"],n);case"basic":return Te(["rem","f90"],n);case"fsharp":return Te(["js","ml"],n);case"ocaml":case"sml":return Te(["ml"],n);case"fortran":return Te(["f90"],n);case"cobol":return Te(["cobol"],n);default:return Te(we,n)}}(t,s),i=e.split(/\r?\n/),r=Object.fromEntries(s.map(e=>[e.className,{start:0,range:""}])),o=Object.fromEntries(s.filter(e=>e.line).map(({className:e,line:n})=>[n,e])),c=Object.fromEntries(s.filter(e=>e.block).map(({className:e,block:n})=>[n.start,e])),l=Object.fromEntries(s.filter(e=>e.block).map(({className:e,block:n})=>[n.end,e]));for(let u=0;u<i.length;){const e=i[u].match(a);if(!e){u+=1;continue}const n=e.slice(1).find(e=>void 0!==e);o[n]?r[o[n]].range+=`${u},`:c[n]?r[c[n]].start=u:l[n]&&(r[l[n]].range+=`${r[l[n]].start}-${u-1},`),i.splice(u,1)}const d={};return Object.entries(r).forEach(([e,{range:n}])=>{ye()(n).forEach(n=>{d[n]??=[],d[n].push(e)})}),{code:i.join("\n"),lineClassNames:d}}function Me(e,n){const t=e.replace(/\r?\n$/,"");return function(e,{metastring:n,magicComments:t}){if(n&&Le.test(n)){const s=n.match(Le).groups.range;if(0===t.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${n}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const a=t[0].className,i=ye()(s).filter(e=>e>0).map(e=>[e-1,[a]]);return{lineClassNames:Object.fromEntries(i),code:e}}return null}(t,{...n})??He(t,{...n})}function Ee(e){const n=function(e){return n=e.language??function(e){if(!e)return;const n=e.split(" ").find(e=>e.startsWith("language-"));return n?.replace(/language-/,"")}(e.className)??e.defaultLanguage,n?.toLowerCase()??"text";var n}({language:e.language,defaultLanguage:e.defaultLanguage,className:e.className}),{lineClassNames:t,code:s}=Me(e.code,{metastring:e.metastring,magicComments:e.magicComments,language:n}),a=function({className:e,language:n}){return(0,u.A)(e,n&&!e?.includes(`language-${n}`)&&`language-${n}`)}({className:e.className,language:n}),i=(r=e.metastring,(r?.match(Ce)?.groups.title??"")||e.title);var r;const o=Be({showLineNumbers:e.showLineNumbers,metastring:e.metastring});return{codeInput:e.code,code:s,className:a,language:n,title:i,lineNumbersStart:o,lineClassNames:t}}const Ie=(0,s.createContext)(null);function Ve({metadata:e,wordWrap:n,children:t}){const a=(0,s.useMemo)(()=>({metadata:e,wordWrap:n}),[e,n]);return(0,r.jsx)(Ie.Provider,{value:a,children:t})}function Se(){const e=(0,s.useContext)(Ie);if(null===e)throw new i.dV("CodeBlockContextProvider");return e}const Ue="codeBlockContainer_Ckt0";function ze({as:e,...n}){const t=function(e){const n={color:"--prism-color",backgroundColor:"--prism-background-color"},t={};return Object.entries(e.plain).forEach(([e,s])=>{const a=n[e];a&&"string"==typeof s&&(t[a]=s)}),t}(Ne());return(0,r.jsx)(e,{...n,style:t,className:(0,u.A)(n.className,Ue,v.G.common.codeBlock)})}const Re="codeBlock_bY9V",Oe="codeBlockStandalone_MEMb",Pe="codeBlockLines_e6Vv",De="codeBlockLinesWithNumbering_o6Pm";function Ge({children:e,className:n}){return(0,r.jsx)(ze,{as:"pre",tabIndex:0,className:(0,u.A)(Oe,"thin-scrollbar",n),children:(0,r.jsx)("code",{className:Pe,children:e})})}const Fe={attributes:!0,characterData:!0,childList:!0,subtree:!0};function $e(e,n){const[t,a]=(0,s.useState)(),r=(0,s.useCallback)(()=>{a(e.current?.closest("[role=tabpanel][hidden]"))},[e,a]);(0,s.useEffect)(()=>{r()},[r]),function(e,n,t=Fe){const a=(0,i._q)(n),r=(0,i.Be)(t);(0,s.useEffect)(()=>{const n=new MutationObserver(a);return e&&n.observe(e,r),()=>n.disconnect()},[e,a,r])}(t,e=>{e.forEach(e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(n(),r())})},{attributes:!0,characterData:!1,childList:!1,subtree:!1})}function We({children:e}){return e}var qe=t(1765);function Je({line:e,token:n,...t}){return(0,r.jsx)("span",{...t})}const Ze="codeLine_lJS_",Xe="codeLineNumber_Tfdd",Ye="codeLineContent_feaV";function Qe({line:e,classNames:n,showLineNumbers:t,getLineProps:s,getTokenProps:a}){const i=function(e){const n=1===e.length&&"\n"===e[0].content?e[0]:void 0;return n?[{...n,content:""}]:e}(e),o=s({line:i,className:(0,u.A)(n,t&&Ze)}),c=i.map((e,n)=>{const t=a({token:e});return(0,r.jsx)(Je,{...t,line:i,token:e,children:t.children},n)});return(0,r.jsxs)("span",{...o,children:[t?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:Xe}),(0,r.jsx)("span",{className:Ye,children:c})]}):c,(0,r.jsx)("br",{})]})}const Ke=s.forwardRef((e,n)=>(0,r.jsx)("pre",{ref:n,tabIndex:0,...e,className:(0,u.A)(e.className,Re,"thin-scrollbar")}));function en(e){const{metadata:n}=Se();return(0,r.jsx)("code",{...e,className:(0,u.A)(e.className,Pe,void 0!==n.lineNumbersStart&&De),style:{...e.style,counterReset:void 0===n.lineNumbersStart?void 0:"line-count "+(n.lineNumbersStart-1)}})}function nn({className:e}){const{metadata:n,wordWrap:t}=Se(),s=Ne(),{code:a,language:i,lineNumbersStart:o,lineClassNames:c}=n;return(0,r.jsx)(qe.f4,{theme:s,code:a,language:i,children:({className:n,style:s,tokens:a,getLineProps:i,getTokenProps:l})=>(0,r.jsx)(Ke,{ref:t.codeBlockRef,className:(0,u.A)(e,n),style:s,children:(0,r.jsx)(en,{children:a.map((e,n)=>(0,r.jsx)(Qe,{line:e,getLineProps:i,getTokenProps:l,classNames:c[n],showLineNumbers:void 0!==o},n))})})})}function tn({children:e,fallback:n}){return(0,je.A)()?(0,r.jsx)(r.Fragment,{children:e?.()}):n??null}function sn({className:e,...n}){return(0,r.jsx)("button",{type:"button",...n,className:(0,u.A)("clean-btn",e)})}function an(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function rn(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const on={copyButtonCopied:"copyButtonCopied_Vdqa",copyButtonIcons:"copyButtonIcons_IEyt",copyButtonIcon:"copyButtonIcon_TrPX",copyButtonSuccessIcon:"copyButtonSuccessIcon_cVMy"};function cn(e){return e?(0,h.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,h.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"})}function ln({className:e}){const{copyCode:n,isCopied:t}=function(){const{metadata:{code:e}}=Se(),[n,t]=(0,s.useState)(!1),a=(0,s.useRef)(void 0),i=(0,s.useCallback)(()=>{navigator.clipboard.writeText(e).then(()=>{t(!0),a.current=window.setTimeout(()=>{t(!1)},1e3)})},[e]);return(0,s.useEffect)(()=>()=>window.clearTimeout(a.current),[]),{copyCode:i,isCopied:n}}();return(0,r.jsx)(sn,{"aria-label":cn(t),title:(0,h.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,u.A)(e,on.copyButton,t&&on.copyButtonCopied),onClick:n,children:(0,r.jsxs)("span",{className:on.copyButtonIcons,"aria-hidden":"true",children:[(0,r.jsx)(an,{className:on.copyButtonIcon}),(0,r.jsx)(rn,{className:on.copyButtonSuccessIcon})]})})}function dn(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const un="wordWrapButtonIcon_b1P5",mn="wordWrapButtonEnabled_uzNF";function hn({className:e}){const{wordWrap:n}=Se();if(!(n.isEnabled||n.isCodeScrollable))return!1;const t=(0,h.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,r.jsx)(sn,{onClick:()=>n.toggle(),className:(0,u.A)(e,n.isEnabled&&mn),"aria-label":t,title:t,children:(0,r.jsx)(dn,{className:un,"aria-hidden":"true"})})}const fn="buttonGroup_M5ko";function pn({className:e}){return(0,r.jsx)(tn,{children:()=>(0,r.jsxs)("div",{className:(0,u.A)(e,fn),children:[(0,r.jsx)(hn,{}),(0,r.jsx)(ln,{})]})})}const xn="codeBlockContent_QJqH",gn="codeBlockTitle_OeMC";function bn({className:e}){const{metadata:n}=Se();return(0,r.jsxs)(ze,{as:"div",className:(0,u.A)(e,n.className),children:[n.title&&(0,r.jsx)("div",{className:gn,children:(0,r.jsx)(We,{children:n.title})}),(0,r.jsxs)("div",{className:xn,children:[(0,r.jsx)(nn,{}),(0,r.jsx)(pn,{})]})]})}function jn(e){const n=function(e){const{prism:n}=(0,J.p)();return Ee({code:e.children,className:e.className,metastring:e.metastring,magicComments:n.magicComments,defaultLanguage:n.defaultLanguage,language:e.language,title:e.title,showLineNumbers:e.showLineNumbers})}(e),t=function(){const[e,n]=(0,s.useState)(!1),[t,a]=(0,s.useState)(!1),i=(0,s.useRef)(null),r=(0,s.useCallback)(()=>{const t=i.current.querySelector("code");e?t.removeAttribute("style"):(t.style.whiteSpace="pre-wrap",t.style.overflowWrap="anywhere"),n(e=>!e)},[i,e]),o=(0,s.useCallback)(()=>{const{scrollWidth:e,clientWidth:n}=i.current,t=e>n||i.current.querySelector("code").hasAttribute("style");a(t)},[i]);return $e(i,o),(0,s.useEffect)(()=>{o()},[e,o]),(0,s.useEffect)(()=>(window.addEventListener("resize",o,{passive:!0}),()=>{window.removeEventListener("resize",o)}),[o]),{codeBlockRef:i,isEnabled:e,isCodeScrollable:t,toggle:r}}();return(0,r.jsx)(Ve,{metadata:n,wordWrap:t,children:(0,r.jsx)(bn,{})})}function vn({children:e,...n}){const t=(0,je.A)(),a=function(e){return s.Children.toArray(e).some(e=>(0,s.isValidElement)(e))?e:Array.isArray(e)?e.join(""):e}(e),i="string"==typeof a?jn:Ge;return(0,r.jsx)(i,{...n,children:a},String(t))}function Nn(e){return(0,r.jsx)("code",{...e})}var An=t(3535);var yn=t(3427);const Cn="details_lb9f",Ln="isBrowser_bmU9",kn="collapsibleContent_i85q";function _n(e){return!!e&&("SUMMARY"===e.tagName||_n(e.parentElement))}function wn(e,n){return!!e&&(e===n||wn(e.parentElement,n))}function Tn({summary:e,children:n,...t}){(0,yn.A)().collectAnchor(t.id);const a=(0,je.A)(),i=(0,s.useRef)(null),{collapsed:o,setCollapsed:c}=(0,q.u)({initialState:!t.open}),[l,d]=(0,s.useState)(t.open),m=s.isValidElement(e)?e:(0,r.jsx)("summary",{children:e??"Details"});return(0,r.jsxs)("details",{...t,ref:i,open:l,"data-collapsed":o,className:(0,u.A)(Cn,a&&Ln,t.className),onMouseDown:e=>{_n(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const n=e.target;_n(n)&&wn(n,i.current)&&(e.preventDefault(),o?(c(!1),d(!0)):c(!0))},children:[m,(0,r.jsx)(q.N,{lazy:!1,collapsed:o,onCollapseTransitionEnd:e=>{c(e),d(!e)},children:(0,r.jsx)("div",{className:kn,children:n})})]})}const Bn="details_b_Ee";function Hn({...e}){return(0,r.jsx)(Tn,{...e,className:(0,u.A)("alert alert--info",Bn,e.className)})}function Mn(e){const n=s.Children.toArray(e.children),t=n.find(e=>s.isValidElement(e)&&"summary"===e.type),a=(0,r.jsx)(r.Fragment,{children:n.filter(e=>e!==t)});return(0,r.jsx)(Hn,{...e,summary:t,children:a})}function En(e){return(0,r.jsx)(xe.A,{...e})}const In="containsTaskList_mC6p";function Vn(e){if(void 0!==e)return(0,u.A)(e,e?.includes("contains-task-list")&&In)}const Sn="img_ev3q";function Un(e){const{mdxAdmonitionTitle:n,rest:t}=function(e){const n=s.Children.toArray(e),t=n.find(e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type),a=n.filter(e=>e!==t),i=t?.props.children;return{mdxAdmonitionTitle:i,rest:a.length>0?(0,r.jsx)(r.Fragment,{children:a}):null}}(e.children),a=e.title??n;return{...e,...a&&{title:a},children:t}}const zn="admonition_xJq3",Rn="admonitionHeading_Gvgb",On="admonitionIcon_Rf37",Pn="admonitionContent_BuS1";function Dn({type:e,className:n,children:t}){return(0,r.jsx)("div",{className:(0,u.A)(v.G.common.admonition,v.G.common.admonitionType(e),zn,n),children:t})}function Gn({icon:e,title:n}){return(0,r.jsxs)("div",{className:Rn,children:[(0,r.jsx)("span",{className:On,children:e}),n]})}function Fn({children:e}){return e?(0,r.jsx)("div",{className:Pn,children:e}):null}function $n(e){const{type:n,icon:t,title:s,children:a,className:i}=e;return(0,r.jsxs)(Dn,{type:n,className:i,children:[s||t?(0,r.jsx)(Gn,{title:s,icon:t}):null,(0,r.jsx)(Fn,{children:a})]})}function Wn(e){return(0,r.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const qn={icon:(0,r.jsx)(Wn,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function Jn(e){return(0,r.jsx)($n,{...qn,...e,className:(0,u.A)("alert alert--secondary",e.className),children:e.children})}function Zn(e){return(0,r.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const Xn={icon:(0,r.jsx)(Zn,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function Yn(e){return(0,r.jsx)($n,{...Xn,...e,className:(0,u.A)("alert alert--success",e.className),children:e.children})}function Qn(e){return(0,r.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const Kn={icon:(0,r.jsx)(Qn,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function et(e){return(0,r.jsx)($n,{...Kn,...e,className:(0,u.A)("alert alert--info",e.className),children:e.children})}function nt(e){return(0,r.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const tt={icon:(0,r.jsx)(nt,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function st(e){return(0,r.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const at={icon:(0,r.jsx)(st,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const it={icon:(0,r.jsx)(nt,{}),title:(0,r.jsx)(h.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const rt={...{note:Jn,tip:Yn,info:et,warning:function(e){return(0,r.jsx)($n,{...tt,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,r.jsx)($n,{...at,...e,className:(0,u.A)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,r.jsx)(Jn,{title:"secondary",...e}),important:e=>(0,r.jsx)(et,{title:"important",...e}),success:e=>(0,r.jsx)(Yn,{title:"success",...e}),caution:function(e){return(0,r.jsx)($n,{...it,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})}}};function ot(e){const n=Un(e),t=(s=n.type,rt[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),rt.info));var s;return(0,r.jsx)(t,{...n})}var ct=t(418);const lt={Head:be.A,details:Mn,Details:Mn,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every(e=>"string"==typeof e&&!e.includes("\n"))}(e)?(0,r.jsx)(Nn,{...e}):(0,r.jsx)(vn,{...e})},a:function(e){const n=(0,An.v)(e.id);return(0,r.jsx)(f.A,{...e,className:(0,u.A)(n,e.className)})},pre:function(e){return(0,r.jsx)(r.Fragment,{children:e.children})},ul:function(e){return(0,r.jsx)("ul",{...e,className:Vn(e.className)})},li:function(e){(0,yn.A)().collectAnchor(e.id);const n=(0,An.v)(e.id);return(0,r.jsx)("li",{className:(0,u.A)(n,e.className),...e})},img:function(e){return(0,r.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(n=e.className,(0,u.A)(n,Sn))});var n},h1:e=>(0,r.jsx)(En,{as:"h1",...e}),h2:e=>(0,r.jsx)(En,{as:"h2",...e}),h3:e=>(0,r.jsx)(En,{as:"h3",...e}),h4:e=>(0,r.jsx)(En,{as:"h4",...e}),h5:e=>(0,r.jsx)(En,{as:"h5",...e}),h6:e=>(0,r.jsx)(En,{as:"h6",...e}),admonition:ot,mermaid:ct.A};function dt({children:e}){return(0,r.jsx)(ge.x,{components:lt,children:e})}function ut({children:e}){const n=function(){const{metadata:e,frontMatter:n,contentTitle:t}=l();return n.hide_title||void 0!==t?null:e.title}();return(0,r.jsxs)("div",{className:(0,u.A)(v.G.docs.docMarkdown,"markdown"),children:[n&&(0,r.jsx)("header",{children:(0,r.jsx)(xe.A,{as:"h1",children:n})}),(0,r.jsx)(dt,{children:e})]})}var mt=t(4718),ht=t(9169),ft=t(6025);function pt(e){return(0,r.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,r.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const xt="breadcrumbHomeIcon_YNFT";function gt(){const e=(0,ft.Ay)("/");return(0,r.jsx)("li",{className:"breadcrumbs__item",children:(0,r.jsx)(f.A,{"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,r.jsx)(pt,{className:xt})})})}function bt(e){const n=function({breadcrumbs:e}){const{siteConfig:n}=(0,b.A)();return{"@context":"https://schema.org","@type":"BreadcrumbList",itemListElement:e.filter(e=>e.href).map((e,t)=>({"@type":"ListItem",position:t+1,name:e.label,item:`${n.url}${e.href}`}))}}({breadcrumbs:e.breadcrumbs});return(0,r.jsx)(be.A,{children:(0,r.jsx)("script",{type:"application/ld+json",children:JSON.stringify(n)})})}const jt="breadcrumbsContainer_Z_bl";function vt({children:e,href:n,isLast:t}){const s="breadcrumbs__link";return t?(0,r.jsx)("span",{className:s,children:e}):n?(0,r.jsx)(f.A,{className:s,href:n,children:(0,r.jsx)("span",{children:e})}):(0,r.jsx)("span",{className:s,children:e})}function Nt({children:e,active:n}){return(0,r.jsx)("li",{className:(0,u.A)("breadcrumbs__item",{"breadcrumbs__item--active":n}),children:e})}function At(){const e=(0,mt.OF)(),n=(0,ht.Dt)();return e?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(bt,{breadcrumbs:e}),(0,r.jsx)("nav",{className:(0,u.A)(v.G.docs.docBreadcrumbs,jt),"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,r.jsxs)("ul",{className:"breadcrumbs",children:[n&&(0,r.jsx)(gt,{}),e.map((n,t)=>{const s=t===e.length-1,a="category"===n.type&&n.linkUnlisted?void 0:n.href;return(0,r.jsx)(Nt,{active:s,children:(0,r.jsx)(vt,{href:a,isLast:s,children:n.label})},t)})]})})]}):null}function yt(){return(0,r.jsx)(h.A,{id:"theme.contentVisibility.unlistedBanner.title",description:"The unlisted content banner title",children:"Unlisted page"})}function Ct(){return(0,r.jsx)(h.A,{id:"theme.contentVisibility.unlistedBanner.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function Lt(){return(0,r.jsx)(be.A,{children:(0,r.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}function kt(){return(0,r.jsx)(h.A,{id:"theme.contentVisibility.draftBanner.title",description:"The draft content banner title",children:"Draft page"})}function _t(){return(0,r.jsx)(h.A,{id:"theme.contentVisibility.draftBanner.message",description:"The draft content banner message",children:"This page is a draft. It will only be visible in dev and be excluded from the production build."})}function wt({className:e}){return(0,r.jsx)(ot,{type:"caution",title:(0,r.jsx)(kt,{}),className:(0,u.A)(e,v.G.common.draftBanner),children:(0,r.jsx)(_t,{})})}function Tt({className:e}){return(0,r.jsx)(ot,{type:"caution",title:(0,r.jsx)(yt,{}),className:(0,u.A)(e,v.G.common.unlistedBanner),children:(0,r.jsx)(Ct,{})})}function Bt(e){return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(Lt,{}),(0,r.jsx)(Tt,{...e})]})}function Ht({metadata:e}){const{unlisted:n,frontMatter:t}=e;return(0,r.jsxs)(r.Fragment,{children:[(n||t.unlisted)&&(0,r.jsx)(Bt,{}),t.draft&&(0,r.jsx)(wt,{})]})}const Mt="docItemContainer_Djhp",Et="docItemCol_VOVn";function It({children:e}){const n=function(){const{frontMatter:e,toc:n}=l(),t=(0,m.l)(),s=e.hide_table_of_contents,a=!s&&n.length>0;return{hidden:s,mobile:a?(0,r.jsx)(me,{}):void 0,desktop:!a||"desktop"!==t&&"ssr"!==t?void 0:(0,r.jsx)(pe,{})}}(),{metadata:t}=l();return(0,r.jsxs)("div",{className:"row",children:[(0,r.jsxs)("div",{className:(0,u.A)("col",!n.hidden&&Et),children:[(0,r.jsx)(Ht,{metadata:t}),(0,r.jsx)(_,{}),(0,r.jsxs)("div",{className:Mt,children:[(0,r.jsxs)("article",{children:[(0,r.jsx)(At,{}),(0,r.jsx)(w,{}),n.mobile,(0,r.jsx)(ut,{children:e}),(0,r.jsx)(W,{})]}),(0,r.jsx)(g,{})]})]}),n.desktop&&(0,r.jsx)("div",{className:"col col--3",children:n.desktop})]})}function Vt(e){const n=`docs-doc-id-${e.content.metadata.id}`,t=e.content;return(0,r.jsx)(c,{content:e.content,children:(0,r.jsxs)(a.e3,{className:n,children:[(0,r.jsx)(d,{}),(0,r.jsx)(It,{children:(0,r.jsx)(t,{})})]})})}},8426(e,n){function t(e){let n,t=[];for(let s of e.split(",").map(e=>e.trim()))if(/^-?\d+$/.test(s))t.push(parseInt(s,10));else if(n=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,a,i]=n;if(s&&i){s=parseInt(s),i=parseInt(i);const e=s<i?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(i+=e);for(let n=s;n!==i;n+=e)t.push(n)}}return t}n.default=t,e.exports=t},8453(e,n,t){"use strict";t.d(n,{R:()=>r,x:()=>o});var s=t(6540);const a={},i=s.createContext(a);function r(e){const n=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1db64337.ab5ebde9.js b/assets/js/1db64337.ab5ebde9.js new file mode 100644 index 0000000..c5e73f7 --- /dev/null +++ b/assets/js/1db64337.ab5ebde9.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[413],{6785(e,r,n){n.r(r),n.d(r,{assets:()=>c,contentTitle:()=>d,default:()=>a,frontMatter:()=>t,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"overview","title":"CmdForge Overview","description":"A lightweight personal tool builder for AI-powered CLI commands.","source":"@site/docs/overview.md","sourceDirName":".","slug":"/","permalink":"/rob/CmdForge/","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","sidebar_position":1},"sidebar":"docs","next":{"title":"CmdForge Architecture","permalink":"/rob/CmdForge/architecture"}}');var i=n(4848),o=n(8453);const t={slug:"/",sidebar_position:1},d="CmdForge Overview",c={},l=[{value:"Project Links",id:"project-links",level:2},{value:"Components",id:"components",level:2},{value:"Key Directories",id:"key-directories",level:2},{value:"Development (AI-Server)",id:"development-ai-server",level:3},{value:"Production (OpenMediaVault)",id:"production-openmediavault",level:3},{value:"Recent Changes",id:"recent-changes",level:2}];function h(e){const r={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.header,{children:(0,i.jsx)(r.h1,{id:"cmdforge-overview",children:"CmdForge Overview"})}),"\n",(0,i.jsx)(r.p,{children:"A lightweight personal tool builder for AI-powered CLI commands."}),"\n",(0,i.jsx)(r.h2,{id:"project-links",children:"Project Links"}),"\n",(0,i.jsxs)(r.table,{children:[(0,i.jsx)(r.thead,{children:(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.th,{children:"Resource"}),(0,i.jsx)(r.th,{children:"URL"})]})}),(0,i.jsxs)(r.tbody,{children:[(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Public Website"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://cmdforge.brrd.tech/",children:"https://cmdforge.brrd.tech/"})})]}),(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Git Repository"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://gitea.brrd.tech/rob/CmdForge",children:"https://gitea.brrd.tech/rob/CmdForge"})})]}),(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Registry Repo"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://gitea.brrd.tech/rob/CmdForge-Registry",children:"https://gitea.brrd.tech/rob/CmdForge-Registry"})})]})]})]}),"\n",(0,i.jsx)(r.h2,{id:"components",children:"Components"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 CmdForge \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 CLI + GUI \u2502 Web UI \u2502 Registry \u2502\n\u2502 (cmdforge) \u2502 (Flask) \u2502 (API + DB) \u2502\n\u2502 (cf picker) \u2502 \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Local install \u2502 cmdforge.brrd. \u2502 Tool publishing \u2502\n\u2502 ~/.cmdforge/ \u2502 tech \u2502 Search, download \u2502\n\u2502 PySide6 desktop \u2502 \u2502 User accounts \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,i.jsx)(r.h2,{id:"key-directories",children:"Key Directories"}),"\n",(0,i.jsx)(r.h3,{id:"development-ai-server",children:"Development (AI-Server)"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"~/PycharmProjects/CmdForge/ # Source code\n~/.cmdforge/ # Local tools storage\n~/.local/bin/cmdforge # CLI symlink\n"})}),"\n",(0,i.jsx)(r.h3,{id:"production-openmediavault",children:"Production (OpenMediaVault)"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"/srv/mergerfs/data_pool/home/rob/cmdforge-registry/ # Deployed code\n/tmp/cmdforge-data/ # Runtime database\n"})}),"\n",(0,i.jsx)(r.h2,{id:"recent-changes",children:"Recent Changes"}),"\n",(0,i.jsxs)(r.ul,{children:["\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-02-02"}),": ",(0,i.jsx)(r.strong,{children:"Semantic Search (AI)"})," - Find tools by describing what you need in natural language using Ollama embeddings (nomic-embed-text). Available via CLI (",(0,i.jsx)(r.code,{children:"cmdforge registry describe"}),'), GUI ("Describe what you need" input), and API (',(0,i.jsx)(r.code,{children:"/api/v1/tools/semantic-search"}),")"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-26"}),": ",(0,i.jsxs)(r.strong,{children:["CLI ",(0,i.jsx)(r.code,{children:"remove"})," command"]})," - Added ",(0,i.jsx)(r.code,{children:"cmdforge remove <tool>"})," to remove dependencies from manifest"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-26"}),": ",(0,i.jsxs)(r.strong,{children:["Improved ",(0,i.jsx)(r.code,{children:"add"})," UX"]})," - ",(0,i.jsx)(r.code,{children:"cmdforge add"}),' now shows "Already installed" for local tools instead of registry errors']}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-26"}),": ",(0,i.jsx)(r.strong,{children:"Hash verification fix"})," - Fixed content hash mismatch for registry tools"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-18"}),": ",(0,i.jsx)(r.strong,{children:"Interactive Tool Picker"})," - Added ",(0,i.jsx)(r.code,{children:"cf"})," command for fuzzy-search tool selection with piping support"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-17"}),": ",(0,i.jsx)(r.strong,{children:"Collections CLI"})," - Added ",(0,i.jsx)(r.code,{children:"cmdforge collections list/info/install"})," commands"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-17"}),": ",(0,i.jsx)(r.strong,{children:"Admin collections UI"})," - Web dashboard for managing tool collections"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": ",(0,i.jsx)(r.strong,{children:"GUI conversion"})," - Replaced urwid TUI with PySide6 desktop GUI"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": Modern GUI with sidebar navigation (My Tools, Registry, Providers)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Tool Builder for creating/editing tools visually"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Registry browser with search and one-click install"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Connect dialog with polling-based account pairing"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": App pairing - connect GUI to web account without manual token copying"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": ",(0,i.jsx)(r.code,{children:"cmdforge config connect <username>"})," command for CLI-based pairing"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),': "Connections" dashboard replaces "API Tokens" for simpler app management']}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": Private tool sync - auto-publish tools privately when connected"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Tool search and filtering with faceted results"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Docker containers: ",(0,i.jsx)(r.code,{children:"Dockerfile.ready"})," (pre-installed), ",(0,i.jsx)(r.code,{children:"Dockerfile.test-install"})," (fresh)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Interactive installer script (",(0,i.jsx)(r.code,{children:"install.sh"}),")"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Database migration system (auto-adds missing columns)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Gunicorn production server (replaced Flask dev server)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": CI/CD auto-deploy via Gitea webhook"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Full ToolSource support in registry (source_json)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Improved error messages with line numbers and call stacks"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-03"}),": Migrated from SmartTools to CmdForge"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-03"}),": Added source field support for Fabric imports"]}),"\n"]})]})}function a(e={}){const{wrapper:r}={...(0,o.R)(),...e.components};return r?(0,i.jsx)(r,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453(e,r,n){n.d(r,{R:()=>t,x:()=>d});var s=n(6540);const i={},o=s.createContext(i);function t(e){const r=s.useContext(o);return s.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),s.createElement(o.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1db64337.aca18eaa.js b/assets/js/1db64337.aca18eaa.js deleted file mode 100644 index a79bf49..0000000 --- a/assets/js/1db64337.aca18eaa.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[413],{6785(e,r,n){n.r(r),n.d(r,{assets:()=>l,contentTitle:()=>d,default:()=>a,frontMatter:()=>t,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"overview","title":"CmdForge Overview","description":"A lightweight personal tool builder for AI-powered CLI commands.","source":"@site/docs/overview.md","sourceDirName":".","slug":"/","permalink":"/rob/CmdForge/","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"slug":"/","sidebar_position":1},"sidebar":"docs","next":{"title":"CmdForge Architecture","permalink":"/rob/CmdForge/architecture"}}');var i=n(4848),o=n(8453);const t={slug:"/",sidebar_position:1},d="CmdForge Overview",l={},c=[{value:"Project Links",id:"project-links",level:2},{value:"Components",id:"components",level:2},{value:"Key Directories",id:"key-directories",level:2},{value:"Development (AI-Server)",id:"development-ai-server",level:3},{value:"Production (OpenMediaVault)",id:"production-openmediavault",level:3},{value:"Recent Changes",id:"recent-changes",level:2}];function h(e){const r={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.header,{children:(0,i.jsx)(r.h1,{id:"cmdforge-overview",children:"CmdForge Overview"})}),"\n",(0,i.jsx)(r.p,{children:"A lightweight personal tool builder for AI-powered CLI commands."}),"\n",(0,i.jsx)(r.h2,{id:"project-links",children:"Project Links"}),"\n",(0,i.jsxs)(r.table,{children:[(0,i.jsx)(r.thead,{children:(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.th,{children:"Resource"}),(0,i.jsx)(r.th,{children:"URL"})]})}),(0,i.jsxs)(r.tbody,{children:[(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Public Website"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://cmdforge.brrd.tech/",children:"https://cmdforge.brrd.tech/"})})]}),(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Git Repository"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://gitea.brrd.tech/rob/CmdForge",children:"https://gitea.brrd.tech/rob/CmdForge"})})]}),(0,i.jsxs)(r.tr,{children:[(0,i.jsx)(r.td,{children:(0,i.jsx)(r.strong,{children:"Registry Repo"})}),(0,i.jsx)(r.td,{children:(0,i.jsx)(r.a,{href:"https://gitea.brrd.tech/rob/CmdForge-Registry",children:"https://gitea.brrd.tech/rob/CmdForge-Registry"})})]})]})]}),"\n",(0,i.jsx)(r.h2,{id:"components",children:"Components"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 CmdForge \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 CLI + GUI \u2502 Web UI \u2502 Registry \u2502\n\u2502 (cmdforge) \u2502 (Flask) \u2502 (API + DB) \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Local install \u2502 cmdforge.brrd. \u2502 Tool publishing \u2502\n\u2502 ~/.cmdforge/ \u2502 tech \u2502 Search, download \u2502\n\u2502 PySide6 desktop \u2502 \u2502 User accounts \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,i.jsx)(r.h2,{id:"key-directories",children:"Key Directories"}),"\n",(0,i.jsx)(r.h3,{id:"development-ai-server",children:"Development (AI-Server)"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"~/PycharmProjects/CmdForge/ # Source code\n~/.cmdforge/ # Local tools storage\n~/.local/bin/cmdforge # CLI symlink\n"})}),"\n",(0,i.jsx)(r.h3,{id:"production-openmediavault",children:"Production (OpenMediaVault)"}),"\n",(0,i.jsx)(r.pre,{children:(0,i.jsx)(r.code,{children:"/srv/mergerfs/data_pool/home/rob/cmdforge-registry/ # Deployed code\n/tmp/cmdforge-data/ # Runtime database\n"})}),"\n",(0,i.jsx)(r.h2,{id:"recent-changes",children:"Recent Changes"}),"\n",(0,i.jsxs)(r.ul,{children:["\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-17"}),": ",(0,i.jsx)(r.strong,{children:"Collections CLI"})," - Added ",(0,i.jsx)(r.code,{children:"cmdforge collections list/info/install"})," commands"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-17"}),": ",(0,i.jsx)(r.strong,{children:"Admin collections UI"})," - Web dashboard for managing tool collections"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": ",(0,i.jsx)(r.strong,{children:"GUI conversion"})," - Replaced urwid TUI with PySide6 desktop GUI"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": Modern GUI with sidebar navigation (My Tools, Registry, Providers)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Tool Builder for creating/editing tools visually"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Registry browser with search and one-click install"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": GUI Connect dialog with polling-based account pairing"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": App pairing - connect GUI to web account without manual token copying"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": ",(0,i.jsx)(r.code,{children:"cmdforge config connect <username>"})," command for CLI-based pairing"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),': "Connections" dashboard replaces "API Tokens" for simpler app management']}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-14"}),": Private tool sync - auto-publish tools privately when connected"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Tool search and filtering with faceted results"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Docker containers: ",(0,i.jsx)(r.code,{children:"Dockerfile.ready"})," (pre-installed), ",(0,i.jsx)(r.code,{children:"Dockerfile.test-install"})," (fresh)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Interactive installer script (",(0,i.jsx)(r.code,{children:"install.sh"}),")"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Database migration system (auto-adds missing columns)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Gunicorn production server (replaced Flask dev server)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": CI/CD auto-deploy via Gitea webhook"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Full ToolSource support in registry (source_json)"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-13"}),": Improved error messages with line numbers and call stacks"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-03"}),": Migrated from SmartTools to CmdForge"]}),"\n",(0,i.jsxs)(r.li,{children:[(0,i.jsx)(r.strong,{children:"2026-01-03"}),": Added source field support for Fabric imports"]}),"\n"]})]})}function a(e={}){const{wrapper:r}={...(0,o.R)(),...e.components};return r?(0,i.jsx)(r,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453(e,r,n){n.d(r,{R:()=>t,x:()=>d});var s=n(6540);const i={},o=s.createContext(i);function t(e){const r=s.useContext(o);return s.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),s.createElement(o.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1db78e9f.338adddd.js b/assets/js/1db78e9f.338adddd.js deleted file mode 100644 index e272b11..0000000 --- a/assets/js/1db78e9f.338adddd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[393],{8363(e,s,i){i.r(s),i.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>r,frontMatter:()=>n,metadata:()=>t,toc:()=>o});const t=JSON.parse('{"id":"todos","title":"CmdForge TODOs","description":"Active Tasks","source":"@site/docs/todos.md","sourceDirName":".","slug":"/todos","permalink":"/rob/CmdForge/todos","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":6,"frontMatter":{"type":"todos","project":"cmdforge","updated":"2026-01-17T00:00:00.000Z","sidebar_position":6},"sidebar":"docs","previous":{"title":"Web UI Design","permalink":"/rob/CmdForge/reference/web-ui-spec"},"next":{"title":"Goals","permalink":"/rob/CmdForge/goals"}}');var c=i(4848),l=i(8453);const n={type:"todos",project:"cmdforge",updated:new Date("2026-01-17T00:00:00.000Z"),sidebar_position:6},d="CmdForge TODOs",a={},o=[{value:"Active Tasks",id:"active-tasks",level:2},{value:"Low Priority",id:"low-priority",level:3},{value:"Completed",id:"completed",level:2},{value:"Ideas / Backlog",id:"ideas--backlog",level:2},{value:"Known Issues",id:"known-issues",level:2}];function h(e){const s={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",input:"input",li:"li",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.header,{children:(0,c.jsx)(s.h1,{id:"cmdforge-todos",children:"CmdForge TODOs"})}),"\n",(0,c.jsx)(s.h2,{id:"active-tasks",children:"Active Tasks"}),"\n",(0,c.jsx)(s.h3,{id:"low-priority",children:"Low Priority"}),"\n",(0,c.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Email verification for registration"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Video embed component for tutorials"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Schema.org structured data for SEO"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",disabled:!0})," ","PWA features (offline support, install prompt)"]}),"\n"]}),"\n",(0,c.jsx)(s.h2,{id:"completed",children:"Completed"}),"\n",(0,c.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Project dependency system (",(0,c.jsx)(s.code,{children:"cmdforge install"}),") @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ",(0,c.jsx)(s.code,{children:"cmdforge add"})," command @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Dependency resolution for meta-tools @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Password reset flow @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Collections CLI commands (",(0,c.jsx)(s.code,{children:"cmdforge collections list/info/install"}),") @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Admin collections management UI @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Improve error messages and debugging @M1 #medium (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Set up CI/CD pipeline with Gitea webhook @M1 #medium (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Add source field display to web UI @M1 #medium (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Set up gunicorn for production server @M1 #medium (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Enable systemd linger for service persistence @M1 #medium (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Fix Dockerfile - remove docs/ symlink copy #medium (2026-01-10)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Create public documentation with Docusaurus @M1 #medium (2026-01-05)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Set up systemd service on production @M1 #medium (2025-12-05)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Migrate from SmartTools to CmdForge naming #medium (2025-12-15)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Add ToolSource dataclass for attribution #medium (2025-12-10)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Create Fabric import script #medium (2025-12-08)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Fix database persistence with backup/restore #medium (2025-12-03)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Update cron jobs to use cmdforge names #medium (2025-12-01)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Implement YAML tool definition system @M0 #medium (2025-12-01)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Create CLI entry point and subcommands @M0 #medium (2025-11-15)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Build provider abstraction layer @M0 #medium (2025-11-10)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Add offline caching for tools @M0 #medium (2025-11-05)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Create web UI for tool browsing @M0 #medium (2025-10-20)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool execution engine @M0 #medium (2025-10-15)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","YAML tool definition system @M0 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","CLI entry point and subcommands @M0 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provider abstraction layer @M0 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Offline caching for tools @M0 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Web UI for tool browsing @M0 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Public documentation @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Systemd service setup @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Gunicorn production server @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Systemd linger for persistence @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","CI/CD pipeline @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Error message improvements @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Source field display in web UI @M1 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","TUI Registry browser @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","TUI Publishing with token input @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Docker containers (test + ready) @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Interactive installer script @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Database migration system @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool search and filtering @M2 #high (2026-01-13)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","App pairing/connection flow @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Registry curation system @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","PySide6 GUI conversion @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","GUI Registry browser @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","GUI Publishing with connect flow @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool ratings/reviews @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool marketplace UI enhancements @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","AI persona profiles @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","AI-assisted code generation @M2 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Import Fabric patterns (233 total) @M3 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Scheduled Fabric repo sync @M3 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Auto-vetting pipeline integration @M3 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Community tool submissions workflow @M3 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Duplicate detection automation @M3 #high (2026-01-14)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Collections CLI commands @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Visual node-based step editor @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool visualization improvements @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Drag-and-drop step reordering @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool composition and chaining UI @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Auto-populate dependencies for ToolStep in GUI @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ",(0,c.jsx)(s.code,{children:"--auto-install"})," flag for runtime dependency installation @M4 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Interactive onboarding walkthroughs @M4 #medium (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Project dependency system (",(0,c.jsx)(s.code,{children:"cmdforge install"}),") @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ",(0,c.jsx)(s.code,{children:"cmdforge add"})," command @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Dependency resolution for meta-tools @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool versioning support @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Version constraints in manifests @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Simple theming (external QSS files) @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Dark mode @M5 #high (2026-01-17)"]}),"\n",(0,c.jsxs)(s.li,{className:"task-list-item",children:[(0,c.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool testing framework @M5 #high (2026-01-17)"]}),"\n"]}),"\n",(0,c.jsx)(s.h2,{id:"ideas--backlog",children:"Ideas / Backlog"}),"\n",(0,c.jsxs)(s.ul,{children:["\n",(0,c.jsx)(s.li,{children:"Tool usage analytics"}),"\n",(0,c.jsx)(s.li,{children:"GUI tool builder (visual YAML editor)"}),"\n",(0,c.jsx)(s.li,{children:"VS Code extension"}),"\n",(0,c.jsx)(s.li,{children:"Provider auto-detection"}),"\n",(0,c.jsx)(s.li,{children:"Parallel tool step execution"}),"\n",(0,c.jsx)(s.li,{children:"Conditional step execution (skip based on conditions)"}),"\n",(0,c.jsx)(s.li,{children:"Tool aliases (shorthand names for frequently used tools)"}),"\n",(0,c.jsx)(s.li,{children:"Output caching for identical inputs"}),"\n",(0,c.jsx)(s.li,{children:"CDN setup for static assets"}),"\n",(0,c.jsx)(s.li,{children:"Accessibility testing (WCAG 2.1 AA formal verification)"}),"\n",(0,c.jsx)(s.li,{children:"Newsletter signup with double opt-in"}),"\n",(0,c.jsx)(s.li,{children:"A/B testing for landing page"}),"\n",(0,c.jsx)(s.li,{children:"Premium publisher tiers"}),"\n",(0,c.jsx)(s.li,{children:"Internationalization (i18n)"}),"\n"]}),"\n",(0,c.jsx)(s.h2,{id:"known-issues",children:"Known Issues"}),"\n",(0,c.jsxs)(s.table,{children:[(0,c.jsx)(s.thead,{children:(0,c.jsxs)(s.tr,{children:[(0,c.jsx)(s.th,{children:"Issue"}),(0,c.jsx)(s.th,{children:"Status"}),(0,c.jsx)(s.th,{children:"Workaround"})]})}),(0,c.jsxs)(s.tbody,{children:[(0,c.jsxs)(s.tr,{children:[(0,c.jsx)(s.td,{children:"MergerFS SQLite limitation"}),(0,c.jsx)(s.td,{children:"Resolved"}),(0,c.jsx)(s.td,{children:"Database moved to /var/tmp on root filesystem"})]}),(0,c.jsxs)(s.tr,{children:[(0,c.jsx)(s.td,{children:"Service persistence"}),(0,c.jsx)(s.td,{children:"Resolved"}),(0,c.jsx)(s.td,{children:"Systemd linger now enabled"})]}),(0,c.jsxs)(s.tr,{children:[(0,c.jsx)(s.td,{children:"Flask dev server"}),(0,c.jsx)(s.td,{children:"Resolved"}),(0,c.jsx)(s.td,{children:"Now using gunicorn for production"})]})]})]})]})}function r(e={}){const{wrapper:s}={...(0,l.R)(),...e.components};return s?(0,c.jsx)(s,{...e,children:(0,c.jsx)(h,{...e})}):h(e)}},8453(e,s,i){i.d(s,{R:()=>n,x:()=>d});var t=i(6540);const c={},l=t.createContext(c);function n(e){const s=t.useContext(l);return t.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function d(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(c):e.components||c:n(e.components),t.createElement(l.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/237.447ba118.js b/assets/js/237.447ba118.js deleted file mode 100644 index 9259147..0000000 --- a/assets/js/237.447ba118.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[237],{2237(e,t,i){i.r(t),i.d(t,{default:()=>l});i(6540);var o=i(1312),n=i(5500),s=i(1656),r=i(3363),a=i(4848);function l(){const e=(0,o.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.be,{title:e}),(0,a.jsx)(s.A,{children:(0,a.jsx)(r.A,{})})]})}},3363(e,t,i){i.d(t,{A:()=>a});i(6540);var o=i(4164),n=i(1312),s=i(1107),r=i(4848);function a({className:e}){return(0,r.jsx)("main",{className:(0,o.A)("container margin-vert--xl",e),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,r.jsx)(n.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(n.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(n.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/assets/js/237.46c4f719.js b/assets/js/237.46c4f719.js new file mode 100644 index 0000000..31f6fbb --- /dev/null +++ b/assets/js/237.46c4f719.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[237],{3363(e,t,i){i.d(t,{A:()=>a});i(6540);var o=i(4164),n=i(1312),s=i(1107),r=i(4848);function a({className:e}){return(0,r.jsx)("main",{className:(0,o.A)("container margin-vert--xl",e),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,r.jsx)(n.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(n.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(n.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},2237(e,t,i){i.r(t),i.d(t,{default:()=>l});i(6540);var o=i(1312),n=i(5500),s=i(1656),r=i(3363),a=i(4848);function l(){const e=(0,o.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.be,{title:e}),(0,a.jsx)(s.A,{children:(0,a.jsx)(r.A,{})})]})}}}]); \ No newline at end of file diff --git a/assets/js/263e9506.4466c5fa.js b/assets/js/263e9506.4466c5fa.js deleted file mode 100644 index e8cb6bd..0000000 --- a/assets/js/263e9506.4466c5fa.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[331],{8453(e,n,i){i.d(n,{R:()=>o,x:()=>c});var l=i(6540);const t={},s=l.createContext(t);function o(e){const n=l.useContext(s);return l.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),l.createElement(s.Provider,{value:n},e.children)}},9499(e,n,i){i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>c,default:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>r});const l=JSON.parse('{"id":"reference/collections","title":"CmdForge Collections","description":"Collections are curated groups of tools that can be installed together with a single command.","source":"@site/docs/reference/collections.md","sourceDirName":"reference","slug":"/reference/collections","permalink":"/rob/CmdForge/reference/collections","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":3,"frontMatter":{"sidebar_label":"Collections","sidebar_position":3,"format":"md"},"sidebar":"docs","previous":{"title":"Meta-Tools","permalink":"/rob/CmdForge/reference/meta-tools"},"next":{"title":"Example Tools","permalink":"/rob/CmdForge/reference/examples"}}');var t=i(4848),s=i(8453);const o={sidebar_label:"Collections",sidebar_position:3,format:"md"},c="CmdForge Collections",d={},r=[{value:"Implementation Status",id:"implementation-status",level:2},{value:"Use Cases",id:"use-cases",level:2},{value:"CLI Usage",id:"cli-usage",level:2},{value:"List Collections",id:"list-collections",level:3},{value:"View Collection Details",id:"view-collection-details",level:3},{value:"Install Collection",id:"install-collection",level:3},{value:"Admin Management",id:"admin-management",level:2},{value:"Admin UI Features",id:"admin-ui-features",level:3},{value:"Admin API Endpoints",id:"admin-api-endpoints",level:3},{value:"Creating a Collection via API",id:"creating-a-collection-via-api",level:3},{value:"Public API Endpoints",id:"public-api-endpoints",level:2},{value:"List Response",id:"list-response",level:3},{value:"Detail Response",id:"detail-response",level:3},{value:"Database Schema",id:"database-schema",level:2},{value:"Collection Manifest Format",id:"collection-manifest-format",level:2},{value:"Web UI",id:"web-ui",level:2},{value:"Implementation Files",id:"implementation-files",level:2}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"cmdforge-collections",children:"CmdForge Collections"})}),"\n",(0,t.jsx)(n.p,{children:"Collections are curated groups of tools that can be installed together with a single command."}),"\n",(0,t.jsx)(n.h2,{id:"implementation-status",children:"Implementation Status"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Feature"}),(0,t.jsx)(n.th,{children:"Status"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Public API endpoints"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Admin API endpoints"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Web UI browse pages"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Admin management UI"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Database schema"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"CLI commands"}),(0,t.jsx)(n.td,{children:"Done"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Registry repo sync"}),(0,t.jsx)(n.td,{children:"Not implemented"})]})]})]}),"\n",(0,t.jsx)(n.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Thematic bundles"}),': "writing-toolkit" with grammar, tone, simplify tools']}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Application stacks"}),': "data-science" with json-extract, csv-insights, etc.']}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Source bundles"}),': "fabric-text" with all Fabric text processing patterns']}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Workflow packages"}),": Tools that work well together for a specific task"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"cli-usage",children:"CLI Usage"}),"\n",(0,t.jsx)(n.h3,{id:"list-collections",children:"List Collections"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"# List available collections\ncmdforge collections list\n\n# List in JSON format\ncmdforge collections list --json\n"})}),"\n",(0,t.jsx)(n.p,{children:"Example output:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Available collections (1):\n\n development-hub\n Development-Hub\n Collection of tools for the development-hub application.\n Tools: 2\n\nInstall a collection with: cmdforge collections install <name>\n"})}),"\n",(0,t.jsx)(n.h3,{id:"view-collection-details",children:"View Collection Details"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"# View collection details\ncmdforge collections info development-hub\n\n# View in JSON format\ncmdforge collections info development-hub --json\n"})}),"\n",(0,t.jsx)(n.p,{children:"Example output:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Development-Hub\n==================================================\n\nCollection of tools for the development-hub application.\n\nMaintainer: official\nTags: Development, Coding, Programming\n\nTools (2):\n - rob/audit-goals\n - rob/realign-goals\n\nInstall all: cmdforge collections install development-hub\n"})}),"\n",(0,t.jsx)(n.h3,{id:"install-collection",children:"Install Collection"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"# Install all tools in a collection\ncmdforge collections install development-hub\n\n# Install with pinned versions from collection\ncmdforge collections install development-hub --pinned\n"})}),"\n",(0,t.jsx)(n.p,{children:"Example output:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Installing collection: Development-Hub\nTools to install: 2\n\n Installing rob/audit-goals... v1.0.0\n Installing rob/realign-goals... v1.0.0\n\nInstalled: 2/2\n\nCollection 'development-hub' installed successfully!\n"})}),"\n",(0,t.jsx)(n.h2,{id:"admin-management",children:"Admin Management"}),"\n",(0,t.jsxs)(n.p,{children:["Collections are managed via the admin dashboard at ",(0,t.jsx)(n.code,{children:"/dashboard/admin/collections"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"admin-ui-features",children:"Admin UI Features"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"List collections"}),": View all collections with tool counts and tags"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Create collection"}),": Add new collection with name, display name, description, tools"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Edit collection"}),": Update existing collection details and tool list"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Delete collection"}),": Remove a collection (does not uninstall tools)"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"admin-api-endpoints",children:"Admin API Endpoints"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Method"}),(0,t.jsx)(n.th,{children:"Endpoint"}),(0,t.jsx)(n.th,{children:"Description"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GET"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/admin/collections"})}),(0,t.jsx)(n.td,{children:"List all collections (admin)"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"POST"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/admin/collections"})}),(0,t.jsx)(n.td,{children:"Create collection (admin)"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"PUT"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/admin/collections/:name"})}),(0,t.jsx)(n.td,{children:"Update collection (admin)"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"DELETE"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/admin/collections/:name"})}),(0,t.jsx)(n.td,{children:"Delete collection (admin)"})]})]})]}),"\n",(0,t.jsx)(n.h3,{id:"creating-a-collection-via-api",children:"Creating a Collection via API"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'curl -X POST https://cmdforge.brrd.tech/api/v1/admin/collections \\\n -H "Authorization: Bearer <admin-token>" \\\n -H "Content-Type: application/json" \\\n -d \'{\n "name": "writing-toolkit",\n "display_name": "Writing Toolkit",\n "description": "Essential tools for writers",\n "maintainer": "official",\n "tools": ["official/fix-grammar", "official/simplify"],\n "pinned": {"official/fix-grammar": "1.0.0"},\n "tags": ["writing", "editing"]\n }\'\n'})}),"\n",(0,t.jsx)(n.h2,{id:"public-api-endpoints",children:"Public API Endpoints"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Method"}),(0,t.jsx)(n.th,{children:"Endpoint"}),(0,t.jsx)(n.th,{children:"Description"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GET"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/collections"})}),(0,t.jsx)(n.td,{children:"List all collections (summary)"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GET"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"/api/v1/collections/:name"})}),(0,t.jsx)(n.td,{children:"Get collection details with tool info"})]})]})]}),"\n",(0,t.jsx)(n.h3,{id:"list-response",children:"List Response"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "data": [\n {\n "name": "writing-toolkit",\n "display_name": "Writing Toolkit",\n "description": "Essential tools for writers",\n "maintainer": "official",\n "icon": "pencil",\n "tags": ["writing", "editing"],\n "tool_count": 5\n }\n ]\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"detail-response",children:"Detail Response"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "data": {\n "name": "writing-toolkit",\n "display_name": "Writing Toolkit",\n "description": "Essential tools for writers",\n "maintainer": "official",\n "icon": "pencil",\n "tags": ["writing", "editing"],\n "tools": [\n {\n "owner": "official",\n "name": "fix-grammar",\n "version": "1.0.0",\n "description": "Fix grammar issues in text",\n "category": "Writing",\n "downloads": 150,\n "pinned_version": "1.0.0"\n }\n ]\n }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"database-schema",children:"Database Schema"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sql",children:"CREATE TABLE collections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n display_name TEXT NOT NULL,\n description TEXT,\n icon TEXT,\n maintainer TEXT NOT NULL,\n tools TEXT NOT NULL, -- JSON array of tool refs\n pinned TEXT, -- JSON object of version constraints\n tags TEXT, -- JSON array\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE INDEX idx_collections_name ON collections(name);\nCREATE INDEX idx_collections_maintainer ON collections(maintainer);\n"})}),"\n",(0,t.jsx)(n.h2,{id:"collection-manifest-format",children:"Collection Manifest Format"}),"\n",(0,t.jsx)(n.p,{children:"For reference, collections can be defined in YAML format:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:'# collections/writing-toolkit.yaml\nname: writing-toolkit\ndisplay_name: Writing Toolkit\ndescription: Essential tools for writers and editors\nicon: pencil # Optional icon identifier\nmaintainer: official # Publisher who maintains this collection\n\ntools:\n - official/fix-grammar\n - official/simplify\n - official/tone-shift\n - official/expand\n - official/proofread\n\n# Optional: version constraints\npinned:\n official/fix-grammar: "1.0.0"\n\ntags:\n - writing\n - editing\n - grammar\n'})}),"\n",(0,t.jsx)(n.h2,{id:"web-ui",children:"Web UI"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/collections"})," - Browse all collections"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/collections/:name"})," - Collection detail page with tool grid"]}),"\n",(0,t.jsx)(n.li,{children:"Install button that shows CLI command"}),"\n",(0,t.jsx)(n.li,{children:"Filter by tag, maintainer"}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"implementation-files",children:"Implementation Files"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Component"}),(0,t.jsx)(n.th,{children:"File"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"CLI commands"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/cli/collections_commands.py"})})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Registry client"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/registry_client.py"})})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"API endpoints"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/registry/app.py"})})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Admin templates"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/web/templates/admin/collections.html"})})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Admin form"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/web/templates/admin/collection_form.html"})})]})]})]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(a,{...e})}):a(e)}}}]); \ No newline at end of file diff --git a/assets/js/28c758de.7bd54231.js b/assets/js/28c758de.7bd54231.js deleted file mode 100644 index 2862ede..0000000 --- a/assets/js/28c758de.7bd54231.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[877],{7411(e){e.exports=JSON.parse('{"categoryGeneratedIndex":{"title":"Reference","description":"Technical reference documentation for CmdForge including API specs, design documents, and implementation guides.","slug":"/category/reference","permalink":"/rob/CmdForge/category/reference","sidebar":"docs","navigation":{"previous":{"title":"CmdForge Architecture","permalink":"/rob/CmdForge/architecture"},"next":{"title":"Provider Setup","permalink":"/rob/CmdForge/reference/providers"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/387720e6.1e51a2f9.js b/assets/js/387720e6.1e51a2f9.js deleted file mode 100644 index 858f5d5..0000000 --- a/assets/js/387720e6.1e51a2f9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[887],{4884(e,n,s){s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>t,default:()=>h,frontMatter:()=>d,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"reference/registry-spec","title":"CmdForge Registry Design","description":"Purpose","source":"@site/docs/reference/registry-spec.md","sourceDirName":"reference","slug":"/reference/registry-spec","permalink":"/rob/CmdForge/reference/registry-spec","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_label":"Registry API","sidebar_position":1,"format":"md"},"sidebar":"docs","previous":{"title":"Provider Setup","permalink":"/rob/CmdForge/reference/providers"},"next":{"title":"Meta-Tools","permalink":"/rob/CmdForge/reference/meta-tools"}}');var r=s(4848),l=s(8453);const d={sidebar_label:"Registry API",sidebar_position:1,format:"md"},t="CmdForge Registry Design",o={},c=[{value:"Purpose",id:"purpose",level:2},{value:"Terminology",id:"terminology",level:2},{value:"Diagram References",id:"diagram-references",level:2},{value:"System Overview",id:"system-overview",level:2},{value:"Pagination",id:"pagination",level:3},{value:"Input Constraints",id:"input-constraints",level:3},{value:"Sort Fields and Indexes",id:"sort-fields-and-indexes",level:3},{value:"Tags Endpoint",id:"tags-endpoint",level:3},{value:"Advanced Search",id:"advanced-search",level:3},{value:"API Version Compatibility",id:"api-version-compatibility",level:3},{value:"Source of Truth",id:"source-of-truth",level:2},{value:"Namespacing and Paths",id:"namespacing-and-paths",level:2},{value:"Namespace Identity",id:"namespace-identity",level:3},{value:"Tool Format (Registry == Local)",id:"tool-format-registry--local",level:2},{value:"Attribution and Source Fields",id:"attribution-and-source-fields",level:3},{value:"Collections",id:"collections",level:2},{value:"Collection Structure",id:"collection-structure",level:3},{value:"Collections API",id:"collections-api",level:3},{value:"CLI Commands",id:"cli-commands",level:3},{value:"Admin Collections API",id:"admin-collections-api",level:3},{value:"Versioning and Immutability",id:"versioning-and-immutability",level:2},{value:"Yank Policy",id:"yank-policy",level:3},{value:"Version Format",id:"version-format",level:3},{value:"Version Constraints",id:"version-constraints",level:3},{value:"Version Resolution Rules",id:"version-resolution-rules",level:3},{value:"Prerelease Handling",id:"prerelease-handling",level:3},{value:"Download Endpoint Version Selection",id:"download-endpoint-version-selection",level:3},{value:"Tool Resolution Order",id:"tool-resolution-order",level:2},{value:"Official Namespace",id:"official-namespace",level:3},{value:"Auto-Fetch Behavior",id:"auto-fetch-behavior",level:2},{value:"Wrapper Script Collisions",id:"wrapper-script-collisions",level:3},{value:"Project Manifest (cmdforge.yaml)",id:"project-manifest-cmdforgeyaml",level:2},{value:"CLI Config and Tokens",id:"cli-config-and-tokens",level:2},{value:"Publishing and Auth",id:"publishing-and-auth",level:2},{value:"Publish Idempotency and Edge Cases",id:"publish-idempotency-and-edge-cases",level:3},{value:"Publisher Registration",id:"publisher-registration",level:2},{value:"Authentication Security",id:"authentication-security",level:3},{value:"Token Scopes and Authorization",id:"token-scopes-and-authorization",level:3},{value:"Web Session Security",id:"web-session-security",level:3},{value:"CLI Commands Reference",id:"cli-commands-reference",level:2},{value:"Registry Commands",id:"registry-commands",level:3},{value:"Project Commands",id:"project-commands",level:3},{value:"Config Commands",id:"config-commands",level:3},{value:"Flags available on most commands",id:"flags-available-on-most-commands",level:3},{value:"Publish State Tracking",id:"publish-state-tracking",level:2},{value:"Local State Storage",id:"local-state-storage",level:3},{value:"Visual Indicators",id:"visual-indicators",level:3},{value:"Automatic Status Sync",id:"automatic-status-sync",level:3},{value:"Manual Sync",id:"manual-sync",level:3},{value:"Hash Computation",id:"hash-computation",level:3},{value:"API Endpoint",id:"api-endpoint",level:3},{value:"Webhooks and Security",id:"webhooks-and-security",level:2},{value:"HMAC Verification",id:"hmac-verification",level:3},{value:"Replay Protection",id:"replay-protection",level:3},{value:"Sync Job Locking",id:"sync-job-locking",level:3},{value:"Atomic Sync Strategy",id:"atomic-sync-strategy",level:3},{value:"Error Handling",id:"error-handling",level:3},{value:"Automated CI Validation",id:"automated-ci-validation",level:2},{value:"Registry Repository Structure",id:"registry-repository-structure",level:2},{value:"Download Stats",id:"download-stats",level:2},{value:"Counting Methodology",id:"counting-methodology",level:3},{value:"Client ID Generation",id:"client-id-generation",level:3},{value:"Privacy Considerations",id:"privacy-considerations",level:3},{value:"Async Stats Strategy",id:"async-stats-strategy",level:3},{value:"Search",id:"search",level:2},{value:"API Caching Strategy",id:"api-caching-strategy",level:2},{value:"Cache Headers",id:"cache-headers",level:3},{value:"ETag Implementation",id:"etag-implementation",level:3},{value:"DB vs Repo Read Strategy",id:"db-vs-repo-read-strategy",level:3},{value:"Staleness Detection",id:"staleness-detection",level:3},{value:"Error Model",id:"error-model",level:2},{value:"Response Envelopes",id:"response-envelopes",level:3},{value:"Error Codes",id:"error-codes",level:3},{value:"Error Scenarios and Fallbacks",id:"error-scenarios-and-fallbacks",level:2},{value:"CLI Error Handling",id:"cli-error-handling",level:3},{value:"Validation Failure Details",id:"validation-failure-details",level:3},{value:"Dependency Resolution Failures",id:"dependency-resolution-failures",level:3},{value:"Graceful Degradation",id:"graceful-degradation",level:3},{value:"UX Requirements (CLI/TUI)",id:"ux-requirements-clitui",level:2},{value:"Publishing UX",id:"publishing-ux",level:3},{value:"Progress Indicators",id:"progress-indicators",level:3},{value:"TUI Browse",id:"tui-browse",level:3},{value:"Project Initialization",id:"project-initialization",level:3},{value:"Accessibility",id:"accessibility",level:3},{value:"Offline Cache",id:"offline-cache",level:2},{value:"Index Integrity",id:"index-integrity",level:3},{value:"Web UI Vision",id:"web-ui-vision",level:2},{value:"README Security",id:"readme-security",level:3},{value:"Registry Curation System",id:"registry-curation-system",level:2},{value:"Roles and Permissions",id:"roles-and-permissions",level:3},{value:"Tool Visibility",id:"tool-visibility",level:3},{value:"Moderation Workflow",id:"moderation-workflow",level:3},{value:"Admin API Endpoints",id:"admin-api-endpoints",level:3},{value:"Ban Behavior",id:"ban-behavior",level:3},{value:"Report Resolution Actions",id:"report-resolution-actions",level:3},{value:"Audit Log",id:"audit-log",level:3},{value:"Web UI Admin Dashboard",id:"web-ui-admin-dashboard",level:3},{value:"Pending Tools Review Page",id:"pending-tools-review-page",level:4},{value:"Creating the First Admin",id:"creating-the-first-admin",level:3},{value:"Implementation Phases",id:"implementation-phases",level:2},{value:"Phase 1: Foundation",id:"phase-1-foundation",level:3},{value:"Phase 2: Core Backend",id:"phase-2-core-backend",level:3},{value:"Phase 3: CLI Commands",id:"phase-3-cli-commands",level:3},{value:"Phase 4: Publishing",id:"phase-4-publishing",level:3},{value:"Phase 5: Project Dependencies",id:"phase-5-project-dependencies",level:3},{value:"Phase 6: Smart Features",id:"phase-6-smart-features",level:3},{value:"Phase 7: Full Web UI",id:"phase-7-full-web-ui",level:3},{value:"Phase 8: Polish & Scale",id:"phase-8-polish--scale",level:3}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"cmdforge-registry-design",children:"CmdForge Registry Design"})}),"\n",(0,r.jsx)(n.h2,{id:"purpose",children:"Purpose"}),"\n",(0,r.jsx)(n.p,{children:"Build a centralized registry for CmdForge to enable discovery, publishing, dependency management, and future curation at scale."}),"\n",(0,r.jsx)(n.h2,{id:"terminology",children:"Terminology"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Term"}),(0,r.jsx)(n.th,{children:"Definition"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Tool definition"})}),(0,r.jsxs)(n.td,{children:["The full YAML file in the registry (",(0,r.jsx)(n.code,{children:"config.yaml"}),") containing name, steps, arguments, etc."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Tool config"})}),(0,r.jsx)(n.td,{children:"The configuration within a tool definition (arguments, steps, provider settings)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"cmdforge.yaml"})}),(0,r.jsx)(n.td,{children:"Project manifest file declaring tool dependencies and overrides"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"config.yaml"})}),(0,r.jsx)(n.td,{children:"The tool definition file, both in registry and when installed locally"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Owner"})}),(0,r.jsxs)(n.td,{children:["Immutable namespace slug identifying the publisher (e.g., ",(0,r.jsx)(n.code,{children:"rob"}),", ",(0,r.jsx)(n.code,{children:"alice"}),")"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Publisher"})}),(0,r.jsx)(n.td,{children:"A registered user who can publish tools to the registry"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Wrapper script"})}),(0,r.jsxs)(n.td,{children:["Auto-generated bash script in ",(0,r.jsx)(n.code,{children:"~/.local/bin/"})," that invokes a tool"]})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Canonical naming:"})," Use ",(0,r.jsx)(n.code,{children:"CmdForge-Registry"})," (capitalized, hyphenated) for the repository name."]}),"\n",(0,r.jsx)(n.h2,{id:"diagram-references",children:"Diagram References"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["System overview: ",(0,r.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_1.puml"})]}),"\n",(0,r.jsxs)(n.li,{children:["Data flows: ",(0,r.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_5.puml"})]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"system-overview",children:"System Overview"}),"\n",(0,r.jsxs)(n.p,{children:["Users interact via the CLI and a future Web UI. Both call a Registry API hosted at ",(0,r.jsx)(n.code,{children:"https://cmdforge.brrd.tech/api/v1"})," (future alias: ",(0,r.jsx)(n.code,{children:"cmdforge.brrd.tech/api/v1"}),"). The API syncs from a Gitea-backed registry repo and maintains a SQLite cache/search index."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Canonical API base path:"})," ",(0,r.jsx)(n.code,{children:"https://cmdforge.brrd.tech/api/v1"})]}),"\n",(0,r.jsxs)(n.p,{children:["All API endpoints are versioned under ",(0,r.jsx)(n.code,{children:"/api/v1"}),". When breaking changes are needed, a new version (",(0,r.jsx)(n.code,{children:"/api/v2"}),") will be introduced with deprecation notices."]}),"\n",(0,r.jsx)(n.p,{children:"Core API endpoints:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tools"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"GET /api/v1/tools/search?q=..."})," (with advanced filtering)"]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tools/{owner}/{name}"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tools/{owner}/{name}/versions"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tools/{owner}/{name}/download?version=..."})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"POST /api/v1/tools"})," (publish)"]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/categories"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"GET /api/v1/tags"})," (list all tags with counts)"]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/collections"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/collections/{name}"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/stats/popular"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"POST /api/v1/webhook/gitea"})}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"pagination",children:"Pagination"}),"\n",(0,r.jsx)(n.p,{children:"All list endpoints support pagination:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Max"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"page"})}),(0,r.jsx)(n.td,{children:"1"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Page number (1-indexed)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"per_page"})}),(0,r.jsx)(n.td,{children:"20"}),(0,r.jsx)(n.td,{children:"100"}),(0,r.jsx)(n.td,{children:"Items per page"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"sort"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"downloads"})}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Sort field"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"order"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"desc"})}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Sort order (asc/desc)"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Stable ordering:"})," To ensure deterministic results across pages, sorting includes a secondary key:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Primary: requested field (e.g., ",(0,r.jsx)(n.code,{children:"downloads"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:["Secondary: ",(0,r.jsx)(n.code,{children:"published_at"})," (desc)"]}),"\n",(0,r.jsxs)(n.li,{children:["Tertiary: ",(0,r.jsx)(n.code,{children:"id"})," (for absolute stability)"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"ORDER BY downloads DESC, published_at DESC, id DESC\nLIMIT 20 OFFSET 0\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Response pagination metadata:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "data": [...],\n "meta": {\n "page": 1,\n "per_page": 20,\n "total": 142,\n "total_pages": 8\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"input-constraints",children:"Input Constraints"}),"\n",(0,r.jsx)(n.p,{children:"Size limits to prevent oversized uploads:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Field"}),(0,r.jsx)(n.th,{children:"Max Size"}),(0,r.jsx)(n.th,{children:"Notes"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"config.yaml"})}),(0,r.jsx)(n.td,{children:"64 KB"}),(0,r.jsx)(n.td,{children:"Tool definition"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"README.md"})}),(0,r.jsx)(n.td,{children:"256 KB"}),(0,r.jsx)(n.td,{children:"Documentation"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Request body"}),(0,r.jsx)(n.td,{children:"512 KB"}),(0,r.jsx)(n.td,{children:"Total POST payload"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool name"}),(0,r.jsx)(n.td,{children:"64 chars"}),(0,r.jsx)(n.td,{children:"Alphanumeric + hyphen"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Description"}),(0,r.jsx)(n.td,{children:"500 chars"}),(0,r.jsx)(n.td,{children:"Short summary"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tag"}),(0,r.jsx)(n.td,{children:"32 chars"}),(0,r.jsx)(n.td,{children:"Individual tag"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tags array"}),(0,r.jsx)(n.td,{children:"10 items"}),(0,r.jsx)(n.td,{children:"Maximum tags per tool"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Validation errors:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "error": {\n "code": "PAYLOAD_TOO_LARGE",\n "message": "config.yaml exceeds 64KB limit",\n "details": {\n "field": "config",\n "size": 72000,\n "limit": 65536\n }\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"sort-fields-and-indexes",children:"Sort Fields and Indexes"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Allowed sort fields:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Endpoint"}),(0,r.jsxs)(n.th,{children:["Allowed ",(0,r.jsx)(n.code,{children:"sort"})," values"]})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"downloads"}),", ",(0,r.jsx)(n.code,{children:"published_at"}),", ",(0,r.jsx)(n.code,{children:"name"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools/search"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"relevance"}),", ",(0,r.jsx)(n.code,{children:"downloads"}),", ",(0,r.jsx)(n.code,{children:"published_at"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /categories"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"name"}),", ",(0,r.jsx)(n.code,{children:"tool_count"})]})]})]})]}),"\n",(0,r.jsx)(n.p,{children:"Invalid sort values return 400:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{"error": {"code": "INVALID_SORT", "message": "Unknown sort field \'foo\'. Allowed: downloads, published_at, name"}}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"tags-endpoint",children:"Tags Endpoint"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tags"})})," - List all tags with usage counts."]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"category"})}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Filter tags to those used in a specific category"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"limit"})}),(0,r.jsx)(n.td,{children:"100"}),(0,r.jsx)(n.td,{children:"Maximum tags to return (max 500)"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Response:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "data": [\n {"name": "cli", "count": 45},\n {"name": "ai", "count": 32},\n {"name": "text", "count": 28}\n ],\n "meta": {"total": 87}\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"advanced-search",children:"Advanced Search"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/tools/search"})})," supports advanced filtering beyond basic text search."]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Default"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"q"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"required"}),(0,r.jsx)(n.td,{children:"Search query (uses FTS5 full-text search)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"category"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Filter by single category"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"categories"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Filter by multiple categories (comma-separated, OR logic)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"tags"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Filter by tags (comma-separated, AND logic)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"owner"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Filter by publisher/owner"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"min_downloads"})}),(0,r.jsx)(n.td,{children:"int"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Minimum download count"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max_downloads"})}),(0,r.jsx)(n.td,{children:"int"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Maximum download count"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"published_after"})}),(0,r.jsx)(n.td,{children:"date"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Published after date (ISO 8601: YYYY-MM-DD)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"published_before"})}),(0,r.jsx)(n.td,{children:"date"}),(0,r.jsx)(n.td,{children:"-"}),(0,r.jsx)(n.td,{children:"Published before date (ISO 8601: YYYY-MM-DD)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"deprecated"})}),(0,r.jsx)(n.td,{children:"bool"}),(0,r.jsx)(n.td,{children:"false"}),(0,r.jsx)(n.td,{children:"Include deprecated tools"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"include_facets"})}),(0,r.jsx)(n.td,{children:"bool"}),(0,r.jsx)(n.td,{children:"false"}),(0,r.jsx)(n.td,{children:"Include faceted counts in response"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"sort"})}),(0,r.jsx)(n.td,{children:"string"}),(0,r.jsx)(n.td,{children:"relevance"}),(0,r.jsx)(n.td,{children:"Sort by: relevance, downloads, published_at, name"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"page"})}),(0,r.jsx)(n.td,{children:"int"}),(0,r.jsx)(n.td,{children:"1"}),(0,r.jsx)(n.td,{children:"Page number"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"per_page"})}),(0,r.jsx)(n.td,{children:"int"}),(0,r.jsx)(n.td,{children:"20"}),(0,r.jsx)(n.td,{children:"Results per page (max 100)"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Tag filtering (AND logic):"})," When multiple tags are specified, only tools with ALL tags are returned:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/tools/search?q=summarize&tags=cli,ai\n# Returns tools that have BOTH "cli" AND "ai" tags\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Category filtering (OR logic):"})," When multiple categories are specified, tools in ANY category are returned:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/tools/search?q=summarize&categories=text-processing,productivity\n# Returns tools in "text-processing" OR "productivity" category\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Faceted response:"})," When ",(0,r.jsx)(n.code,{children:"include_facets=true"}),", the response includes counts for filtering:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "data": [...],\n "meta": {"page": 1, "per_page": 20, "total": 42, "total_pages": 3},\n "facets": {\n "categories": [\n {"name": "text-processing", "count": 25},\n {"name": "productivity", "count": 17}\n ],\n "tags": [\n {"name": "ai", "count": 30},\n {"name": "cli", "count": 22},\n {"name": "text", "count": 18}\n ],\n "owners": [\n {"name": "official", "count": 15},\n {"name": "rob", "count": 10}\n ]\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Database indexes:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"-- Frequent query patterns\nCREATE INDEX idx_tools_owner_name ON tools(owner, name);\nCREATE INDEX idx_tools_owner ON tools(owner); -- For owner filtering\nCREATE INDEX idx_tools_category ON tools(category);\nCREATE INDEX idx_tools_published_at ON tools(published_at DESC);\nCREATE INDEX idx_tools_downloads ON tools(downloads DESC);\nCREATE INDEX idx_tools_owner_name_version ON tools(owner, name, version);\n\n-- For pagination stability\nCREATE INDEX idx_tools_sort_stable ON tools(downloads DESC, published_at DESC, id DESC);\n\n-- Publisher lookups\nCREATE INDEX idx_publishers_slug ON publishers(slug);\nCREATE INDEX idx_publishers_email ON publishers(email);\n\n-- Token lookups\nCREATE INDEX idx_api_tokens_hash ON api_tokens(token_hash);\nCREATE INDEX idx_api_tokens_publisher ON api_tokens(publisher_id);\n"})}),"\n",(0,r.jsx)(n.h3,{id:"api-version-compatibility",children:"API Version Compatibility"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Forward compatibility:"})," Clients should ignore unknown fields in API responses:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"# Good: ignore unknown fields\ntool = response['data']\nname = tool.get('name')\n# Don't fail if 'new_field' exists but client doesn't know about it\n\n# Bad: strict parsing that fails on unknown fields\ntool = ToolSchema.parse(response['data']) # May fail on new fields\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Backward compatibility:"})," The API will:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Never remove fields in a version (only deprecate)"}),"\n",(0,r.jsx)(n.li,{children:"Never change field types"}),"\n",(0,r.jsx)(n.li,{children:"Add new optional fields without version bump"}),"\n",(0,r.jsxs)(n.li,{children:["Use new version (",(0,r.jsx)(n.code,{children:"/api/v2"}),") for breaking changes"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Deprecation process:"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Add ",(0,r.jsx)(n.code,{children:"X-Deprecated-Field: old_field"})," header"]}),"\n",(0,r.jsx)(n.li,{children:"Document in changelog"}),"\n",(0,r.jsx)(n.li,{children:"Remove after 6 months minimum"}),"\n",(0,r.jsx)(n.li,{children:"Major version bump if widely used"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Client version header:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"X-CmdForge-Client: cli/1.2.0\n"})}),"\n",(0,r.jsx)(n.p,{children:"Helps server track client versions for deprecation decisions."}),"\n",(0,r.jsx)(n.h2,{id:"source-of-truth",children:"Source of Truth"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Gitea registry repo is the source of truth."}),"\n",(0,r.jsx)(n.li,{children:"API syncs repo content into SQLite for fast queries, stats, and FTS5 search."}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"index.json"})," remains useful for offline CLI search and as a fallback."]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"If the cache is stale, the API can fall back to repo reads; a warning header may be emitted."}),"\n",(0,r.jsx)(n.h2,{id:"namespacing-and-paths",children:"Namespacing and Paths"}),"\n",(0,r.jsx)(n.p,{children:"Support owner/name from day one:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Registry path: ",(0,r.jsx)(n.code,{children:"tools/{owner}/{name}/config.yaml"})]}),"\n",(0,r.jsxs)(n.li,{children:["API URL: ",(0,r.jsx)(n.code,{children:"/tools/{owner}/{name}"})]}),"\n",(0,r.jsxs)(n.li,{children:["Install: ",(0,r.jsx)(n.code,{children:"cmdforge registry install rob/summarize"})]}),"\n",(0,r.jsxs)(n.li,{children:["Shorthand: ",(0,r.jsx)(n.code,{children:"cmdforge registry install summarize"})," resolves to the official namespace."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["PR branches: ",(0,r.jsx)(n.code,{children:"submit/{owner}/{name}/{version}"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"namespace-identity",children:"Namespace Identity"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"owner"})," is an ",(0,r.jsx)(n.strong,{children:"immutable slug"}),", not the display name:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:'-- In publishers table\nslug TEXT UNIQUE NOT NULL, -- immutable: "rob", "alice-dev"\ndisplay_name TEXT NOT NULL, -- mutable: "Rob", "Alice Developer"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Slug rules:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Lowercase alphanumeric + hyphens only: ",(0,r.jsx)(n.code,{children:"^[a-z0-9][a-z0-9-]*[a-z0-9]$"})]}),"\n",(0,r.jsx)(n.li,{children:"2-39 characters"}),"\n",(0,r.jsx)(n.li,{children:"Cannot start/end with hyphen"}),"\n",(0,r.jsx)(n.li,{children:"Set once at registration, cannot be changed"}),"\n",(0,r.jsxs)(n.li,{children:["Reserved slugs: ",(0,r.jsx)(n.code,{children:"official"}),", ",(0,r.jsx)(n.code,{children:"admin"}),", ",(0,r.jsx)(n.code,{children:"system"}),", ",(0,r.jsx)(n.code,{children:"api"}),", ",(0,r.jsx)(n.code,{children:"registry"})]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Rename policy:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"display_name"})," can be changed anytime via dashboard"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"slug"})," (owner) is permanent to preserve URLs and tool references"]}),"\n",(0,r.jsxs)(n.li,{children:["If a publisher absolutely must change slug (legal reasons, etc.):","\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Create new account with new slug"}),"\n",(0,r.jsx)(n.li,{children:"Republish tools under new namespace"}),"\n",(0,r.jsxs)(n.li,{children:["Mark old tools as deprecated with ",(0,r.jsx)(n.code,{children:"replacement"})," pointing to new namespace"]}),"\n",(0,r.jsx)(n.li,{children:"Old namespace remains reserved (cannot be reused by others)"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Why immutable:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"rob/summarize@1.0.0"})," must always resolve to the same tool"]}),"\n",(0,r.jsx)(n.li,{children:"Prevents namespace hijacking after rename"}),"\n",(0,r.jsx)(n.li,{children:"Simplifies caching and CDN strategies"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"tool-format-registry--local",children:"Tool Format (Registry == Local)"}),"\n",(0,r.jsx)(n.p,{children:"Registry tool folders mirror local tools:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"tools/\n rob/\n summarize/\n config.yaml\n README.md\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Tool files match the existing CmdForge format. Registry-specific metadata is kept under ",(0,r.jsx)(n.code,{children:"registry:"}),". Deprecation is tool-defined and top-level:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: summarize\nversion: "1.2.0"\ndeprecated: true\ndeprecated_message: "Security issue. Use v1.2.1"\nreplacement: "rob/summarize@1.2.1"\nregistry:\n published_at: "2025-01-15T10:30:00Z"\n downloads: 142\n'})}),"\n",(0,r.jsx)(n.h3,{id:"attribution-and-source-fields",children:"Attribution and Source Fields"}),"\n",(0,r.jsx)(n.p,{children:"Tools can include optional source attribution for provenance and licensing:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: summarize\nversion: "1.2.0"\ndescription: "Summarize text using AI"\n\n# Attribution fields (optional)\nsource:\n type: original # original, adapted, or imported\n license: MIT # SPDX license identifier\n url: https://example.com/tool-repo\n author: "Original Author"\n\n # For adapted/imported tools\n original_tool: other/original-summarize@1.0.0\n changes: "Added French language support"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Source types:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"original"})}),(0,r.jsx)(n.td,{children:"Created from scratch by the publisher"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"adapted"})}),(0,r.jsx)(n.td,{children:"Based on another tool with modifications"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"imported"})}),(0,r.jsx)(n.td,{children:"Direct import of external tool (e.g., from npm/pip)"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"License field:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Uses SPDX identifiers: ",(0,r.jsx)(n.code,{children:"MIT"}),", ",(0,r.jsx)(n.code,{children:"Apache-2.0"}),", ",(0,r.jsx)(n.code,{children:"GPL-3.0"}),", etc."]}),"\n",(0,r.jsx)(n.li,{children:"Required for registry publication"}),"\n",(0,r.jsx)(n.li,{children:"Validated against SPDX license list"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"collections",children:"Collections"}),"\n",(0,r.jsx)(n.p,{children:"Collections are curated groups of tools that can be installed together with a single command."}),"\n",(0,r.jsx)(n.h3,{id:"collection-structure",children:"Collection Structure"}),"\n",(0,r.jsxs)(n.p,{children:["Collections are defined in ",(0,r.jsx)(n.code,{children:"collections/{name}.yaml"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: text-processing-essentials\ndisplay_name: "Text Processing Essentials"\ndescription: "Essential tools for text processing and manipulation"\nicon: "\ud83d\udcdd"\n\ntools:\n - official/summarize\n - official/translate\n - official/fix-grammar\n - official/simplify\n - official/tone-shift\n\n# Optional\ncurator: official\ntags: ["text", "nlp", "writing"]\n'})}),"\n",(0,r.jsx)(n.h3,{id:"collections-api",children:"Collections API"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"List all collections:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/collections\n\nResponse:\n{\n "data": [\n {\n "name": "text-processing-essentials",\n "display_name": "Text Processing Essentials",\n "description": "Essential tools for text processing...",\n "icon": "\ud83d\udcdd",\n "tool_count": 5,\n "curator": "official"\n }\n ],\n "meta": {"page": 1, "per_page": 20, "total": 8}\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Get collection details:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/collections/{name}\n\nResponse:\n{\n "data": {\n "name": "text-processing-essentials",\n "display_name": "Text Processing Essentials",\n "description": "Essential tools for text processing...",\n "icon": "\ud83d\udcdd",\n "curator": "official",\n "tools": [\n {"owner": "official", "name": "summarize", "version": "1.2.0", ...},\n {"owner": "official", "name": "translate", "version": "2.1.0", ...}\n ]\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"cli-commands",children:"CLI Commands"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# List available collections\ncmdforge collections list\n\n# List in JSON format\ncmdforge collections list --json\n\n# View collection details\ncmdforge collections info text-processing-essentials\n\n# View in JSON format\ncmdforge collections info text-processing-essentials --json\n\n# Install all tools in a collection\ncmdforge collections install text-processing-essentials\n\n# Install with pinned versions from collection\ncmdforge collections install text-processing-essentials --pinned\n"})}),"\n",(0,r.jsx)(n.h3,{id:"admin-collections-api",children:"Admin Collections API"}),"\n",(0,r.jsxs)(n.p,{children:["Collections are managed via the admin dashboard at ",(0,r.jsx)(n.code,{children:"/dashboard/admin/collections"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/admin/collections # List all collections (admin)\nPOST /api/v1/admin/collections # Create collection (admin)\nPUT /api/v1/admin/collections/:name # Update collection (admin)\nDELETE /api/v1/admin/collections/:name # Delete collection (admin)\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Schema compatibility note:"})," The current CmdForge config parser may reject unknown top-level keys like ",(0,r.jsx)(n.code,{children:"deprecated"}),", ",(0,r.jsx)(n.code,{children:"replacement"}),", and ",(0,r.jsx)(n.code,{children:"registry"}),". Before implementing registry features:"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Update the YAML parser to ignore unknown keys (permissive mode)"}),"\n",(0,r.jsx)(n.li,{children:"Or explicitly define these fields in the Tool dataclass with defaults"}),"\n",(0,r.jsx)(n.li,{children:"Validate registry-specific fields only when publishing, not when running locally"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"This ensures local tools continue to work even if they don't have registry fields."}),"\n",(0,r.jsx)(n.h2,{id:"versioning-and-immutability",children:"Versioning and Immutability"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Unique key: ",(0,r.jsx)(n.code,{children:"owner/name + version"}),"."]}),"\n",(0,r.jsx)(n.li,{children:"Published versions are immutable."}),"\n",(0,r.jsxs)(n.li,{children:["Deprecation uses ",(0,r.jsx)(n.code,{children:"deprecated"}),", ",(0,r.jsx)(n.code,{children:"deprecated_message"}),", and ",(0,r.jsx)(n.code,{children:"replacement"}),"."]}),"\n",(0,r.jsx)(n.li,{children:"CLI warns on install if a version is deprecated."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"yank-policy",children:"Yank Policy"}),"\n",(0,r.jsx)(n.p,{children:"Yanking allows removing a version from resolution without deleting it (for auditability):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'# In tool config\nyanked: true\nyanked_reason: "Critical security vulnerability CVE-2025-1234"\nyanked_at: "2025-01-20T15:00:00Z"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Yanked version behavior:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Operation"}),(0,r.jsx)(n.th,{children:"Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"install foo@1.0.0"})," (exact)"]}),(0,r.jsx)(n.td,{children:"Warns but allows install"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"install foo@^1.0.0"})," (constraint)"]}),(0,r.jsx)(n.td,{children:"Excludes yanked, resolves to next valid"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"search"})," / ",(0,r.jsx)(n.code,{children:"browse"})]}),(0,r.jsxs)(n.td,{children:["Hidden by default, shown with ",(0,r.jsx)(n.code,{children:"--include-yanked"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Direct URL access"}),(0,r.jsxs)(n.td,{children:["Returns tool with ",(0,r.jsx)(n.code,{children:"yanked: true"})," in response"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Already installed"}),(0,r.jsx)(n.td,{children:"Continues to work, no forced removal"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Database schema addition:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"-- Add to tools table\nyanked BOOLEAN DEFAULT FALSE,\nyanked_reason TEXT,\nyanked_at TIMESTAMP\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Yank vs Delete:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Yank"}),": Version remains in DB, excluded from resolution, auditable"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Delete"}),": Reserved for DMCA/legal, requires admin action, leaves tombstone record"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"version-format",children:"Version Format"}),"\n",(0,r.jsx)(n.p,{children:"Tools use semantic versioning (semver):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]\n\nExamples:\n 1.0.0 # stable release\n 1.2.3 # stable release\n 2.0.0-alpha.1 # prerelease\n 2.0.0-beta.2 # prerelease\n 2.0.0-rc.1 # release candidate\n"})}),"\n",(0,r.jsx)(n.h3,{id:"version-constraints",children:"Version Constraints"}),"\n",(0,r.jsx)(n.p,{children:"Manifest files support these constraint formats:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Constraint"}),(0,r.jsx)(n.th,{children:"Meaning"}),(0,r.jsx)(n.th,{children:"Example Match"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"1.2.3"})}),(0,r.jsx)(n.td,{children:"Exact version"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.2.3"})," only"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:">=1.2.0"})}),(0,r.jsx)(n.td,{children:"Minimum version"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.2.0"}),", ",(0,r.jsx)(n.code,{children:"1.3.0"}),", ",(0,r.jsx)(n.code,{children:"2.0.0"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"<2.0.0"})}),(0,r.jsx)(n.td,{children:"Below version"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.9.9"}),", ",(0,r.jsx)(n.code,{children:"1.0.0"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:">=1.0.0,<2.0.0"})}),(0,r.jsx)(n.td,{children:"Range"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.0.0"})," to ",(0,r.jsx)(n.code,{children:"1.9.9"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"^1.2.3"})}),(0,r.jsx)(n.td,{children:"Compatible (same major)"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.2.3"})," to ",(0,r.jsx)(n.code,{children:"1.9.9"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"~1.2.3"})}),(0,r.jsx)(n.td,{children:"Approximately (same minor)"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"1.2.3"})," to ",(0,r.jsx)(n.code,{children:"1.2.9"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"*"})}),(0,r.jsx)(n.td,{children:"Any version"}),(0,r.jsx)(n.td,{children:"latest stable"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"version-resolution-rules",children:"Version Resolution Rules"}),"\n",(0,r.jsx)(n.p,{children:"When resolving a version constraint:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Filter"}),": Get all versions matching the constraint"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Exclude prereleases"}),": Unless constraint explicitly includes them (e.g., ",(0,r.jsx)(n.code,{children:">=2.0.0-alpha.1"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Sort"}),": By semver precedence (descending)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Select"}),": Highest matching version"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Tie-breakers:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Stable versions preferred over prereleases"}),"\n",(0,r.jsx)(n.li,{children:"Later publish date wins if versions are equal (shouldn't happen with immutability)"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Unsatisfiable constraints:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'// API Response: 404\n{\n "error": {\n "code": "VERSION_NOT_FOUND",\n "message": "No version of \'rob/summarize\' satisfies constraint \'>=5.0.0\'",\n "details": {\n "tool": "rob/summarize",\n "constraint": ">=5.0.0",\n "available_versions": ["1.0.0", "1.1.0", "1.2.0"],\n "latest_stable": "1.2.0"\n }\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"prerelease-handling",children:"Prerelease Handling"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Prereleases are ",(0,r.jsx)(n.strong,{children:"not"})," returned for ",(0,r.jsx)(n.code,{children:"*"})," or range constraints by default"]}),"\n",(0,r.jsxs)(n.li,{children:["To install prerelease: ",(0,r.jsx)(n.code,{children:"cmdforge registry install rob/summarize@2.0.0-beta.1"})]}),"\n",(0,r.jsxs)(n.li,{children:["To allow prereleases in manifest: ",(0,r.jsx)(n.code,{children:'version: ">=2.0.0-0"'})," (the ",(0,r.jsx)(n.code,{children:"-0"})," suffix includes prereleases)"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"download-endpoint-version-selection",children:"Download Endpoint Version Selection"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"/api/v1/tools/{owner}/{name}/download"})," endpoint accepts version parameters:"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Parameter"}),(0,r.jsx)(n.th,{children:"Behavior"}),(0,r.jsx)(n.th,{children:"Example"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"(none)"}),(0,r.jsx)(n.td,{children:"Returns latest stable version"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"/download"})," \u2192 ",(0,r.jsx)(n.code,{children:"1.2.0"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"version=1.2.0"})}),(0,r.jsx)(n.td,{children:"Exact version (must exist)"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/download?version=1.2.0"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"version=^1.0.0"})}),(0,r.jsx)(n.td,{children:"Server resolves constraint"}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"/download?version=^1.0.0"})," \u2192 ",(0,r.jsx)(n.code,{children:"1.2.0"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"version=latest"})}),(0,r.jsx)(n.td,{children:"Alias for latest stable"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/download?version=latest"})})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Server-side resolution:"})," The API server resolves version constraints, not the client. This ensures consistent resolution and allows the server to apply policies (e.g., exclude yanked versions)."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/tools/rob/summarize/download?version=^1.0.0&install=true\n\nResponse (200):\n{\n "data": {\n "owner": "rob",\n "name": "summarize",\n "resolved_version": "1.2.0",\n "config": "... YAML content ..."\n },\n "meta": {\n "constraint": "^1.0.0",\n "available_versions": ["1.0.0", "1.1.0", "1.2.0"]\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Invalid/unsatisfiable constraint:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/tools/rob/summarize/download?version=^5.0.0\n\nResponse (404):\n{\n "error": {\n "code": "CONSTRAINT_UNSATISFIABLE",\n "message": "No version matches constraint \'^5.0.0\'",\n "details": {\n "constraint": "^5.0.0",\n "latest_stable": "1.2.0",\n "available_versions": ["1.0.0", "1.1.0", "1.2.0"]\n }\n }\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"tool-resolution-order",children:"Tool Resolution Order"}),"\n",(0,r.jsx)(n.p,{children:"When a tool is invoked, the CLI searches in this order:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Local project"}),": ",(0,r.jsx)(n.code,{children:"./.cmdforge/<owner>/<name>/config.yaml"})," (or ",(0,r.jsx)(n.code,{children:"./.cmdforge/<name>/"})," for unnamespaced)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Global user"}),": ",(0,r.jsx)(n.code,{children:"~/.cmdforge/<owner>/<name>/config.yaml"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Registry"}),": Fetch from API, install to global, then run"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Error"}),": ",(0,r.jsx)(n.code,{children:"Tool '<toolname>' not found"})]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Step 3 only occurs if ",(0,r.jsx)(n.code,{children:"auto_fetch_from_registry: true"})," in config (default: true)."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Path convention:"})," Use ",(0,r.jsx)(n.code,{children:".cmdforge/"})," (with leading dot) for both local and global to maintain consistency."]}),"\n",(0,r.jsx)(n.p,{children:"Resolution also respects namespacing:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"summarize"})," \u2192 searches for any tool named ",(0,r.jsx)(n.code,{children:"summarize"}),", prefers ",(0,r.jsx)(n.code,{children:"official/summarize"})," if exists"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"rob/summarize"})," \u2192 searches for exactly ",(0,r.jsx)(n.code,{children:"rob/summarize"})]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"official-namespace",children:"Official Namespace"}),"\n",(0,r.jsxs)(n.p,{children:["The slug ",(0,r.jsx)(n.code,{children:"official"})," is reserved for curated, high-quality tools maintained by the registry administrators."]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Shorthand ",(0,r.jsx)(n.code,{children:"summarize"})," resolves to ",(0,r.jsx)(n.code,{children:"official/summarize"})," if it exists"]}),"\n",(0,r.jsxs)(n.li,{children:["If no ",(0,r.jsx)(n.code,{children:"official/summarize"}),", falls back to most-downloaded tool named ",(0,r.jsx)(n.code,{children:"summarize"})]}),"\n",(0,r.jsxs)(n.li,{children:["To avoid ambiguity, always use full ",(0,r.jsx)(n.code,{children:"owner/name"})," in manifests"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Reserved slugs that cannot be registered: ",(0,r.jsx)(n.code,{children:"official"}),", ",(0,r.jsx)(n.code,{children:"admin"}),", ",(0,r.jsx)(n.code,{children:"system"}),", ",(0,r.jsx)(n.code,{children:"api"}),", ",(0,r.jsx)(n.code,{children:"registry"}),", ",(0,r.jsx)(n.code,{children:"cmdforge"})]}),"\n",(0,r.jsx)(n.h2,{id:"auto-fetch-behavior",children:"Auto-Fetch Behavior"}),"\n",(0,r.jsxs)(n.p,{children:["When enabled (",(0,r.jsx)(n.code,{children:"auto_fetch_from_registry: true"}),"), missing tools are automatically fetched:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ summarize < file.txt\n# Tool 'summarize' not found locally.\n# Fetching from registry...\n# Installed: official/summarize@1.2.0\n# Running...\n"})}),"\n",(0,r.jsx)(n.p,{children:"Behavior details:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Fetches latest stable version unless pinned in ",(0,r.jsx)(n.code,{children:"cmdforge.yaml"})]}),"\n",(0,r.jsxs)(n.li,{children:["Installs to ",(0,r.jsx)(n.code,{children:"~/.cmdforge/<owner>/<name>/"})]}),"\n",(0,r.jsxs)(n.li,{children:["Generates wrapper script in ",(0,r.jsx)(n.code,{children:"~/.local/bin/"})]}),"\n",(0,r.jsx)(n.li,{children:"Subsequent runs use local copy (no re-fetch)"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"To disable (require explicit install):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"# ~/.cmdforge/config.yaml\nauto_fetch_from_registry: false\n"})}),"\n",(0,r.jsx)(n.h3,{id:"wrapper-script-collisions",children:"Wrapper Script Collisions"}),"\n",(0,r.jsx)(n.p,{children:"When two tools from different owners have the same name:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scenario"}),(0,r.jsx)(n.th,{children:"Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Install ",(0,r.jsx)(n.code,{children:"official/summarize"})]}),(0,r.jsxs)(n.td,{children:["Creates wrapper ",(0,r.jsx)(n.code,{children:"~/.local/bin/summarize"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Install ",(0,r.jsx)(n.code,{children:"rob/summarize"})," (collision)"]}),(0,r.jsxs)(n.td,{children:["Creates wrapper ",(0,r.jsx)(n.code,{children:"~/.local/bin/rob-summarize"})]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Uninstall ",(0,r.jsx)(n.code,{children:"official/summarize"})]}),(0,r.jsxs)(n.td,{children:["Removes ",(0,r.jsx)(n.code,{children:"summarize"})," wrapper, promotes ",(0,r.jsx)(n.code,{children:"rob-summarize"})," \u2192 ",(0,r.jsx)(n.code,{children:"summarize"})," if desired"]})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:["The first-installed tool with a given name gets the short wrapper. Subsequent tools use ",(0,r.jsx)(n.code,{children:"owner-name"})," format."]}),"\n",(0,r.jsx)(n.p,{children:"To invoke a specific owner's tool:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Short form (whichever was installed first)\nsummarize < file.txt\n\n# Explicit owner form (always works)\nrob-summarize < file.txt\n\n# Or via cmdforge run\ncmdforge run rob/summarize < file.txt\n"})}),"\n",(0,r.jsx)(n.h2,{id:"project-manifest-cmdforgeyaml",children:"Project Manifest (cmdforge.yaml)"}),"\n",(0,r.jsx)(n.p,{children:"Defines tool dependencies with optional runtime overrides:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'name: my-ai-project\nversion: "1.0.0"\ndependencies:\n - name: rob/summarize\n version: ">=1.0.0"\noverrides:\n rob/summarize:\n provider: ollama\n'})}),"\n",(0,r.jsx)(n.p,{children:"Overrides are applied at runtime and do not mutate installed tool configs."}),"\n",(0,r.jsx)(n.h2,{id:"cli-config-and-tokens",children:"CLI Config and Tokens"}),"\n",(0,r.jsxs)(n.p,{children:["Global config lives in ",(0,r.jsx)(n.code,{children:"~/.cmdforge/config.yaml"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'registry:\n url: https://cmdforge.brrd.tech/api/v1 # Must match canonical base path\n token: "reg_xxxxxxxxxxxx"\nclient_id: "anon_abc123def456"\nauto_fetch_from_registry: true\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"client_id"})," is generated locally and used for anonymous install dedupe."]}),"\n",(0,r.jsx)(n.h2,{id:"publishing-and-auth",children:"Publishing and Auth"}),"\n",(0,r.jsx)(n.p,{children:"Publishing uses registry accounts, not Gitea accounts:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Public endpoints require no auth."}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"POST /tools"})," requires a registry token."]}),"\n",(0,r.jsx)(n.li,{children:"The API server uses a private Gitea service account to open PRs."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"publish-idempotency-and-edge-cases",children:"Publish Idempotency and Edge Cases"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Idempotency key:"})," ",(0,r.jsx)(n.code,{children:"owner/name@version"})]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scenario"}),(0,r.jsx)(n.th,{children:"API Response"}),(0,r.jsx)(n.th,{children:"HTTP Code"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"New version, no PR exists"}),(0,r.jsx)(n.td,{children:"Create PR, return URL"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"201 Created"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"PR already exists (pending)"}),(0,r.jsx)(n.td,{children:"Return existing PR URL"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"200 OK"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Version already published"}),(0,r.jsx)(n.td,{children:"Error: version exists"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"409 Conflict"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"PR was closed without merge"}),(0,r.jsx)(n.td,{children:"Allow new PR"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"201 Created"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"PR was merged, then tool deleted"}),(0,r.jsx)(n.td,{children:"Error: version exists (tombstone)"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"409 Conflict"})})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Version immutability enforcement:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'// Attempt to publish existing version\n// Response: 409 Conflict\n{\n "error": {\n "code": "VERSION_EXISTS",\n "message": "Version 1.2.0 of \'rob/summarize\' already exists and cannot be overwritten",\n "details": {\n "published_at": "2025-01-15T10:30:00Z",\n "action": "Bump version number to publish changes"\n }\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Closed PR handling:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Track PR state in database: ",(0,r.jsx)(n.code,{children:"pending"}),", ",(0,r.jsx)(n.code,{children:"merged"}),", ",(0,r.jsx)(n.code,{children:"closed"})]}),"\n",(0,r.jsx)(n.li,{children:"If PR was closed (rejected/abandoned), allow new submission for same version"}),"\n",(0,r.jsx)(n.li,{children:"If PR was merged, version is immutable forever"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Update flow (new version, not overwrite):"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Developer modifies tool locally"}),"\n",(0,r.jsxs)(n.li,{children:["Bumps version in ",(0,r.jsx)(n.code,{children:"config.yaml"})," (e.g., ",(0,r.jsx)(n.code,{children:"1.2.0"})," \u2192 ",(0,r.jsx)(n.code,{children:"1.3.0"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:["Runs ",(0,r.jsx)(n.code,{children:"cmdforge registry publish"})]}),"\n",(0,r.jsxs)(n.li,{children:["New PR created for ",(0,r.jsx)(n.code,{children:"1.3.0"})]}),"\n",(0,r.jsxs)(n.li,{children:["Old version ",(0,r.jsx)(n.code,{children:"1.2.0"})," remains available"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"publisher-registration",children:"Publisher Registration"}),"\n",(0,r.jsx)(n.p,{children:"Publishers register on the registry website, not Gitea:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Registration flow:"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["User visits ",(0,r.jsx)(n.code,{children:"https://gitea.brrd.tech/registry/register"})," (or future ",(0,r.jsx)(n.code,{children:"cmdforge.brrd.tech"}),")"]}),"\n",(0,r.jsx)(n.li,{children:"Creates account with email + password + slug"}),"\n",(0,r.jsxs)(n.li,{children:["Receives verification email (optional in v1, but track ",(0,r.jsx)(n.code,{children:"verified"})," status)"]}),"\n",(0,r.jsxs)(n.li,{children:["Logs into dashboard at ",(0,r.jsx)(n.code,{children:"/dashboard"})]}),"\n",(0,r.jsx)(n.li,{children:"Generates API token from dashboard"}),"\n",(0,r.jsx)(n.li,{children:"Uses token in CLI for publishing"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"authentication-security",children:"Authentication Security"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Password hashing:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Algorithm: Argon2id (memory-hard, recommended by OWASP)"}),"\n",(0,r.jsxs)(n.li,{children:["Parameters: ",(0,r.jsx)(n.code,{children:"memory=65536, iterations=3, parallelism=4"})]}),"\n",(0,r.jsxs)(n.li,{children:["Library: ",(0,r.jsx)(n.code,{children:"argon2-cffi"})," for Python"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from argon2 import PasswordHasher\nph = PasswordHasher(memory_cost=65536, time_cost=3, parallelism=4)\nhash = ph.hash(password)\nph.verify(hash, password) # raises on mismatch\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"API token format:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"reg_<random-32-bytes-base62>\n\nExample: reg_7kX9mPqR2sT4vW6xY8zA1bC3dE5fG7hJ\n"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Prefix ",(0,r.jsx)(n.code,{children:"reg_"})," for easy identification in logs/configs"]}),"\n",(0,r.jsx)(n.li,{children:"32 bytes of cryptographically random data"}),"\n",(0,r.jsx)(n.li,{children:"Base62 encoded (alphanumeric, no special chars)"}),"\n",(0,r.jsx)(n.li,{children:"Total length: ~47 characters"}),"\n",(0,r.jsx)(n.li,{children:"Stored as SHA-256 hash in database (never plain text)"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Token lifecycle:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Action"}),(0,r.jsx)(n.th,{children:"Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Generate"}),(0,r.jsx)(n.td,{children:"Create new token, return once, store hash"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"List"}),(0,r.jsx)(n.td,{children:"Show token name, created date, last used (not the token itself)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Revoke"}),(0,r.jsxs)(n.td,{children:["Set ",(0,r.jsx)(n.code,{children:"revoked_at"})," timestamp, reject future uses"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Rotate"}),(0,r.jsx)(n.td,{children:"Generate new token, optionally revoke old"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Rate limits:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Endpoint"}),(0,r.jsx)(n.th,{children:"Limit"}),(0,r.jsx)(n.th,{children:"Window"}),(0,r.jsx)(n.th,{children:"Scope"}),(0,r.jsx)(n.th,{children:"Retry-After"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"POST /register"})}),(0,r.jsx)(n.td,{children:"5"}),(0,r.jsx)(n.td,{children:"1 hour"}),(0,r.jsx)(n.td,{children:"IP"}),(0,r.jsx)(n.td,{children:"3600"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"POST /login"})}),(0,r.jsx)(n.td,{children:"10"}),(0,r.jsx)(n.td,{children:"15 min"}),(0,r.jsx)(n.td,{children:"IP"}),(0,r.jsx)(n.td,{children:"900"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"POST /login"})," (failed)"]}),(0,r.jsx)(n.td,{children:"5"}),(0,r.jsx)(n.td,{children:"15 min"}),(0,r.jsx)(n.td,{children:"IP + email"}),(0,r.jsx)(n.td,{children:"900"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"POST /tokens"})}),(0,r.jsx)(n.td,{children:"10"}),(0,r.jsx)(n.td,{children:"1 hour"}),(0,r.jsx)(n.td,{children:"Token"}),(0,r.jsx)(n.td,{children:"3600"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"POST /tools"})}),(0,r.jsx)(n.td,{children:"20"}),(0,r.jsx)(n.td,{children:"1 hour"}),(0,r.jsx)(n.td,{children:"Token"}),(0,r.jsx)(n.td,{children:"3600"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools/*"})}),(0,r.jsx)(n.td,{children:"100"}),(0,r.jsx)(n.td,{children:"1 min"}),(0,r.jsx)(n.td,{children:"IP"}),(0,r.jsx)(n.td,{children:"60"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /download"})}),(0,r.jsx)(n.td,{children:"60"}),(0,r.jsx)(n.td,{children:"1 min"}),(0,r.jsx)(n.td,{children:"IP"}),(0,r.jsx)(n.td,{children:"60"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Rate limit response (429):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "error": {\n "code": "RATE_LIMITED",\n "message": "Too many requests. Try again in 60 seconds.",\n "details": {\n "limit": 100,\n "window": "1 minute",\n "retry_after": 60\n }\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Headers on rate-limited response:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"HTTP/1.1 429 Too Many Requests\nRetry-After: 60\nX-RateLimit-Limit: 100\nX-RateLimit-Remaining: 0\nX-RateLimit-Reset: 1705766400\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Scope priority:"})," For authenticated requests, both IP and token limits apply. The more restrictive limit wins."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Account lockout:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"After 5 failed login attempts: 15-minute lockout for that email"}),"\n",(0,r.jsx)(n.li,{children:"After 10 failed attempts: 1-hour lockout"}),"\n",(0,r.jsx)(n.li,{children:"Lockout clears on successful password reset"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Password reset flow (deferred to v1.1):"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"User requests reset via email"}),"\n",(0,r.jsx)(n.li,{children:"Server generates time-limited token (1 hour expiry)"}),"\n",(0,r.jsx)(n.li,{children:"Email contains reset link with token"}),"\n",(0,r.jsx)(n.li,{children:"User sets new password"}),"\n",(0,r.jsx)(n.li,{children:"All existing sessions/tokens optionally invalidated"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Email verification flow (deferred to v1.1):"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"On registration, send verification email"}),"\n",(0,r.jsx)(n.li,{children:"User clicks link with verification token"}),"\n",(0,r.jsxs)(n.li,{children:["Set ",(0,r.jsx)(n.code,{children:"verified = true"})," in database"]}),"\n",(0,r.jsx)(n.li,{children:"Unverified accounts can browse but not publish"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"token-scopes-and-authorization",children:"Token Scopes and Authorization"}),"\n",(0,r.jsx)(n.p,{children:"Tokens have scopes that limit their capabilities:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scope"}),(0,r.jsx)(n.th,{children:"Permissions"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"read"})}),(0,r.jsx)(n.td,{children:"View own published tools, download stats"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"publish"})}),(0,r.jsx)(n.td,{children:"Submit new tools, update own tool metadata"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"admin"})}),(0,r.jsx)(n.td,{children:"Yank tools, manage categories (registry admins only)"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Default scope:"})," New tokens get ",(0,r.jsx)(n.code,{children:"read,publish"})," by default."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Ownership enforcement:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"@app.route('/api/v1/tools', methods=['POST'])\n@require_token(scopes=['publish'])\ndef publish_tool():\n token = get_current_token()\n tool_data = request.json\n\n # Enforce owner == token holder's slug\n if tool_data['owner'] != token.publisher.slug:\n return {\n \"error\": {\n \"code\": \"FORBIDDEN\",\n \"message\": f\"Cannot publish to namespace '{tool_data['owner']}'. \"\n f\"Your namespace is '{token.publisher.slug}'.\"\n }\n }, 403\n\n # Proceed with publish...\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:[(0,r.jsx)(n.code,{children:"GET /api/v1/me/tools"})," authorization:"]})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Requires valid token with ",(0,r.jsx)(n.code,{children:"read"})," scope"]}),"\n",(0,r.jsxs)(n.li,{children:["Returns only tools where ",(0,r.jsx)(n.code,{children:"owner == token.publisher.slug"})]}),"\n",(0,r.jsx)(n.li,{children:"Includes pending PRs and all versions (including yanked)"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"web-session-security",children:"Web Session Security"}),"\n",(0,r.jsx)(n.p,{children:"Dashboard login uses session cookies (not tokens) for browser auth:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Cookie settings:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"SESSION_COOKIE_NAME = 'cmdforge_session'\nSESSION_COOKIE_HTTPONLY = True # Prevent JS access\nSESSION_COOKIE_SECURE = True # HTTPS only in production\nSESSION_COOKIE_SAMESITE = 'Lax' # CSRF protection\nSESSION_COOKIE_MAX_AGE = 86400 * 7 # 7 days\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"CSRF protection:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["All POST/PUT/DELETE forms include ",(0,r.jsx)(n.code,{children:"csrf_token"})," hidden field"]}),"\n",(0,r.jsx)(n.li,{children:"Token validated server-side before processing"}),"\n",(0,r.jsx)(n.li,{children:"403 Forbidden if token missing or invalid"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Session lifecycle:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Event"}),(0,r.jsx)(n.th,{children:"Action"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Login"}),(0,r.jsx)(n.td,{children:"Create session, set cookie"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Logout"}),(0,r.jsx)(n.td,{children:"Delete session, clear cookie"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Idle 24h"}),(0,r.jsx)(n.td,{children:"Session expires, re-login required"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Password change"}),(0,r.jsx)(n.td,{children:"Invalidate all sessions"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Token revocation"}),(0,r.jsx)(n.td,{children:"Existing sessions continue (token != session)"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Secure session storage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"# Store sessions in DB, not filesystem\nfrom flask_session import Session\napp.config['SESSION_TYPE'] = 'sqlalchemy'\napp.config['SESSION_SQLALCHEMY_TABLE'] = 'sessions'\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Database schema:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:'-- Publishers\nCREATE TABLE publishers (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n email TEXT UNIQUE NOT NULL,\n password_hash TEXT NOT NULL,\n slug TEXT UNIQUE NOT NULL, -- immutable namespace: "rob", "alice-dev"\n display_name TEXT NOT NULL, -- mutable: "Rob", "Alice Developer"\n bio TEXT,\n website TEXT,\n verified BOOLEAN DEFAULT FALSE,\n locked_until TIMESTAMP, -- account lockout\n failed_login_attempts INTEGER DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\n-- API tokens (one publisher can have multiple)\nCREATE TABLE api_tokens (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n publisher_id INTEGER NOT NULL REFERENCES publishers(id),\n token_hash TEXT NOT NULL,\n name TEXT NOT NULL, -- "CLI token", "CI token"\n last_used_at TIMESTAMP,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n revoked_at TIMESTAMP -- NULL if active\n);\n\n-- Tools (links to publisher)\nCREATE TABLE tools (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n owner TEXT NOT NULL, -- namespace slug (immutable, from publisher.slug)\n name TEXT NOT NULL,\n version TEXT NOT NULL,\n description TEXT,\n category TEXT,\n tags TEXT, -- JSON array\n config_yaml TEXT NOT NULL, -- Full tool config\n readme TEXT,\n publisher_id INTEGER NOT NULL REFERENCES publishers(id),\n deprecated BOOLEAN DEFAULT FALSE,\n deprecated_message TEXT,\n replacement TEXT,\n downloads INTEGER DEFAULT 0,\n published_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n UNIQUE(owner, name, version)\n);\n\n-- Download stats (for deduplication)\nCREATE TABLE download_stats (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n tool_id INTEGER NOT NULL REFERENCES tools(id),\n client_id TEXT NOT NULL,\n downloaded_at DATE NOT NULL,\n UNIQUE(tool_id, client_id, downloaded_at)\n);\n\n-- Search index (FTS5)\nCREATE VIRTUAL TABLE tools_fts USING fts5(\n name, description, tags, readme,\n content=\'tools\',\n content_rowid=\'id\'\n);\n\n-- FTS5 sync triggers (required for external content tables)\nCREATE TRIGGER tools_ai AFTER INSERT ON tools BEGIN\n INSERT INTO tools_fts(rowid, name, description, tags, readme)\n VALUES (new.id, new.name, new.description, new.tags, new.readme);\nEND;\n\nCREATE TRIGGER tools_ad AFTER DELETE ON tools BEGIN\n INSERT INTO tools_fts(tools_fts, rowid, name, description, tags, readme)\n VALUES (\'delete\', old.id, old.name, old.description, old.tags, old.readme);\nEND;\n\nCREATE TRIGGER tools_au AFTER UPDATE ON tools BEGIN\n INSERT INTO tools_fts(tools_fts, rowid, name, description, tags, readme)\n VALUES (\'delete\', old.id, old.name, old.description, old.tags, old.readme);\n INSERT INTO tools_fts(rowid, name, description, tags, readme)\n VALUES (new.id, new.name, new.description, new.tags, new.readme);\nEND;\n\n-- Pending PRs (track publish state)\nCREATE TABLE pending_prs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n publisher_id INTEGER NOT NULL REFERENCES publishers(id),\n owner TEXT NOT NULL,\n name TEXT NOT NULL,\n version TEXT NOT NULL,\n pr_number INTEGER NOT NULL,\n pr_url TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT \'pending\', -- pending, merged, closed\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n UNIQUE(owner, name, version)\n);\n\n-- Webhook sync log (idempotency)\nCREATE TABLE webhook_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n delivery_id TEXT UNIQUE NOT NULL, -- Gitea delivery ID\n event_type TEXT NOT NULL,\n processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Note on tags indexing:"})," The ",(0,r.jsx)(n.code,{children:"tags"})," column stores JSON arrays as text. For v1, FTS5 will search within the JSON string. If tag filtering becomes a bottleneck, normalize to a ",(0,r.jsx)(n.code,{children:"tool_tags"})," junction table:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"-- Future: normalized tags (if needed)\nCREATE TABLE tags (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL\n);\n\nCREATE TABLE tool_tags (\n tool_id INTEGER REFERENCES tools(id),\n tag_id INTEGER REFERENCES tags(id),\n PRIMARY KEY (tool_id, tag_id)\n);\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Connecting to your account:"})}),"\n",(0,r.jsx)(n.p,{children:"The recommended way to authenticate is using the app pairing flow, which eliminates manual token copying:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"CLI connection flow:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ cmdforge config connect rob\n\nConnecting to CmdForge as @rob...\nDevice: my-laptop\n\nWaiting for approval from the web interface...\nGo to https://cmdforge.brrd.tech/dashboard/connections\nand click 'Connect New App', then 'I've Run the Command'\n\nPress Ctrl+C to cancel\n\nWaiting...\n\nConnected successfully!\nYour device 'my-laptop' is now linked to @rob\n\nYou can now publish tools with: cmdforge registry publish\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"TUI connection flow:"})}),"\n",(0,r.jsxs)(n.p,{children:["The TUI (",(0,r.jsx)(n.code,{children:"cmdforge ui"}),") includes a Connect button for connecting without using the command line:"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:'Click "Connect" button in the main menu'}),"\n",(0,r.jsx)(n.li,{children:"Enter your CmdForge username (create account at cmdforge.brrd.tech if needed)"}),"\n",(0,r.jsx)(n.li,{children:"A countdown timer shows the pairing expiration (5 minutes)"}),"\n",(0,r.jsx)(n.li,{children:"Go to cmdforge.brrd.tech/dashboard/connections in your browser"}),"\n",(0,r.jsx)(n.li,{children:'Click "Connect New App" and approve the pending connection'}),"\n",(0,r.jsx)(n.li,{children:"TUI automatically detects approval and saves the token"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"CLI first-time publish flow:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ cmdforge registry publish\n\nNo registry account configured.\n\nOptions:\n1. Connect to account (recommended): cmdforge config connect <username>\n2. Manual token entry\n\nChoose option [1]: 1\nEnter username: rob\n\nConnecting to CmdForge as @rob...\n[Follows connection flow above]\n\nValidating tool...\n\u2713 config.yaml is valid\n\u2713 README.md exists (2.3 KB)\n\u2713 Version 1.0.0 not yet published\n\nPublishing rob/my-tool@1.0.0...\n\u2713 PR created: https://gitea.brrd.tech/rob/CmdForge-Registry/pulls/42\n\nYour tool is pending review. You'll receive an email when it's approved.\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"TUI publish flow:"})}),"\n",(0,r.jsx)(n.p,{children:'When already connected, the TUI main menu shows "Publish" instead of "Connect":'}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Select a tool in the list"}),"\n",(0,r.jsx)(n.li,{children:'Click "Publish" button'}),"\n",(0,r.jsx)(n.li,{children:"If no version in config, TUI prompts for version number"}),"\n",(0,r.jsx)(n.li,{children:"Confirm and publish"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Private sync after save:"})}),"\n",(0,r.jsx)(n.p,{children:"When connected to an account, saving a tool in the TUI offers to sync it privately to the registry:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Save a tool (new or edited)"}),"\n",(0,r.jsx)(n.li,{children:'TUI asks: "Sync to registry privately?"'}),"\n",(0,r.jsx)(n.li,{children:"If yes, enter/confirm version number"}),"\n",(0,r.jsxs)(n.li,{children:["Tool is published with ",(0,r.jsx)(n.code,{children:"visibility: private"})," (only you can see it)"]}),"\n",(0,r.jsx)(n.li,{children:"Useful for backup or accessing your tools from multiple machines"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"cli-commands-reference",children:"CLI Commands Reference"}),"\n",(0,r.jsx)(n.p,{children:"Full mapping of CLI commands to API calls:"}),"\n",(0,r.jsx)(n.h3,{id:"registry-commands",children:"Registry Commands"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Search for tools (basic)\n$ cmdforge registry search <query> [--category=<cat>] [--limit=20]\n \u2192 GET /api/v1/tools/search?q=<query>&category=<cat>&limit=20\n\n# Search with advanced filtering\n$ cmdforge registry search <query> [options]\n Options:\n -c, --category CAT Filter by category\n -t, --tag TAG Filter by tag (repeatable, AND logic)\n -o, --owner OWNER Filter by publisher/owner\n --min-downloads N Minimum downloads\n --popular Shortcut for --min-downloads 100\n --new Shortcut for --max-downloads 10\n --since DATE Published after (YYYY-MM-DD)\n --before DATE Published before (YYYY-MM-DD)\n -s, --sort FIELD Sort by: relevance, downloads, published_at, name\n -l, --limit N Max results (default: 20)\n --json Output as JSON\n --show-facets Show category/tag counts\n --deprecated Include deprecated tools\n\n# List available tags\n$ cmdforge registry tags [-c CATEGORY] [-l LIMIT] [--json]\n \u2192 GET /api/v1/tags?category=<cat>&limit=<limit>\n\n# Browse tools (TUI)\n$ cmdforge registry browse [--category=<cat>]\n \u2192 GET /api/v1/tools?category=<cat>&page=1\n \u2192 GET /api/v1/categories\n\n# View tool details\n$ cmdforge registry info <owner/name>\n \u2192 GET /api/v1/tools/<owner>/<name>\n\n# Install a tool\n$ cmdforge registry install <owner/name> [--version=<ver>]\n \u2192 GET /api/v1/tools/<owner>/<name>/download?version=<ver>&install=true\n \u2192 Writes to ~/.cmdforge/<owner>/<name>/config.yaml\n \u2192 Generates ~/.local/bin/<name> wrapper (or <owner>-<name> if collision)\n\n# Uninstall a tool\n$ cmdforge registry uninstall <owner/name>\n \u2192 Removes ~/.cmdforge/<owner>/<name>/\n \u2192 Removes wrapper script\n\n# Publish a tool\n$ cmdforge registry publish [path] [--dry-run]\n \u2192 POST /api/v1/tools (with registry token)\n \u2192 Returns PR URL\n\n# List my published tools\n$ cmdforge registry my-tools\n \u2192 GET /api/v1/me/tools (with registry token)\n\n# Update index cache\n$ cmdforge registry update\n \u2192 GET /api/v1/index.json\n \u2192 Writes to ~/.cmdforge/registry/index.json\n"})}),"\n",(0,r.jsx)(n.h3,{id:"project-commands",children:"Project Commands"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Install project dependencies from cmdforge.yaml\n$ cmdforge install\n \u2192 Reads ./cmdforge.yaml\n \u2192 For each dependency:\n GET /api/v1/tools/<owner>/<name>/download?version=<constraint>&install=true\n \u2192 Installs to ~/.cmdforge/<owner>/<name>/\n\n# Add a dependency to cmdforge.yaml\n$ cmdforge add <owner/name> [--version=<constraint>]\n \u2192 Adds to ./cmdforge.yaml dependencies\n \u2192 Runs install for that tool\n\n# Show project dependencies status\n$ cmdforge deps\n \u2192 Reads ./cmdforge.yaml\n \u2192 Shows installed status for each dependency\n \u2192 Note: "cmdforge list" is reserved for listing installed tools\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Command naming note:"})," ",(0,r.jsx)(n.code,{children:"cmdforge list"})," already exists to list locally installed tools. Use ",(0,r.jsx)(n.code,{children:"cmdforge deps"})," to show project manifest dependencies."]}),"\n",(0,r.jsx)(n.h3,{id:"config-commands",children:"Config Commands"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Show current configuration\n$ cmdforge config show\n \u2192 Displays registry URL, token status, client ID, auto-fetch setting\n\n# Connect to your CmdForge account (recommended)\n$ cmdforge config connect <username>\n \u2192 Initiates app pairing flow\n \u2192 Polls /api/v1/pairing/check/<username>?hostname=<hostname>\n \u2192 On approval, saves token to ~/.cmdforge/config.yaml\n\n# Set registry token manually (alternative to connect)\n$ cmdforge config set-token <token>\n \u2192 Saves token to ~/.cmdforge/config.yaml\n\n# Set configuration values\n$ cmdforge config set <key> <value>\n \u2192 Available keys: auto_fetch, default_provider, registry_url\n"})}),"\n",(0,r.jsx)(n.h3,{id:"flags-available-on-most-commands",children:"Flags available on most commands"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Flag"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--offline"})}),(0,r.jsx)(n.td,{children:"Use cached index only, don't fetch"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--refresh"})}),(0,r.jsx)(n.td,{children:"Force refresh of cached data"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--json"})}),(0,r.jsx)(n.td,{children:"Output in JSON format"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--verbose"})}),(0,r.jsx)(n.td,{children:"Show detailed output"})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"publish-state-tracking",children:"Publish State Tracking"}),"\n",(0,r.jsx)(n.p,{children:"The GUI tracks the publish state of local tools to show whether they've been published, are pending review, or have been modified since publishing."}),"\n",(0,r.jsx)(n.h3,{id:"local-state-storage",children:"Local State Storage"}),"\n",(0,r.jsxs)(n.p,{children:["When a tool is published, two fields are saved to the local ",(0,r.jsx)(n.code,{children:"config.yaml"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: my-tool\ndescription: My awesome tool\n# ... tool config ...\nregistry_hash: sha256:abc123... # Hash of published config\nregistry_status: pending # Moderation status: pending, approved, rejected\n"})}),"\n",(0,r.jsx)(n.h3,{id:"visual-indicators",children:"Visual Indicators"}),"\n",(0,r.jsx)(n.p,{children:"The Tools page shows different indicators based on publish state:"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"State"}),(0,r.jsx)(n.th,{children:"Indicator"}),(0,r.jsx)(n.th,{children:"Meaning"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Published"}),(0,r.jsx)(n.td,{children:"\u2713 (green)"}),(0,r.jsx)(n.td,{children:"Approved in registry, local matches published"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Pending"}),(0,r.jsx)(n.td,{children:"\u25d0 (yellow)"}),(0,r.jsx)(n.td,{children:"Submitted, awaiting moderator review"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Modified"}),(0,r.jsx)(n.td,{children:"\u25cf (orange)"}),(0,r.jsx)(n.td,{children:"Published but local config has changes"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Local"}),(0,r.jsx)(n.td,{children:"(none)"}),(0,r.jsx)(n.td,{children:"Never published to registry"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"automatic-status-sync",children:"Automatic Status Sync"}),"\n",(0,r.jsx)(n.p,{children:"When the Tools page loads, a background sync automatically checks the registry for status updates on all published tools. This means:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"When a moderator approves your tool, the indicator updates automatically on next visit"}),"\n",(0,r.jsx)(n.li,{children:"No manual refresh needed - just navigate to the Tools page"}),"\n",(0,r.jsx)(n.li,{children:"Status messages appear when tool statuses change"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"manual-sync",children:"Manual Sync"}),"\n",(0,r.jsx)(n.p,{children:'A "Sync Status" button is available to force an immediate status check for the selected tool. This is useful if you want to check status without leaving the page.'}),"\n",(0,r.jsx)(n.h3,{id:"hash-computation",children:"Hash Computation"}),"\n",(0,r.jsx)(n.p,{children:"The publish state hash is computed from the tool's core content, excluding:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"registry_hash"})," - The stored hash itself"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"registry_status"})," - The moderation status"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"version"})," - Publication version (added during publish)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"tags"})," - Publication tags (added during publish)"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:'This ensures that only actual tool content changes (steps, arguments, prompts) trigger the "modified" indicator.'}),"\n",(0,r.jsx)(n.h3,{id:"api-endpoint",children:"API Endpoint"}),"\n",(0,r.jsx)(n.p,{children:"The status sync uses:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'GET /api/v1/me/tools/<name>/status\n\nResponse:\n{\n "data": {\n "name": "my-tool",\n "version": "1.0.0",\n "status": "approved",\n "config_hash": "sha256:abc123...",\n "published_at": "2025-01-15T10:30:00Z"\n }\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"webhooks-and-security",children:"Webhooks and Security"}),"\n",(0,r.jsx)(n.h3,{id:"hmac-verification",children:"HMAC Verification"}),"\n",(0,r.jsx)(n.p,{children:"All Gitea webhooks are verified using HMAC-SHA256:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"import hmac\nimport hashlib\n\ndef verify_webhook(request, secret):\n signature = request.headers.get('X-Gitea-Signature')\n if not signature:\n return False\n\n expected = hmac.new(\n secret.encode(),\n request.body,\n hashlib.sha256\n ).hexdigest()\n\n return hmac.compare_digest(signature, expected)\n"})}),"\n",(0,r.jsx)(n.h3,{id:"replay-protection",children:"Replay Protection"}),"\n",(0,r.jsx)(n.p,{children:"While sync is idempotent, implement basic replay protection:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'def process_webhook(request):\n delivery_id = request.headers.get(\'X-Gitea-Delivery\')\n\n # Check if already processed\n if db.webhook_log.exists(delivery_id=delivery_id):\n return {"status": "already_processed"}, 200\n\n # Verify signature\n if not verify_webhook(request, WEBHOOK_SECRET):\n return {"error": "invalid_signature"}, 401\n\n # Process with lock to prevent concurrent processing\n with db.lock(f"webhook:{delivery_id}"):\n # Double-check after acquiring lock\n if db.webhook_log.exists(delivery_id=delivery_id):\n return {"status": "already_processed"}, 200\n\n # Process the webhook\n result = sync_from_repo()\n\n # Log successful processing\n db.webhook_log.insert(\n delivery_id=delivery_id,\n event_type=request.json.get(\'action\'),\n processed_at=datetime.utcnow()\n )\n\n return {"status": "processed"}, 200\n'})}),"\n",(0,r.jsx)(n.h3,{id:"sync-job-locking",children:"Sync Job Locking"}),"\n",(0,r.jsx)(n.p,{children:"Prevent concurrent sync operations:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'# Using file lock or database advisory lock\nSYNC_LOCK_TIMEOUT = 300 # 5 minutes max\n\ndef sync_from_repo():\n try:\n with acquire_lock("registry_sync", timeout=SYNC_LOCK_TIMEOUT):\n # Pull latest from Gitea\n repo.fetch()\n repo.reset(\'origin/main\', hard=True)\n\n # Parse and update database\n for tool_path in glob(\'tools/*/*/config.yaml\'):\n update_tool_in_db(tool_path)\n\n # Rebuild FTS index if needed\n rebuild_fts_index()\n\n except LockTimeout:\n logger.warning("Sync already in progress, skipping")\n return {"status": "skipped", "reason": "sync_in_progress"}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"atomic-sync-strategy",children:"Atomic Sync Strategy"}),"\n",(0,r.jsx)(n.p,{children:"To avoid partially updated DB during webhook sync, use transactional table swap:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'def sync_from_repo_atomic():\n with acquire_lock("registry_sync", timeout=SYNC_LOCK_TIMEOUT):\n # 1. Pull latest from Gitea\n repo.fetch()\n repo.reset(\'origin/main\', hard=True)\n\n # 2. Parse all tools into memory\n new_tools = []\n for tool_path in glob(\'tools/*/*/config.yaml\'):\n tool_data = parse_tool(tool_path)\n if tool_data:\n new_tools.append(tool_data)\n\n # 3. Atomic swap using transaction\n with db.transaction():\n # Create temp table\n db.execute("CREATE TABLE tools_new AS SELECT * FROM tools WHERE 0")\n\n # Bulk insert into temp table\n for tool in new_tools:\n db.execute("INSERT INTO tools_new ...", tool)\n\n # Swap tables atomically\n db.execute("ALTER TABLE tools RENAME TO tools_old")\n db.execute("ALTER TABLE tools_new RENAME TO tools")\n db.execute("DROP TABLE tools_old")\n\n # Rebuild FTS index\n db.execute("INSERT INTO tools_fts(tools_fts) VALUES(\'rebuild\')")\n\n # Update sync timestamp\n db.execute("UPDATE sync_status SET last_sync = ?", [datetime.utcnow()])\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Why atomic:"})," Per-row updates with FTS triggers can yield inconsistent reads under load. Readers may see partial state mid-sync. Table swap ensures all-or-nothing visibility."]}),"\n",(0,r.jsx)(n.h3,{id:"error-handling",children:"Error Handling"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Error Scenario"}),(0,r.jsx)(n.th,{children:"Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Repo fetch fails"}),(0,r.jsx)(n.td,{children:"Log error, retry in 5 min, alert if 3 failures"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"YAML parse error"}),(0,r.jsx)(n.td,{children:"Skip tool, log error, continue with others"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Database write fails"}),(0,r.jsx)(n.td,{children:"Rollback transaction, retry once, then alert"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Lock timeout"}),(0,r.jsx)(n.td,{children:"Skip this sync, next webhook will retry"})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"automated-ci-validation",children:"Automated CI Validation"}),"\n",(0,r.jsx)(n.p,{children:"PRs are validated automatically using CmdForge (dogfooding):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"PR Submitted\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Gitea CI runs validation tools: \u2502\n\u2502 \u2022 schema-validator \u2502\n\u2502 \u2022 security-scanner \u2502\n\u2502 \u2022 duplicate-detector \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 \u2502\n All pass Any fail\n \u2502 \u2502\n \u25bc \u25bc\n Auto-merge or Add comment,\n flag for review request changes\n"})}),"\n",(0,r.jsx)(n.p,{children:"Validation checks:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Schema validation"}),": config.yaml matches expected format"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Security scan"}),": No dangerous shell commands, no secrets in prompts"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Duplicate detection"}),": AI-powered similarity check against existing tools"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"README check"}),": README.md exists and is non-empty"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["CI workflow (",(0,r.jsx)(n.code,{children:".gitea/workflows/validate.yaml"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: Validate Tool Submission\non: [pull_request]\njobs:\n validate:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - name: Validate schema\n run: python scripts/validate_tool.py ${{ github.event.pull_request.head.sha }}\n - name: Security scan\n run: cmdforge run security-scanner < changed_files.txt\n - name: Check duplicates\n run: cmdforge run duplicate-detector < changed_files.txt\n"})}),"\n",(0,r.jsx)(n.h2,{id:"registry-repository-structure",children:"Registry Repository Structure"}),"\n",(0,r.jsx)(n.p,{children:"Full structure of the CmdForge-Registry repo:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"CmdForge-Registry/\n\u251c\u2500\u2500 README.md # Registry overview\n\u251c\u2500\u2500 CONTRIBUTING.md # How to submit tools\n\u251c\u2500\u2500 LICENSE\n\u2502\n\u251c\u2500\u2500 tools/ # All published tools\n\u2502 \u251c\u2500\u2500 rob/\n\u2502 \u2502 \u251c\u2500\u2500 summarize/\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 config.yaml\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 README.md\n\u2502 \u2502 \u2514\u2500\u2500 translate/\n\u2502 \u2502 \u251c\u2500\u2500 config.yaml\n\u2502 \u2502 \u2514\u2500\u2500 README.md\n\u2502 \u2514\u2500\u2500 alice/\n\u2502 \u2514\u2500\u2500 code-review/\n\u2502 \u251c\u2500\u2500 config.yaml\n\u2502 \u2514\u2500\u2500 README.md\n\u2502\n\u251c\u2500\u2500 categories/\n\u2502 \u2514\u2500\u2500 categories.yaml # Category definitions\n\u2502\n\u251c\u2500\u2500 collections/ # Curated tool collections\n\u2502 \u251c\u2500\u2500 text-processing-essentials.yaml\n\u2502 \u251c\u2500\u2500 developer-toolkit.yaml\n\u2502 \u2514\u2500\u2500 data-pipeline-basics.yaml\n\u2502\n\u251c\u2500\u2500 index.json # Auto-generated search index\n\u2502\n\u251c\u2500\u2500 .gitea/\n\u2502 \u2514\u2500\u2500 workflows/\n\u2502 \u251c\u2500\u2500 validate.yaml # PR validation\n\u2502 \u251c\u2500\u2500 build-index.yaml # Rebuild index on merge\n\u2502 \u2514\u2500\u2500 notify-api.yaml # Webhook to API server\n\u2502\n\u2514\u2500\u2500 scripts/\n \u251c\u2500\u2500 validate_tool.py # Schema validation\n \u251c\u2500\u2500 build_index.py # Generate index.json\n \u251c\u2500\u2500 check_duplicates.py # Similarity detection\n \u2514\u2500\u2500 security_scan.py # Security checks\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"categories.yaml"})," format:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"categories:\n - name: text-processing\n description: Tools for manipulating and analyzing text\n icon: \ud83d\udcdd\n - name: code\n description: Tools for code review, generation, and analysis\n icon: \ud83d\udcbb\n - name: data\n description: Tools for data transformation and analysis\n icon: \ud83d\udcca\n - name: media\n description: Tools for image, audio, and video processing\n icon: \ud83c\udfa8\n - name: productivity\n description: General productivity and automation tools\n icon: \u26a1\n"})}),"\n",(0,r.jsx)(n.h2,{id:"download-stats",children:"Download Stats"}),"\n",(0,r.jsx)(n.h3,{id:"counting-methodology",children:"Counting Methodology"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Count installs only, not views or searches"}),"\n",(0,r.jsxs)(n.li,{children:["Increment ",(0,r.jsx)(n.strong,{children:"after"})," successful download (response sent)"]}),"\n",(0,r.jsxs)(n.li,{children:["Dedupe by ",(0,r.jsx)(n.code,{children:"client_id + tool_id + date"})]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'def download_tool(owner, name, version, install=False, client_id=None):\n tool = get_tool(owner, name, version)\n if not tool:\n return {"error": "not_found"}, 404\n\n config_yaml = tool.config_yaml\n\n # Only count if this is an install (not just viewing)\n if install:\n record_download(tool.id, client_id)\n\n return {"config": config_yaml}, 200\n\ndef record_download(tool_id, client_id):\n today = date.today()\n\n # Use client_id if provided, otherwise generate anonymous fallback\n effective_client_id = client_id or f"anon_{hash(request.remote_addr)}"\n\n # Dedupe: only count once per client per tool per day\n try:\n db.download_stats.insert(\n tool_id=tool_id,\n client_id=effective_client_id,\n downloaded_at=today\n )\n # Increment counter (can be async/batch updated)\n db.execute("UPDATE tools SET downloads = downloads + 1 WHERE id = ?", [tool_id])\n except IntegrityError:\n pass # Already counted today, ignore\n'})}),"\n",(0,r.jsx)(n.h3,{id:"client-id-generation",children:"Client ID Generation"}),"\n",(0,r.jsx)(n.p,{children:"CLI generates a persistent anonymous ID on first run:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"# In CLI, on first run\nimport uuid\nimport os\n\nCONFIG_PATH = os.path.expanduser(\"~/.cmdforge/config.yaml\")\n\ndef get_or_create_client_id():\n config = load_config()\n if 'client_id' not in config:\n config['client_id'] = f\"anon_{uuid.uuid4().hex[:16]}\"\n save_config(config)\n return config['client_id']\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Fallback when client_id missing:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["If header ",(0,r.jsx)(n.code,{children:"X-Client-ID"})," not sent, use IP hash as fallback"]}),"\n",(0,r.jsx)(n.li,{children:"This still provides some dedupe for anonymous users"}),"\n",(0,r.jsx)(n.li,{children:"Logged users' downloads are attributed to their account instead"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"privacy-considerations",children:"Privacy Considerations"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"No IP addresses stored in database"}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"client_id"})," is client-controlled and can be regenerated"]}),"\n",(0,r.jsx)(n.li,{children:"Stats are aggregated (total count), not individual tracking"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"async-stats-strategy",children:"Async Stats Strategy"}),"\n",(0,r.jsx)(n.p,{children:"To avoid DB contention on the hot download path:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from queue import Queue\nfrom threading import Thread\n\n# In-memory queue for stats\nstats_queue = Queue()\n\ndef record_download_async(tool_id, client_id):\n """Non-blocking: enqueue for background processing"""\n stats_queue.put({\n \'tool_id\': tool_id,\n \'client_id\': client_id,\n \'date\': date.today()\n })\n\ndef stats_worker():\n """Background thread: batch process stats every 5 seconds"""\n batch = []\n while True:\n try:\n item = stats_queue.get(timeout=5)\n batch.append(item)\n except Empty:\n if batch:\n flush_batch(batch)\n batch = []\n\ndef flush_batch(batch):\n """Bulk insert with conflict ignore"""\n with db.transaction():\n for item in batch:\n try:\n db.execute("""\n INSERT INTO download_stats (tool_id, client_id, downloaded_at)\n VALUES (?, ?, ?)\n ON CONFLICT DO NOTHING\n """, [item[\'tool_id\'], item[\'client_id\'], item[\'date\']])\n except Exception as e:\n logger.warning(f"Stats insert failed: {e}")\n # Don\'t fail downloads for stats errors\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Failure behavior:"}),' If stats DB write fails, log the error but don\'t fail the download. Stats are "best effort" - the download must succeed.']}),"\n",(0,r.jsx)(n.h2,{id:"search",children:"Search"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Primary search: SQLite FTS5 inside the API."}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"index.json"})," provides offline CLI search and backup."]}),"\n",(0,r.jsxs)(n.li,{children:["If FTS5 is stale, return results with ",(0,r.jsx)(n.code,{children:"X-Search-Index-Stale: true"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"api-caching-strategy",children:"API Caching Strategy"}),"\n",(0,r.jsx)(n.h3,{id:"cache-headers",children:"Cache Headers"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Endpoint"}),(0,r.jsx)(n.th,{children:"Cache-Control"}),(0,r.jsx)(n.th,{children:"ETag"}),(0,r.jsx)(n.th,{children:"Notes"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /index.json"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max-age=300, stale-while-revalidate=60"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"5 min cache, background refresh"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools/{owner}/{name}"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max-age=60"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"1 min cache"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools/{owner}/{name}/download"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max-age=3600, immutable"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"Immutable versions, 1 hour"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /tools/search"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"no-cache"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"Always fresh"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"GET /categories"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max-age=3600"})}),(0,r.jsx)(n.td,{children:"Yes"}),(0,r.jsx)(n.td,{children:"Categories change rarely"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"etag-implementation",children:"ETag Implementation"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'import hashlib\nfrom datetime import datetime\n\ndef get_tool_etag(tool):\n """Generate ETag from tool identity (immutable versions don\'t change)"""\n # Since versions are immutable, owner/name@version is stable\n # Use published_at for extra safety (not updated_at, which doesn\'t exist)\n content = f"{tool.owner}/{tool.name}@{tool.version}:{tool.published_at.isoformat()}"\n return hashlib.md5(content.encode()).hexdigest()\n\ndef get_index_etag():\n """Generate ETag from last sync timestamp"""\n last_sync = db.get_last_sync_time()\n return hashlib.md5(last_sync.isoformat().encode()).hexdigest()\n\n@app.route(\'/api/v1/tools/<owner>/<name>/download\')\ndef download_tool(owner, name):\n version = request.args.get(\'version\', \'latest\')\n tool = resolve_and_get_tool(owner, name, version)\n etag = get_tool_etag(tool)\n\n # Check If-None-Match header\n if request.headers.get(\'If-None-Match\') == etag:\n return \'\', 304 # Not Modified\n\n response = jsonify({\n "data": {\n "owner": tool.owner,\n "name": tool.name,\n "resolved_version": tool.version,\n "config": tool.config_yaml\n }\n })\n response.headers[\'ETag\'] = etag\n response.headers[\'Cache-Control\'] = \'max-age=3600, immutable\'\n return response\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Note:"})," Since tool versions are immutable, the ETag based on ",(0,r.jsx)(n.code,{children:"owner/name@version"})," is permanently stable. The ",(0,r.jsx)(n.code,{children:"published_at"})," timestamp is included for defense-in-depth but won't change."]}),"\n",(0,r.jsx)(n.h3,{id:"db-vs-repo-read-strategy",children:"DB vs Repo Read Strategy"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scenario"}),(0,r.jsx)(n.th,{children:"Read From"}),(0,r.jsx)(n.th,{children:"Reason"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Normal operation"}),(0,r.jsx)(n.td,{children:"SQLite DB"}),(0,r.jsx)(n.td,{children:"Fast, indexed, FTS"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"DB empty/corrupted"}),(0,r.jsx)(n.td,{children:"Gitea repo"}),(0,r.jsx)(n.td,{children:"Fallback/recovery"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Webhook sync in progress"}),(0,r.jsx)(n.td,{children:"DB (stale OK)"}),(0,r.jsx)(n.td,{children:"Avoid blocking reads"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Search query"}),(0,r.jsx)(n.td,{children:"SQLite FTS5"}),(0,r.jsx)(n.td,{children:"Full-text search"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Download specific version"}),(0,r.jsx)(n.td,{children:"DB, fallback to repo"}),(0,r.jsx)(n.td,{children:"DB is cache, repo is truth"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"staleness-detection",children:"Staleness Detection"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"STALE_THRESHOLD = timedelta(minutes=10)\n\ndef is_db_stale():\n last_sync = db.get_last_sync_time()\n return datetime.utcnow() - last_sync > STALE_THRESHOLD\n\n@app.route('/tools/search')\ndef search_tools(q):\n results = db.search_fts(q)\n\n response = jsonify({\"results\": results})\n if is_db_stale():\n response.headers['X-Search-Index-Stale'] = 'true'\n response.headers['X-Last-Sync'] = db.get_last_sync_time().isoformat()\n\n return response\n"})}),"\n",(0,r.jsx)(n.h2,{id:"error-model",children:"Error Model"}),"\n",(0,r.jsx)(n.h3,{id:"response-envelopes",children:"Response Envelopes"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Success response:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "data": { ... },\n "meta": {\n "page": 1,\n "per_page": 20,\n "total": 42,\n "total_pages": 3\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Error response:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "error": {\n "code": "TOOL_NOT_FOUND",\n "message": "Tool \'foo/bar\' does not exist",\n "details": {\n "owner": "foo",\n "name": "bar",\n "suggestion": "Did you mean \'rob/bar\'?"\n },\n "docs_url": "https://cmdforge.brrd.tech/docs/errors#TOOL_NOT_FOUND"\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"error-codes",children:"Error Codes"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Code"}),(0,r.jsx)(n.th,{children:"HTTP"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"TOOL_NOT_FOUND"})}),(0,r.jsx)(n.td,{children:"404"}),(0,r.jsx)(n.td,{children:"Tool does not exist"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"VERSION_NOT_FOUND"})}),(0,r.jsx)(n.td,{children:"404"}),(0,r.jsx)(n.td,{children:"Requested version doesn't exist"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"VERSION_EXISTS"})}),(0,r.jsx)(n.td,{children:"409"}),(0,r.jsx)(n.td,{children:"Cannot overwrite published version"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"INVALID_VERSION"})}),(0,r.jsx)(n.td,{children:"400"}),(0,r.jsx)(n.td,{children:"Version string is not valid semver"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"INVALID_CONSTRAINT"})}),(0,r.jsx)(n.td,{children:"400"}),(0,r.jsx)(n.td,{children:"Version constraint syntax error"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CONSTRAINT_UNSATISFIABLE"})}),(0,r.jsx)(n.td,{children:"404"}),(0,r.jsx)(n.td,{children:"No version matches constraint"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"VALIDATION_ERROR"})}),(0,r.jsx)(n.td,{children:"400"}),(0,r.jsx)(n.td,{children:"Tool config validation failed"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"UNAUTHORIZED"})}),(0,r.jsx)(n.td,{children:"401"}),(0,r.jsx)(n.td,{children:"Missing or invalid auth token"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"FORBIDDEN"})}),(0,r.jsx)(n.td,{children:"403"}),(0,r.jsx)(n.td,{children:"Token valid but lacks permission"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"RATE_LIMITED"})}),(0,r.jsx)(n.td,{children:"429"}),(0,r.jsx)(n.td,{children:"Too many requests"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SLUG_TAKEN"})}),(0,r.jsx)(n.td,{children:"409"}),(0,r.jsx)(n.td,{children:"Namespace slug already registered"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ACCOUNT_LOCKED"})}),(0,r.jsx)(n.td,{children:"403"}),(0,r.jsx)(n.td,{children:"Too many failed login attempts"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"SERVER_ERROR"})}),(0,r.jsx)(n.td,{children:"500"}),(0,r.jsx)(n.td,{children:"Internal error (logged for debugging)"})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"error-scenarios-and-fallbacks",children:"Error Scenarios and Fallbacks"}),"\n",(0,r.jsx)(n.h3,{id:"cli-error-handling",children:"CLI Error Handling"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scenario"}),(0,r.jsx)(n.th,{children:"CLI Behavior"}),(0,r.jsx)(n.th,{children:"User Message"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Registry offline"}),(0,r.jsx)(n.td,{children:"Use cached tools if available"}),(0,r.jsx)(n.td,{children:'"Registry unavailable. Using cached version."'})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool not found"}),(0,r.jsx)(n.td,{children:"Check cache, then fail"}),(0,r.jsx)(n.td,{children:"\"Tool 'foo/bar' not found in registry or cache.\""})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Version constraint unsatisfiable"}),(0,r.jsx)(n.td,{children:"Show available versions"}),(0,r.jsx)(n.td,{children:"\"No version matches '>=5.0.0'. Available: 1.0.0, 1.1.0, 1.2.0\""})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Auth token expired"}),(0,r.jsx)(n.td,{children:"Prompt for new token"}),(0,r.jsx)(n.td,{children:'"Token expired. Please re-authenticate."'})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Rate limited"}),(0,r.jsx)(n.td,{children:"Wait and retry (backoff)"}),(0,r.jsx)(n.td,{children:'"Rate limited. Retrying in 30 seconds..."'})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Network timeout"}),(0,r.jsx)(n.td,{children:"Retry with backoff, then fail"}),(0,r.jsx)(n.td,{children:'"Connection timed out. Check your network."'})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"validation-failure-details",children:"Validation Failure Details"}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"VALIDATION_ERROR"})," occurs, provide specific field errors:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "error": {\n "code": "VALIDATION_ERROR",\n "message": "Tool configuration is invalid",\n "details": {\n "errors": [\n {\n "path": "steps[0].provider",\n "message": "Provider \'gpt5\' is not recognized",\n "allowed": ["claude", "openai", "ollama", "mock"]\n },\n {\n "path": "version",\n "message": "Version \'1.0\' is not valid semver (use \'1.0.0\')"\n }\n ]\n },\n "docs_url": "https://cmdforge.brrd.tech/docs/tool-format"\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"dependency-resolution-failures",children:"Dependency Resolution Failures"}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"cmdforge install"})," fails on a manifest:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'$ cmdforge install\n\nError: Could not resolve all dependencies\n\n rob/summarize@^2.0.0\n \u2717 No matching version (latest: 1.2.0)\n\n alice/translate@>=1.0.0\n \u2713 Found 1.3.0\n\nSuggestions:\n - Update rob/summarize constraint to "^1.0.0"\n - Contact the tool author for a v2 release\n'})}),"\n",(0,r.jsx)(n.h3,{id:"graceful-degradation",children:"Graceful Degradation"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Component Down"}),(0,r.jsx)(n.th,{children:"Fallback Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"API server"}),(0,r.jsxs)(n.td,{children:["CLI uses ",(0,r.jsx)(n.code,{children:"~/.cmdforge/registry/index.json"})," for search"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Gitea repo"}),(0,r.jsx)(n.td,{children:"API serves from DB cache (may be stale)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"FTS5 index"}),(0,r.jsx)(n.td,{children:"Fall back to LIKE queries (slower but works)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Network"}),(0,r.jsx)(n.td,{children:"Use locally installed tools, skip registry features"})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"ux-requirements-clitui",children:"UX Requirements (CLI/TUI)"}),"\n",(0,r.jsx)(n.h3,{id:"publishing-ux",children:"Publishing UX"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"cmdforge registry publish --dry-run"})," validates locally and shows what would be submitted:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'$ cmdforge registry publish --dry-run\n\nValidating tool...\n\u2713 config.yaml is valid\n\u2713 README.md exists (2.3 KB)\n\u2713 Version 1.1.0 not yet published\n\nWould submit:\n Owner: rob\n Name: summarize\n Version: 1.1.0\n Category: text-processing\n Tags: summarization, ai, text\n\nConfig preview:\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nname: summarize\nversion: "1.1.0"\ndescription: Summarize text using AI\n...\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nRun without --dry-run to submit for review.\n'})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Version bump reminder:"})," CLI warns if version hasn't changed from published:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"\u26a0 Version 1.0.0 is already published. Bump version in config.yaml to publish changes.\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"First-time publishing flow prompts for token and saves it to config."}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"progress-indicators",children:"Progress Indicators"}),"\n",(0,r.jsx)(n.p,{children:"Long-running operations show progress:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ cmdforge install\n\nInstalling project dependencies...\n [1/3] rob/summarize@^1.0.0\n Resolving version... 1.2.0\n Downloading... done\n Installing... done \u2713\n [2/3] alice/translate@>=2.0.0\n Resolving version... 2.1.0\n Downloading... done\n Installing... done \u2713\n [3/3] official/code-review@*\n Resolving version... 1.0.0\n Downloading... done\n Installing... done \u2713\n\n\u2713 Installed 3 tools\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ cmdforge registry publish\n\nSubmitting rob/summarize@1.1.0...\n Validating... done \u2713\n Uploading... done \u2713\n Creating PR... done \u2713\n\n\u2713 PR created: https://gitea.brrd.tech/rob/CmdForge-Registry/pulls/42\n\nYour tool is pending review. You'll receive an email when it's approved.\n"})}),"\n",(0,r.jsx)(n.h3,{id:"tui-browse",children:"TUI Browse"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"cmdforge registry browse"})," opens a full-screen terminal UI:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"\u250c\u2500 CmdForge Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Search: [________________] [All Categories \u25bc] [Sort: Popular \u25bc] \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u2502\n\u2502 \u25b6 rob/summarize v1.2.0 \u2b07 142 \u2502\n\u2502 Summarize text using AI \u2502\n\u2502 [text-processing] [ai] [summarization] \u2502\n\u2502 \u2502\n\u2502 alice/translate v2.1.0 \u2b07 98 \u2502\n\u2502 Translate text between languages \u2502\n\u2502 [text-processing] [translation] \u2502\n\u2502 \u2502\n\u2502 official/code-review v1.0.0 \u2b07 87 \u2502\n\u2502 AI-powered code review \u2502\n\u2502 [code] [review] [ai] \u2502\n\u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u2191\u2193 Navigate Enter: Details i: Install /: Search q: Quit \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Keyboard shortcuts:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Action"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"\u2191/\u2193"})," or ",(0,r.jsx)(n.code,{children:"j/k"})]}),(0,r.jsx)(n.td,{children:"Navigate list"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"Enter"})}),(0,r.jsx)(n.td,{children:"View tool details"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"i"})}),(0,r.jsx)(n.td,{children:"Install selected tool"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/"})}),(0,r.jsx)(n.td,{children:"Focus search box"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"c"})}),(0,r.jsx)(n.td,{children:"Change category filter"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"s"})}),(0,r.jsx)(n.td,{children:"Change sort order"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"?"})}),(0,r.jsx)(n.td,{children:"Show help"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"q"})}),(0,r.jsx)(n.td,{children:"Quit"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Virtual scrolling:"})," For large tool lists (>100), use virtual scrolling to maintain performance."]}),"\n",(0,r.jsx)(n.h3,{id:"project-initialization",children:"Project Initialization"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"$ cmdforge init\n\nCreating cmdforge.yaml...\n\nProject name [my-project]: my-ai-project\nVersion [1.0.0]:\n\nWould you like to add any tools? (search with 's', skip with Enter)\n> s\nSearch: summ\n 1. rob/summarize v1.2.0 - Summarize text using AI\n 2. alice/summary v1.0.0 - Generate summaries\n\nAdd tool (number, or Enter to finish): 1\nAdded rob/summarize@^1.2.0\n\nAdd tool (number, or Enter to finish):\n\n\u2713 Created cmdforge.yaml\n\nname: my-ai-project\nversion: \"1.0.0\"\ndependencies:\n - name: rob/summarize\n version: \"^1.2.0\"\n\nRun 'cmdforge install' to install dependencies.\n"})}),"\n",(0,r.jsx)(n.h3,{id:"accessibility",children:"Accessibility"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"CLI:"})," All output works with screen readers, no color-only information"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"TUI:"})," Full keyboard navigation, high-contrast mode support"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Web UI:"})," WCAG 2.1 AA compliance target","\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Semantic HTML"}),"\n",(0,r.jsx)(n.li,{children:"ARIA labels for interactive elements"}),"\n",(0,r.jsx)(n.li,{children:"Focus management in modals"}),"\n",(0,r.jsx)(n.li,{children:"Skip links for navigation"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"offline-cache",children:"Offline Cache"}),"\n",(0,r.jsx)(n.p,{children:"Cache registry index locally:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"~/.cmdforge/registry/index.json\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Refresh when older than 24 hours; support ",(0,r.jsx)(n.code,{children:"--offline"})," and ",(0,r.jsx)(n.code,{children:"--refresh"})," flags."]}),"\n",(0,r.jsx)(n.h3,{id:"index-integrity",children:"Index Integrity"}),"\n",(0,r.jsxs)(n.p,{children:["The cached ",(0,r.jsx)(n.code,{children:"index.json"})," includes integrity metadata:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "version": "1.0",\n "generated_at": "2025-01-20T12:00:00Z",\n "checksum": "sha256:abc123...",\n "tool_count": 142,\n "tools": [...]\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"API response headers:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'ETag: "abc123def456"\nX-Index-Checksum: sha256:abc123...\nX-Index-Generated: 2025-01-20T12:00:00Z\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"CLI verification:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"def verify_cached_index():\n \"\"\"Verify cached index integrity on load\"\"\"\n cached = load_cached_index()\n if not cached:\n return None\n\n # Verify checksum\n content = json.dumps(cached['tools'], sort_keys=True)\n computed = hashlib.sha256(content.encode()).hexdigest()\n\n if computed != cached.get('checksum', '').replace('sha256:', ''):\n logger.warning(\"Cached index checksum mismatch, will refresh\")\n return None\n\n return cached\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Corruption handling:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"If checksum fails, discard cache and fetch fresh"}),"\n",(0,r.jsx)(n.li,{children:"If partial write detected (missing fields), discard and refresh"}),"\n",(0,r.jsx)(n.li,{children:'CLI shows warning: "Cached index corrupted, fetching fresh copy..."'}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"web-ui-vision",children:"Web UI Vision"}),"\n",(0,r.jsx)(n.p,{children:"The registry includes a full website, not just an API:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Site structure:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"cmdforge.brrd.tech (or gitea.brrd.tech/registry)\n\u251c\u2500\u2500 / # Landing page\n\u251c\u2500\u2500 /tools # Browse all tools\n\u251c\u2500\u2500 /tools/{owner}/{name} # Tool detail page\n\u251c\u2500\u2500 /categories # Browse by category\n\u251c\u2500\u2500 /categories/{name} # Tools in category\n\u251c\u2500\u2500 /collections # Browse curated collections\n\u251c\u2500\u2500 /collections/{name} # Collection detail page\n\u251c\u2500\u2500 /search?q=... # Search results\n\u251c\u2500\u2500 /docs # Documentation\n\u2502 \u251c\u2500\u2500 /docs/getting-started\n\u2502 \u251c\u2500\u2500 /docs/creating-tools\n\u2502 \u251c\u2500\u2500 /docs/publishing\n\u2502 \u2514\u2500\u2500 /docs/best-practices\n\u251c\u2500\u2500 /tutorials # Step-by-step guides\n\u2502 \u251c\u2500\u2500 /tutorials/first-tool\n\u2502 \u251c\u2500\u2500 /tutorials/chaining-steps\n\u2502 \u2514\u2500\u2500 /tutorials/code-steps\n\u251c\u2500\u2500 /examples # Example projects\n\u251c\u2500\u2500 /blog # Updates, announcements (optional)\n\u251c\u2500\u2500 /register # Publisher registration\n\u251c\u2500\u2500 /login # Publisher login\n\u251c\u2500\u2500 /dashboard # Publisher dashboard\n\u2502 \u251c\u2500\u2500 /dashboard/tools # My published tools\n\u2502 \u251c\u2500\u2500 /dashboard/connections # Connected apps\n\u2502 \u2514\u2500\u2500 /dashboard/settings # Account settings\n\u2514\u2500\u2500 /api/v1/... # API endpoints\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Landing page content:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:'Hero: "Share and discover AI-powered CLI tools"'}),"\n",(0,r.jsx)(n.li,{children:"Quick install example"}),"\n",(0,r.jsx)(n.li,{children:"Featured/popular tools"}),"\n",(0,r.jsx)(n.li,{children:"Category highlights"}),"\n",(0,r.jsx)(n.li,{children:'"Get Started" CTA'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Tool detail page:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Name, description, version, author"}),"\n",(0,r.jsx)(n.li,{children:"README rendered as markdown (sanitized)"}),"\n",(0,r.jsx)(n.li,{children:"Install command (copy-to-clipboard)"}),"\n",(0,r.jsx)(n.li,{children:"Version history"}),"\n",(0,r.jsx)(n.li,{children:"Download stats"}),"\n",(0,r.jsx)(n.li,{children:"Category/tags"}),"\n",(0,r.jsx)(n.li,{children:'"Report" button for abuse'}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"readme-security",children:"README Security"}),"\n",(0,r.jsx)(n.p,{children:"When rendering README markdown, apply XSS sanitization:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"import bleach\nfrom markdown import markdown\n\nALLOWED_TAGS = [\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'p', 'br', 'hr',\n 'ul', 'ol', 'li',\n 'strong', 'em', 'code', 'pre',\n 'blockquote',\n 'a', 'img',\n 'table', 'thead', 'tbody', 'tr', 'th', 'td'\n]\n\nALLOWED_ATTRS = {\n 'a': ['href', 'title'],\n 'img': ['src', 'alt', 'title'],\n 'code': ['class'], # for syntax highlighting\n}\n\ndef render_readme_safe(readme_raw: str) -> str:\n \"\"\"Convert markdown to sanitized HTML\"\"\"\n # Convert markdown to HTML\n html = markdown(readme_raw, extensions=['fenced_code', 'tables'])\n\n # Sanitize to prevent XSS\n safe_html = bleach.clean(\n html,\n tags=ALLOWED_TAGS,\n attributes=ALLOWED_ATTRS,\n strip=True\n )\n\n # Linkify URLs\n safe_html = bleach.linkify(safe_html)\n\n return safe_html\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Storage strategy:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Store raw README in ",(0,r.jsx)(n.code,{children:"tools.readme"})]}),"\n",(0,r.jsx)(n.li,{children:"Render and sanitize on request (or cache rendered HTML)"}),"\n",(0,r.jsx)(n.li,{children:"Never trust client-submitted HTML directly"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Tech stack options:"})}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Option"}),(0,r.jsx)(n.th,{children:"Pros"}),(0,r.jsx)(n.th,{children:"Cons"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Flask + Jinja + Tailwind"}),(0,r.jsx)(n.td,{children:"Simple, Python-only, fast to build"}),(0,r.jsx)(n.td,{children:"Less interactive"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"FastAPI + Vue/React SPA"}),(0,r.jsx)(n.td,{children:"Modern, interactive"}),(0,r.jsx)(n.td,{children:"More complex, separate build"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Astro/Next.js"}),(0,r.jsx)(n.td,{children:"Great SEO, static-first"}),(0,r.jsx)(n.td,{children:"Different stack (Node.js)"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Recommendation:"})," Flask + Jinja + Tailwind for v1"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Keeps everything in Python"}),"\n",(0,r.jsx)(n.li,{children:"Server-rendered is fine for a registry"}),"\n",(0,r.jsx)(n.li,{children:"Good SEO out of the box"}),"\n",(0,r.jsx)(n.li,{children:"Can add interactivity with Alpine.js or htmx if needed"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Monetization considerations:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"AdSense-compatible (server-rendered pages)"}),"\n",(0,r.jsx)(n.li,{children:"Analytics tracking for traffic insights"}),"\n",(0,r.jsx)(n.li,{children:"Future: sponsored tools, featured placements"}),"\n",(0,r.jsx)(n.li,{children:"Future: premium publisher tiers (more tools, priority review)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"registry-curation-system",children:"Registry Curation System"}),"\n",(0,r.jsx)(n.p,{children:"The registry includes a moderation system for content curation, abuse prevention, and quality control."}),"\n",(0,r.jsx)(n.h3,{id:"roles-and-permissions",children:"Roles and Permissions"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Role"}),(0,r.jsx)(n.th,{children:"Permissions"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"user"})}),(0,r.jsx)(n.td,{children:"Publish tools, manage own tools, view public content"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"moderator"})}),(0,r.jsx)(n.td,{children:"All user permissions + approve/reject tools, resolve reports, view all publishers"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"admin"})}),(0,r.jsx)(n.td,{children:"All moderator permissions + ban/unban publishers, change roles, delete tools, view audit log"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Database columns:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"-- In publishers table\nrole TEXT DEFAULT 'user', -- 'user', 'moderator', 'admin'\nbanned INTEGER DEFAULT 0,\nbanned_at TIMESTAMP,\nbanned_by TEXT,\nban_reason TEXT,\n\n-- In tools table\nvisibility TEXT DEFAULT 'public', -- 'public', 'private', 'unlisted'\nmoderation_status TEXT DEFAULT 'pending', -- 'pending', 'approved', 'rejected', 'removed'\nmoderation_note TEXT,\nmoderated_by TEXT,\nmoderated_at TIMESTAMP,\n"})}),"\n",(0,r.jsx)(n.h3,{id:"tool-visibility",children:"Tool Visibility"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Visibility"}),(0,r.jsx)(n.th,{children:"In Search/List"}),(0,r.jsx)(n.th,{children:"Direct Link"}),(0,r.jsx)(n.th,{children:"Who Can See"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"public"})}),(0,r.jsx)(n.td,{children:"Yes (if approved)"}),(0,r.jsx)(n.td,{children:"Yes (if approved)"}),(0,r.jsx)(n.td,{children:"Everyone"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"private"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"Owner only"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"unlisted"})}),(0,r.jsx)(n.td,{children:"No"}),(0,r.jsx)(n.td,{children:"Yes (if approved)"}),(0,r.jsx)(n.td,{children:"Anyone with link"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"moderation-workflow",children:"Moderation Workflow"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"Tool Published\n \u2502\n \u251c\u2500\u2500 visibility = 'private' or 'unlisted'\n \u2502 \u2514\u2500\u2500 Auto-approved (moderation_status = 'approved')\n \u2502\n \u2514\u2500\u2500 visibility = 'public'\n \u2514\u2500\u2500 moderation_status = 'pending'\n \u2502\n \u251c\u2500\u2500 Moderator approves \u2192 'approved' \u2192 Visible in search\n \u251c\u2500\u2500 Moderator rejects \u2192 'rejected' \u2192 Not visible\n \u2514\u2500\u2500 Moderator removes \u2192 'removed' \u2192 Removed from view\n"})}),"\n",(0,r.jsx)(n.h3,{id:"admin-api-endpoints",children:"Admin API Endpoints"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Tool Moderation (moderator+):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/admin/tools/pending # List pending tools\nGET /api/v1/admin/tools/<id> # Get full tool details for review\nPOST /api/v1/admin/tools/<id>/approve # Approve a tool\nPOST /api/v1/admin/tools/<id>/reject # Reject with reason (required)\nPOST /api/v1/admin/tools/<id>/remove # Soft-delete approved tool\nDELETE /api/v1/admin/tools/<id> # Hard delete (admin only)\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Tool Detail Response (",(0,r.jsx)(n.code,{children:"GET /api/v1/admin/tools/<id>"}),"):"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "data": {\n "id": 123,\n "owner": "alice",\n "name": "my-tool",\n "version": "1.0.0",\n "description": "Tool description",\n "category": "Text Processing",\n "tags": "ai,text",\n "published_at": "2025-01-15T10:30:00Z",\n "publisher_name": "Alice Smith",\n "visibility": "public",\n "moderation_status": "pending",\n "scrutiny_status": "pending_review",\n "scrutiny_report": {\n "findings": [\n {"check": "shell_commands", "result": "warning", "message": "...", "suggestion": "..."}\n ]\n },\n "config": {\n "name": "my-tool",\n "description": "...",\n "arguments": [...],\n "steps": [...]\n },\n "readme": "# My Tool\\n\\nDocumentation here..."\n }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Publisher Management (moderator+ to view, admin to modify):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/admin/publishers # List all publishers\nGET /api/v1/admin/publishers/<id> # Publisher details\nPOST /api/v1/admin/publishers/<id>/ban # Ban with reason (admin)\nPOST /api/v1/admin/publishers/<id>/unban # Unban (admin)\nPOST /api/v1/admin/publishers/<id>/role # Change role (admin)\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Reports (moderator+):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/admin/reports # List reports\nPOST /api/v1/admin/reports/<id>/resolve # Resolve with action\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Audit Log (admin only):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"GET /api/v1/admin/audit-log # View moderation history\n ?target_type=tool|publisher\n ?target_id=<id>\n ?actor_id=<id>\n ?since=<date>\n"})}),"\n",(0,r.jsx)(n.h3,{id:"ban-behavior",children:"Ban Behavior"}),"\n",(0,r.jsx)(n.p,{children:"When a publisher is banned:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"banned"})," set to 1, ",(0,r.jsx)(n.code,{children:"banned_at"}),", ",(0,r.jsx)(n.code,{children:"banned_by"}),", ",(0,r.jsx)(n.code,{children:"ban_reason"})," recorded"]}),"\n",(0,r.jsx)(n.li,{children:"All active API tokens revoked"}),"\n",(0,r.jsxs)(n.li,{children:["All their tools set to ",(0,r.jsx)(n.code,{children:"moderation_status = 'removed'"})]}),"\n",(0,r.jsx)(n.li,{children:"Action logged to audit trail"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Banned publishers see error on any authenticated API call:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "error": {\n "code": "ACCOUNT_BANNED",\n "message": "Your account has been banned: <reason>"\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"report-resolution-actions",children:"Report Resolution Actions"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Action"}),(0,r.jsx)(n.th,{children:"Effect"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"dismiss"})}),(0,r.jsx)(n.td,{children:"Close report, no action taken"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"warn"})}),(0,r.jsx)(n.td,{children:"Close report, no automated action (manual warning)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"remove_tool"})}),(0,r.jsx)(n.td,{children:"Remove the reported tool"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ban_publisher"})}),(0,r.jsx)(n.td,{children:"Ban the tool's publisher"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"audit-log",children:"Audit Log"}),"\n",(0,r.jsx)(n.p,{children:"All moderation actions are logged:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"CREATE TABLE audit_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n action TEXT NOT NULL, -- 'approve_tool', 'reject_tool', 'ban_publisher', etc.\n target_type TEXT NOT NULL, -- 'tool', 'publisher', 'report'\n target_id TEXT NOT NULL,\n actor_id TEXT NOT NULL, -- Who performed the action\n details TEXT, -- JSON with additional context\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n"})}),"\n",(0,r.jsx)(n.h3,{id:"web-ui-admin-dashboard",children:"Web UI Admin Dashboard"}),"\n",(0,r.jsx)(n.p,{children:'Moderators and admins see an "Admin Panel" link in their dashboard sidebar leading to:'}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"/dashboard/admin"})," - Overview with pending counts"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"/dashboard/admin/pending"})," - Pending tools queue"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"/dashboard/admin/publishers"})," - Publisher management"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"/dashboard/admin/reports"})," - Report queue"]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"pending-tools-review-page",children:"Pending Tools Review Page"}),"\n",(0,r.jsxs)(n.p,{children:["The pending tools page (",(0,r.jsx)(n.code,{children:"/dashboard/admin/pending"}),") provides a comprehensive interface for reviewing submitted tools:"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Table View:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Tool name (clickable to open detail modal)"}),"\n",(0,r.jsx)(n.li,{children:"Publisher name and category"}),"\n",(0,r.jsx)(n.li,{children:"Scrutiny status with expandable warnings"}),"\n",(0,r.jsx)(n.li,{children:"Submission date"}),"\n",(0,r.jsx)(n.li,{children:"Approve/Reject action buttons"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Pagination:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Page number links with ellipsis for large ranges"}),"\n",(0,r.jsxs)(n.li,{children:["First (",(0,r.jsx)(n.code,{children:"\xab"}),") and Last (",(0,r.jsx)(n.code,{children:"\xbb"}),") page buttons"]}),"\n",(0,r.jsx)(n.li,{children:"Previous/Next navigation"}),"\n",(0,r.jsx)(n.li,{children:'"Page X of Y (total)" indicator'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Tool Detail Modal:"})}),"\n",(0,r.jsx)(n.p,{children:"Clicking a tool name opens a draggable modal showing:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Scrutiny Warnings"})," - Yellow warning boxes at the top showing any security or quality concerns from automated analysis, including:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:'Check name (e.g., "shell_commands", "network_access")'}),"\n",(0,r.jsx)(n.li,{children:"Warning message"}),"\n",(0,r.jsx)(n.li,{children:"Suggestion for resolution"}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Description"})," - Tool's description text"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Arguments"})," - List of tool arguments with flags, variables, and descriptions"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Steps"})," - Full display of all tool steps:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Prompt steps"}),": Shows provider, output variable, and full prompt content"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Code steps"}),": Shows output variable and code with syntax highlighting (dark theme)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Tool steps"}),": Shows tool name and arguments"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"README"})," - Full README content if provided"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Modal Features:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Draggable by header bar"}),"\n",(0,r.jsx)(n.li,{children:"Scrollable content area (header and buttons stay fixed)"}),"\n",(0,r.jsx)(n.li,{children:"Approve/Reject buttons in modal footer"}),"\n",(0,r.jsx)(n.li,{children:"Dark overlay prevents interaction with page behind"}),"\n",(0,r.jsx)(n.li,{children:"Background scroll locked while modal is open"}),"\n",(0,r.jsx)(n.li,{children:"Closes with X button or after action"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"creating-the-first-admin",children:"Creating the First Admin"}),"\n",(0,r.jsx)(n.p,{children:"After deployment, create the first admin via direct SQL:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"UPDATE publishers SET role = 'admin' WHERE slug = 'rob';\n"})}),"\n",(0,r.jsx)(n.p,{children:"Subsequent admins can be promoted via the web UI or API."}),"\n",(0,r.jsx)(n.h2,{id:"implementation-phases",children:"Implementation Phases"}),"\n",(0,r.jsx)(n.h3,{id:"phase-1-foundation",children:"Phase 1: Foundation"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Define ",(0,r.jsx)(n.code,{children:"cmdforge.yaml"})," manifest format"]}),"\n",(0,r.jsx)(n.li,{children:"Implement tool resolution order (local \u2192 global \u2192 registry)"}),"\n",(0,r.jsx)(n.li,{children:"Create CmdForge-Registry repo on Gitea (bootstrap)"}),"\n",(0,r.jsx)(n.li,{children:"Add 3-5 example tools to seed the registry"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-2-core-backend",children:"Phase 2: Core Backend"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Set up Flask/FastAPI project structure"}),"\n",(0,r.jsx)(n.li,{children:"Implement SQLite database schema"}),"\n",(0,r.jsx)(n.li,{children:"Build core API endpoints (list, search, get, download)"}),"\n",(0,r.jsx)(n.li,{children:"Implement webhook receiver for Gitea sync"}),"\n",(0,r.jsx)(n.li,{children:"Set up HMAC verification"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-3-cli-commands",children:"Phase 3: CLI Commands"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"cmdforge registry search"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"cmdforge registry install"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"cmdforge registry info"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"cmdforge registry browse"})," (TUI)"]}),"\n",(0,r.jsx)(n.li,{children:"Local index caching"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-4-publishing",children:"Phase 4: Publishing"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Publisher registration (web UI)"}),"\n",(0,r.jsx)(n.li,{children:"Token management"}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"cmdforge registry publish"})," command"]}),"\n",(0,r.jsx)(n.li,{children:"PR creation via Gitea API"}),"\n",(0,r.jsx)(n.li,{children:"CI validation workflows"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-5-project-dependencies",children:"Phase 5: Project Dependencies"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"cmdforge install"})," (from manifest)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"cmdforge add"})," command"]}),"\n",(0,r.jsx)(n.li,{children:"Runtime override application"}),"\n",(0,r.jsx)(n.li,{children:"Dependency resolution"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-6-smart-features",children:"Phase 6: Smart Features"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"SQLite FTS5 search index"}),"\n",(0,r.jsx)(n.li,{children:"AI-powered auto-categorization"}),"\n",(0,r.jsx)(n.li,{children:"Duplicate/similarity detection"}),"\n",(0,r.jsx)(n.li,{children:"Security scanning"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-7-full-web-ui",children:"Phase 7: Full Web UI"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Landing page"}),"\n",(0,r.jsx)(n.li,{children:"Tool browsing/search pages"}),"\n",(0,r.jsx)(n.li,{children:"Tool detail pages with README rendering"}),"\n",(0,r.jsx)(n.li,{children:"Publisher dashboard"}),"\n",(0,r.jsx)(n.li,{children:"Documentation/tutorials section"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"phase-8-polish--scale",children:"Phase 8: Polish & Scale"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Rate limiting"}),"\n",(0,r.jsx)(n.li,{children:"Abuse reporting"}),"\n",(0,r.jsx)(n.li,{children:"Analytics integration"}),"\n",(0,r.jsx)(n.li,{children:"Performance optimization"}),"\n",(0,r.jsx)(n.li,{children:"Monitoring/alerting"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453(e,n,s){s.d(n,{R:()=>d,x:()=>t});var i=s(6540);const r={},l=i.createContext(r);function d(e){const n=i.useContext(l);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3fbf7384.013e3796.js b/assets/js/3fbf7384.013e3796.js deleted file mode 100644 index 8917d0c..0000000 --- a/assets/js/3fbf7384.013e3796.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[854],{5253(e){e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docs":[{"type":"link","href":"/rob/CmdForge/","label":"CmdForge Overview","docId":"overview","unlisted":false},{"type":"link","href":"/rob/CmdForge/architecture","label":"CmdForge Architecture","docId":"architecture","unlisted":false},{"type":"category","label":"Reference","collapsible":true,"collapsed":true,"items":[{"type":"link","href":"/rob/CmdForge/reference/providers","label":"Provider Setup","docId":"reference/providers","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/registry-spec","label":"Registry API","docId":"reference/registry-spec","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/meta-tools","label":"Meta-Tools","docId":"reference/meta-tools","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/collections","label":"Collections","docId":"reference/collections","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/examples","label":"Example Tools","docId":"reference/examples","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/design","label":"Design Philosophy","docId":"reference/design","unlisted":false},{"type":"link","href":"/rob/CmdForge/reference/web-ui-spec","label":"Web UI Design","docId":"reference/web-ui-spec","unlisted":false}],"href":"/rob/CmdForge/category/reference"},{"type":"link","href":"/rob/CmdForge/todos","label":"CmdForge TODOs","docId":"todos","unlisted":false},{"type":"link","href":"/rob/CmdForge/goals","label":"Goals","docId":"goals","unlisted":false},{"type":"link","href":"/rob/CmdForge/ideas-and-exploration","label":"Ideas & Exploration","docId":"ideas-and-exploration","unlisted":false},{"type":"link","href":"/rob/CmdForge/milestones","label":"Milestones","docId":"milestones","unlisted":false}]},"docs":{"architecture":{"id":"architecture","title":"CmdForge Architecture","description":"Module Structure","sidebar":"docs"},"goals":{"id":"goals","title":"Goals","description":"Vision","sidebar":"docs"},"ideas-and-exploration":{"id":"ideas-and-exploration","title":"Ideas & Exploration","description":"Completed","sidebar":"docs"},"milestones":{"id":"milestones","title":"Milestones","description":"Active","sidebar":"docs"},"overview":{"id":"overview","title":"CmdForge Overview","description":"A lightweight personal tool builder for AI-powered CLI commands.","sidebar":"docs"},"reference/collections":{"id":"reference/collections","title":"CmdForge Collections","description":"Collections are curated groups of tools that can be installed together with a single command.","sidebar":"docs"},"reference/design":{"id":"reference/design","title":"CmdForge Design Document","description":"A lightweight personal tool builder for AI-powered CLI commands","sidebar":"docs"},"reference/examples":{"id":"reference/examples","title":"Example Tools","description":"CmdForge comes with 28 pre-built tools. This document shows their configurations and usage.","sidebar":"docs"},"reference/meta-tools":{"id":"reference/meta-tools","title":"Meta-Tools: Tools That Call Other Tools","description":"Meta-tools are CmdForge tools that can invoke other tools as steps in their workflow. This enables powerful composition and reuse of existing tools.","sidebar":"docs"},"reference/providers":{"id":"reference/providers","title":"Provider Setup Guide","description":"CmdForge works with any AI CLI tool that accepts input via stdin or arguments. This guide covers setup for the most popular providers.","sidebar":"docs"},"reference/registry-spec":{"id":"reference/registry-spec","title":"CmdForge Registry Design","description":"Purpose","sidebar":"docs"},"reference/web-ui-spec":{"id":"reference/web-ui-spec","title":"CmdForge Web UI Design","description":"Purpose","sidebar":"docs"},"todos":{"id":"todos","title":"CmdForge TODOs","description":"Active Tasks","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/3fbf7384.1561f6b5.js b/assets/js/3fbf7384.1561f6b5.js new file mode 100644 index 0000000..7ceda01 --- /dev/null +++ b/assets/js/3fbf7384.1561f6b5.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[854],{5253(e){e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docs":[{"type":"link","href":"/rob/CmdForge/","label":"CmdForge Overview","docId":"overview","unlisted":false},{"type":"link","href":"/rob/CmdForge/architecture","label":"CmdForge Architecture","docId":"architecture","unlisted":false},{"type":"link","href":"/rob/CmdForge/goals","label":"Goals","docId":"goals","unlisted":false},{"type":"link","href":"/rob/CmdForge/ideas-and-exploration","label":"Ideas & Exploration","docId":"ideas-and-exploration","unlisted":false},{"type":"link","href":"/rob/CmdForge/milestones","label":"Milestones","docId":"milestones","unlisted":false}]},"docs":{"architecture":{"id":"architecture","title":"CmdForge Architecture","description":"Module Structure","sidebar":"docs"},"goals":{"id":"goals","title":"Goals","description":"Vision","sidebar":"docs"},"ideas-and-exploration":{"id":"ideas-and-exploration","title":"Ideas & Exploration","description":"Completed","sidebar":"docs"},"milestones":{"id":"milestones","title":"Milestones","description":"Active","sidebar":"docs"},"overview":{"id":"overview","title":"CmdForge Overview","description":"A lightweight personal tool builder for AI-powered CLI commands.","sidebar":"docs"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/5281b7a2.1c1a5adb.js b/assets/js/5281b7a2.1c1a5adb.js new file mode 100644 index 0000000..b613576 --- /dev/null +++ b/assets/js/5281b7a2.1c1a5adb.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[443],{936(e,n,o){o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>i,metadata:()=>r,toc:()=>a});const r=JSON.parse('{"id":"architecture","title":"CmdForge Architecture","description":"Module Structure","source":"@site/docs/architecture.md","sourceDirName":".","slug":"/architecture","permalink":"/rob/CmdForge/architecture","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2},"sidebar":"docs","previous":{"title":"CmdForge Overview","permalink":"/rob/CmdForge/"},"next":{"title":"Goals","permalink":"/rob/CmdForge/goals"}}');var s=o(4848),t=o(8453);const i={sidebar_position:2},l="CmdForge Architecture",d={},a=[{value:"Module Structure",id:"module-structure",level:2},{value:"Data Flow",id:"data-flow",level:2},{value:"CLI Tool Execution",id:"cli-tool-execution",level:3},{value:"Web UI Request Flow",id:"web-ui-request-flow",level:3},{value:"Key Classes",id:"key-classes",level:2},{value:"Tool (tool.py)",id:"tool-toolpy",level:3},{value:"ToolSource (tool.py)",id:"toolsource-toolpy",level:3},{value:"Provider (providers.py)",id:"provider-providerspy",level:3},{value:"Collection (collection.py)",id:"collection-collectionpy",level:3},{value:"ToolResolutionResult (collection.py)",id:"toolresolutionresult-collectionpy",level:3},{value:"Error Handling",id:"error-handling",level:2},{value:"Code Step Errors",id:"code-step-errors",level:3},{value:"YAML Syntax Errors",id:"yaml-syntax-errors",level:3},{value:"Nested Tool Errors",id:"nested-tool-errors",level:3},{value:"Registry Database",id:"registry-database",level:2},{value:"Semantic Search Embeddings",id:"semantic-search-embeddings",level:3},{value:"Configuration Files",id:"configuration-files",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"cmdforge-architecture",children:"CmdForge Architecture"})}),"\n",(0,s.jsx)(n.h2,{id:"module-structure",children:"Module Structure"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"src/cmdforge/\n\u251c\u2500\u2500 cli/ # CLI commands\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 tool_commands.py # list, create, edit, delete\n\u2502 \u251c\u2500\u2500 provider_commands.py # providers management\n\u2502 \u251c\u2500\u2500 registry_commands.py # publish, install\n\u2502 \u2514\u2500\u2500 collections_commands.py # collections create, show, add, remove, delete, publish, status\n\u251c\u2500\u2500 registry/ # Registry API\n\u2502 \u251c\u2500\u2500 app.py # Flask API endpoints\n\u2502 \u251c\u2500\u2500 db.py # SQLite schema and queries\n\u2502 \u251c\u2500\u2500 embeddings.py # Semantic search (Ollama embeddings)\n\u2502 \u251c\u2500\u2500 settings.py # Admin-configurable settings\n\u2502 \u251c\u2500\u2500 sync.py # Git repo sync\n\u2502 \u2514\u2500\u2500 rate_limit.py\n\u251c\u2500\u2500 web/ # Web UI (cmdforge.brrd.tech)\n\u2502 \u251c\u2500\u2500 app.py # Flask app factory\n\u2502 \u251c\u2500\u2500 routes.py # Page routes\n\u2502 \u251c\u2500\u2500 auth.py # User authentication\n\u2502 \u251c\u2500\u2500 forum/ # Forum feature\n\u2502 \u251c\u2500\u2500 templates/ # Jinja2 templates\n\u2502 \u2514\u2500\u2500 static/ # CSS, JS\n\u251c\u2500\u2500 gui/ # Desktop GUI (PySide6)\n\u2502 \u251c\u2500\u2500 __init__.py # Entry point, run_gui()\n\u2502 \u251c\u2500\u2500 main_window.py # Main window with sidebar\n\u2502 \u251c\u2500\u2500 styles.py # QSS stylesheet\n\u2502 \u251c\u2500\u2500 pages/ # Application pages\n\u2502 \u2502 \u251c\u2500\u2500 tools_page.py # Tool list and details\n\u2502 \u2502 \u251c\u2500\u2500 tool_builder_page.py # Create/edit tools\n\u2502 \u2502 \u251c\u2500\u2500 registry_page.py # Browse/install tools\n\u2502 \u2502 \u251c\u2500\u2500 collections_page.py # Local and registry collections\n\u2502 \u2502 \u2514\u2500\u2500 providers_page.py # Provider management\n\u2502 \u2514\u2500\u2500 dialogs/ # Modal dialogs\n\u2502 \u251c\u2500\u2500 step_dialog.py # Prompt/code step editors\n\u2502 \u251c\u2500\u2500 argument_dialog.py\n\u2502 \u251c\u2500\u2500 provider_dialog.py\n\u2502 \u251c\u2500\u2500 connect_dialog.py # Registry connect\n\u2502 \u2514\u2500\u2500 publish_dialog.py\n\u251c\u2500\u2500 tool.py # Tool dataclass and loading\n\u251c\u2500\u2500 collection.py # Collection dataclass and tool resolution\n\u251c\u2500\u2500 runner.py # Tool execution engine\n\u2514\u2500\u2500 providers.py # AI provider abstraction\n"})}),"\n",(0,s.jsx)(n.h2,{id:"data-flow",children:"Data Flow"}),"\n",(0,s.jsx)(n.h3,{id:"cli-tool-execution",children:"CLI Tool Execution"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"User Input (stdin)\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 runner.py \u2502 \u2500\u2500\u2500\u2500 Loads tool from ~/.cmdforge/<name>/config.yaml\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Steps \u2502\n\u2502 (prompt/ \u2502 \u2500\u2500\u2500\u2500 For prompt steps, calls providers.py\n\u2502 code) \u2502 \u2500\u2500\u2500\u2500 For code steps, exec() Python\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n Output (stdout)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"web-ui-request-flow",children:"Web UI Request Flow"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Browser Request\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Cloudflare \u2502 \u2500\u2500\u2500\u2500 HTTPS termination\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Flask :5050 \u2502 \u2500\u2500\u2500\u2500 web/app.py\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u251c\u2500\u2500\u2500\u2500 /api/* \u2192 registry/app.py (API)\n \u2514\u2500\u2500\u2500\u2500 /* \u2192 web/routes.py (Pages)\n \u2502\n \u25bc\n \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 SQLite DB \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,s.jsx)(n.h2,{id:"key-classes",children:"Key Classes"}),"\n",(0,s.jsx)(n.h3,{id:"tool-toolpy",children:"Tool (tool.py)"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"@dataclass\nclass Tool:\n name: str\n description: str\n category: str\n arguments: List[ToolArgument]\n steps: List[Step] # PromptStep | CodeStep | ToolStep\n output: str\n dependencies: List[str]\n source: Optional[ToolSource] # Attribution for imports\n version: str\n"})}),"\n",(0,s.jsx)(n.h3,{id:"toolsource-toolpy",children:"ToolSource (tool.py)"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'@dataclass\nclass ToolSource:\n type: str # "original", "imported", "forked"\n license: str\n url: str\n author: str\n original_tool: str # e.g., "fabric/patterns/extract_wisdom"\n'})}),"\n",(0,s.jsx)(n.h3,{id:"provider-providerspy",children:"Provider (providers.py)"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:'@dataclass\nclass Provider:\n name: str # e.g., "opencode-pickle"\n command: str # e.g., "$HOME/.opencode/bin/opencode run --model ..."\n description: str\n'})}),"\n",(0,s.jsx)(n.h3,{id:"collection-collectionpy",children:"Collection (collection.py)"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"@dataclass\nclass Collection:\n name: str # Unique identifier (kebab-case)\n display_name: str # Human-readable name\n description: str\n maintainer: str\n tools: List[str] # Tool references (local or owner/name)\n pinned: Dict[str, str] # Version constraints\n tags: List[str]\n published: bool # Whether published to registry\n registry_name: str # Name in registry (if different)\n pending_approval: bool # Awaiting moderation\n pending_tools: List[str] # Tools awaiting approval\n"})}),"\n",(0,s.jsx)(n.h3,{id:"toolresolutionresult-collectionpy",children:"ToolResolutionResult (collection.py)"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-python",children:"@dataclass\nclass ToolResolutionResult:\n registry_refs: List[str] # Transformed owner/name refs\n transformed_pinned: Dict[str, str] # Pinned with transformed keys\n local_unpublished: List[str] # Local tools not in registry\n local_published: List[tuple] # (name, status, has_approved) tuples\n visibility_issues: List[tuple] # (name, visibility) for non-public\n registry_tool_issues: List[tuple] # (ref, reason) for invalid refs\n"})}),"\n",(0,s.jsx)(n.h2,{id:"error-handling",children:"Error Handling"}),"\n",(0,s.jsx)(n.p,{children:"The runner provides detailed error messages for debugging:"}),"\n",(0,s.jsx)(n.h3,{id:"code-step-errors",children:"Code Step Errors"}),"\n",(0,s.jsx)(n.p,{children:"When Python code fails in a code step, shows:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Step number and error type"}),"\n",(0,s.jsx)(n.li,{children:"Offending line with context (line before/after)"}),"\n",(0,s.jsxs)(n.li,{children:["Visual pointer (",(0,s.jsx)(n.code,{children:">>>"}),") to error line"]}),"\n",(0,s.jsx)(n.li,{children:"List of available variables"}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Error in code step (step 2):\n NameError: name 'undefined_var' is not defined\n\n 1: data = input.split('\\n')\n>>> 2: result = undefined_var + data\n 3: output = result\n\n Available variables: ['input', 'max_size', 'step1_output']\n"})}),"\n",(0,s.jsx)(n.h3,{id:"yaml-syntax-errors",children:"YAML Syntax Errors"}),"\n",(0,s.jsx)(n.p,{children:"When a tool's config.yaml has syntax errors:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Line and column number"}),"\n",(0,s.jsx)(n.li,{children:"Visual pointer to exact position"}),"\n",(0,s.jsx)(n.li,{children:"Context line above"}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Error loading tool 'my-tool': YAML syntax error\n Line 15, column 8\n\n 14: steps:\n > 15: - type prompt # missing colon\n ^\n Problem: expected ',' or ']'\n"})}),"\n",(0,s.jsx)(n.h3,{id:"nested-tool-errors",children:"Nested Tool Errors"}),"\n",(0,s.jsx)(n.p,{children:"When a tool calls another tool that fails, shows the full call stack:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"Error in tool chain:\nmy-wrapper (step 2)\n -> summarize (step 1)\n -> Tool 'missing-tool' not found\n"})}),"\n",(0,s.jsx)(n.h2,{id:"registry-database",children:"Registry Database"}),"\n",(0,s.jsx)(n.p,{children:"SQLite schema for published tools:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sql",children:"CREATE TABLE tools (\n id INTEGER PRIMARY KEY,\n name TEXT UNIQUE NOT NULL,\n description TEXT,\n category TEXT DEFAULT 'Other',\n config_yaml TEXT NOT NULL, -- Full tool YAML\n source TEXT, -- Deprecated (type only)\n source_url TEXT, -- Deprecated\n source_json TEXT, -- Full ToolSource as JSON\n published_at TIMESTAMP,\n downloads INTEGER DEFAULT 0,\n owner_id INTEGER REFERENCES users(id)\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"source_json"})," column stores the complete ToolSource object, preserving all attribution fields when tools are published."]}),"\n",(0,s.jsx)(n.h3,{id:"semantic-search-embeddings",children:"Semantic Search Embeddings"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sql",children:'CREATE TABLE tool_embeddings (\n tool_id INTEGER PRIMARY KEY REFERENCES tools(id) ON DELETE CASCADE,\n embedding BLOB NOT NULL, -- Packed float32 vector (768 dims \xd7 4 bytes = 3KB)\n dimensions INTEGER NOT NULL, -- Actual vector dimensions\n model TEXT NOT NULL, -- Model used (e.g., "nomic-embed-text")\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Embeddings are generated via Ollama (AI-Server, 192.168.0.186:11434) using the ",(0,s.jsx)(n.code,{children:"nomic-embed-text"})," model. Only public+approved tools are embedded. Vectors are stored as packed binary blobs and compared using pure Python cosine similarity at query time (~100 tools = sub-ms)."]}),"\n",(0,s.jsx)(n.h2,{id:"configuration-files",children:"Configuration Files"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"File"}),(0,s.jsx)(n.th,{children:"Location"}),(0,s.jsx)(n.th,{children:"Purpose"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool config"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"~/.cmdforge/<name>/config.yaml"})}),(0,s.jsx)(n.td,{children:"Tool definition"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Providers"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"~/.cmdforge/providers.yaml"})}),(0,s.jsx)(n.td,{children:"AI provider commands"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Main config"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"~/.cmdforge/config.yaml"})}),(0,s.jsx)(n.td,{children:"Registry URL, client ID"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Collections"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"~/.cmdforge/collections/<name>.yaml"})}),(0,s.jsx)(n.td,{children:"Local collection definitions"})]})]})]})]})}function p(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},8453(e,n,o){o.d(n,{R:()=>i,x:()=>l});var r=o(6540);const s={},t=r.createContext(s);function i(e){const n=r.useContext(t);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5281b7a2.1fd85cce.js b/assets/js/5281b7a2.1fd85cce.js deleted file mode 100644 index 017161a..0000000 --- a/assets/js/5281b7a2.1fd85cce.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[443],{936(e,n,r){r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>i,metadata:()=>o,toc:()=>a});const o=JSON.parse('{"id":"architecture","title":"CmdForge Architecture","description":"Module Structure","source":"@site/docs/architecture.md","sourceDirName":".","slug":"/architecture","permalink":"/rob/CmdForge/architecture","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2},"sidebar":"docs","previous":{"title":"CmdForge Overview","permalink":"/rob/CmdForge/"},"next":{"title":"Reference","permalink":"/rob/CmdForge/category/reference"}}');var t=r(4848),s=r(8453);const i={sidebar_position:2},l="CmdForge Architecture",d={},a=[{value:"Module Structure",id:"module-structure",level:2},{value:"Data Flow",id:"data-flow",level:2},{value:"CLI Tool Execution",id:"cli-tool-execution",level:3},{value:"Web UI Request Flow",id:"web-ui-request-flow",level:3},{value:"Key Classes",id:"key-classes",level:2},{value:"Tool (tool.py)",id:"tool-toolpy",level:3},{value:"ToolSource (tool.py)",id:"toolsource-toolpy",level:3},{value:"Provider (providers.py)",id:"provider-providerspy",level:3},{value:"Error Handling",id:"error-handling",level:2},{value:"Code Step Errors",id:"code-step-errors",level:3},{value:"YAML Syntax Errors",id:"yaml-syntax-errors",level:3},{value:"Nested Tool Errors",id:"nested-tool-errors",level:3},{value:"Registry Database",id:"registry-database",level:2},{value:"Configuration Files",id:"configuration-files",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"cmdforge-architecture",children:"CmdForge Architecture"})}),"\n",(0,t.jsx)(n.h2,{id:"module-structure",children:"Module Structure"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"src/cmdforge/\n\u251c\u2500\u2500 cli/ # CLI commands\n\u2502 \u251c\u2500\u2500 __init__.py\n\u2502 \u251c\u2500\u2500 tool_commands.py # list, create, edit, delete\n\u2502 \u251c\u2500\u2500 provider_commands.py # providers management\n\u2502 \u251c\u2500\u2500 registry_commands.py # publish, install\n\u2502 \u2514\u2500\u2500 collections_commands.py # collections list, info, install\n\u251c\u2500\u2500 registry/ # Registry API\n\u2502 \u251c\u2500\u2500 app.py # Flask API endpoints\n\u2502 \u251c\u2500\u2500 db.py # SQLite schema and queries\n\u2502 \u251c\u2500\u2500 sync.py # Git repo sync\n\u2502 \u2514\u2500\u2500 rate_limit.py\n\u251c\u2500\u2500 web/ # Web UI (cmdforge.brrd.tech)\n\u2502 \u251c\u2500\u2500 app.py # Flask app factory\n\u2502 \u251c\u2500\u2500 routes.py # Page routes\n\u2502 \u251c\u2500\u2500 auth.py # User authentication\n\u2502 \u251c\u2500\u2500 forum/ # Forum feature\n\u2502 \u251c\u2500\u2500 templates/ # Jinja2 templates\n\u2502 \u2514\u2500\u2500 static/ # CSS, JS\n\u251c\u2500\u2500 gui/ # Desktop GUI (PySide6)\n\u2502 \u251c\u2500\u2500 __init__.py # Entry point, run_gui()\n\u2502 \u251c\u2500\u2500 main_window.py # Main window with sidebar\n\u2502 \u251c\u2500\u2500 styles.py # QSS stylesheet\n\u2502 \u251c\u2500\u2500 pages/ # Application pages\n\u2502 \u2502 \u251c\u2500\u2500 tools_page.py # Tool list and details\n\u2502 \u2502 \u251c\u2500\u2500 tool_builder_page.py # Create/edit tools\n\u2502 \u2502 \u251c\u2500\u2500 registry_page.py # Browse/install tools\n\u2502 \u2502 \u2514\u2500\u2500 providers_page.py # Provider management\n\u2502 \u2514\u2500\u2500 dialogs/ # Modal dialogs\n\u2502 \u251c\u2500\u2500 step_dialog.py # Prompt/code step editors\n\u2502 \u251c\u2500\u2500 argument_dialog.py\n\u2502 \u251c\u2500\u2500 provider_dialog.py\n\u2502 \u251c\u2500\u2500 connect_dialog.py # Registry connect\n\u2502 \u2514\u2500\u2500 publish_dialog.py\n\u251c\u2500\u2500 tool.py # Tool dataclass and loading\n\u251c\u2500\u2500 runner.py # Tool execution engine\n\u2514\u2500\u2500 providers.py # AI provider abstraction\n"})}),"\n",(0,t.jsx)(n.h2,{id:"data-flow",children:"Data Flow"}),"\n",(0,t.jsx)(n.h3,{id:"cli-tool-execution",children:"CLI Tool Execution"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"User Input (stdin)\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 runner.py \u2502 \u2500\u2500\u2500\u2500 Loads tool from ~/.cmdforge/<name>/config.yaml\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Steps \u2502\n\u2502 (prompt/ \u2502 \u2500\u2500\u2500\u2500 For prompt steps, calls providers.py\n\u2502 code) \u2502 \u2500\u2500\u2500\u2500 For code steps, exec() Python\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n Output (stdout)\n"})}),"\n",(0,t.jsx)(n.h3,{id:"web-ui-request-flow",children:"Web UI Request Flow"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Browser Request\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Cloudflare \u2502 \u2500\u2500\u2500\u2500 HTTPS termination\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Flask :5050 \u2502 \u2500\u2500\u2500\u2500 web/app.py\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u251c\u2500\u2500\u2500\u2500 /api/* \u2192 registry/app.py (API)\n \u2514\u2500\u2500\u2500\u2500 /* \u2192 web/routes.py (Pages)\n \u2502\n \u25bc\n \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 SQLite DB \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,t.jsx)(n.h2,{id:"key-classes",children:"Key Classes"}),"\n",(0,t.jsx)(n.h3,{id:"tool-toolpy",children:"Tool (tool.py)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:"@dataclass\nclass Tool:\n name: str\n description: str\n category: str\n arguments: List[ToolArgument]\n steps: List[Step] # PromptStep | CodeStep | ToolStep\n output: str\n dependencies: List[str]\n source: Optional[ToolSource] # Attribution for imports\n version: str\n"})}),"\n",(0,t.jsx)(n.h3,{id:"toolsource-toolpy",children:"ToolSource (tool.py)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'@dataclass\nclass ToolSource:\n type: str # "original", "imported", "forked"\n license: str\n url: str\n author: str\n original_tool: str # e.g., "fabric/patterns/extract_wisdom"\n'})}),"\n",(0,t.jsx)(n.h3,{id:"provider-providerspy",children:"Provider (providers.py)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-python",children:'@dataclass\nclass Provider:\n name: str # e.g., "opencode-pickle"\n command: str # e.g., "$HOME/.opencode/bin/opencode run --model ..."\n description: str\n'})}),"\n",(0,t.jsx)(n.h2,{id:"error-handling",children:"Error Handling"}),"\n",(0,t.jsx)(n.p,{children:"The runner provides detailed error messages for debugging:"}),"\n",(0,t.jsx)(n.h3,{id:"code-step-errors",children:"Code Step Errors"}),"\n",(0,t.jsx)(n.p,{children:"When Python code fails in a code step, shows:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Step number and error type"}),"\n",(0,t.jsx)(n.li,{children:"Offending line with context (line before/after)"}),"\n",(0,t.jsxs)(n.li,{children:["Visual pointer (",(0,t.jsx)(n.code,{children:">>>"}),") to error line"]}),"\n",(0,t.jsx)(n.li,{children:"List of available variables"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Error in code step (step 2):\n NameError: name 'undefined_var' is not defined\n\n 1: data = input.split('\\n')\n>>> 2: result = undefined_var + data\n 3: output = result\n\n Available variables: ['input', 'max_size', 'step1_output']\n"})}),"\n",(0,t.jsx)(n.h3,{id:"yaml-syntax-errors",children:"YAML Syntax Errors"}),"\n",(0,t.jsx)(n.p,{children:"When a tool's config.yaml has syntax errors:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Line and column number"}),"\n",(0,t.jsx)(n.li,{children:"Visual pointer to exact position"}),"\n",(0,t.jsx)(n.li,{children:"Context line above"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Error loading tool 'my-tool': YAML syntax error\n Line 15, column 8\n\n 14: steps:\n > 15: - type prompt # missing colon\n ^\n Problem: expected ',' or ']'\n"})}),"\n",(0,t.jsx)(n.h3,{id:"nested-tool-errors",children:"Nested Tool Errors"}),"\n",(0,t.jsx)(n.p,{children:"When a tool calls another tool that fails, shows the full call stack:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Error in tool chain:\nmy-wrapper (step 2)\n -> summarize (step 1)\n -> Tool 'missing-tool' not found\n"})}),"\n",(0,t.jsx)(n.h2,{id:"registry-database",children:"Registry Database"}),"\n",(0,t.jsx)(n.p,{children:"SQLite schema for published tools:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sql",children:"CREATE TABLE tools (\n id INTEGER PRIMARY KEY,\n name TEXT UNIQUE NOT NULL,\n description TEXT,\n category TEXT DEFAULT 'Other',\n config_yaml TEXT NOT NULL, -- Full tool YAML\n source TEXT, -- Deprecated (type only)\n source_url TEXT, -- Deprecated\n source_json TEXT, -- Full ToolSource as JSON\n published_at TIMESTAMP,\n downloads INTEGER DEFAULT 0,\n owner_id INTEGER REFERENCES users(id)\n);\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"source_json"})," column stores the complete ToolSource object, preserving all attribution fields when tools are published."]}),"\n",(0,t.jsx)(n.h2,{id:"configuration-files",children:"Configuration Files"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"File"}),(0,t.jsx)(n.th,{children:"Location"}),(0,t.jsx)(n.th,{children:"Purpose"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Tool config"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"~/.cmdforge/<name>/config.yaml"})}),(0,t.jsx)(n.td,{children:"Tool definition"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Providers"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"~/.cmdforge/providers.yaml"})}),(0,t.jsx)(n.td,{children:"AI provider commands"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"Main config"}),(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"~/.cmdforge/config.yaml"})}),(0,t.jsx)(n.td,{children:"Registry URL, client ID"})]})]})]})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453(e,n,r){r.d(n,{R:()=>i,x:()=>l});var o=r(6540);const t={},s=o.createContext(t);function i(e){const n=o.useContext(s);return o.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5eebbccf.7d0f69ae.js b/assets/js/5eebbccf.7d0f69ae.js new file mode 100644 index 0000000..81145c7 --- /dev/null +++ b/assets/js/5eebbccf.7d0f69ae.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[894],{7836(e,s,i){i.r(s),i.d(s,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>d});const t=JSON.parse('{"id":"goals","title":"Goals","description":"Vision","source":"@site/docs/goals.md","sourceDirName":".","slug":"/goals","permalink":"/rob/CmdForge/goals","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"goals","project":"CmdForge","updated":"2026-07-21T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"CmdForge Architecture","permalink":"/rob/CmdForge/architecture"},"next":{"title":"Ideas & Exploration","permalink":"/rob/CmdForge/ideas-and-exploration"}}');var n=i(4848),l=i(8453);const o={type:"goals",project:"CmdForge",updated:new Date("2026-07-21T00:00:00.000Z")},a="Goals",c={},d=[{value:"Vision",id:"vision",level:2},{value:"Active",id:"active",level:2},{value:"Completed",id:"completed",level:2},{value:"Future",id:"future",level:2},{value:"Non-Goals",id:"non-goals",level:2}];function r(e){const s={code:"code",h1:"h1",h2:"h2",header:"header",input:"input",li:"li",p:"p",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.header,{children:(0,n.jsx)(s.h1,{id:"goals",children:"Goals"})}),"\n",(0,n.jsx)(s.h2,{id:"vision",children:"Vision"}),"\n",(0,n.jsx)(s.p,{children:"CmdForge is a universal librarian for AI-powered tools \u2014 enabling developers to build applications from verified, composable, Lego-like components. It breaks complex problems into small, decoupled, reusable tools, tracks them across a global registry, continuously verifies their correctness, and makes them composable through Unix pipelines. The result: development that's faster, safer, and collaborative on a humanity-wide scale."}),"\n",(0,n.jsx)(s.p,{children:"The private project-docs repository contains the detailed July 2026 strategic\nanalysis and roadmap. They are intentionally excluded from this public build."}),"\n",(0,n.jsx)(s.h2,{id:"active",children:"Active"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Complete the reviewed production deployment and publish ",(0,n.jsx)(s.code,{children:"forge-tool"})," 1.1.0 #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Make CmdForge the easiest path for coding agents through discovery, project-local tools, and host bootstrap #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Complete transactional email and administrator recovery #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Grow a small, dependable official-tool baseline and adoption guide #medium"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"completed",children:"Completed"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provide a simple, intuitive way for users to create AI-powered CLI tools without coding #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Enable tool sharing so users can discover, use, and improve community-created tools #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Integrate seamlessly with Unix workflows through standard stdin/stdout piping #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Abstract away AI provider complexity so tools work with any backend #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Maintain tool reliability through offline caching and graceful degradation #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Ensure tool quality through a curation system that prevents duplication and maintains standards #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Support tool composition where tools can chain together and build on each other #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provide extensibility for custom AI backends and integrations #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Update and modernize provider ecosystem for the 2026 landscape #critical"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Integrate MCP as both client and server #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Evolve providers into bounded agents with skills, tool access, and delegation #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Add contracts, preflight, verification, scoring, reuse guidance, and auditing #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Add prompt optimization, improvement, integrity, community, and attestation workflows #high"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"future",children:"Future"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Create a monetization plan for sustainable tool ecosystem #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Supply chain attestation (signed releases, GPG/Sigstore verification) #low"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"non-goals",children:"Non-Goals"}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Replace shell scripting"})," - CmdForge augments shell workflows, not replaces them"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Build a full IDE"})," - Focus on CLI tool building, not general development"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Require coding knowledge"})," - Tools should be creatable without programming"]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.strong,{children:"Lock users to specific providers"})," - Provider-agnostic by design"]}),"\n"]})]})}function h(e={}){const{wrapper:s}={...(0,l.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(r,{...e})}):r(e)}},8453(e,s,i){i.d(s,{R:()=>o,x:()=>a});var t=i(6540);const n={},l=t.createContext(n);function o(e){const s=t.useContext(l);return t.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),t.createElement(l.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5eebbccf.e6c8b639.js b/assets/js/5eebbccf.e6c8b639.js deleted file mode 100644 index 76bf531..0000000 --- a/assets/js/5eebbccf.e6c8b639.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[894],{7836(e,s,t){t.r(s),t.d(s,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"goals","title":"Goals","description":"Vision","source":"@site/docs/goals.md","sourceDirName":".","slug":"/goals","permalink":"/rob/CmdForge/goals","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"goals","project":"cmdforge","updated":"2026-01-13T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"CmdForge TODOs","permalink":"/rob/CmdForge/todos"},"next":{"title":"Ideas & Exploration","permalink":"/rob/CmdForge/ideas-and-exploration"}}');var n=t(4848),a=t(8453);const o={type:"goals",project:"cmdforge",updated:new Date("2026-01-13T00:00:00.000Z")},l="Goals",c={},d=[{value:"Vision",id:"vision",level:2},{value:"Active",id:"active",level:2},{value:"Future",id:"future",level:2},{value:"Non-Goals",id:"non-goals",level:2}];function r(e){const s={h1:"h1",h2:"h2",header:"header",input:"input",li:"li",p:"p",ul:"ul",...(0,a.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.header,{children:(0,n.jsx)(s.h1,{id:"goals",children:"Goals"})}),"\n",(0,n.jsx)(s.h2,{id:"vision",children:"Vision"}),"\n",(0,n.jsx)(s.p,{children:"CmdForge empowers users to create custom AI-powered CLI commands as easily as writing a config file. It bridges the gap between powerful AI capabilities and the simplicity of Unix pipes, letting anyone build tools that fit their workflow without writing code."}),"\n",(0,n.jsx)(s.h2,{id:"active",children:"Active"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provide a simple, intuitive way for users to create AI-powered CLI tools without coding #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Enable tool sharing so users can discover, use, and improve community-created tools #high"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Integrate seamlessly with Unix workflows through standard stdin/stdout piping #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Abstract away AI provider complexity so tools work with any backend #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Maintain tool reliability through offline caching and graceful degradation #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Ensure tool quality through a curation system that prevents duplication and maintains standards #low"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"future",children:"Future"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Support tool composition where tools can chain together and build on each other #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Create a monetization plan for sustainable tool ecosystem #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provide extensibility for custom AI backends and integrations #low"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"non-goals",children:"Non-Goals"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Replace shell scripting #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Build a full IDE #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Require coding knowledge #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Lock users to specific providers #medium"]}),"\n"]})]})}function u(e={}){const{wrapper:s}={...(0,a.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(r,{...e})}):r(e)}},8453(e,s,t){t.d(s,{R:()=>o,x:()=>l});var i=t(6540);const n={},a=i.createContext(n);function o(e){const s=i.useContext(a);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function l(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),i.createElement(a.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6704ba13.e26e2266.js b/assets/js/6704ba13.e26e2266.js deleted file mode 100644 index 89a3621..0000000 --- a/assets/js/6704ba13.e26e2266.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[105],{2403(e,n,d){d.r(n),d.d(n,{assets:()=>o,contentTitle:()=>c,default:()=>a,frontMatter:()=>l,metadata:()=>s,toc:()=>t});const s=JSON.parse('{"id":"reference/providers","title":"Provider Setup Guide","description":"CmdForge works with any AI CLI tool that accepts input via stdin or arguments. This guide covers setup for the most popular providers.","source":"@site/docs/reference/providers.md","sourceDirName":"reference","slug":"/reference/providers","permalink":"/rob/CmdForge/reference/providers","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"sidebar_label":"Provider Setup","sidebar_position":1,"format":"md"},"sidebar":"docs","previous":{"title":"Reference","permalink":"/rob/CmdForge/category/reference"},"next":{"title":"Registry API","permalink":"/rob/CmdForge/reference/registry-spec"}}');var i=d(4848),r=d(8453);const l={sidebar_label:"Provider Setup",sidebar_position:1,format:"md"},c="Provider Setup Guide",o={},t=[{value:"Provider Comparison",id:"provider-comparison",level:2},{value:"Recommendations",id:"recommendations",level:3},{value:"Provider Setup",id:"provider-setup",level:2},{value:"OpenCode (Recommended)",id:"opencode-recommended",level:3},{value:"Claude CLI",id:"claude-cli",level:3},{value:"Codex (OpenAI)",id:"codex-openai",level:3},{value:"Gemini",id:"gemini",level:3},{value:"Managing Providers",id:"managing-providers",level:2},{value:"Interactive Installation (Recommended)",id:"interactive-installation-recommended",level:3},{value:"List Providers",id:"list-providers",level:3},{value:"Check Availability",id:"check-availability",level:3},{value:"Add Custom Provider",id:"add-custom-provider",level:3},{value:"Provider Command Format",id:"provider-command-format",level:3},{value:"Using Providers in Tools",id:"using-providers-in-tools",level:2},{value:"In Tool Config",id:"in-tool-config",level:3},{value:"Override at Runtime",id:"override-at-runtime",level:3},{value:"Provider Selection Strategy",id:"provider-selection-strategy",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:""Provider 'X' not found"",id:"provider-x-not-found",level:3},{value:""Command 'X' not found"",id:"command-x-not-found",level:3},{value:"Slow Provider",id:"slow-provider",level:3},{value:"Cost Optimization",id:"cost-optimization",level:2},{value:"Free Providers",id:"free-providers",level:3},{value:"Cheap Providers",id:"cheap-providers",level:3},{value:"Tips",id:"tips",level:3},{value:"Adding New Providers",id:"adding-new-providers",level:2}];function h(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"provider-setup-guide",children:"Provider Setup Guide"})}),"\n",(0,i.jsx)(n.p,{children:"CmdForge works with any AI CLI tool that accepts input via stdin or arguments. This guide covers setup for the most popular providers."}),"\n",(0,i.jsx)(n.h2,{id:"provider-comparison",children:"Provider Comparison"}),"\n",(0,i.jsx)(n.p,{children:"We profiled 12 providers with a 4-task benchmark (Math, Code, Reasoning, Data Extraction):"}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Provider"}),(0,i.jsx)(n.th,{children:"Speed"}),(0,i.jsx)(n.th,{children:"Score"}),(0,i.jsx)(n.th,{children:"Cost"}),(0,i.jsx)(n.th,{children:"Best For"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"opencode-deepseek"})}),(0,i.jsx)(n.td,{children:"13s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$0.28/M tokens"}),(0,i.jsxs)(n.td,{children:[(0,i.jsx)(n.strong,{children:"Best value"})," - daily driver"]})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"opencode-pickle"})}),(0,i.jsx)(n.td,{children:"13s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"FREE"}),(0,i.jsxs)(n.td,{children:[(0,i.jsx)(n.strong,{children:"Best free"})," - accurate"]})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"claude-haiku"})}),(0,i.jsx)(n.td,{children:"14s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$0.25/M tokens"}),(0,i.jsx)(n.td,{children:"Fast + high quality"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"codex"})}),(0,i.jsx)(n.td,{children:"14s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$1.25/M tokens"}),(0,i.jsx)(n.td,{children:"Reliable, auto-routes"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"claude"})}),(0,i.jsx)(n.td,{children:"18s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"Varies"}),(0,i.jsx)(n.td,{children:"Auto-routes to best"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"claude-opus"})}),(0,i.jsx)(n.td,{children:"18s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$15/M tokens"}),(0,i.jsx)(n.td,{children:"Highest quality"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"claude-sonnet"})}),(0,i.jsx)(n.td,{children:"21s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$3/M tokens"}),(0,i.jsx)(n.td,{children:"Balanced"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"opencode-nano"})}),(0,i.jsx)(n.td,{children:"24s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"Paid"}),(0,i.jsx)(n.td,{children:"GPT-5 Nano"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"gemini-flash"})}),(0,i.jsx)(n.td,{children:"28s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$0.075/M tokens"}),(0,i.jsx)(n.td,{children:"Google, faster"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"opencode-reasoner"})}),(0,i.jsx)(n.td,{children:"33s"}),(0,i.jsx)(n.td,{children:"4/4"}),(0,i.jsx)(n.td,{children:"~$0.28/M tokens"}),(0,i.jsx)(n.td,{children:"Complex reasoning"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"gemini"})}),(0,i.jsx)(n.td,{children:"91s"}),(0,i.jsx)(n.td,{children:"3/4"}),(0,i.jsx)(n.td,{children:"~$1.25/M tokens"}),(0,i.jsx)(n.td,{children:"1M token context"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.strong,{children:"opencode-grok"})}),(0,i.jsx)(n.td,{children:"11s"}),(0,i.jsx)(n.td,{children:"2/4"}),(0,i.jsx)(n.td,{children:"FREE"}),(0,i.jsx)(n.td,{children:"Fastest but unreliable"})]})]})]}),"\n",(0,i.jsx)(n.h3,{id:"recommendations",children:"Recommendations"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Daily use:"})," ",(0,i.jsx)(n.code,{children:"opencode-deepseek"})," or ",(0,i.jsx)(n.code,{children:"opencode-pickle"})," (free)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Quality work:"})," ",(0,i.jsx)(n.code,{children:"claude-haiku"})," or ",(0,i.jsx)(n.code,{children:"claude-opus"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Complex reasoning:"})," ",(0,i.jsx)(n.code,{children:"opencode-reasoner"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Large documents:"})," ",(0,i.jsx)(n.code,{children:"gemini"})," (1M token context window)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Budget:"})," ",(0,i.jsx)(n.code,{children:"opencode-pickle"})," (free) or ",(0,i.jsx)(n.code,{children:"opencode-deepseek"})," (cheap)"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"provider-setup",children:"Provider Setup"}),"\n",(0,i.jsx)(n.h3,{id:"opencode-recommended",children:"OpenCode (Recommended)"}),"\n",(0,i.jsx)(n.p,{children:"OpenCode provides access to multiple models including free options."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Install:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"curl -fsSL https://opencode.ai/install | bash\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Authenticate:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"~/.opencode/bin/opencode auth\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Available Models:"})}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Provider Name"}),(0,i.jsx)(n.th,{children:"Model"}),(0,i.jsx)(n.th,{children:"Cost"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"opencode-deepseek"})}),(0,i.jsx)(n.td,{children:"deepseek-chat"}),(0,i.jsx)(n.td,{children:"Cheap"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"opencode-pickle"})}),(0,i.jsx)(n.td,{children:"big-pickle"}),(0,i.jsx)(n.td,{children:"FREE"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"opencode-grok"})}),(0,i.jsx)(n.td,{children:"grok-code"}),(0,i.jsx)(n.td,{children:"FREE"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"opencode-nano"})}),(0,i.jsx)(n.td,{children:"gpt-5-nano"}),(0,i.jsx)(n.td,{children:"Paid"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"opencode-reasoner"})}),(0,i.jsx)(n.td,{children:"deepseek-reasoner"}),(0,i.jsx)(n.td,{children:"Cheap"})]})]})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Test:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'echo "Hello" | ~/.opencode/bin/opencode run --model opencode/big-pickle\n'})}),"\n",(0,i.jsx)(n.h3,{id:"claude-cli",children:"Claude CLI"}),"\n",(0,i.jsx)(n.p,{children:"Anthropic's official CLI for Claude models."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Install:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"npm install -g @anthropic-ai/claude-code\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Authenticate:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"claude # Opens browser for sign-in (auto-saves auth tokens)\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Available Models:"})}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Provider Name"}),(0,i.jsx)(n.th,{children:"Model"}),(0,i.jsx)(n.th,{children:"Cost"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"claude"})}),(0,i.jsx)(n.td,{children:"Auto-routes"}),(0,i.jsx)(n.td,{children:"Varies"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"claude-haiku"})}),(0,i.jsx)(n.td,{children:"Haiku 4.5"}),(0,i.jsx)(n.td,{children:"Cheap"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"claude-sonnet"})}),(0,i.jsx)(n.td,{children:"Sonnet 4.5"}),(0,i.jsx)(n.td,{children:"Medium"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"claude-opus"})}),(0,i.jsx)(n.td,{children:"Opus 4.5"}),(0,i.jsx)(n.td,{children:"Expensive"})]})]})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Test:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'echo "Hello" | claude -p\n'})}),"\n",(0,i.jsx)(n.h3,{id:"codex-openai",children:"Codex (OpenAI)"}),"\n",(0,i.jsx)(n.p,{children:"OpenAI's Codex CLI with auto-routing."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Install:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"npm install -g @openai/codex\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Authenticate:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"codex # Opens browser for sign-in (auto-saves auth tokens)\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Test:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'echo "Hello" | codex exec -\n'})}),"\n",(0,i.jsx)(n.h3,{id:"gemini",children:"Gemini"}),"\n",(0,i.jsx)(n.p,{children:"Google's Gemini models. Best for large context (1M tokens)."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Install:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"npm install -g @google/gemini-cli\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Authenticate:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"gemini # Opens browser for Google sign-in\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Available Models:"})}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Provider Name"}),(0,i.jsx)(n.th,{children:"Model"}),(0,i.jsx)(n.th,{children:"Notes"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"gemini"})}),(0,i.jsx)(n.td,{children:"gemini-2.5-pro"}),(0,i.jsx)(n.td,{children:"Quality, slow CLI"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"gemini-flash"})}),(0,i.jsx)(n.td,{children:"gemini-2.5-flash"}),(0,i.jsx)(n.td,{children:"Faster"})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Note:"})," Gemini CLI has known performance issues. Use ",(0,i.jsx)(n.code,{children:"gemini-flash"})," for interactive tasks, ",(0,i.jsx)(n.code,{children:"gemini"})," for large documents."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Test:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'echo "Hello" | gemini --model gemini-2.5-flash\n'})}),"\n",(0,i.jsx)(n.h2,{id:"managing-providers",children:"Managing Providers"}),"\n",(0,i.jsx)(n.h3,{id:"interactive-installation-recommended",children:"Interactive Installation (Recommended)"}),"\n",(0,i.jsx)(n.p,{children:"The easiest way to install providers:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cmdforge providers install\n"})}),"\n",(0,i.jsx)(n.p,{children:"This interactive guide:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Shows available AI providers with costs"}),"\n",(0,i.jsx)(n.li,{children:"Runs the installation command"}),"\n",(0,i.jsx)(n.li,{children:"Updates PATH automatically"}),"\n",(0,i.jsx)(n.li,{children:"Shows next steps for authentication"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"list-providers",children:"List Providers"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cmdforge providers list\n"})}),"\n",(0,i.jsx)(n.h3,{id:"check-availability",children:"Check Availability"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cmdforge providers check\n"})}),"\n",(0,i.jsx)(n.h3,{id:"add-custom-provider",children:"Add Custom Provider"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'cmdforge providers add myname "my-command --args" -d "Description"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Or edit ",(0,i.jsx)(n.code,{children:"~/.cmdforge/providers.yaml"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"providers:\n - name: my-custom\n command: my-ai-tool --prompt\n description: My custom AI tool\n"})}),"\n",(0,i.jsx)(n.h3,{id:"provider-command-format",children:"Provider Command Format"}),"\n",(0,i.jsx)(n.p,{children:"The command should:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"Accept input via stdin"}),"\n",(0,i.jsx)(n.li,{children:"Output response to stdout"}),"\n",(0,i.jsx)(n.li,{children:"Exit 0 on success"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Example commands:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# Claude\nclaude -p\n\n# OpenCode\n$HOME/.opencode/bin/opencode run --model deepseek/deepseek-chat\n\n# Gemini\ngemini --model gemini-2.5-flash\n\n# Codex\ncodex exec -\n\n# Custom (any tool that reads stdin)\nmy-tool --input -\n"})}),"\n",(0,i.jsx)(n.h2,{id:"using-providers-in-tools",children:"Using Providers in Tools"}),"\n",(0,i.jsx)(n.h3,{id:"in-tool-config",children:"In Tool Config"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:'steps:\n - type: prompt\n prompt: "Summarize: {input}"\n provider: opencode-pickle # Use this provider\n output_var: response\n'})}),"\n",(0,i.jsx)(n.h3,{id:"override-at-runtime",children:"Override at Runtime"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"# Use a different provider for this run\ncat file.txt | summarize --provider claude-opus\n"})}),"\n",(0,i.jsx)(n.h3,{id:"provider-selection-strategy",children:"Provider Selection Strategy"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Tool default"})," - Set in tool's config.yaml"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Runtime override"})," - ",(0,i.jsx)(n.code,{children:"--provider"})," flag"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Cost optimization"})," - Use cheap providers for simple tasks"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Quality needs"})," - Use opus/sonnet for important work"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsx)(n.h3,{id:"provider-x-not-found",children:"\"Provider 'X' not found\""}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Check it's in your providers list: ",(0,i.jsx)(n.code,{children:"cmdforge providers"})]}),"\n",(0,i.jsxs)(n.li,{children:["Verify the command works: ",(0,i.jsx)(n.code,{children:'echo "test" | <command>'})]}),"\n",(0,i.jsxs)(n.li,{children:["Add it: ",(0,i.jsx)(n.code,{children:"cmdforge providers add"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"command-x-not-found",children:"\"Command 'X' not found\""}),"\n",(0,i.jsx)(n.p,{children:"The AI CLI tool isn't installed or not in PATH:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"which claude # Should show path\nwhich opencode # Might need full path\n"})}),"\n",(0,i.jsx)(n.p,{children:"For OpenCode, use full path in provider:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"command: $HOME/.opencode/bin/opencode run\n"})}),"\n",(0,i.jsx)(n.h3,{id:"slow-provider",children:"Slow Provider"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"gemini-flash"})," instead of ",(0,i.jsx)(n.code,{children:"gemini"})]}),"\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"claude-haiku"})," instead of ",(0,i.jsx)(n.code,{children:"claude-opus"})]}),"\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"opencode-deepseek"})," for best speed/quality ratio"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"cost-optimization",children:"Cost Optimization"}),"\n",(0,i.jsx)(n.h3,{id:"free-providers",children:"Free Providers"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"opencode-pickle"})," - Big Pickle model (FREE, accurate)"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"opencode-grok"})," - Grok Code (FREE, fast but less reliable)"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"cheap-providers",children:"Cheap Providers"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"opencode-deepseek"})," - ~$0.28/M tokens"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"opencode-reasoner"})," - ~$0.28/M tokens"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"claude-haiku"})," - ~$0.25/M tokens"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"tips",children:"Tips"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"opencode-pickle"})," for simple tasks (free + accurate)"]}),"\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"claude-haiku"})," when you need reliability"]}),"\n",(0,i.jsxs)(n.li,{children:["Reserve ",(0,i.jsx)(n.code,{children:"claude-opus"})," for important work"]}),"\n",(0,i.jsxs)(n.li,{children:["Use ",(0,i.jsx)(n.code,{children:"gemini"})," only for large document analysis"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"adding-new-providers",children:"Adding New Providers"}),"\n",(0,i.jsx)(n.p,{children:"Any CLI tool that:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Reads from stdin"}),"\n",(0,i.jsx)(n.li,{children:"Writes to stdout"}),"\n",(0,i.jsx)(n.li,{children:"Exits 0 on success"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Can be a provider. Examples:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Local LLM (Ollama):"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"- name: ollama-llama\n command: ollama run llama3\n description: Local Llama 3\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Custom API wrapper:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"- name: my-api\n command: curl -s -X POST https://my-api.com/chat -d @-\n description: My custom API\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"Python script:"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"- name: my-python\n command: python3 ~/scripts/my_ai.py\n description: Custom Python AI\n"})})]})}function a(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453(e,n,d){d.d(n,{R:()=>l,x:()=>c});var s=d(6540);const i={},r=s.createContext(i);function l(e){const n=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/817f7194.070f961b.js b/assets/js/817f7194.070f961b.js new file mode 100644 index 0000000..808d832 --- /dev/null +++ b/assets/js/817f7194.070f961b.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[574],{921(e,n,i){i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"milestones","title":"Milestones","description":"Active","source":"@site/docs/milestones.md","sourceDirName":".","slug":"/milestones","permalink":"/rob/CmdForge/milestones","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"milestones","project":"CmdForge","updated":"2026-07-21T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"Ideas & Exploration","permalink":"/rob/CmdForge/ideas-and-exploration"}}');var r=i(4848),s=i(8453);const o={type:"milestones",project:"CmdForge",updated:new Date("2026-07-21T00:00:00.000Z")},d="Milestones",l={},c=[{value:"Active",id:"active",level:2},{value:"Production Readiness and Adoption",id:"production-readiness-and-adoption",level:4},{value:"Completed",id:"completed",level:2},{value:"M9: The Feedback Loop",id:"m9-the-feedback-loop",level:4},{value:"M8: The Librarian",id:"m8-the-librarian",level:4},{value:"M7: Architecture Modernization",id:"m7-architecture-modernization",level:4},{value:"M6: Stability & Fixes",id:"m6-stability--fixes",level:4},{value:"M5: Testing & Polish",id:"m5-testing--polish",level:4},{value:"M0: Core Platform",id:"m0-core-platform",level:4},{value:"M1: Production Ready",id:"m1-production-ready",level:4},{value:"M2: Tool Discovery",id:"m2-tool-discovery",level:4},{value:"M3: Content & Automation",id:"m3-content--automation",level:4},{value:"M4: User Experience",id:"m4-user-experience",level:4}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h4:"h4",header:"header",hr:"hr",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"milestones",children:"Milestones"})}),"\n",(0,r.jsx)(n.h2,{id:"active",children:"Active"}),"\n",(0,r.jsx)(n.h4,{id:"production-readiness-and-adoption",children:"Production Readiness and Adoption"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Status"}),": In progress"]}),"\n",(0,r.jsxs)(n.p,{children:["Deploy the completed M6-M9 work, restore account recovery, publish\n",(0,r.jsx)(n.code,{children:"forge-tool"})," 1.1.0, validate official-tool installation from production, and\nmake coding-agent discovery and project-local creation easy to adopt."]}),"\n",(0,r.jsx)(n.h2,{id:"completed",children:"Completed"}),"\n",(0,r.jsx)(n.h4,{id:"m9-the-feedback-loop",children:"M9: The Feedback Loop"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q2-Q3 2027\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (2026-07-20)"]}),"\n",(0,r.jsx)(n.p,{children:"Added prompt variation and optimization, improvement proposals, community\nworkflows, full integrity verification, and signed supply-chain attestation.\nThe cumulative non-integration suite reached 777 passing tests at completion."}),"\n",(0,r.jsx)(n.h4,{id:"m8-the-librarian",children:"M8: The Librarian"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q1 2027\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (2026-07-20)"]}),"\n",(0,r.jsx)(n.p,{children:"Added input/output contracts and inference, deterministic preflight and\nconformance testing, evidence-based regression analysis, schema compatibility,\nexplainable quality scores, reuse detection, audit evidence, deprecation, and\nregistry-aware discovery. Privacy-sensitive usage tracking was implemented as\nan explicit local opt-in workflow. The milestone passed 710 tests before later\nhardening work."}),"\n",(0,r.jsx)(n.h4,{id:"m7-architecture-modernization",children:"M7: Architecture Modernization"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q4 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (2026-07-20)"]}),"\n",(0,r.jsx)(n.p,{children:"Added bidirectional, stdio-based MCP integration and evolved providers into\nbounded agents with validated skills, CmdForge-tool/MCP-server access policies,\nand recursive delegation context. Final non-integration validation: 577 passed,\n12 skipped, 12 integration tests deselected."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"MCP architecture decision"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["MCP client and dedicated ",(0,r.jsx)(n.code,{children:"McpStep"})]}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"CmdForge MCP server with typed schemas and exposure policy"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider-attached Agent Skills"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider tool and MCP-server access control"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Recursive profile, skill, tool, and provider delegation"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.p,{children:"Streamable HTTP was completed in the later follow-up. Non-tool MCP\ncapabilities, registry-backed discovery, and parallel/restarting clients remain\nideas for future evaluation in the private roadmap and MCP decision record."}),"\n",(0,r.jsx)(n.h4,{id:"m6-stability--fixes",children:"M6: Stability & Fixes"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q3 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (2026-07-19)"]}),"\n",(0,r.jsxs)(n.p,{children:["Modernized provider execution and onboarding, removed stale provider data and\ndead code, extracted shared semver handling, and closed visibility model gaps.\nBaseline: CmdForge commit ",(0,r.jsx)(n.code,{children:"6908d8e"})," (",(0,r.jsx)(n.code,{children:"Modernize provider support"}),"), validated\nwith 406 passing non-integration tests."]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider audit and remediation"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Subprocess, OpenAI-compatible API, and experimental PTY provider types"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider discovery and first-run configuration"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Multi-step fallback chains with cycle detection"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider install guide updates"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Dead-code removal and semver extraction"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool visibility model and regression fixes"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsxs)(n.p,{children:["Deferred follow-ups are tracked explicitly in the roadmap: tool-level fallback\nchain preference, PTY production hardening, and migration of still-relevant\n",(0,r.jsx)(n.code,{children:"olddocs/"})," material."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m5-testing--polish",children:"M5: Testing & Polish"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q1 2027\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsxs)(n.p,{children:["Testing framework, theming, and version management. ",(0,r.jsx)(n.strong,{children:"Project dependencies"})," (completed): - ",(0,r.jsx)(n.code,{children:"cmdforge.yaml"})," manifest format for declaring tool dependencies - ",(0,r.jsx)(n.code,{children:"cmdforge install"})," to install all dependencies from manifest - ",(0,r.jsx)(n.code,{children:"cmdforge add official/toolname"})," to add a dependency to manifest - ",(0,r.jsx)(n.code,{children:"cmdforge remove <tool>"})," to remove dependencies from manifest - Automatic dependency checking before running meta-tools. ",(0,r.jsx)(n.strong,{children:"Tool testing framework"})," includes: - TestStepDialog for interactive step testing from GUI - Test button in Tool Builder to test individual steps - Variable input forms auto-detect ",(0,r.jsx)(n.code,{children:"{variable}"})," references from step templates - Multiple assertion types (not_empty, contains, valid_json, matches_regex, min/max_length, etc.) - Background execution with timing metrics - Output variable display and assertion pass/fail results - Provider override for testing with mock provider"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool testing framework"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Simple theming (external QSS files)"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Dark mode"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool versioning support"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Version constraints in manifests"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Project dependency system (",(0,r.jsx)(n.code,{children:"cmdforge install"}),")"]}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"cmdforge add"})," command"]}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"cmdforge remove"})," command"]}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Dependency resolution for meta-tools"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Hash verification fix"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Improved ",(0,r.jsx)(n.code,{children:"add"})," UX for local tools"]}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m0-core-platform",children:"M0: Core Platform"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": December 2025\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsx)(n.p,{children:"The foundational CmdForge platform with AI-powered CLI tool builder, YAML tool definitions, web UI, offline caching, and provider abstraction."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"YAML tool definition system"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"CLI entry point and subcommands"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Provider abstraction layer"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Offline caching for tools"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Web UI for tool browsing"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool execution engine"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m1-production-ready",children:"M1: Production Ready"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": February 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsx)(n.p,{children:"Production deployment with proper server configuration, complete documentation, and improved reliability."}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Public documentation"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Systemd service setup"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Gunicorn production server"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Systemd linger for persistence"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"CI/CD pipeline"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Error message improvements"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Source field display in web UI"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m2-tool-discovery",children:"M2: Tool Discovery"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q2 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsxs)(n.p,{children:["Enable users to discover, rate, and share tools through a marketplace interface with curation to maintain quality. ",(0,r.jsx)(n.strong,{children:"Tool search and filtering"})," includes: - ",(0,r.jsx)(n.code,{children:"/api/v1/tags"})," endpoint for listing tags with counts - Advanced search with tag filtering (AND logic), multi-category (OR logic), owner, download range, date range - Faceted search responses with category/tag/owner counts - CLI: ",(0,r.jsx)(n.code,{children:"--tag"}),", ",(0,r.jsx)(n.code,{children:"--owner"}),", ",(0,r.jsx)(n.code,{children:"--min-downloads"}),", ",(0,r.jsx)(n.code,{children:"--popular"}),", ",(0,r.jsx)(n.code,{children:"--since"}),", ",(0,r.jsx)(n.code,{children:"--json"}),", ",(0,r.jsx)(n.code,{children:"--show-facets"})," options - CLI: ",(0,r.jsx)(n.code,{children:"registry tags"})," subcommand - Web UI: Filter sidebar with checkboxes, dropdowns, active filter chips, URL-based state ",(0,r.jsx)(n.strong,{children:"PySide6 GUI conversion"})," includes: - Modern desktop GUI replacing urwid TUI - Sidebar navigation (My Tools, Registry, Providers, Profiles) - Tool Builder with visual form for creating/editing tools - Keyboard shortcuts (Ctrl+N, Ctrl+S, Ctrl+R, Ctrl+1/2/3/4, Escape, Ctrl+Q) - Window geometry persistence ",(0,r.jsx)(n.strong,{children:"GUI Registry browser"})," includes: - Browse/search tools with category and sort filters - Star ratings display in table and details - Clickable tags for filtering - Installed indicator (\u2713) and update available (\u2191) - Pagination for large result sets - Publisher reputation info ",(0,r.jsx)(n.strong,{children:"GUI Publishing"})," includes: - Connect dialog with polling-based account pairing - Publish workflow with version selection - Full publish workflow with confirmation ",(0,r.jsx)(n.strong,{children:"Infrastructure improvements"}),": - ",(0,r.jsx)(n.code,{children:"Dockerfile.test-install"}),": Fresh environment for testing installer - ",(0,r.jsx)(n.code,{children:"Dockerfile.ready"}),": Pre-installed container for quick usage - ",(0,r.jsx)(n.code,{children:"install.sh"}),": Interactive installer with venv, PATH setup, optional example tools - Database migration: Auto-adds missing columns on server start ",(0,r.jsx)(n.strong,{children:"Registry curation system"})," includes: - Role-based access control (user, moderator, admin) - Tool moderation workflow (pending \u2192 approved/rejected/removed) - Publisher management (ban/unban, role changes) - Private/unlisted tool visibility (auto-approved, owner-only access) - Audit logging for all moderation actions - Admin web UI pages (pending queue, publishers, reports, audit log) - Report resolution workflow ",(0,r.jsx)(n.strong,{children:"App pairing/connection flow"})," includes: - ",(0,r.jsx)(n.code,{children:"cmdforge config connect <username>"}),' CLI command - GUI Connect dialog with polling-based approval - Web UI "Connections" page (replaces API Tokens) - Device hostname tracking for connected apps ',(0,r.jsx)(n.strong,{children:"Tool ratings/reviews"})," includes: - 5-star rating system with review text - Average rating display on tool cards - Publisher reputation scores - Rating count and distribution ",(0,r.jsx)(n.strong,{children:"Tool marketplace UI enhancements"})," includes: - Browse all tools on page load - Category filter dropdown - Sort by popularity, rating, newest, name - Clickable tags for filtering - Installed/update indicators - Pagination controls ",(0,r.jsx)(n.strong,{children:"AI persona profiles"})," includes: - Profile dataclass with name, description, system_prompt - 8 built-in profiles (Comedian, Technical Writer, Teacher, Concise, Creative, Code Reviewer, Analyst) - Custom profile creation and storage - Profile selector in Prompt Step dialog - Profile injection during tool execution - Profiles page in GUI (Ctrl+4) ",(0,r.jsx)(n.strong,{children:"AI-assisted code generation"})," includes: - Split-view Code Step dialog (editor + AI assist panel) - Provider selector for AI calls - Smart prompt template with available variables - Background thread for non-blocking AI calls - Automatic markdown fence stripping - Python syntax checking before save"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool search and filtering"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"PySide6 GUI conversion"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"GUI Registry browser"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"GUI Publishing with connect flow"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Docker containers (test + ready)"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Interactive installer script"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Database migration system"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Registry curation system"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"App pairing/connection flow"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool ratings/reviews"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool marketplace UI enhancements"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"AI persona profiles"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"AI-assisted code generation"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m3-content--automation",children:"M3: Content & Automation"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q3 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsxs)(n.p,{children:["Automated content ingestion and quality assurance for the tool ecosystem. ",(0,r.jsx)(n.strong,{children:"Import Fabric patterns"})," includes: - Run existing ",(0,r.jsx)(n.code,{children:"scripts/import_fabric.py"})," to populate registry - Automatic attribution with source fields (imported, MIT license, Daniel Miessler) - Category mapping based on pattern name prefixes - README generation with original pattern attribution ",(0,r.jsx)(n.strong,{children:"Auto-vetting pipeline"})," includes: - Integration with existing ",(0,r.jsx)(n.code,{children:"scrutiny.py"})," (honesty, transparency, scope, efficiency checks) - Integration with existing ",(0,r.jsx)(n.code,{children:"similarity.py"})," (duplicate detection) - Auto-approve/review/reject decision logic - Helpful suggestions for tool improvements ",(0,r.jsx)(n.strong,{children:"Scheduled sync"})," includes: - Periodic checks for Fabric repo updates - Automatic import of new patterns - Version tracking for updated patterns - Admin notifications for review queue"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Import Fabric patterns (233 total)"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Scheduled Fabric repo sync"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Auto-vetting pipeline integration"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Community tool submissions workflow"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Duplicate detection automation"}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h4,{id:"m4-user-experience",children:"M4: User Experience"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Target"}),": Q4 2026\n",(0,r.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,r.jsxs)(n.p,{children:["Visual improvements, interactive guidance, and missing registry features. ",(0,r.jsx)(n.strong,{children:"Collections CLI commands"})," includes: - ",(0,r.jsx)(n.code,{children:"cmdforge collections list"})," - List available collections with tool counts - ",(0,r.jsx)(n.code,{children:"cmdforge collections info <name>"})," - Show collection details with tool list - ",(0,r.jsx)(n.code,{children:"cmdforge collections install <name>"})," - Install all tools in a collection - ",(0,r.jsx)(n.code,{children:"--json"})," flag for machine-readable output - ",(0,r.jsx)(n.code,{children:"--pinned"})," flag to use pinned versions from collection ",(0,r.jsx)(n.strong,{children:"Admin collections management"})," includes: - Admin dashboard page at ",(0,r.jsx)(n.code,{children:"/dashboard/admin/collections"})," - Create/edit/delete collections via web UI - Tool reference input with version pinning - Admin API endpoints (GET/POST/PUT/DELETE) ",(0,r.jsx)(n.strong,{children:"Password reset flow"})," includes: - ",(0,r.jsx)(n.code,{children:"/forgot-password"})," page with email input form - ",(0,r.jsx)(n.code,{children:"/reset-password?token=xxx"})," page with new password form - API endpoints: request, validate, complete password reset - Email utility module (logs to console in dev mode, SMTP-ready for production) - Security: 1-hour token expiry, single-use tokens, rate limiting (5/hour per IP, 3/hour per email) - Session invalidation on password change - Email enumeration prevention (always returns success message) ",(0,r.jsx)(n.strong,{children:"Visual node-based editor"})," includes: - NodeGraphQt-based flow visualization (",(0,r.jsx)(n.code,{children:"flow_graph.py"}),") - Custom node types: InputNode, PromptNode, CodeNode, OutputNode - Visual connections showing data flow between steps - Double-click nodes to edit steps - Auto-layout with fit-to-view - Keyboard shortcuts (A: select all, F: fit view) - Context menu for common actions - Help banner overlay with controls ",(0,r.jsx)(n.strong,{children:"Drag-and-drop step reordering"})," includes: - Drag-drop reordering in list view - Reordering support from flow view - Variable dependency warnings when reordering breaks references - Automatic step index updates ",(0,r.jsx)(n.strong,{children:"Tool visualization improvements"})," includes: - Flow graph widget showing tool execution pipeline - Color-coded nodes by step type (indigo=prompt, green=code, purple=tool) - Input/output port visualization - Variable flow connections between steps ",(0,r.jsx)(n.strong,{children:"Tool composition and chaining UI"}),' includes: - ToolStep data class for calling other tools as pipeline steps - ToolStepDialog for configuring tool steps (tool selection, input mapping, args) - "Add Tool" button in Tool Builder alongside Add Prompt/Add Code - ToolNode in flow graph visualization (purple node) - Input template with variable substitution from previous steps - Argument passing with variable substitution - Provider override option for nested tool calls - Recursion depth protection (max 10 levels) - Dependency checking and missing tool warnings - Auto-populate dependencies when adding ToolStep in GUI - ',(0,r.jsx)(n.code,{children:"--auto-install"})," flag for automatic dependency installation at runtime ",(0,r.jsx)(n.strong,{children:"Interactive walkthroughs"})," includes: - First-time user onboarding - Guided tool creation tutorial - Feature discovery tooltips - Context-sensitive help ",(0,r.jsx)(n.strong,{children:"Interactive Tool Picker"})," includes: - ",(0,r.jsx)(n.code,{children:"cf"})," command for fuzzy-search tool selection - Piping support for seamless workflow integration"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Deliverable"}),(0,r.jsx)(n.th,{children:"Status"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Collections CLI commands"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Admin collections management UI"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Visual node-based step editor"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Interactive onboarding walkthroughs"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool visualization improvements"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Tool composition and chaining UI"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Drag-and-drop step reordering"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Password reset flow"}),(0,r.jsx)(n.td,{children:"Done"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsxs)(n.td,{children:["Interactive Tool Picker (",(0,r.jsx)(n.code,{children:"cf"})," command)"]}),(0,r.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,r.jsx)(n.hr,{})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453(e,n,i){i.d(n,{R:()=>o,x:()=>d});var t=i(6540);const r={},s=t.createContext(r);function o(e){const n=t.useContext(s);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/817f7194.9dbada51.js b/assets/js/817f7194.9dbada51.js deleted file mode 100644 index bae95ef..0000000 --- a/assets/js/817f7194.9dbada51.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[574],{921(e,n,t){t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"milestones","title":"Milestones","description":"Active","source":"@site/docs/milestones.md","sourceDirName":".","slug":"/milestones","permalink":"/rob/CmdForge/milestones","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"milestones","project":"cmdforge","updated":"2026-01-17T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"Ideas & Exploration","permalink":"/rob/CmdForge/ideas-and-exploration"}}');var s=t(4848),r=t(8453);const o={type:"milestones",project:"cmdforge",updated:new Date("2026-01-17T00:00:00.000Z")},d="Milestones",l={},c=[{value:"Active",id:"active",level:2},{value:"Completed",id:"completed",level:2},{value:"M5: Testing & Polish",id:"m5-testing--polish",level:4},{value:"M0: Core Platform",id:"m0-core-platform",level:4},{value:"M1: Production Ready",id:"m1-production-ready",level:4},{value:"M2: Tool Discovery",id:"m2-tool-discovery",level:4},{value:"M3: Content & Automation",id:"m3-content--automation",level:4},{value:"M4: User Experience",id:"m4-user-experience",level:4}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h4:"h4",header:"header",hr:"hr",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"milestones",children:"Milestones"})}),"\n",(0,s.jsx)(n.h2,{id:"active",children:"Active"}),"\n",(0,s.jsx)(n.p,{children:"(none)"}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h2,{id:"completed",children:"Completed"}),"\n",(0,s.jsx)(n.h4,{id:"m5-testing--polish",children:"M5: Testing & Polish"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": Q1 2027\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,s.jsxs)(n.p,{children:["Testing framework, theming, and version management. ",(0,s.jsx)(n.strong,{children:"Project dependencies"})," (completed): - ",(0,s.jsx)(n.code,{children:"cmdforge.yaml"})," manifest format for declaring tool dependencies - ",(0,s.jsx)(n.code,{children:"cmdforge install"})," to install all dependencies from manifest - ",(0,s.jsx)(n.code,{children:"cmdforge add official/toolname"})," to add a dependency to manifest - Automatic dependency checking before running meta-tools. ",(0,s.jsx)(n.strong,{children:"Tool testing framework"})," includes: - TestStepDialog for interactive step testing from GUI - Test button in Tool Builder to test individual steps - Variable input forms auto-detect ",(0,s.jsx)(n.code,{children:"{variable}"})," references from step templates - Multiple assertion types (not_empty, contains, valid_json, matches_regex, min/max_length, etc.) - Background execution with timing metrics - Output variable display and assertion pass/fail results - Provider override for testing with mock provider"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool testing framework"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Simple theming (external QSS files)"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Dark mode"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool versioning support"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Version constraints in manifests"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.td,{children:["Project dependency system (",(0,s.jsx)(n.code,{children:"cmdforge install"}),")"]}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"cmdforge add"})," command"]}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Dependency resolution for meta-tools"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h4,{id:"m0-core-platform",children:"M0: Core Platform"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": December 2025\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,s.jsx)(n.p,{children:"The foundational CmdForge platform with AI-powered CLI tool builder, YAML tool definitions, web UI, offline caching, and provider abstraction."}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML tool definition system"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"CLI entry point and subcommands"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Provider abstraction layer"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Offline caching for tools"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Web UI for tool browsing"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool execution engine"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h4,{id:"m1-production-ready",children:"M1: Production Ready"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": February 2026\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,s.jsx)(n.p,{children:"Production deployment with proper server configuration, complete documentation, and improved reliability."}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Public documentation"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Systemd service setup"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Gunicorn production server"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Systemd linger for persistence"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"CI/CD pipeline"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Error message improvements"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Source field display in web UI"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h4,{id:"m2-tool-discovery",children:"M2: Tool Discovery"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": Q2 2026\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,s.jsxs)(n.p,{children:["Enable users to discover, rate, and share tools through a marketplace interface with curation to maintain quality. ",(0,s.jsx)(n.strong,{children:"Tool search and filtering"})," includes: - ",(0,s.jsx)(n.code,{children:"/api/v1/tags"})," endpoint for listing tags with counts - Advanced search with tag filtering (AND logic), multi-category (OR logic), owner, download range, date range - Faceted search responses with category/tag/owner counts - CLI: ",(0,s.jsx)(n.code,{children:"--tag"}),", ",(0,s.jsx)(n.code,{children:"--owner"}),", ",(0,s.jsx)(n.code,{children:"--min-downloads"}),", ",(0,s.jsx)(n.code,{children:"--popular"}),", ",(0,s.jsx)(n.code,{children:"--since"}),", ",(0,s.jsx)(n.code,{children:"--json"}),", ",(0,s.jsx)(n.code,{children:"--show-facets"})," options - CLI: ",(0,s.jsx)(n.code,{children:"registry tags"})," subcommand - Web UI: Filter sidebar with checkboxes, dropdowns, active filter chips, URL-based state ",(0,s.jsx)(n.strong,{children:"PySide6 GUI conversion"})," includes: - Modern desktop GUI replacing urwid TUI - Sidebar navigation (My Tools, Registry, Providers, Profiles) - Tool Builder with visual form for creating/editing tools - Keyboard shortcuts (Ctrl+N, Ctrl+S, Ctrl+R, Ctrl+1/2/3/4, Escape, Ctrl+Q) - Window geometry persistence ",(0,s.jsx)(n.strong,{children:"GUI Registry browser"})," includes: - Browse/search tools with category and sort filters - Star ratings display in table and details - Clickable tags for filtering - Installed indicator (\u2713) and update available (\u2191) - Pagination for large result sets - Publisher reputation info ",(0,s.jsx)(n.strong,{children:"GUI Publishing"})," includes: - Connect dialog with polling-based account pairing - Publish workflow with version selection - Full publish workflow with confirmation ",(0,s.jsx)(n.strong,{children:"Infrastructure improvements"}),": - ",(0,s.jsx)(n.code,{children:"Dockerfile.test-install"}),": Fresh environment for testing installer - ",(0,s.jsx)(n.code,{children:"Dockerfile.ready"}),": Pre-installed container for quick usage - ",(0,s.jsx)(n.code,{children:"install.sh"}),": Interactive installer with venv, PATH setup, optional example tools - Database migration: Auto-adds missing columns on server start ",(0,s.jsx)(n.strong,{children:"Registry curation system"})," includes: - Role-based access control (user, moderator, admin) - Tool moderation workflow (pending \u2192 approved/rejected/removed) - Publisher management (ban/unban, role changes) - Private/unlisted tool visibility (auto-approved, owner-only access) - Audit logging for all moderation actions - Admin web UI pages (pending queue, publishers, reports, audit log) - Report resolution workflow ",(0,s.jsx)(n.strong,{children:"App pairing/connection flow"})," includes: - ",(0,s.jsx)(n.code,{children:"cmdforge config connect <username>"}),' CLI command - GUI Connect dialog with polling-based approval - Web UI "Connections" page (replaces API Tokens) - Device hostname tracking for connected apps ',(0,s.jsx)(n.strong,{children:"Tool ratings/reviews"})," includes: - 5-star rating system with review text - Average rating display on tool cards - Publisher reputation scores - Rating count and distribution ",(0,s.jsx)(n.strong,{children:"Tool marketplace UI enhancements"})," includes: - Browse all tools on page load - Category filter dropdown - Sort by popularity, rating, newest, name - Clickable tags for filtering - Installed/update indicators - Pagination controls ",(0,s.jsx)(n.strong,{children:"AI persona profiles"})," includes: - Profile dataclass with name, description, system_prompt - 8 built-in profiles (Comedian, Technical Writer, Teacher, Concise, Creative, Code Reviewer, Analyst) - Custom profile creation and storage - Profile selector in Prompt Step dialog - Profile injection during tool execution - Profiles page in GUI (Ctrl+4) ",(0,s.jsx)(n.strong,{children:"AI-assisted code generation"})," includes: - Split-view Code Step dialog (editor + AI assist panel) - Provider selector for AI calls - Smart prompt template with available variables - Background thread for non-blocking AI calls - Automatic markdown fence stripping - Python syntax checking before save"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool search and filtering"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"PySide6 GUI conversion"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"GUI Registry browser"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"GUI Publishing with connect flow"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Docker containers (test + ready)"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Interactive installer script"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Database migration system"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Registry curation system"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"App pairing/connection flow"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool ratings/reviews"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool marketplace UI enhancements"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"AI persona profiles"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"AI-assisted code generation"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h4,{id:"m3-content--automation",children:"M3: Content & Automation"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": Q3 2026\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (100%)"]}),"\n",(0,s.jsxs)(n.p,{children:["Automated content ingestion and quality assurance for the tool ecosystem. ",(0,s.jsx)(n.strong,{children:"Import Fabric patterns"})," includes: - Run existing ",(0,s.jsx)(n.code,{children:"scripts/import_fabric.py"})," to populate registry - Automatic attribution with source fields (imported, MIT license, Daniel Miessler) - Category mapping based on pattern name prefixes - README generation with original pattern attribution ",(0,s.jsx)(n.strong,{children:"Auto-vetting pipeline"})," includes: - Integration with existing ",(0,s.jsx)(n.code,{children:"scrutiny.py"})," (honesty, transparency, scope, efficiency checks) - Integration with existing ",(0,s.jsx)(n.code,{children:"similarity.py"})," (duplicate detection) - Auto-approve/review/reject decision logic - Helpful suggestions for tool improvements ",(0,s.jsx)(n.strong,{children:"Scheduled sync"})," includes: - Periodic checks for Fabric repo updates - Automatic import of new patterns - Version tracking for updated patterns - Admin notifications for review queue"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Import Fabric patterns (233 total)"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Scheduled Fabric repo sync"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Auto-vetting pipeline integration"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Community tool submissions workflow"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Duplicate detection automation"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{}),"\n",(0,s.jsx)(n.h4,{id:"m4-user-experience",children:"M4: User Experience"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Target"}),": Q4 2026\n",(0,s.jsx)(n.strong,{children:"Status"}),": Completed (87%)"]}),"\n",(0,s.jsxs)(n.p,{children:["Visual improvements, interactive guidance, and missing registry features. ",(0,s.jsx)(n.strong,{children:"Collections CLI commands"})," includes: - ",(0,s.jsx)(n.code,{children:"cmdforge collections list"})," - List available collections with tool counts - ",(0,s.jsx)(n.code,{children:"cmdforge collections info <name>"})," - Show collection details with tool list - ",(0,s.jsx)(n.code,{children:"cmdforge collections install <name>"})," - Install all tools in a collection - ",(0,s.jsx)(n.code,{children:"--json"})," flag for machine-readable output - ",(0,s.jsx)(n.code,{children:"--pinned"})," flag to use pinned versions from collection ",(0,s.jsx)(n.strong,{children:"Admin collections management"})," includes: - Admin dashboard page at ",(0,s.jsx)(n.code,{children:"/dashboard/admin/collections"})," - Create/edit/delete collections via web UI - Tool reference input with version pinning - Admin API endpoints (GET/POST/PUT/DELETE) ",(0,s.jsx)(n.strong,{children:"Password reset flow"})," includes: - ",(0,s.jsx)(n.code,{children:"/forgot-password"})," page with email input form - ",(0,s.jsx)(n.code,{children:"/reset-password?token=xxx"})," page with new password form - API endpoints: request, validate, complete password reset - Email utility module (logs to console in dev mode, SMTP-ready for production) - Security: 1-hour token expiry, single-use tokens, rate limiting (5/hour per IP, 3/hour per email) - Session invalidation on password change - Email enumeration prevention (always returns success message) ",(0,s.jsx)(n.strong,{children:"Visual node-based editor"})," includes: - NodeGraphQt-based flow visualization (",(0,s.jsx)(n.code,{children:"flow_graph.py"}),") - Custom node types: InputNode, PromptNode, CodeNode, OutputNode - Visual connections showing data flow between steps - Double-click nodes to edit steps - Auto-layout with fit-to-view - Keyboard shortcuts (A: select all, F: fit view) - Context menu for common actions - Help banner overlay with controls ",(0,s.jsx)(n.strong,{children:"Drag-and-drop step reordering"})," includes: - Drag-drop reordering in list view - Reordering support from flow view - Variable dependency warnings when reordering breaks references - Automatic step index updates ",(0,s.jsx)(n.strong,{children:"Tool visualization improvements"})," includes: - Flow graph widget showing tool execution pipeline - Color-coded nodes by step type (indigo=prompt, green=code, purple=tool) - Input/output port visualization - Variable flow connections between steps ",(0,s.jsx)(n.strong,{children:"Tool composition and chaining UI"}),' includes: - ToolStep data class for calling other tools as pipeline steps - ToolStepDialog for configuring tool steps (tool selection, input mapping, args) - "Add Tool" button in Tool Builder alongside Add Prompt/Add Code - ToolNode in flow graph visualization (purple node) - Input template with variable substitution from previous steps - Argument passing with variable substitution - Provider override option for nested tool calls - Recursion depth protection (max 10 levels) - Dependency checking and missing tool warnings - Auto-populate dependencies when adding ToolStep in GUI - ',(0,s.jsx)(n.code,{children:"--auto-install"})," flag for automatic dependency installation at runtime ",(0,s.jsx)(n.strong,{children:"Interactive walkthroughs"})," includes: - First-time user onboarding - Guided tool creation tutorial - Feature discovery tooltips - Context-sensitive help"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Deliverable"}),(0,s.jsx)(n.th,{children:"Status"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Collections CLI commands"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Admin collections management UI"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Visual node-based step editor"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Interactive onboarding walkthroughs"}),(0,s.jsx)(n.td,{children:"Not Started"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool visualization improvements"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Tool composition and chaining UI"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Drag-and-drop step reordering"}),(0,s.jsx)(n.td,{children:"Done"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"Password reset flow"}),(0,s.jsx)(n.td,{children:"Done"})]})]})]}),"\n",(0,s.jsx)(n.hr,{})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453(e,n,t){t.d(n,{R:()=>o,x:()=>d});var i=t(6540);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9bb76ab4.34bde5a9.js b/assets/js/9bb76ab4.34bde5a9.js deleted file mode 100644 index 7dc246f..0000000 --- a/assets/js/9bb76ab4.34bde5a9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[530],{7367(e,n,i){i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"reference/design","title":"CmdForge Design Document","description":"A lightweight personal tool builder for AI-powered CLI commands","source":"@site/docs/reference/design.md","sourceDirName":"reference","slug":"/reference/design","permalink":"/rob/CmdForge/reference/design","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"sidebar_label":"Design Philosophy","sidebar_position":5,"format":"md"},"sidebar":"docs","previous":{"title":"Example Tools","permalink":"/rob/CmdForge/reference/examples"},"next":{"title":"Web UI Design","permalink":"/rob/CmdForge/reference/web-ui-spec"}}');var r=i(4848),l=i(8453);const t={sidebar_label:"Design Philosophy",sidebar_position:5,format:"md"},o="CmdForge Design Document",d={},c=[{value:"Overview",id:"overview",level:2},{value:"Core Concepts",id:"core-concepts",level:2},{value:"Tool = Directory + Config",id:"tool--directory--config",level:3},{value:"config.yaml Format",id:"configyaml-format",level:3},{value:"Step Types",id:"step-types",level:3},{value:"Variables",id:"variables",level:3},{value:"Output Variables",id:"output-variables",level:3},{value:"CLI Interface",id:"cli-interface",level:2},{value:"Running Tools",id:"running-tools",level:3},{value:"Input Handling",id:"input-handling",level:3},{value:"Universal Flags (all tools)",id:"universal-flags-all-tools",level:3},{value:"Managing Tools",id:"managing-tools",level:3},{value:"Tool Composition",id:"tool-composition",level:2},{value:"External Pipelines (Tool-to-Tool)",id:"external-pipelines-tool-to-tool",level:3},{value:"Internal Pipelines (Multi-Step)",id:"internal-pipelines-multi-step",level:3},{value:"What This Design Doesn't Include",id:"what-this-design-doesnt-include",level:2},{value:"Dependencies",id:"dependencies",level:2},{value:"Example Workflow",id:"example-workflow",level:2}];function a(e){const n={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"cmdforge-design-document",children:"CmdForge Design Document"})}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsx)(n.p,{children:"A lightweight personal tool builder for AI-powered CLI commands"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsx)(n.p,{children:"CmdForge lets you create custom AI-powered terminal commands. You define a tool once (name, steps, provider), then use it like any Linux command."}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Example:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Create a summarizer tool, then use it:\nsum -i text.txt -o summary.txt --max 512\n"})}),"\n",(0,r.jsx)(n.h2,{id:"core-concepts",children:"Core Concepts"}),"\n",(0,r.jsx)(n.h3,{id:"tool--directory--config",children:"Tool = Directory + Config"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"~/.cmdforge/\n sum/\n config.yaml\n processed.py # Optional external code file\n reviewer/\n config.yaml\n translator/\n config.yaml\n"})}),"\n",(0,r.jsx)(n.h3,{id:"configyaml-format",children:"config.yaml Format"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: sum\ndescription: "Summarize documents"\narguments:\n - flag: --max\n variable: max\n default: "500"\n description: "Maximum words in summary"\nsteps:\n - type: prompt\n prompt: |\n Summarize the following text in {max} words or less:\n\n {input}\n provider: claude\n output_var: response\noutput: "{response}"\n\n# Optional: declare dependencies for meta-tools\ndependencies:\n - official/summarize\n - official/translate@^1.0.0 # With version constraint\n'})}),"\n",(0,r.jsx)(n.h3,{id:"step-types",children:"Step Types"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Prompt Step"})," - Calls an AI provider:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'- type: prompt\n prompt: "Your prompt template with {variables}"\n provider: claude\n output_var: response\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Code Step"})," - Runs Python code:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"- type: code\n code: |\n processed = input.upper()\n count = len(processed.split())\n output_var: processed, count\n code_file: processed.py # Optional: external file storage\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Tool Step"})," - Calls another CmdForge tool (meta-tools):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'- type: tool\n tool: official/summarize # Tool reference (owner/name or just name for local)\n input: "{input}" # Input to pass (supports variable substitution)\n args: # Optional arguments\n max_words: "100"\n output_var: summary # Variable to store the tool\'s output\n provider: claude # Optional: override the called tool\'s provider\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Steps execute in order. Each step's ",(0,r.jsx)(n.code,{children:"output_var"})," becomes available to subsequent steps."]}),"\n",(0,r.jsx)(n.h3,{id:"variables",children:"Variables"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"{input}"})," - Always available, contains stdin or input file content (empty string if no input)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"{variable_name}"})," - From arguments (e.g., ",(0,r.jsx)(n.code,{children:"{max}"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"{output_var}"})," - From previous steps (e.g., ",(0,r.jsx)(n.code,{children:"{response}"}),", ",(0,r.jsx)(n.code,{children:"{processed}"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"output-variables",children:"Output Variables"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"output_var"})," field specifies which Python variable(s) to capture from your code:"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Single variable:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"output_var: processed\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"processed = input.upper() # This gets captured\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Multiple variables (comma-separated):"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"output_var: processed, count, summary\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'processed = input.upper()\ncount = len(processed.split())\nsummary = f"Processed {count} words"\n# All three are captured and available as {processed}, {count}, {summary}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"cli-interface",children:"CLI Interface"}),"\n",(0,r.jsx)(n.h3,{id:"running-tools",children:"Running Tools"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Basic usage (wrapper script in ~/.local/bin)\nsum -i document.txt -o summary.txt\n\n# With custom args\nsum -i document.txt --max 200\n\n# Preview prompt without calling AI\nsum -i document.txt --dry-run\n\n# Test with mock (no API call)\nsum -i document.txt --provider mock\n\n# Read from stdin, write to stdout\ncat doc.txt | sum | less\n\n# Or via cmdforge run\ncmdforge run sum -i document.txt\n"})}),"\n",(0,r.jsx)(n.h3,{id:"input-handling",children:"Input Handling"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Scenario"}),(0,r.jsx)(n.th,{children:"Behavior"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"Piped stdin"}),(0,r.jsxs)(n.td,{children:["Automatically read (",(0,r.jsx)(n.code,{children:"cat file.txt | mytool"}),")"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-i file.txt"})}),(0,r.jsx)(n.td,{children:"Read from file"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--stdin"})}),(0,r.jsx)(n.td,{children:"Interactive input (type then Ctrl+D)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:"No input"}),(0,r.jsx)(n.td,{children:"Empty string (useful for argument-only tools)"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"universal-flags-all-tools",children:"Universal Flags (all tools)"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Flag"}),(0,r.jsx)(n.th,{children:"Short"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--input"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-i"})}),(0,r.jsx)(n.td,{children:"Input file"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--output"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-o"})}),(0,r.jsx)(n.td,{children:"Output file (or stdout if omitted)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--stdin"})}),(0,r.jsx)(n.td,{}),(0,r.jsx)(n.td,{children:"Read input interactively (type then Ctrl+D)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--dry-run"})}),(0,r.jsx)(n.td,{}),(0,r.jsx)(n.td,{children:"Show prompt, don't call AI"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--show-prompt"})}),(0,r.jsx)(n.td,{}),(0,r.jsx)(n.td,{children:"Call AI but also print prompt to stderr"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--provider"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-p"})}),(0,r.jsxs)(n.td,{children:["Override provider (e.g., ",(0,r.jsx)(n.code,{children:"--provider mock"}),")"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--verbose"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-v"})}),(0,r.jsx)(n.td,{children:"Show debug info"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"--help"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"-h"})}),(0,r.jsx)(n.td,{children:"Show help"})]})]})]}),"\n",(0,r.jsx)(n.h3,{id:"managing-tools",children:"Managing Tools"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cmdforge list # List all tools\ncmdforge create sum # Create new tool (basic)\ncmdforge edit sum # Edit tool config in $EDITOR\ncmdforge delete sum # Delete tool\ncmdforge test sum # Test with mock provider\ncmdforge run sum # Run tool for real\ncmdforge refresh # Refresh all wrapper scripts\ncmdforge check sum # Check dependencies for meta-tools\ncmdforge ui # Launch interactive UI\n"})}),"\n",(0,r.jsx)(n.h2,{id:"tool-composition",children:"Tool Composition"}),"\n",(0,r.jsx)(n.p,{children:"CmdForge tools are designed to chain together like any Unix command."}),"\n",(0,r.jsx)(n.h3,{id:"external-pipelines-tool-to-tool",children:"External Pipelines (Tool-to-Tool)"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Chain multiple CmdForge tools\ncat logs.txt | log-errors | summarize | translate --lang Japanese\n\n# Mix with standard Unix tools\ngit log --oneline | head -20 | changelog | tee CHANGELOG.md\n\n# Build complex workflows\ncat *.py | review-code --focus security | json-extract --fields "issue, severity, file" | json2csv\n'})}),"\n",(0,r.jsx)(n.p,{children:"Each tool reads stdin and writes stdout. No special integration needed."}),"\n",(0,r.jsx)(n.h3,{id:"internal-pipelines-multi-step",children:"Internal Pipelines (Multi-Step)"}),"\n",(0,r.jsx)(n.p,{children:"Within a single tool, chain steps for preprocessing/validation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"steps:\n - type: code # Preprocess\n code: |\n filtered = '\\n'.join(l for l in input.split('\\n') if 'ERROR' in l)\n output_var: filtered\n - type: prompt # AI processes filtered input\n prompt: \"Explain these errors: {filtered}\"\n provider: claude-haiku\n output_var: explanation\n - type: code # Post-process\n code: |\n result = f\"Found {len(filtered.split(chr(10)))} errors:\\n\\n{explanation}\"\n output_var: result\noutput: \"{result}\"\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"When to use which:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"External pipelines"}),": Reusable tools, different providers per stage, standard Unix interop"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Internal pipelines"}),": Tightly coupled steps, shared context, validation of AI output"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"what-this-design-doesnt-include",children:"What This Design Doesn't Include"}),"\n",(0,r.jsx)(n.p,{children:"Intentionally omitted (not needed for personal use):"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Trust tiers / security levels"}),"\n",(0,r.jsx)(n.li,{children:"Cryptographic signing"}),"\n",(0,r.jsx)(n.li,{children:"Container isolation / sandboxing"}),"\n",(0,r.jsx)(n.li,{children:"Certification testing"}),"\n",(0,r.jsx)(n.li,{children:"Distribution packaging"}),"\n",(0,r.jsx)(n.li,{children:"PII redaction"}),"\n",(0,r.jsx)(n.li,{children:"Audit logging"}),"\n",(0,r.jsx)(n.li,{children:"Provider capability negotiation"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Why?"})," This is a personal tool builder. You write the tools, you run the tools, you accept the responsibility. Just like any bash script you write."]}),"\n",(0,r.jsx)(n.h2,{id:"dependencies",children:"Dependencies"}),"\n",(0,r.jsx)(n.p,{children:"Required:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Python 3.10+"}),"\n",(0,r.jsx)(n.li,{children:"PyYAML"}),"\n",(0,r.jsx)(n.li,{children:"urwid (for TUI)"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Optional fallbacks:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"python3-newt/snack (simpler TUI)"}),"\n",(0,r.jsx)(n.li,{children:"dialog/whiptail (basic TUI)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"example-workflow",children:"Example Workflow"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Run ",(0,r.jsx)(n.code,{children:"cmdforge"})," to open UI"]}),"\n",(0,r.jsx)(n.li,{children:'Select "Create" to create a new tool'}),"\n",(0,r.jsx)(n.li,{children:"Fill in: name, description, output template"}),"\n",(0,r.jsxs)(n.li,{children:["Add arguments (e.g., ",(0,r.jsx)(n.code,{children:"--max"})," with default ",(0,r.jsx)(n.code,{children:"500"}),")"]}),"\n",(0,r.jsx)(n.li,{children:"Add a prompt step with your prompt template and provider"}),"\n",(0,r.jsx)(n.li,{children:'Click "Save"'}),"\n",(0,r.jsx)(n.li,{children:"Exit UI"}),"\n",(0,r.jsxs)(n.li,{children:["Run ",(0,r.jsx)(n.code,{children:"sum -i myfile.txt -o summary.txt"})]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Done. No containers, no signing, no certification. Just a tool that works."})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453(e,n,i){i.d(n,{R:()=>t,x:()=>o});var s=i(6540);const r={},l=s.createContext(r);function t(e){const n=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:t(e.components),s.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a94703ab.b8c77466.js b/assets/js/a94703ab.b8c77466.js deleted file mode 100644 index b38cdb9..0000000 --- a/assets/js/a94703ab.b8c77466.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[48],{3363(e,t,n){n.d(t,{A:()=>l});n(6540);var a=n(4164),i=n(1312),s=n(1107),o=n(4848);function l({className:e}){return(0,o.jsx)("main",{className:(0,a.A)("container margin-vert--xl",e),children:(0,o.jsx)("div",{className:"row",children:(0,o.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,o.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,o.jsx)(i.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,o.jsx)("p",{children:(0,o.jsx)(i.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,o.jsx)("p",{children:(0,o.jsx)(i.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},8115(e,t,n){n.r(t),n.d(t,{default:()=>Se});var a=n(6540),i=n(4164),s=n(5500),o=n(7559),l=n(4718),r=n(609),c=n(1312),d=n(3104),u=n(5062);const m="backToTopButton_sjWU",b="backToTopButtonShow_xfvO";var h=n(4848);function p(){const{shown:e,scrollToTop:t}=function({threshold:e}){const[t,n]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:o}=(0,d.gk)();return(0,d.Mq)(({scrollY:t},a)=>{const s=a?.scrollY;s&&(i.current?i.current=!1:t>=s?(o(),n(!1)):t<e?n(!1):t+window.innerHeight<document.documentElement.scrollHeight&&n(!0))}),(0,u.$)(e=>{e.location.hash&&(i.current=!0,n(!1))}),{shown:t,scrollToTop:()=>s(0)}}({threshold:300});return(0,h.jsx)("button",{"aria-label":(0,c.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,i.A)("clean-btn",o.G.common.backToTopButton,m,e&&b),type:"button",onClick:t})}var x=n(3109),j=n(6347),f=n(4581),_=n(6342),g=n(3465);function v(e){return(0,h.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,h.jsxs)("g",{fill:"#7a7a7a",children:[(0,h.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,h.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const A="collapseSidebarButton_PEFL",C="collapseSidebarButtonIcon_kv0_";function k({onClick:e}){return(0,h.jsx)("button",{type:"button",title:(0,c.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,i.A)("button button--secondary button--outline",A),onClick:e,children:(0,h.jsx)(v,{className:C})})}var S=n(5041),N=n(9532);const T=Symbol("EmptyContext"),I=a.createContext(T);function y({children:e}){const[t,n]=(0,a.useState)(null),i=(0,a.useMemo)(()=>({expandedItem:t,setExpandedItem:n}),[t]);return(0,h.jsx)(I.Provider,{value:i,children:e})}var L=n(1422),w=n(9169),B=n(8774),E=n(2303),M=n(6654),H=n(3186);const P="menuExternalLink_NmtK",G="linkLabel_WmDU";function W({label:e}){return(0,h.jsx)("span",{title:e,className:G,children:e})}function D({item:e,onItemClick:t,activePath:n,level:a,index:s,...r}){const{href:c,label:d,className:u,autoAddBaseUrl:m}=e,b=(0,l.w8)(e,n),p=(0,M.A)(c);return(0,h.jsx)("li",{className:(0,i.A)(o.G.docs.docSidebarItemLink,o.G.docs.docSidebarItemLinkLevel(a),"menu__list-item",u),children:(0,h.jsxs)(B.A,{className:(0,i.A)("menu__link",!p&&P,{"menu__link--active":b}),autoAddBaseUrl:m,"aria-current":b?"page":void 0,to:c,...p&&{onClick:t?()=>t(e):void 0},...r,children:[(0,h.jsx)(W,{label:d}),!p&&(0,h.jsx)(H.A,{})]})},d)}const R="categoryLink_byQd",U="categoryLinkLabel_W154";function F({collapsed:e,categoryLabel:t,onClick:n}){return(0,h.jsx)("button",{"aria-label":e?(0,c.T)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:t}):(0,c.T)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:t}),"aria-expanded":!e,type:"button",className:"clean-btn menu__caret",onClick:n})}function V({label:e}){return(0,h.jsx)("span",{title:e,className:U,children:e})}function Y(e){return 0===(0,l.Y)(e.item.items,e.activePath).length?(0,h.jsx)(K,{...e}):(0,h.jsx)(z,{...e})}function K({item:e,...t}){if("string"!=typeof e.href)return null;const{type:n,collapsed:a,collapsible:i,items:s,linkUnlisted:o,...l}=e,r={type:"link",...l};return(0,h.jsx)(D,{item:r,...t})}function z({item:e,onItemClick:t,activePath:n,level:s,index:r,...c}){const{items:d,label:u,collapsible:m,className:b,href:p}=e,{docs:{sidebar:{autoCollapseCategories:x}}}=(0,_.p)(),j=function(e){const t=(0,E.A)();return(0,a.useMemo)(()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.Nr)(e):void 0,[e,t])}(e),f=(0,l.w8)(e,n),g=(0,w.ys)(p,n),{collapsed:v,setCollapsed:A}=(0,L.u)({initialState:()=>!!m&&(!f&&e.collapsed)}),{expandedItem:C,setExpandedItem:k}=function(){const e=(0,a.useContext)(I);if(e===T)throw new N.dV("DocSidebarItemsExpandedStateProvider");return e}(),S=(e=!v)=>{k(e?null:r),A(e)};!function({isActive:e,collapsed:t,updateCollapsed:n,activePath:i}){const s=(0,N.ZC)(e),o=(0,N.ZC)(i);(0,a.useEffect)(()=>{(e&&!s||e&&s&&i!==o)&&t&&n(!1)},[e,s,t,n,i,o])}({isActive:f,collapsed:v,updateCollapsed:S,activePath:n}),(0,a.useEffect)(()=>{m&&null!=C&&C!==r&&x&&A(!0)},[m,C,r,A,x]);return(0,h.jsxs)("li",{className:(0,i.A)(o.G.docs.docSidebarItemCategory,o.G.docs.docSidebarItemCategoryLevel(s),"menu__list-item",{"menu__list-item--collapsed":v},b),children:[(0,h.jsxs)("div",{className:(0,i.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g}),children:[(0,h.jsx)(B.A,{className:(0,i.A)(R,"menu__link",{"menu__link--sublist":m,"menu__link--sublist-caret":!p&&m,"menu__link--active":f}),onClick:n=>{t?.(e),m&&(p?g?(n.preventDefault(),S()):S(!1):(n.preventDefault(),S()))},"aria-current":g?"page":void 0,role:m&&!p?"button":void 0,"aria-expanded":m&&!p?!v:void 0,href:m?j??"#":j,...c,children:(0,h.jsx)(V,{label:u})}),p&&m&&(0,h.jsx)(F,{collapsed:v,categoryLabel:u,onClick:e=>{e.preventDefault(),S()}})]}),(0,h.jsx)(L.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:v,children:(0,h.jsx)(J,{items:d,tabIndex:v?-1:0,onItemClick:t,activePath:n,level:s+1})})]})}const q="menuHtmlItem_M9Kj";function O({item:e,level:t,index:n}){const{value:a,defaultStyle:s,className:l}=e;return(0,h.jsx)("li",{className:(0,i.A)(o.G.docs.docSidebarItemLink,o.G.docs.docSidebarItemLinkLevel(t),s&&[q,"menu__list-item"],l),dangerouslySetInnerHTML:{__html:a}},n)}function Q({item:e,...t}){switch(e.type){case"category":return(0,h.jsx)(Y,{item:e,...t});case"html":return(0,h.jsx)(O,{item:e,...t});default:return(0,h.jsx)(D,{item:e,...t})}}function Z({items:e,...t}){const n=(0,l.Y)(e,t.activePath);return(0,h.jsx)(y,{children:n.map((e,n)=>(0,h.jsx)(Q,{item:e,index:n,...t},n))})}const J=(0,a.memo)(Z),X="menu_SIkG",$="menuWithAnnouncementBar_GW3s";function ee({path:e,sidebar:t,className:n}){const s=function(){const{isActive:e}=(0,S.M)(),[t,n]=(0,a.useState)(e);return(0,d.Mq)(({scrollY:t})=>{e&&n(0===t)},[e]),e&&t}();return(0,h.jsx)("nav",{"aria-label":(0,c.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,i.A)("menu thin-scrollbar",X,s&&$,n),children:(0,h.jsx)("ul",{className:(0,i.A)(o.G.docs.docSidebarMenu,"menu__list"),children:(0,h.jsx)(J,{items:t,activePath:e,level:1})})})}const te="sidebar_njMd",ne="sidebarWithHideableNavbar_wUlq",ae="sidebarHidden_VK0M",ie="sidebarLogo_isFc";function se({path:e,sidebar:t,onCollapse:n,isHidden:a}){const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:o}}}=(0,_.p)();return(0,h.jsxs)("div",{className:(0,i.A)(te,s&&ne,a&&ae),children:[s&&(0,h.jsx)(g.A,{tabIndex:-1,className:ie}),(0,h.jsx)(ee,{path:e,sidebar:t}),o&&(0,h.jsx)(k,{onClick:n})]})}const oe=a.memo(se);var le=n(5600),re=n(2069);const ce=({sidebar:e,path:t})=>{const n=(0,re.M)();return(0,h.jsx)("ul",{className:(0,i.A)(o.G.docs.docSidebarMenu,"menu__list"),children:(0,h.jsx)(J,{items:e,activePath:t,onItemClick:e=>{"category"===e.type&&e.href&&n.toggle(),"link"===e.type&&n.toggle()},level:1})})};function de(e){return(0,h.jsx)(le.GX,{component:ce,props:e})}const ue=a.memo(de);function me(e){const t=(0,f.l)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,h.jsxs)(h.Fragment,{children:[n&&(0,h.jsx)(oe,{...e}),a&&(0,h.jsx)(ue,{...e})]})}const be="expandButton_TmdG",he="expandButtonIcon_i1dp";function pe({toggleSidebar:e}){return(0,h.jsx)("div",{className:be,title:(0,c.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:e,onClick:e,children:(0,h.jsx)(v,{className:he})})}const xe={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function je({children:e}){const t=(0,r.t)();return(0,h.jsx)(a.Fragment,{children:e},t?.name??"noSidebar")}function fe({sidebar:e,hiddenSidebarContainer:t,setHiddenSidebarContainer:n}){const{pathname:s}=(0,j.zy)(),[l,r]=(0,a.useState)(!1),c=(0,a.useCallback)(()=>{l&&r(!1),!l&&(0,x.O)()&&r(!0),n(e=>!e)},[n,l]);return(0,h.jsx)("aside",{className:(0,i.A)(o.G.docs.docSidebarContainer,xe.docSidebarContainer,t&&xe.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(xe.docSidebarContainer)&&t&&r(!0)},children:(0,h.jsx)(je,{children:(0,h.jsxs)("div",{className:(0,i.A)(xe.sidebarViewport,l&&xe.sidebarViewportHidden),children:[(0,h.jsx)(me,{sidebar:e,path:s,onCollapse:c,isHidden:l}),l&&(0,h.jsx)(pe,{toggleSidebar:c})]})})})}const _e={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ge({hiddenSidebarContainer:e,children:t}){const n=(0,r.t)();return(0,h.jsx)("main",{className:(0,i.A)(_e.docMainContainer,(e||!n)&&_e.docMainContainerEnhanced),children:(0,h.jsx)("div",{className:(0,i.A)("container padding-top--md padding-bottom--lg",_e.docItemWrapper,e&&_e.docItemWrapperEnhanced),children:t})})}const ve="docRoot_UBD9",Ae="docsWrapper_hBAB";function Ce({children:e}){const t=(0,r.t)(),[n,i]=(0,a.useState)(!1);return(0,h.jsxs)("div",{className:Ae,children:[(0,h.jsx)(p,{}),(0,h.jsxs)("div",{className:ve,children:[t&&(0,h.jsx)(fe,{sidebar:t.items,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}),(0,h.jsx)(ge,{hiddenSidebarContainer:n,children:e})]})]})}var ke=n(3363);function Se(e){const t=(0,l.B5)(e);if(!t)return(0,h.jsx)(ke.A,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,h.jsx)(s.e3,{className:(0,i.A)(o.G.page.docsDocPage),children:(0,h.jsx)(r.V,{name:a,items:c,children:(0,h.jsx)(Ce,{children:n})})})}}}]); \ No newline at end of file diff --git a/assets/js/a94703ab.c0ce3492.js b/assets/js/a94703ab.c0ce3492.js new file mode 100644 index 0000000..ad51433 --- /dev/null +++ b/assets/js/a94703ab.c0ce3492.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[48],{8115(e,t,n){n.r(t),n.d(t,{default:()=>Se});var a=n(6540),i=n(4164),s=n(5500),o=n(7559),l=n(4718),r=n(609),c=n(1312),d=n(3104),u=n(5062);const m="backToTopButton_sjWU",b="backToTopButtonShow_xfvO";var h=n(4848);function p(){const{shown:e,scrollToTop:t}=function({threshold:e}){const[t,n]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:o}=(0,d.gk)();return(0,d.Mq)(({scrollY:t},a)=>{const s=a?.scrollY;s&&(i.current?i.current=!1:t>=s?(o(),n(!1)):t<e?n(!1):t+window.innerHeight<document.documentElement.scrollHeight&&n(!0))}),(0,u.$)(e=>{e.location.hash&&(i.current=!0,n(!1))}),{shown:t,scrollToTop:()=>s(0)}}({threshold:300});return(0,h.jsx)("button",{"aria-label":(0,c.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,i.A)("clean-btn",o.G.common.backToTopButton,m,e&&b),type:"button",onClick:t})}var x=n(3109),j=n(6347),f=n(4581),_=n(6342),g=n(3465);function v(e){return(0,h.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,h.jsxs)("g",{fill:"#7a7a7a",children:[(0,h.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,h.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const A="collapseSidebarButton_PEFL",C="collapseSidebarButtonIcon_kv0_";function k({onClick:e}){return(0,h.jsx)("button",{type:"button",title:(0,c.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,i.A)("button button--secondary button--outline",A),onClick:e,children:(0,h.jsx)(v,{className:C})})}var S=n(5041),N=n(9532);const T=Symbol("EmptyContext"),I=a.createContext(T);function y({children:e}){const[t,n]=(0,a.useState)(null),i=(0,a.useMemo)(()=>({expandedItem:t,setExpandedItem:n}),[t]);return(0,h.jsx)(I.Provider,{value:i,children:e})}var L=n(1422),w=n(9169),B=n(8774),E=n(2303),M=n(6654),H=n(3186);const P="menuExternalLink_NmtK",G="linkLabel_WmDU";function W({label:e}){return(0,h.jsx)("span",{title:e,className:G,children:e})}function D({item:e,onItemClick:t,activePath:n,level:a,index:s,...r}){const{href:c,label:d,className:u,autoAddBaseUrl:m}=e,b=(0,l.w8)(e,n),p=(0,M.A)(c);return(0,h.jsx)("li",{className:(0,i.A)(o.G.docs.docSidebarItemLink,o.G.docs.docSidebarItemLinkLevel(a),"menu__list-item",u),children:(0,h.jsxs)(B.A,{className:(0,i.A)("menu__link",!p&&P,{"menu__link--active":b}),autoAddBaseUrl:m,"aria-current":b?"page":void 0,to:c,...p&&{onClick:t?()=>t(e):void 0},...r,children:[(0,h.jsx)(W,{label:d}),!p&&(0,h.jsx)(H.A,{})]})},d)}const R="categoryLink_byQd",U="categoryLinkLabel_W154";function F({collapsed:e,categoryLabel:t,onClick:n}){return(0,h.jsx)("button",{"aria-label":e?(0,c.T)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:t}):(0,c.T)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:t}),"aria-expanded":!e,type:"button",className:"clean-btn menu__caret",onClick:n})}function V({label:e}){return(0,h.jsx)("span",{title:e,className:U,children:e})}function Y(e){return 0===(0,l.Y)(e.item.items,e.activePath).length?(0,h.jsx)(K,{...e}):(0,h.jsx)(z,{...e})}function K({item:e,...t}){if("string"!=typeof e.href)return null;const{type:n,collapsed:a,collapsible:i,items:s,linkUnlisted:o,...l}=e,r={type:"link",...l};return(0,h.jsx)(D,{item:r,...t})}function z({item:e,onItemClick:t,activePath:n,level:s,index:r,...c}){const{items:d,label:u,collapsible:m,className:b,href:p}=e,{docs:{sidebar:{autoCollapseCategories:x}}}=(0,_.p)(),j=function(e){const t=(0,E.A)();return(0,a.useMemo)(()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.Nr)(e):void 0,[e,t])}(e),f=(0,l.w8)(e,n),g=(0,w.ys)(p,n),{collapsed:v,setCollapsed:A}=(0,L.u)({initialState:()=>!!m&&(!f&&e.collapsed)}),{expandedItem:C,setExpandedItem:k}=function(){const e=(0,a.useContext)(I);if(e===T)throw new N.dV("DocSidebarItemsExpandedStateProvider");return e}(),S=(e=!v)=>{k(e?null:r),A(e)};!function({isActive:e,collapsed:t,updateCollapsed:n,activePath:i}){const s=(0,N.ZC)(e),o=(0,N.ZC)(i);(0,a.useEffect)(()=>{(e&&!s||e&&s&&i!==o)&&t&&n(!1)},[e,s,t,n,i,o])}({isActive:f,collapsed:v,updateCollapsed:S,activePath:n}),(0,a.useEffect)(()=>{m&&null!=C&&C!==r&&x&&A(!0)},[m,C,r,A,x]);return(0,h.jsxs)("li",{className:(0,i.A)(o.G.docs.docSidebarItemCategory,o.G.docs.docSidebarItemCategoryLevel(s),"menu__list-item",{"menu__list-item--collapsed":v},b),children:[(0,h.jsxs)("div",{className:(0,i.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g}),children:[(0,h.jsx)(B.A,{className:(0,i.A)(R,"menu__link",{"menu__link--sublist":m,"menu__link--sublist-caret":!p&&m,"menu__link--active":f}),onClick:n=>{t?.(e),m&&(p?g?(n.preventDefault(),S()):S(!1):(n.preventDefault(),S()))},"aria-current":g?"page":void 0,role:m&&!p?"button":void 0,"aria-expanded":m&&!p?!v:void 0,href:m?j??"#":j,...c,children:(0,h.jsx)(V,{label:u})}),p&&m&&(0,h.jsx)(F,{collapsed:v,categoryLabel:u,onClick:e=>{e.preventDefault(),S()}})]}),(0,h.jsx)(L.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:v,children:(0,h.jsx)(J,{items:d,tabIndex:v?-1:0,onItemClick:t,activePath:n,level:s+1})})]})}const q="menuHtmlItem_M9Kj";function O({item:e,level:t,index:n}){const{value:a,defaultStyle:s,className:l}=e;return(0,h.jsx)("li",{className:(0,i.A)(o.G.docs.docSidebarItemLink,o.G.docs.docSidebarItemLinkLevel(t),s&&[q,"menu__list-item"],l),dangerouslySetInnerHTML:{__html:a}},n)}function Q({item:e,...t}){switch(e.type){case"category":return(0,h.jsx)(Y,{item:e,...t});case"html":return(0,h.jsx)(O,{item:e,...t});default:return(0,h.jsx)(D,{item:e,...t})}}function Z({items:e,...t}){const n=(0,l.Y)(e,t.activePath);return(0,h.jsx)(y,{children:n.map((e,n)=>(0,h.jsx)(Q,{item:e,index:n,...t},n))})}const J=(0,a.memo)(Z),X="menu_SIkG",$="menuWithAnnouncementBar_GW3s";function ee({path:e,sidebar:t,className:n}){const s=function(){const{isActive:e}=(0,S.M)(),[t,n]=(0,a.useState)(e);return(0,d.Mq)(({scrollY:t})=>{e&&n(0===t)},[e]),e&&t}();return(0,h.jsx)("nav",{"aria-label":(0,c.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,i.A)("menu thin-scrollbar",X,s&&$,n),children:(0,h.jsx)("ul",{className:(0,i.A)(o.G.docs.docSidebarMenu,"menu__list"),children:(0,h.jsx)(J,{items:t,activePath:e,level:1})})})}const te="sidebar_njMd",ne="sidebarWithHideableNavbar_wUlq",ae="sidebarHidden_VK0M",ie="sidebarLogo_isFc";function se({path:e,sidebar:t,onCollapse:n,isHidden:a}){const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:o}}}=(0,_.p)();return(0,h.jsxs)("div",{className:(0,i.A)(te,s&&ne,a&&ae),children:[s&&(0,h.jsx)(g.A,{tabIndex:-1,className:ie}),(0,h.jsx)(ee,{path:e,sidebar:t}),o&&(0,h.jsx)(k,{onClick:n})]})}const oe=a.memo(se);var le=n(5600),re=n(2069);const ce=({sidebar:e,path:t})=>{const n=(0,re.M)();return(0,h.jsx)("ul",{className:(0,i.A)(o.G.docs.docSidebarMenu,"menu__list"),children:(0,h.jsx)(J,{items:e,activePath:t,onItemClick:e=>{"category"===e.type&&e.href&&n.toggle(),"link"===e.type&&n.toggle()},level:1})})};function de(e){return(0,h.jsx)(le.GX,{component:ce,props:e})}const ue=a.memo(de);function me(e){const t=(0,f.l)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,h.jsxs)(h.Fragment,{children:[n&&(0,h.jsx)(oe,{...e}),a&&(0,h.jsx)(ue,{...e})]})}const be="expandButton_TmdG",he="expandButtonIcon_i1dp";function pe({toggleSidebar:e}){return(0,h.jsx)("div",{className:be,title:(0,c.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:e,onClick:e,children:(0,h.jsx)(v,{className:he})})}const xe={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function je({children:e}){const t=(0,r.t)();return(0,h.jsx)(a.Fragment,{children:e},t?.name??"noSidebar")}function fe({sidebar:e,hiddenSidebarContainer:t,setHiddenSidebarContainer:n}){const{pathname:s}=(0,j.zy)(),[l,r]=(0,a.useState)(!1),c=(0,a.useCallback)(()=>{l&&r(!1),!l&&(0,x.O)()&&r(!0),n(e=>!e)},[n,l]);return(0,h.jsx)("aside",{className:(0,i.A)(o.G.docs.docSidebarContainer,xe.docSidebarContainer,t&&xe.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(xe.docSidebarContainer)&&t&&r(!0)},children:(0,h.jsx)(je,{children:(0,h.jsxs)("div",{className:(0,i.A)(xe.sidebarViewport,l&&xe.sidebarViewportHidden),children:[(0,h.jsx)(me,{sidebar:e,path:s,onCollapse:c,isHidden:l}),l&&(0,h.jsx)(pe,{toggleSidebar:c})]})})})}const _e={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ge({hiddenSidebarContainer:e,children:t}){const n=(0,r.t)();return(0,h.jsx)("main",{className:(0,i.A)(_e.docMainContainer,(e||!n)&&_e.docMainContainerEnhanced),children:(0,h.jsx)("div",{className:(0,i.A)("container padding-top--md padding-bottom--lg",_e.docItemWrapper,e&&_e.docItemWrapperEnhanced),children:t})})}const ve="docRoot_UBD9",Ae="docsWrapper_hBAB";function Ce({children:e}){const t=(0,r.t)(),[n,i]=(0,a.useState)(!1);return(0,h.jsxs)("div",{className:Ae,children:[(0,h.jsx)(p,{}),(0,h.jsxs)("div",{className:ve,children:[t&&(0,h.jsx)(fe,{sidebar:t.items,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}),(0,h.jsx)(ge,{hiddenSidebarContainer:n,children:e})]})]})}var ke=n(3363);function Se(e){const t=(0,l.B5)(e);if(!t)return(0,h.jsx)(ke.A,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,h.jsx)(s.e3,{className:(0,i.A)(o.G.page.docsDocPage),children:(0,h.jsx)(r.V,{name:a,items:c,children:(0,h.jsx)(Ce,{children:n})})})}},3363(e,t,n){n.d(t,{A:()=>l});n(6540);var a=n(4164),i=n(1312),s=n(1107),o=n(4848);function l({className:e}){return(0,o.jsx)("main",{className:(0,a.A)("container margin-vert--xl",e),children:(0,o.jsx)("div",{className:"row",children:(0,o.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,o.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,o.jsx)(i.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,o.jsx)("p",{children:(0,o.jsx)(i.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,o.jsx)("p",{children:(0,o.jsx)(i.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/assets/js/de715384.f1197b74.js b/assets/js/de715384.f1197b74.js deleted file mode 100644 index 444437a..0000000 --- a/assets/js/de715384.f1197b74.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[746],{7921(e,n,s){s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>i,default:()=>p,frontMatter:()=>l,metadata:()=>t,toc:()=>c});const t=JSON.parse('{"id":"reference/examples","title":"Example Tools","description":"CmdForge comes with 28 pre-built tools. This document shows their configurations and usage.","source":"@site/docs/reference/examples.md","sourceDirName":"reference","slug":"/reference/examples","permalink":"/rob/CmdForge/reference/examples","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":4,"frontMatter":{"sidebar_label":"Example Tools","sidebar_position":4,"format":"md"},"sidebar":"docs","previous":{"title":"Collections","permalink":"/rob/CmdForge/reference/collections"},"next":{"title":"Design Philosophy","permalink":"/rob/CmdForge/reference/design"}}');var r=s(4848),a=s(8453);const l={sidebar_label:"Example Tools",sidebar_position:4,format:"md"},i="Example Tools",o={},c=[{value:"Quick Install",id:"quick-install",level:2},{value:"Text Processing Tools",id:"text-processing-tools",level:2},{value:"summarize",id:"summarize",level:3},{value:"translate",id:"translate",level:3},{value:"fix-grammar",id:"fix-grammar",level:3},{value:"simplify",id:"simplify",level:3},{value:"tone-shift",id:"tone-shift",level:3},{value:"eli5",id:"eli5",level:3},{value:"tldr",id:"tldr",level:3},{value:"expand",id:"expand",level:3},{value:"Developer Tools",id:"developer-tools",level:2},{value:"explain-error",id:"explain-error",level:3},{value:"explain-code",id:"explain-code",level:3},{value:"review-code",id:"review-code",level:3},{value:"gen-tests",id:"gen-tests",level:3},{value:"docstring",id:"docstring",level:3},{value:"commit-msg",id:"commit-msg",level:3},{value:"Data Tools",id:"data-tools",level:2},{value:"json-extract",id:"json-extract",level:3},{value:"sql-from-text",id:"sql-from-text",level:3},{value:"Advanced Multi-Step Tools",id:"advanced-multi-step-tools",level:2},{value:"log-errors",id:"log-errors",level:3},{value:"diff-focus",id:"diff-focus",level:3},{value:"Pipeline Recipes",id:"pipeline-recipes",level:2},{value:"Development Workflows",id:"development-workflows",level:3},{value:"Data Processing",id:"data-processing",level:3},{value:"Text Processing Pipelines",id:"text-processing-pipelines",level:3},{value:"Shell Functions",id:"shell-functions",level:3}];function d(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",p:"p",pre:"pre",strong:"strong",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"example-tools",children:"Example Tools"})}),"\n",(0,r.jsx)(n.p,{children:"CmdForge comes with 28 pre-built tools. This document shows their configurations and usage."}),"\n",(0,r.jsx)(n.h2,{id:"quick-install",children:"Quick Install"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Install all example tools (from the CmdForge directory)\npython examples/install.py\ncmdforge refresh\n\n# Or install from anywhere\ncurl -sSL https://gitea.brrd.tech/rob/cmdforge/raw/branch/main/examples/install.py | python3\n"})}),"\n",(0,r.jsx)(n.h2,{id:"text-processing-tools",children:"Text Processing Tools"}),"\n",(0,r.jsx)(n.h3,{id:"summarize",children:"summarize"}),"\n",(0,r.jsx)(n.p,{children:"Condense long documents to key points."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: summarize\ndescription: Condense long documents to key points\narguments:\n - flag: --length\n variable: length\n default: "3-5 bullet points"\nsteps:\n - type: prompt\n prompt: |\n Summarize the following text into \\{length\\}. Be concise and capture the key points:\n\n \\{input\\}\n provider: opencode-pickle\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat article.txt | summarize\ncat book.txt | summarize --length "10 bullet points"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"translate",children:"translate"}),"\n",(0,r.jsx)(n.p,{children:"Translate text to any language."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: translate\ndescription: Translate text to any language\narguments:\n - flag: --lang\n variable: lang\n default: Spanish\nsteps:\n - type: prompt\n prompt: |\n Translate the following text to \\{lang\\}. Only output the translation, nothing else:\n\n \\{input\\}\n provider: claude-haiku\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'echo "Hello, world!" | translate --lang French\ncat readme.md | translate --lang Japanese\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"fix-grammar",children:"fix-grammar"}),"\n",(0,r.jsx)(n.p,{children:"Fix grammar and spelling errors."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: fix-grammar\ndescription: Fix grammar and spelling errors\narguments: []\nsteps:\n - type: prompt\n prompt: |\n Fix all grammar, spelling, and punctuation errors in the following text. Only output the corrected text, no explanations:\n\n \\{input\\}\n provider: opencode-deepseek\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'echo "teh cat sat on teh mat" | fix-grammar\ncat draft.txt | fix-grammar > fixed.txt\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"simplify",children:"simplify"}),"\n",(0,r.jsx)(n.p,{children:"Rewrite text for easier understanding."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: simplify\ndescription: Rewrite text for easier understanding\narguments:\n - flag: --level\n variable: level\n default: "5th grade reading level"\nsteps:\n - type: prompt\n prompt: |\n Rewrite the following text for a \\{level\\}. Keep the meaning but use simpler words and shorter sentences:\n\n \\{input\\}\n provider: opencode-pickle\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat legal_document.txt | simplify\ncat technical.md | simplify --level "non-technical reader"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"tone-shift",children:"tone-shift"}),"\n",(0,r.jsx)(n.p,{children:"Change the tone of text."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: tone-shift\ndescription: Change the tone of text\narguments:\n - flag: --tone\n variable: tone\n default: professional\nsteps:\n - type: prompt\n prompt: |\n Rewrite the following text in a \\{tone\\} tone. Keep the core message but adjust the style:\n\n \\{input\\}\n provider: opencode-deepseek\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat angry_email.txt | tone-shift --tone "calm and professional"\ncat casual_note.txt | tone-shift --tone formal\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"eli5",children:"eli5"}),"\n",(0,r.jsx)(n.p,{children:"Explain like I'm 5."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: eli5\ndescription: Explain like I'm 5\narguments: []\nsteps:\n - type: prompt\n prompt: |\n Explain this like I'm 5 years old. Use simple words and fun analogies:\n\n \\{input\\}\n provider: opencode-pickle\n output_var: response\noutput: \"\\{response\\}\"\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'echo "What is quantum computing?" | eli5\ncat whitepaper.txt | eli5\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"tldr",children:"tldr"}),"\n",(0,r.jsx)(n.p,{children:"One-line summary."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: tldr\ndescription: One-line summary\narguments: []\nsteps:\n - type: prompt\n prompt: |\n Give a one-line TL;DR summary of this text:\n\n \\{input\\}\n provider: opencode-grok\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cat long_article.txt | tldr\ncurl -s https://example.com | tldr\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"expand",children:"expand"}),"\n",(0,r.jsx)(n.p,{children:"Expand bullet points to paragraphs."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: expand\ndescription: Expand bullet points to paragraphs\narguments: []\nsteps:\n - type: prompt\n prompt: |\n Expand these bullet points into well-written paragraphs:\n\n \\{input\\}\n provider: opencode-pickle\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat notes.txt | expand\necho "- Fast\\n- Reliable\\n- Easy to use" | expand\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"developer-tools",children:"Developer Tools"}),"\n",(0,r.jsx)(n.h3,{id:"explain-error",children:"explain-error"}),"\n",(0,r.jsx)(n.p,{children:"Explain error messages and stack traces."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: explain-error\ndescription: Explain error messages and stack traces\narguments: []\nsteps:\n - type: prompt\n prompt: |\n Explain this error/stack trace in plain English. What went wrong and how to fix it:\n\n \\{input\\}\n provider: claude-haiku\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cat error.log | explain-error\npython script.py 2>&1 | explain-error\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"explain-code",children:"explain-code"}),"\n",(0,r.jsx)(n.p,{children:"Explain what code does."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: explain-code\ndescription: Explain what code does\narguments:\n - flag: --detail\n variable: detail\n default: moderate\nsteps:\n - type: prompt\n prompt: |\n Explain what this code does at a \\{detail\\} level of detail:\n\n"})}),"\n",(0,r.jsx)(n.p,{children:"{input}"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'provider: opencode-pickle\noutput_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat script.py | explain-code\ncat complex.js | explain-code --detail "very detailed"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"review-code",children:"review-code"}),"\n",(0,r.jsx)(n.p,{children:"Quick code review with suggestions."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: review-code\ndescription: Quick code review with suggestions\narguments:\n - flag: --focus\n variable: focus\n default: "bugs, security, and improvements"\nsteps:\n - type: prompt\n prompt: |\n Review this code focusing on \\{focus\\}. Be concise and actionable:\n\n'})}),"\n",(0,r.jsx)(n.p,{children:"{input}"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'provider: claude-sonnet\noutput_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat pull_request.diff | review-code\ncat auth.py | review-code --focus "security vulnerabilities"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"gen-tests",children:"gen-tests"}),"\n",(0,r.jsx)(n.p,{children:"Generate unit tests for code."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: gen-tests\ndescription: Generate unit tests for code\narguments:\n - flag: --framework\n variable: framework\n default: pytest\nsteps:\n - type: prompt\n prompt: |\n Generate comprehensive unit tests for this code using \\{framework\\}. Include edge cases:\n\n"})}),"\n",(0,r.jsx)(n.p,{children:"{input}"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'provider: claude-haiku\noutput_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cat utils.py | gen-tests\ncat api.js | gen-tests --framework jest\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"docstring",children:"docstring"}),"\n",(0,r.jsx)(n.p,{children:"Add docstrings to functions/classes."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: docstring\ndescription: Add docstrings to functions/classes\narguments:\n - flag: --style\n variable: style\n default: Google style\nsteps:\n - type: prompt\n prompt: |\n Add \\{style\\} docstrings to all functions and classes in this code. Output the complete code with docstrings:\n\n"})}),"\n",(0,r.jsx)(n.p,{children:"{input}"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:'provider: opencode-deepseek\noutput_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'cat module.py | docstring\ncat functions.py | docstring --style "NumPy style"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"commit-msg",children:"commit-msg"}),"\n",(0,r.jsx)(n.p,{children:"Generate commit message from diff."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: commit-msg\ndescription: Generate commit message from diff\narguments:\n - flag: --style\n variable: style\n default: conventional commits\nsteps:\n - type: prompt\n prompt: |\n Generate a concise \\{style\\} commit message for this diff. Just the message, no explanation:\n\n \\{input\\}\n provider: opencode-pickle\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'git diff --staged | commit-msg\ngit diff HEAD~1 | commit-msg --style "simple"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"data-tools",children:"Data Tools"}),"\n",(0,r.jsx)(n.h3,{id:"json-extract",children:"json-extract"}),"\n",(0,r.jsx)(n.p,{children:"Extract structured data as validated JSON."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: json-extract\ndescription: Extract structured data as validated JSON\narguments:\n - flag: --fields\n variable: fields\n default: any relevant fields\nsteps:\n - type: prompt\n prompt: |\n Extract \\{fields\\} from this text as a JSON object. Output ONLY valid JSON, no markdown, no explanation:\n\n \\{input\\}\n provider: opencode-deepseek\n output_var: raw_json\n - type: code\n code: |\n import json\n import re\n text = raw_json.strip()\n text = re.sub(r'^```json?\\s*', '', text)\n text = re.sub(r'\\s*```$', '', text)\n try:\n parsed = json.loads(text)\n validated = json.dumps(parsed, indent=2)\n except json.JSONDecodeError as e:\n validated = f\"ERROR: Invalid JSON - {e}\\nRaw output: {text[:500]}\"\n output_var: validated\noutput: \"\\{validated\\}\"\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'echo "Price $49.99, SKU ABC-123" | json-extract --fields "price, sku"\ncat invoice.txt | json-extract --fields "total, date, items"\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"sql-from-text",children:"sql-from-text"}),"\n",(0,r.jsx)(n.p,{children:"Generate SQL from natural language."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'name: sql-from-text\ndescription: Generate SQL from natural language\narguments:\n - flag: --dialect\n variable: dialect\n default: PostgreSQL\nsteps:\n - type: prompt\n prompt: |\n Generate a \\{dialect\\} SQL query for this request. Output only the SQL, no explanation:\n\n \\{input\\}\n provider: claude-haiku\n output_var: response\noutput: "\\{response\\}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'echo "get all users who signed up last month" | sql-from-text\necho "count orders by status" | sql-from-text --dialect MySQL\n'})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"advanced-multi-step-tools",children:"Advanced Multi-Step Tools"}),"\n",(0,r.jsx)(n.h3,{id:"log-errors",children:"log-errors"}),"\n",(0,r.jsx)(n.p,{children:"Extract and explain errors from large log files."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: log-errors\ndescription: Extract and explain errors from large log files\narguments: []\nsteps:\n - type: code\n code: |\n import re\n lines = input.split('\\n')\n result = []\n for i, line in enumerate(lines):\n if re.search(r'\\b(ERROR|CRITICAL|FATAL|Exception|Traceback)\\b', line, re.I):\n result.extend(lines[i:i+5])\n extracted = '\\n'.join(result[:200])\n output_var: extracted\n - type: prompt\n prompt: |\n Analyze these error log entries. Group by error type, explain likely causes, and suggest fixes:\n\n \\{extracted\\}\n provider: claude-haiku\n output_var: response\noutput: \"\\{response\\}\"\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cat huge_app.log | log-errors\nzcat archived.log.gz | log-errors\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"diff-focus",children:"diff-focus"}),"\n",(0,r.jsx)(n.p,{children:"Review only the added/changed code in a diff."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"name: diff-focus\ndescription: Review only the added/changed code in a diff\narguments: []\nsteps:\n - type: code\n code: |\n lines = input.split('\\n')\n result = []\n for i, line in enumerate(lines):\n if line.startswith('@@') or line.startswith('+++') or line.startswith('---'):\n result.append(line)\n elif line.startswith('+') and not line.startswith('+++'):\n result.append(line)\n extracted = '\\n'.join(result)\n output_var: extracted\n - type: prompt\n prompt: |\n Review these added lines of code. Focus on bugs, security issues, and improvements:\n\n \\{extracted\\}\n provider: claude-haiku\n output_var: response\noutput: \"\\{response\\}\"\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Usage:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"git diff | diff-focus\ngit diff HEAD~5 | diff-focus\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{id:"pipeline-recipes",children:"Pipeline Recipes"}),"\n",(0,r.jsx)(n.p,{children:"CmdForge tools chain together like Unix commands:"}),"\n",(0,r.jsx)(n.h3,{id:"development-workflows",children:"Development Workflows"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# Quick PR review: extract changes, review, summarize\ngit diff main | diff-focus | review-code --focus \"bugs and security\" | tldr\n\n# Explain and fix an error in one pipeline\npython script.py 2>&1 | explain-error | tee error_analysis.txt\n\n# Generate tests for changed files only\ngit diff --name-only | grep '\\.py$' | xargs cat | gen-tests > new_tests.py\n\n# Create release notes from commits\ngit log v1.0..v1.1 --oneline | changelog | translate --lang French > RELEASE_FR.md\n"})}),"\n",(0,r.jsx)(n.h3,{id:"data-processing",children:"Data Processing"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Extract, transform, analyze\ncurl -s api.example.com/data | json-extract --fields "users, revenue" | json2csv | csv-insights\n\n# Process multiple files\nfor f in reports/*.txt; do\n cat "$f" | json-extract --fields "total, date"\ndone | json2csv > summary.csv\n'})}),"\n",(0,r.jsx)(n.h3,{id:"text-processing-pipelines",children:"Text Processing Pipelines"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Translate technical docs for international team\ncat API.md | simplify --level "non-technical" | translate --lang Spanish > API_ES.md\n\n# Process customer feedback\ncat feedback.txt | summarize --length "10 points" | tone-shift --tone analytical\n'})}),"\n",(0,r.jsx)(n.h3,{id:"shell-functions",children:"Shell Functions"}),"\n",(0,r.jsxs)(n.p,{children:["Add to ",(0,r.jsx)(n.code,{children:"~/.bashrc"})," for common workflows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'# Review recent changes\nreview-recent() {\n git diff HEAD~"${1:-1}" | diff-focus | review-code | tldr\n}\n\n# Quick translate with summary\ntranslate-summary() {\n cat "$1" | summarize | translate --lang "${2:-Spanish}"\n}\n\n# Generate commit message and commit\nauto-commit() {\n msg=$(git diff --staged | commit-msg)\n echo "Commit message: $msg"\n read -p "Commit? [y/N] " confirm\n [[ $confirm == [yY] ]] && git commit -m "$msg"\n}\n'})})]})}function p(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},8453(e,n,s){s.d(n,{R:()=>l,x:()=>i});var t=s(6540);const r={},a=t.createContext(r);function l(e){const n=t.useContext(a);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e719f3dc.5bfd6599.js b/assets/js/e719f3dc.5bfd6599.js new file mode 100644 index 0000000..cf35540 --- /dev/null +++ b/assets/js/e719f3dc.5bfd6599.js @@ -0,0 +1 @@ +"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[207],{7271(e,i,t){t.r(i),t.d(i,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>l,metadata:()=>n,toc:()=>d});const n=JSON.parse('{"id":"ideas-and-exploration","title":"Ideas & Exploration","description":"Completed","source":"@site/docs/ideas-and-exploration.md","sourceDirName":".","slug":"/ideas-and-exploration","permalink":"/rob/CmdForge/ideas-and-exploration","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"ideas","project":"cmdforge","updated":"2026-07-19T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"Goals","permalink":"/rob/CmdForge/goals"},"next":{"title":"Milestones","permalink":"/rob/CmdForge/milestones"}}');var s=t(4848),o=t(8453);const l={type:"ideas",project:"cmdforge",updated:new Date("2026-07-19T00:00:00.000Z")},a="Ideas & Exploration",c={},d=[{value:"Completed",id:"completed",level:2},{value:"Future Ideas",id:"future-ideas",level:2},{value:"Live evaluation",id:"live-evaluation",level:3},{value:"Parallel step execution",id:"parallel-step-execution",level:3},{value:"Contract-driven composition",id:"contract-driven-composition",level:3},{value:"Conditional routing",id:"conditional-routing",level:3},{value:"Issue-based improvement loop",id:"issue-based-improvement-loop",level:3},{value:"Natural language tool creation #medium",id:"natural-language-tool-creation-medium",level:3},{value:"VS Code extension #low",id:"vs-code-extension-low",level:3},{value:"Tool usage analytics #low",id:"tool-usage-analytics-low",level:3},{value:"Plugin architecture design #medium",id:"plugin-architecture-design-medium",level:3},{value:"Mobile companion app #low",id:"mobile-companion-app-low",level:3}];function r(e){const i={code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",input:"input",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.header,{children:(0,s.jsx)(i.h1,{id:"ideas--exploration",children:"Ideas & Exploration"})}),"\n",(0,s.jsx)(i.h2,{id:"completed",children:"Completed"}),"\n",(0,s.jsxs)(i.ul,{className:"contains-task-list",children:["\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool marketplace design #medium"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool search and filtering #medium"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","User tool ratings/reviews #low"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool composition and chaining #medium"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool testing framework #medium"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Provider auto-detection #low"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool templates/scaffolding (wizards + guided creation) #medium"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","MCP client + server integration"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Agent Skills standard (SKILL.md + per-provider skills)"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool contracts (input_schema / output_schema)"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Deterministic contract conformance testing"]}),"\n",(0,s.jsxs)(i.li,{className:"task-list-item",children:[(0,s.jsx)(i.input,{type:"checkbox",checked:!0,disabled:!0})," ","Registry-aware cf picker"]}),"\n"]}),"\n",(0,s.jsx)(i.h2,{id:"future-ideas",children:"Future Ideas"}),"\n",(0,s.jsx)(i.h3,{id:"live-evaluation",children:"Live evaluation"}),"\n",(0,s.jsx)(i.p,{children:"Run a tool with multiple real providers and compare outputs. Feed results into\nthe quality scoring engine. Tells users which provider works best for each\ntool."}),"\n",(0,s.jsx)(i.h3,{id:"parallel-step-execution",children:"Parallel step execution"}),"\n",(0,s.jsx)(i.p,{children:"Run independent steps concurrently. The contract system knows which steps\ndepend on which variables \u2014 auto-parallelize to cut wall-clock time."}),"\n",(0,s.jsx)(i.h3,{id:"contract-driven-composition",children:"Contract-driven composition"}),"\n",(0,s.jsx)(i.p,{children:"When building a tool, suggest downstream tools whose input contracts match the\ncurrent tool's output contract. Surface compatible tools from local and\nregistry."}),"\n",(0,s.jsx)(i.h3,{id:"conditional-routing",children:"Conditional routing"}),"\n",(0,s.jsx)(i.p,{children:'Declarative step routing based on output properties (e.g., "if confidence is\nlow, retry with a more capable provider") without writing Python logic.'}),"\n",(0,s.jsx)(i.h3,{id:"issue-based-improvement-loop",children:"Issue-based improvement loop"}),"\n",(0,s.jsxs)(i.p,{children:[(0,s.jsx)(i.code,{children:'cf --issue "description"'})," captures tool name, version, input size, execution\ntime, and error output into ",(0,s.jsx)(i.code,{children:"~/.cmdforge/<tool>/issues/"}),". The improvement\nengine (M9.2) correlates issues with scrutiny findings and suggests specific\nfixes. Reviewable via ",(0,s.jsx)(i.code,{children:"cmdforge review <tool>"}),"."]}),"\n",(0,s.jsx)(i.h3,{id:"natural-language-tool-creation-medium",children:"Natural language tool creation #medium"}),"\n",(0,s.jsx)(i.h3,{id:"vs-code-extension-low",children:"VS Code extension #low"}),"\n",(0,s.jsx)(i.h3,{id:"tool-usage-analytics-low",children:"Tool usage analytics #low"}),"\n",(0,s.jsx)(i.h3,{id:"plugin-architecture-design-medium",children:"Plugin architecture design #medium"}),"\n",(0,s.jsx)(i.h3,{id:"mobile-companion-app-low",children:"Mobile companion app #low"})]})}function u(e={}){const{wrapper:i}={...(0,o.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(r,{...e})}):r(e)}},8453(e,i,t){t.d(i,{R:()=>l,x:()=>a});var n=t(6540);const s={},o=n.createContext(s);function l(e){const i=n.useContext(o);return n.useMemo(function(){return"function"==typeof e?e(i):{...i,...e}},[i,e])}function a(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),n.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e719f3dc.de2c390f.js b/assets/js/e719f3dc.de2c390f.js deleted file mode 100644 index 4f84f50..0000000 --- a/assets/js/e719f3dc.de2c390f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[207],{7271(e,s,t){t.r(s),t.d(s,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"ideas-and-exploration","title":"Ideas & Exploration","description":"Completed","source":"@site/docs/ideas-and-exploration.md","sourceDirName":".","slug":"/ideas-and-exploration","permalink":"/rob/CmdForge/ideas-and-exploration","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"type":"ideas","project":"cmdforge","updated":"2026-01-17T00:00:00.000Z"},"sidebar":"docs","previous":{"title":"Goals","permalink":"/rob/CmdForge/goals"},"next":{"title":"Milestones","permalink":"/rob/CmdForge/milestones"}}');var n=t(4848),l=t(8453);const a={type:"ideas",project:"cmdforge",updated:new Date("2026-01-17T00:00:00.000Z")},o="Ideas & Exploration",c={},d=[{value:"Completed",id:"completed",level:2},{value:"Ideas",id:"ideas",level:2}];function r(e){const s={h1:"h1",h2:"h2",header:"header",input:"input",li:"li",ul:"ul",...(0,l.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.header,{children:(0,n.jsx)(s.h1,{id:"ideas--exploration",children:"Ideas & Exploration"})}),"\n",(0,n.jsx)(s.h2,{id:"completed",children:"Completed"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool marketplace design #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool search and filtering #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","User tool ratings/reviews #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool composition and chaining #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",checked:!0,disabled:!0})," ","Tool testing framework #medium"]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:"ideas",children:"Ideas"}),"\n",(0,n.jsxs)(s.ul,{className:"contains-task-list",children:["\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Tool usage analytics #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Plugin architecture design #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Custom AI backend support #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","VS Code extension #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Provider auto-detection #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Mobile companion app #low"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Tool templates/scaffolding #medium"]}),"\n",(0,n.jsxs)(s.li,{className:"task-list-item",children:[(0,n.jsx)(s.input,{type:"checkbox",disabled:!0})," ","Natural language tool creation #medium"]}),"\n"]})]})}function p(e={}){const{wrapper:s}={...(0,l.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(r,{...e})}):r(e)}},8453(e,s,t){t.d(s,{R:()=>a,x:()=>o});var i=t(6540);const n={},l=i.createContext(n);function a(e){const s=i.useContext(l);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function o(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:a(e.components),i.createElement(l.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/edbf8f3a.fe76e489.js b/assets/js/edbf8f3a.fe76e489.js deleted file mode 100644 index 1dd3d7a..0000000 --- a/assets/js/edbf8f3a.fe76e489.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[838],{834(e,n,i){i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>h,frontMatter:()=>t,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"reference/web-ui-spec","title":"CmdForge Web UI Design","description":"Purpose","source":"@site/docs/reference/web-ui-spec.md","sourceDirName":"reference","slug":"/reference/web-ui-spec","permalink":"/rob/CmdForge/reference/web-ui-spec","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":6,"frontMatter":{"sidebar_label":"Web UI Design","sidebar_position":6,"format":"md"},"sidebar":"docs","previous":{"title":"Design Philosophy","permalink":"/rob/CmdForge/reference/design"},"next":{"title":"CmdForge TODOs","permalink":"/rob/CmdForge/todos"}}');var l=i(4848),r=i(8453);const t={sidebar_label:"Web UI Design",sidebar_position:6,format:"md"},d="CmdForge Web UI Design",o={},c=[{value:"Purpose",id:"purpose",level:2},{value:"Mission Alignment",id:"mission-alignment",level:2},{value:"Guiding Principles",id:"guiding-principles",level:2},{value:"Information Architecture",id:"information-architecture",level:2},{value:"Visual Design System",id:"visual-design-system",level:2},{value:"Color Palette",id:"color-palette",level:3},{value:"Typography",id:"typography",level:3},{value:"Spacing System",id:"spacing-system",level:3},{value:"Border Radius",id:"border-radius",level:3},{value:"Shadow System",id:"shadow-system",level:3},{value:"Page Requirements",id:"page-requirements",level:2},{value:"Landing Page (<code>/</code>)",id:"landing-page-",level:3},{value:"Section 1: Hero (Above the Fold)",id:"section-1-hero-above-the-fold",level:4},{value:"Section 2: Three Pillars (Why CmdForge?)",id:"section-2-three-pillars-why-cmdforge",level:4},{value:"Section 3: Featured Tools & Projects",id:"section-3-featured-tools--projects",level:4},{value:"Section 4: Getting Started",id:"section-4-getting-started",level:4},{value:"Section 5: Featured Contributor",id:"section-5-featured-contributor",level:4},{value:"Section 6: Footer Ad Zone (Optional)",id:"section-6-footer-ad-zone-optional",level:4},{value:"Section 7: Footer",id:"section-7-footer",level:4},{value:"Docs/Tutorials Pages (<code>/docs/*</code>, <code>/tutorials/*</code>)",id:"docstutorials-pages-docs-tutorials",level:3},{value:"Tool Detail Page (<code>/tools/{owner}/{name}</code>)",id:"tool-detail-page-toolsownername",level:3},{value:"Registry Browse Page (<code>/tools</code>)",id:"registry-browse-page-tools",level:3},{value:"Publisher Dashboard (<code>/dashboard</code>)",id:"publisher-dashboard-dashboard",level:3},{value:"Donate Page (<code>/donate</code>)",id:"donate-page-donate",level:3},{value:"Component Library",id:"component-library",level:2},{value:"Buttons",id:"buttons",level:3},{value:"Cards",id:"cards",level:3},{value:"Navigation",id:"navigation",level:3},{value:"Form Elements",id:"form-elements",level:3},{value:"Badges and Tags",id:"badges-and-tags",level:3},{value:"Code Blocks",id:"code-blocks",level:3},{value:"Callout Boxes",id:"callout-boxes",level:3},{value:"Loading States",id:"loading-states",level:3},{value:"Responsive Design",id:"responsive-design",level:2},{value:"Breakpoints",id:"breakpoints",level:3},{value:"Layout Adaptations",id:"layout-adaptations",level:3},{value:"Touch Targets",id:"touch-targets",level:3},{value:"Mobile-Specific Considerations",id:"mobile-specific-considerations",level:3},{value:"Performance Budgets",id:"performance-budgets",level:2},{value:"Core Web Vitals Targets",id:"core-web-vitals-targets",level:3},{value:"Resource Budgets",id:"resource-budgets",level:3},{value:"Loading Strategy",id:"loading-strategy",level:3},{value:"Caching Strategy",id:"caching-strategy",level:3},{value:"Performance Monitoring",id:"performance-monitoring",level:3},{value:"Error States and Fallbacks",id:"error-states-and-fallbacks",level:2},{value:"Network Errors",id:"network-errors",level:3},{value:"Tool Not Found (404):",id:"tool-not-found-404",level:3},{value:"Search No Results:",id:"search-no-results",level:3},{value:"Offline Mode",id:"offline-mode",level:3},{value:"Form Errors",id:"form-errors",level:3},{value:"Ad and Revenue Strategy",id:"ad-and-revenue-strategy",level:2},{value:"Monetization Extensions (Optional)",id:"monetization-extensions-optional",level:2},{value:"Data and Governance",id:"data-and-governance",level:2},{value:"Privacy and Consent",id:"privacy-and-consent",level:2},{value:"UX and Accessibility",id:"ux-and-accessibility",level:2},{value:"Tech Stack (Phase 7 Target)",id:"tech-stack-phase-7-target",level:2},{value:"Auth and Session Model",id:"auth-and-session-model",level:2},{value:"API Surfaces for Web UI",id:"api-surfaces-for-web-ui",level:2},{value:"Payments and Donations (Optional)",id:"payments-and-donations-optional",level:2},{value:"Moderation and Abuse Reporting",id:"moderation-and-abuse-reporting",level:2},{value:"Media and Asset Handling",id:"media-and-asset-handling",level:2},{value:"Caching and SEO Serving",id:"caching-and-seo-serving",level:2},{value:"SEO Strategy",id:"seo-strategy",level:2},{value:"Technical SEO",id:"technical-seo",level:3},{value:"Structured Data (Schema.org)",id:"structured-data-schemaorg",level:3},{value:"Open Graph & Social Sharing",id:"open-graph--social-sharing",level:3},{value:"Sitemap",id:"sitemap",level:3},{value:"robots.txt",id:"robotstxt",level:3},{value:"Canonical URLs",id:"canonical-urls",level:3},{value:"Performance for SEO",id:"performance-for-seo",level:3},{value:"Content Strategy",id:"content-strategy",level:2},{value:"Risks and Mitigations",id:"risks-and-mitigations",level:2},{value:"Phase 7 Implementation Checklist",id:"phase-7-implementation-checklist",level:2},{value:"7.1 Foundation & Setup",id:"71-foundation--setup",level:3},{value:"7.2 Core Templates & Components",id:"72-core-templates--components",level:3},{value:"7.3 Landing Page",id:"73-landing-page",level:3},{value:"7.4 Registry Pages (Ad-Free)",id:"74-registry-pages-ad-free",level:3},{value:"7.5 Documentation & Tutorials",id:"75-documentation--tutorials",level:3},{value:"7.6 Authentication & Dashboard",id:"76-authentication--dashboard",level:3},{value:"7.7 Privacy & Consent",id:"77-privacy--consent",level:3},{value:"7.8 Ads & Monetization",id:"78-ads--monetization",level:3},{value:"7.9 SEO & Performance",id:"79-seo--performance",level:3},{value:"7.10 Testing & QA",id:"710-testing--qa",level:3},{value:"7.11 Launch Preparation",id:"711-launch-preparation",level:3},{value:"API Endpoints for Web UI",id:"api-endpoints-for-web-ui",level:2},{value:"Diagram References",id:"diagram-references",level:2},{value:"Deployment Guide",id:"deployment-guide",level:2},{value:"Requirements",id:"requirements",level:3},{value:"Quick Start (Development)",id:"quick-start-development",level:3},{value:"Production Deployment",id:"production-deployment",level:3},{value:"1. Environment Variables",id:"1-environment-variables",level:4},{value:"2. Database Location",id:"2-database-location",level:4},{value:"3. Running with systemd",id:"3-running-with-systemd",level:4},{value:"4. Reverse Proxy (nginx)",id:"4-reverse-proxy-nginx",level:4},{value:"5. SSL with Certbot",id:"5-ssl-with-certbot",level:4},{value:"Tailwind CSS Build",id:"tailwind-css-build",level:3},{value:"Health Check",id:"health-check",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3},{value:"Future Considerations (Phase 8+)",id:"future-considerations-phase-8",level:2}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",input:"input",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.header,{children:(0,l.jsx)(n.h1,{id:"cmdforge-web-ui-design",children:"CmdForge Web UI Design"})}),"\n",(0,l.jsx)(n.h2,{id:"purpose",children:"Purpose"}),"\n",(0,l.jsx)(n.p,{children:"Deliver a professional web front-end that explains CmdForge, helps users discover tools, and supports a collaborative ecosystem. The site should drive sustainable revenue without undermining trust or usability."}),"\n",(0,l.jsx)(n.h2,{id:"mission-alignment",children:"Mission Alignment"}),"\n",(0,l.jsxs)(n.p,{children:["This web UI serves the broader CmdForge mission: to provide a ",(0,l.jsx)(n.strong,{children:"universally accessible development ecosystem"})," that empowers regular people to collaborate and build upon each other's progress rather than compete. Revenue generated supports:"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Maintaining and expanding the project"}),"\n",(0,l.jsx)(n.li,{children:"Future hosting of AI models for users with less access to paid services"}),"\n",(0,l.jsx)(n.li,{children:"Building a sustainable, community-first platform"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"The UI design must reflect these values through its structure, content, and monetization approach."}),"\n",(0,l.jsx)(n.h2,{id:"guiding-principles",children:"Guiding Principles"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Utility first"}),": Documentation, tutorials, and examples are the primary draw."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Trust and clarity"}),": Ads and monetization are transparent, minimal, and never block core flows."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Collaboration over competition"}),": Highlight contributors, shared projects, and community learning."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Performance and accessibility"}),": Fast, readable, WCAG 2.1 AA target."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Unix philosophy"}),": Composable, provider-agnostic, YAML-based tools\u2014the UI should communicate this clearly."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"information-architecture",children:"Information Architecture"}),"\n",(0,l.jsx)(n.p,{children:"Public, ad-supported (Tier 1):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/"})," landing"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/docs/*"})," documentation"]}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/tutorials/*"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/examples"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/blog"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/about"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/donate"})}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Registry (Tier 2, ad-free):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/tools"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/tools/{owner}/{name}"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/categories"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/categories/{name}"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/search"})}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Community (Tier 3, light ads):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/forum"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/contributors"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/announcements"})}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Publisher dashboard (auth-only):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/register"}),", ",(0,l.jsx)(n.code,{children:"/login"})]}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/dashboard/tools"})}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/dashboard/connections"})," (manage connected apps)"]}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.code,{children:"/dashboard/settings"})}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"API:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/api/v1/*"})," (shared with CLI)"]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"visual-design-system",children:"Visual Design System"}),"\n",(0,l.jsx)(n.h3,{id:"color-palette",children:"Color Palette"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Role"}),(0,l.jsx)(n.th,{children:"Color"}),(0,l.jsx)(n.th,{children:"Hex"}),(0,l.jsx)(n.th,{children:"Usage"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Primary"}),(0,l.jsx)(n.td,{children:"Indigo"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#6366F1"})}),(0,l.jsx)(n.td,{children:"CTAs, active states, brand identity"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Secondary"}),(0,l.jsx)(n.td,{children:"Cyan"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#06B6D4"})}),(0,l.jsx)(n.td,{children:"Secondary actions, accents, links"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Background"}),(0,l.jsx)(n.td,{children:"Off-white"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#F9FAFB"})}),(0,l.jsx)(n.td,{children:"Page background"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Surface"}),(0,l.jsx)(n.td,{children:"White"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#FFFFFF"})}),(0,l.jsx)(n.td,{children:"Cards, content areas"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Text Primary"}),(0,l.jsx)(n.td,{children:"Dark gray"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#1F2937"})}),(0,l.jsx)(n.td,{children:"Headlines, body text"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Text Secondary"}),(0,l.jsx)(n.td,{children:"Medium gray"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#6B7280"})}),(0,l.jsx)(n.td,{children:"Descriptions, metadata"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Text Muted"}),(0,l.jsx)(n.td,{children:"Light gray"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#9CA3AF"})}),(0,l.jsx)(n.td,{children:"Timestamps, hints"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Border"}),(0,l.jsx)(n.td,{children:"Light gray"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#E5E7EB"})}),(0,l.jsx)(n.td,{children:"Card borders, dividers"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Success"}),(0,l.jsx)(n.td,{children:"Green"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#10B981"})}),(0,l.jsx)(n.td,{children:"Success states, confirmations"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Warning"}),(0,l.jsx)(n.td,{children:"Amber"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#F59E0B"})}),(0,l.jsx)(n.td,{children:"Warnings, deprecation notices"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Error"}),(0,l.jsx)(n.td,{children:"Red"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#EF4444"})}),(0,l.jsx)(n.td,{children:"Error states, critical alerts"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Header"}),(0,l.jsx)(n.td,{children:"Dark slate"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#2C3E50"})}),(0,l.jsx)(n.td,{children:"Header background"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Ad Container"}),(0,l.jsx)(n.td,{children:"Light blue"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#DBEAFE"})}),(0,l.jsx)(n.td,{children:"Ad zone background (distinct from content)"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Sponsored"}),(0,l.jsx)(n.td,{children:"Light amber"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"#FEF3C7"})}),(0,l.jsx)(n.td,{children:"Sponsored content background"})]})]})]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Contrast Requirements:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Body text: minimum 4.5:1 ratio (WCAG AA)"}),"\n",(0,l.jsx)(n.li,{children:"Large text (18px+): minimum 3:1 ratio"}),"\n",(0,l.jsx)(n.li,{children:"UI components: minimum 3:1 ratio against adjacent colors"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"typography",children:"Typography"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Element"}),(0,l.jsx)(n.th,{children:"Font"}),(0,l.jsx)(n.th,{children:"Size"}),(0,l.jsx)(n.th,{children:"Weight"}),(0,l.jsx)(n.th,{children:"Line Height"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"H1"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"36px (2.25rem)"}),(0,l.jsx)(n.td,{children:"700"}),(0,l.jsx)(n.td,{children:"1.2"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"H2"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"24px (1.5rem)"}),(0,l.jsx)(n.td,{children:"700"}),(0,l.jsx)(n.td,{children:"1.3"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"H3"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"20px (1.25rem)"}),(0,l.jsx)(n.td,{children:"600"}),(0,l.jsx)(n.td,{children:"1.4"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"H4"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"18px (1.125rem)"}),(0,l.jsx)(n.td,{children:"600"}),(0,l.jsx)(n.td,{children:"1.4"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Body"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"16px (1rem)"}),(0,l.jsx)(n.td,{children:"400"}),(0,l.jsx)(n.td,{children:"1.6"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Small"}),(0,l.jsx)(n.td,{children:"Inter/system-ui"}),(0,l.jsx)(n.td,{children:"14px (0.875rem)"}),(0,l.jsx)(n.td,{children:"400"}),(0,l.jsx)(n.td,{children:"1.5"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Code"}),(0,l.jsx)(n.td,{children:"JetBrains Mono/monospace"}),(0,l.jsx)(n.td,{children:"14px"}),(0,l.jsx)(n.td,{children:"400"}),(0,l.jsx)(n.td,{children:"1.5"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Code block"}),(0,l.jsx)(n.td,{children:"JetBrains Mono/monospace"}),(0,l.jsx)(n.td,{children:"13px"}),(0,l.jsx)(n.td,{children:"400"}),(0,l.jsx)(n.td,{children:"1.6"})]})]})]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Font Stack:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-css",children:"--font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;\n--font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', monospace;\n"})}),"\n",(0,l.jsx)(n.h3,{id:"spacing-system",children:"Spacing System"}),"\n",(0,l.jsx)(n.p,{children:"Use an 8px base grid for consistent spacing:"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Token"}),(0,l.jsx)(n.th,{children:"Value"}),(0,l.jsx)(n.th,{children:"Usage"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-1"})}),(0,l.jsx)(n.td,{children:"4px"}),(0,l.jsx)(n.td,{children:"Tight spacing, icon margins"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-2"})}),(0,l.jsx)(n.td,{children:"8px"}),(0,l.jsx)(n.td,{children:"Element gaps"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-3"})}),(0,l.jsx)(n.td,{children:"12px"}),(0,l.jsx)(n.td,{children:"Small component padding"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-4"})}),(0,l.jsx)(n.td,{children:"16px"}),(0,l.jsx)(n.td,{children:"Card padding, section gaps"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-6"})}),(0,l.jsx)(n.td,{children:"24px"}),(0,l.jsx)(n.td,{children:"Section padding"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-8"})}),(0,l.jsx)(n.td,{children:"32px"}),(0,l.jsx)(n.td,{children:"Large gaps"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-12"})}),(0,l.jsx)(n.td,{children:"48px"}),(0,l.jsx)(n.td,{children:"Section margins"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--space-16"})}),(0,l.jsx)(n.td,{children:"64px"}),(0,l.jsx)(n.td,{children:"Major section separators"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"border-radius",children:"Border Radius"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Token"}),(0,l.jsx)(n.th,{children:"Value"}),(0,l.jsx)(n.th,{children:"Usage"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--radius-sm"})}),(0,l.jsx)(n.td,{children:"4px"}),(0,l.jsx)(n.td,{children:"Buttons, badges"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--radius-md"})}),(0,l.jsx)(n.td,{children:"8px"}),(0,l.jsx)(n.td,{children:"Cards, inputs"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--radius-lg"})}),(0,l.jsx)(n.td,{children:"12px"}),(0,l.jsx)(n.td,{children:"Modals, large cards"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"--radius-full"})}),(0,l.jsx)(n.td,{children:"9999px"}),(0,l.jsx)(n.td,{children:"Avatars, pills"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"shadow-system",children:"Shadow System"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-css",children:"--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);\n--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);\n--shadow-hover: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n"})}),"\n",(0,l.jsx)(n.h2,{id:"page-requirements",children:"Page Requirements"}),"\n",(0,l.jsxs)(n.h3,{id:"landing-page-",children:["Landing Page (",(0,l.jsx)(n.code,{children:"/"}),")"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Purpose:"})," Convert visitors to users by clearly communicating CmdForge' value proposition and providing immediate paths to explore."]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Reference mockup:"})," ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_6.svg"})]}),"\n",(0,l.jsx)(n.h4,{id:"section-1-hero-above-the-fold",children:"Section 1: Hero (Above the Fold)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [CmdForge] Docs Tutorials Registry Community About \ud83d\udd0d \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u2502\n\u2502 Build Custom AI Commands in YAML \u2502\n\u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502 Create Unix-style pipeable tools that work with any AI \u2502\n\u2502 provider. Provider-agnostic and composable. \u2502\n\u2502 \u2502\n\u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 $ pip install cmdforge && cmdforge init \u2502 [\ud83d\udccb]\u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502 \u2502\n\u2502 [Get Started] [View Tutorials] \u2502\n\u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Headline:"}),' "Build Custom AI Commands in YAML" (benefit-focused, differentiating)']}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Subheadline:"}),' "Create Unix-style pipeable tools that work with any AI provider. Provider-agnostic and composable for ultimate flexibility."']}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Install snippet:"})," ",(0,l.jsx)(n.code,{children:"pip install cmdforge && cmdforge init"})," with copy button"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Primary CTA:"}),' "Get Started" \u2192 links to ',(0,l.jsx)(n.code,{children:"/docs/getting-started"})," (indigo background)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Secondary CTA:"}),' "View Tutorials" \u2192 links to ',(0,l.jsx)(n.code,{children:"/tutorials"})," (outlined, cyan border)"]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Hero background: white card (#FFFFFF) with subtle shadow on off-white page"}),"\n",(0,l.jsx)(n.li,{children:"Maximum content width: 1100px centered"}),"\n",(0,l.jsx)(n.li,{children:"Install snippet: monospace font, light gray background (#E0E0E0), copy icon on right"}),"\n"]}),"\n",(0,l.jsx)(n.h4,{id:"section-2-three-pillars-why-cmdforge",children:"Section 2: Three Pillars (Why CmdForge?)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Why CmdForge? \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [\u2713] Easy \u2502 [\u26a1] Powerful \u2502 [\ud83d\udc65] Community \u2502\n\u2502 \u2502 \u2502 \u2502\n\u2502 Simple YAML \u2502 Any AI \u2502 Share, discover, \u2502\n\u2502 configuration \u2502 provider, \u2502 contribute to a \u2502\n\u2502 for quick \u2502 compose \u2502 growing ecosystem. \u2502\n\u2502 setup. \u2502 complex \u2502 \u2502\n\u2502 \u2502 workflows. \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Pillar 1 - Easy to Use:"}),' Icon in indigo circle, "Simple YAML configuration for quick setup."']}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Pillar 2 - Powerful:"}),' Icon in cyan circle, "Leverage any AI provider, compose complex workflows."']}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Pillar 3 - Community:"}),' Icon in indigo circle, "Share, discover, and contribute to a growing ecosystem."']}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Each pillar: white card with 1px border, subtle shadow on hover"}),"\n",(0,l.jsx)(n.li,{children:"Icon circles: 40px diameter with pillar icon centered"}),"\n",(0,l.jsx)(n.li,{children:"Equal width columns (3 across on desktop)"}),"\n"]}),"\n",(0,l.jsx)(n.h4,{id:"section-3-featured-tools--projects",children:"Section 3: Featured Tools & Projects"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Featured Tools & Projects \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [Category] \u2502 [Category] \u2502 [Category] \u2502\n\u2502 \u25cf Tool Title \u2502 \u25cf Tool Title \u2502 \u25cf Tool Title \u2502\n\u2502 Description... \u2502 Description... \u2502 Description... \u2502\n\u2502 Author: name \u2502 Author: name \u2502 Author: name \u2502\n\u2502 Downloads: 1.2K \u2502 Downloads: 800 \u2502 Downloads: 2.5K \u2502\n\u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502run command \u2502 \u2502 \u2502run command \u2502 \u2502 \u2502run command \u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [Row 2...] \u2502 [Row 2...] \u2502 [Row 2...] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content (per card):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Category badge (top-right, cyan pill)"}),"\n",(0,l.jsx)(n.li,{children:"Tool icon/avatar (indigo circle)"}),"\n",(0,l.jsx)(n.li,{children:"Tool name (bold, 18px)"}),"\n",(0,l.jsx)(n.li,{children:"Short description (14px, secondary text)"}),"\n",(0,l.jsx)(n.li,{children:"Author attribution"}),"\n",(0,l.jsx)(n.li,{children:"Download count with icon"}),"\n",(0,l.jsx)(n.li,{children:"One-line install command in code box"}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Data Source:"})," ",(0,l.jsx)(n.code,{children:"GET /api/v1/tools?sort=downloads&limit=6"})]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"3 columns on desktop, 2 on tablet, 1 on mobile"}),"\n",(0,l.jsx)(n.li,{children:"Cards have subtle shadow, lift on hover"}),"\n",(0,l.jsxs)(n.li,{children:['"View All Tools" link below grid \u2192 ',(0,l.jsx)(n.code,{children:"/tools"})]}),"\n"]}),"\n",(0,l.jsx)(n.h4,{id:"section-4-getting-started",children:"Section 4: Getting Started"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Getting Started \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Tutorial 1: \u2502 Tutorial 2: \u2502 Tutorial 3: \u2502\n\u2502 Basic Setup \u2502 Your First Tool \u2502 Advanced Workflows \u2502\n\u2502 Learn how to... \u2502 Create a \u2502 Combine multiple \u2502\n\u2502 \u2502 simple AI... \u2502 tools for... \u2502\n\u2502 [Read More] \u2502 [Read More] \u2502 [Read More] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"3 tutorial cards highlighting core learning paths"}),"\n",(0,l.jsx)(n.li,{children:"Each card: title (bold), description (2 lines max), CTA button"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Matches tool card styling for visual consistency"}),"\n",(0,l.jsx)(n.li,{children:'"Read More" buttons in primary indigo'}),"\n"]}),"\n",(0,l.jsx)(n.h4,{id:"section-5-featured-contributor",children:"Section 5: Featured Contributor"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Featured Contributor \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [Avatar] Name Here \u2502\n\u2502 Creator of "Tool Name" and active community member. \u2502\n\u2502 [View Profile] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n'})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Monthly rotating spotlight"}),"\n",(0,l.jsx)(n.li,{children:"Avatar (60px circle), name, brief bio, profile link"}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Data Source:"})," Manual curation or ",(0,l.jsx)(n.code,{children:"GET /api/v1/contributors/featured"})]}),"\n",(0,l.jsx)(n.h4,{id:"section-6-footer-ad-zone-optional",children:"Section 6: Footer Ad Zone (Optional)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Advertisement: Support CmdForge Development] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Light blue background (#DBEAFE) to distinguish from content"}),"\n",(0,l.jsx)(n.li,{children:"Clearly labeled as advertisement"}),"\n",(0,l.jsx)(n.li,{children:"Optional based on ad fill rate"}),"\n"]}),"\n",(0,l.jsx)(n.h4,{id:"section-7-footer",children:"Section 7: Footer"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 CmdForge \u2502\n\u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502 Docs | Registry | Community | About | Donate \u2502\n\u2502 Privacy | Terms | GitHub | Twitter \u2502\n\u2502 \u2502\n\u2502 \xa9 2025 CmdForge. Open source under MIT License. \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.h3,{id:"docstutorials-pages-docs-tutorials",children:["Docs/Tutorials Pages (",(0,l.jsx)(n.code,{children:"/docs/*"}),", ",(0,l.jsx)(n.code,{children:"/tutorials/*"}),")"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Layout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Header Navigation] \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 TOC \u2502 Content Area (70%) \u2502 Sidebar \u2502\n\u2502 (Desktop) \u2502 \u2502 (Ads) \u2502\n\u2502 \u2502 # Page Title \u2502 \u2502\n\u2502 - Section 1 \u2502 \u2502 [Ad] \u2502\n\u2502 - Section 2 \u2502 Content with code blocks... \u2502 \u2502\n\u2502 - Section 3 \u2502 \u2502 \u2502\n\u2502 \u2502 ```python \u2502 \u2502\n\u2502 \u2502 # Code with syntax highlighting \u2502 \u2502\n\u2502 \u2502 ``` [Copy] \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 [Embedded Video] \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content Requirements:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Persistent left TOC on desktop (scroll-spy highlighting current section)"}),"\n",(0,l.jsx)(n.li,{children:"Code blocks with syntax highlighting and copy button"}),"\n",(0,l.jsx)(n.li,{children:"Video embeds (YouTube) with play button overlay, lazy-loaded"}),"\n",(0,l.jsx)(n.li,{children:"Callout boxes for tips, warnings, info (color-coded)"}),"\n",(0,l.jsx)(n.li,{children:"Related articles at bottom"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"TOC: fixed on scroll, 200px width"}),"\n",(0,l.jsx)(n.li,{children:"Content area: max-width 700px, generous line-height (1.6-1.8)"}),"\n",(0,l.jsx)(n.li,{children:"Sidebar ads: 300px width, only on desktop"}),"\n",(0,l.jsx)(n.li,{children:"Mobile: TOC collapses to hamburger, sidebar hidden"}),"\n"]}),"\n",(0,l.jsxs)(n.h3,{id:"tool-detail-page-toolsownername",children:["Tool Detail Page (",(0,l.jsx)(n.code,{children:"/tools/{owner}/{name}"}),")"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Layout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Header Navigation] \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 README Content (70%) \u2502 Sidebar (30%) \u2502\n\u2502 \u2502 \u2502\n\u2502 # tool-name \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 \u2502Install \u2502 \u2502\n\u2502 Rendered markdown from README.md... \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502$ run cmd \u2502 \u2502\n\u2502 - Usage examples \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502 - Configuration \u2502 \u2502\n\u2502 - Step definitions \u2502 Versions: \u2502\n\u2502 \u2502 v1.2.0 \u25cf \u2502\n\u2502 \u2502 v1.1.0 \u2502\n\u2502 \u2502 v1.0.0 \u2502\n\u2502 \u2502 \u2502\n\u2502 \u2502 Downloads: \u2502\n\u2502 \u2502 1,234 \u2502\n\u2502 \u2502 \u2502\n\u2502 \u2502 Category: \u2502\n\u2502 \u2502 [text-proc] \u2502\n\u2502 \u2502 \u2502\n\u2502 \u2502 Tags: \u2502\n\u2502 \u2502 [ai] [cli] \u2502\n\u2502 \u2502 \u2502\n\u2502 \u2502 [Report] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Sidebar Elements:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Install command with copy button (prominent)"}),"\n",(0,l.jsx)(n.li,{children:"Version selector/list (current version highlighted)"}),"\n",(0,l.jsx)(n.li,{children:"Download statistics"}),"\n",(0,l.jsx)(n.li,{children:"Category badge (linked)"}),"\n",(0,l.jsx)(n.li,{children:"Tags (linked to search)"}),"\n",(0,l.jsx)(n.li,{children:"Report abuse button"}),"\n",(0,l.jsx)(n.li,{children:"Publisher info (avatar, name, link to profile)"}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"NO ADS on tool detail pages"})," (Tier 2 - registry is ad-free)"]}),"\n",(0,l.jsxs)(n.h3,{id:"registry-browse-page-tools",children:["Registry Browse Page (",(0,l.jsx)(n.code,{children:"/tools"}),")"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Layout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Header Navigation] \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 \ud83d\udd0d Search tools... [Category \u25bc] [Sort \u25bc] \u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Showing 142 tools \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [Tool Card] \u2502 [Tool Card] \u2502 [Tool Card] \u2502 [Tool Card] \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [Tool Card] \u2502 [Tool Card] \u2502 [Tool Card] \u2502 [Tool Card] \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 [\u2190 Previous] Page 1 of 8 [Next \u2192] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Search/Filter Features:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Full-text search with debounce (300ms)"}),"\n",(0,l.jsx)(n.li,{children:"Category dropdown filter"}),"\n",(0,l.jsx)(n.li,{children:"Sort options: Popular (downloads), Recent, Name"}),"\n",(0,l.jsx)(n.li,{children:"Results count display"}),"\n",(0,l.jsx)(n.li,{children:"Pagination (20 per page)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tool Card (compact):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Tool name + owner"}),"\n",(0,l.jsx)(n.li,{children:"Short description (2 lines max, truncated)"}),"\n",(0,l.jsx)(n.li,{children:"Download count"}),"\n",(0,l.jsx)(n.li,{children:"Last updated date"}),"\n",(0,l.jsx)(n.li,{children:"Category tag"}),"\n"]}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"NO ADS on browse pages"})," (Tier 2)"]}),"\n",(0,l.jsxs)(n.h3,{id:"publisher-dashboard-dashboard",children:["Publisher Dashboard (",(0,l.jsx)(n.code,{children:"/dashboard"}),")"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Layout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Header with user menu] \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Sidebar \u2502 Content Area \u2502\n\u2502 \u2502 \u2502\n\u2502 Overview \u2502 \u250c\u2500 Tab: My Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 My Tools \u2502 \u2502 \u2502 \u2502\n\u2502 Connections \u2502 \u2502 Published Tools (3) [+ New Tool] \u2502 \u2502\n\u2502 Settings \u2502 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 summarize v1.2.0 | 142 downloads \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 [Edit] [View] [Yank] \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 Pending PRs (1) \u2502 \u2502\n\u2502 \u2502 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 new-tool v1.0.0 | Awaiting review \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2502 [View PR] \u2502 \u2502 \u2502\n\u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502\n\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tabs:"})}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Overview:"})," Dashboard with stats (tools count, downloads, connections)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"My Tools:"})," List of published tools with stats, edit/view/yank actions"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Connections:"})," Manage connected apps (CLI/TUI instances linked to account)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Settings:"})," Profile editing (display name, bio, website), password change"]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Connections Page:"})}),"\n",(0,l.jsxs)(n.p,{children:["The Connections page (",(0,l.jsx)(n.code,{children:"/dashboard/connections"}),") replaces the old API Tokens page with a simpler app pairing flow:"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Connect New App:"})," Button opens modal with pairing instructions","\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsxs)(n.li,{children:["Shows command: ",(0,l.jsx)(n.code,{children:"cmdforge config connect <username>"})]}),"\n",(0,l.jsxs)(n.li,{children:["Or use the TUI: open ",(0,l.jsx)(n.code,{children:"cmdforge ui"})," and click Connect"]}),"\n",(0,l.jsx)(n.li,{children:'"I\'ve Run the Command" button shows pending connections'}),"\n",(0,l.jsx)(n.li,{children:"Approve pending connection with one click"}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Connected Apps:"})," List of connected devices showing:","\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Device hostname"}),"\n",(0,l.jsx)(n.li,{children:"Connection date"}),"\n",(0,l.jsx)(n.li,{children:"Last used timestamp"}),"\n",(0,l.jsx)(n.li,{children:"Disconnect button to revoke access"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"This eliminates the need to manually copy API tokens - users just approve connections from the web UI."}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Clean, utilitarian design"}),"\n",(0,l.jsx)(n.li,{children:"Clear action buttons"}),"\n",(0,l.jsx)(n.li,{children:"Status indicators for pending PRs"}),"\n",(0,l.jsx)(n.li,{children:"Pairing modal guides users through connection flow"}),"\n"]}),"\n",(0,l.jsxs)(n.h3,{id:"donate-page-donate",children:["Donate Page (",(0,l.jsx)(n.code,{children:"/donate"}),")"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Content:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Mission statement (emotional, connecting to values)"}),"\n",(0,l.jsx)(n.li,{children:"Clear explanation of fund usage (hosting, development, future AI hosting)"}),"\n",(0,l.jsx)(n.li,{children:"Multiple donation options (GitHub Sponsors, PayPal, Ko-fi)"}),"\n",(0,l.jsx)(n.li,{children:"Optional donor recognition section"}),"\n",(0,l.jsx)(n.li,{children:"Transparency about current costs/goals"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Design Notes:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Clean, trustworthy design"}),"\n",(0,l.jsx)(n.li,{children:"Clear CTAs for each donation method"}),"\n",(0,l.jsx)(n.li,{children:"No ads on this page"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"component-library",children:"Component Library"}),"\n",(0,l.jsx)(n.h3,{id:"buttons",children:"Buttons"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Primary Button:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<button class="btn-primary">Get Started</button>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Primary indigo (#6366F1)"}),"\n",(0,l.jsx)(n.li,{children:"Text: White, 16px, font-weight 600"}),"\n",(0,l.jsx)(n.li,{children:"Padding: 12px 24px"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 4px"}),"\n",(0,l.jsx)(n.li,{children:"Hover: Darken 10%, subtle shadow"}),"\n",(0,l.jsx)(n.li,{children:"Focus: 2px outline offset"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Secondary Button:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<button class="btn-secondary">View Tutorials</button>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Transparent"}),"\n",(0,l.jsx)(n.li,{children:"Border: 2px solid cyan (#06B6D4)"}),"\n",(0,l.jsx)(n.li,{children:"Text: Cyan, 16px, font-weight 600"}),"\n",(0,l.jsx)(n.li,{children:"Hover: Light cyan background (#ECFEFF)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Ghost Button:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<button class="btn-ghost">Read More</button>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Transparent"}),"\n",(0,l.jsx)(n.li,{children:"Text: Primary indigo"}),"\n",(0,l.jsx)(n.li,{children:"Hover: Light indigo background"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Danger Button:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<button class="btn-danger">Revoke Token</button>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Error red (#EF4444)"}),"\n",(0,l.jsx)(n.li,{children:"Text: White"}),"\n",(0,l.jsx)(n.li,{children:"Used for destructive actions"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"cards",children:"Cards"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tool Card:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Category] \u2502\n\u2502 [\u25cf] Tool Name \u2502\n\u2502 Short description of the tool that \u2502\n\u2502 may span two lines maximum... \u2502\n\u2502 \u2502\n\u2502 Author: owner-name \u2502\n\u2502 \u2b07 1,234 downloads \u2502\n\u2502 \u2502\n\u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502 \u2502 cmdforge run owner/tool \u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: White (#FFFFFF)"}),"\n",(0,l.jsx)(n.li,{children:"Border: 1px solid border color (#E5E7EB)"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 8px"}),"\n",(0,l.jsx)(n.li,{children:"Shadow: shadow-sm, shadow-md on hover"}),"\n",(0,l.jsx)(n.li,{children:"Padding: 16px"}),"\n",(0,l.jsx)(n.li,{children:"Category badge: absolute top-right, cyan background, white text, 12px"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tutorial Card:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Optional Thumbnail Image] \u2502\n\u2502 \u2502\n\u2502 Tutorial Title Here \u2502\n\u2502 Brief description of what the \u2502\n\u2502 tutorial covers... \u2502\n\u2502 \u2502\n\u2502 [Read More \u2192] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Same base styling as tool card"}),"\n",(0,l.jsx)(n.li,{children:"Optional thumbnail: aspect-ratio 16:9, lazy-loaded"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Contributor Card:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Avatar] Contributor Name \u2502\n\u2502 @github-handle \u2502\n\u2502 Creator of "Tool Name" \u2502\n\u2502 [View Profile] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Avatar: 48px circle"}),"\n",(0,l.jsx)(n.li,{children:"Horizontal layout for spotlight, vertical for grid"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"navigation",children:"Navigation"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Header Navigation:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 [Logo] [Docs] [Tutorials] [Registry] [Community] [About] \ud83d\udd0d \u2502\n\u2502 [Donate] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Dark slate (#2C3E50)"}),"\n",(0,l.jsx)(n.li,{children:"Logo: White text, 24px, bold"}),"\n",(0,l.jsx)(n.li,{children:"Nav links: White text, 16px"}),"\n",(0,l.jsx)(n.li,{children:"Active/hover: Underline or slight background"}),"\n",(0,l.jsx)(n.li,{children:"Mobile: Hamburger menu with slide-out drawer"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Breadcrumbs:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"Registry > owner > tool-name > v1.2.0\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Separator: ",(0,l.jsx)(n.code,{children:">"})," or ",(0,l.jsx)(n.code,{children:"/"})]}),"\n",(0,l.jsx)(n.li,{children:"Current page: bold, not linked"}),"\n",(0,l.jsx)(n.li,{children:"Previous pages: linked, secondary color"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"form-elements",children:"Form Elements"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Text Input:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<input type="text" class="input" placeholder="Search tools...">\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Border: 1px solid border color"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 8px"}),"\n",(0,l.jsx)(n.li,{children:"Padding: 12px 16px"}),"\n",(0,l.jsx)(n.li,{children:"Focus: Primary indigo border, subtle shadow"}),"\n",(0,l.jsx)(n.li,{children:"Height: 44px (touch target compliance)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Search Input with Icon:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \ud83d\udd0d Search tools... \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Icon: Left-aligned, muted color"}),"\n",(0,l.jsx)(n.li,{children:"Placeholder: Secondary text color"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Select/Dropdown:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Category \u25bc \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Same styling as text input"}),"\n",(0,l.jsx)(n.li,{children:"Chevron icon on right"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"badges-and-tags",children:"Badges and Tags"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Category Badge:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<span class="badge badge-category">text-processing</span>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Cyan (#06B6D4)"}),"\n",(0,l.jsx)(n.li,{children:"Text: White, 12px"}),"\n",(0,l.jsx)(n.li,{children:"Padding: 4px 8px"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 4px"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tag:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<span class="tag">ai</span>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light gray (#F3F4F6)"}),"\n",(0,l.jsx)(n.li,{children:"Text: Secondary gray, 12px"}),"\n",(0,l.jsx)(n.li,{children:"Border: 1px solid border color"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 9999px (pill)"}),"\n",(0,l.jsx)(n.li,{children:"Clickable (links to search)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Status Badge:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<span class="badge badge-success">Published</span>\n<span class="badge badge-warning">Pending</span>\n<span class="badge badge-error">Yanked</span>\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Success: Green background"}),"\n",(0,l.jsx)(n.li,{children:"Warning: Amber background"}),"\n",(0,l.jsx)(n.li,{children:"Error: Red background"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"code-blocks",children:"Code Blocks"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Inline Code:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:"<code>cmdforge run foo</code>\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light gray (#F3F4F6)"}),"\n",(0,l.jsx)(n.li,{children:"Font: Monospace"}),"\n",(0,l.jsx)(n.li,{children:"Padding: 2px 6px"}),"\n",(0,l.jsx)(n.li,{children:"Border-radius: 4px"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Code Block with Copy:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 ```python [\ud83d\udccb] \u2502\n\u2502 def hello(): \u2502\n\u2502 print("Hello, World!") \u2502\n\u2502 ``` \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n'})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Dark (#1F2937) or light (#F9FAFB)"}),"\n",(0,l.jsx)(n.li,{children:"Syntax highlighting (Prism.js or Highlight.js)"}),"\n",(0,l.jsx)(n.li,{children:"Copy button: top-right, appears on hover"}),"\n",(0,l.jsx)(n.li,{children:"Line numbers: optional, enabled for tutorials"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"callout-boxes",children:"Callout Boxes"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Info Callout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u2139\ufe0f Note \u2502\n\u2502 This is helpful information for the user. \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light blue (#DBEAFE)"}),"\n",(0,l.jsx)(n.li,{children:"Border-left: 4px solid blue (#3B82F6)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Warning Callout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u26a0\ufe0f Warning \u2502\n\u2502 Be careful with this configuration. \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light amber (#FEF3C7)"}),"\n",(0,l.jsx)(n.li,{children:"Border-left: 4px solid amber (#F59E0B)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Error Callout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u274c Important \u2502\n\u2502 This action cannot be undone. \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light red (#FEE2E2)"}),"\n",(0,l.jsx)(n.li,{children:"Border-left: 4px solid red (#EF4444)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tip Callout:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \ud83d\udca1 Tip \u2502\n\u2502 You can also use this shortcut... \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Background: Light green (#D1FAE5)"}),"\n",(0,l.jsx)(n.li,{children:"Border-left: 4px solid green (#10B981)"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"loading-states",children:"Loading States"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Skeleton Loader:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2502\n\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2502\n\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Animated shimmer effect"}),"\n",(0,l.jsx)(n.li,{children:"Matches component dimensions"}),"\n",(0,l.jsx)(n.li,{children:"Used for cards, text blocks"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Spinner:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Circular spinner for buttons, inline loading"}),"\n",(0,l.jsx)(n.li,{children:"Primary indigo color"}),"\n",(0,l.jsx)(n.li,{children:"Size: 16px (small), 24px (medium), 32px (large)"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Progress Bar:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Used for multi-step operations"}),"\n",(0,l.jsx)(n.li,{children:"Shows percentage or step count"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"responsive-design",children:"Responsive Design"}),"\n",(0,l.jsx)(n.h3,{id:"breakpoints",children:"Breakpoints"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Breakpoint"}),(0,l.jsx)(n.th,{children:"Width"}),(0,l.jsx)(n.th,{children:"Name"}),(0,l.jsx)(n.th,{children:"Grid Columns"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"xs"}),(0,l.jsx)(n.td,{children:"< 480px"}),(0,l.jsx)(n.td,{children:"Extra small phones"}),(0,l.jsx)(n.td,{children:"1"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"sm"}),(0,l.jsx)(n.td,{children:"480-639px"}),(0,l.jsx)(n.td,{children:"Phones"}),(0,l.jsx)(n.td,{children:"1"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"md"}),(0,l.jsx)(n.td,{children:"640-767px"}),(0,l.jsx)(n.td,{children:"Large phones / small tablets"}),(0,l.jsx)(n.td,{children:"2"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"lg"}),(0,l.jsx)(n.td,{children:"768-1023px"}),(0,l.jsx)(n.td,{children:"Tablets"}),(0,l.jsx)(n.td,{children:"2-3"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"xl"}),(0,l.jsx)(n.td,{children:"1024-1279px"}),(0,l.jsx)(n.td,{children:"Small desktops"}),(0,l.jsx)(n.td,{children:"3-4"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"2xl"}),(0,l.jsx)(n.td,{children:"\u2265 1280px"}),(0,l.jsx)(n.td,{children:"Large desktops"}),(0,l.jsx)(n.td,{children:"4"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"layout-adaptations",children:"Layout Adaptations"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Mobile (< 640px):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Single-column layout"}),"\n",(0,l.jsx)(n.li,{children:"Navigation: hamburger menu with slide-out drawer"}),"\n",(0,l.jsx)(n.li,{children:"Hero: stacked content, centered"}),"\n",(0,l.jsx)(n.li,{children:"Tool cards: full-width, stacked"}),"\n",(0,l.jsx)(n.li,{children:"TOC: collapsible accordion at top of page"}),"\n",(0,l.jsx)(n.li,{children:"Sidebar ads: hidden"}),"\n",(0,l.jsx)(n.li,{children:"Footer ads: optional, minimal"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Tablet (640-1023px):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Two-column grid for cards"}),"\n",(0,l.jsx)(n.li,{children:"Navigation: horizontal but condensed"}),"\n",(0,l.jsx)(n.li,{children:"TOC: collapsible sidebar"}),"\n",(0,l.jsx)(n.li,{children:"Sidebar ads: may show below content"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Desktop (\u2265 1024px):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Full multi-column layout"}),"\n",(0,l.jsx)(n.li,{children:"Navigation: full horizontal with all links visible"}),"\n",(0,l.jsx)(n.li,{children:"TOC: fixed left sidebar"}),"\n",(0,l.jsx)(n.li,{children:"Sidebar ads: visible in right column"}),"\n",(0,l.jsx)(n.li,{children:"Maximum content width: 1280px with centered container"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"touch-targets",children:"Touch Targets"}),"\n",(0,l.jsx)(n.p,{children:"All interactive elements must meet minimum touch target size:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Minimum size: 44\xd744px (WCAG 2.1 AA)"}),"\n",(0,l.jsx)(n.li,{children:"Spacing between targets: minimum 8px"}),"\n",(0,l.jsx)(n.li,{children:"Applies to: buttons, links, form inputs, navigation items"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"mobile-specific-considerations",children:"Mobile-Specific Considerations"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"No horizontal scrolling"}),"\n",(0,l.jsx)(n.li,{children:"Images: responsive with max-width: 100%"}),"\n",(0,l.jsx)(n.li,{children:"Tables: horizontal scroll wrapper on small screens"}),"\n",(0,l.jsx)(n.li,{children:"Code blocks: horizontal scroll with visible scrollbar"}),"\n",(0,l.jsx)(n.li,{children:"Modals: full-screen on mobile, centered on desktop"}),"\n",(0,l.jsx)(n.li,{children:"Keyboard: virtual keyboard should not obscure inputs"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"performance-budgets",children:"Performance Budgets"}),"\n",(0,l.jsx)(n.h3,{id:"core-web-vitals-targets",children:"Core Web Vitals Targets"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Metric"}),(0,l.jsx)(n.th,{children:"Target"}),(0,l.jsx)(n.th,{children:"Maximum"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Largest Contentful Paint (LCP)"}),(0,l.jsx)(n.td,{children:"< 1.5s"}),(0,l.jsx)(n.td,{children:"< 2.5s"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"First Input Delay (FID)"}),(0,l.jsx)(n.td,{children:"< 50ms"}),(0,l.jsx)(n.td,{children:"< 100ms"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Cumulative Layout Shift (CLS)"}),(0,l.jsx)(n.td,{children:"< 0.05"}),(0,l.jsx)(n.td,{children:"< 0.1"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"First Contentful Paint (FCP)"}),(0,l.jsx)(n.td,{children:"< 1.0s"}),(0,l.jsx)(n.td,{children:"< 1.8s"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Time to Interactive (TTI)"}),(0,l.jsx)(n.td,{children:"< 2.5s"}),(0,l.jsx)(n.td,{children:"< 3.5s"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"resource-budgets",children:"Resource Budgets"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Resource"}),(0,l.jsx)(n.th,{children:"Budget"}),(0,l.jsx)(n.th,{children:"Notes"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Total page weight"}),(0,l.jsx)(n.td,{children:"< 500KB"}),(0,l.jsx)(n.td,{children:"Excluding ads"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"JavaScript (compressed)"}),(0,l.jsx)(n.td,{children:"< 100KB"}),(0,l.jsx)(n.td,{children:"Main bundle"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"CSS (compressed)"}),(0,l.jsx)(n.td,{children:"< 50KB"}),(0,l.jsx)(n.td,{children:"Main stylesheet"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Images (above fold)"}),(0,l.jsx)(n.td,{children:"< 200KB"}),(0,l.jsx)(n.td,{children:"Hero, featured tools"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Fonts"}),(0,l.jsx)(n.td,{children:"< 100KB"}),(0,l.jsx)(n.td,{children:"Subset, WOFF2 format"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Third-party scripts"}),(0,l.jsx)(n.td,{children:"< 150KB"}),(0,l.jsx)(n.td,{children:"Analytics, ads (lazy)"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"loading-strategy",children:"Loading Strategy"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Critical Path (synchronous):"})}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsx)(n.li,{children:"HTML document"}),"\n",(0,l.jsxs)(n.li,{children:["Critical CSS (inlined in ",(0,l.jsx)(n.code,{children:"<head>"}),")"]}),"\n",(0,l.jsx)(n.li,{children:"Above-the-fold content"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Deferred Loading:"})}),"\n",(0,l.jsxs)(n.ol,{children:["\n",(0,l.jsx)(n.li,{children:"Non-critical CSS (preload, async)"}),"\n",(0,l.jsx)(n.li,{children:"JavaScript (defer)"}),"\n",(0,l.jsxs)(n.li,{children:["Below-fold images (lazy-load with ",(0,l.jsx)(n.code,{children:'loading="lazy"'}),")"]}),"\n",(0,l.jsx)(n.li,{children:"Third-party scripts (ads, analytics)"}),"\n",(0,l.jsx)(n.li,{children:"Video embeds (lazy, placeholder until visible)"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"caching-strategy",children:"Caching Strategy"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Resource"}),(0,l.jsx)(n.th,{children:"Cache-Control"}),(0,l.jsx)(n.th,{children:"Notes"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Static assets (CSS, JS)"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"max-age=31536000, immutable"})}),(0,l.jsx)(n.td,{children:"Hashed filenames"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Images"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"max-age=86400"})}),(0,l.jsx)(n.td,{children:"1 day"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"HTML pages"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"max-age=300, stale-while-revalidate=60"})}),(0,l.jsx)(n.td,{children:"5 min, background refresh"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"API responses"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"max-age=60"})}),(0,l.jsx)(n.td,{children:"1 min for tool lists"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Tool downloads"}),(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"max-age=3600, immutable"})}),(0,l.jsx)(n.td,{children:"Immutable versions"})]})]})]}),"\n",(0,l.jsx)(n.h3,{id:"performance-monitoring",children:"Performance Monitoring"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Monitor Core Web Vitals in production"}),"\n",(0,l.jsxs)(n.li,{children:["Set up alerts for degradation (",(0,l.jsx)(n.code,{children:">10%"})," threshold)"]}),"\n",(0,l.jsx)(n.li,{children:"Track page load times by route"}),"\n",(0,l.jsx)(n.li,{children:"Monitor JavaScript error rates"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"error-states-and-fallbacks",children:"Error States and Fallbacks"}),"\n",(0,l.jsx)(n.h3,{id:"network-errors",children:"Network Errors"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"API Unavailable:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 \u26a0\ufe0f Registry Temporarily Unavailable \u2502\n\u2502 \u2502\n\u2502 We're having trouble connecting to the registry. \u2502\n\u2502 Please try again in a few moments. \u2502\n\u2502 \u2502\n\u2502 [Retry] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Slow Connection:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Show skeleton loaders for content"}),"\n",(0,l.jsx)(n.li,{children:"Progressive loading with visible feedback"}),"\n",(0,l.jsx)(n.li,{children:"Timeout after 10 seconds with retry option"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"tool-not-found-404",children:"Tool Not Found (404):"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Tool Not Found \u2502\n\u2502 \u2502\n\u2502 The tool "owner/tool-name" doesn\'t exist or may \u2502\n\u2502 have been removed. \u2502\n\u2502 \u2502\n\u2502 [Browse Tools] [Search Registry] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n'})}),"\n",(0,l.jsx)(n.h3,{id:"search-no-results",children:"Search No Results:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:'\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 No tools found for "query" \u2502\n\u2502 \u2502\n\u2502 Suggestions: \u2502\n\u2502 \u2022 Try different keywords \u2502\n\u2502 \u2022 Check spelling \u2502\n\u2502 \u2022 Browse by category \u2502\n\u2502 \u2502\n\u2502 [Browse All Tools] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n'})}),"\n",(0,l.jsx)(n.h3,{id:"offline-mode",children:"Offline Mode"}),"\n",(0,l.jsx)(n.p,{children:"If service worker is implemented:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Show cached pages when offline"}),"\n",(0,l.jsx)(n.li,{children:"Indicate offline status in header"}),"\n",(0,l.jsx)(n.li,{children:"Queue actions (report, install) for when online"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"form-errors",children:"Form Errors"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Inline Validation:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Show error message below field"}),"\n",(0,l.jsx)(n.li,{children:"Red border on invalid fields"}),"\n",(0,l.jsx)(n.li,{children:"Error icon in field"}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Form Submission Error:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Toast notification for transient errors"}),"\n",(0,l.jsx)(n.li,{children:"Inline error summary for validation failures"}),"\n",(0,l.jsx)(n.li,{children:"Preserve form state on error"}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"ad-and-revenue-strategy",children:"Ad and Revenue Strategy"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Ad placement"}),": One sidebar unit on long-form docs/tut pages, optional footer banner on landing, none on registry pages."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"No ads"})," in install flows, login/registration, or tool browsing details."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Sponsored content"}),": Clearly labeled and separated from organic rankings."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"YouTube"}),": Embed tutorials with transcripts; also drive to channel."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"monetization-extensions-optional",children:"Monetization Extensions (Optional)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Donations"}),": Single page with clear use-of-funds."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Featured projects"}),": Curated or sponsored slots with explicit labeling."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Premium publisher tier"}),": More tools, enhanced analytics, priority review."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Training/consulting"}),": Workshops or enterprise onboarding."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"data-and-governance",children:"Data and Governance"}),"\n",(0,l.jsx)(n.p,{children:"Proposed minimal tables (web-only):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"promotions"})," (featured tools/projects, start/end, placement, audit)."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"featured_projects"})," (title, description, owner, url, status)."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"content_pages"})," (docs/tutorials metadata for listing)."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"announcements"})," (title, body, published_at)."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Roles and permissions:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"admin"}),": can publish announcements, manage promotions, moderate reports."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"editor"}),": can create/update docs, tutorials, featured projects."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"publisher"}),": can manage their own tools and profile only."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"contributor"}),": can partisipate in discussions in the forums."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Audit fields (required on content tables):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"created_by"}),", ",(0,l.jsx)(n.code,{children:"updated_by"}),", ",(0,l.jsx)(n.code,{children:"created_at"}),", ",(0,l.jsx)(n.code,{children:"updated_at"}),"."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Ranking rules:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Organic search uses relevance and downloads."}),"\n",(0,l.jsx)(n.li,{children:"Sponsored placements appear in dedicated sections and do not alter organic order."}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Promotions placement rules:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Slots are deterministic (e.g., positions 1 and 5 in lists)."}),"\n",(0,l.jsx)(n.li,{children:"Promotions are clearly labeled and never mixed into organic ranking."}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"promotions"})," includes ",(0,l.jsx)(n.code,{children:"placement"}),", ",(0,l.jsx)(n.code,{children:"priority"}),", ",(0,l.jsx)(n.code,{children:"start_at"}),", ",(0,l.jsx)(n.code,{children:"end_at"}),", ",(0,l.jsx)(n.code,{children:"status"}),"."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"privacy-and-consent",children:"Privacy and Consent"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Consent banner for analytics/ads."}),"\n",(0,l.jsx)(n.li,{children:"Minimal tracking, anonymized IPs."}),"\n",(0,l.jsx)(n.li,{children:"Clear privacy policy and retention policy."}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Consent storage:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Store a ",(0,l.jsx)(n.code,{children:"consents"})," record keyed by ",(0,l.jsx)(n.code,{children:"client_id"})," (anonymous) or user id (logged-in)."]}),"\n",(0,l.jsx)(n.li,{children:"Respect opt-outs by disabling analytics/ads on server-rendered pages."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"ux-and-accessibility",children:"UX and Accessibility"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Keyboard navigation for all interactive elements."}),"\n",(0,l.jsx)(n.li,{children:"High contrast and readable typography."}),"\n",(0,l.jsx)(n.li,{children:"Mobile-first layout; ads hidden on mobile except optional footer."}),"\n",(0,l.jsx)(n.li,{children:"Avoid popups and auto-play media."}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Responsive breakpoints (baseline):"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Mobile: ",(0,l.jsx)(n.code,{children:"<640px"})]}),"\n",(0,l.jsxs)(n.li,{children:["Tablet: ",(0,l.jsx)(n.code,{children:"640\u20131024px"})]}),"\n",(0,l.jsxs)(n.li,{children:["Desktop: ",(0,l.jsx)(n.code,{children:">1024px"})]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"tech-stack-phase-7-target",children:"Tech Stack (Phase 7 Target)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Flask + Jinja + Tailwind"})," for SEO-friendly server-rendered pages."]}),"\n",(0,l.jsxs)(n.li,{children:["Optional ",(0,l.jsx)(n.strong,{children:"htmx"})," or ",(0,l.jsx)(n.strong,{children:"Alpine.js"})," for small interactivity."]}),"\n",(0,l.jsx)(n.li,{children:"Shared registry API for data."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"auth-and-session-model",children:"Auth and Session Model"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Server-side sessions (DB-backed) for dashboard views."}),"\n",(0,l.jsxs)(n.li,{children:["Cookies: ",(0,l.jsx)(n.code,{children:"HttpOnly"}),", ",(0,l.jsx)(n.code,{children:"SameSite=Lax"}),", ",(0,l.jsx)(n.code,{children:"Secure"})," in production."]}),"\n",(0,l.jsx)(n.li,{children:"CSRF protection on all POST/PUT/DELETE web forms."}),"\n",(0,l.jsx)(n.li,{children:"Session TTL: 7 days with rotation on login."}),"\n",(0,l.jsx)(n.li,{children:"Logout invalidates session server-side."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"api-surfaces-for-web-ui",children:"API Surfaces for Web UI"}),"\n",(0,l.jsx)(n.p,{children:"Read-only UI calls should use the existing API:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/api/v1/tools"}),", ",(0,l.jsx)(n.code,{children:"/api/v1/tools/search"}),", ",(0,l.jsx)(n.code,{children:"/api/v1/categories"}),", ",(0,l.jsx)(n.code,{children:"/api/v1/stats/popular"}),"."]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:"Publisher dashboard uses auth endpoints:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"/api/v1/login"}),", ",(0,l.jsx)(n.code,{children:"/api/v1/tokens"}),", ",(0,l.jsx)(n.code,{children:"/api/v1/me/tools"}),"."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"payments-and-donations-optional",children:"Payments and Donations (Optional)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Decide early on a processor (Stripe, Ko-fi, paypal, bitcoin/crypto) to avoid churn."}),"\n",(0,l.jsx)(n.li,{children:"Webhook handling must verify signatures and enforce idempotency keys."}),"\n",(0,l.jsxs)(n.li,{children:["Store donation/subscription state with ",(0,l.jsx)(n.code,{children:"status"}),", ",(0,l.jsx)(n.code,{children:"amount"}),", ",(0,l.jsx)(n.code,{children:"currency"}),", ",(0,l.jsx)(n.code,{children:"provider_id"}),", ",(0,l.jsx)(n.code,{children:"created_at"}),"."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"moderation-and-abuse-reporting",children:"Moderation and Abuse Reporting"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Tool detail pages require a minimal abuse report endpoint."}),"\n",(0,l.jsxs)(n.li,{children:["Create ",(0,l.jsx)(n.code,{children:"reports"})," table with ",(0,l.jsx)(n.code,{children:"tool_id"}),", ",(0,l.jsx)(n.code,{children:"reporter"}),", ",(0,l.jsx)(n.code,{children:"reason"}),", ",(0,l.jsx)(n.code,{children:"status"}),"."]}),"\n",(0,l.jsx)(n.li,{children:"Add rate limit to the report endpoint to prevent spam."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"media-and-asset-handling",children:"Media and Asset Handling"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Images/screenshots stored in object storage (preferred) or a dedicated ",(0,l.jsx)(n.code,{children:"assets/"})," bucket."]}),"\n",(0,l.jsx)(n.li,{children:"Enforce size limits and content-type validation."}),"\n",(0,l.jsx)(n.li,{children:"Generate thumbnails for cards and lazy-load in UI."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"caching-and-seo-serving",children:"Caching and SEO Serving"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Public pages include ETag/Last-Modified for CDN caching."}),"\n",(0,l.jsx)(n.li,{children:"Dashboard pages are non-cacheable and user-specific."}),"\n",(0,l.jsx)(n.li,{children:"Avoid cache poisoning by varying on auth cookies."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"seo-strategy",children:"SEO Strategy"}),"\n",(0,l.jsx)(n.h3,{id:"technical-seo",children:"Technical SEO"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"URL Structure:"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"/ # Landing page\n/tools # Registry browse\n/tools/{owner}/{name} # Tool detail (canonical)\n/tools/{owner}/{name}/v/1.0 # Specific version\n/categories/{slug} # Category listing\n/docs/{section}/{page} # Documentation\n/tutorials/{slug} # Tutorial pages\n"})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Meta Tags (per page type):"})}),"\n",(0,l.jsx)(n.p,{children:"Landing page:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'<title>CmdForge - Build Custom AI Commands in YAML\n\n\n'})}),"\n",(0,l.jsx)(n.p,{children:"Tool detail page:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'{tool-name} by {owner} - CmdForge Registry\n\n'})}),"\n",(0,l.jsx)(n.h3,{id:"structured-data-schemaorg",children:"Structured Data (Schema.org)"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"SoftwareApplication (for tools):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'{\n "@context": "https://schema.org",\n "@type": "SoftwareApplication",\n "name": "summarize",\n "applicationCategory": "DeveloperApplication",\n "operatingSystem": "Linux, macOS, Windows",\n "author": {\n "@type": "Person",\n "name": "owner-name"\n },\n "downloadUrl": "https://cmdforge.brrd.tech/tools/owner/summarize",\n "softwareVersion": "1.2.0",\n "aggregateRating": {\n "@type": "AggregateRating",\n "ratingValue": "4.5",\n "ratingCount": "142"\n }\n}\n'})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Organization (site-wide):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'{\n "@context": "https://schema.org",\n "@type": "Organization",\n "name": "CmdForge",\n "url": "https://cmdforge.dev",\n "logo": "https://cmdforge.dev/logo.png",\n "sameAs": [\n "https://github.com/your-org/cmdforge",\n "https://twitter.com/cmdforge"\n ]\n}\n'})}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Article (for tutorials/blog):"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-json",children:'{\n "@context": "https://schema.org",\n "@type": "TechArticle",\n "headline": "Getting Started with CmdForge",\n "author": {"@type": "Person", "name": "Author Name"},\n "datePublished": "2025-01-15",\n "dateModified": "2025-01-20"\n}\n'})}),"\n",(0,l.jsx)(n.h3,{id:"open-graph--social-sharing",children:"Open Graph & Social Sharing"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-html",children:'\x3c!-- Open Graph --\x3e\n\n\n\n\n\n\n\x3c!-- Twitter Card --\x3e\n\n\n\n\n\n'})}),"\n",(0,l.jsx)(n.h3,{id:"sitemap",children:"Sitemap"}),"\n",(0,l.jsxs)(n.p,{children:["Auto-generate ",(0,l.jsx)(n.code,{children:"sitemap.xml"}),":"]}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"All public pages"}),"\n",(0,l.jsx)(n.li,{children:"Tool detail pages (updated on publish)"}),"\n",(0,l.jsx)(n.li,{children:"Category pages"}),"\n",(0,l.jsx)(n.li,{children:"Documentation pages"}),"\n",(0,l.jsx)(n.li,{children:"Priority based on page importance"}),"\n"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-xml",children:'\n\n \n https://cmdforge.dev/\n 1.0\n daily\n \n \n https://cmdforge.dev/tools\n 0.9\n daily\n \n \x3c!-- Tool pages, docs, etc. --\x3e\n\n'})}),"\n",(0,l.jsx)(n.h3,{id:"robotstxt",children:"robots.txt"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{children:"User-agent: *\nAllow: /\n\n# Block auth pages from indexing\nDisallow: /login\nDisallow: /register\nDisallow: /dashboard\nDisallow: /api/\n\nSitemap: https://cmdforge.dev/sitemap.xml\n"})}),"\n",(0,l.jsx)(n.h3,{id:"canonical-urls",children:"Canonical URLs"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Each page has a single canonical URL"}),"\n",(0,l.jsxs)(n.li,{children:["Use ",(0,l.jsx)(n.code,{children:''})," tag"]}),"\n",(0,l.jsx)(n.li,{children:"Avoid duplicate content issues"}),"\n",(0,l.jsx)(n.li,{children:"Tool versions link to latest as canonical"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"performance-for-seo",children:"Performance for SEO"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Server-side rendering for all public pages (Flask + Jinja)"}),"\n",(0,l.jsx)(n.li,{children:"No JavaScript required for content visibility"}),"\n",(0,l.jsx)(n.li,{children:"Fast TTFB (< 200ms target)"}),"\n",(0,l.jsx)(n.li,{children:"Mobile-friendly (responsive design)"}),"\n",(0,l.jsx)(n.li,{children:'Core Web Vitals in "good" range'}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"content-strategy",children:"Content Strategy"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Core tutorials that mirror CLI workflows."}),"\n",(0,l.jsx)(n.li,{children:'"Project spotlights" to showcase real usage.'}),"\n",(0,l.jsx)(n.li,{children:"Contributor recognition (monthly spotlight)."}),"\n",(0,l.jsx)(n.li,{children:"Announcements and changelog summaries."}),"\n",(0,l.jsx)(n.li,{children:"Encourage AI parsing to increase adsense revenue."}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"risks-and-mitigations",children:"Risks and Mitigations"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Ad overload"}),": strict placement rules, no ads in registry."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Moderation burden and load"}),": Implement AI enabled moderation with flags to alert human intervention to keep things moving and simplefy maintenence."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Content drift"}),": quarterly doc reviews tied to releases."]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Consent and tracking"}),": default to privacy-preserving settings."]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"phase-7-implementation-checklist",children:"Phase 7 Implementation Checklist"}),"\n",(0,l.jsx)(n.h3,{id:"71-foundation--setup",children:"7.1 Foundation & Setup"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Set up Flask project structure with blueprints"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Configure Jinja2 templates with base layout"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Integrate Tailwind CSS (build pipeline)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Set up static asset handling (CSS, JS, images)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Configure development/production environments"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Set up database models for web-specific tables"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"72-core-templates--components",children:"7.2 Core Templates & Components"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Create base template with header/footer"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Implement navigation component (desktop + mobile)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Build reusable card components (tool, tutorial, contributor)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Create form components (inputs, buttons, dropdowns)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Implement callout/alert components"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Build code block component with copy functionality"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Create loading states (skeleton, spinner)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Implement responsive grid system"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"73-landing-page",children:"7.3 Landing Page"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Hero section with install snippet"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Three pillars section (Easy, Powerful, Community)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Featured tools grid (API integration)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Getting started tutorial cards"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Featured contributor spotlight"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Footer with links and optional ad zone"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"74-registry-pages-ad-free",children:"7.4 Registry Pages (Ad-Free)"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Tool browse page with search bar"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Category dropdown filter"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Sort options (popular, recent, name)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Pagination component"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Tool card grid layout"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Tool detail page with README rendering"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Version selector in sidebar"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Install command with copy"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Report abuse button/modal"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Category pages"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"75-documentation--tutorials",children:"7.5 Documentation & Tutorials"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Docs landing page with section links"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Tutorial listing page"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Content page template with TOC"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Scroll-spy for TOC highlighting"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Code syntax highlighting (Prism/Highlight.js)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Video embed component (YouTube)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Related articles section"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Sidebar ad placement (desktop only)"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"76-authentication--dashboard",children:"7.6 Authentication & Dashboard"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Registration page and flow"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Login page with error handling"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Password reset flow (if implementing)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Session management (cookies, CSRF)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Dashboard layout with sidebar"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","My Tools tab with tool list"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Connections tab with app pairing flow"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Settings tab with profile edit"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",checked:!0,disabled:!0})," ","Logout functionality"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"77-privacy--consent",children:"7.7 Privacy & Consent"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Cookie consent banner"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Consent preferences modal"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Consent state storage"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Privacy policy page"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Terms of service page"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Honor consent in analytics/ad loading"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"78-ads--monetization",children:"7.8 Ads & Monetization"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","AdSense integration (account setup)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Ad container components"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Lazy loading for ad scripts"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Ad placement rules enforcement"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Sponsored content styling (if applicable)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Donate page with donation options"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"79-seo--performance",children:"7.9 SEO & Performance"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Meta tags for all page types"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Open Graph tags"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Schema.org structured data"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Sitemap generation"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","robots.txt configuration"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Canonical URL implementation"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Image optimization pipeline"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","CSS/JS minification"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Critical CSS inlining"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Lazy loading for images"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"710-testing--qa",children:"7.10 Testing & QA"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Responsive design testing (all breakpoints)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Accessibility testing (WCAG 2.1 AA)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Cross-browser testing (Chrome, Firefox, Safari, Edge)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Performance testing (Lighthouse scores)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Form validation testing"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Error state testing"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Mobile usability testing"]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"711-launch-preparation",children:"7.11 Launch Preparation"}),"\n",(0,l.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Content creation (initial docs, tutorials)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Seed featured tools selection"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Initial contributor spotlight"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Analytics setup (privacy-respecting)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Error monitoring (Sentry or similar)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","SSL certificate configuration"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","CDN setup (optional)"]}),"\n",(0,l.jsxs)(n.li,{className:"task-list-item",children:[(0,l.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Backup and recovery procedures"]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"api-endpoints-for-web-ui",children:"API Endpoints for Web UI"}),"\n",(0,l.jsx)(n.p,{children:"The web UI consumes these existing API endpoints:"}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Public (read-only):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/tools"})," - List tools with pagination/filters"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/tools/search?q=..."})," - Search tools"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/tools/{owner}/{name}"})," - Tool details"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/tools/{owner}/{name}/versions"})," - Version list"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/categories"})," - Category list"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/stats/popular"})," - Popular tools"]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"Authenticated (dashboard):"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"POST /api/v1/login"})," - User login (returns session)"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"POST /api/v1/register"})," - User registration"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/me/tools"})," - User's published tools"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/pairing/connected-apps"})," - List connected apps"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"POST /api/v1/pairing/initiate"})," - Start app pairing flow"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/pairing/status"})," - Get pending pairing requests"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"POST /api/v1/pairing/claim/{pairing_id}"})," - Approve a pending connection"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"DELETE /api/v1/tokens/{id}"})," - Disconnect/revoke an app"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"PUT /api/v1/me/settings"})," - Update profile"]}),"\n"]}),"\n",(0,l.jsx)(n.p,{children:(0,l.jsx)(n.strong,{children:"New endpoints for web UI:"})}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/featured/tools"})," - Curated featured tools"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/featured/contributors"})," - Featured contributor"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"GET /api/v1/content/announcements"})," - Site announcements"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.code,{children:"POST /api/v1/reports"})," - Abuse report submission"]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"diagram-references",children:"Diagram References"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["Landing page mockup: ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_6.svg"})]}),"\n",(0,l.jsxs)(n.li,{children:["System overview: ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_1.puml"})]}),"\n",(0,l.jsxs)(n.li,{children:["Data flows: ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-registry_rob_5.puml"})]}),"\n",(0,l.jsxs)(n.li,{children:["Web UI strategy: ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-web-ui-strategy.puml"})]}),"\n",(0,l.jsxs)(n.li,{children:["UI visual strategy: ",(0,l.jsx)(n.code,{children:"discussions/diagrams/cmdforge-web-ui-visual-strategy.puml"})]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"deployment-guide",children:"Deployment Guide"}),"\n",(0,l.jsx)(n.h3,{id:"requirements",children:"Requirements"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:"Python 3.11+"}),"\n",(0,l.jsx)(n.li,{children:"pip/virtualenv"}),"\n",(0,l.jsx)(n.li,{children:"SQLite 3 (included with Python)"}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"quick-start-development",children:"Quick Start (Development)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'# Clone the repository\ngit clone https://gitea.brrd.tech/rob/CmdForge.git\ncd CmdForge\n\n# Create virtual environment\npython3 -m venv venv\nsource venv/bin/activate\n\n# Install with registry extras\npip install -e ".[registry]"\n\n# Run the web server\npython -m cmdforge.web.app\n'})}),"\n",(0,l.jsxs)(n.p,{children:["The server will start on ",(0,l.jsx)(n.code,{children:"http://localhost:5000"}),"."]}),"\n",(0,l.jsx)(n.h3,{id:"production-deployment",children:"Production Deployment"}),"\n",(0,l.jsx)(n.h4,{id:"1-environment-variables",children:"1. Environment Variables"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"# Required\nexport CMDFORGE_REGISTRY_DB=/path/to/registry.db\nexport PORT=5050\n\n# Optional\nexport CMDFORGE_ENV=production # Enables secure cookies\nexport CMDFORGE_SHOW_ADS=true # Enable ad placeholders\n"})}),"\n",(0,l.jsx)(n.h4,{id:"2-database-location",children:"2. Database Location"}),"\n",(0,l.jsxs)(n.p,{children:["By default, the registry uses ",(0,l.jsx)(n.code,{children:"~/.cmdforge/registry.db"}),". For production:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"# Create dedicated directory\nmkdir -p /var/lib/cmdforge\nexport CMDFORGE_REGISTRY_DB=/var/lib/cmdforge/registry.db\n"})}),"\n",(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.strong,{children:"Note"}),": If using a merged filesystem (e.g., mergerfs), store the database on a single disk or in ",(0,l.jsx)(n.code,{children:"/tmp"})," to avoid SQLite WAL mode issues:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"export CMDFORGE_REGISTRY_DB=/tmp/cmdforge-registry/registry.db\n"})}),"\n",(0,l.jsx)(n.h4,{id:"3-running-with-systemd",children:"3. Running with systemd"}),"\n",(0,l.jsxs)(n.p,{children:["Create ",(0,l.jsx)(n.code,{children:"/etc/systemd/system/cmdforge-registry.service"}),":"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-ini",children:"[Unit]\nDescription=CmdForge Registry Web Server\nAfter=network.target\n\n[Service]\nType=simple\nUser=cmdforge\nWorkingDirectory=/opt/cmdforge\nEnvironment=CMDFORGE_REGISTRY_DB=/var/lib/cmdforge/registry.db\nEnvironment=PORT=5050\nEnvironment=CMDFORGE_ENV=production\nExecStart=/opt/cmdforge/venv/bin/python -m cmdforge.web.app\nRestart=always\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\n"})}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"sudo systemctl daemon-reload\nsudo systemctl enable cmdforge-registry\nsudo systemctl start cmdforge-registry\n"})}),"\n",(0,l.jsx)(n.h4,{id:"4-reverse-proxy-nginx",children:"4. Reverse Proxy (nginx)"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-nginx",children:'server {\n listen 80;\n server_name cmdforge.brrd.tech;\n\n location / {\n proxy_pass http://127.0.0.1:5050;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n }\n\n location /static {\n alias /opt/cmdforge/src/cmdforge/web/static;\n expires 1y;\n add_header Cache-Control "public, immutable";\n }\n}\n'})}),"\n",(0,l.jsx)(n.h4,{id:"5-ssl-with-certbot",children:"5. SSL with Certbot"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"sudo certbot --nginx -d cmdforge.brrd.tech\n"})}),"\n",(0,l.jsx)(n.h3,{id:"tailwind-css-build",children:"Tailwind CSS Build"}),"\n",(0,l.jsx)(n.p,{children:"The CSS is pre-built and committed. To rebuild after changes:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"# Install dependencies\nnpm install\n\n# Build for production\nnpx tailwindcss -i src/cmdforge/web/static/css/input.css \\\n -o src/cmdforge/web/static/css/main.css \\\n --minify\n"})}),"\n",(0,l.jsx)(n.h3,{id:"health-check",children:"Health Check"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'curl http://localhost:5050/api/v1/tools\n# Returns: {"data":[],"meta":{"page":1,"per_page":20,"total":0,"total_pages":1}}\n'})}),"\n",(0,l.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Issue"}),(0,l.jsx)(n.th,{children:"Solution"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"disk I/O error"})}),(0,l.jsx)(n.td,{children:"Move database to non-merged filesystem"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Port already in use"}),(0,l.jsx)(n.td,{children:"Change PORT environment variable"})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"500 errors"}),(0,l.jsxs)(n.td,{children:["Check ",(0,l.jsx)(n.code,{children:"/tmp/cmdforge.log"})," for stack traces"]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:"Static files not loading"}),(0,l.jsx)(n.td,{children:"Verify static folder path in deployment"})]})]})]}),"\n",(0,l.jsx)(n.h2,{id:"future-considerations-phase-8",children:"Future Considerations (Phase 8+)"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Forum integration"}),": External (Discourse) or built-in discussions"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Newsletter signup"}),": Email collection with double opt-in"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"A/B testing"}),": Hero messaging, CTA variations"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Analytics dashboard"}),": Traffic insights for publishers"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Premium features"}),": Private registries, enhanced analytics"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Internationalization"}),": Multi-language support"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"Dark mode"}),": Theme toggle with persistence"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.strong,{children:"PWA features"}),": Offline support, install prompt"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(a,{...e})}):a(e)}},8453(e,n,i){i.d(n,{R:()=>t,x:()=>d});var s=i(6540);const l={},r=s.createContext(l);function t(e){const n=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:t(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/main.6f2cae7a.js b/assets/js/main.6f2cae7a.js new file mode 100644 index 0000000..85b6a31 --- /dev/null +++ b/assets/js/main.6f2cae7a.js @@ -0,0 +1,2 @@ +/*! For license information please see main.6f2cae7a.js.LICENSE.txt */ +(globalThis.webpackChunkproject_public_docs=globalThis.webpackChunkproject_public_docs||[]).push([[792],{8328(e,t,n){"use strict";n.d(t,{A:()=>f});n(6540);var r=n(3259),o=n.n(r),a=n(4054);const i={17896441:[()=>Promise.all([n.e(869),n.e(401)]).then(n.bind(n,8252)),"@theme/DocItem",8252],"1db64337":[()=>n.e(413).then(n.bind(n,6785)),"@site/docs/overview.md",6785],"3fbf7384":[()=>n.e(854).then(n.t.bind(n,5253,19)),"@generated/docusaurus-plugin-content-docs/default/p/rob-cmd-forge-3f4.json",5253],"5281b7a2":[()=>n.e(443).then(n.bind(n,936)),"@site/docs/architecture.md",936],"5e95c892":[()=>n.e(647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"5eebbccf":[()=>n.e(894).then(n.bind(n,7836)),"@site/docs/goals.md",7836],"817f7194":[()=>n.e(574).then(n.bind(n,921)),"@site/docs/milestones.md",921],a7bd4aaa:[()=>n.e(98).then(n.bind(n,1723)),"@theme/DocVersionRoot",1723],a94703ab:[()=>Promise.all([n.e(869),n.e(48)]).then(n.bind(n,8115)),"@theme/DocRoot",8115],aba21aa0:[()=>n.e(742).then(n.t.bind(n,7093,19)),"@generated/docusaurus-plugin-content-docs/default/__plugin.json",7093],e719f3dc:[()=>n.e(207).then(n.bind(n,7271)),"@site/docs/ideas-and-exploration.md",7271]};var l=n(4848);function s({error:e,retry:t,pastDelay:n}){return e?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(e)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:t,children:"Retry"})})]}):n?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var u=n(6921),c=n(3102);function d(e,t){if("*"===e)return o()({loading:s,loader:()=>n.e(237).then(n.bind(n,2237)),modules:["@theme/NotFound"],webpack:()=>[2237],render(e,t){const n=e.default;return(0,l.jsx)(c.W,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=a[`${e}-${t}`],d={},f=[],p=[],m=(0,u.A)(r);return Object.entries(m).forEach(([e,t])=>{const n=i[t];n&&(d[e]=n[0],f.push(n[1]),p.push(n[2]))}),o().Map({loading:s,loader:d,modules:f,webpack:()=>p,render(t,n){const o=JSON.parse(JSON.stringify(r));Object.entries(t).forEach(([t,n])=>{const r=n.default;if(!r)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof r&&"function"!=typeof r||Object.keys(n).filter(e=>"default"!==e).forEach(e=>{r[e]=n[e]});let a=o;const i=t.split(".");i.slice(0,-1).forEach(e=>{a=a[e]}),a[i[i.length-1]]=r});const a=o.__comp;delete o.__comp;const i=o.__context;delete o.__context;const s=o.__props;return delete o.__props,(0,l.jsx)(c.W,{value:i,children:(0,l.jsx)(a,{...o,...s,...n})})}})}const f=[{path:"/rob/CmdForge/",component:d("/rob/CmdForge/","90d"),routes:[{path:"/rob/CmdForge/",component:d("/rob/CmdForge/","9e8"),routes:[{path:"/rob/CmdForge/",component:d("/rob/CmdForge/","a10"),routes:[{path:"/rob/CmdForge/architecture/",component:d("/rob/CmdForge/architecture/","66c"),exact:!0,sidebar:"docs"},{path:"/rob/CmdForge/goals/",component:d("/rob/CmdForge/goals/","119"),exact:!0,sidebar:"docs"},{path:"/rob/CmdForge/ideas-and-exploration/",component:d("/rob/CmdForge/ideas-and-exploration/","4fe"),exact:!0,sidebar:"docs"},{path:"/rob/CmdForge/milestones/",component:d("/rob/CmdForge/milestones/","979"),exact:!0,sidebar:"docs"},{path:"/rob/CmdForge/",component:d("/rob/CmdForge/","cc6"),exact:!0,sidebar:"docs"}]}]}]},{path:"*",component:d("*")}]},6125(e,t,n){"use strict";n.d(t,{o:()=>a,x:()=>i});var r=n(6540),o=n(4848);const a=r.createContext(!1);function i({children:e}){const[t,n]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{n(!0)},[]),(0,o.jsx)(a.Provider,{value:t,children:e})}},8600(e,t,n){"use strict";var r=n(6540),o=n(5338),a=n(545),i=n(4625),l=n(4784),s=n(8193);const u=[n(119),n(6134),n(6294),n(1043)];var c=n(8328),d=n(6347),f=n(2831),p=n(4848);function m({children:e}){return(0,p.jsx)(p.Fragment,{children:e})}var h=n(4563);const g=e=>e.defaultFormatter(e);function y({children:e}){return(0,p.jsx)(h.AL,{formatter:g,children:e})}function b({children:e}){return(0,p.jsx)(y,{children:e})}var v=n(5260),w=n(4586),k=n(6025),S=n(6342),x=n(5500),E=n(2131),C=n(4090);var A=n(440),_=n(1463);function T(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,w.A)(),r=(0,E.o)(),o=n[e].htmlLang,a=e=>e.replace("-","_");return(0,p.jsxs)(v.A,{children:[Object.entries(n).map(([e,{htmlLang:t}])=>(0,p.jsx)("link",{rel:"alternate",href:r.createUrl({locale:e,fullyQualified:!0}),hrefLang:t},e)),(0,p.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,p.jsx)("meta",{property:"og:locale",content:a(o)}),Object.values(n).filter(e=>o!==e.htmlLang).map(e=>(0,p.jsx)("meta",{property:"og:locale:alternate",content:a(e.htmlLang)},`meta-og-${e.htmlLang}`))]})}function j({permalink:e}){const{siteConfig:{url:t}}=(0,w.A)(),n=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,w.A)(),{pathname:r}=(0,d.zy)();return e+(0,A.Ks)((0,k.Ay)(r),{trailingSlash:n,baseUrl:t})}(),r=e?`${t}${e}`:n;return(0,p.jsxs)(v.A,{children:[(0,p.jsx)("meta",{property:"og:url",content:r}),(0,p.jsx)("link",{rel:"canonical",href:r})]})}function P(){const{i18n:{currentLocale:e}}=(0,w.A)(),{metadata:t,image:n}=(0,S.p)();return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsxs)(v.A,{children:[(0,p.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,p.jsx)("body",{className:C.w})]}),n&&(0,p.jsx)(x.be,{image:n}),(0,p.jsx)(j,{}),(0,p.jsx)(T,{}),(0,p.jsx)(_.A,{tag:"default",locale:e}),(0,p.jsx)(v.A,{children:t.map((e,t)=>(0,p.jsx)("meta",{...e},t))})]})}const L=new Map;var N=n(6125),O=n(6988),R=n(205);function D(e,...t){const n=u.map(n=>{const r=n.default?.[e]??n[e];return r?.(...t)});return()=>n.forEach(e=>e?.())}const F=function({children:e,location:t,previousLocation:n}){return(0,R.A)(()=>{n!==t&&(!function({location:e,previousLocation:t}){if(!t)return;const n=e.pathname===t.pathname,r=e.hash===t.hash,o=e.search===t.search;if(n&&r&&!o)return;const{hash:a}=e;if(a){const e=decodeURIComponent(a.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:t,previousLocation:n}),D("onRouteDidUpdate",{previousLocation:n,location:t}))},[n,t]),e};function I(e){const t=Array.from(new Set([e,decodeURI(e)])).map(e=>(0,f.u)(c.A,e)).flat();return Promise.all(t.map(e=>e.route.component.preload?.()))}class M extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=s.A.canUseDOM?D("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=D("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),I(n.pathname).then(()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})}).catch(e=>{console.warn(e),window.location.reload()}),!1}render(){const{children:e,location:t}=this.props;return(0,p.jsx)(F,{previousLocation:this.previousLocation,location:t,children:(0,p.jsx)(d.qh,{location:t,render:()=>e})})}}const z=M,B="__docusaurus-base-url-issue-banner-suggestion-container";function $(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '__docusaurus-base-url-issue-banner-container';\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/!0===e.exact))return L.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return L.set(e.pathname,t),{...e,pathname:t}}((0,d.zy)());return(0,p.jsx)(z,{location:e,children:Q})}function Y(){return(0,p.jsx)(G.A,{children:(0,p.jsx)(O.l,{children:(0,p.jsxs)(N.x,{children:[(0,p.jsx)(m,{children:(0,p.jsxs)(b,{children:[(0,p.jsx)(H,{}),(0,p.jsx)(P,{}),(0,p.jsx)(q,{}),(0,p.jsx)(K,{})]})}),(0,p.jsx)(W,{})]})})})}var X=n(4054);const Z=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const o=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;o?.appendChild(r)})}:function(e){return new Promise((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)})};var J=n(6921);const ee=new Set,te=new Set,ne=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,re={prefetch:e=>{if(!(e=>!ne()&&!te.has(e)&&!ee.has(e))(e))return!1;ee.add(e);const t=(0,f.u)(c.A,e).flatMap(e=>{return t=e.route.path,Object.entries(X).filter(([e])=>e.replace(/-[^-]+$/,"")===t).flatMap(([,e])=>Object.values((0,J.A)(e)));var t});return Promise.all(t.map(e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Z(t).catch(()=>{}):Promise.resolve()}))},preload:e=>!!(e=>!ne()&&!te.has(e))(e)&&(te.add(e),I(e))},oe=Object.freeze(re);function ae({children:e}){return"hash"===l.A.future.experimental_router?(0,p.jsx)(i.I9,{children:e}):(0,p.jsx)(i.Kd,{children:e})}const ie=Boolean(!0);if(s.A.canUseDOM){window.docusaurus=oe;const e=document.getElementById("__docusaurus"),t=(0,p.jsx)(a.vd,{children:(0,p.jsx)(ae,{children:(0,p.jsx)(Y,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},i=()=>{if(window.docusaurusRoot)window.docusaurusRoot.render(t);else if(ie)window.docusaurusRoot=o.hydrateRoot(e,t,{onRecoverableError:n});else{const r=o.createRoot(e,{onRecoverableError:n});r.render(t),window.docusaurusRoot=r}};I(window.location.pathname).then(()=>{(0,r.startTransition)(i)})}},6988(e,t,n){"use strict";n.d(t,{o:()=>d,l:()=>f});var r=n(6540),o=n(4784);const a=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/rob/CmdForge/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/rob/CmdForge/","mainDocId":"overview","docs":[{"id":"architecture","path":"/rob/CmdForge/architecture","sidebar":"docs"},{"id":"goals","path":"/rob/CmdForge/goals","sidebar":"docs"},{"id":"ideas-and-exploration","path":"/rob/CmdForge/ideas-and-exploration","sidebar":"docs"},{"id":"milestones","path":"/rob/CmdForge/milestones","sidebar":"docs"},{"id":"overview","path":"/rob/CmdForge/","sidebar":"docs"}],"draftIds":[],"sidebars":{"docs":{"link":{"path":"/rob/CmdForge/","label":"overview"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en","translate":false,"url":"https://pages.brrd.tech","baseUrl":"/rob/CmdForge/"}}}');var l=n(2654);const s=JSON.parse('{"docusaurusVersion":"3.9.2","siteVersion":"1.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.9.2"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.9.2"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.9.2"},"docusaurus-plugin-svgr":{"type":"package","name":"@docusaurus/plugin-svgr","version":"3.9.2"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.9.2"}}}');var u=n(4848);const c={siteConfig:o.A,siteMetadata:s,globalData:a,i18n:i,codeTranslations:l},d=r.createContext(c);function f({children:e}){return(0,u.jsx)(d.Provider,{value:c,children:e})}},7489(e,t,n){"use strict";n.d(t,{A:()=>h});var r=n(6540),o=n(8193),a=n(5260),i=n(440),l=n(1656),s=n(3102),u=n(4848);function c({error:e,tryAgain:t}){return(0,u.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,u.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,u.jsx)("button",{type:"button",onClick:t,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,u.jsx)(d,{error:e})]})}function d({error:e}){const t=(0,i.rA)(e).map(e=>e.message).join("\n\nCause:\n");return(0,u.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:t})}function f({children:e}){return(0,u.jsx)(s.W,{value:{plugin:{name:"docusaurus-core-error-boundary",id:"default"}},children:e})}function p({error:e,tryAgain:t}){return(0,u.jsx)(f,{children:(0,u.jsxs)(h,{fallback:()=>(0,u.jsx)(c,{error:e,tryAgain:t}),children:[(0,u.jsx)(a.A,{children:(0,u.jsx)("title",{children:"Page Error"})}),(0,u.jsx)(l.A,{children:(0,u.jsx)(c,{error:e,tryAgain:t})})]})})}const m=e=>(0,u.jsx)(p,{...e});class h extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){o.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??m)(e)}return e??null}}},8193(e,t,n){"use strict";n.d(t,{A:()=>o});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,o={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5260(e,t,n){"use strict";n.d(t,{A:()=>a});n(6540);var r=n(545),o=n(4848);function a(e){return(0,o.jsx)(r.mg,{...e})}},8774(e,t,n){"use strict";n.d(t,{A:()=>p});var r=n(6540),o=n(4625),a=n(440),i=n(4586),l=n(6654),s=n(8193),u=n(3427),c=n(6025),d=n(4848);function f({isNavLink:e,to:t,href:n,activeClassName:f,isActive:p,"data-noBrokenLinkCheck":m,autoAddBaseUrl:h=!0,...g},y){const{siteConfig:b}=(0,i.A)(),{trailingSlash:v,baseUrl:w}=b,k=b.future.experimental_router,{withBaseUrl:S}=(0,c.hH)(),x=(0,u.A)(),E=(0,r.useRef)(null);(0,r.useImperativeHandle)(y,()=>E.current);const C=t||n;const A=(0,l.A)(C),_=C?.replace("pathname://","");let T=void 0!==_?(j=_,h&&(e=>e.startsWith("/"))(j)?S(j):j):void 0;var j;"hash"===k&&T?.startsWith("./")&&(T=T?.slice(1)),T&&A&&(T=(0,a.Ks)(T,{trailingSlash:v,baseUrl:w}));const P=(0,r.useRef)(!1),L=e?o.k2:o.N_,N=s.A.canUseIntersectionObserver,O=(0,r.useRef)(),R=()=>{P.current||null==T||(window.docusaurus.preload(T),P.current=!0)};(0,r.useEffect)(()=>(!N&&A&&s.A.canUseDOM&&null!=T&&window.docusaurus.prefetch(T),()=>{N&&O.current&&O.current.disconnect()}),[O,T,N,A]);const D=T?.startsWith("#")??!1,F=!g.target||"_self"===g.target,I=!T||!A||!F||D&&"hash"!==k;m||!D&&I||x.collectLink(T),g.id&&x.collectAnchor(g.id);const M={};return I?(0,d.jsx)("a",{ref:E,href:T,...C&&!A&&{target:"_blank",rel:"noopener noreferrer"},...g,...M}):(0,d.jsx)(L,{...g,onMouseEnter:R,onTouchStart:R,innerRef:e=>{E.current=e,N&&e&&A&&(O.current=new window.IntersectionObserver(t=>{t.forEach(t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(O.current.unobserve(e),O.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))})}),O.current.observe(e))},to:T,...e&&{isActive:p,activeClassName:f},...M})}const p=r.forwardRef(f)},418(e,t,n){"use strict";n.d(t,{A:()=>r});const r=()=>null},1312(e,t,n){"use strict";n.d(t,{A:()=>u,T:()=>s});var r=n(6540),o=n(4848);function a(e,t){const n=e.split(/(\{\w+\})/).map((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e});return n.some(e=>(0,r.isValidElement)(e))?n.map((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e).filter(e=>""!==e):n.join("")}var i=n(2654);function l({id:e,message:t}){if(void 0===e&&void 0===t)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[e??t]??t??e}function s({message:e,id:t},n){return a(l({message:e,id:t}),n)}function u({children:e,id:t,values:n}){if(e&&"string"!=typeof e)throw console.warn("Illegal children",e),new Error("The Docusaurus component only accept simple string values");const r=l({message:e,id:t});return(0,o.jsx)(o.Fragment,{children:a(r,n)})}},7065(e,t,n){"use strict";n.d(t,{W:()=>r});const r="default"},6654(e,t,n){"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function o(e){return void 0!==e&&!r(e)}n.d(t,{A:()=>o,z:()=>r})},6025(e,t,n){"use strict";n.d(t,{Ay:()=>l,hH:()=>i});var r=n(6540),o=n(4586),a=n(6654);function i(){const{siteConfig:e}=(0,o.A)(),{baseUrl:t,url:n}=e,i=e.future.experimental_router,l=(0,r.useCallback)((e,r)=>function({siteUrl:e,baseUrl:t,url:n,options:{forcePrependBaseUrl:r=!1,absolute:o=!1}={},router:i}){if(!n||n.startsWith("#")||(0,a.z)(n))return n;if("hash"===i)return n.startsWith("/")?`.${n}`:`./${n}`;if(r)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return o?e+l:l}({siteUrl:n,baseUrl:t,url:e,options:r,router:i}),[n,t,i]);return{withBaseUrl:l}}function l(e,t={}){const{withBaseUrl:n}=i();return n(e,t)}},3427(e,t,n){"use strict";n.d(t,{A:()=>a});var r=n(6540);n(4848);const o=r.createContext({collectAnchor:()=>{},collectLink:()=>{}});function a(){return(0,r.useContext)(o)}},4586(e,t,n){"use strict";n.d(t,{A:()=>a});var r=n(6540),o=n(6988);function a(){return(0,r.useContext)(o.o)}},2303(e,t,n){"use strict";n.d(t,{A:()=>a});var r=n(6540),o=n(6125);function a(){return(0,r.useContext)(o.o)}},205(e,t,n){"use strict";n.d(t,{A:()=>o});var r=n(6540);const o=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect},6803(e,t,n){"use strict";n.d(t,{A:()=>a});var r=n(6540),o=n(3102);function a(){const e=r.useContext(o.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}},6921(e,t,n){"use strict";n.d(t,{A:()=>r});function r(e){const t={};return function e(n,r){Object.entries(n).forEach(([n,o])=>{const a=r?`${r}.${n}`:n;var i;"object"==typeof(i=o)&&i&&Object.keys(i).length>0?e(o,a):t[a]=o})}(e),t}},3102(e,t,n){"use strict";n.d(t,{W:()=>i,o:()=>a});var r=n(6540),o=n(4848);const a=r.createContext(null);function i({children:e,value:t}){const n=r.useContext(a),i=(0,r.useMemo)(()=>function({parent:e,value:t}){if(!e){if(!t)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in t))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return t}const n={...e.data,...t?.data};return{plugin:e.plugin,data:n}}({parent:n,value:t}),[n,t]);return(0,o.jsx)(a.Provider,{value:i,children:e})}},3886(e,t,n){"use strict";n.d(t,{VQ:()=>y,g1:()=>v});var r=n(6540),o=n(4070),a=n(7065),i=n(6342),l=n(679),s=n(9532),u=n(4848);const c=e=>`docs-preferred-version-${e}`,d=(e,t,n)=>{(0,l.Wf)(c(e),{persistence:t}).set(n)},f=(e,t)=>(0,l.Wf)(c(e),{persistence:t}).get(),p=(e,t)=>{(0,l.Wf)(c(e),{persistence:t}).del()};const m=r.createContext(null);function h(){const e=(0,o.Gy)(),t=(0,i.p)().docs.versionPersistence,n=(0,r.useMemo)(()=>Object.keys(e),[e]),[a,l]=(0,r.useState)(()=>(e=>Object.fromEntries(e.map(e=>[e,{preferredVersionName:null}])))(n));(0,r.useEffect)(()=>{l(function({pluginIds:e,versionPersistence:t,allDocsData:n}){function r(e){const r=f(e,t);return n[e].versions.some(e=>e.name===r)?{preferredVersionName:r}:(p(e,t),{preferredVersionName:null})}return Object.fromEntries(e.map(e=>[e,r(e)]))}({allDocsData:e,versionPersistence:t,pluginIds:n}))},[e,t,n]);return[a,(0,r.useMemo)(()=>({savePreferredVersion:function(e,n){d(e,t,n),l(t=>({...t,[e]:{preferredVersionName:n}}))}}),[t])]}function g({children:e}){const t=h();return(0,u.jsx)(m.Provider,{value:t,children:e})}function y({children:e}){return(0,u.jsx)(g,{children:e})}function b(){const e=(0,r.useContext)(m);if(!e)throw new s.dV("DocsPreferredVersionContextProvider");return e}function v(e=a.W){const t=(0,o.ht)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find(e=>e.name===l)??null,savePreferredVersionName:(0,r.useCallback)(t=>{i.savePreferredVersion(e,t)},[i,e])}}},609(e,t,n){"use strict";n.d(t,{V:()=>s,t:()=>u});var r=n(6540),o=n(9532),a=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s({children:e,name:t,items:n}){const o=(0,r.useMemo)(()=>t&&n?{name:t,items:n}:null,[t,n]);return(0,a.jsx)(l.Provider,{value:o,children:e})}function u(){const e=(0,r.useContext)(l);if(e===i)throw new o.dV("DocsSidebarProvider");return e}},4718(e,t,n){"use strict";n.d(t,{Nr:()=>f,w8:()=>m,B5:()=>S,Vd:()=>v,QB:()=>k,fW:()=>w,OF:()=>b,Y:()=>g});var r=n(6540),o=n(6347),a=n(2831),i=n(4070),l=n(9169);function s(e){return Array.from(new Set(e))}var u=n(3886),c=n(3025),d=n(609);function f(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=f(t);if(e)return e}}(e):void 0:e.href}const p=(e,t)=>void 0!==e&&(0,l.ys)(e,t);function m(e,t){return"link"===e.type?p(e.href,t):"category"===e.type&&(p(e.href,t)||((e,t)=>e.some(e=>m(e,t)))(e.items,t))}function h(e,t){switch(e.type){case"category":return m(e,t)||void 0!==e.href&&!e.linkUnlisted||e.items.some(e=>h(e,t));case"link":return!e.unlisted||m(e,t);default:return!0}}function g(e,t){return(0,r.useMemo)(()=>e.filter(e=>h(e,t)),[e,t])}function y({sidebarItems:e,pathname:t,onlyCategories:n=!1}){const r=[];return function e(o){for(const a of o)if("category"===a.type&&((0,l.ys)(a.href,t)||e(a.items))||"link"===a.type&&(0,l.ys)(a.href,t)){return n&&"category"!==a.type||r.unshift(a),!0}return!1}(e),r}function b(){const e=(0,d.t)(),{pathname:t}=(0,o.zy)(),n=(0,i.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,i.zK)(e),{preferredVersion:n}=(0,u.g1)(e),o=(0,i.r7)(e);return(0,r.useMemo)(()=>s([t,n,o].filter(Boolean)),[t,n,o])}function w(e,t){const n=v(t);return(0,r.useMemo)(()=>{const t=n.flatMap(e=>e.sidebars?Object.entries(e.sidebars):[]),r=t.find(t=>t[0]===e);if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map(e=>e.name).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map(e=>e[0]).join("\n- ")}`);return r[1]},[e,n])}function k(e,t){const n=v(t);return(0,r.useMemo)(()=>{const t=n.flatMap(e=>e.docs),r=t.find(t=>t.id===e);if(!r){if(n.flatMap(e=>e.draftIds).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map(e=>e.name).join(", ")}".\nAvailable doc ids are:\n- ${s(t.map(e=>e.id)).join("\n- ")}`)}return r},[e,n])}function S({route:e}){const t=(0,o.zy)(),n=(0,c.r)(),r=e.routes,i=r.find(e=>(0,o.B6)(t.pathname,e));if(!i)return null;const l=i.sidebar,s=l?n.docsSidebars[l]:void 0;return{docElement:(0,a.v)(r),sidebarName:l,sidebarItems:s}}},3025(e,t,n){"use strict";n.d(t,{n:()=>l,r:()=>s});var r=n(6540),o=n(9532),a=n(4848);const i=r.createContext(null);function l({children:e,version:t}){return(0,a.jsx)(i.Provider,{value:t,children:e})}function s(){const e=(0,r.useContext)(i);if(null===e)throw new o.dV("DocsVersionProvider");return e}},4070(e,t,n){"use strict";n.d(t,{zK:()=>h,vT:()=>f,Gy:()=>c,HW:()=>g,ht:()=>d,r7:()=>m,jh:()=>p});var r=n(6347),o=n(4586),a=n(7065);function i(e,t={}){const n=function(){const{globalData:e}=(0,o.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find(e=>e.isLast);function s(e,t){const n=function(e,t){return[...e.versions].sort((e,t)=>e.path===t.path?0:e.path.includes(t.path)?-1:t.path.includes(e.path)?1:0).find(e=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1}))}(e,t),o=n?.docs.find(e=>!!(0,r.B6)(t,{path:e.path,exact:!0,strict:!1}));return{activeVersion:n,activeDoc:o,alternateDocVersions:o?function(t){const n={};return e.versions.forEach(e=>{e.docs.forEach(r=>{r.id===t&&(n[e.name]=r)})}),n}(o.id):{}}}const u={},c=()=>i("docusaurus-plugin-content-docs")??u,d=e=>{try{return function(e,t=a.W,n={}){const r=i(e),o=r?.[t];if(!o&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return o}("docusaurus-plugin-content-docs",e,{failfast:!0})}catch(t){throw new Error("You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled"+("Default"===e?"":` (pluginId=${e}`),{cause:t})}};function f(e={}){const t=c(),{pathname:n}=(0,r.zy)();return function(e,t,n={}){const o=Object.entries(e).sort((e,t)=>t[1].path.localeCompare(e[1].path)).find(([,e])=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1})),a=o?{pluginId:o[0],pluginData:o[1]}:void 0;if(!a&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map(e=>e.path).join(", ")}`);return a}(t,n,e)}function p(e){return d(e).versions}function m(e){const t=d(e);return l(t)}function h(e){const t=d(e),{pathname:n}=(0,r.zy)();return s(t,n)}function g(e){const t=d(e),{pathname:n}=(0,r.zy)();return function(e,t){const n=l(e);return{latestDocSuggestion:s(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6294(e,t,n){"use strict";n.r(t),n.d(t,{default:()=>a});var r=n(5947),o=n.n(r);o().configure({showSpinner:!1});const a={onRouteUpdate({location:e,previousLocation:t}){if(t&&e.pathname!==t.pathname){const e=window.setTimeout(()=>{o().start()},200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){o().done()}}},6134(e,t,n){"use strict";var r=n(1765),o=n(4784);!function(e){const{themeConfig:{prism:t}}=o.A,{additionalLanguages:r}=t,a=globalThis.Prism;globalThis.Prism=e,r.forEach(e=>{"php"===e&&n(9700),n(6018)(`./prism-${e}`)}),delete globalThis.Prism,void 0!==a&&(globalThis.Prism=e)}(r.My)},1107(e,t,n){"use strict";n.d(t,{A:()=>u});n(6540);var r=n(4164),o=n(1312),a=n(3535),i=n(8774),l=n(3427),s=n(4848);function u({as:e,id:t,...n}){const u=(0,l.A)(),c=(0,a.v)(t);if("h1"===e||!t)return(0,s.jsx)(e,{...n,id:void 0});u.collectAnchor(t);const d=(0,o.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof n.children?n.children:t});return(0,s.jsxs)(e,{...n,className:(0,r.A)("anchor",c,n.className),id:t,children:[n.children,(0,s.jsx)(i.A,{className:"hash-link",to:`#${t}`,"aria-label":d,title:d,translate:"no",children:"\u200b"})]})}},3186(e,t,n){"use strict";n.d(t,{A:()=>i});n(6540);var r=n(1312);const o="iconExternalLink_nPIU";var a=n(4848);function i({width:e=13.5,height:t=13.5}){return(0,a.jsx)("svg",{width:e,height:t,"aria-label":(0,r.T)({id:"theme.IconExternalLink.ariaLabel",message:"(opens in new tab)",description:"The ARIA label for the external link icon"}),className:o,children:(0,a.jsx)("use",{href:"#theme-svg-external-link"})})}},1656(e,t,n){"use strict";n.d(t,{A:()=>Nt});var r=n(6540),o=n(4164),a=n(7489),i=n(5500),l=n(6347),s=n(1312),u=n(5062),c=n(4848);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,l.W6)(),n=(0,r.useCallback)(e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)},[]);return(0,u.$)(({location:n})=>{e.current&&!n.hash&&"PUSH"===t&&f(e.current)}),{containerRef:e,onClick:n}}const m=(0,s.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:r}=p();return(0,c.jsx)("div",{ref:n,role:"region","aria-label":m,children:(0,c.jsx)("a",{...e,href:`#${d}`,onClick:r,children:t})})}var g=n(7559),y=n(4090);const b="skipToContent_fXgn";function v(){return(0,c.jsx)(h,{className:b})}var w=n(6342),k=n(5041);function S({width:e=21,height:t=21,color:n="currentColor",strokeWidth:r=1.2,className:o,...a}){return(0,c.jsx)("svg",{viewBox:"0 0 15 15",width:e,height:t,...a,children:(0,c.jsx)("g",{stroke:n,strokeWidth:r,children:(0,c.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const x="closeButton_CVFx";function E(e){return(0,c.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,o.A)("clean-btn close",x,e.className),children:(0,c.jsx)(S,{width:14,height:14,strokeWidth:3.1})})}const C="content_knG7";function A(e){const{announcementBar:t}=(0,w.p)(),{content:n}=t;return(0,c.jsx)("div",{...e,className:(0,o.A)(C,e.className),dangerouslySetInnerHTML:{__html:n}})}const _="announcementBar_mb4j",T="announcementBarPlaceholder_vyr4",j="announcementBarClose_gvF7",P="announcementBarContent_xLdY";function L(){const{announcementBar:e}=(0,w.p)(),{isActive:t,close:n}=(0,k.M)();if(!t)return null;const{backgroundColor:r,textColor:a,isCloseable:i}=e;return(0,c.jsxs)("div",{className:(0,o.A)(g.G.announcementBar.container,_),style:{backgroundColor:r,color:a},role:"banner",children:[i&&(0,c.jsx)("div",{className:T}),(0,c.jsx)(A,{className:P}),i&&(0,c.jsx)(E,{onClick:n,className:j})]})}var N=n(2069),O=n(3104);var R=n(9532),D=n(5600);const F=r.createContext(null);function I({children:e}){const t=function(){const e=(0,N.M)(),t=(0,D.YL)(),[n,o]=(0,r.useState)(!1),a=null!==t.component,i=(0,R.ZC)(a);return(0,r.useEffect)(()=>{a&&!i&&o(!0)},[a,i]),(0,r.useEffect)(()=>{a?e.shown||o(!0):o(!1)},[e.shown,a]),(0,r.useMemo)(()=>[n,o],[n])}();return(0,c.jsx)(F.Provider,{value:t,children:e})}function M(e){if(e.component){const t=e.component;return(0,c.jsx)(t,{...e.props})}}function z(){const e=(0,r.useContext)(F);if(!e)throw new R.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,o=(0,r.useCallback)(()=>n(!1),[n]),a=(0,D.YL)();return(0,r.useMemo)(()=>({shown:t,hide:o,content:M(a)}),[o,a,t])}function B(e){return parseInt(r.version.split(".")[0],10)<19?{inert:e?"":void 0}:{inert:e}}function $({children:e,inert:t}){return(0,c.jsx)("div",{className:(0,o.A)(g.G.layout.navbar.mobileSidebar.panel,"navbar-sidebar__item menu"),...B(t),children:e})}function U({header:e,primaryMenu:t,secondaryMenu:n}){const{shown:r}=z();return(0,c.jsxs)("div",{className:(0,o.A)(g.G.layout.navbar.mobileSidebar.container,"navbar-sidebar"),children:[e,(0,c.jsxs)("div",{className:(0,o.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":r}),children:[(0,c.jsx)($,{inert:r,children:t}),(0,c.jsx)($,{inert:!r,children:n})]})]})}var q=n(5293),H=n(2303);function G(e){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,c.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function V(e){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,c.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}function W(e){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,c.jsx)("path",{fill:"currentColor",d:"m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"})})}const Q="toggle_vylO",K="toggleButton_gllP",Y="toggleIcon_g3eP",X="systemToggleIcon_QzmC",Z="lightToggleIcon_pyhR",J="darkToggleIcon_wfgR",ee="toggleButtonDisabled_aARS";function te(e){switch(e){case null:return(0,s.T)({message:"system mode",id:"theme.colorToggle.ariaLabel.mode.system",description:"The name for the system color mode"});case"light":return(0,s.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"});case"dark":return(0,s.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"});default:throw new Error(`unexpected color mode ${e}`)}}function ne(e){return(0,s.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the color mode toggle"},{mode:te(e)})}function re(){return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(G,{"aria-hidden":!0,className:(0,o.A)(Y,Z)}),(0,c.jsx)(V,{"aria-hidden":!0,className:(0,o.A)(Y,J)}),(0,c.jsx)(W,{"aria-hidden":!0,className:(0,o.A)(Y,X)})]})}function oe({className:e,buttonClassName:t,respectPrefersColorScheme:n,value:r,onChange:a}){const i=(0,H.A)();return(0,c.jsx)("div",{className:(0,o.A)(Q,e),children:(0,c.jsx)("button",{className:(0,o.A)("clean-btn",K,!i&&ee,t),type:"button",onClick:()=>a(function(e,t){if(!t)return"dark"===e?"light":"dark";switch(e){case null:return"light";case"light":return"dark";case"dark":return null;default:throw new Error(`unexpected color mode ${e}`)}}(r,n)),disabled:!i,title:te(r),"aria-label":ne(r),children:(0,c.jsx)(re,{})})})}const ae=r.memo(oe),ie="darkNavbarColorModeToggle_X3D1";function le({className:e}){const t=(0,w.p)().navbar.style,{disableSwitch:n,respectPrefersColorScheme:r}=(0,w.p)().colorMode,{colorModeChoice:o,setColorMode:a}=(0,q.G)();return n?null:(0,c.jsx)(ae,{className:e,buttonClassName:"dark"===t?ie:void 0,respectPrefersColorScheme:r,value:o,onChange:a})}var se=n(3465);function ue(){return(0,c.jsx)(se.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function ce(){const e=(0,N.M)();return(0,c.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,c.jsx)(S,{color:"var(--ifm-color-emphasis-600)"})})}function de(){return(0,c.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,c.jsx)(ue,{}),(0,c.jsx)(le,{className:"margin-right--md"}),(0,c.jsx)(ce,{})]})}var fe=n(8774),pe=n(6025),me=n(6654);function he(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var ge=n(3186);function ye({activeBasePath:e,activeBaseRegex:t,to:n,href:r,label:o,html:a,isDropdownLink:i,prependBaseUrlToHref:l,...s}){const u=(0,pe.Ay)(n),d=(0,pe.Ay)(e),f=(0,pe.Ay)(r,{forcePrependBaseUrl:!0}),p=o&&r&&!(0,me.A)(r),m=a?{dangerouslySetInnerHTML:{__html:a}}:{children:(0,c.jsxs)(c.Fragment,{children:[o,p&&(0,c.jsx)(ge.A,{...i&&{width:12,height:12}})]})};return r?(0,c.jsx)(fe.A,{href:l?f:r,...s,...m}):(0,c.jsx)(fe.A,{to:u,isNavLink:!0,...(e||t)&&{isActive:(e,n)=>t?he(t,n.pathname):n.pathname.startsWith(d)},...s,...m})}function be({className:e,isDropdownItem:t,...n}){return(0,c.jsx)("li",{className:"menu__list-item",children:(0,c.jsx)(ye,{className:(0,o.A)("menu__link",e),...n})})}function ve({className:e,isDropdownItem:t=!1,...n}){const r=(0,c.jsx)(ye,{className:(0,o.A)(t?"dropdown__link":"navbar__item navbar__link",e),isDropdownLink:t,...n});return t?(0,c.jsx)("li",{children:r}):r}function we({mobile:e=!1,position:t,...n}){const r=e?be:ve;return(0,c.jsx)(r,{...n,activeClassName:n.activeClassName??(e?"menu__link--active":"navbar__link--active")})}var ke=n(1422),Se=n(9169),xe=n(4586);const Ee="dropdownNavbarItemMobile_J0Sd";function Ce(e,t){return e.some(e=>function(e,t){return!!(0,Se.ys)(e.to,t)||!!he(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t))}function Ae({collapsed:e,onClick:t}){return(0,c.jsx)("button",{"aria-label":e?(0,s.T)({id:"theme.navbar.mobileDropdown.collapseButton.expandAriaLabel",message:"Expand the dropdown",description:"The ARIA label of the button to expand the mobile dropdown navbar item"}):(0,s.T)({id:"theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel",message:"Collapse the dropdown",description:"The ARIA label of the button to collapse the mobile dropdown navbar item"}),"aria-expanded":!e,type:"button",className:"clean-btn menu__caret",onClick:t})}function _e({items:e,className:t,position:n,onClick:a,...i}){const s=function(){const{siteConfig:{baseUrl:e}}=(0,xe.A)(),{pathname:t}=(0,l.zy)();return t.replace(e,"/")}(),u=(0,Se.ys)(i.to,s),d=Ce(e,s),{collapsed:f,toggleCollapsed:p}=function({active:e}){const{collapsed:t,toggleCollapsed:n,setCollapsed:o}=(0,ke.u)({initialState:()=>!e});return(0,r.useEffect)(()=>{e&&o(!1)},[e,o]),{collapsed:t,toggleCollapsed:n}}({active:u||d}),m=i.to?void 0:"#";return(0,c.jsxs)("li",{className:(0,o.A)("menu__list-item",{"menu__list-item--collapsed":f}),children:[(0,c.jsxs)("div",{className:(0,o.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":u}),children:[(0,c.jsx)(ye,{role:"button",className:(0,o.A)(Ee,"menu__link menu__link--sublist",t),href:m,...i,onClick:e=>{"#"===m&&e.preventDefault(),p()},children:i.children??i.label}),(0,c.jsx)(Ae,{collapsed:f,onClick:e=>{e.preventDefault(),p()}})]}),(0,c.jsx)(ke.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:f,children:e.map((e,t)=>(0,r.createElement)(He,{mobile:!0,isDropdownItem:!0,onClick:a,activeClassName:"menu__link--active",...e,key:t}))})]})}function Te({items:e,position:t,className:n,onClick:a,...i}){const l=(0,r.useRef)(null),[s,u]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&u(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}},[l]),(0,c.jsxs)("div",{ref:l,className:(0,o.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===t,"dropdown--show":s}),children:[(0,c.jsx)(ye,{"aria-haspopup":"true","aria-expanded":s,role:"button",href:i.to?void 0:"#",className:(0,o.A)("navbar__link",n),...i,onClick:i.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),u(!s))},children:i.children??i.label}),(0,c.jsx)("ul",{className:"dropdown__menu",children:e.map((e,t)=>(0,r.createElement)(He,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t}))})]})}function je({mobile:e=!1,...t}){const n=e?_e:Te;return(0,c.jsx)(n,{...t})}var Pe=n(2131),Le=n(7485);function Ne({width:e=20,height:t=20,...n}){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:e,height:t,"aria-hidden":!0,...n,children:(0,c.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const Oe="iconLanguage_nlXk";function Re(){const{siteConfig:e,i18n:{localeConfigs:t}}=(0,xe.A)(),n=(0,Pe.o)(),r=(0,Le.Hl)(e=>e.location.search),o=(0,Le.Hl)(e=>e.location.hash),a=e=>{const n=t[e];if(!n)throw new Error(`Docusaurus bug, no locale config found for locale=${e}`);return n};return{getURL:(t,i)=>{const l=(0,Le.jy)([r,i.queryString],"append");return`${(t=>a(t).url===e.url?`pathname://${n.createUrl({locale:t,fullyQualified:!1})}`:n.createUrl({locale:t,fullyQualified:!0}))(t)}${l}${o}`},getLabel:e=>a(e).label,getLang:e=>a(e).htmlLang}}var De=n(418);const Fe="navbarSearchContainer_Bca1";function Ie({children:e,className:t}){return(0,c.jsx)("div",{className:(0,o.A)(t,Fe),children:e})}var Me=n(4070),ze=n(4718);var Be=n(3886);function $e({docsPluginId:e,configs:t}){return function(e,t){if(t){const n=new Map(e.map(e=>[e.name,e])),r=(t,r)=>{const o=n.get(t);if(!o)throw new Error(`No docs version exist for name '${t}', please verify your 'docsVersionDropdown' navbar item versions config.\nAvailable version names:\n- ${e.map(e=>`${e.name}`).join("\n- ")}`);return{version:o,label:r?.label??o.label}};return Array.isArray(t)?t.map(e=>r(e,void 0)):Object.entries(t).map(([e,t])=>r(e,t))}return e.map(e=>({version:e,label:e.label}))}((0,Me.jh)(e),t)}function Ue(e,t){return t.alternateDocVersions[e.name]??function(e){return e.docs.find(t=>t.id===e.mainDocId)}(e)}const qe={default:we,localeDropdown:function({mobile:e,dropdownItemsBefore:t,dropdownItemsAfter:n,queryString:r,...o}){const a=Re(),{i18n:{currentLocale:i,locales:l}}=(0,xe.A)(),u=[...t,...l.map(t=>({label:a.getLabel(t),lang:a.getLang(t),to:a.getURL(t,{queryString:r}),target:"_self",autoAddBaseUrl:!1,className:t===i?e?"menu__link--active":"dropdown__link--active":""})),...n],d=e?(0,s.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):a.getLabel(i);return(0,c.jsx)(je,{...o,mobile:e,label:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(Ne,{className:Oe}),d]}),items:u})},search:function({mobile:e,className:t}){return e?null:(0,c.jsx)(Ie,{className:t,children:(0,c.jsx)(De.A,{})})},dropdown:je,html:function({value:e,className:t,mobile:n=!1,isDropdownItem:r=!1}){const a=r?"li":"div";return(0,c.jsx)(a,{className:(0,o.A)({navbar__item:!n&&!r,"menu__list-item":n},t),dangerouslySetInnerHTML:{__html:e}})},doc:function({docId:e,label:t,docsPluginId:n,...r}){const{activeDoc:o}=(0,Me.zK)(n),a=(0,ze.QB)(e,n),i=o?.path===a?.path;return null===a||a.unlisted&&!i?null:(0,c.jsx)(we,{exact:!0,...r,isActive:()=>i||!!o?.sidebar&&o.sidebar===a.sidebar,label:t??a.id,to:a.path})},docSidebar:function({sidebarId:e,label:t,docsPluginId:n,...r}){const{activeDoc:o}=(0,Me.zK)(n),a=(0,ze.fW)(e,n).link;if(!a)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${e}" doesn't have anything to be linked to.`);return(0,c.jsx)(we,{exact:!0,...r,isActive:()=>o?.sidebar===e,label:t??a.label,to:a.path})},docsVersion:function({label:e,to:t,docsPluginId:n,...r}){const o=(0,ze.Vd)(n)[0],a=e??o.label,i=t??(e=>e.docs.find(t=>t.id===e.mainDocId))(o).path;return(0,c.jsx)(we,{...r,label:a,to:i})},docsVersionDropdown:function({mobile:e,docsPluginId:t,dropdownActiveClassDisabled:n,dropdownItemsBefore:r,dropdownItemsAfter:o,versions:a,...i}){const l=(0,Le.Hl)(e=>e.location.search),u=(0,Le.Hl)(e=>e.location.hash),d=(0,Me.zK)(t),{savePreferredVersionName:f}=(0,Be.g1)(t),p=$e({docsPluginId:t,configs:a}),m=function({docsPluginId:e,versionItems:t}){return(0,ze.Vd)(e).map(e=>t.find(t=>t.version===e)).filter(e=>void 0!==e)[0]??t[0]}({docsPluginId:t,versionItems:p}),h=[...r,...p.map(function({version:e,label:t}){return{label:t,to:`${Ue(e,d).path}${l}${u}`,isActive:()=>e===d.activeVersion,onClick:()=>f(e.name)}}),...o],g=e&&h.length>1?(0,s.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):m.label,y=e&&h.length>1?void 0:Ue(m.version,d).path;return h.length<=1?(0,c.jsx)(we,{...i,mobile:e,label:g,to:y,isActive:n?()=>!1:void 0}):(0,c.jsx)(je,{...i,mobile:e,label:g,to:y,items:h,isActive:n?()=>!1:void 0})}};function He({type:e,...t}){const n=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(e,t),r=qe[n];if(!r)throw new Error(`No NavbarItem component found for type "${e}".`);return(0,c.jsx)(r,{...t})}function Ge(){const e=(0,N.M)(),t=(0,w.p)().navbar.items;return(0,c.jsx)("ul",{className:"menu__list",children:t.map((t,n)=>(0,r.createElement)(He,{mobile:!0,...t,onClick:()=>e.toggle(),key:n}))})}function Ve(e){return(0,c.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,c.jsx)(s.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function We(){const e=0===(0,w.p)().navbar.items.length,t=z();return(0,c.jsxs)(c.Fragment,{children:[!e&&(0,c.jsx)(Ve,{onClick:()=>t.hide()}),t.content]})}function Qe(){const e=(0,N.M)();return function(e=!0){(0,r.useEffect)(()=>(document.body.style.overflow=e?"hidden":"visible",()=>{document.body.style.overflow="visible"}),[e])}(e.shown),e.shouldRender?(0,c.jsx)(U,{header:(0,c.jsx)(de,{}),primaryMenu:(0,c.jsx)(Ge,{}),secondaryMenu:(0,c.jsx)(We,{})}):null}const Ke="navbarHideable_m1mJ",Ye="navbarHidden_jGov";function Xe(e){return(0,c.jsx)("div",{role:"presentation",...e,className:(0,o.A)("navbar-sidebar__backdrop",e.className)})}function Ze({children:e}){const{navbar:{hideOnScroll:t,style:n}}=(0,w.p)(),a=(0,N.M)(),{navbarRef:i,isNavbarVisible:l}=function(e){const[t,n]=(0,r.useState)(e),o=(0,r.useRef)(!1),a=(0,r.useRef)(0),i=(0,r.useCallback)(e=>{null!==e&&(a.current=e.getBoundingClientRect().height)},[]);return(0,O.Mq)(({scrollY:t},r)=>{if(!e)return;if(t=i?n(!1):t+s{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return o.current=!0,void n(!1);n(!0)}),{navbarRef:i,isNavbarVisible:t}}(t);return(0,c.jsxs)("nav",{ref:i,"aria-label":(0,s.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,o.A)(g.G.layout.navbar.container,"navbar","navbar--fixed-top",t&&[Ke,!l&&Ye],{"navbar--dark":"dark"===n,"navbar--primary":"primary"===n,"navbar-sidebar--show":a.shown}),children:[e,(0,c.jsx)(Xe,{onClick:a.toggle}),(0,c.jsx)(Qe,{})]})}var Je=n(440);const et="errorBoundaryError_a6uf";function tt(e){return(0,c.jsx)("button",{type:"button",...e,children:(0,c.jsx)(s.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function nt({error:e}){const t=(0,Je.rA)(e).map(e=>e.message).join("\n\nCause:\n");return(0,c.jsx)("p",{className:et,children:t})}class rt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}function ot({width:e=30,height:t=30,className:n,...r}){return(0,c.jsx)("svg",{className:n,width:e,height:t,viewBox:"0 0 30 30","aria-hidden":"true",...r,children:(0,c.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function at(){const{toggle:e,shown:t}=(0,N.M)();return(0,c.jsx)("button",{onClick:e,"aria-label":(0,s.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,c.jsx)(ot,{})})}const it="colorModeToggle_DEke";function lt({items:e}){return(0,c.jsx)(c.Fragment,{children:e.map((e,t)=>(0,c.jsx)(rt,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,c.jsx)(He,{...e})},t))})}function st({left:e,right:t}){return(0,c.jsxs)("div",{className:"navbar__inner",children:[(0,c.jsx)("div",{className:(0,o.A)(g.G.layout.navbar.containerLeft,"navbar__items"),children:e}),(0,c.jsx)("div",{className:(0,o.A)(g.G.layout.navbar.containerRight,"navbar__items navbar__items--right"),children:t})]})}function ut(){const e=(0,N.M)(),t=(0,w.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??"right")}return[e.filter(t),e.filter(e=>!t(e))]}(t),o=t.find(e=>"search"===e.type);return(0,c.jsx)(st,{left:(0,c.jsxs)(c.Fragment,{children:[!e.disabled&&(0,c.jsx)(at,{}),(0,c.jsx)(ue,{}),(0,c.jsx)(lt,{items:n})]}),right:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(lt,{items:r}),(0,c.jsx)(le,{className:it}),!o&&(0,c.jsx)(Ie,{children:(0,c.jsx)(De.A,{})})]})})}function ct(){return(0,c.jsx)(Ze,{children:(0,c.jsx)(ut,{})})}function dt({item:e}){const{to:t,href:n,label:r,prependBaseUrlToHref:a,className:i,...l}=e,s=(0,pe.Ay)(t),u=(0,pe.Ay)(n,{forcePrependBaseUrl:!0});return(0,c.jsxs)(fe.A,{className:(0,o.A)("footer__link-item",i),...n?{href:a?u:n}:{to:s},...l,children:[r,n&&!(0,me.A)(n)&&(0,c.jsx)(ge.A,{})]})}function ft({item:e}){return e.html?(0,c.jsx)("li",{className:(0,o.A)("footer__item",e.className),dangerouslySetInnerHTML:{__html:e.html}}):(0,c.jsx)("li",{className:"footer__item",children:(0,c.jsx)(dt,{item:e})},e.href??e.to)}function pt({column:e}){return(0,c.jsxs)("div",{className:(0,o.A)(g.G.layout.footer.column,"col footer__col",e.className),children:[(0,c.jsx)("div",{className:"footer__title",children:e.title}),(0,c.jsx)("ul",{className:"footer__items clean-list",children:e.items.map((e,t)=>(0,c.jsx)(ft,{item:e},t))})]})}function mt({columns:e}){return(0,c.jsx)("div",{className:"row footer__links",children:e.map((e,t)=>(0,c.jsx)(pt,{column:e},t))})}function ht(){return(0,c.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function gt({item:e}){return e.html?(0,c.jsx)("span",{className:(0,o.A)("footer__link-item",e.className),dangerouslySetInnerHTML:{__html:e.html}}):(0,c.jsx)(dt,{item:e})}function yt({links:e}){return(0,c.jsx)("div",{className:"footer__links text--center",children:(0,c.jsx)("div",{className:"footer__links",children:e.map((t,n)=>(0,c.jsxs)(r.Fragment,{children:[(0,c.jsx)(gt,{item:t}),e.length!==n+1&&(0,c.jsx)(ht,{})]},n))})})}function bt({links:e}){return function(e){return"title"in e[0]}(e)?(0,c.jsx)(mt,{columns:e}):(0,c.jsx)(yt,{links:e})}var vt=n(1122);const wt="footerLogoLink_BH7S";function kt({logo:e}){const{withBaseUrl:t}=(0,pe.hH)(),n={light:t(e.src),dark:t(e.srcDark??e.src)};return(0,c.jsx)(vt.A,{className:(0,o.A)("footer__logo",e.className),alt:e.alt,sources:n,width:e.width,height:e.height,style:e.style})}function St({logo:e}){return e.href?(0,c.jsx)(fe.A,{href:e.href,className:wt,target:e.target,children:(0,c.jsx)(kt,{logo:e})}):(0,c.jsx)(kt,{logo:e})}function xt({copyright:e}){return(0,c.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:e}})}function Et({style:e,links:t,logo:n,copyright:r}){return(0,c.jsx)("footer",{className:(0,o.A)(g.G.layout.footer.container,"footer",{"footer--dark":"dark"===e}),children:(0,c.jsxs)("div",{className:"container container-fluid",children:[t,(n||r)&&(0,c.jsxs)("div",{className:"footer__bottom text--center",children:[n&&(0,c.jsx)("div",{className:"margin-bottom--sm",children:n}),r]})]})})}function Ct(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:o}=e;return(0,c.jsx)(Et,{style:o,links:n&&n.length>0&&(0,c.jsx)(bt,{links:n}),logo:r&&(0,c.jsx)(St,{logo:r}),copyright:t&&(0,c.jsx)(xt,{copyright:t})})}const At=r.memo(Ct),_t=(0,R.fM)([q.a,k.o,O.Tv,Be.VQ,i.Jx,function({children:e}){return(0,c.jsx)(D.y_,{children:(0,c.jsx)(N.e,{children:(0,c.jsx)(I,{children:e})})})}]);function Tt({children:e}){return(0,c.jsx)(_t,{children:e})}var jt=n(1107);function Pt({error:e,tryAgain:t}){return(0,c.jsx)("main",{className:"container margin-vert--xl",children:(0,c.jsx)("div",{className:"row",children:(0,c.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,c.jsx)(jt.A,{as:"h1",className:"hero__title",children:(0,c.jsx)(s.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,c.jsx)("div",{className:"margin-vert--lg",children:(0,c.jsx)(tt,{onClick:t,className:"button button--primary shadow--lw"})}),(0,c.jsx)("hr",{}),(0,c.jsx)("div",{className:"margin-vert--md",children:(0,c.jsx)(nt,{error:e})})]})})})}const Lt="mainWrapper_z2l0";function Nt(e){const{children:t,noFooter:n,wrapperClassName:r,title:l,description:s}=e;return(0,y.J)(),(0,c.jsxs)(Tt,{children:[(0,c.jsx)(i.be,{title:l,description:s}),(0,c.jsx)(v,{}),(0,c.jsx)(L,{}),(0,c.jsx)(ct,{}),(0,c.jsx)("div",{id:d,className:(0,o.A)(g.G.layout.main.container,g.G.wrapper.main,Lt,r),children:(0,c.jsx)(a.A,{fallback:e=>(0,c.jsx)(Pt,{...e}),children:t})}),!n&&(0,c.jsx)(At,{})]})}},3465(e,t,n){"use strict";n.d(t,{A:()=>c});n(6540);var r=n(8774),o=n(6025),a=n(4586),i=n(6342),l=n(1122),s=n(4848);function u({logo:e,alt:t,imageClassName:n}){const r={light:(0,o.Ay)(e.src),dark:(0,o.Ay)(e.srcDark||e.src)},a=(0,s.jsx)(l.A,{className:e.className,sources:r,height:e.height,width:e.width,alt:t,style:e.style});return n?(0,s.jsx)("div",{className:n,children:a}):a}function c(e){const{siteConfig:{title:t}}=(0,a.A)(),{navbar:{title:n,logo:l}}=(0,i.p)(),{imageClassName:c,titleClassName:d,...f}=e,p=(0,o.Ay)(l?.href||"/"),m=n?"":t,h=l?.alt??m;return(0,s.jsxs)(r.A,{to:p,...f,...l?.target&&{target:l.target},children:[l&&(0,s.jsx)(u,{logo:l,alt:h,imageClassName:c}),null!=n&&(0,s.jsx)("b",{className:d,children:n})]})}},1463(e,t,n){"use strict";n.d(t,{A:()=>a});n(6540);var r=n(5260),o=n(4848);function a({locale:e,version:t,tag:n}){const a=e;return(0,o.jsxs)(r.A,{children:[e&&(0,o.jsx)("meta",{name:"docusaurus_locale",content:e}),t&&(0,o.jsx)("meta",{name:"docusaurus_version",content:t}),n&&(0,o.jsx)("meta",{name:"docusaurus_tag",content:n}),a&&(0,o.jsx)("meta",{name:"docsearch:language",content:a}),t&&(0,o.jsx)("meta",{name:"docsearch:version",content:t}),n&&(0,o.jsx)("meta",{name:"docsearch:docusaurus_tag",content:n})]})}},1122(e,t,n){"use strict";n.d(t,{A:()=>c});var r=n(6540),o=n(4164),a=n(2303),i=n(5293);const l={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var s=n(4848);function u({className:e,children:t}){const n=(0,a.A)(),{colorMode:u}=(0,i.G)();return(0,s.jsx)(s.Fragment,{children:(n?"dark"===u?["dark"]:["light"]:["light","dark"]).map(n=>{const a=t({theme:n,className:(0,o.A)(e,l.themedComponent,l[`themedComponent--${n}`])});return(0,s.jsx)(r.Fragment,{children:a},n)})})}function c(e){const{sources:t,className:n,alt:r,...o}=e;return(0,s.jsx)(u,{className:n,children:({theme:e,className:n})=>(0,s.jsx)("img",{src:t[e],alt:r,className:n,...o})})}},1422(e,t,n){"use strict";n.d(t,{N:()=>m,u:()=>l});var r=n(6540),o=n(205),a=n(3109),i=n(4848);function l({initialState:e}){const[t,n]=(0,r.useState)(e??!1),o=(0,r.useCallback)(()=>{n(e=>!e)},[]);return{collapsed:t,setCollapsed:n,toggleCollapsed:o}}const s={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function c(e,t){const n=t?s:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function d({collapsibleRef:e,collapsed:t,animation:n}){const o=(0,r.useRef)(!1);(0,r.useEffect)(()=>{const r=e.current;function i(){const e=r.scrollHeight,t=n?.duration??function(e){if((0,a.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(e);return{transition:`height ${t}ms ${n?.easing??"ease-in-out"}`,height:`${e}px`}}function l(){const e=i();r.style.transition=e.transition,r.style.height=e.height}if(!o.current)return c(r,t),void(o.current=!0);return r.style.willChange="height",function(){const e=requestAnimationFrame(()=>{t?(l(),requestAnimationFrame(()=>{r.style.height=s.height,r.style.overflow=s.overflow})):(r.style.display="block",requestAnimationFrame(()=>{l()}))});return()=>cancelAnimationFrame(e)}()},[e,t,n])}function f({as:e="div",collapsed:t,children:n,animation:o,onCollapseTransitionEnd:a,className:l}){const s=(0,r.useRef)(null);return d({collapsibleRef:s,collapsed:t,animation:o}),(0,i.jsx)(e,{ref:s,onTransitionEnd:e=>{"height"===e.propertyName&&(c(s.current,t),a?.(t))},className:l,children:n})}function p({collapsed:e,...t}){const[n,a]=(0,r.useState)(!e),[l,s]=(0,r.useState)(e);return(0,o.A)(()=>{e||a(!0)},[e]),(0,o.A)(()=>{n&&s(e)},[n,e]),n?(0,i.jsx)(f,{...t,collapsed:l}):null}function m({lazy:e,...t}){const n=e?p:f;return(0,i.jsx)(n,{...t})}},5041(e,t,n){"use strict";n.d(t,{M:()=>h,o:()=>m});var r=n(6540),o=n(2303),a=n(679),i=n(9532),l=n(6342),s=n(4848);const u=(0,a.Wf)("docusaurus.announcement.dismiss"),c=(0,a.Wf)("docusaurus.announcement.id"),d=()=>"true"===u.get(),f=e=>u.set(String(e)),p=r.createContext(null);function m({children:e}){const t=function(){const{announcementBar:e}=(0,l.p)(),t=(0,o.A)(),[n,a]=(0,r.useState)(()=>!!t&&d());(0,r.useEffect)(()=>{a(d())},[]);const i=(0,r.useCallback)(()=>{f(!0),a(!0)},[]);return(0,r.useEffect)(()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&f(!1),!r&&d()||a(!1)},[e]),(0,r.useMemo)(()=>({isActive:!!e&&!n,close:i}),[e,n,i])}();return(0,s.jsx)(p.Provider,{value:t,children:e})}function h(){const e=(0,r.useContext)(p);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},5293(e,t,n){"use strict";n.d(t,{G:()=>S,a:()=>k});var r=n(6540),o=n(2303),a=n(9532),i=n(679),l=n(6342),s=n(4848);function u(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function c(e){return function(e,t){const n=window.matchMedia(e);return n.addEventListener("change",t),()=>n.removeEventListener("change",t)}("(prefers-color-scheme: dark)",()=>e(u()))}const d=r.createContext(void 0),f=(0,i.Wf)("theme"),p="system",m=e=>"dark"===e?"dark":"light",h=e=>null===e||e===p?null:m(e),g=()=>m(document.documentElement.getAttribute("data-theme")),y=e=>{document.documentElement.setAttribute("data-theme",m(e))},b=()=>h(document.documentElement.getAttribute("data-theme-choice")),v=e=>{document.documentElement.setAttribute("data-theme-choice",h(e)??p)};function w(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.p)(),{colorMode:a,setColorModeState:i,colorModeChoice:s,setColorModeChoiceState:d}=function(){const{colorMode:{defaultMode:e}}=(0,l.p)(),t=(0,o.A)(),[n,a]=(0,r.useState)(t?g():e),[i,s]=(0,r.useState)(t?b():null);return(0,r.useEffect)(()=>{a(g()),s(b())},[]),{colorMode:n,setColorModeState:a,colorModeChoice:i,setColorModeChoiceState:s}}();(0,r.useEffect)(()=>{t&&f.del()},[t]);const p=(0,r.useCallback)((t,r={})=>{const{persist:o=!0}=r;if(null===t){const t=n?u():e;y(t),i(t),v(null),d(null)}else y(t),v(t),i(t),d(t);var a;o&&(null===(a=t)?f.del():f.set(m(a)))},[i,d,n,e]);return(0,r.useEffect)(()=>f.listen(e=>{p(h(e.newValue))}),[p]),(0,r.useEffect)(()=>{if(null===s&&n)return c(e=>{i(e),y(e)})},[n,s,i]),(0,r.useMemo)(()=>({colorMode:a,colorModeChoice:s,setColorMode:p,get isDarkTheme(){return"dark"===a},setLightTheme(){p("light")},setDarkTheme(){p("dark")}}),[a,s,p])}function k({children:e}){const t=w();return(0,s.jsx)(d.Provider,{value:t,children:e})}function S(){const e=(0,r.useContext)(d);if(null==e)throw new a.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},2069(e,t,n){"use strict";n.d(t,{M:()=>m,e:()=>p});var r=n(6540),o=n(5600),a=n(4581),i=n(7485),l=n(6342),s=n(9532),u=n(4848);const c=r.createContext(void 0);function d(){const e=function(){const e=(0,o.YL)(),{items:t}=(0,l.p)().navbar;return 0===t.length&&!e.component}(),t=(0,a.l)(),n=!e&&"mobile"===t,[i,s]=(0,r.useState)(!1),u=(0,r.useCallback)(()=>{s(e=>!e)},[]);return(0,r.useEffect)(()=>{"desktop"===t&&s(!1)},[t]),(0,r.useMemo)(()=>({disabled:e,shouldRender:n,toggle:u,shown:i}),[e,n,u,i])}function f({handler:e}){return(0,i.$Z)(e),null}function p({children:e}){const t=d();return(0,u.jsxs)(u.Fragment,{children:[t.shown&&(0,u.jsx)(f,{handler:()=>(t.toggle(),!1)}),(0,u.jsx)(c.Provider,{value:t,children:e})]})}function m(){const e=r.useContext(c);if(void 0===e)throw new s.dV("NavbarMobileSidebarProvider");return e}},5600(e,t,n){"use strict";n.d(t,{GX:()=>u,YL:()=>s,y_:()=>l});var r=n(6540),o=n(9532),a=n(4848);const i=r.createContext(null);function l({children:e}){const t=(0,r.useState)({component:null,props:null});return(0,a.jsx)(i.Provider,{value:t,children:e})}function s(){const e=(0,r.useContext)(i);if(!e)throw new o.dV("NavbarSecondaryMenuContentProvider");return e[0]}function u({component:e,props:t}){const n=(0,r.useContext)(i);if(!n)throw new o.dV("NavbarSecondaryMenuContentProvider");const[,a]=n,l=(0,o.Be)(t);return(0,r.useEffect)(()=>{a({component:e,props:l})},[a,e,l]),(0,r.useEffect)(()=>()=>a({component:null,props:null}),[a]),null}},4090(e,t,n){"use strict";n.d(t,{w:()=>o,J:()=>a});var r=n(6540);const o="navigation-with-keyboard";function a(){(0,r.useEffect)(()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(o),"mousedown"===e.type&&document.body.classList.remove(o)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(o),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}},[])}},4581(e,t,n){"use strict";n.d(t,{l:()=>l});var r=n(6540),o=n(8193);const a="desktop",i="mobile";function l({desktopBreakpoint:e=996}={}){const[t,n]=(0,r.useState)(()=>"ssr");return(0,r.useEffect)(()=>{function t(){n(function(e){if(!o.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?a:i}(e))}return t(),window.addEventListener("resize",t),()=>{window.removeEventListener("resize",t)}},[e]),t}},7559(e,t,n){"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",blogAuthorsListPage:"blog-authors-list-page",blogAuthorsPostsPage:"blog-authors-posts-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",draftBanner:"theme-draft-banner",admonitionType:e=>`theme-admonition-${e}`},announcementBar:{container:"theme-announcement-bar"},tabs:{container:"theme-tabs-container"},layout:{navbar:{container:"theme-layout-navbar",containerLeft:"theme-layout-navbar-left",containerRight:"theme-layout-navbar-right",mobileSidebar:{container:"theme-layout-navbar-sidebar",panel:"theme-layout-navbar-sidebar-panel"}},main:{container:"theme-layout-main"},footer:{container:"theme-layout-footer",column:"theme-layout-footer-column"}},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{blogFooterTagsRow:"theme-blog-footer-tags-row",blogFooterEditMetaRow:"theme-blog-footer-edit-meta-row"},pages:{pageFooterEditMetaRow:"theme-pages-footer-edit-meta-row"}}},3109(e,t,n){"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},3535(e,t,n){"use strict";n.d(t,{v:()=>i});var r=n(6342);const o="anchorTargetStickyNavbar_Vzrq",a="anchorTargetHideOnScrollNavbar_vjPI";function i(e){const{navbar:{hideOnScroll:t}}=(0,r.p)();if(void 0!==e)return t?a:o}},7485(e,t,n){"use strict";n.d(t,{$Z:()=>i,Hl:()=>l,jy:()=>s});var r=n(6540),o=n(6347),a=n(9532);function i(e){!function(e){const t=(0,o.W6)(),n=(0,a._q)(e);(0,r.useEffect)(()=>t.block((e,t)=>n(e,t)),[t,n])}((t,n)=>{if("POP"===n)return e(t,n)})}function l(e){const t=(0,o.W6)();return(0,r.useSyncExternalStore)(t.listen,()=>e(t),()=>e({...t,location:{...t.location,search:"",hash:"",state:void 0}}))}function s(e,t){const n=function(e,t){const n=new URLSearchParams;for(const r of e)for(const[e,o]of r.entries())"append"===t?n.append(e,o):n.set(e,o);return n}(e.map(e=>new URLSearchParams(e??"")),t),r=n.toString();return r?`?${r}`:r}},5500(e,t,n){"use strict";n.d(t,{Jx:()=>y,be:()=>m,e3:()=>g});var r=n(6540),o=n(4164),a=n(5260),i=n(6803),l=n(6025),s=n(4563),u=n(4848);function c({title:e}){const t=(0,s.s$)().format(e);return(0,u.jsxs)(a.A,{children:[(0,u.jsx)("title",{children:t}),(0,u.jsx)("meta",{property:"og:title",content:t})]})}function d({description:e}){return(0,u.jsxs)(a.A,{children:[(0,u.jsx)("meta",{name:"description",content:e}),(0,u.jsx)("meta",{property:"og:description",content:e})]})}function f({image:e}){const{withBaseUrl:t}=(0,l.hH)(),n=t(e,{absolute:!0});return(0,u.jsxs)(a.A,{children:[(0,u.jsx)("meta",{property:"og:image",content:n}),(0,u.jsx)("meta",{name:"twitter:image",content:n})]})}function p({keywords:e}){return(0,u.jsx)(a.A,{children:(0,u.jsx)("meta",{name:"keywords",content:Array.isArray(e)?e.join(","):e})})}function m({title:e,description:t,keywords:n,image:r,children:o}){return(0,u.jsxs)(u.Fragment,{children:[e&&(0,u.jsx)(c,{title:e}),t&&(0,u.jsx)(d,{description:t}),n&&(0,u.jsx)(p,{keywords:n}),r&&(0,u.jsx)(f,{image:r}),o&&(0,u.jsx)(a.A,{children:o})]})}const h=r.createContext(void 0);function g({className:e,children:t}){const n=r.useContext(h),i=(0,o.A)(n,e);return(0,u.jsxs)(h.Provider,{value:i,children:[(0,u.jsx)(a.A,{children:(0,u.jsx)("html",{className:i})}),t]})}function y({children:e}){const t=(0,i.A)(),n=`plugin-${t.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const r=`plugin-id-${t.plugin.id}`;return(0,u.jsx)(g,{className:(0,o.A)(n,r),children:e})}},9532(e,t,n){"use strict";n.d(t,{Be:()=>u,ZC:()=>l,_q:()=>i,dV:()=>s,fM:()=>c});var r=n(6540),o=n(205),a=n(4848);function i(e){const t=(0,r.useRef)(e);return(0,o.A)(()=>{t.current=e},[e]),(0,r.useCallback)((...e)=>t.current(...e),[])}function l(e){const t=(0,r.useRef)();return(0,o.A)(()=>{t.current=e}),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function u(e){const t=Object.entries(e);return t.sort((e,t)=>e[0].localeCompare(t[0])),(0,r.useMemo)(()=>e,t.flat())}function c(e){return({children:t})=>(0,a.jsx)(a.Fragment,{children:e.reduceRight((e,t)=>(0,a.jsx)(t,{children:e}),t)})}},9169(e,t,n){"use strict";n.d(t,{Dt:()=>l,ys:()=>i});var r=n(6540),o=n(8328),a=n(4586);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,a.A)().siteConfig;return(0,r.useMemo)(()=>function({baseUrl:e,routes:t}){function n(t){return t.path===e&&!0===t.exact}function r(t){return t.path===e&&!t.exact}return function e(t){if(0===t.length)return;return t.find(n)||e(t.filter(r).flatMap(e=>e.routes??[]))}(t)}({routes:o.A,baseUrl:e}),[e])}},3104(e,t,n){"use strict";n.d(t,{Mq:()=>f,Tv:()=>u,gk:()=>p});var r=n(6540),o=n(8193),a=n(2303),i=(n(205),n(9532)),l=n(4848);const s=r.createContext(void 0);function u({children:e}){const t=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)(()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}}),[])}();return(0,l.jsx)(s.Provider,{value:t,children:e})}function c(){const e=(0,r.useContext)(s);if(null==e)throw new i.dV("ScrollControllerProvider");return e}const d=()=>o.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function f(e,t=[]){const{scrollEventsEnabledRef:n}=c(),o=(0,r.useRef)(d()),a=(0,i._q)(e);(0,r.useEffect)(()=>{const e=()=>{if(!n.current)return;const e=d();a(e,o.current),o.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)},[a,n,...t])}function p(){const e=(0,r.useRef)(null),t=(0,a.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const o=document.documentElement.scrollTop;(n&&o>e||!n&&ot&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},679(e,t,n){"use strict";n.d(t,{Wf:()=>u});n(6540);const r=JSON.parse('{"N":"localStorage","M":""}');const o=r.N;function a({key:e,oldValue:t,newValue:n,storage:r}){if(t===n)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,e,t,n,window.location.href,r),window.dispatchEvent(o)}function i(e=o){if("undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,l||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),l=!0),null}var t}let l=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){const n=`${e}${r.M}`;if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(n);const o=i(t?.persistence);return null===o?s:{get:()=>{try{return o.getItem(n)}catch(e){return console.error(`Docusaurus storage error, can't get key=${n}`,e),null}},set:e=>{try{const t=o.getItem(n);o.setItem(n,e),a({key:n,oldValue:t,newValue:e,storage:o})}catch(t){console.error(`Docusaurus storage error, can't set ${n}=${e}`,t)}},del:()=>{try{const e=o.getItem(n);o.removeItem(n),a({key:n,oldValue:e,newValue:null,storage:o})}catch(e){console.error(`Docusaurus storage error, can't delete key=${n}`,e)}},listen:e=>{try{const t=t=>{t.storageArea===o&&t.key===n&&e(t)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}catch(t){return console.error(`Docusaurus storage error, can't listen for changes of key=${n}`,t),()=>{}}}}}},4563(e,t,n){"use strict";n.d(t,{AL:()=>c,s$:()=>d});var r=n(6540),o=n(4586),a=n(6803),i=n(9532),l=n(4848);const s=({title:e,siteTitle:t,titleDelimiter:n})=>{const r=e?.trim();return r&&r!==t?`${r} ${n} ${t}`:t},u=(0,r.createContext)(null);function c({formatter:e,children:t}){return(0,l.jsx)(u.Provider,{value:e,children:t})}function d(){const e=function(){const e=(0,r.useContext)(u);if(null===e)throw new i.dV("TitleFormatterProvider");return e}(),{siteConfig:t}=(0,o.A)(),{title:n,titleDelimiter:l}=t,{plugin:c}=(0,a.A)();return{format:t=>e({title:t,siteTitle:n,titleDelimiter:l,plugin:c,defaultFormatter:s})}}},2131(e,t,n){"use strict";n.d(t,{o:()=>i});var r=n(4586),o=n(6347),a=n(440);function i(){const{siteConfig:{baseUrl:e,trailingSlash:t},i18n:{localeConfigs:n}}=(0,r.A)(),{pathname:i}=(0,o.zy)(),l=(0,a.Ks)(i,{trailingSlash:t,baseUrl:e}).replace(e,"");return{createUrl:function({locale:e,fullyQualified:t}){const r=function(e){const t=n[e];if(!t)throw new Error(`Unexpected Docusaurus bug, no locale config found for locale=${e}`);return t}(e);return`${`${t?r.url:""}`}${r.baseUrl}${l}`}}}},5062(e,t,n){"use strict";n.d(t,{$:()=>i});var r=n(6540),o=n(6347),a=n(9532);function i(e){const t=(0,o.zy)(),n=(0,a.ZC)(t),i=(0,a._q)(e);(0,r.useEffect)(()=>{n&&t!==n&&i({location:t,previousLocation:n})},[i,t,n])}},6342(e,t,n){"use strict";n.d(t,{p:()=>o});var r=n(4586);function o(){return(0,r.A)().siteConfig.themeConfig}},2983(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addTrailingSlash=o,t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[i]=e.split(/[#?]/),l="/"===i||i===r?i:(s=i,u=n,u?o(s):a(s));var s,u;return e.replace(i,l)},t.addLeadingSlash=function(e){return(0,r.addPrefix)(e,"/")},t.removeTrailingSlash=a;const r=n(2566);function o(e){return e.endsWith("/")?e:`${e}/`}function a(e){return(0,r.removeSuffix)(e,"/")}},253(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=function e(t){if(t.cause)return[t,...e(t.cause)];return[t]}},440(e,t,n){"use strict";t.rA=t.Ks=void 0;const r=n(1635);var o=n(2983);Object.defineProperty(t,"Ks",{enumerable:!0,get:function(){return r.__importDefault(o).default}});var a=n(2566);var i=n(253);Object.defineProperty(t,"rA",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},2566(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addPrefix=function(e,t){return e.startsWith(t)?e:`${t}${e}`},t.removeSuffix=function(e,t){if(""===t)return e;return e.endsWith(t)?e.slice(0,-t.length):e},t.addSuffix=function(e,t){return e.endsWith(t)?e:`${e}${t}`},t.removePrefix=function(e,t){return e.startsWith(t)?e.slice(t.length):e}},1513(e,t,n){"use strict";n.d(t,{zR:()=>w,TM:()=>A,yJ:()=>p,sC:()=>T,AO:()=>f});var r=n(8168);function o(e){return"/"===e.charAt(0)}function a(e,t){for(var n=t,r=n+1,o=e.length;r=0;f--){var p=i[f];"."===p?a(i,f):".."===p?(a(i,f),d++):d&&(a(i,f),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&o(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(1561);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,o=t||"/";return n&&"?"!==n&&(o+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(o+="#"===r.charAt(0)?r:"#"+r),o}function p(e,t,n,o){var a;"string"==typeof e?(a=function(e){var t=e||"/",n="",r="",o=t.indexOf("#");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf("?");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),a.state=t):(void 0===(a=(0,r.A)({},e)).pathname&&(a.pathname=""),a.search?"?"!==a.search.charAt(0)&&(a.search="?"+a.search):a.search="",a.hash?"#"!==a.hash.charAt(0)&&(a.hash="#"+a.hash):a.hash="",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+a.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(a.key=n),o?a.pathname?"/"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname="/"),a}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a="function"==typeof e?e(t,n):e;"string"==typeof a?"function"==typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter(function(e){return e!==r})}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,o):n.push(o),d({action:r,location:o,index:t,entries:n})}})},replace:function(e,t){var r="REPLACE",o=p(e,t,h(),w.location);c.confirmTransitionTo(o,r,n,function(e){e&&(w.entries[w.index]=o,d({action:r,location:o}))})},go:v,goBack:function(){v(-1)},goForward:function(){v(1)},canGo:function(e){var t=w.index+e;return t>=0&&t
'};function o(e,t,n){return en?n:e}function a(e){return 100*(-1+e)}function i(e,t,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+a(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+a(e)+"%,0)"}:{"margin-left":a(e)+"%"}).transition="all "+t+"ms "+n,o}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=o(e,r.minimum,1),n.status=1===e?null:e;var a=n.render(!t),u=a.querySelector(r.barSelector),c=r.speed,d=r.easing;return a.offsetWidth,l(function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(a,{transition:"none",opacity:1}),a.offsetWidth,setTimeout(function(){s(a,{transition:"all "+c+"ms linear",opacity:0}),setTimeout(function(){n.remove(),t()},c)},c)):setTimeout(t,c)}),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout(function(){n.status&&(n.trickle(),e())},r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*o(Math.random()*t,.1,.95)),t=o(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always(function(){0===--t?(e=0,n.done()):n.set((e-t)/e)}),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var o,i=t.querySelector(r.barSelector),l=e?"-100":a(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(o=t.querySelector(r.spinnerSelector))&&p(o),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(e,t){return t.toUpperCase()})}function r(t){var n=document.body.style;if(t in n)return t;for(var r,o=e.length,a=t.charAt(0).toUpperCase()+t.slice(1);o--;)if((r=e[o]+a)in n)return r;return t}function o(e){return e=n(e),t[e]||(t[e]=r(e))}function a(e,t,n){t=o(t),e.style[t]=n}return function(e,t){var n,r,o=arguments;if(2==o.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&a(e,n,r);else a(e,o[1],o[2])}}();function u(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(o="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=o)},5302(e,t,n){var r=n(4634);e.exports=h,e.exports.parse=a,e.exports.compile=function(e,t){return u(a(e,t),t)},e.exports.tokensToFunction=u,e.exports.tokensToRegExp=m;var o=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function a(e,t){for(var n,r=[],a=0,l=0,s="",u=t&&t.delimiter||"/";null!=(n=o.exec(e));){var c=n[0],f=n[1],p=n.index;if(s+=e.slice(l,p),l=p+c.length,f)s+=f[1];else{var m=e[l],h=n[2],g=n[3],y=n[4],b=n[5],v=n[6],w=n[7];s&&(r.push(s),s="");var k=null!=h&&null!=m&&m!==h,S="+"===v||"*"===v,x="?"===v||"*"===v,E=h||u,C=y||b,A=h||("string"==typeof r[r.length-1]?r[r.length-1]:"");r.push({name:g||a++,prefix:h||"",delimiter:E,optional:x,repeat:S,partial:k,asterisk:!!w,pattern:C?d(C):w?".*":i(E,A)})}}return l-1?"[^"+c(e)+"]+?":c(t)+"|(?:(?!"+c(t)+")[^"+c(e)+"])+?"}function l(e){return encodeURI(e).replace(/[\/?#]/g,function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})}function s(e){return encodeURI(e).replace(/[?#]/g,function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})}function u(e,t){for(var n=new Array(e.length),o=0;o