diff --git a/.brv/context-tree/curated/extracted/extracted_facts.md b/.brv/context-tree/curated/extracted/extracted_facts.md
new file mode 100644
index 0000000..dee2028
--- /dev/null
+++ b/.brv/context-tree/curated/extracted/extracted_facts.md
@@ -0,0 +1,35 @@
+---
+title: Extracted Facts
+summary: Aggregated facts extracted from provided context
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:15:07.392Z'
+updatedAt: '2026-05-29T09:15:07.392Z'
+---
+## Reason
+Store extracted factual statements from context
+
+## Raw Concept
+**Task:**
+Curated knowledge extraction
+
+**Flow:**
+Extraction -> Deduplication -> Grouping -> Curation
+
+**Timestamp:** 2026-05-29T09:15:07.391Z
+
+## Narrative
+### Structure
+Aggregated extracted facts grouped by subject.
+
+### Highlights
+Caplets
+
+## Facts
+- **Caplets**: The headline is "Caplets: Give your agents capabilities, not giant tool walls"
+- **Caplets**: Supporting subhead: "Caplets turns MCP servers, APIs, and commands into focused capabilities your agent can discover, inspect, and use one step at a time."
+- **Caplets**: Shorter social version: "Stop dumping 100+ tools into your agent’s context. Caplets gives agents focused capabilities instead of giant tool walls."
+- **Caplets**: GitHub description variant: "Progressive disclosure for agent tools: wrap MCP servers, APIs, and commands as focused capabilities instead of flat tool walls."
+- **Caplets**: HN title variant: "Show HN: Caplets, give agents capabilities, not giant tool walls"
+- **Caplets**: README hero: "Give your agents capabilities, not giant tool walls. Caplets turns MCP servers, APIs, and commands into focused capabilities: one card first, searchable tools next, inspectable schemas before calls, and preserved results after."
diff --git a/.brv/context-tree/curation/extracted/extracted_context.md b/.brv/context-tree/curation/extracted/extracted_context.md
new file mode 100644
index 0000000..7f556c7
--- /dev/null
+++ b/.brv/context-tree/curation/extracted/extracted_context.md
@@ -0,0 +1,23 @@
+---
+title: Extracted Context
+summary: Curated extracted context from RLM task
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:13:04.949Z'
+updatedAt: '2026-05-29T09:13:04.949Z'
+---
+## Reason
+Curate provided RLM context
+
+## Raw Concept
+**Task:**
+Curate provided context
+
+**Timestamp:** 2026-05-29T09:13:04.947Z
+
+## Narrative
+### Structure
+The following is a conversation between a user and an AI assistant.
+Curate only information with lasting value: facts, decisions, technical details, preferences, or notable outcomes.
+Skip trivial messages such as greetings, acknowledgments ("ok", "thanks", "sure", "got it"), one-word replies, anythi
diff --git a/.brv/context-tree/facts/project/animation.md b/.brv/context-tree/facts/project/animation.md
new file mode 100644
index 0000000..c692ea4
--- /dev/null
+++ b/.brv/context-tree/facts/project/animation.md
@@ -0,0 +1,24 @@
+---
+title: Animation
+summary: Facts about animation
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.192Z'
+updatedAt: '2026-05-29T09:19:16.192Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for animation
+
+## Facts
+- **animation**: Do not animate CSS layout properties.
diff --git a/.brv/context-tree/facts/project/apps_landing_src_pages_index_astro.md b/.brv/context-tree/facts/project/apps_landing_src_pages_index_astro.md
index 0305d05..6853899 100644
--- a/.brv/context-tree/facts/project/apps_landing_src_pages_index_astro.md
+++ b/.brv/context-tree/facts/project/apps_landing_src_pages_index_astro.md
@@ -1,27 +1,27 @@
---
-title: apps/landing/src/pages/index.astro
+title: Apps/landing/src/pages/index.astro
summary: Facts about apps/landing/src/pages/index.astro
tags: []
related: []
keywords: []
createdAt: '2026-05-28T13:51:08.350Z'
-updatedAt: '2026-05-28T13:51:08.350Z'
+updatedAt: '2026-05-29T09:19:16.211Z'
---
## Reason
-Curated extracted facts
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document factual statements about apps/landing/src/pages/index.astro
+Document factual statements
-**Timestamp:** 2026-05-28T13:51:08.346Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected facts for apps/landing/src/pages/index.astro
### Highlights
-Changed files: apps/landing/src/pages/index.astro
+Extracted 1 facts for apps/landing/src/pages/index.astro
## Facts
-- **apps/landing/src/pages/index.astro**: Changed files: apps/landing/src/pages/index.astro
+- **apps/landing/src/pages/index.astro**: Updated page title and meta description in apps/landing/src/pages/index.astro.
diff --git a/.brv/context-tree/facts/project/border_usage.md b/.brv/context-tree/facts/project/border_usage.md
new file mode 100644
index 0000000..f3c16f0
--- /dev/null
+++ b/.brv/context-tree/facts/project/border_usage.md
@@ -0,0 +1,24 @@
+---
+title: Border usage
+summary: Facts about border usage
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.195Z'
+updatedAt: '2026-05-29T09:19:16.195Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for border usage
+
+## Facts
+- **border usage**: Side-stripe borders greater than 1px as colored accents are prohibited.
diff --git a/.brv/context-tree/facts/project/build.md b/.brv/context-tree/facts/project/build.md
index 54e0849..44ef6a9 100644
--- a/.brv/context-tree/facts/project/build.md
+++ b/.brv/context-tree/facts/project/build.md
@@ -5,16 +5,16 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:59:51.352Z'
-updatedAt: '2026-05-28T13:55:17.314Z'
+updatedAt: '2026-05-29T09:19:16.222Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted factual statements
+Document factual statements
-**Timestamp:** 2026-05-28T13:55:17.267Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
@@ -24,4 +24,4 @@ Collected facts for build
Extracted 1 facts for build
## Facts
-- **build**: pnpm --filter @caplets/landing build passed, building 1 page successfully.
+- **build**: Build for @caplets/landing completed successfully, building 1 page.
diff --git a/.brv/context-tree/facts/project/campaign_headline.md b/.brv/context-tree/facts/project/campaign_headline.md
new file mode 100644
index 0000000..e9640a1
--- /dev/null
+++ b/.brv/context-tree/facts/project/campaign_headline.md
@@ -0,0 +1,24 @@
+---
+title: Campaign headline
+summary: Facts about campaign headline
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.209Z'
+updatedAt: '2026-05-29T09:19:16.209Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for campaign headline
+
+## Facts
+- **campaign headline**: Implemented the new campaign headline across the visible first-screen surfaces.
diff --git a/.brv/context-tree/facts/project/caplets.md b/.brv/context-tree/facts/project/caplets.md
index 12b5318..3c783d8 100644
--- a/.brv/context-tree/facts/project/caplets.md
+++ b/.brv/context-tree/facts/project/caplets.md
@@ -5,16 +5,16 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-28T11:17:59.543Z'
-updatedAt: '2026-05-28T11:17:59.543Z'
+updatedAt: '2026-05-29T09:16:04.065Z'
---
## Reason
-Curated facts extracted from context
+Curate extracted factual statements
## Raw Concept
**Task:**
-Document facts about Caplets
+Document factual statements
**Timestamp:** 2026-05-28T11:17:59.530Z
## Facts
-- **Caplets**: Caplets uses a warm light palette, restrained ember accents, and mono for machine-facing text, aligning with PRODUCT/DESIGN direction.
+- **Caplets**: Caplets: Give your agents capabilities, not giant tool walls
diff --git a/.brv/context-tree/facts/project/caplets_try_it_in_60_seconds_path.md b/.brv/context-tree/facts/project/caplets_try_it_in_60_seconds_path.md
new file mode 100644
index 0000000..3a4b16a
--- /dev/null
+++ b/.brv/context-tree/facts/project/caplets_try_it_in_60_seconds_path.md
@@ -0,0 +1,27 @@
+---
+title: Caplets "try it in 60 seconds" path
+summary: Facts about Caplets "try it in 60 seconds" path
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:10:59.472Z'
+updatedAt: '2026-05-29T09:10:59.472Z'
+---
+## Reason
+Curate extracted facts from context
+
+## Raw Concept
+**Task:**
+Curate extracted facts
+
+**Timestamp:** 2026-05-29T09:10:59.470Z
+
+## Narrative
+### Structure
+Collected factual statements
+
+## Facts
+- **Caplets "try it in 60 seconds" path**: A new user can install, run, and see value quickly with no extra setup friction.
+- **Caplets "try it in 60 seconds" path**: The quickstart is accurate, but the payoff is not instantly obvious or demo-like.
+- **Caplets "try it in 60 seconds" path**: Setup works, but users may hit friction, missing examples, or unclear next steps.
+- **Caplets "try it in 60 seconds" path**: You have not watched enough fresh users try it yet.
diff --git a/.brv/context-tree/facts/project/card_grids.md b/.brv/context-tree/facts/project/card_grids.md
index 44867ba..77d470f 100644
--- a/.brv/context-tree/facts/project/card_grids.md
+++ b/.brv/context-tree/facts/project/card_grids.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:18:57.166Z'
-updatedAt: '2026-05-27T19:18:57.166Z'
+updatedAt: '2026-05-29T09:19:16.203Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for card grids
## Facts
-- **card grids**: Identical card grids with repeated icon, heading, and text are banned.
+- **card grids**: Identical card grids with repeated icon, heading, and text are prohibited.
diff --git a/.brv/context-tree/facts/project/color_specification.md b/.brv/context-tree/facts/project/color_specification.md
index edceac5..288ec28 100644
--- a/.brv/context-tree/facts/project/color_specification.md
+++ b/.brv/context-tree/facts/project/color_specification.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:12:30.292Z'
-updatedAt: '2026-05-27T19:18:57.138Z'
+updatedAt: '2026-05-29T09:19:16.171Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for color specification
## Facts
- **color specification**: Use OKLCH for colors and reduce chroma as lightness approaches 0 or 100.
diff --git a/.brv/context-tree/facts/project/color_strategy.md b/.brv/context-tree/facts/project/color_strategy.md
index 28db99a..e7b00cf 100644
--- a/.brv/context-tree/facts/project/color_strategy.md
+++ b/.brv/context-tree/facts/project/color_strategy.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:18:57.141Z'
-updatedAt: '2026-05-27T19:18:57.141Z'
+updatedAt: '2026-05-29T09:19:16.177Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for color strategy
## Facts
- **color strategy**: The "one accent ≤10%" rule applies only to the Restrained color strategy.
diff --git a/.brv/context-tree/facts/project/color_usage.md b/.brv/context-tree/facts/project/color_usage.md
index 10251aa..49928cf 100644
--- a/.brv/context-tree/facts/project/color_usage.md
+++ b/.brv/context-tree/facts/project/color_usage.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.598Z'
-updatedAt: '2026-05-27T19:18:57.134Z'
+updatedAt: '2026-05-29T09:19:16.167Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for color usage
## Facts
- **color usage**: Never use #000 or #fff; tint every neutral toward the brand hue.
diff --git a/.brv/context-tree/facts/project/communication_assets.md b/.brv/context-tree/facts/project/communication_assets.md
new file mode 100644
index 0000000..2916bfa
--- /dev/null
+++ b/.brv/context-tree/facts/project/communication_assets.md
@@ -0,0 +1,18 @@
+---
+title: Communication assets
+summary: Facts about communication assets
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:16:04.076Z'
+updatedAt: '2026-05-29T09:16:04.076Z'
+---
+## Reason
+Curate extracted factual statements
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+## Facts
+- **communication assets**: Include the headline in the README hero, landing page hero, GitHub description, social posts, HN title, demo visuals, benchmark framing, and MCP builder copy
diff --git a/.brv/context-tree/facts/project/context_loading.md b/.brv/context-tree/facts/project/context_loading.md
index 41e127e..c63f272 100644
--- a/.brv/context-tree/facts/project/context_loading.md
+++ b/.brv/context-tree/facts/project/context_loading.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.527Z'
-updatedAt: '2026-05-27T19:18:57.131Z'
+updatedAt: '2026-05-29T09:19:16.143Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for context loading
## Facts
- **context loading**: The loader looks at the project root by default and falls back to .agents/context/ and docs/ if the root is clean.
diff --git a/.brv/context-tree/facts/project/core_line.md b/.brv/context-tree/facts/project/core_line.md
new file mode 100644
index 0000000..6f93013
--- /dev/null
+++ b/.brv/context-tree/facts/project/core_line.md
@@ -0,0 +1,25 @@
+---
+title: Core line
+summary: Facts about core line
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.224Z'
+updatedAt: '2026-05-29T09:19:16.224Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 2 facts for core line
+
+## Facts
+- **core line**: The new core line is now: “Give your agents capabilities, not giant tool walls.”
+- **core line**: The new core line is: “Give your agents capabilities, not giant tool walls.”
diff --git a/.brv/context-tree/facts/project/design_md.md b/.brv/context-tree/facts/project/design_md.md
index 686548c..fb40301 100644
--- a/.brv/context-tree/facts/project/design_md.md
+++ b/.brv/context-tree/facts/project/design_md.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.556Z'
-updatedAt: '2026-05-27T19:18:57.128Z'
+updatedAt: '2026-05-29T09:19:16.138Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for DESIGN.md
## Facts
- **DESIGN.md**: DESIGN.md is optional, strongly recommended.
diff --git a/.brv/context-tree/facts/project/easing.md b/.brv/context-tree/facts/project/easing.md
new file mode 100644
index 0000000..ae960ca
--- /dev/null
+++ b/.brv/context-tree/facts/project/easing.md
@@ -0,0 +1,24 @@
+---
+title: Easing
+summary: Facts about easing
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.193Z'
+updatedAt: '2026-05-29T09:19:16.193Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for easing
+
+## Facts
+- **easing**: Use ease-out exponential curves (ease-out-quart, quint, expo) for motion; no bounce or elastic.
diff --git a/.brv/context-tree/facts/project/footer.md b/.brv/context-tree/facts/project/footer.md
new file mode 100644
index 0000000..7a45036
--- /dev/null
+++ b/.brv/context-tree/facts/project/footer.md
@@ -0,0 +1,24 @@
+---
+title: Footer
+summary: Facts about footer
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.217Z'
+updatedAt: '2026-05-29T09:19:16.217Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for footer
+
+## Facts
+- **footer**: Updated footer line in apps/landing/src/pages/index.astro.
diff --git a/.brv/context-tree/facts/project/glassmorphism.md b/.brv/context-tree/facts/project/glassmorphism.md
index daf2c8d..16ca871 100644
--- a/.brv/context-tree/facts/project/glassmorphism.md
+++ b/.brv/context-tree/facts/project/glassmorphism.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.633Z'
-updatedAt: '2026-05-27T19:18:57.163Z'
+updatedAt: '2026-05-29T09:19:16.198Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for glassmorphism
## Facts
-- **glassmorphism**: Glassmorphism as default is banned.
+- **glassmorphism**: Glassmorphism as default is prohibited.
diff --git a/.brv/context-tree/facts/project/gradient_text.md b/.brv/context-tree/facts/project/gradient_text.md
index 81cad04..bc2187b 100644
--- a/.brv/context-tree/facts/project/gradient_text.md
+++ b/.brv/context-tree/facts/project/gradient_text.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.631Z'
-updatedAt: '2026-05-27T19:18:57.155Z'
+updatedAt: '2026-05-29T09:19:16.196Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for gradient text
## Facts
-- **gradient text**: Gradient text using background-clip: text with a gradient background is banned.
+- **gradient text**: Gradient text using background-clip: text with a gradient background is prohibited.
diff --git a/.brv/context-tree/facts/project/hero_metric_template.md b/.brv/context-tree/facts/project/hero_metric_template.md
index 43c8123..7380527 100644
--- a/.brv/context-tree/facts/project/hero_metric_template.md
+++ b/.brv/context-tree/facts/project/hero_metric_template.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:18:57.165Z'
-updatedAt: '2026-05-27T19:18:57.165Z'
+updatedAt: '2026-05-29T09:19:16.201Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for hero-metric template
## Facts
-- **hero-metric template**: The hero-metric template is banned.
+- **hero-metric template**: The hero-metric template (big number, small label, supporting stats, gradient accent) is prohibited.
diff --git a/.brv/context-tree/facts/project/hero_section.md b/.brv/context-tree/facts/project/hero_section.md
new file mode 100644
index 0000000..94e8a1a
--- /dev/null
+++ b/.brv/context-tree/facts/project/hero_section.md
@@ -0,0 +1,24 @@
+---
+title: Hero section
+summary: Facts about hero section
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.214Z'
+updatedAt: '2026-05-29T09:19:16.214Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for hero section
+
+## Facts
+- **hero section**: Updated hero kicker, H1, hero lede, and definition copy in apps/landing/src/pages/index.astro.
diff --git a/.brv/context-tree/facts/project/hierarchy.md b/.brv/context-tree/facts/project/hierarchy.md
new file mode 100644
index 0000000..1f76670
--- /dev/null
+++ b/.brv/context-tree/facts/project/hierarchy.md
@@ -0,0 +1,24 @@
+---
+title: Hierarchy
+summary: Facts about hierarchy
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.191Z'
+updatedAt: '2026-05-29T09:19:16.191Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for hierarchy
+
+## Facts
+- **hierarchy**: Maintain a hierarchy through scale and weight contrast with at least a 1.25 ratio between steps.
diff --git a/.brv/context-tree/facts/project/impeccable_context_dir.md b/.brv/context-tree/facts/project/impeccable_context_dir.md
index 00b3b4f..1ff2f6e 100644
--- a/.brv/context-tree/facts/project/impeccable_context_dir.md
+++ b/.brv/context-tree/facts/project/impeccable_context_dir.md
@@ -5,20 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:12:30.267Z'
-updatedAt: '2026-05-27T19:12:30.267Z'
+updatedAt: '2026-05-29T09:19:16.146Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:12:30.245Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Extracted facts for IMPECCABLE_CONTEXT_DIR
+### Highlights
+Extracted 1 facts for IMPECCABLE_CONTEXT_DIR
+
## Facts
-- **IMPECCABLE_CONTEXT_DIR**: The context directory can be overridden with IMPECCABLE_CONTEXT_DIR=path/to/dir (absolute or relative to cwd).
+- **IMPECCABLE_CONTEXT_DIR**: Override the context directory with IMPECCABLE_CONTEXT_DIR=path/to/dir (absolute or relative to cwd).
diff --git a/.brv/context-tree/facts/project/line_length.md b/.brv/context-tree/facts/project/line_length.md
index 2e01239..bc87137 100644
--- a/.brv/context-tree/facts/project/line_length.md
+++ b/.brv/context-tree/facts/project/line_length.md
@@ -5,20 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:12:30.298Z'
-updatedAt: '2026-05-27T19:12:30.298Z'
+updatedAt: '2026-05-29T09:19:16.188Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:12:30.246Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Extracted facts for line length
+### Highlights
+Extracted 1 facts for line length
+
## Facts
-- **line length**: Body line length should be capped at 65–75 characters.
+- **line length**: Cap body line length at 65–75 characters.
diff --git a/.brv/context-tree/facts/project/loader_output.md b/.brv/context-tree/facts/project/loader_output.md
index 3a0158b..8f3849a 100644
--- a/.brv/context-tree/facts/project/loader_output.md
+++ b/.brv/context-tree/facts/project/loader_output.md
@@ -5,20 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:12:30.272Z'
-updatedAt: '2026-05-27T19:12:30.272Z'
+updatedAt: '2026-05-29T09:19:16.149Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:12:30.245Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Extracted facts for loader output
+### Highlights
+Extracted 1 facts for loader output
+
## Facts
- **loader output**: Never pipe the loader output through head, tail, grep, or jq.
diff --git a/.brv/context-tree/facts/project/log.md b/.brv/context-tree/facts/project/log.md
new file mode 100644
index 0000000..4c94e1f
--- /dev/null
+++ b/.brv/context-tree/facts/project/log.md
@@ -0,0 +1,24 @@
+---
+title: Log
+summary: Facts about log
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.226Z'
+updatedAt: '2026-05-29T09:19:16.226Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for log
+
+## Facts
+- **log**: There were 0 errors, 0 warnings, and 0 hints.
diff --git a/.brv/context-tree/facts/project/missing_design_md.md b/.brv/context-tree/facts/project/missing_design_md.md
index 5cc4739..a06ff21 100644
--- a/.brv/context-tree/facts/project/missing_design_md.md
+++ b/.brv/context-tree/facts/project/missing_design_md.md
@@ -5,16 +5,16 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.588Z'
-updatedAt: '2026-05-27T19:12:30.278Z'
+updatedAt: '2026-05-29T09:19:16.164Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:12:30.246Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
@@ -24,4 +24,4 @@ Extracted facts for missing DESIGN.md
Extracted 1 facts for missing DESIGN.md
## Facts
-- **missing DESIGN.md**: If DESIGN.md is missing, the assistant should nudge the user once per session to run {{command_prefix}}impeccable document.
+- **missing DESIGN.md**: If DESIGN.md is missing, nudge once per session to run {{command_prefix}}impeccable document.
diff --git a/.brv/context-tree/facts/project/missing_product_md.md b/.brv/context-tree/facts/project/missing_product_md.md
index eb5d213..cdb6003 100644
--- a/.brv/context-tree/facts/project/missing_product_md.md
+++ b/.brv/context-tree/facts/project/missing_product_md.md
@@ -5,16 +5,16 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.563Z'
-updatedAt: '2026-05-27T19:12:30.274Z'
+updatedAt: '2026-05-29T09:19:16.161Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:12:30.246Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
@@ -24,4 +24,4 @@ Extracted facts for missing PRODUCT.md
Extracted 1 facts for missing PRODUCT.md
## Facts
-- **missing PRODUCT.md**: If PRODUCT.md is missing, empty, or contains placeholder markers (<200 chars), run {{command_prefix}}impeccable teach.
+- **missing PRODUCT.md**: If PRODUCT.md is missing, empty, or contains placeholder [TODO] markers under 200 characters, run {{command_prefix}}impeccable teach.
diff --git a/.brv/context-tree/facts/project/modal_usage.md b/.brv/context-tree/facts/project/modal_usage.md
new file mode 100644
index 0000000..db27862
--- /dev/null
+++ b/.brv/context-tree/facts/project/modal_usage.md
@@ -0,0 +1,24 @@
+---
+title: Modal usage
+summary: Facts about modal usage
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.205Z'
+updatedAt: '2026-05-29T09:19:16.205Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for modal usage
+
+## Facts
+- **modal usage**: Using a modal as the first thought is prohibited; prefer inline or progressive alternatives.
diff --git a/.brv/context-tree/facts/project/next_move.md b/.brv/context-tree/facts/project/next_move.md
new file mode 100644
index 0000000..20dfe0f
--- /dev/null
+++ b/.brv/context-tree/facts/project/next_move.md
@@ -0,0 +1,18 @@
+---
+title: Next move
+summary: Facts about next move
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:16:04.078Z'
+updatedAt: '2026-05-29T09:16:04.078Z'
+---
+## Reason
+Curate extracted factual statements
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+## Facts
+- **next move**: Best immediate next move: tighten the first-screen experience around that headline, then make the before and after demo impossible to miss
diff --git a/.brv/context-tree/facts/project/overall_content.md b/.brv/context-tree/facts/project/overall_content.md
new file mode 100644
index 0000000..ba5fb39
--- /dev/null
+++ b/.brv/context-tree/facts/project/overall_content.md
@@ -0,0 +1,18 @@
+---
+title: Overall content
+summary: Facts about overall content
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:16:04.075Z'
+updatedAt: '2026-05-29T09:16:04.075Z'
+---
+## Reason
+Curate extracted factual statements
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+## Facts
+- **overall content**: Everything else should reinforce that single idea
diff --git a/.brv/context-tree/facts/project/pnpm.md b/.brv/context-tree/facts/project/pnpm.md
new file mode 100644
index 0000000..0f53f14
--- /dev/null
+++ b/.brv/context-tree/facts/project/pnpm.md
@@ -0,0 +1,24 @@
+---
+title: Pnpm
+summary: Facts about pnpm
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.227Z'
+updatedAt: '2026-05-29T09:19:16.227Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for pnpm
+
+## Facts
+- **pnpm**: The command `pnpm --filter @caplets/landing build` completed successfully and built 1 page.
diff --git a/.brv/context-tree/facts/project/problem_section.md b/.brv/context-tree/facts/project/problem_section.md
new file mode 100644
index 0000000..2d72159
--- /dev/null
+++ b/.brv/context-tree/facts/project/problem_section.md
@@ -0,0 +1,24 @@
+---
+title: Problem section
+summary: Facts about problem section
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.216Z'
+updatedAt: '2026-05-29T09:19:16.216Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 1 facts for problem section
+
+## Facts
+- **problem section**: Reframed the problem section around “giant tool walls” in apps/landing/src/pages/index.astro.
diff --git a/.brv/context-tree/facts/project/product_md.md b/.brv/context-tree/facts/project/product_md.md
index 21638c3..7a8f8fb 100644
--- a/.brv/context-tree/facts/project/product_md.md
+++ b/.brv/context-tree/facts/project/product_md.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.543Z'
-updatedAt: '2026-05-27T19:18:57.122Z'
+updatedAt: '2026-05-29T09:19:16.127Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for PRODUCT.md
## Facts
- **PRODUCT.md**: PRODUCT.md is required.
diff --git a/.brv/context-tree/facts/project/punctuation.md b/.brv/context-tree/facts/project/punctuation.md
index 7d2a1c5..df45b25 100644
--- a/.brv/context-tree/facts/project/punctuation.md
+++ b/.brv/context-tree/facts/project/punctuation.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:47:50.642Z'
-updatedAt: '2026-05-27T19:18:57.169Z'
+updatedAt: '2026-05-29T09:19:16.207Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for punctuation
## Facts
-- **punctuation**: No em dashes are allowed; use commas, colons, semicolons, periods, or parentheses instead.
+- **punctuation**: No em dashes are allowed in copy; use commas, colons, semicolons, periods, or parentheses.
diff --git a/.brv/context-tree/facts/project/readme_md.md b/.brv/context-tree/facts/project/readme_md.md
new file mode 100644
index 0000000..618b147
--- /dev/null
+++ b/.brv/context-tree/facts/project/readme_md.md
@@ -0,0 +1,25 @@
+---
+title: README.md
+summary: Facts about README.md
+tags: []
+related: []
+keywords: []
+createdAt: '2026-05-29T09:19:16.218Z'
+updatedAt: '2026-05-29T09:19:16.218Z'
+---
+## Reason
+Curated factual statements from context extraction
+
+## Raw Concept
+**Task:**
+Document factual statements
+
+**Timestamp:** 2026-05-29T09:19:16.120Z
+
+## Narrative
+### Highlights
+Extracted 2 facts for README.md
+
+## Facts
+- **README.md**: Updated hero tagline in README.md.
+- **README.md**: Added sharper “Stop dumping every operation into context up front” positioning in README.md.
diff --git a/.brv/context-tree/facts/project/theme_selection.md b/.brv/context-tree/facts/project/theme_selection.md
index dacd49b..ef0796b 100644
--- a/.brv/context-tree/facts/project/theme_selection.md
+++ b/.brv/context-tree/facts/project/theme_selection.md
@@ -5,23 +5,23 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T19:12:30.296Z'
-updatedAt: '2026-05-27T19:18:57.148Z'
+updatedAt: '2026-05-29T09:19:16.185Z'
---
## Reason
-Curated facts extracted from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document project facts
+Document factual statements
-**Timestamp:** 2026-05-27T19:18:57.119Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
Collected factual statements
### Highlights
-Contains 1 facts
+Extracted 1 facts for theme selection
## Facts
-- **theme selection**: Dark vs. light theme is never a default; choose based on a physical scene description.
+- **theme selection**: Dark vs. light theme is never a default; choose based on a concrete physical scene description.
diff --git a/.brv/context-tree/facts/project/typecheck.md b/.brv/context-tree/facts/project/typecheck.md
index cd6ac9b..b51414b 100644
--- a/.brv/context-tree/facts/project/typecheck.md
+++ b/.brv/context-tree/facts/project/typecheck.md
@@ -5,16 +5,16 @@ tags: []
related: []
keywords: []
createdAt: '2026-05-27T18:59:51.354Z'
-updatedAt: '2026-05-28T13:55:17.303Z'
+updatedAt: '2026-05-29T09:19:16.220Z'
---
## Reason
-Curated extracted facts from context
+Curated factual statements from context extraction
## Raw Concept
**Task:**
-Document extracted factual statements
+Document factual statements
-**Timestamp:** 2026-05-28T13:55:17.267Z
+**Timestamp:** 2026-05-29T09:19:16.120Z
## Narrative
### Structure
@@ -24,4 +24,4 @@ Collected facts for typecheck
Extracted 1 facts for typecheck
## Facts
-- **typecheck**: pnpm --filter @caplets/landing typecheck passed with 0 errors, 0 warnings, and 0 hints.
+- **typecheck**: Typecheck for @caplets/landing completed with 0 errors, 0 warnings, and 0 hints.
diff --git a/.changeset/quick-setup-cli.md b/.changeset/quick-setup-cli.md
new file mode 100644
index 0000000..d68ff32
--- /dev/null
+++ b/.changeset/quick-setup-cli.md
@@ -0,0 +1,8 @@
+---
+"@caplets/core": patch
+"@caplets/opencode": patch
+"@caplets/pi": patch
+"caplets": patch
+---
+
+Add `caplets setup` to install or configure supported agent integrations.
diff --git a/.gitignore b/.gitignore
index 6a7c5eb..7c7430c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,6 @@ benchmark-results/
.env*
!.env.example
+
+# impeccable
+.impeccable/live
diff --git a/.impeccable/critique/2026-05-29T10-04-14Z__apps-landing-src-pages-index-astro.md b/.impeccable/critique/2026-05-29T10-04-14Z__apps-landing-src-pages-index-astro.md
new file mode 100644
index 0000000..db33a28
--- /dev/null
+++ b/.impeccable/critique/2026-05-29T10-04-14Z__apps-landing-src-pages-index-astro.md
@@ -0,0 +1,108 @@
+---
+target: apps/landing/src/pages/index.astro
+total_score: 26
+p0_count: 0
+p1_count: 2
+timestamp: 2026-05-29T10-04-14Z
+slug: apps-landing-src-pages-index-astro
+---
+
+#### Design Health Score
+
+| # | Heuristic | Score | Key Issue |
+| --------- | --------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| 1 | Visibility of System Status | 3 | Copy buttons have feedback and tabs expose selected state, but there is no visible install success path or live state beyond copy feedback. |
+| 2 | Match System / Real World | 3 | The core metaphor, capabilities instead of tool walls, is concrete for agent builders. Some labels still assume MCP fluency. |
+| 3 | User Control and Freedom | 3 | Anchor navigation, copy fallback, and tab keyboard controls are solid. Hidden inactive panels create many invisible buttons in the DOM, but not user-visible traps. |
+| 4 | Consistency and Standards | 3 | Visual system is cohesive, but numbered top nav and repeated eyebrow cadence conflict with the otherwise product-specific voice. |
+| 5 | Error Prevention | 2 | Install commands are copyable, but there is no guardrail for prerequisites, failed installs, or what users should verify after `caplets serve`. |
+| 6 | Recognition Rather Than Recall | 3 | The trace, proof panel, and install path make the model visible. Some advanced terms, `get_caplet`, `structuredContent`, and MCP client setup, rely on prior knowledge. |
+| 7 | Flexibility and Efficiency of Use | 3 | Agent-specific tabs and copy buttons support fast use. The page does not yet expose a shortest path for experienced users above the fold. |
+| 8 | Aesthetic and Minimalist Design | 2 | Strong editorial direction, but the page is long, card-heavy, and still carries AI-pattern residue: numbered nav, eyebrow chips, wide shadows, and many bordered containers. |
+| 9 | Error Recovery | 2 | The product concept explains scoped error recovery, but the landing page does not help users recover from install or setup failure. |
+| 10 | Help and Documentation | 2 | GitHub/config links exist, but contextual help is light and task-focused docs are not surfaced near the install commands. |
+| **Total** | | **26/40** | **Acceptable: strong message, needs hierarchy and activation polish before broad launch.** |
+
+#### Anti-Patterns Verdict
+
+**LLM assessment**: This does not look like generic AI slop at first glance. The message is specific, the trace card is relevant, and the benchmark proof creates a sharper story than a normal SaaS landing page. The slop risk is structural rather than visual: too many sections use the same formula of small label, large heading, bordered container, and explanatory prose. The page says progressive disclosure, but the page itself asks visitors to process a long sequence of similarly weighted proof blocks.
+
+**Deterministic scan**: The CLI detector found 2 issues in `apps/landing/src/pages/index.astro`:
+
+- `em-dash-overuse`, warning, line 0: reported 5 `--` sequences. This is mostly a false positive from command-line flags like `--command` and frontmatter delimiters, not body copy.
+- `numbered-section-markers`, advisory, line 0: top navigation uses `01`, `02`, `03`, which matches the numbered editorial scaffold ban.
+
+**Browser overlay / console evidence**: Injection succeeded on the live page at `http://127.0.0.1:4321/`. The detector console reported: uppercase body text, hero eyebrow chip, oversized H1, 1px border plus 100px shadow blur, wide tracking, long line length around 143 chars, and overused primary font. Several are advisory or noisy, but two align with the manual review: the eyebrow/numbered scaffold and the thin-border plus wide-shadow pattern.
+
+#### Overall Impression
+
+The landing page has a real argument: Caplets reduces tool-wall overload with progressive discovery. The best parts are the hero trace, the before/after comparison, and the deterministic benchmark proof. The biggest opportunity is to make the page behave like the product promise: one clear capability story first, then deeper evidence only as needed. Right now it still feels like every section is competing to prove the same point.
+
+#### What's Working
+
+1. **The core claim is memorable and specific.** “Capabilities, not giant tool walls” names the pain and the mechanism. It is much stronger than a vague agent-platform tagline.
+2. **The trace card demonstrates the product instead of decorating it.** The hero’s `get_caplet → search_tools → get_tool → call_tool` flow helps technical readers understand the mental model quickly.
+3. **The benchmark proof has launch value.** “106 flat tools became 3 capability cards” is concrete enough for Reddit, HN, and agent-builder audiences, provided the visual treatment stays sober.
+
+#### Priority Issues
+
+**[P1] The page contradicts its own progressive-disclosure premise**
+
+- **Why it matters**: The product says agents should not see every operation up front, but the landing page gives humans many similarly weighted sections, cards, proof blocks, tabs, trust details, and install steps. The message is right, but the experience still feels like a tool wall translated into marketing sections.
+- **Fix**: Collapse the middle of the page into a tighter narrative: hero trace, benchmark proof, one trust strip, then install. Move secondary explanatory cards into expandable details or lower-priority documentation links.
+- **Suggested command**: `$impeccable distill apps/landing/`
+
+**[P1] The activation path is too late and too similar in weight to the rest of the page**
+
+- **Why it matters**: Agent power users want the quickest route to proof. They should be able to install, add Context7, and recognize the aha moment without scrolling past multiple conceptual sections.
+- **Fix**: Promote the Context7 aha path closer to the hero, or add a compact “Try it in 60 seconds” strip immediately after the hero/proof pair. Keep the final install card, but make it the expanded version, not the first activation cue.
+- **Suggested command**: `$impeccable onboard apps/landing/`
+
+**[P2] AI-pattern residue weakens an otherwise specific brand**
+
+- **Why it matters**: The audience is agent power users and MCP server builders, exactly the people most sensitive to AI-generated landing-page tropes. Numbered nav markers, repeated eyebrow labels, wide tracking, and bordered card repetition make the page feel more templated than the product deserves.
+- **Fix**: Remove `01/02/03` from nav, reduce eyebrow frequency, replace at least one card grid with a more native artifact, such as a config diff, terminal transcript, or source manifest.
+- **Suggested command**: `$impeccable quieter apps/landing/`
+
+**[P2] Setup confidence is incomplete**
+
+- **Why it matters**: The page gets users to `caplets serve`, but does not answer “what should I see next?” or “what if it fails?” That creates a trust gap at the exact moment activation should peak.
+- **Fix**: Add expected output and verification after the commands: one capability appears, then `get_caplet`, then scoped discovery. Add one concise troubleshooting line for Node version, missing `npx`, or MCP client connection.
+- **Suggested command**: `$impeccable harden apps/landing/`
+
+**[P3] The hero visual treatment still has a heavy SaaS-card smell**
+
+- **Why it matters**: The trace card is conceptually good, but the 1px border plus broad soft shadow pattern is a known AI/devtool visual tell. It makes the strongest artifact feel more generic than it needs to.
+- **Fix**: Either commit to a flatter technical artifact, like a real terminal/config panel with minimal shadow, or make it feel like a source manifest with sharper borders and less blur.
+- **Suggested command**: `$impeccable polish apps/landing/`
+
+#### Persona Red Flags
+
+**Jordan, first-time agent-tool user**
+
+- Primary action: understand what Caplets does, then try it.
+- Red flags: `MCP`, `structuredContent`, `get_caplet`, `search_tools`, and `call_tool` appear before enough plain-language anchoring for a new user. Jordan understands the headline but may not know whether Caplets is a CLI, MCP server, plugin, or framework until later.
+
+**Riley, deliberate stress tester**
+
+- Primary action: verify the claims before installing.
+- Red flags: the benchmark claim is strong, but the page does not directly link from the proof asset to the deterministic benchmark report. Riley will want the source of “106 flat tools” and the exact test conditions.
+
+**Casey, distracted mobile user**
+
+- Primary action: scan on a phone, save or try later.
+- Red flags: mobile has no horizontal overflow, which is good, but the hero alone is very tall and the full page is long. Casey reaches the install section only after several large sections. The top nav is available, but the primary “try it” cue is not persistent or early enough.
+
+#### Minor Observations
+
+- Touch targets are generally good, with most links and buttons at or above 44px.
+- The hidden copy buttons in inactive tab panels show as 0×0 in measurement because panels are hidden. That is acceptable if screen reader exposure is also hidden by the `hidden` attribute.
+- The repeated section-note/kicker pattern is useful in moderation, but the page uses it often enough to become a rhythm rather than a decision.
+- The installed command now uses `context7`, which matches the activation story better than the older `docs` alias.
+- The body background and warm tokens are established identity in this repo, but they still sit close to the current AI “paper” default. The dark integrations section helps break that pattern.
+
+#### Questions to Consider
+
+- What if the page had only one deep technical artifact above the fold, then let proof and install orbit around it?
+- What would change if “try Context7 in 60 seconds” were the second thing users saw?
+- Which details belong on the landing page, and which belong in docs for users already convinced?
diff --git a/.impeccable/critique/2026-05-29T16-03-18Z__apps-landing-src-pages-index-astro.md b/.impeccable/critique/2026-05-29T16-03-18Z__apps-landing-src-pages-index-astro.md
new file mode 100644
index 0000000..404d3a6
--- /dev/null
+++ b/.impeccable/critique/2026-05-29T16-03-18Z__apps-landing-src-pages-index-astro.md
@@ -0,0 +1,90 @@
+---
+target: apps/landing/src/pages/index.astro
+total_score: 28
+p0_count: 0
+p1_count: 2
+timestamp: 2026-05-29T16-03-18Z
+slug: apps-landing-src-pages-index-astro
+---
+
+Design Health Score
+
+| # | Heuristic | Score | Key Issue |
+| ----- | ------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------- |
+| 1 | Visibility of System Status | 3 | The trace status and active step are strong, but remote setup status is not as immediately legible. |
+| 2 | Match System / Real World | 3 | The inspect/search/schema/call story maps well to agent behavior; remote server copy is accurate but abstract. |
+| 3 | User Control and Freedom | 3 | Theme, tabs, copy buttons, and hover interruption are solid; the hero animation still competes with direct scanning. |
+| 4 | Consistency and Standards | 3 | Radius tokens and tab patterns are much improved; mono labels and pills are now used heavily enough to blur hierarchy. |
+| 5 | Error Prevention | 2 | Setup snippets are copyable, but commands omit enough real-world auth caveats that users may hit avoidable dead ends. |
+| 6 | Recognition Rather Than Recall | 3 | The capability trace teaches the model; the remote value still asks visitors to infer why this changes daily use. |
+| 7 | Flexibility and Efficiency | 3 | Tabs and examples support different agents and caplets; mobile hides too much trace detail to stay educational. |
+| 8 | Aesthetic and Minimalist Design | 3 | The page has a clear point of view, but the dark remote/setup slabs make the middle of the page feel heavier than the hero. |
+| 9 | Error Recovery | 2 | Copy fallback exists, but no setup troubleshooting path is embedded beyond brief text. |
+| 10 | Help and Documentation | 3 | Benchmark and repo links are present; the page could route users from each example to its exact CAPLET.md. |
+| Total | | 28/40 | Strong, shippable, still a bit explanation-heavy. |
+
+Anti-Patterns Verdict
+
+LLM assessment: This no longer reads like a generic AI landing page. The hero proposition is specific, the trace reactor is a real visual artifact, and the setup content is product-grounded. The remaining slop risk is not visual cliché so much as developer-page density: labels, pills, snippets, terminals, and muted panels repeat until the page starts feeling like a reference doc wearing a campaign outfit.
+
+Deterministic scan: Clean. The bundled detector returned zero findings for apps/landing/src/pages/index.astro.
+
+Visual overlays: Browser overlay injection was not available in this session. Fallback evidence used: live dev-server HTML fetched successfully from http://100.120.25.110:4321/, source inspection, detector output, campaign check, and Astro typecheck.
+
+Overall Impression
+
+The landing page is much stronger than where it started: the motto is crisp, the hero teaches the core mechanism, and the remote/server story finally has a home. The single biggest opportunity is to turn the lower half from "complete documentation preview" into a sharper conversion path. The page proves Caplets works; now it needs to make the next action feel inevitable.
+
+What's Working
+
+1. The hero is finally anchored by the right product sentence: "Give your agent capabilities, not tools" in apps/landing/src/pages/index.astro:264. It is concrete and differentiated.
+2. The trace reactor is the page's best asset. It explains progressive disclosure visually, not just verbally, with source/auth/state/steps in apps/landing/src/pages/index.astro:275-323.
+3. The new setup sequence is directionally right: integration first, then premade caplet examples, with GitHub/Sourcegraph/OSV showing different value shapes in apps/landing/src/pages/index.astro:417-540.
+
+Priority Issues
+
+[P1] The hero gives away too much educational surface on mobile
+Why it matters: At max-width 980px and 720px, CSS hides metadata, step descriptions, and code results from the trace (apps/landing/src/styles/global.css:1469-1473 and 1626-1651). That prevents overflow, but it also strips the hero's main proof object down to labels. A first-time mobile visitor sees the claim, not the mechanism.
+Fix: Replace the full reactor with a dedicated mobile trace summary: one compact source/auth row, four tappable steps, and the active result shown in a single fixed output well below the tabs. Do not just hide fields.
+Suggested command: $impeccable adapt landing
+
+[P1] The remote story says the value, but does not dramatize the pain it solves
+Why it matters: The section explains auth centralization in apps/landing/src/pages/index.astro:343-414, but it does not show the before/after: repeated local auth per client versus one server-held provider token reused everywhere. Users who do not already feel that pain may miss why the remote mode matters.
+Fix: Reframe the section around a two-state comparison: "Without remote Caplets" and "With remote Caplets". Keep the snippets, but make the auth reuse the hero of the layout, not a paragraph.
+Suggested command: $impeccable clarify landing
+
+[P2] The setup area is useful but visually over-weighted
+Why it matters: The integrations section is a large dark block, followed by a lighter activation block with another tab system. Both are valid, but together they create a dense reference-zone after the benchmark. The conversion path becomes: choose integration, read config, pick example, read commands, copy. That is a lot of micro-decisions.
+Fix: Make Setup a guided two-step: Step 1 integration, Step 2 first caplet. Keep tabs, but reduce visible chrome and collapse secondary examples until the selected path is understood.
+Suggested command: $impeccable distill landing
+
+[P2] The page still relies too much on mono pills as the main explanatory language
+Why it matters: Pills are used for nav, integration tabs, example tabs, discovery paths, status, copy buttons, and labels. It creates consistency, but it also makes very different actions and concepts feel equally important.
+Fix: Reserve filled pills for selected state and actual capability identity. Use quieter text links or segmented controls for navigation; use plain inline code for discovery operations.
+Suggested command: $impeccable typeset landing
+
+[P3] The proof strip underplays the benchmark emotionally
+Why it matters: The benchmark is strong, but apps/landing/src/pages/index.astro:327-340 presents it as a thin row. It is easy to scan past despite being one of the most persuasive claims on the page.
+Fix: Give the benchmark one decisive sentence and a small before/after payload visualization. Avoid hero-metric cliché; use the actual 106 -> 3 reduction as a compact structural diagram.
+Suggested command: $impeccable bolder landing
+
+Persona Red Flags
+
+Jordan, first-time agent tool user: Jordan understands the headline, but the trace loses meaning on mobile because descriptions and results are hidden. The remote section assumes they already know why provider auth spread across clients is annoying.
+
+Riley, power user evaluating install friction: Riley likes copyable snippets and tabs, but wants exact links from each premade example to its source CAPLET.md, plus clearer command/auth expectations before copying.
+
+Sam, skeptical maintainer: Sam is persuaded by the deterministic benchmark, but the proof strip is visually quiet. They may miss the strongest evidence unless they intentionally read the whole page.
+
+Minor Observations
+
+- The kicker "Agent tools without the wall" is clear, but it is close enough to the H1 that it may be redundant.
+- The remote endpoints row is accurate, but endpoints are lower-value than the auth reuse story for a landing page.
+- The page uses Inter, which is serviceable, but the brand could eventually benefit from a less default technical sans once layout stabilizes.
+- The footer motto still says "giant tool walls" while the H1 says "not tools"; the H1 is stronger.
+
+Questions to Consider
+
+- What is the one setup path the page most wants a new user to complete in the first minute: Codex + GitHub, or agent-agnostic install?
+- Should the remote story be a proof section, a setup mode, or a hero-adjacent value prop?
+- Is the benchmark supposed to reassure after the hero, or should it be the main persuasion engine?
diff --git a/.oxfmtrc.json b/.oxfmtrc.json
index 64d8512..2f61360 100644
--- a/.oxfmtrc.json
+++ b/.oxfmtrc.json
@@ -1,4 +1,13 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
- "ignorePatterns": [".brv/"]
+ "ignorePatterns": [".brv/"],
+ "plugins": ["prettier-plugin-astro"],
+ "overrides": [
+ {
+ "files": ["*.astro"],
+ "options": {
+ "parser": "astro"
+ }
+ }
+ ]
}
diff --git a/README.md b/README.md
index f4455f2..2ac9e53 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
Caplets
- Give agents capabilities, not tool walls.
+ Give your agent capabilities, not tools.
Turn MCP servers, APIs, and commands into focused agent capabilities.
@@ -28,10 +28,23 @@
Caplets turns MCP servers, APIs, and commands into focused agent capabilities: one card first, searchable tools next, inspectable schemas before calls, and preserved results after.
-Caplets wraps each tool source as a capability an agent can discover, inspect, call, and recover from one step at a time. Instead of exposing a flat wall of operations, Caplets shows a compact capability card with source, status, and next actions. The agent chooses a domain first, then uses scoped operations like `search_tools`, `get_tool`, and `call_tool` only when it needs more detail.
+Stop dumping every operation into context up front. Caplets wraps each tool source as a capability an agent can discover, inspect, call, and recover from one step at a time. Instead of exposing a giant flat wall of operations, Caplets shows a compact capability card with source, status, and next actions. The agent chooses a domain first, then uses scoped operations like `search_tools`, `get_tool`, and `call_tool` only when it needs more detail.
For MCP-backed Caplets, the scoped operation set also includes resource discovery and reading, prompt listing and rendering, resource-template discovery, and completion for prompt or template arguments. Non-MCP backends expose focused tool and action operations.
+## Try the aha moment
+
+Install Caplets, add Context7, and watch your agent see one capability before it searches downstream tools.
+
+```sh
+npm install -g caplets
+caplets init
+caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp
+caplets serve
+```
+
+In the deterministic benchmark, 106 flat tools became 3 top-level capabilities with an 87.9% smaller initial payload. Your agent starts with `context7`, then drills in through `inspect`, `search_tools`, `get_tool`, and `call_tool` only when needed.
+
## Quick Start
Caplets requires Node.js 22 or newer.
@@ -73,7 +86,7 @@ caplets install spiritledsoftware/caplets github linear context7
Configured Caplets can be invoked directly from the CLI for agent-friendly scripts and smoke tests:
```sh
-caplets get-caplet context7
+caplets inspect context7
caplets list-tools context7
caplets get-tool context7 resolve-library-id
caplets call-tool context7 resolve-library-id --args '{"libraryName":"react"}'
@@ -478,8 +491,11 @@ tags:
- code
- review
mcpServer:
- command: npx
- args: ["-y", "github-mcp-server"]
+ transport: http
+ url: https://api.githubcopilot.com/mcp
+ auth:
+ type: bearer
+ token: $env:GH_TOKEN
---
# GitHub
@@ -573,7 +589,7 @@ normal Markdown links from `CAPLET.md`.
This repository includes polished working examples under [`caplets/`](caplets/):
-- `github`: GitHub's official MCP server container, using `GITHUB_PERSONAL_ACCESS_TOKEN`.
+- `github`: GitHub's hosted MCP endpoint, using `GH_TOKEN`.
- `linear`: Linear's hosted OAuth MCP endpoint.
- `context7`: Context7 documentation lookup through `@upstash/context7-mcp`.
- `repo-cli`: Read-oriented repository CLI workflows through `git` and package scripts.
@@ -871,7 +887,7 @@ an existing destination file.
### Caplet Sets
Use `capletSets` to expose another Caplets collection as nested Caplets. Each child Caplet appears
-as one downstream tool and supports the full Caplets operation set: `get_caplet`, `check_backend`,
+as one downstream tool and supports the full Caplets operation set: `inspect`, `check_backend`,
`list_tools`, `search_tools`, `get_tool`, and `call_tool`.
```json
@@ -1011,6 +1027,34 @@ top-level MCP tool list without restarting Caplets. When an MCP-backed Caplet ch
removed, Caplets closes only that affected downstream connection; unrelated Caplets and
their downstream connections keep running.
+## Quick Integration Setup
+
+Use `caplets setup` to install or configure an agent integration:
+
+```bash
+caplets setup codex
+caplets setup claude-code
+caplets setup opencode
+caplets setup pi
+caplets setup mcp-client --output ./caplets.mcp.json
+```
+
+Preview the actions before changing anything:
+
+```bash
+caplets setup codex --dry-run
+```
+
+For native integrations that should connect to a remote Caplets HTTP service:
+
+```bash
+caplets setup opencode --remote --server-url https://caplets.example.com/caplets
+```
+
+`caplets setup` runs the supported agent installer commands or writes the explicit config
+path you pass with `--output`. It does not store secrets, edit unknown MCP client config
+locations, or start `caplets serve`.
+
## Additional Native Integrations
OpenCode and Pi support true native tool registration. Those integrations expose one
@@ -1076,7 +1120,7 @@ Call one exact downstream tool:
Available operations:
-- `get_caplet`: return the configured capability card without starting the downstream server.
+- `inspect`: return the configured capability card without starting the downstream server.
- `check_backend`: verify the selected backend, whether MCP, OpenAPI, GraphQL, HTTP, CLI, or nested Caplets.
- `list_tools`: return compact downstream tool metadata.
- `search_tools`: search downstream tool names and descriptions within this Caplet.
@@ -1086,7 +1130,7 @@ Available operations:
Requests are strict: operation-specific extra fields are rejected, and `call_tool` requires
`arguments` to be a JSON object.
-Discovery operations (`get_caplet`, `check_backend`, `list_tools`, `search_tools`, and
+Discovery operations (`inspect`, `check_backend`, `list_tools`, `search_tools`, and
`get_tool`) return wrapper-generated results whose `structuredContent.caplets` field
identifies the Caplet with `id`, plus backend, operation, status, and elapsed time when
available. Discovery result objects and compact tool entries also use `id` for the
diff --git a/apps/landing/package.json b/apps/landing/package.json
index 174619b..f57b542 100644
--- a/apps/landing/package.json
+++ b/apps/landing/package.json
@@ -8,12 +8,14 @@
"build": "astro build",
"dev": "astro dev",
"preview": "astro preview",
- "typecheck": "astro check"
+ "typecheck": "astro check",
+ "campaign:check": "node test/campaign-copy.check.mjs"
},
"dependencies": {
"@astrojs/check": "^0.9.9",
+ "@hugeicons/core-free-icons": "4.2.0",
"@tailwindcss/vite": "^4.3.0",
- "astro": "^6.3.8",
+ "astro": "^6.4.2",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.3"
},
diff --git a/apps/landing/public/icon-header-dark.png b/apps/landing/public/icon-header-dark.png
new file mode 100644
index 0000000..7f54aa6
Binary files /dev/null and b/apps/landing/public/icon-header-dark.png differ
diff --git a/apps/landing/public/icon-header-light.png b/apps/landing/public/icon-header-light.png
new file mode 100644
index 0000000..7f54aa6
Binary files /dev/null and b/apps/landing/public/icon-header-light.png differ
diff --git a/apps/landing/src/components/HugeIcon.astro b/apps/landing/src/components/HugeIcon.astro
new file mode 100644
index 0000000..061b785
--- /dev/null
+++ b/apps/landing/src/components/HugeIcon.astro
@@ -0,0 +1,19 @@
+---
+type HugeIconNode = readonly [string, { readonly [key: string]: string | number }];
+
+type Props = {
+ icon: readonly HugeIconNode[];
+ class?: string;
+};
+
+const { icon, class: className } = Astro.props;
+---
+
+
+ {
+ icon.map(([tag, attrs]) => {
+ const Element = tag;
+ return ;
+ })
+ }
+
diff --git a/apps/landing/src/pages/index.astro b/apps/landing/src/pages/index.astro
index 9258646..8ae2edf 100644
--- a/apps/landing/src/pages/index.astro
+++ b/apps/landing/src/pages/index.astro
@@ -1,5 +1,7 @@
---
import "../styles/global.css";
+import { Cancel01Icon, CheckIcon, Copy01Icon, Menu01Icon } from "@hugeicons/core-free-icons";
+import HugeIcon from "../components/HugeIcon.astro";
const heroTrace = {
capability: "github",
@@ -8,7 +10,7 @@ const heroTrace = {
auth: "token present, redacted",
steps: [
{
- label: "get_caplet",
+ label: "inspect",
detail: "Show one capability card before any downstream tool list enters context.",
result: "search_tools · get_tool · call_tool",
},
@@ -30,45 +32,69 @@ const heroTrace = {
],
};
-const capabilityFramework = [
+const heroCommands = [
{
- title: "One capability first",
- copy: "Each tool source enters agent context as a focused card with source, status, and next actions, not a long list of operations.",
+ label: "Install",
+ command: "npm install -g caplets",
},
{
- title: "Schemas before calls",
- copy: "Agents search inside one capability, then inspect the exact tool schema before they invoke anything.",
- },
- {
- title: "Results stay intact",
- copy: "Caplets preserves structured content, resource links, images, and downstream errors instead of flattening results away.",
+ label: "Setup",
+ command: "caplets setup codex",
},
];
-const trustMechanics = [
+const proofStats = [
+ {
+ value: "106",
+ label: "flat tools",
+ detail: "Direct MCP aggregation exposes every downstream operation up front.",
+ },
{
- label: "Source",
- value: ".caplets/config.json",
- copy: "Users can see where the capability came from before trusting it.",
+ value: "3",
+ label: "capability cards",
+ detail: "Caplets starts with one focused card per tool source.",
},
{
- label: "Auth",
- value: "GITHUB_TOKEN: redacted",
- copy: "Secrets stay hidden while auth state remains inspectable.",
+ value: "87.9%",
+ label: "smaller initial payload",
+ detail: "The deterministic benchmark cuts serialized tool metadata before discovery.",
},
+];
+
+const proofComparison = [
+ { label: "Direct MCP", value: "106", detail: "flat tools up front" },
+ { label: "Caplets", value: "3", detail: "capability cards first" },
+];
+
+const remoteCommands = {
+ server: `CAPLETS_SERVER_URL=https://caplets.example.com/caplets
+CAPLETS_SERVER_PASSWORD=...
+caplets serve --transport http`,
+ client: `CAPLETS_MODE=remote
+CAPLETS_SERVER_URL=https://caplets.example.com/caplets
+CAPLETS_SERVER_PASSWORD=...
+opencode`,
+};
+
+const remoteEndpoints = [
+ { label: "MCP", value: "/caplets/mcp" },
+ { label: "Control", value: "/caplets/control" },
+ { label: "Health", value: "/caplets/healthz" },
+];
+
+const remoteComparison = [
{
- label: "Timeout",
- value: "30s boundary",
- copy: "Slow or stuck tools fail visibly instead of disappearing into agent context."
+ label: "Without remote Caplets",
+ detail: "Each agent client needs its own provider tokens, OAuth login, and local MCP wiring.",
+ points: ["Repeat auth per client", "Duplicate secrets", "Debug setup in every agent"],
},
{
- label: "Error",
- value: "safe message + raw detail scoped",
- copy: "Recovery information stays useful without leaking sensitive configuration.",
+ label: "With remote Caplets",
+ detail: "One server holds provider auth; every agent connects to the same capability surface.",
+ points: ["Auth once on the server", "Reuse from Codex, OpenCode, Pi, Claude", "Inspect, search, schema, call everywhere"],
},
];
-const sources = ["MCP", "OpenAPI", "GraphQL", "HTTP", "CLI"];
const agentSetups = [
{
id: "claude-code",
@@ -130,14 +156,57 @@ pi install npm:@caplets/pi`,
},
];
-const integrations = agentSetups.map((agent) => agent.name);
-const themeColor = "oklch(97% 0.012 85)";
+const lightThemeColor = "oklch(97% 0.012 85)";
+const darkThemeColor = "oklch(18% 0.014 100)";
-const installSteps = [
- "npm install -g caplets",
- "caplets init",
- "caplets add mcp docs --command npx --arg -y --arg @upstash/context7-mcp",
- "caplets serve",
+const exampleCaplets = [
+ {
+ id: "github",
+ name: "GitHub",
+ summary: "A huge hosted MCP surface for repositories, issues, pull requests, branches, commits, and reviews.",
+ why: "Use it when the value is avoiding a giant GitHub tool wall.",
+ path: ["github", "inspect", "search_tools", "get_tool", "call_tool"],
+ steps: [
+ { command: "export GH_TOKEN=github_pat_...", label: "GitHub token export" },
+ {
+ command: "caplets install spiritledsoftware/caplets github",
+ label: "GitHub caplet install command",
+ },
+ { command: 'codex "try using the github caplet"', label: "Codex trial command" },
+ ],
+ help: ["If setup fails, check Node 22+, plugin installation, and ", "GH_TOKEN", "."],
+ },
+ {
+ id: "sourcegraph",
+ name: "Sourcegraph",
+ summary: "Hosted code search for finding examples, references, and implementation patterns across repositories.",
+ why: "Use it when the agent should search code first, then inspect only the matching operations.",
+ path: ["sourcegraph", "inspect", "search_tools", "get_tool", "call_tool"],
+ steps: [
+ {
+ command: "caplets install spiritledsoftware/caplets sourcegraph",
+ label: "Sourcegraph caplet install command",
+ },
+ { command: "caplets auth login sourcegraph", label: "Sourcegraph auth command" },
+ { command: 'codex "try using the sourcegraph caplet"', label: "Codex trial command" },
+ ],
+ help: ["If setup fails, check Node 22+, plugin installation, and Sourcegraph OAuth login."],
+ },
+ {
+ id: "osv",
+ name: "OSV",
+ summary: "A small explicit HTTP API for vulnerability lookups by package, purl, commit, or batch query.",
+ why: "Use it when Caplets should bound a sharp task without exposing arbitrary HTTP calls.",
+ path: ["osv", "inspect", "search_tools", "get_tool", "call_tool"],
+ steps: [
+ {
+ command: "caplets install spiritledsoftware/caplets osv",
+ label: "OSV caplet install command",
+ },
+ { command: 'codex "try using the osv caplet"', label: "Codex trial command" },
+ ],
+ help: ["OSV is public and does not need auth; check Node 22+ and plugin installation."],
+ },
];
---
@@ -150,25 +219,75 @@ const installSteps = [
-
- Caplets, capability cards for coding agents
+
+
+ Caplets, capabilities instead of giant tool walls
+
Skip to content
+
+
+
+
-
Capability cards for coding agents
-
Give agents capabilities, not tool walls.
+
Agent tools without the wall
+
Give your agent capabilities, not tools
- Caplets turns MCP servers, APIs, and commands into focused agent capabilities: one card
- first, searchable tools next, inspectable schemas before calls, and preserved results after.
-
-
- Wrap each MCP server, API, or command set as a capability an agent can discover, inspect,
- call, and recover from one step at a time.
+ Caplets wraps MCP servers, APIs, and commands as focused capabilities. Your agent picks a source,
+ searches inside it, inspects the schema, then calls the tool.
-
-
-
Sources
- {sources.join(" · ")}
-
-
-
Clients
-
{integrations.join(" · ")}
+
+
-
+
+ {heroCommands.map((item, index) => (
+
+ {String(index + 1).padStart(2, "0")}
+
+ {item.label}
+ {item.command}
+
+
+
+
+
+
+ ))}
+
+
-
-
-
-
-
source
-
{heroTrace.source}
+
+
+
-
-
auth
-
{heroTrace.auth}
+
+
+
source
+ {heroTrace.source}
+
+
+
auth
+ {heroTrace.auth}
+
+
+
+ {heroTrace.steps.map((step, index) => (
+
+
+
{step.label}
+
{step.detail}
+
+ {step.result}
+
+ ))}
+
+
+
{heroTrace.steps[0].label}
+
{heroTrace.steps[0].result}
+
{heroTrace.steps[0].detail}
-
-
- {heroTrace.steps.map((step) => (
-
-
-
{step.label}
-
{step.detail}
-
- {step.result}
-
- ))}
-
+
+
+
+
+
+
+
+
+
+ caplet
+ search
+ schema
+ call
+
+
+
-
-
-
The tool wall problem
-
Flat tool lists force agents to choose before they understand.
+
+
+
Deterministic benchmark
+
Direct MCP aggregation exposed 106 flat tools. Caplets started with 3 capability cards and an 87.9% smaller initial payload.
-
-
- Before
- Every operation enters context before the agent knows which one matters.
-
-
-
-
-
-
Capability-shaped tools
-
A tool source is safer for agents when it reveals itself in stages.
-
-
- {capabilityFramework.map((point, index) => (
-
- 0{index + 1}
- {point.title}
- {point.copy}
-
+ ))}
+
+
+ {proofComparison.map((item, index) => (
+ <>
+ {index > 0 &&
to }
+
+ {item.label}
+ {item.value}
+ {item.detail}
+
+ >
))}
+
Read benchmark method
-
-
-
Trust before invocation
-
Trust is visible before the call.
+
+
+
Remote Caplets server
+
Auth into tools once. Use them from every agent.
+
+ Run Caplets as a small HTTP service. Provider tokens and OAuth state stay with that
+ server; Codex, OpenCode, Pi, Claude Code, and any MCP client connect to the same
+ capability surface.
+
-
- {trustMechanics.map((item) => (
-
- {item.label}
- {item.value}
- {item.copy}
+
+ {remoteComparison.map((item) => (
+
+ {item.label}
+ {item.detail}
+
+ {item.points.map((point) => {point} )}
+
))}
-
-
Safe recovery example
-
- If a tool fails, Caplets keeps the error scoped to that capability, preserves useful
- recovery detail, and redacts sensitive configuration before it reaches the agent.
-
+
+
+
+ Server owns auth
+ GitHub, Sourcegraph, OSV
+
+
+
+ Caplets exposes
+ inspect · search · schema · call
+
+
+
+ Agents reuse it
+ Codex · OpenCode · Pi · Claude
+
+
+
+
+
+ Serve once
+
+
+
+
+
+
{remoteCommands.server}
+
+
+
+ Use remotely
+
+
+
+
+
+
{remoteCommands.client}
+
+
+
+ {remoteEndpoints.map((endpoint) => (
+
+
{endpoint.label}
+ {endpoint.value}
+
+ ))}
+
-
Works where agents work
-
Run Caplets from the coding agent you already use.
+
Step 1
+
Connect your agent to Caplets.
@@ -335,11 +570,14 @@ const installSteps = [
- Copy
+
+
{agent.installCommand}
@@ -350,11 +588,14 @@ const installSteps = [
- Copy
+
+
{agent.configSnippet}
@@ -366,41 +607,77 @@ const installSteps = [
-
-
-
Start with one tool source
-
Install Caplets, add a source, serve capabilities.
+
+
+
Step 2
+
Add one caplet and try the capability.
- Caplets can run as a universal MCP server, a native Pi or OpenCode tool layer, or a remote
- HTTP service for shared environments.
+ Pick the integration above, then try one premade Caplet. Your agent sees one focused
+ capability before it can search or call downstream tools.
-
-
-
-
-
- {installSteps.map((step, index) => (
-
- {step}
-
- Copy
+
+
+
+
+
+ {exampleCaplets.map((example) => (
+
+
+
Add {example.name}
+
{example.summary}
+
{example.why}
+
+ {example.path.map((step, index) => index === 0 ? {step} : {step} )}
+
+
+ {example.help.map((part) => part === "GH_TOKEN" ? {part} : part)}
+
+
+
+
+
+
+
+ {example.steps.map((step, index) => (
+
+ {step.command}
+
+
+
+
+
+ ))}
+
+
+
))}
-
+
@@ -432,7 +709,107 @@ const installSteps = [
const agentTablist = document.querySelector("[data-agent-tablist]");
const agentTabs = Array.from(document.querySelectorAll("[data-agent-tab]"));
const agentPanels = Array.from(document.querySelectorAll("[data-agent-panel]"));
+ const exampleTabsRoot = document.querySelector("[data-caplet-examples]");
+ const exampleTablist = document.querySelector("[data-example-tablist]");
+ const exampleTabs = Array.from(document.querySelectorAll("[data-example-tab]"));
+ const examplePanels = Array.from(document.querySelectorAll("[data-example-panel]"));
const copyButtons = Array.from(document.querySelectorAll("[data-copy-value]"));
+ const copyStatus = document.querySelector("[data-copy-status]");
+ const themeToggle = document.querySelector("[data-theme-toggle]");
+ const mobileMenu = document.querySelector("[data-mobile-menu]");
+ const mobileMenuOpen = document.querySelector("[data-mobile-menu-open]");
+ const mobileMenuClose = document.querySelector("[data-mobile-menu-close]");
+ const mobileMenuLinks = Array.from(document.querySelectorAll("[data-mobile-menu-link]"));
+ const systemThemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
+ const themeStorageKey = "caplets-theme";
+
+ function getStoredTheme() {
+ try {
+ const theme = localStorage.getItem(themeStorageKey);
+ return theme === "light" || theme === "dark" ? theme : null;
+ } catch {
+ return null;
+ }
+ }
+
+ function storeTheme(theme: "light" | "dark") {
+ try {
+ localStorage.setItem(themeStorageKey, theme);
+ } catch {}
+ }
+
+ function getResolvedTheme() {
+ return getStoredTheme() ?? (systemThemeQuery.matches ? "dark" : "light");
+ }
+
+ function applyResolvedTheme(theme: "light" | "dark") {
+ if (theme === "dark") {
+ document.documentElement.dataset.theme = "dark";
+ } else {
+ document.documentElement.dataset.theme = "light";
+ }
+ }
+
+ function syncThemeToggle() {
+ if (!themeToggle) return;
+
+ const resolvedTheme = getResolvedTheme();
+ const nextTheme = resolvedTheme === "dark" ? "light" : "dark";
+ themeToggle.dataset.resolvedTheme = resolvedTheme;
+ themeToggle.setAttribute("aria-label", `Use ${nextTheme} theme`);
+ themeToggle.setAttribute("aria-pressed", String(resolvedTheme === "dark"));
+ }
+
+ function setTheme(theme: "light" | "dark") {
+ applyResolvedTheme(theme);
+ storeTheme(theme);
+ syncThemeToggle();
+ }
+
+ applyResolvedTheme(getResolvedTheme());
+ syncThemeToggle();
+ systemThemeQuery.addEventListener("change", () => {
+ if (!getStoredTheme()) {
+ applyResolvedTheme(getResolvedTheme());
+ syncThemeToggle();
+ }
+ });
+
+ themeToggle?.addEventListener("click", () => {
+ const nextTheme = getResolvedTheme() === "dark" ? "light" : "dark";
+ setTheme(nextTheme);
+ });
+
+ function openMobileMenu() {
+ if (!mobileMenu || mobileMenu.open) return;
+ mobileMenu.showModal();
+ mobileMenuOpen?.setAttribute("aria-expanded", "true");
+ }
+
+ function closeMobileMenu() {
+ if (!mobileMenu?.open) return;
+ mobileMenu.close();
+ }
+
+ function syncMobileMenuState() {
+ mobileMenuOpen?.setAttribute("aria-expanded", String(Boolean(mobileMenu?.open)));
+ }
+
+ mobileMenuOpen?.addEventListener("click", openMobileMenu);
+ mobileMenuClose?.addEventListener("click", closeMobileMenu);
+ mobileMenu?.addEventListener("close", () => {
+ syncMobileMenuState();
+ mobileMenuOpen?.focus({ preventScroll: true });
+ });
+ mobileMenu?.addEventListener("click", (event: MouseEvent) => {
+ if (event.target === mobileMenu) closeMobileMenu();
+ });
+
+ for (const link of mobileMenuLinks) {
+ link.addEventListener("click", () => {
+ if (mobileMenu?.open) mobileMenu.close();
+ });
+ }
function selectAgentTab(selectedId: string) {
for (const tab of agentTabs) {
@@ -488,12 +865,68 @@ const installSteps = [
}
}
+ function selectExampleTab(selectedId: string) {
+ for (const tab of exampleTabs) {
+ const tabId = tab.dataset.exampleTab;
+ const isSelected = tabId === selectedId;
+ tab.setAttribute("role", "tab");
+ tab.setAttribute("aria-selected", String(isSelected));
+ if (tabId) tab.setAttribute("aria-controls", `example-panel-${tabId}`);
+ tab.tabIndex = isSelected ? 0 : -1;
+ }
+
+ for (const panel of examplePanels) {
+ const panelId = panel.dataset.examplePanel;
+ panel.setAttribute("role", "tabpanel");
+ if (panelId) panel.setAttribute("aria-labelledby", `example-tab-${panelId}`);
+ panel.hidden = panelId !== selectedId;
+ }
+ }
+
+ if (exampleTabsRoot && exampleTabs.length > 0 && examplePanels.length > 0) {
+ exampleTablist?.setAttribute("role", "tablist");
+ selectExampleTab(exampleTabs[0].dataset.exampleTab ?? "");
+
+ for (const tab of exampleTabs) {
+ tab.addEventListener("click", () => {
+ const selectedId = tab.dataset.exampleTab;
+ if (selectedId) selectExampleTab(selectedId);
+ });
+
+ tab.addEventListener("keydown", (event: KeyboardEvent) => {
+ const currentIndex = exampleTabs.indexOf(tab);
+ const lastIndex = exampleTabs.length - 1;
+ const nextIndex =
+ event.key === "ArrowRight"
+ ? currentIndex + 1
+ : event.key === "ArrowLeft"
+ ? currentIndex - 1
+ : event.key === "Home"
+ ? 0
+ : event.key === "End"
+ ? lastIndex
+ : currentIndex;
+ const wrappedIndex = nextIndex < 0 ? lastIndex : nextIndex > lastIndex ? 0 : nextIndex;
+
+ if (wrappedIndex !== currentIndex) {
+ event.preventDefault();
+ const nextTab = exampleTabs[wrappedIndex];
+ const selectedId = nextTab.dataset.exampleTab;
+ nextTab.focus();
+ if (selectedId) selectExampleTab(selectedId);
+ }
+ });
+ }
+ }
+
function setCopyFeedback(button: HTMLButtonElement, label: string, timeout = 1600) {
- button.textContent = label;
+ const copyLabel = button.dataset.copyLabel ?? "value";
button.setAttribute("data-copied", "true");
+ button.setAttribute("aria-live", "polite");
+ if (copyStatus) copyStatus.textContent = `${label}: ${copyLabel}.`;
window.setTimeout(() => {
- button.textContent = "Copy";
button.removeAttribute("data-copied");
+ button.removeAttribute("aria-live");
}, timeout);
}
@@ -539,10 +972,109 @@ const installSteps = [
button.addEventListener("click", () => void copyValue(button));
}
+ const reactorRoot = document.querySelector(".trace-reactor");
+ const reactorSteps = Array.from(document.querySelectorAll("[data-reactor-step]"));
+ const reactorDots = Array.from(document.querySelectorAll("[data-reactor-dot]"));
+ const reactorBeam = document.querySelector("[data-reactor-beam]");
+ const reactorMobileOutput = document.querySelector("[data-reactor-mobile-output]");
+ let reactorStepIndex = 0;
+ let reactorTimer = 0;
+ let reactorUserPaused = false;
+
+ function setReactorStep(index: number) {
+ reactorStepIndex = index;
+ reactorRoot?.style.setProperty("--reactor-position", String(index));
+ reactorRoot?.style.setProperty(
+ "--reactor-progress",
+ String(reactorSteps.length > 1 ? index / (reactorSteps.length - 1) : 0)
+ );
+ reactorBeam?.style.setProperty("--reactor-beam-scale", String(index / 3));
+
+ for (const step of reactorSteps) {
+ step.classList.toggle("is-active", step.dataset.reactorStep === String(index));
+ }
+
+ for (const dot of reactorDots) {
+ dot.classList.toggle("is-active", dot.dataset.reactorDot === String(index));
+ }
+
+ const activeStep = reactorSteps[index];
+ if (reactorMobileOutput && activeStep) {
+ const label = activeStep.querySelector(".trace-label")?.textContent ?? "";
+ const result = activeStep.querySelector("code")?.textContent ?? "";
+ const detail = activeStep.querySelector("p")?.textContent ?? "";
+ reactorMobileOutput.replaceChildren();
+ const labelElement = document.createElement("span");
+ labelElement.textContent = label;
+ const resultElement = document.createElement("code");
+ resultElement.textContent = result;
+ const detailElement = document.createElement("p");
+ detailElement.textContent = detail;
+ reactorMobileOutput.append(labelElement, resultElement, detailElement);
+ }
+ }
+
+ const stopReactorAutoplay = () => {
+ window.clearInterval(reactorTimer);
+ reactorTimer = 0;
+ };
+ const startReactorAutoplay = () => {
+ if (!canAnimate || reactorTimer || reactorUserPaused || document.hidden) return;
+ reactorTimer = window.setInterval(() => setReactorStep((reactorStepIndex + 1) % reactorSteps.length), 2100);
+ };
+ const setUserReactorStep = (index: number) => {
+ reactorUserPaused = true;
+ stopReactorAutoplay();
+ setReactorStep(index);
+ };
+
+ if (reactorRoot && reactorSteps.length > 0) {
+ setReactorStep(0);
+ startReactorAutoplay();
+
+ for (const step of reactorSteps) {
+ step.addEventListener("pointerenter", () => {
+ const index = Number(step.dataset.reactorStep);
+ if (Number.isInteger(index)) setUserReactorStep(index);
+ });
+ step.addEventListener("click", () => {
+ const index = Number(step.dataset.reactorStep);
+ if (Number.isInteger(index)) setUserReactorStep(index);
+ });
+ step.addEventListener("focus", () => {
+ const index = Number(step.dataset.reactorStep);
+ if (Number.isInteger(index)) setUserReactorStep(index);
+ });
+ step.addEventListener("keydown", (event: KeyboardEvent) => {
+ if (event.key !== "Enter" && event.key !== " ") return;
+ event.preventDefault();
+ const index = Number(step.dataset.reactorStep);
+ if (Number.isInteger(index)) setUserReactorStep(index);
+ });
+ }
+
+ for (const dot of reactorDots) {
+ dot.addEventListener("pointerenter", () => {
+ const index = Number(dot.dataset.reactorDot);
+ if (Number.isInteger(index)) setUserReactorStep(index);
+ });
+ }
+
+ reactorRoot.addEventListener("pointerleave", () => {
+ reactorUserPaused = false;
+ startReactorAutoplay();
+ });
+
+ document.addEventListener("visibilitychange", () => {
+ stopReactorAutoplay();
+ startReactorAutoplay();
+ });
+ }
+
if (canAnimate && "IntersectionObserver" in window) {
const revealTargets = Array.from(
document.querySelectorAll(
- ".problem, .proof, .trust, .integrations, .install, .proof-item, .trust-item, .trust-error, .agent-setup-panel, .terminal li"
+ ".proof-strip, .remote-story, .activation, .integrations, .agent-setup-panel, .terminal li"
)
);
diff --git a/apps/landing/src/styles/global.css b/apps/landing/src/styles/global.css
index 15b3d4f..a2ee72d 100644
--- a/apps/landing/src/styles/global.css
+++ b/apps/landing/src/styles/global.css
@@ -1,7 +1,7 @@
@import "tailwindcss";
:root {
- color-scheme: light;
+ color-scheme: light dark;
--ember: oklch(62% 0.155 35);
--ember-deep: oklch(51% 0.145 35);
--parchment: oklch(91% 0.035 82);
@@ -20,17 +20,17 @@
--dark-accent: oklch(86% 0.08 35);
--dark-selected-panel: oklch(25% 0.016 100);
--dark-tool: oklch(28% 0.018 100);
- --muted-tool: oklch(54% 0.035 110 / 0.72);
--page-warmth: oklch(91% 0.035 42 / 0.52);
--page-grid-line: oklch(88% 0.018 82 / 0.26);
--page-grid-line-muted: oklch(88% 0.018 82 / 0.24);
--body-sweep: oklch(98% 0.014 82 / 0.55);
- --header-surface: oklch(98% 0.014 82 / 0.9);
- --trace-surface-start: oklch(98% 0.014 82 / 0.98);
- --trace-surface-end: oklch(96% 0.018 82 / 0.98);
+ --header-surface: oklch(98% 0.014 82);
+ --header-control-bg: oklch(98% 0.014 82);
+ --header-control-hover: oklch(91% 0.035 82);
+ --header-control-ring: oklch(24% 0.018 100 / 0.14);
+ --brand-icon-ring: oklch(24% 0.018 100 / 0.18);
--trace-status-bg: oklch(95% 0.03 145);
--trace-status-text: oklch(34% 0.07 145);
- --trace-shadow: oklch(24% 0.018 100 / 0.08);
--terminal-success: oklch(72% 0.12 145);
--terminal-step: oklch(82% 0.08 35);
--font-sans:
@@ -39,12 +39,42 @@
--ease-out: cubic-bezier(0.25, 1, 0.5, 1);
--ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
--content: min(1180px, calc(100vw - 32px));
+ --radius-control: 8px;
+ --radius-panel: 12px;
+ --radius-shell: 16px;
+ --radius-pill: 999px;
--scrollbar-thumb: transparent;
--scrollbar-thumb-active: oklch(51% 0.045 100 / 0.42);
--scrollbar-thumb-hover: oklch(43% 0.05 100 / 0.56);
--scrollbar-track: transparent;
}
+:root[data-theme="dark"] {
+ --ember: oklch(72% 0.12 35);
+ --ember-deep: oklch(82% 0.08 35);
+ --parchment: oklch(31% 0.025 82);
+ --charred-ink: oklch(93% 0.026 82);
+ --linen: oklch(18% 0.014 100);
+ --paper: oklch(22% 0.016 100);
+ --ash: oklch(38% 0.024 82);
+ --olive: oklch(82% 0.03 82);
+ --success: oklch(72% 0.12 145);
+ --focus: oklch(76% 0.13 35 / 0.78);
+ --page-warmth: oklch(28% 0.035 35 / 0.36);
+ --page-grid-line: oklch(42% 0.018 82 / 0.24);
+ --page-grid-line-muted: oklch(42% 0.018 82 / 0.2);
+ --body-sweep: oklch(24% 0.016 100 / 0.45);
+ --header-surface: oklch(18% 0.014 100);
+ --header-control-bg: oklch(23% 0.016 100);
+ --header-control-hover: oklch(31% 0.025 82);
+ --header-control-ring: oklch(93% 0.026 82 / 0.14);
+ --brand-icon-ring: oklch(93% 0.026 82 / 0.16);
+ --trace-status-bg: oklch(25% 0.045 145);
+ --trace-status-text: oklch(82% 0.08 145);
+ --scrollbar-thumb-active: oklch(76% 0.03 82 / 0.5);
+ --scrollbar-thumb-hover: oklch(86% 0.03 82 / 0.62);
+}
+
* {
box-sizing: border-box;
scrollbar-width: thin;
@@ -68,7 +98,7 @@ html.scrollbars-active,
::-webkit-scrollbar-thumb {
border: 3px solid transparent;
- border-radius: 999px;
+ border-radius: var(--radius-pill);
background: var(--scrollbar-thumb);
background-clip: padding-box;
}
@@ -138,7 +168,7 @@ a {
top: 1rem;
z-index: 20;
transform: translateY(-140%);
- border-radius: 10px;
+ border-radius: var(--radius-control);
background: var(--charred-ink);
color: var(--parchment);
padding: 0.75rem 1rem;
@@ -150,6 +180,15 @@ a {
transform: translateY(0);
}
+.copy-status {
+ position: fixed;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip-path: inset(50%);
+ white-space: nowrap;
+}
+
.site-header {
width: 100%;
min-height: 58px;
@@ -179,7 +218,7 @@ a {
align-items: center;
gap: 10px;
padding: 8px 10px;
- border-radius: 12px;
+ border-radius: var(--radius-control);
font-weight: 720;
letter-spacing: -0.025em;
}
@@ -191,11 +230,19 @@ a {
white-space: nowrap;
}
-.brand-mark img {
+.brand-icon {
width: 32px;
height: 32px;
- border-radius: 10px;
- background: var(--charred-ink);
+ display: block;
+ border-radius: var(--radius-control);
+ box-shadow: 0 0 0 1px var(--brand-icon-ring);
+ flex: 0 0 auto;
+ overflow: hidden;
+}
+
+.brand-icon img {
+ width: 100%;
+ height: 100%;
object-fit: cover;
}
@@ -211,7 +258,7 @@ a {
display: inline-flex;
align-items: center;
justify-content: center;
- border-radius: 11px;
+ border-radius: var(--radius-control);
padding: 0 13px;
color: var(--olive);
font-size: 0.875rem;
@@ -222,20 +269,9 @@ a {
border-color 180ms var(--ease-out);
}
-.top-nav a {
- gap: 8px;
-}
-
-.top-nav a span {
- color: var(--ember-deep);
- font-family: var(--font-mono);
- font-size: 0.68rem;
- letter-spacing: 0.045em;
-}
-
.top-nav a:hover,
.header-action:hover {
- background: var(--parchment);
+ background: var(--header-control-hover);
color: var(--charred-ink);
}
@@ -247,7 +283,18 @@ a {
}
.header-action {
+ border: 1px solid transparent;
color: var(--charred-ink);
+ background: transparent;
+ cursor: pointer;
+}
+
+.theme-toggle {
+ position: relative;
+ display: inline-grid;
+ place-items: center;
+ border-color: transparent;
+ background: transparent;
}
.icon-link {
@@ -261,19 +308,65 @@ a {
fill: currentColor;
}
+.theme-toggle .theme-icon {
+ grid-area: 1 / 1;
+ width: 21px;
+ height: 21px;
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 2;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ transition:
+ opacity 160ms var(--ease-out),
+ transform 160ms var(--ease-out);
+}
+
+.theme-icon-sun {
+ opacity: 0;
+ transform: scale(0.78) rotate(-18deg);
+}
+
+.theme-icon-moon {
+ opacity: 1;
+ transform: scale(1) rotate(0deg);
+}
+
+.theme-toggle[data-resolved-theme="dark"] .theme-icon-sun {
+ opacity: 1;
+ transform: scale(1) rotate(0deg);
+}
+
+.theme-toggle[data-resolved-theme="dark"] .theme-icon-moon {
+ opacity: 0;
+ transform: scale(0.78) rotate(18deg);
+}
+
+.mobile-menu-toggle,
+.mobile-nav-drawer {
+ display: none;
+}
+
+.header-action-icon {
+ width: 22px;
+ height: 22px;
+ color: currentcolor;
+}
+
main {
display: grid;
- gap: clamp(74px, 10vw, 142px);
+ gap: clamp(56px, 5vw, 80px);
}
.hero {
width: var(--content);
- margin: clamp(42px, 7vw, 84px) auto 0;
+ margin: clamp(18px, 3.5vw, 44px) auto 0;
display: grid;
grid-template-columns: minmax(488px, 0.78fr) minmax(0, 1.22fr);
align-items: center;
gap: clamp(28px, 3vw, 32px);
- min-height: 92vh;
+ min-height: calc(100vh - 58px);
+ overflow: clip;
}
.hero-copy {
@@ -282,7 +375,6 @@ main {
}
.kicker,
-.proof-eyebrow,
dt {
font-family: var(--font-mono);
font-size: 0.75rem;
@@ -315,11 +407,11 @@ p {
}
h1 {
- max-width: 10.7ch;
+ max-width: 11.2ch;
margin-bottom: 24px;
- font-size: clamp(4rem, 6.6vw, 6rem);
- line-height: 0.9;
- letter-spacing: -0.075em;
+ font-size: clamp(3.8rem, 6.1vw, 5.7rem);
+ line-height: 0.94;
+ letter-spacing: -0.038em;
text-wrap: balance;
}
@@ -336,7 +428,107 @@ h1 {
display: flex;
flex-wrap: wrap;
gap: 10px;
- margin-bottom: 34px;
+ margin-bottom: 18px;
+}
+
+.hero-quickstart {
+ max-width: 560px;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-panel);
+ background: color-mix(in oklch, var(--paper) 82%, transparent);
+ overflow: hidden;
+}
+
+.hero-quickstart-heading {
+ min-height: 44px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 0 12px;
+ border-bottom: 1px solid var(--ash);
+ color: var(--olive);
+ font-family: var(--font-mono);
+ font-size: 0.7rem;
+ font-weight: 760;
+}
+
+.hero-quickstart-heading span {
+ color: var(--ember-deep);
+ text-transform: uppercase;
+ letter-spacing: 0.055em;
+}
+
+.hero-quickstart-heading a {
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
+ text-decoration: none;
+}
+
+.hero-quickstart-heading a:hover {
+ color: var(--charred-ink);
+}
+
+.hero-quickstart ol {
+ display: grid;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.hero-quickstart li {
+ min-width: 0;
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ align-items: center;
+ gap: 12px;
+ padding: 11px 12px;
+}
+
+.hero-quickstart li + li {
+ border-top: 1px solid var(--ash);
+}
+
+.hero-quickstart li > span {
+ width: 26px;
+ height: 26px;
+ display: inline-grid;
+ place-items: center;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-pill);
+ background: var(--parchment);
+ color: var(--ember-deep);
+ font-family: var(--font-mono);
+ font-size: 0.67rem;
+ font-weight: 820;
+}
+
+.hero-quickstart strong {
+ display: block;
+ margin-bottom: 2px;
+ color: var(--olive);
+ font-size: 0.76rem;
+ font-weight: 720;
+}
+
+.hero-quickstart code {
+ display: block;
+ min-width: 0;
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: clamp(0.82rem, 1vw, 0.9rem);
+ font-weight: 720;
+ line-height: 1.35;
+ overflow-wrap: anywhere;
+}
+
+.hero-copy-button {
+ width: 44px;
+ min-width: 44px;
+ height: 44px;
+ min-height: 44px;
+ color: var(--charred-ink);
}
.button {
@@ -344,7 +536,7 @@ h1 {
display: inline-flex;
align-items: center;
justify-content: center;
- border-radius: 12px;
+ border-radius: var(--radius-control);
padding: 0 16px;
font-family: var(--font-mono);
font-size: 0.78rem;
@@ -385,22 +577,6 @@ h1 {
border-color: var(--charred-ink);
}
-.hero-facts {
- display: grid;
- gap: 10px;
- margin: 0;
-}
-
-.hero-facts div {
- min-width: 0;
- display: grid;
- grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
- gap: 16px;
- align-items: baseline;
- padding-top: 10px;
- border-top: 1px solid var(--ash);
-}
-
dt {
color: var(--ember-deep);
text-transform: uppercase;
@@ -412,22 +588,23 @@ dd {
font-size: 0.94rem;
}
-.hero-definition {
- max-width: 62ch;
- margin: -12px 0 28px;
- color: var(--charred-ink);
- font-size: clamp(0.98rem, 1.2vw, 1.1rem);
- line-height: 1.55;
+.trace-reactor {
+ --reactor-position: 0;
+ --reactor-progress: 0;
+ position: relative;
+ min-width: 0;
+ isolation: isolate;
}
-.trace-stage {
+.reactor-shell {
min-width: 0;
border: 1px solid var(--ash);
- border-radius: 28px;
- background:
- linear-gradient(180deg, var(--trace-surface-start), var(--trace-surface-end)), var(--paper);
+ border-radius: var(--radius-shell);
+ background: var(--paper);
overflow: hidden;
- box-shadow: 0 18px 54px var(--trace-shadow);
+ box-shadow:
+ 0 6px 0 oklch(24% 0.018 100 / 0.08),
+ 0 0 0 1px color-mix(in oklch, var(--ember), transparent 74%);
}
.trace-header {
@@ -449,7 +626,7 @@ dd {
align-items: center;
gap: 8px;
border: 1px solid color-mix(in oklch, var(--success), var(--ash) 45%);
- border-radius: 999px;
+ border-radius: var(--radius-pill);
background: var(--trace-status-bg);
color: var(--trace-status-text);
padding: 5px 9px;
@@ -461,7 +638,7 @@ dd {
content: "";
width: 7px;
height: 7px;
- border-radius: 999px;
+ border-radius: var(--radius-pill);
background: currentColor;
}
@@ -509,12 +686,23 @@ dd {
}
.trace-steps li {
+ position: relative;
counter-increment: trace;
display: grid;
- grid-template-columns: minmax(0, 1fr) minmax(180px, 0.72fr);
- gap: 18px;
- padding: 18px;
+ grid-template-columns: minmax(0, 0.92fr) minmax(180px, 1.08fr);
+ gap: 14px;
+ align-items: center;
+ padding: 14px 16px;
border-top: 1px solid var(--ash);
+ cursor: pointer;
+ transition:
+ background-color 420ms var(--ease-out),
+ color 420ms var(--ease-out);
+}
+
+.trace-steps li:focus-visible {
+ outline: 3px solid var(--focus);
+ outline-offset: -5px;
}
.trace-steps li::before {
@@ -523,19 +711,24 @@ dd {
align-self: start;
width: fit-content;
border: 1px solid var(--ash);
- border-radius: 999px;
+ border-radius: var(--radius-pill);
background: var(--parchment);
color: var(--ember-deep);
padding: 4px 7px;
font-family: var(--font-mono);
font-size: 0.68rem;
font-weight: 760;
+ transition:
+ background-color 420ms var(--ease-out),
+ border-color 420ms var(--ease-out),
+ color 420ms var(--ease-out),
+ transform 420ms var(--ease-out);
}
.trace-steps li > div {
min-width: 0;
display: grid;
- gap: 7px;
+ gap: 5px;
}
.trace-label {
@@ -546,54 +739,151 @@ dd {
.trace-steps p {
margin: 0;
color: var(--olive);
- font-size: 0.92rem;
- line-height: 1.45;
+ font-size: 0.88rem;
+ line-height: 1.38;
}
.trace-steps code {
min-width: 0;
align-self: start;
border: 1px solid var(--ash);
- border-radius: 14px;
+ border-radius: var(--radius-panel);
background: var(--linen);
color: var(--charred-ink);
- padding: 12px;
+ padding: 10px 11px;
font-family: var(--font-mono);
- font-size: 0.78rem;
- line-height: 1.45;
+ font-size: 0.75rem;
+ line-height: 1.38;
+ overflow-wrap: anywhere;
+ transition:
+ background-color 420ms var(--ease-out),
+ border-color 420ms var(--ease-out),
+ color 420ms var(--ease-out),
+ transform 420ms var(--ease-out);
+}
+
+.trace-steps li.is-active {
+ background: color-mix(in oklch, var(--ember), transparent 90%);
+}
+
+.trace-steps li.is-active::before {
+ border-color: var(--ember);
+ background: var(--ember);
+ color: var(--paper);
+ transform: translateX(2px);
+}
+
+.trace-steps li.is-active code {
+ border-color: color-mix(in oklch, var(--ember), var(--ash) 20%);
+ background: color-mix(in oklch, var(--ember), var(--linen) 84%);
+ transform: translateX(-2px);
+}
+
+.trace-mobile-output {
+ display: none;
+}
+
+.reactor-rail {
+ display: grid;
+ gap: 8px;
+ padding: 14px 18px 16px;
+ border-top: 1px solid var(--ash);
+ background: color-mix(in oklch, var(--paper), var(--ember) 4%);
+}
+
+.reactor-rail-track {
+ position: relative;
+ height: 14px;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ align-items: center;
+}
+
+.reactor-rail-track::before {
+ content: "";
+ position: absolute;
+ left: 8px;
+ right: 8px;
+ top: 50%;
+ height: 1px;
+ background: var(--ash);
+ transform: translateY(-50%);
+}
+
+.reactor-rail-track span {
+ position: relative;
+ z-index: 1;
+ width: 11px;
+ height: 11px;
+ justify-self: center;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-pill);
+ background: var(--paper);
+ transition:
+ background-color 420ms var(--ease-out),
+ border-color 420ms var(--ease-out),
+ transform 420ms var(--ease-out);
+}
+
+.reactor-rail-track span.is-active {
+ border-color: var(--ember);
+ background: var(--ember);
+ transform: scale(1.22);
+}
+
+.reactor-rail-track i {
+ position: absolute;
+ z-index: 0;
+ display: block;
+ left: 12.5%;
+ top: 50%;
+ width: 75%;
+ height: 2px;
+ border-radius: var(--radius-pill);
+ background: var(--ember);
+ transform: translateY(-50%) scaleX(var(--reactor-beam-scale, 0));
+ transform-origin: left center;
+ transition: transform 520ms var(--ease-expo);
+}
+
+.reactor-rail-labels {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 8px;
+ color: var(--olive);
+ font-family: var(--font-mono);
+ font-size: 0.68rem;
+ font-weight: 760;
+}
+
+.reactor-rail-labels span {
+ text-align: center;
overflow-wrap: anywhere;
}
-.problem,
-.proof,
+
+.proof-strip,
+.remote-story,
+.activation,
.integrations,
-.install,
.site-footer {
width: var(--content);
margin-inline: auto;
}
-.motion-ready .problem,
-.motion-ready .proof,
-.motion-ready .trust,
+.motion-ready .proof-strip,
+.motion-ready .remote-story,
+.motion-ready .activation,
.motion-ready .integrations,
-.motion-ready .install,
-.motion-ready .proof-item,
-.motion-ready .trust-item,
-.motion-ready .trust-error,
.motion-ready .agent-setup-panel,
.motion-ready .terminal li {
opacity: 0;
transform: translateY(22px);
}
-.motion-ready .problem.is-visible,
-.motion-ready .proof.is-visible,
-.motion-ready .trust.is-visible,
+.motion-ready .proof-strip.is-visible,
+.motion-ready .remote-story.is-visible,
+.motion-ready .activation.is-visible,
.motion-ready .integrations.is-visible,
-.motion-ready .install.is-visible,
-.motion-ready .proof-item.is-visible,
-.motion-ready .trust-item.is-visible,
-.motion-ready .trust-error.is-visible,
.motion-ready .agent-setup-panel.is-visible,
.motion-ready .terminal li.is-visible {
opacity: 1;
@@ -604,214 +894,465 @@ dd {
transition-delay: calc(var(--reveal-index, 0) * 45ms);
}
-.problem .section-heading {
- opacity: 1;
+.integrations h2 {
+ margin: 0;
+ font-size: clamp(2.1rem, 4.2vw, 4.35rem);
+ line-height: 1.02;
+ letter-spacing: -0.038em;
+ text-wrap: balance;
}
-.dense-list,
-.ordered-flow {
- transform: none;
+.integrations {
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-shell);
+ background: var(--paper);
}
-.section-heading {
- min-width: 0;
+.site-footer p {
+ color: var(--olive);
+}
+
+.proof-strip {
display: grid;
- grid-template-columns: minmax(0, 0.4fr) minmax(0, 0.8fr);
- gap: clamp(18px, 4vw, 56px);
- align-items: start;
- margin-bottom: 28px;
+ grid-template-areas:
+ "copy stats"
+ "flow link";
+ grid-template-columns: minmax(320px, 1fr) minmax(360px, auto);
+ gap: 18px clamp(22px, 3vw, 34px);
+ align-items: center;
+ border-block: 1px solid var(--ash);
+ padding-block: clamp(18px, 3vw, 26px);
}
-.section-heading > * {
+.proof-strip-copy {
+ grid-area: copy;
min-width: 0;
}
-.section-heading.narrow {
- max-width: 760px;
- grid-template-columns: 1fr;
- gap: 0;
+.proof-strip-copy span {
+ display: block;
+ margin-bottom: 6px;
+ color: var(--ember-deep);
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ font-weight: 800;
}
-.section-heading h2,
-.install h2,
-.integrations h2 {
+.proof-strip-copy p {
+ max-width: 68ch;
margin: 0;
- font-size: clamp(2.2rem, 5vw, 5.4rem);
- line-height: 0.95;
- letter-spacing: -0.065em;
- text-wrap: balance;
+ color: var(--charred-ink);
}
-.comparison {
- display: grid;
- grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
- gap: 18px;
+.proof-strip-stats {
+ grid-area: stats;
+ display: flex;
+ flex-wrap: wrap;
+ justify-self: end;
+ gap: 1px;
+ margin: 0;
+ border: 1px solid var(--ash);
+ background: var(--ash);
}
-.dense-list,
-.ordered-flow,
-.proof-item,
-.integrations,
-.install {
- border: 1px solid var(--ash);
- border-radius: 26px;
+.proof-strip-stats div {
+ min-width: 112px;
+ padding: 12px 14px;
background: var(--paper);
}
-.dense-list,
-.ordered-flow {
- min-width: 0;
- min-height: 390px;
- padding: clamp(20px, 3vw, 34px);
+.proof-strip-stats dt {
+ color: var(--olive);
+ text-transform: none;
+ font-size: 0.82rem;
}
-.dense-list h3,
-.ordered-flow h3,
-.proof-item h3 {
- margin-bottom: 8px;
- font-size: 1.35rem;
- letter-spacing: -0.035em;
+.proof-strip-stats dd {
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: 1rem;
+ font-weight: 800;
}
-.dense-list p,
-.ordered-flow p,
-.proof-item p,
-.install-copy p,
-.site-footer p {
- color: var(--olive);
+.proof-flow {
+ grid-area: flow;
+ display: grid;
+ grid-auto-flow: column;
+ grid-auto-columns: minmax(108px, auto);
+ justify-self: start;
+ align-items: center;
+ gap: 8px;
}
-.tool-noise {
+.proof-flow div {
+ min-width: 0;
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
- gap: 7px;
- margin-top: 26px;
- max-height: 250px;
- overflow: hidden;
- mask-image: linear-gradient(to bottom, oklch(24% 0.018 100 / 0.92) 58%, transparent);
+ gap: 2px;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-panel);
+ background: var(--paper);
+ padding: 10px 12px;
}
-.tool-noise span {
- border: 1px solid var(--ash);
- border-radius: 999px;
- background: var(--linen);
- padding: 7px 8px;
- color: var(--muted-tool);
+.proof-flow span,
+.proof-flow small {
+ color: var(--olive);
font-family: var(--font-mono);
- font-size: 0.72rem;
+ font-size: 0.68rem;
+ font-weight: 760;
+}
+
+.proof-flow strong {
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: 1.45rem;
+ line-height: 1;
+}
+
+.proof-arrow {
+ color: var(--ember-deep);
+ text-align: center;
+}
+
+.proof-strip a {
+ grid-area: link;
+ justify-self: end;
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
+ color: var(--charred-ink);
+ font-weight: 760;
+ white-space: nowrap;
}
-.ordered-flow ol {
+.remote-story {
display: grid;
- gap: 12px;
- margin: 26px 0 0;
+ gap: clamp(20px, 3vw, 34px);
+ border: 1px solid var(--night-line);
+ border-radius: var(--radius-shell);
+ background: var(--night-ink);
+ color: var(--night-text);
+ padding: clamp(22px, 3.4vw, 42px);
+}
+
+.remote-story-copy {
+ max-width: 900px;
+}
+
+.remote-story .section-note {
+ color: var(--dark-accent);
+}
+
+.remote-story h2 {
+ max-width: 18ch;
+ margin: 0;
+ color: var(--night-text);
+ font-size: clamp(2rem, 4vw, 4.1rem);
+ line-height: 1.03;
+ letter-spacing: -0.036em;
+ text-wrap: balance;
+}
+
+.remote-story-copy p:last-child {
+ max-width: 72ch;
+ color: var(--night-muted);
+}
+
+.remote-compare {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 1px;
+ border: 1px solid var(--night-line);
+ border-radius: var(--radius-panel);
+ background: var(--night-line);
+ overflow: hidden;
+}
+
+.remote-compare article {
+ min-width: 0;
+ background: var(--night-panel);
+ padding: clamp(16px, 2.4vw, 24px);
+}
+
+.remote-compare article:last-child {
+ background: color-mix(in oklch, var(--dark-selected-panel), var(--ember) 8%);
+}
+
+.remote-compare h3 {
+ margin-bottom: 8px;
+ color: var(--night-text);
+ font-size: clamp(1.05rem, 1.6vw, 1.35rem);
+ line-height: 1.18;
+}
+
+.remote-compare p {
+ max-width: 58ch;
+ color: var(--night-muted);
+}
+
+.remote-compare ul {
+ display: grid;
+ gap: 7px;
+ margin: 14px 0 0;
padding: 0;
list-style: none;
- counter-reset: flow;
}
-.ordered-flow li {
+.remote-compare li {
+ position: relative;
+ padding-left: 18px;
+ color: var(--night-text);
+ font-size: 0.94rem;
+}
+
+.remote-compare li::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0.68em;
+ width: 7px;
+ height: 7px;
+ border-radius: var(--radius-pill);
+ background: var(--dark-accent);
+ transform: translateY(-50%);
+}
+
+.remote-story-grid {
+ display: grid;
+ grid-template-columns: minmax(280px, 0.82fr) minmax(480px, 1.18fr);
+ gap: clamp(20px, 4vw, 44px);
+ align-items: stretch;
+}
+
+.remote-flow {
min-width: 0;
- counter-increment: flow;
display: grid;
- grid-template-columns: auto minmax(0, 1fr) minmax(0, auto);
- align-items: center;
- gap: 14px;
- border: 1px solid var(--ash);
- border-radius: 16px;
- background: var(--linen);
- padding: 12px;
+ grid-template-rows: auto 22px auto 22px auto;
+ align-content: center;
+ gap: 10px;
+ border: 1px solid var(--night-line);
+ border-radius: var(--radius-panel);
+ background: var(--dark-selected-panel);
+ padding: clamp(16px, 3vw, 26px);
}
-.ordered-flow li::before {
- content: counter(flow, decimal-leading-zero);
+.remote-flow div {
+ min-width: 0;
display: grid;
- place-items: center;
- width: 36px;
- height: 36px;
- border-radius: 12px;
- background: var(--charred-ink);
- color: var(--parchment);
+ gap: 5px;
+}
+
+.remote-flow span {
+ color: var(--dark-accent);
font-family: var(--font-mono);
font-size: 0.72rem;
- font-weight: 750;
+ font-weight: 800;
+}
+
+.remote-flow strong {
+ color: var(--night-text);
+ font-size: clamp(1.2rem, 2vw, 1.7rem);
+ line-height: 1.12;
+ text-wrap: balance;
+}
+
+.remote-flow i {
+ width: 1px;
+ min-height: 22px;
+ background: var(--night-line);
}
-.ordered-flow span {
+.remote-snippets {
min-width: 0;
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.remote-snippets pre {
+ min-width: 0;
+ min-height: 100%;
+ margin: 0;
+ padding: 14px;
+ border: 1px solid var(--night-line);
+ border-radius: var(--radius-panel);
+ background: var(--night-panel);
+ color: var(--night-text);
+ overflow-x: auto;
+}
+
+.remote-snippets code {
font-family: var(--font-mono);
- color: var(--ember-deep);
- font-size: 0.82rem;
- font-weight: 700;
+ font-size: 0.78rem;
+ line-height: 1.55;
+ white-space: pre-wrap;
overflow-wrap: anywhere;
}
-.proof-list {
+.remote-endpoints {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 18px;
+ gap: 1px;
+ margin: 0;
+ border: 1px solid var(--night-line);
+ border-radius: var(--radius-panel);
+ background: var(--night-line);
+ overflow: hidden;
}
-.proof-item {
- padding: 24px;
+.remote-endpoints div {
+ min-width: 0;
+ padding: 14px;
+ background: var(--night-panel);
}
-.proof-eyebrow {
- margin-bottom: 38px;
- color: var(--ember-deep);
- text-transform: uppercase;
+.remote-endpoints dt {
+ color: var(--dark-accent);
+ font-family: var(--font-mono);
+ font-size: 0.72rem;
+ font-weight: 800;
}
-.proof-item p:last-child {
- margin-bottom: 0;
+.remote-endpoints dd {
+ color: var(--night-text);
+ font-family: var(--font-mono);
+ font-size: 0.86rem;
+ overflow-wrap: anywhere;
}
-.trust {
- width: var(--content);
- margin-inline: auto;
+.activation {
+ display: grid;
+ gap: clamp(20px, 3vw, 34px);
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-shell);
+ background: var(--paper);
+ padding: clamp(20px, 3vw, 34px);
+}
+
+.activation-copy {
+ max-width: 860px;
+}
+
+.activation h2 {
+ max-width: 16ch;
+ margin: 0;
+ font-size: clamp(2.1rem, 4.2vw, 4.35rem);
+ line-height: 1.02;
+ letter-spacing: -0.038em;
+ text-wrap: balance;
}
-.trust-grid {
+.activation-copy p:last-child {
+ max-width: 68ch;
+ color: var(--olive);
+}
+
+.caplet-examples {
display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
+ gap: 16px;
}
-.trust-item,
-.trust-error {
- min-width: 0;
+.example-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 14px;
+}
+
+.example-tabs {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.example-tab {
+ min-height: 44px;
border: 1px solid var(--ash);
- border-radius: 22px;
- background: var(--paper);
- padding: 18px;
+ border-radius: var(--radius-control);
+ background: var(--linen);
+ color: var(--olive);
+ padding: 8px 14px;
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ font-weight: 780;
+ cursor: pointer;
}
-.trust-item code {
- display: block;
- margin: 10px 0 12px;
+.example-tab[aria-selected="true"] {
+ background: var(--charred-ink);
+ color: var(--parchment);
+}
+
+.example-more {
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
color: var(--charred-ink);
+ font-size: 0.92rem;
+ font-weight: 780;
+ white-space: nowrap;
+}
+
+.example-panel {
+ display: grid;
+ grid-template-columns: minmax(0, 0.78fr) minmax(320px, 1fr);
+ gap: clamp(20px, 4vw, 44px);
+ align-items: start;
+}
+
+.example-panel[hidden] {
+ display: none;
+}
+
+.example-panel h3 {
+ margin-bottom: 10px;
+ font-size: 1.35rem;
+}
+
+.example-panel p {
+ color: var(--olive);
+}
+
+.discovery-path {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin: 18px 0;
+}
+
+.discovery-path code,
+.discovery-path span {
+ display: inline;
font-family: var(--font-mono);
- font-size: 0.82rem;
- line-height: 1.45;
- overflow-wrap: anywhere;
+ font-size: 0.72rem;
+ font-weight: 760;
}
-.trust-item p,
-.trust-error p {
- margin: 0;
+.discovery-path code {
+ color: var(--charred-ink);
+}
+
+.discovery-path span {
color: var(--olive);
}
-.trust-error {
- margin-top: 12px;
- background: var(--linen);
+.discovery-path span::before {
+ content: "/";
+ margin-right: 8px;
+ color: var(--ember-deep);
+}
+
+.setup-help {
+ max-width: 62ch;
+ margin-bottom: 0;
+ font-size: 0.94rem;
}
.integrations {
display: grid;
- grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
+ grid-template-columns: minmax(280px, 0.68fr) minmax(560px, 1.32fr);
gap: clamp(20px, 4vw, 56px);
- align-items: end;
+ align-items: start;
padding: clamp(24px, 4vw, 46px);
background: var(--night-ink);
color: var(--night-text);
@@ -835,7 +1376,7 @@ dd {
min-width: 44px;
min-height: 44px;
border: 1px solid var(--night-line);
- border-radius: 999px;
+ border-radius: var(--radius-control);
padding: 10px 12px;
color: var(--night-text);
background: var(--dark-tool);
@@ -852,16 +1393,19 @@ dd {
transform 180ms var(--ease-out);
}
-.integration-pill:hover,
-.integration-pill[aria-selected="true"] {
+.integration-pill:hover {
border-color: var(--dark-accent);
- background: var(--parchment);
- color: var(--night-ink);
+ background: var(--dark-selected-panel);
+ color: var(--night-text);
transform: translateY(-1px);
}
.integration-pill[aria-selected="true"] {
- box-shadow: inset 0 0 0 2px var(--night-ink);
+ border-color: var(--dark-accent);
+ background: var(--dark-accent);
+ color: var(--night-ink);
+ box-shadow: none;
+ transform: none;
}
.agent-setup-card {
@@ -873,14 +1417,14 @@ dd {
.agent-setup-panels {
min-width: 0;
border: 1px solid var(--night-line);
- border-radius: 20px;
+ border-radius: var(--radius-shell);
background: var(--dark-selected-panel);
overflow: visible;
}
.js-enabled .agent-setup-panels {
- block-size: clamp(260px, 24vw, 320px);
- overflow: hidden;
+ block-size: auto;
+ overflow: visible;
}
.agent-setup-panel {
@@ -888,8 +1432,8 @@ dd {
}
.js-enabled .agent-setup-panel {
- block-size: 100%;
- overflow: auto;
+ block-size: auto;
+ overflow: visible;
}
.agent-setup-panel[hidden] {
@@ -903,12 +1447,15 @@ dd {
.agent-setup-grid {
display: grid;
- grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
+ grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
gap: 12px;
+ align-items: stretch;
}
.snippet-block {
min-width: 0;
+ display: grid;
+ grid-template-rows: auto 1fr;
}
.snippet-heading {
@@ -924,23 +1471,25 @@ dd {
}
.copy-button {
+ width: 44px;
+ min-width: 44px;
+ height: 44px;
min-height: 44px;
display: none;
align-items: center;
justify-content: center;
border: 1px solid currentColor;
- border-radius: 999px;
+ border-radius: var(--radius-control);
background: transparent;
color: inherit;
- padding: 0 10px;
+ padding: 0;
font: inherit;
- font-family: var(--font-mono);
- font-size: 0.68rem;
- font-weight: 780;
cursor: pointer;
transition:
background-color 160ms var(--ease-out),
- color 160ms var(--ease-out);
+ border-color 160ms var(--ease-out),
+ color 160ms var(--ease-out),
+ transform 160ms var(--ease-out);
}
.js-enabled .copy-button {
@@ -951,6 +1500,24 @@ dd {
.copy-button[data-copied="true"] {
background: var(--parchment);
color: var(--night-ink);
+ transform: translateY(-1px);
+}
+
+.copy-button-icon {
+ width: 17px;
+ height: 17px;
+}
+
+.copy-button-icon-check {
+ display: none;
+}
+
+.copy-button[data-copied="true"] .copy-button-icon-copy {
+ display: none;
+}
+
+.copy-button[data-copied="true"] .copy-button-icon-check {
+ display: block;
}
.agent-setup-label {
@@ -970,7 +1537,7 @@ dd {
margin: 0;
padding: 14px;
border: 1px solid var(--night-line);
- border-radius: 14px;
+ border-radius: var(--radius-panel);
background: var(--night-ink);
color: var(--night-text);
overflow-x: auto;
@@ -984,28 +1551,11 @@ dd {
overflow-wrap: anywhere;
}
-.install {
- display: grid;
- grid-template-columns: minmax(0, 0.8fr) minmax(min(100%, 360px), 1fr);
- gap: clamp(22px, 4vw, 54px);
- align-items: center;
- padding: clamp(22px, 4vw, 42px);
-}
-
-.install-copy {
- min-width: 0;
-}
-
-.install-copy p {
- max-width: 56ch;
- margin-bottom: 0;
-}
-
.terminal {
min-width: 0;
overflow: hidden;
border: 1px solid var(--night-line);
- border-radius: 20px;
+ border-radius: var(--radius-shell);
background: var(--night-ink);
color: var(--night-text);
}
@@ -1077,6 +1627,9 @@ dd {
margin: 0;
}
.site-footer a {
+ min-height: 44px;
+ display: inline-flex;
+ align-items: center;
font-weight: 750;
color: var(--charred-ink);
}
@@ -1087,6 +1640,10 @@ dd {
gap: 10px;
}
+ main {
+ gap: 16px;
+ }
+
.top-nav {
justify-self: center;
}
@@ -1100,30 +1657,66 @@ dd {
}
.hero,
- .comparison,
- .integrations,
- .install {
+ .proof-strip,
+ .proof-flow,
+ .remote-compare,
+ .remote-story-grid,
+ .remote-snippets,
+ .remote-endpoints,
+ .activation,
+ .example-panel,
+ .integrations {
grid-template-columns: 1fr;
}
- .hero {
- margin-top: 42px;
+ .proof-strip-stats {
+ width: 100%;
+ justify-self: stretch;
}
- .trace-stage {
- max-width: 100%;
+ .proof-flow {
+ grid-auto-flow: row;
+ grid-auto-columns: auto;
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
+ width: 100%;
+ }
+
+ .example-bar {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+
+ .proof-strip {
+ grid-template-areas:
+ "copy"
+ "stats"
+ "flow"
+ "link";
+ }
+
+ .proof-strip a,
+ .proof-flow {
+ justify-self: stretch;
+ }
+
+ .hero {
+ margin-top: 42px;
+ min-height: 0;
+ align-items: start;
}
h1 {
- max-width: 11ch;
+ font-size: clamp(2.75rem, 8vw, 4.5rem);
}
- .proof-list {
- grid-template-columns: 1fr;
+ .trace-reactor {
+ max-width: 100%;
}
- .trust-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
+ .trace-metadata,
+ .trace-steps p,
+ .trace-steps code {
+ display: none;
}
.integration-strip {
@@ -1171,41 +1764,149 @@ dd {
display: none;
}
- .brand-mark img {
+ .brand-icon {
width: 30px;
height: 30px;
- border-radius: 9px;
+ border-radius: var(--radius-control);
}
.top-nav {
- gap: 0;
- justify-content: center;
+ display: none;
}
- .top-nav a,
.header-action {
min-height: 44px;
padding-inline: 7px;
font-size: 0.8rem;
}
- .top-nav a span {
- display: none;
- }
-
.header-actions {
- gap: 2px;
+ gap: 6px;
}
.icon-link {
width: 44px;
}
+ .mobile-menu-toggle {
+ display: inline-grid;
+ }
+
+ .npm-link,
+ .header-actions > a[aria-label="Caplets on GitHub"] {
+ display: none;
+ }
+
.icon-link svg {
width: 20px;
height: 20px;
}
+ .mobile-nav-drawer {
+ width: min(360px, calc(100vw - 24px));
+ max-width: calc(100vw - 24px);
+ margin: 0;
+ inset: 10px 10px 10px auto;
+ padding: 0;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-shell);
+ background: var(--paper);
+ color: var(--charred-ink);
+ overflow: hidden;
+ }
+
+ .mobile-nav-drawer[open] {
+ display: block;
+ }
+
+ .mobile-nav-drawer::backdrop {
+ background: oklch(18% 0.014 100 / 0.42);
+ }
+
+ .mobile-nav-panel {
+ display: grid;
+ gap: 14px;
+ padding: 14px;
+ }
+
+ .mobile-nav-header {
+ min-height: 44px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 14px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid var(--ash);
+ }
+
+ .mobile-nav-header p,
+ .mobile-nav-header span {
+ margin: 0;
+ }
+
+ .mobile-nav-header p {
+ color: var(--ember-deep);
+ font-family: var(--font-mono);
+ font-size: 0.75rem;
+ font-weight: 760;
+ }
+
+ .mobile-nav-header span {
+ display: block;
+ margin-top: 2px;
+ font-size: 1.2rem;
+ font-weight: 760;
+ letter-spacing: -0.03em;
+ }
+
+ .mobile-nav-links,
+ .mobile-nav-project {
+ display: grid;
+ gap: 6px;
+ }
+
+ .mobile-nav-links a,
+ .mobile-nav-project a {
+ min-height: 46px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-control);
+ padding: 10px 12px;
+ color: var(--charred-ink);
+ font-weight: 760;
+ text-decoration: none;
+ transition:
+ background-color 180ms var(--ease-out),
+ border-color 180ms var(--ease-out),
+ color 180ms var(--ease-out);
+ }
+
+ .mobile-nav-drawer[open] .mobile-nav-links a::after,
+ .mobile-nav-drawer[open] .mobile-nav-project a::after {
+ content: "->";
+ color: var(--ember-deep);
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ }
+
+ .mobile-nav-links a:hover,
+ .mobile-nav-project a:hover {
+ border-color: var(--ember);
+ background: var(--parchment);
+ }
+
+ .mobile-nav-project {
+ padding-top: 12px;
+ border-top: 1px solid var(--ash);
+ }
+
+ .mobile-nav-project a {
+ color: var(--olive);
+ font-size: 0.92rem;
+ }
+
.agent-setup-panel {
padding: 14px;
}
@@ -1238,57 +1939,172 @@ dd {
}
h1 {
- font-size: clamp(3.6rem, 18vw, 5.8rem);
+ font-size: clamp(1.95rem, 9.8vw, 2.75rem);
+ line-height: 0.98;
}
- .hero-facts div,
- .section-heading {
- grid-template-columns: 1fr;
+ main {
+ gap: 24px;
+ }
+
+ .hero {
+ margin-top: 28px;
+ gap: 20px;
+ }
+
+ .hero-lede {
+ font-size: 1rem;
+ line-height: 1.48;
}
- .trace-stage {
- border-radius: 22px;
+ .hero-lede {
+ margin-bottom: 18px;
+ }
+
+ .hero-actions {
+ margin-bottom: 14px;
+ }
+
+ .hero-quickstart {
+ max-width: 100%;
+ }
+
+ .reactor-shell {
+ border-radius: var(--radius-shell);
+ }
+
+ .trace-header {
+ min-height: 44px;
+ padding-inline: 14px;
+ }
+
+ .trace-metadata div {
+ padding: 11px 14px;
+ }
+
+ .trace-metadata {
+ display: none;
}
.trace-metadata,
- .trace-steps li,
- .trust-grid {
+ .trace-steps li {
grid-template-columns: 1fr;
}
.trace-steps li {
- gap: 12px;
+ grid-template-columns: minmax(0, 1fr);
+ gap: 0;
+ min-height: 44px;
+ padding: 9px 14px;
+ }
+
+ .trace-steps li::before {
+ display: none;
+ }
+
+ .trace-steps p {
+ display: none;
}
.trace-steps code {
- width: 100%;
+ display: none;
}
- .trust-item,
- .trust-error {
- border-radius: 18px;
+ .trace-mobile-output {
+ display: grid;
+ gap: 8px;
+ padding: 12px 14px 14px;
+ border-top: 1px solid var(--ash);
+ background: color-mix(in oklch, var(--paper), var(--ember) 4%);
}
- .copy-button {
- min-height: 44px;
- padding-inline: 12px;
+ .trace-mobile-output span {
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: 0.72rem;
+ font-weight: 760;
+ }
+
+ .trace-mobile-output code {
+ border: 1px solid var(--ash);
+ border-radius: var(--radius-panel);
+ background: var(--linen);
+ color: var(--charred-ink);
+ padding: 10px 11px;
+ font-family: var(--font-mono);
+ font-size: 0.72rem;
+ line-height: 1.38;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ }
+
+ .trace-mobile-output p {
+ margin: 0;
+ color: var(--olive);
+ font-size: 0.9rem;
+ line-height: 1.42;
+ }
+
+ .remote-compare {
+ grid-template-columns: 1fr;
+ }
+
+ .proof-flow {
+ grid-template-columns: 1fr;
+ }
+
+ .proof-arrow {
+ min-height: 24px;
}
.terminal li {
- grid-template-columns: 38px minmax(0, 1fr);
+ grid-template-columns: 38px minmax(0, 1fr) auto;
}
.terminal-copy {
- grid-column: 2;
- justify-self: start;
+ grid-column: auto;
+ justify-self: end;
}
- .dense-list,
- .ordered-flow,
- .proof-item,
- .integrations,
- .install {
- border-radius: 20px;
+ .activation h2 {
+ max-width: 17ch;
+ font-size: 1.85rem;
+ line-height: 1.08;
+ }
+
+ .remote-story h2 {
+ max-width: 18ch;
+ font-size: 1.8rem;
+ line-height: 1.08;
+ }
+
+ .remote-flow strong {
+ font-size: 1.12rem;
+ }
+
+ .activation-copy p:last-child,
+ .example-panel p {
+ margin-bottom: 10px;
+ }
+
+ .discovery-path {
+ margin-block: 14px;
+ }
+
+ .terminal ol {
+ padding-block: 8px 12px;
+ }
+
+ .terminal li {
+ padding: 8px 14px;
+ }
+
+ .proof-strip a {
+ white-space: normal;
+ }
+
+ .integrations {
+ border-radius: var(--radius-shell);
}
.site-footer {
@@ -1317,16 +2133,15 @@ dd {
transition-duration: 0.01ms !important;
}
- .problem,
- .proof,
- .trust,
+ .proof-strip,
+ .remote-story,
+ .activation,
.integrations,
- .install,
- .proof-item,
- .trust-item,
- .trust-error,
.agent-setup-panel,
- .terminal li {
+ .terminal li,
+ .reactor-rail-track i,
+ .trace-steps li,
+ .trace-steps code {
opacity: 1 !important;
transform: none !important;
}
diff --git a/apps/landing/test/campaign-copy.check.mjs b/apps/landing/test/campaign-copy.check.mjs
new file mode 100644
index 0000000..7085699
--- /dev/null
+++ b/apps/landing/test/campaign-copy.check.mjs
@@ -0,0 +1,129 @@
+import { readFileSync } from "node:fs";
+import { dirname, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const page = readFileSync(resolve(__dirname, "../src/pages/index.astro"), "utf8");
+const css = readFileSync(resolve(__dirname, "../src/styles/global.css"), "utf8");
+const source = `${page}\n${css}`;
+
+const required = [
+ "Give your agent capabilities, not tools",
+ "106",
+ "3",
+ "87.9%",
+ "Remote Caplets server",
+ "Auth into tools once. Use them from every agent.",
+ "Provider tokens and OAuth state stay with that",
+ "Without remote Caplets",
+ "With remote Caplets",
+ "Each agent client needs its own provider tokens",
+ "One server holds provider auth",
+ "Auth once on the server",
+ "CAPLETS_SERVER_URL=https://caplets.example.com/caplets",
+ "CAPLETS_SERVER_PASSWORD=...",
+ "caplets serve --transport http",
+ "CAPLETS_MODE=remote",
+ "opencode",
+ "/caplets/mcp",
+ "/caplets/control",
+ "/caplets/healthz",
+ "remote server command",
+ "remote client command",
+ "Claude Code",
+ "Codex",
+ "OpenCode",
+ "Pi",
+ "Any MCP client",
+ "caplets install spiritledsoftware/caplets github",
+ "caplets install spiritledsoftware/caplets sourcegraph",
+ "caplets install spiritledsoftware/caplets osv",
+ "caplets auth login sourcegraph",
+ "Explore more Caplets",
+ "https://github.com/spiritledsoftware/caplets/tree/main/caplets",
+ 'codex "try using the github caplet"',
+ 'codex "try using the sourcegraph caplet"',
+ 'codex "try using the osv caplet"',
+ "GH_TOKEN",
+ "github",
+ "sourcegraph",
+ "osv",
+ "inspect",
+ "search_tools",
+ "get_tool",
+ "call_tool",
+ "data-copy-status",
+ 'aria-live="polite"',
+ "data-copy-label",
+ "aria-label={`Copy ${step.label}`}",
+ "content={lightThemeColor}",
+ "content={darkThemeColor}",
+ "color-scheme: light dark;",
+ "data-theme-toggle",
+ 'localStorage.getItem("caplets-theme")',
+ ':root[data-theme="dark"]',
+ 'window.matchMedia("(prefers-color-scheme: dark)")',
+ 'themeToggle.setAttribute("aria-pressed", String(resolvedTheme === "dark"))',
+ 'aria-label="Use light theme"',
+ "/icon-header-light.png",
+ "/icon-header-dark.png",
+ 'href="#remote"',
+ 'id="remote"',
+ "npm-link",
+ "trace-reactor",
+ "data-reactor-step",
+ "data-reactor-mobile-output",
+ 'role="button"',
+ 'tabindex="0"',
+ 'addEventListener("keydown"',
+ 'addEventListener("focus"',
+ "data-reactor-dot",
+ "reactor-rail",
+ "reactorUserPaused",
+ 'addEventListener("pointerenter"',
+ 'addEventListener("pointerleave"',
+ "data-caplet-examples",
+ "data-example-tab",
+ "data-example-panel",
+ "--radius-control: 8px",
+ "--radius-panel: 12px",
+ "--radius-shell: 16px",
+ "--radius-pill: 999px",
+ "border-radius: var(--radius-shell)",
+ "border-radius: var(--radius-panel)",
+ "border-radius: var(--radius-control)",
+];
+
+const forbiddenVisibleCopy = [
+ "01",
+ "02",
+ "03",
+ "Try the aha moment",
+ "install-step-4",
+ "Before: flat tool wall",
+ "After: capability first",
+ "Trust before invocation",
+ "Expanded setup reference",
+ "Context7",
+ "context7",
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
+ "Docker",
+];
+
+const missing = required.filter((needle) => !source.includes(needle));
+const forbidden = forbiddenVisibleCopy.filter((needle) => page.includes(needle));
+
+if (missing.length > 0 || forbidden.length > 0) {
+ if (missing.length > 0) console.error("Missing required copy:", missing);
+ if (forbidden.length > 0) console.error("Forbidden old copy remains:", forbidden);
+ process.exit(1);
+}
+
+const hardcodedRadii = [...css.matchAll(/border-radius:\s*([^;]+);/g)]
+ .map((match) => match[1].trim())
+ .filter((value) => !value.startsWith("var(--radius-") && value !== "50%");
+
+if (hardcodedRadii.length > 0) {
+ console.error("Hardcoded non-token border radius remains:", hardcodedRadii);
+ process.exit(1);
+}
diff --git a/caplets/github/CAPLET.md b/caplets/github/CAPLET.md
index 6cf8a0c..7d65e51 100644
--- a/caplets/github/CAPLET.md
+++ b/caplets/github/CAPLET.md
@@ -9,16 +9,11 @@ tags:
- issues
- reviews
mcpServer:
- command: docker
- args:
- - run
- - -i
- - --rm
- - -e
- - GITHUB_PERSONAL_ACCESS_TOKEN
- - ghcr.io/github/github-mcp-server
- env:
- GITHUB_PERSONAL_ACCESS_TOKEN: $env:GITHUB_PERSONAL_ACCESS_TOKEN
+ transport: http
+ url: https://api.githubcopilot.com/mcp
+ auth:
+ type: bearer
+ token: $env:GH_TOKEN
---
# GitHub
@@ -37,18 +32,18 @@ issues, pull requests, branches, commits, or review feedback.
## Use Carefully
- Mutating operations can affect real repositories. Prefer read operations first.
-- Use a least-privilege `GITHUB_PERSONAL_ACCESS_TOKEN`.
+- Use a least-privilege `GH_TOKEN`.
- Do not ask the agent to expose token values, repository secrets, or private issue contents outside
the intended conversation.
## Setup
-Create a GitHub personal access token with the minimum repository scopes needed for your workflow,
-then export it before starting Caplets:
+Create a GitHub token with the minimum repository scopes needed for your workflow, then export it
+before starting Caplets:
```sh
-export GITHUB_PERSONAL_ACCESS_TOKEN=github_pat_...
+export GH_TOKEN=github_pat_...
caplets serve
```
-This Caplet uses GitHub's official MCP server container, so Docker must be available on the host.
+This Caplet uses GitHub's hosted MCP endpoint at `https://api.githubcopilot.com/mcp`.
diff --git a/caplets/github/README.md b/caplets/github/README.md
index 6b7a2ce..5fe22bb 100644
--- a/caplets/github/README.md
+++ b/caplets/github/README.md
@@ -1,9 +1,10 @@
# GitHub Caplet
-This Caplet wraps GitHub's official MCP server container:
+This Caplet wraps GitHub's hosted MCP endpoint:
```sh
-docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server
+export GH_TOKEN=github_pat_...
+caplets serve
```
Install it from this repo:
diff --git a/docs/benchmarks/coding-agent.md b/docs/benchmarks/coding-agent.md
index 3df193f..d13d6ab 100644
--- a/docs/benchmarks/coding-agent.md
+++ b/docs/benchmarks/coding-agent.md
@@ -7,20 +7,20 @@ This report is generated by `pnpm --filter @caplets/benchmarks benchmark` from d
The deterministic benchmark compares two ways of exposing the same three mock MCP servers to a coding agent:
- Direct flat MCP aggregation exposes every downstream tool from the `policy`, `tickets`, `api` servers in the initial `tools/list` payload.
-- Caplets progressive disclosure exposes one top-level capability tool per server, then keeps downstream tools behind scoped `get_caplet`, `list_tools` or `search_tools`, `get_tool`, and `call_tool` operations.
+- Caplets progressive disclosure exposes one top-level capability tool per server, then keeps downstream tools behind scoped `inspect`, `list_tools` or `search_tools`, `get_tool`, and `call_tool` operations.
The fixture uses local mock MCP metadata only. It does not call external APIs, depend on network access, or require model credentials. Approximate token counts use `Math.ceil(bytes / 4)` as a stable context-size proxy, not provider billing data.
## Summary
- Initial tools visible: direct flat MCP 106, Caplets top-level 3, 97.2% fewer.
-- Serialized payload bytes: direct flat MCP 32090, Caplets top-level 3906, 87.8% fewer.
-- Approx. tokens: direct flat MCP 8023, Caplets top-level 977, 7046 fewer.
+- Serialized payload bytes: direct flat MCP 32090, Caplets top-level 3879, 87.9% fewer.
+- Approx. tokens: direct flat MCP 8023, Caplets top-level 970, 7053 fewer.
- Candidate set before discovery: direct flat MCP 106, Caplets top-level 3, 103 fewer.
## Deterministic Results
-Caplets reduces the initial serialized MCP tool payload by 87.8%, from 32090 bytes to 3906 bytes. It reduces initially visible tools by 97.2%, from 106 direct flat tools to 3 Caplets capability tools, while preserving access to downstream tools through scoped discovery and `call_tool`.
+Caplets reduces the initial serialized MCP tool payload by 87.9%, from 32090 bytes to 3879 bytes. It reduces initially visible tools by 97.2%, from 106 direct flat tools to 3 Caplets capability tools, while preserving access to downstream tools through scoped discovery and `call_tool`.
## Collision Check
@@ -34,11 +34,11 @@ Caplets top-level duplicate tool-name collisions: 0
Direct flat MCP exposes all downstream tools immediately, so expected discovery calls are 0 but the initial candidate set is 106 tools.
-Caplets starts from 3 capability tools. Expected task-specific discovery is 4 calls: `get_caplet`, `list_tools` or `search_tools`, `get_tool`, then `call_tool`.
+Caplets starts from 3 capability tools. Expected task-specific discovery is 4 calls: `inspect`, `list_tools` or `search_tools`, `get_tool`, then `call_tool`.
## Validation
-- Initial payload reduction threshold: 87.8% >= 70.0%
+- Initial payload reduction threshold: 87.9% >= 70.0%
- Top-level Caplets collisions: 0
Payload implementation: `source`
diff --git a/docs/plans/2026-05-29-caplets-growth-campaign.md b/docs/plans/2026-05-29-caplets-growth-campaign.md
new file mode 100644
index 0000000..8a14c90
--- /dev/null
+++ b/docs/plans/2026-05-29-caplets-growth-campaign.md
@@ -0,0 +1,233 @@
+# Caplets Growth Campaign Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Build the public campaign assets that make Caplets easy to understand, try, and share before wider launch.
+
+**Architecture:** The campaign centers on one message: “Give your agents capabilities, not giant tool walls.” The first implementation slice strengthens activation proof by adding a visible “100+ tools vs 3 capabilities” proof asset and a guided “Try the aha moment” path to the landing page and README. Later slices prepare outreach copy and launch-channel assets without changing product runtime behavior.
+
+**Tech Stack:** Astro landing page in `apps/landing`, project README Markdown, existing Caplets benchmark report in `docs/benchmarks/coding-agent.md`, pnpm 11.0.9, Node >=22.
+
+---
+
+## File Structure
+
+- Modify: `apps/landing/src/pages/index.astro`
+ - Owns landing content, proof copy, install/try steps, and inline data arrays for static rendering.
+- Modify: `apps/landing/src/styles/global.css`
+ - Owns visual treatment for the proof asset and aha section. Keep to existing OKLCH variables and Caplets design laws.
+- Modify: `README.md`
+ - Mirrors the shortest activation path and proof numbers for GitHub visitors.
+- Reference: `docs/benchmarks/coding-agent.md`
+ - Source for deterministic proof numbers: 106 direct tools, 3 Caplets capabilities, 97.2% fewer initially visible tools, 87.8% smaller initial payload.
+- Create later: `docs/product/caplets-launch-posts.md`
+ - Draft HN, Reddit, X/Twitter, and outreach copy.
+- Create later: `docs/product/caplets-outreach-list.md`
+ - Manual outreach targets, status, and feedback notes.
+
+## Task 1: Add activation proof and aha path
+
+**Files:**
+
+- Modify: `apps/landing/src/pages/index.astro`
+- Modify: `apps/landing/src/styles/global.css`
+- Modify: `README.md`
+
+- [ ] **Step 1: Add text assertions before editing content**
+
+Create a temporary shell check that fails until the campaign proof copy exists:
+
+```bash
+node - <<'NODE'
+const fs = require('fs');
+const landing = fs.readFileSync('apps/landing/src/pages/index.astro', 'utf8');
+const readme = fs.readFileSync('README.md', 'utf8');
+const checks = [
+ [landing, '106 flat tools'],
+ [landing, '3 capability cards'],
+ [landing, 'Try the aha moment'],
+ [readme, 'Try the aha moment'],
+ [readme, '106 flat tools became 3 top-level capabilities'],
+];
+const missing = checks.filter(([text, needle]) => !text.includes(needle)).map(([, needle]) => needle);
+if (missing.length) {
+ console.error('Missing campaign copy:', missing.join(', '));
+ process.exit(1);
+}
+NODE
+```
+
+Expected before implementation: exits `1` and lists missing strings.
+
+- [ ] **Step 2: Add proof data and aha copy to `index.astro`**
+
+Add static constants near existing hero data:
+
+```ts
+const proofStats = [
+ {
+ value: "106",
+ label: "flat tools",
+ detail: "Direct MCP aggregation exposes every downstream operation up front.",
+ },
+ {
+ value: "3",
+ label: "capability cards",
+ detail: "Caplets starts with one focused card per tool source.",
+ },
+ {
+ value: "87.8%",
+ label: "smaller initial payload",
+ detail: "The deterministic benchmark cuts serialized tool metadata before discovery.",
+ },
+];
+
+const ahaSteps = [
+ "npm install -g caplets",
+ "caplets init",
+ "caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp",
+ "caplets serve",
+];
+```
+
+Add a proof block in the existing problem section so the before/after comparison has hard numbers. Add an aha section before the install section with copy-paste commands and the expected agent discovery path: `context7 → get_caplet → search_tools → get_tool → call_tool`.
+
+- [ ] **Step 3: Style the proof asset and aha path**
+
+In `apps/landing/src/styles/global.css`, add responsive styles for:
+
+- `.proof-asset`
+- `.proof-stat`
+- `.aha`
+- `.aha-path`
+- `.aha-commands`
+
+Use existing tokens: `--paper`, `--parchment`, `--ash`, `--charred-ink`, `--ember`, `--olive`. Do not add gradient text, glassmorphism, side-stripe borders, or decorative motion.
+
+- [ ] **Step 4: Mirror the activation path in README**
+
+Add a `## Try the aha moment` section before `## Quick Start`:
+
+````md
+## Try the aha moment
+
+Install Caplets, add Context7, and watch your agent see one capability before it searches downstream tools.
+
+```sh
+npm install -g caplets
+caplets init
+caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp
+caplets serve
+```
+````
+
+In the deterministic benchmark, 106 flat tools became 3 top-level capabilities with an 87.8% smaller initial payload. Your agent starts with `context7`, then drills in through `get_caplet`, `search_tools`, `get_tool`, and `call_tool` only when needed.
+
+````
+
+- [ ] **Step 5: Re-run the text assertions**
+
+Run the same Node assertion from Step 1.
+
+Expected after implementation: exits `0` with no output.
+
+- [ ] **Step 6: Verify landing page**
+
+Run:
+
+```bash
+pnpm --filter @caplets/landing typecheck
+pnpm --filter @caplets/landing build
+````
+
+Expected: Astro check reports 0 errors, 0 warnings, 0 hints; build completes with 1 page built.
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add README.md apps/landing/src/pages/index.astro apps/landing/src/styles/global.css docs/plans/2026-05-29-caplets-growth-campaign.md
+git commit -m "docs: plan caplets growth campaign"
+```
+
+## Task 2: Prepare launch copy drafts
+
+**Files:**
+
+- Create: `docs/product/caplets-launch-posts.md`
+
+- [ ] **Step 1: Draft HN post**
+
+Include title, opening paragraph, benchmark proof, setup command, and repo link. Use the headline: `Show HN: Caplets, give agents capabilities instead of giant tool walls`.
+
+- [ ] **Step 2: Draft X/Twitter thread**
+
+Write 6 to 8 short posts: pain, before visual, after visual, benchmark, Context7/GitHub demo, repo CTA.
+
+- [ ] **Step 3: Draft Reddit post**
+
+Write one technical, transparent post titled `I built Caplets to reduce MCP tool overload for coding agents`. Avoid asking for stars directly.
+
+- [ ] **Step 4: Verify copy constraints**
+
+Search the file for em dashes and replace them with commas, colons, semicolons, or parentheses:
+
+```bash
+node - <<'NODE'
+const fs = require('fs');
+const text = fs.readFileSync('docs/product/caplets-launch-posts.md', 'utf8');
+if (text.includes('—')) {
+ console.error('Found em dash in launch copy');
+ process.exit(1);
+}
+NODE
+```
+
+## Task 3: Prepare manual outreach tracker
+
+**Files:**
+
+- Create: `docs/product/caplets-outreach-list.md`
+
+- [ ] **Step 1: Create target categories**
+
+Add sections for MCP server authors, agent power users, awesome-list maintainers, AI devtool newsletter writers, and community moderators.
+
+- [ ] **Step 2: Add outreach message templates**
+
+Include a short DM template that asks for feedback on the 60-second demo rather than asking for a star.
+
+- [ ] **Step 3: Add tracking table**
+
+Columns: `Target`, `Channel`, `Why relevant`, `Status`, `Feedback`, `Follow-up`.
+
+## Task 4: Launch readiness review
+
+**Files:**
+
+- Modify: `docs/product/caplets-launch-posts.md`
+- Modify: `docs/product/caplets-outreach-list.md`
+- Modify as needed: `README.md`, `apps/landing/src/pages/index.astro`, `apps/landing/src/styles/global.css`
+
+- [ ] **Step 1: Run full focused verification**
+
+```bash
+pnpm --filter @caplets/landing typecheck
+pnpm --filter @caplets/landing build
+pnpm format:check
+```
+
+Expected: all commands exit 0.
+
+- [ ] **Step 2: Review first-screen message**
+
+Confirm the landing page and README both surface the same message: `Give your agents capabilities, not giant tool walls.`
+
+- [ ] **Step 3: Review activation path**
+
+Confirm a fresh visitor can see install commands, a concrete MCP example, and the expected progressive discovery path without scrolling through broad feature lists first.
+
+## Self-Review
+
+- Spec coverage: The plan covers the immediate proof asset and aha section, then launch copy, outreach, and readiness review.
+- Placeholder scan: No TBD, TODO, or vague implementation placeholders remain.
+- Type consistency: Constants and CSS class names are defined in the same task that uses them.
diff --git a/docs/plans/2026-05-29-cli-integration-setup.md b/docs/plans/2026-05-29-cli-integration-setup.md
new file mode 100644
index 0000000..39df2d3
--- /dev/null
+++ b/docs/plans/2026-05-29-cli-integration-setup.md
@@ -0,0 +1,967 @@
+# CLI Integration Setup Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Add a quick `caplets setup` CLI command that actually installs or configures supported agent integrations, with `--dry-run` available for preview.
+
+**Architecture:** Add an integration setup executor in `packages/core/src/cli/setup.ts` that models each setup as a list of concrete actions. Wire it into the existing Commander CLI in `packages/core/src/cli.ts`, inject the command runner for tests, and keep external mutations limited to explicit agent setup commands or explicit output paths.
+
+**Tech Stack:** TypeScript, Commander, Node `child_process.execFile`, Vitest, existing Caplets CLI helpers, `pnpm` verification.
+
+---
+
+## Command Design
+
+The command should be:
+
+```bash
+caplets setup [integration]
+```
+
+Supported integrations:
+
+- `codex`
+- `claude-code`
+- `opencode`
+- `pi`
+- `mcp-client`
+
+Options:
+
+- `--remote`: configure the integration for a remote Caplets HTTP server where supported.
+- `--server-url `: remote Caplets service base URL, defaulting to `CAPLETS_SERVER_URL` when present, otherwise `https://caplets.example.com/caplets`.
+- `--output `: write generic MCP client config to a file. Required for `mcp-client`, because there is no universal MCP client config path.
+- `--dry-run`: print the exact actions without executing commands or writing files.
+- `--format `: `plain` or `json`; default `plain`.
+
+Default behavior is mutating for concrete integrations. `caplets setup codex` runs Codex plugin commands. `caplets setup opencode` runs OpenCode's plugin installer. The command should fail if a required external binary is unavailable and should show the exact failed action.
+
+Known executable command shapes, verified locally where available:
+
+```bash
+codex plugin marketplace add spiritledsoftware/caplets
+codex plugin add caplets@caplets
+opencode plugin @caplets/opencode --global
+pi install npm:@caplets/pi
+```
+
+Claude Code is not installed in this environment, but existing repo docs use:
+
+```bash
+claude plugin marketplace add spiritledsoftware/caplets
+claude plugin install caplets@caplets
+```
+
+Out of scope for this first implementation:
+
+- Editing arbitrary unknown MCP client config files without `--output`.
+- Detecting every possible agent install location.
+- Managing secrets.
+- Starting or daemonizing `caplets serve`.
+
+## File Structure
+
+- Create: `packages/core/src/cli/setup.ts`
+ - Owns supported integration IDs.
+ - Owns setup action modeling.
+ - Executes external commands through an injected runner.
+ - Writes generic MCP config files only when `--output` is provided.
+ - Formats execution results for plain and JSON output.
+- Modify: `packages/core/src/cli/commands.ts`
+ - Adds `setup` to `cliCommands`.
+ - Adds `setup` to `topLevelCommandNames`.
+ - Adds setup integration completions to `cliSubcommands`.
+- Modify: `packages/core/src/cli.ts`
+ - Extends `CliIO` with an optional setup command runner.
+ - Imports setup helpers.
+ - Adds the Commander command.
+- Modify: `packages/core/src/cli/completion.ts`
+ - Adds `setup --format` value completion.
+- Test: `packages/core/test/cli.test.ts`
+ - Adds setup execution tests with injected command runners.
+- Test: `packages/core/test/cli-completion.test.ts`
+ - Adds completion tests for `setup`.
+- Modify: `README.md` and `packages/cli/README.md`
+ - Documents that `caplets setup` performs setup, and that `--dry-run` previews actions.
+- Create: `.changeset/quick-setup-cli.md`
+ - Patch release for `@caplets/core` and `caplets`, because this adds a user-facing CLI command exported through the published CLI package.
+
+## Task 1: Add Failing Setup Execution Tests
+
+**Files:**
+
+- Test: `packages/core/test/cli.test.ts`
+- Later create: `packages/core/src/cli/setup.ts`
+
+- [ ] **Step 1: Write failing tests for menu, Codex execution, and dry-run**
+
+Add this block near existing CLI command tests in `packages/core/test/cli.test.ts`:
+
+```ts
+describe("cli setup", () => {
+ it("prints supported integrations when no integration is provided", async () => {
+ const out: string[] = [];
+
+ await runCli(["setup"], { writeOut: (value) => out.push(value) });
+
+ const text = out.join("");
+ expect(text).toContain("Usage: caplets setup ");
+ expect(text).toContain("codex");
+ expect(text).toContain("claude-code");
+ expect(text).toContain("opencode");
+ expect(text).toContain("pi");
+ expect(text).toContain("mcp-client");
+ expect(text).toContain("--dry-run");
+ });
+
+ it("runs Codex setup commands", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(["setup", "codex"], {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ });
+
+ expect(commands).toEqual([
+ { command: "codex", args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"] },
+ { command: "codex", args: ["plugin", "add", "caplets@caplets"] },
+ ]);
+ expect(out.join("")).toContain("Completed Codex setup");
+ });
+
+ it("does not execute commands during dry-run", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(["setup", "codex", "--dry-run"], {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ });
+
+ expect(commands).toEqual([]);
+ expect(out.join("")).toContain("Dry run");
+ expect(out.join("")).toContain("codex plugin marketplace add spiritledsoftware/caplets");
+ expect(out.join("")).toContain("codex plugin add caplets@caplets");
+ });
+});
+```
+
+- [ ] **Step 2: Run the focused test and verify it fails**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli.test.ts
+```
+
+Expected before implementation: tests fail because `setup` is an unknown command and `runSetupCommand` is not part of `CliIO`.
+
+## Task 2: Implement Setup Action Model and Local Execution
+
+**Files:**
+
+- Create: `packages/core/src/cli/setup.ts`
+- Modify: `packages/core/src/cli/commands.ts`
+- Modify: `packages/core/src/cli.ts`
+
+- [ ] **Step 1: Add command constants**
+
+In `packages/core/src/cli/commands.ts`, add `setup`:
+
+```ts
+export const cliCommands = {
+ completion: "completion",
+ completeHidden: "__complete",
+ serve: "serve",
+ init: "init",
+ setup: "setup",
+ list: "list",
+ install: "install",
+ add: "add",
+ inspect: "inspect",
+ checkBackend: "check-backend",
+ listTools: "list-tools",
+ searchTools: "search-tools",
+ getTool: "get-tool",
+ callTool: "call-tool",
+ listResources: "list-resources",
+ searchResources: "search-resources",
+ listResourceTemplates: "list-resource-templates",
+ readResource: "read-resource",
+ listPrompts: "list-prompts",
+ searchPrompts: "search-prompts",
+ getPrompt: "get-prompt",
+ complete: "complete",
+ config: "config",
+ auth: "auth",
+} as const;
+```
+
+Also insert `cliCommands.setup` in `topLevelCommandNames` after `init`, and add:
+
+```ts
+[cliCommands.setup]: ["codex", "claude-code", "opencode", "pi", "mcp-client"],
+```
+
+to `cliSubcommands`.
+
+- [ ] **Step 2: Create setup executor**
+
+Create `packages/core/src/cli/setup.ts`:
+
+```ts
+import { execFile } from "node:child_process";
+import { mkdirSync, writeFileSync } from "node:fs";
+import { dirname } from "node:path";
+import { promisify } from "node:util";
+import { CapletsError } from "../errors";
+
+const execFileAsync = promisify(execFile);
+
+export const setupIntegrationIds = [
+ "codex",
+ "claude-code",
+ "opencode",
+ "pi",
+ "mcp-client",
+] as const;
+
+export type SetupIntegrationId = (typeof setupIntegrationIds)[number];
+export type SetupFormat = "plain" | "json";
+
+export type SetupCommandResult = {
+ stdout: string;
+ stderr: string;
+};
+
+export type SetupCommandRunner = (command: string, args: string[]) => Promise;
+
+export type SetupOptions = {
+ remote?: boolean;
+ serverUrl?: string;
+ output?: string;
+ dryRun?: boolean;
+ env?: NodeJS.ProcessEnv | Record;
+ format?: SetupFormat;
+ runCommand?: SetupCommandRunner;
+};
+
+type SetupAction =
+ | { type: "command"; label: string; command: string; args: string[] }
+ | { type: "writeFile"; label: string; path: string; content: string };
+
+type SetupActionResult = {
+ label: string;
+ command?: string;
+ path?: string;
+ status: "planned" | "completed";
+};
+
+type SetupResult = {
+ integration: SetupIntegrationId;
+ name: string;
+ mode: "local" | "remote";
+ dryRun: boolean;
+ actions: SetupActionResult[];
+ nextSteps: string[];
+};
+
+const localMcpConfig = `{
+ "mcpServers": {
+ "caplets": {
+ "command": "caplets",
+ "args": ["serve"]
+ }
+ }
+}
+`;
+
+export function formatSetupMenu(): string {
+ return [
+ "Usage: caplets setup ",
+ "",
+ "Supported integrations:",
+ " codex Run Codex plugin marketplace and plugin install commands",
+ " claude-code Run Claude Code plugin marketplace and plugin install commands",
+ " opencode Run OpenCode native plugin install",
+ " pi Run Pi extension install",
+ " mcp-client Write a generic MCP client config with --output",
+ "",
+ "Examples:",
+ " caplets setup codex",
+ " caplets setup opencode --dry-run",
+ " caplets setup mcp-client --output ./caplets.mcp.json",
+ "",
+ ].join("\n");
+}
+
+export async function runSetup(integration: string, options: SetupOptions = {}): Promise {
+ const result = await executeSetup(integration, options);
+ if (options.format === "json") return `${JSON.stringify(result, null, 2)}\n`;
+ return formatSetupResult(result);
+}
+
+async function executeSetup(integration: string, options: SetupOptions): Promise {
+ const id = parseSetupIntegrationId(integration);
+ const definition = setupDefinition(id, options);
+ const actions: SetupActionResult[] = [];
+ const runner = options.runCommand ?? defaultSetupCommandRunner;
+
+ for (const action of definition.actions) {
+ if (action.type === "command") {
+ const commandText = formatCommand(action.command, action.args);
+ if (!options.dryRun) {
+ try {
+ await runner(action.command, action.args);
+ } catch (error) {
+ throw new CapletsError(
+ "REQUEST_FAILED",
+ `Setup action failed: ${commandText}${error instanceof Error ? `: ${error.message}` : ""}`,
+ );
+ }
+ }
+ actions.push({
+ label: action.label,
+ command: commandText,
+ status: options.dryRun ? "planned" : "completed",
+ });
+ continue;
+ }
+
+ if (!options.dryRun) {
+ mkdirSync(dirname(action.path), { recursive: true });
+ writeFileSync(action.path, action.content, { flag: "wx", mode: 0o600 });
+ }
+ actions.push({
+ label: action.label,
+ path: action.path,
+ status: options.dryRun ? "planned" : "completed",
+ });
+ }
+
+ return {
+ integration: id,
+ name: definition.name,
+ mode: options.remote ? "remote" : "local",
+ dryRun: Boolean(options.dryRun),
+ actions,
+ nextSteps: definition.nextSteps,
+ };
+}
+
+function setupDefinition(
+ id: SetupIntegrationId,
+ options: SetupOptions,
+): { name: string; actions: SetupAction[]; nextSteps: string[] } {
+ if (options.remote) return remoteSetupDefinition(id, options);
+
+ switch (id) {
+ case "codex":
+ return {
+ name: "Codex",
+ actions: [
+ {
+ type: "command",
+ label: "Add Caplets marketplace to Codex",
+ command: "codex",
+ args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"],
+ },
+ {
+ type: "command",
+ label: "Install Caplets Codex plugin",
+ command: "codex",
+ args: ["plugin", "add", "caplets@caplets"],
+ },
+ ],
+ nextSteps: [
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ 'Ask Codex: codex "try using the github caplet"',
+ ],
+ };
+ case "claude-code":
+ return {
+ name: "Claude Code",
+ actions: [
+ {
+ type: "command",
+ label: "Add Caplets marketplace to Claude Code",
+ command: "claude",
+ args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"],
+ },
+ {
+ type: "command",
+ label: "Install Caplets Claude Code plugin",
+ command: "claude",
+ args: ["plugin", "install", "caplets@caplets"],
+ },
+ ],
+ nextSteps: [
+ "Restart Claude Code if it was already running.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "opencode":
+ return {
+ name: "OpenCode",
+ actions: [
+ {
+ type: "command",
+ label: "Install OpenCode Caplets plugin globally",
+ command: "opencode",
+ args: ["plugin", "@caplets/opencode", "--global"],
+ },
+ ],
+ nextSteps: [
+ "OpenCode reads local Caplets config and exposes native caplets_ tools.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "pi":
+ return {
+ name: "Pi",
+ actions: [
+ {
+ type: "command",
+ label: "Install Pi Caplets extension",
+ command: "pi",
+ args: ["install", "npm:@caplets/pi"],
+ },
+ ],
+ nextSteps: [
+ "Pi reads local Caplets config and exposes native tools.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "mcp-client":
+ if (!options.output) {
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ "caplets setup mcp-client requires --output because MCP clients do not share one config path",
+ );
+ }
+ return {
+ name: "Any MCP client",
+ actions: [
+ {
+ type: "writeFile",
+ label: "Write generic MCP stdio config",
+ path: options.output,
+ content: localMcpConfig,
+ },
+ ],
+ nextSteps: ["Import the written MCP config into your MCP client."],
+ };
+ }
+}
+
+function remoteSetupDefinition(
+ id: SetupIntegrationId,
+ options: SetupOptions,
+): { name: string; actions: SetupAction[]; nextSteps: string[] } {
+ const serverUrl =
+ nonEmpty(options.serverUrl) ??
+ nonEmpty(options.env?.CAPLETS_SERVER_URL) ??
+ "https://caplets.example.com/caplets";
+
+ if (id === "opencode") {
+ return {
+ name: "OpenCode",
+ actions: [
+ {
+ type: "command",
+ label: "Install OpenCode Caplets plugin globally",
+ command: "opencode",
+ args: ["plugin", "@caplets/opencode", "--global"],
+ },
+ ],
+ nextSteps: [
+ `Run OpenCode with CAPLETS_MODE=remote and CAPLETS_SERVER_URL=${serverUrl}.`,
+ "Keep CAPLETS_SERVER_PASSWORD in your shell or secret manager.",
+ ],
+ };
+ }
+
+ if (id === "pi") {
+ return {
+ name: "Pi",
+ actions: [
+ {
+ type: "command",
+ label: "Install Pi Caplets extension",
+ command: "pi",
+ args: ["install", "npm:@caplets/pi"],
+ },
+ ],
+ nextSteps: [
+ `Start Pi with CAPLETS_MODE=remote and CAPLETS_SERVER_URL=${serverUrl}.`,
+ "Keep CAPLETS_SERVER_PASSWORD in your shell or secret manager.",
+ ],
+ };
+ }
+
+ if (!options.output) {
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ "remote MCP-backed setup requires --output so Caplets can write a client config without guessing your agent's secret storage",
+ );
+ }
+
+ return {
+ name: id === "codex" ? "Codex" : id === "claude-code" ? "Claude Code" : "Any MCP client",
+ actions: [
+ {
+ type: "writeFile",
+ label: "Write remote MCP config",
+ path: options.output,
+ content: `${JSON.stringify({ mcpServers: { caplets: { url: `${serverUrl.replace(/\/$/, "")}/mcp` } } }, null, 2)}\n`,
+ },
+ ],
+ nextSteps: [
+ "Add Basic Auth credentials through your agent's secret mechanism.",
+ "Do not hardcode CAPLETS_SERVER_PASSWORD in a committed config file.",
+ ],
+ };
+}
+
+function parseSetupIntegrationId(value: string): SetupIntegrationId {
+ if (setupIntegrationIds.includes(value as SetupIntegrationId)) {
+ return value as SetupIntegrationId;
+ }
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ `setup integration must be one of: ${setupIntegrationIds.join(", ")}`,
+ );
+}
+
+async function defaultSetupCommandRunner(
+ command: string,
+ args: string[],
+): Promise {
+ const { stdout, stderr } = await execFileAsync(command, args, {
+ encoding: "utf8",
+ windowsHide: true,
+ });
+ return { stdout, stderr };
+}
+
+function formatSetupResult(result: SetupResult): string {
+ const lines = [
+ `${result.dryRun ? "Dry run" : "Completed"} ${result.name} setup (${result.mode})`,
+ "",
+ ];
+ for (const action of result.actions) {
+ if (action.command) lines.push(`- ${action.status}: ${action.command}`);
+ if (action.path) lines.push(`- ${action.status}: wrote ${action.path}`);
+ }
+ if (result.nextSteps.length > 0) {
+ lines.push("", "Next steps:");
+ for (const step of result.nextSteps) lines.push(`- ${step}`);
+ }
+ lines.push("");
+ return lines.join("\n");
+}
+
+function formatCommand(command: string, args: string[]): string {
+ return [command, ...args].join(" ");
+}
+
+function nonEmpty(value: string | undefined): string | undefined {
+ const trimmed = value?.trim();
+ return trimmed ? trimmed : undefined;
+}
+```
+
+- [ ] **Step 3: Wire Commander and injected runner**
+
+In `packages/core/src/cli.ts`, import:
+
+```ts
+import { runSetup, type SetupCommandRunner, type SetupFormat } from "./cli/setup";
+```
+
+Extend `CliIO`:
+
+```ts
+type CliIO = {
+ writeOut?: (value: string) => void;
+ writeErr?: (value: string) => void;
+ env?: NodeJS.ProcessEnv | Record;
+ fetch?: typeof fetch;
+ authDir?: string;
+ version?: string;
+ setExitCode?: (code: number) => void;
+ serve?: (options: ServeOptions) => Promise;
+ runSetupCommand?: SetupCommandRunner;
+};
+```
+
+Add this command after `init`:
+
+```ts
+program
+ .command(cliCommands.setup)
+ .description("Install or configure an agent integration for Caplets.")
+ .argument("[integration]", "integration: codex, claude-code, opencode, pi, or mcp-client")
+ .option("--remote", "configure for a remote Caplets server")
+ .option("--server-url ", "remote Caplets service base URL")
+ .option("--output ", "config path to write for generic MCP setup")
+ .option("--dry-run", "print actions without running commands or writing files")
+ .option("--format ", "output format: plain or json", parseSetupFormat)
+ .action(
+ async (
+ integration: string | undefined,
+ options: {
+ remote?: boolean;
+ serverUrl?: string;
+ output?: string;
+ dryRun?: boolean;
+ format?: SetupFormat;
+ },
+ ) => {
+ if (!integration) {
+ writeOut(formatSetupMenu());
+ return;
+ }
+ writeOut(
+ await runSetup(integration, {
+ ...options,
+ env,
+ runCommand: io.runSetupCommand,
+ }),
+ );
+ },
+ );
+```
+
+Keep `formatSetupMenu` imported:
+
+```ts
+import { formatSetupMenu, runSetup, type SetupCommandRunner, type SetupFormat } from "./cli/setup";
+```
+
+Add this helper near existing parse helpers:
+
+```ts
+function parseSetupFormat(value: string): SetupFormat {
+ if (value === "plain" || value === "json") return value;
+ throw new CapletsError("REQUEST_INVALID", "setup format must be plain or json");
+}
+```
+
+- [ ] **Step 4: Run the focused test and verify it passes**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli.test.ts
+```
+
+Expected: the new setup tests pass.
+
+## Task 3: Add File Write, Remote, JSON, and Failure Coverage
+
+**Files:**
+
+- Modify: `packages/core/test/cli.test.ts`
+- Modify: `packages/core/src/cli/setup.ts`
+
+- [ ] **Step 1: Write failing tests for generic config writing and invalid generic setup**
+
+Add:
+
+```ts
+it("writes a generic MCP client config when output is provided", async () => {
+ const dir = mkdtempSync(join(tmpdir(), "caplets-setup-mcp-"));
+ const output = join(dir, "caplets.mcp.json");
+ const out: string[] = [];
+ try {
+ await runCli(["setup", "mcp-client", "--output", output], {
+ writeOut: (value) => out.push(value),
+ });
+
+ expect(readFileSync(output, "utf8")).toContain('"command": "caplets"');
+ expect(readFileSync(output, "utf8")).toContain('"args": ["serve"]');
+ expect(out.join("")).toContain("Completed Any MCP client setup");
+ } finally {
+ rmSync(dir, { recursive: true, force: true });
+ }
+});
+
+it("rejects generic MCP client setup without output", async () => {
+ await expect(runCli(["setup", "mcp-client"], { writeErr: () => {} })).rejects.toThrow(
+ expect.objectContaining({ code: "REQUEST_INVALID" }) as CapletsError,
+ );
+});
+```
+
+- [ ] **Step 2: Write failing tests for remote JSON and command failure**
+
+Add:
+
+```ts
+it("runs remote OpenCode setup and reports JSON output", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(["setup", "opencode", "--remote", "--format", "json"], {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ });
+
+ const parsed = JSON.parse(out.join(""));
+ expect(commands).toEqual([
+ { command: "opencode", args: ["plugin", "@caplets/opencode", "--global"] },
+ ]);
+ expect(parsed).toMatchObject({
+ integration: "opencode",
+ name: "OpenCode",
+ mode: "remote",
+ dryRun: false,
+ });
+});
+
+it("wraps setup command failures with the failed command", async () => {
+ await expect(
+ runCli(["setup", "codex"], {
+ writeErr: () => {},
+ runSetupCommand: async () => {
+ throw new Error("missing binary");
+ },
+ }),
+ ).rejects.toThrow(
+ expect.objectContaining({
+ code: "REQUEST_FAILED",
+ message: expect.stringContaining("codex plugin marketplace add spiritledsoftware/caplets"),
+ }) as CapletsError,
+ );
+});
+```
+
+- [ ] **Step 3: Run focused tests and verify failure before implementation**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli.test.ts
+```
+
+Expected before Task 2 implementation: failures identify missing setup behavior. Expected after Task 2 implementation: all setup tests pass.
+
+## Task 4: Add Completion Coverage
+
+**Files:**
+
+- Modify: `packages/core/test/cli-completion.test.ts`
+- Modify: `packages/core/src/cli/commands.ts`
+- Modify: `packages/core/src/cli/completion.ts`
+
+- [ ] **Step 1: Write failing completion tests**
+
+Add tests to `packages/core/test/cli-completion.test.ts`:
+
+```ts
+it("suggests setup as a top-level command", async () => {
+ await expect(completeCliWords(["set"])).resolves.toContain("setup");
+});
+
+it("suggests setup integrations", async () => {
+ await expect(completeCliWords(["setup", ""])).resolves.toEqual([
+ "codex",
+ "claude-code",
+ "opencode",
+ "pi",
+ "mcp-client",
+ ]);
+});
+
+it("suggests setup formats", async () => {
+ await expect(completeCliWords(["setup", "codex", "--format", ""])).resolves.toEqual([
+ "plain",
+ "json",
+ ]);
+});
+```
+
+- [ ] **Step 2: Run completion tests and verify failure**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli-completion.test.ts
+```
+
+Expected before implementation: `setup` and setup format suggestions are missing.
+
+- [ ] **Step 3: Add setup completion values**
+
+In `packages/core/src/cli/completion.ts`, update `optionValueSuggestions`:
+
+```ts
+const optionValueSuggestions: Record> = {
+ "*": { "--format": ["markdown", "md", "plain", "json"] },
+ setup: { "--format": ["plain", "json"] },
+ serve: { "--transport": ["stdio", "http"] },
+ "add:mcp": { "--transport": ["http", "sse"] },
+ "add:cli": { "--include": ["git", "gh", "package"] },
+};
+```
+
+The `cliSubcommands` update from Task 2 supplies integration suggestions.
+
+- [ ] **Step 4: Run completion tests**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli-completion.test.ts
+```
+
+Expected: completion tests pass.
+
+## Task 5: Document Mutating Setup
+
+**Files:**
+
+- Modify: `README.md`
+- Modify: `packages/cli/README.md`
+
+- [ ] **Step 1: Add setup command documentation**
+
+In both README files, near the existing integration table, add:
+
+````md
+### Quick integration setup
+
+Use `caplets setup` to install or configure an agent integration:
+
+```bash
+caplets setup codex
+caplets setup claude-code
+caplets setup opencode
+caplets setup pi
+caplets setup mcp-client --output ./caplets.mcp.json
+```
+
+Preview actions before changing anything:
+
+```bash
+caplets setup codex --dry-run
+```
+
+For native integrations that should connect to a remote Caplets HTTP service:
+
+```bash
+caplets setup opencode --remote --server-url https://caplets.example.com/caplets
+```
+
+`caplets setup` runs the supported agent installer commands or writes the explicit config path you pass with `--output`. It does not store secrets, edit unknown MCP client config locations, or start `caplets serve`.
+````
+
+- [ ] **Step 2: Run docs-sensitive checks**
+
+Run:
+
+```bash
+pnpm format:check
+```
+
+Expected: formatting passes.
+
+## Task 6: Add Changeset
+
+**Files:**
+
+- Create: `.changeset/quick-setup-cli.md`
+
+- [ ] **Step 1: Add a changeset**
+
+Create `.changeset/quick-setup-cli.md`:
+
+```md
+---
+"@caplets/core": patch
+"caplets": patch
+---
+
+Add `caplets setup` to install or configure supported agent integrations.
+```
+
+- [ ] **Step 2: Run focused package checks**
+
+Run:
+
+```bash
+pnpm --filter @caplets/core test -- test/cli.test.ts test/cli-completion.test.ts
+pnpm --filter @caplets/core typecheck
+```
+
+Expected: tests and typecheck pass.
+
+## Task 7: Full Verification
+
+**Files:**
+
+- All changed files.
+
+- [ ] **Step 1: Run the full gate**
+
+Run:
+
+```bash
+pnpm verify
+```
+
+Expected:
+
+- format check passes.
+- lint passes.
+- typecheck passes.
+- schema check passes.
+- Vitest passes.
+- benchmark check passes.
+- build passes.
+
+- [ ] **Step 2: Inspect final diff**
+
+Run:
+
+```bash
+git diff --check
+git status --short
+```
+
+Expected: no whitespace errors. Changed files should be limited to CLI setup implementation, tests, docs, and changeset, plus pre-existing unrelated work that should not be reverted.
+
+## Self-Review
+
+Spec coverage:
+
+- Setup performs real actions by default: covered by Tasks 1-3.
+- Dry-run preview: covered by Task 1.
+- Codex, Claude Code, OpenCode, Pi, and generic MCP client surfaces: covered by Task 2.
+- Generic MCP client safety through explicit `--output`: covered by Task 3.
+- Remote setup mode: covered by Tasks 2-3.
+- Completion support: covered by Task 4.
+- Documentation: covered by Task 5.
+- Release metadata: covered by Task 6.
+- Verification: covered by Task 7.
+
+Placeholder scan:
+
+- No unresolved implementation placeholders remain.
+- Every implementation step includes concrete file paths and code shapes.
+
+Type consistency:
+
+- `SetupIntegrationId`, `SetupFormat`, `SetupCommandRunner`, and `SetupCommandResult` are introduced before use.
+- Commander wiring uses `runSetup`, `formatSetupMenu`, and `parseSetupFormat` exactly as defined.
diff --git a/docs/plans/2026-05-29-landing-proof-led-activation.md b/docs/plans/2026-05-29-landing-proof-led-activation.md
new file mode 100644
index 0000000..686743f
--- /dev/null
+++ b/docs/plans/2026-05-29-landing-proof-led-activation.md
@@ -0,0 +1,927 @@
+# Landing Page Proof-Led Activation Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Redesign the Caplets landing page around proof-led, agent-native activation so users add Caplets to their agent or MCP client before configuring Context7 as the first capability source.
+
+**Architecture:** Keep the implementation inside the existing Astro page and CSS file. Reorder and reshape page sections rather than introducing a new component system. Preserve the current client-side tab and copy-button script, but update the data and markup it operates on.
+
+**Tech Stack:** Astro, TypeScript-in-Astro script, plain CSS with existing OKLCH tokens, pnpm, Astro typecheck/build.
+
+---
+
+## File Structure
+
+- Modify `apps/landing/src/pages/index.astro`
+ - Update top navigation labels.
+ - Replace the bottom-heavy install flow with an agent-native activation section near the top.
+ - Convert benchmark proof into a compact proof strip after the hero.
+ - Compress problem, capability, and trust explanation into one structured section.
+ - Keep integration tabs as expanded setup reference.
+ - Preserve copy-button and tab behavior.
+- Modify `apps/landing/src/styles/global.css`
+ - Add styles for the compact proof strip, activation section, and compressed explanation.
+ - Remove or retire styles only used by deleted repeated sections.
+ - Flatten the hero trace visual by reducing wide shadow and excessive roundness.
+ - Ensure responsive layout has no horizontal overflow.
+- Optionally modify `README.md`
+ - Only if implementation changes public activation wording already duplicated in README.
+- Do not modify `.brv/` files.
+- Do not modify `package.json` package manager metadata.
+
+---
+
+### Task 1: Add Source Assertions for the New Story
+
+**Files:**
+
+- Create: `apps/landing/test/campaign-copy.test.mjs`
+- Modify: `apps/landing/package.json`
+
+- [ ] **Step 1: Add a source-level assertion script**
+
+Create `apps/landing/test/campaign-copy.test.mjs`:
+
+```js
+import { readFileSync } from "node:fs";
+import { fileURLToPath } from "node:url";
+import { dirname, resolve } from "node:path";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const page = readFileSync(resolve(__dirname, "../src/pages/index.astro"), "utf8");
+
+const required = [
+ "Give your agents capabilities, not giant tool walls.",
+ "106",
+ "3",
+ "87.8%",
+ "Claude Code",
+ "Codex",
+ "OpenCode",
+ "Pi",
+ "Any MCP client",
+ "caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp",
+ "context7",
+ "get_caplet",
+ "search_tools",
+ "get_tool",
+ "call_tool",
+];
+
+const forbiddenVisibleCopy = [
+ "01",
+ "02",
+ "03",
+ "Try the aha moment",
+ "caplets serve\",\n];
+
+const missing = required.filter((needle) => !page.includes(needle));
+const forbidden = forbiddenVisibleCopy.filter((needle) => page.includes(needle));
+
+if (missing.length > 0 || forbidden.length > 0) {
+ if (missing.length > 0) console.error("Missing required copy:", missing);
+ if (forbidden.length > 0) console.error("Forbidden old copy remains:", forbidden);
+ process.exit(1);
+}
+```
+
+- [ ] **Step 2: Add a package script**
+
+In `apps/landing/package.json`, add this script while preserving existing scripts:
+
+```json
+"campaign:check": "node test/campaign-copy.test.mjs"
+```
+
+If the file currently contains:
+
+```json
+{
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "typecheck": "astro check"
+ }
+}
+```
+
+it should become:
+
+```json
+{
+ "scripts": {
+ "dev": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "typecheck": "astro check",
+ "campaign:check": "node test/campaign-copy.test.mjs"
+ }
+}
+```
+
+- [ ] **Step 3: Run the new assertion and verify it fails before implementation**
+
+Run:
+
+```bash
+pnpm --filter @caplets/landing campaign:check
+```
+
+Expected: FAIL because the page still contains old activation structure and may still include the old manual `caplets serve` install step.
+
+- [ ] **Step 4: Commit the failing assertion**
+
+```bash
+git add apps/landing/test/campaign-copy.test.mjs apps/landing/package.json
+git commit -m "test: assert landing activation story"
+```
+
+---
+
+### Task 2: Restructure Landing Page Content
+
+**Files:**
+
+- Modify: `apps/landing/src/pages/index.astro`
+
+- [ ] **Step 1: Replace activation data model**
+
+In `apps/landing/src/pages/index.astro`, replace the existing `installSteps` constant with these constants:
+
+```ts
+const context7Steps = [
+ "caplets init",
+ "caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp",
+];
+
+const discoveryPath = ["context7", "get_caplet", "search_tools", "get_tool", "call_tool"];
+
+const primaryAgentPaths = [
+ {
+ name: "Claude Code",
+ setup:
+ "Install the Caplets plugin from the marketplace, then add Context7 as your first source.",
+ command: "claude plugin marketplace add spiritledsoftware/caplets",
+ },
+ {
+ name: "Codex",
+ setup:
+ "Add the Caplets plugin marketplace, install the plugin, then add Context7 as your first source.",
+ command: "codex plugin marketplace add spiritledsoftware/caplets",
+ },
+ {
+ name: "Any MCP client",
+ setup: "Configure the client to launch Caplets as its MCP server command, then add Context7.",
+ command: '{ "command": "caplets", "args": ["serve"] }',
+ },
+];
+```
+
+Do not delete `agentSetups`; the expanded integration tabs still use it.
+
+- [ ] **Step 2: Update navigation labels**
+
+Replace the current top nav numbered links:
+
+```astro
+01 Trace
+02 Proof
+03 Install
+```
+
+with plain labels:
+
+```astro
+Trace
+Proof
+Add to agent
+```
+
+- [ ] **Step 3: Update hero CTA labels**
+
+Replace:
+
+```astro
+Install Caplets
+Inspect the repo
+```
+
+with:
+
+```astro
+Add Caplets to your agent
+See the benchmark
+```
+
+- [ ] **Step 4: Move proof strip immediately after hero**
+
+After the closing `` for the hero, insert this new proof strip:
+
+```astro
+
+
+
Deterministic benchmark
+
Direct MCP aggregation exposed 106 flat tools. Caplets started with 3 capability cards and an 87.8% smaller initial payload.
+
+
+ {proofStats.map((stat) => (
+
+
{stat.label}
+ {stat.value}
+
+ ))}
+
+ Read benchmark method
+
+```
+
+- [ ] **Step 5: Add agent-native activation section immediately after proof strip**
+
+Insert this section after `proof-strip`:
+
+```astro
+
+
+
Add Caplets to your agent
+
Install the integration, then add Context7 as your first capability.
+
+ Start where you already work. Caplets should be loaded by your agent plugin, native integration,
+ or MCP client configuration, with Context7 as the first source to prove the flow.
+
+
+
+
+ {primaryAgentPaths.map((path) => (
+
+ {path.name}
+ {path.setup}
+ {path.command}
+
+ ))}
+
+
+
+
+
Add Context7
+
After the integration is installed, add Context7 and look for one `context7` capability inside your agent.
+
+ {discoveryPath.map((step, index) => index === 0 ? {step} : {step} )}
+
+
If setup fails, check Node 22+, `npx`, plugin installation, and your MCP client command configuration.
+
+
+
+
+
+
+ {context7Steps.map((step, index) => (
+
+ {step}
+
+ Copy
+
+
+ ))}
+
+
+
+
+```
+
+- [ ] **Step 6: Replace repeated middle sections with one compressed explanation**
+
+Replace the existing `problem`, `proof`, and `trust` sections with this single section:
+
+```astro
+
+
+
Why it works
+
A capability gives the agent one decision before it sees every operation.
+
+
+
+ Before: flat tool wall
+ Every downstream operation enters context before the agent knows which domain matters.
+
+
+ After: capability first
+ The agent chooses a source, searches inside that scope, inspects the schema, then calls the tool.
+
+
+ Trust before invocation
+ Source, auth state, timeout boundary, and safe error recovery stay visible before the call.
+
+
+
+```
+
+Delete the old `proof-asset` inside the problem section because the new `proof-strip` replaces it.
+
+- [ ] **Step 7: Rename integrations heading to expanded setup**
+
+Update the integrations section heading from:
+
+```astro
+Works where agents work
+Run Caplets from the coding agent you already use.
+```
+
+to:
+
+```astro
+Expanded setup reference
+Choose the integration your agent should load.
+```
+
+- [ ] **Step 8: Remove the old install section**
+
+Delete the old bottom `` because the new `activation` section owns `id="install"`. Keep the footer.
+
+- [ ] **Step 9: Run the source assertion**
+
+Run:
+
+```bash
+pnpm --filter @caplets/landing campaign:check
+```
+
+Expected: PASS.
+
+- [ ] **Step 10: Commit content restructure**
+
+```bash
+git add apps/landing/src/pages/index.astro
+git commit -m "feat: restructure landing around agent activation"
+```
+
+---
+
+### Task 3: Update CSS for New Section Rhythm
+
+**Files:**
+
+- Modify: `apps/landing/src/styles/global.css`
+
+- [ ] **Step 1: Update shared section selectors**
+
+Replace occurrences of shared selectors that list old sections:
+
+```css
+.problem,
+.proof,
+.integrations,
+.install,
+.site-footer
+```
+
+with:
+
+```css
+.proof-strip,
+.activation,
+.model,
+.integrations,
+.site-footer
+```
+
+For motion selectors, use:
+
+```css
+.motion-ready .proof-strip,
+.motion-ready .activation,
+.motion-ready .model,
+.motion-ready .integrations,
+.motion-ready .agent-path,
+.motion-ready .model-grid article,
+.motion-ready .agent-setup-panel,
+.motion-ready .terminal li
+```
+
+and the matching `.is-visible` selector list.
+
+- [ ] **Step 2: Flatten the trace artifact**
+
+Replace the current `.trace-stage` block with:
+
+```css
+.trace-stage {
+ min-width: 0;
+ border: 1px solid var(--ash);
+ border-radius: 18px;
+ background: var(--paper);
+ overflow: hidden;
+ box-shadow: 0 6px 0 oklch(24% 0.018 100 / 0.08);
+}
+```
+
+This removes the wide 54px blur shadow and over-rounded card feel.
+
+- [ ] **Step 3: Add proof strip styles**
+
+Add after the hero styles:
+
+```css
+.proof-strip {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto auto;
+ gap: clamp(18px, 3vw, 34px);
+ align-items: center;
+ border-block: 1px solid var(--ash);
+ padding-block: clamp(18px, 3vw, 26px);
+}
+
+.proof-strip-copy {
+ min-width: 0;
+}
+
+.proof-strip-copy span {
+ display: block;
+ margin-bottom: 6px;
+ color: var(--ember-deep);
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ font-weight: 800;
+}
+
+.proof-strip-copy p {
+ max-width: 68ch;
+ margin: 0;
+ color: var(--charred-ink);
+}
+
+.proof-strip-stats {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1px;
+ margin: 0;
+ border: 1px solid var(--ash);
+ background: var(--ash);
+}
+
+.proof-strip-stats div {
+ min-width: 112px;
+ padding: 12px 14px;
+ background: var(--paper);
+}
+
+.proof-strip-stats dt {
+ color: var(--olive);
+ text-transform: none;
+ font-size: 0.82rem;
+}
+
+.proof-strip-stats dd {
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: 1rem;
+ font-weight: 800;
+}
+
+.proof-strip a {
+ color: var(--charred-ink);
+ font-weight: 760;
+ white-space: nowrap;
+}
+```
+
+- [ ] **Step 4: Add activation styles**
+
+Add after proof strip styles:
+
+```css
+.activation {
+ display: grid;
+ gap: clamp(22px, 4vw, 40px);
+ border: 1px solid var(--ash);
+ border-radius: 20px;
+ background: var(--paper);
+ padding: clamp(22px, 4vw, 42px);
+}
+
+.activation-copy {
+ max-width: 860px;
+}
+
+.activation h2 {
+ max-width: 13ch;
+ margin: 0;
+ font-size: clamp(2.1rem, 4.2vw, 4.35rem);
+ line-height: 1.02;
+ letter-spacing: -0.038em;
+ text-wrap: balance;
+}
+
+.activation-copy p:last-child {
+ max-width: 68ch;
+ color: var(--olive);
+}
+
+.agent-paths {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 1px;
+ border: 1px solid var(--ash);
+ background: var(--ash);
+}
+
+.agent-path {
+ min-width: 0;
+ background: var(--linen);
+ padding: 18px;
+}
+
+.agent-path h3 {
+ margin-bottom: 8px;
+ font-size: 1.1rem;
+}
+
+.agent-path p {
+ color: var(--olive);
+}
+
+.agent-path code {
+ display: block;
+ color: var(--charred-ink);
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ line-height: 1.45;
+ overflow-wrap: anywhere;
+}
+
+.context7-setup {
+ display: grid;
+ grid-template-columns: minmax(0, 0.78fr) minmax(320px, 1fr);
+ gap: clamp(20px, 4vw, 44px);
+ align-items: start;
+}
+
+.context7-setup h3 {
+ margin-bottom: 10px;
+ font-size: 1.35rem;
+}
+
+.context7-setup p {
+ color: var(--olive);
+}
+
+.discovery-path {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin: 18px 0;
+}
+
+.discovery-path code,
+.discovery-path span {
+ min-height: 34px;
+ display: inline-flex;
+ align-items: center;
+ border: 1px solid var(--ash);
+ border-radius: 999px;
+ padding: 7px 10px;
+ font-family: var(--font-mono);
+ font-size: 0.72rem;
+ font-weight: 760;
+}
+
+.discovery-path code {
+ background: var(--charred-ink);
+ color: var(--parchment);
+}
+
+.discovery-path span {
+ background: var(--linen);
+ color: var(--ember-deep);
+}
+
+.setup-help {
+ max-width: 62ch;
+ margin-bottom: 0;
+ font-size: 0.94rem;
+}
+```
+
+- [ ] **Step 5: Add compressed model styles**
+
+Add after activation styles:
+
+```css
+.model {
+ display: grid;
+ gap: 26px;
+}
+
+.model-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 1px;
+ border: 1px solid var(--ash);
+ background: var(--ash);
+}
+
+.model-grid article {
+ min-width: 0;
+ background: var(--paper);
+ padding: 22px;
+}
+
+.model-grid h3 {
+ margin-bottom: 8px;
+ font-size: 1.25rem;
+}
+
+.model-grid p {
+ margin: 0;
+ color: var(--olive);
+}
+```
+
+- [ ] **Step 6: Retire deleted-section styles**
+
+Delete CSS blocks that are only used by removed markup:
+
+```css
+.comparison
+.dense-list
+.ordered-flow
+.tool-noise
+.proof-asset
+.proof-stats
+.proof-stat
+.proof-list
+.proof-item
+.proof-eyebrow
+.trust
+.trust-grid
+.trust-item
+.trust-error
+.aha-path
+.install
+.install-copy
+```
+
+Keep `.terminal`, `.terminal-bar`, `.terminal li`, `.terminal-copy`, `.integrations`, and all tab/copy styles.
+
+- [ ] **Step 7: Update responsive rules**
+
+In `@media (max-width: 980px)`, ensure these selectors collapse to one column:
+
+```css
+.proof-strip,
+.activation,
+.context7-setup,
+.agent-paths,
+.model-grid,
+.integrations {
+ grid-template-columns: 1fr;
+}
+
+.proof-strip-stats {
+ width: 100%;
+}
+```
+
+In `@media (max-width: 720px)`, ensure terminal rows and cards fit:
+
+```css
+.agent-path,
+.model-grid article {
+ padding: 16px;
+}
+
+.proof-strip a {
+ white-space: normal;
+}
+```
+
+- [ ] **Step 8: Run typecheck and campaign assertion**
+
+```bash
+pnpm --filter @caplets/landing campaign:check
+pnpm --filter @caplets/landing typecheck
+```
+
+Expected: both pass.
+
+- [ ] **Step 9: Commit CSS restructure**
+
+```bash
+git add apps/landing/src/styles/global.css
+git commit -m "style: tighten landing activation layout"
+```
+
+---
+
+### Task 4: Update Motion Script Selectors
+
+**Files:**
+
+- Modify: `apps/landing/src/pages/index.astro`
+
+- [ ] **Step 1: Update reveal target selector**
+
+In the script near the bottom of `apps/landing/src/pages/index.astro`, replace the old selector string:
+
+```ts
+".problem, .proof, .trust, .integrations, .install, .proof-item, .trust-item, .trust-error, .agent-setup-panel, .terminal li";
+```
+
+with:
+
+```ts
+".proof-strip, .activation, .model, .integrations, .agent-path, .model-grid article, .agent-setup-panel, .terminal li";
+```
+
+- [ ] **Step 2: Run typecheck**
+
+```bash
+pnpm --filter @caplets/landing typecheck
+```
+
+Expected: PASS.
+
+- [ ] **Step 3: Commit motion selector update**
+
+```bash
+git add apps/landing/src/pages/index.astro
+git commit -m "fix: update landing reveal targets"
+```
+
+---
+
+### Task 5: Browser Verification and Polish
+
+**Files:**
+
+- Modify: `apps/landing/src/pages/index.astro` if browser inspection finds copy or structure defects.
+- Modify: `apps/landing/src/styles/global.css` if browser inspection finds spacing, contrast, overflow, or responsive defects.
+
+- [ ] **Step 1: Open the user dev server**
+
+Use the running server at:
+
+```text
+http://127.0.0.1:4321/
+```
+
+If port 4321 is not responding, ask the user before starting another server.
+
+- [ ] **Step 2: Inspect desktop layout**
+
+Use browser automation at `1440x1100`. Evaluate:
+
+```js
+(() => {
+ const vw = innerWidth;
+ const overflow = [...document.querySelectorAll("body *")]
+ .filter((el) => {
+ const r = el.getBoundingClientRect();
+ return r.right > vw + 1 || r.left < -1;
+ })
+ .map((el) => ({
+ tag: el.tagName,
+ cls: String(el.className),
+ text: el.textContent.trim().slice(0, 80),
+ }));
+
+ const sections = [...document.querySelectorAll("main > section")].map((el) => {
+ const r = el.getBoundingClientRect();
+ return { cls: String(el.className), top: Math.round(r.top), height: Math.round(r.height) };
+ });
+
+ return { scrollWidth: document.documentElement.scrollWidth, vw, overflow, sections };
+})();
+```
+
+Expected:
+
+```json
+{
+ "scrollWidth": 1440,
+ "vw": 1440,
+ "overflow": []
+}
+```
+
+Section heights should show activation near the top, before the compressed model and integrations.
+
+- [ ] **Step 3: Inspect mobile layout**
+
+Resize to `390x844` and run the same overflow script.
+
+Expected:
+
+```json
+{
+ "scrollWidth": 390,
+ "vw": 390,
+ "overflow": []
+}
+```
+
+Confirm the activation section appears before detailed integrations and that terminal code wraps rather than overflowing.
+
+- [ ] **Step 4: Check console messages**
+
+Expected: no browser errors or warnings from the app.
+
+- [ ] **Step 5: Apply minimal polish fixes**
+
+If any of these are observed, apply only the matching fix:
+
+- Horizontal overflow from code: add `overflow-wrap: anywhere` to the specific code selector.
+- Activation too visually heavy: reduce padding by one clamp step or remove a redundant border.
+- Proof strip feels like metric cards: reduce stat box padding and keep labels subdued.
+- Hero trace still looks like SaaS card: reduce border radius to `16px` or remove remaining shadow.
+
+- [ ] **Step 6: Run focused verification**
+
+```bash
+pnpm --filter @caplets/landing campaign:check
+pnpm --filter @caplets/landing typecheck
+pnpm --filter @caplets/landing build
+git diff --check
+```
+
+Expected: all pass.
+
+- [ ] **Step 7: Commit browser polish**
+
+If Step 5 changed files:
+
+```bash
+git add apps/landing/src/pages/index.astro apps/landing/src/styles/global.css
+git commit -m "fix: polish landing activation responsiveness"
+```
+
+If Step 5 changed nothing, do not create an empty commit.
+
+---
+
+### Task 6: Final Verification and Report
+
+**Files:**
+
+- No source edits unless verification exposes a defect.
+
+- [ ] **Step 1: Run final source assertions**
+
+```bash
+pnpm --filter @caplets/landing campaign:check
+```
+
+Expected: PASS.
+
+- [ ] **Step 2: Run final typecheck**
+
+```bash
+pnpm --filter @caplets/landing typecheck
+```
+
+Expected: `0 errors`, `0 warnings`, `0 hints`.
+
+- [ ] **Step 3: Run final build**
+
+```bash
+pnpm --filter @caplets/landing build
+```
+
+Expected: build completes successfully and reports one page built.
+
+- [ ] **Step 4: Run whitespace check**
+
+```bash
+git diff --check
+```
+
+Expected: no output and exit code 0.
+
+- [ ] **Step 5: Summarize changed files and verification**
+
+Report:
+
+```text
+Changed files:
+- apps/landing/src/pages/index.astro
+- apps/landing/src/styles/global.css
+- apps/landing/package.json
+- apps/landing/test/campaign-copy.test.mjs
+- docs/specs/2026-05-29-landing-proof-led-activation-design.md
+- docs/plans/2026-05-29-landing-proof-led-activation.md
+
+Verification:
+- pnpm --filter @caplets/landing campaign:check: passed
+- pnpm --filter @caplets/landing typecheck: passed
+- pnpm --filter @caplets/landing build: passed
+- git diff --check: passed
+- Browser desktop/mobile overflow: none
+```
+
+Do not claim completion if any verification step fails.
diff --git a/docs/specs/2026-05-29-landing-proof-led-activation-design.md b/docs/specs/2026-05-29-landing-proof-led-activation-design.md
new file mode 100644
index 0000000..8a6bfd4
--- /dev/null
+++ b/docs/specs/2026-05-29-landing-proof-led-activation-design.md
@@ -0,0 +1,123 @@
+# Landing page proof-led activation design
+
+## Goal
+
+Revise the Caplets landing page so it matches the product promise: reveal one clear capability story first, then provide deeper evidence and setup details only when useful. The page should drive agent power users and MCP server builders toward installing the right agent plugin, integration, or MCP client setup with Context7 as the first capability source. Preserve the campaign headline: “Caplets: Give your agents capabilities, not giant tool walls”.
+
+## Current problems to fix
+
+1. The page explains progressive disclosure but currently presents many equal-weight sections, cards, tabs, trust details, and install steps.
+2. The activation path appears too late for power users who want proof quickly.
+3. Numbered nav markers, repeated eyebrow labels, wide shadows, and repeated bordered card patterns create AI-generated landing-page residue.
+4. The install path overemphasizes manually running `caplets serve`. The primary activation path should be agent-native: plugin install, integration setup, or MCP client configuration.
+5. The hero trace is conceptually strong but visually too close to a polished SaaS card.
+
+## Proposed direction
+
+Use a proof-led activation structure:
+
+1. Hero claim and flattened trace artifact.
+2. Compact benchmark proof strip immediately after hero.
+3. “Add Caplets to your agent” activation section near the top, using Context7 as the first source.
+4. Compressed explanation of problem, capability model, and safety mechanics.
+5. Detailed integrations as a supporting section after the primary activation path.
+
+This keeps the page focused on the launch campaign and avoids a full visual reset.
+
+## Detailed design
+
+### 1. Hero
+
+- Keep the primary headline: “Give your agents capabilities, not giant tool walls.”
+- Keep the current progressive disclosure trace because it explains the product better than a decorative illustration.
+- Remove numbered top navigation markers. Nav labels should be plain section names such as “Trace”, “Proof”, and “Install”.
+- Reduce the trace artifact’s wide shadow and overly rounded card feel. It should read as a technical artifact: flatter, sharper, and more inspectable.
+- Keep the primary CTA focused on adding Caplets to the user's agent, not on manually running the server. The page must surface a fast Context7 trial path near the top.
+
+### 2. Benchmark proof strip
+
+- Move deterministic proof close to the hero.
+- Show the three proof facts compactly:
+ - 106 flat tools
+ - 3 capability cards
+ - 87.9% smaller initial payload
+- Link the proof strip to `docs/benchmarks/coding-agent.md` or an equivalent public benchmark URL if available in the site routing.
+- Avoid the hero-metric template. The proof should feel like a benchmark note or evidence row, not a celebratory stats block.
+
+### 3. Agent-native Context7 activation section
+
+- Place the activation section before the long explanatory material.
+- Lead with agent-native setup choices, not a manual `caplets serve` workflow.
+- Recommended primary paths:
+ - Claude Code: install the Caplets plugin from the marketplace.
+ - Codex: add the Caplets plugin marketplace and install the plugin.
+ - OpenCode: install `caplets` and use the native `@caplets/opencode` plugin.
+ - Pi: install `caplets` and add `npm:@caplets/pi`.
+ - Any MCP client: configure the client to launch `caplets serve` as its MCP server command.
+- Use Context7 as the first capability source after the agent integration is in place:
+ - `caplets init`
+ - `caplets add mcp context7 --command npx --arg -y --arg @upstash/context7-mcp`
+- Show expected result inside the agent:
+ - The agent starts with a `context7` capability.
+ - The next path is `inspect`, `search_tools`, `get_tool`, `call_tool`.
+- Add a concise troubleshooting line for common activation blockers: Node version, `npx`, plugin installation, and MCP client configuration.
+- Preserve copy buttons and keyboard accessibility.
+
+### 4. Compressed explanation
+
+Replace the current repeated middle sections with a tighter explanation. It should cover:
+
+- Flat tool walls force agents to choose before they understand.
+- Caplets exposes one capability first, then scoped search and schema inspection.
+- Trust is visible before invocation through source, auth state, timeout boundary, and safe error recovery.
+
+The section should not become another identical card grid. Prefer a single structured comparison, a compact checklist, or a source-manifest style artifact.
+
+### 5. Integrations
+
+- Keep integration tabs because they are now part of the primary activation story: where can Caplets run, and what should the user install for their agent?
+- Surface the most common integrations near the activation path. The full tabbed setup can remain lower on the page as the expanded reference.
+- For MCP clients, present `caplets serve` as the configured command the client launches, not as the main thing the user runs manually.
+- Preserve tab semantics, keyboard navigation, copy buttons, and mobile behavior.
+
+## Copy and visual constraints
+
+- No em dashes in prose.
+- Avoid `--` in visible body copy except command-line flags inside code.
+- No gradient text.
+- No side-stripe card accents.
+- No glassmorphism.
+- Avoid hero-metric styling.
+- Avoid repeated numbered section markers.
+- Reduce repeated eyebrow cadence. Use labels sparingly where they add orientation.
+- Preserve existing OKLCH token system and brand colors unless a local contrast fix is required.
+- Keep display heading letter spacing at or above `-0.04em`.
+- Keep body copy line length under roughly 75ch.
+
+## Accessibility and interaction requirements
+
+- No horizontal overflow at desktop or mobile widths.
+- All buttons and links must remain keyboard reachable.
+- Tab controls must retain `role="tablist"`, `role="tab"`, `role="tabpanel"`, selected state, and arrow-key behavior.
+- Copy buttons must preserve success feedback and fallback text selection behavior.
+- Reveal motion must preserve visible defaults and support `prefers-reduced-motion: reduce`.
+- Mobile touch targets should remain at least 44px high.
+
+## Verification plan
+
+Run these checks before claiming completion:
+
+1. Browser inspection on the user dev server at desktop and mobile widths.
+2. Confirm no horizontal overflow.
+3. Confirm no browser console errors or warnings.
+4. Run the campaign copy assertion or equivalent source assertion for the key headline, proof facts, agent integration activation paths, and Context7 source setup.
+5. Run `pnpm --filter @caplets/landing typecheck`.
+6. Run `pnpm --filter @caplets/landing build`.
+7. Run `git diff --check`.
+
+## Out of scope
+
+- Changing package manager versions.
+- Modifying unrelated `.brv/` memory files.
+- Rebuilding the entire brand identity.
+- Adding new dependencies unless the implementation cannot meet the design without them.
diff --git a/package.json b/package.json
index fe386db..0917b59 100644
--- a/package.json
+++ b/package.json
@@ -32,22 +32,23 @@
},
"devDependencies": {
"@changesets/cli": "^2.31.0",
- "@cloudflare/workers-types": "^4.20260527.1",
+ "@cloudflare/workers-types": "^4.20260529.1",
"@types/node": "^25.9.1",
- "@typescript/native-preview": "7.0.0-dev.20260527.1",
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
"alchemy": "0.93.9",
"husky": "^9.1.7",
"lint-staged": "^17.0.5",
"oxfmt": "^0.52.0",
"oxlint": "^1.67.0",
+ "prettier-plugin-astro": "^0.14.1",
"rolldown": "^1.0.3",
"tsx": "^4.22.3",
- "turbo": "^2.9.15",
+ "turbo": "^2.9.16",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
},
"engines": {
"node": ">=22"
},
- "packageManager": "pnpm@11.0.9"
+ "packageManager": "pnpm@11.4.0"
}
diff --git a/packages/benchmarks/lib/surface.ts b/packages/benchmarks/lib/surface.ts
index 462eefb..4794ae7 100644
--- a/packages/benchmarks/lib/surface.ts
+++ b/packages/benchmarks/lib/surface.ts
@@ -146,7 +146,7 @@ This report is generated by \`pnpm --filter @caplets/benchmarks benchmark\` from
The deterministic benchmark compares two ways of exposing the same three mock MCP servers to a coding agent:
- Direct flat MCP aggregation exposes every downstream tool from the \`${result.source.servers.join("`, `")}\` servers in the initial \`tools/list\` payload.
-- Caplets progressive disclosure exposes one top-level capability tool per server, then keeps downstream tools behind scoped \`get_caplet\`, \`list_tools\` or \`search_tools\`, \`get_tool\`, and \`call_tool\` operations.
+- Caplets progressive disclosure exposes one top-level capability tool per server, then keeps downstream tools behind scoped \`inspect\`, \`list_tools\` or \`search_tools\`, \`get_tool\`, and \`call_tool\` operations.
The fixture uses local mock MCP metadata only. It does not call external APIs, depend on network access, or require model credentials. Approximate token counts use \`Math.ceil(bytes / 4)\` as a stable context-size proxy, not provider billing data.
@@ -173,7 +173,7 @@ Caplets top-level duplicate tool-name collisions: ${result.collisions.capletsTop
Direct flat MCP exposes all downstream tools immediately, so expected discovery calls are ${result.discovery.directExpectedDiscoveryCalls} but the initial candidate set is ${result.direct.toolCount} tools.
-Caplets starts from ${result.caplets.toolCount} capability tools. Expected task-specific discovery is ${result.discovery.capletsExpectedDiscoveryCalls.total} calls: \`get_caplet\`, \`list_tools\` or \`search_tools\`, \`get_tool\`, then \`call_tool\`.
+Caplets starts from ${result.caplets.toolCount} capability tools. Expected task-specific discovery is ${result.discovery.capletsExpectedDiscoveryCalls.total} calls: \`inspect\`, \`list_tools\` or \`search_tools\`, \`get_tool\`, then \`call_tool\`.
## Validation
diff --git a/packages/benchmarks/package.json b/packages/benchmarks/package.json
index ee6ffb5..91a13dc 100644
--- a/packages/benchmarks/package.json
+++ b/packages/benchmarks/package.json
@@ -13,11 +13,11 @@
},
"dependencies": {
"@caplets/core": "workspace:*",
- "commander": "^14.0.3"
+ "commander": "^15.0.0"
},
"devDependencies": {
"@types/node": "^25.9.1",
- "@typescript/native-preview": "7.0.0-dev.20260527.1",
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
"caplets": "workspace:*",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 5060f0e..f2764ff 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -46,7 +46,7 @@
},
"devDependencies": {
"@types/node": "^25.9.1",
- "@typescript/native-preview": "7.0.0-dev.20260527.1",
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
"rolldown": "^1.0.3",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
diff --git a/packages/core/package.json b/packages/core/package.json
index 0caa1f6..d2aba76 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -56,7 +56,7 @@
"@hono/mcp": "^0.3.0",
"@hono/node-server": "^2.0.4",
"@modelcontextprotocol/sdk": "^1.29.0",
- "commander": "^14.0.3",
+ "commander": "^15.0.0",
"graphql": "^16.14.0",
"hono": "^4.12.23",
"vfile": "^6.0.3",
diff --git a/packages/core/src/capability-description.ts b/packages/core/src/capability-description.ts
index 0cf4ffd..c888d93 100644
--- a/packages/core/src/capability-description.ts
+++ b/packages/core/src/capability-description.ts
@@ -5,8 +5,8 @@ export function capabilityDescription(server: CapletConfig): string {
`${server.name} Caplet.`,
server.description,
server.backend === "mcp"
- ? "Use get_caplet for details when needed; use tools for actions, resources for readable context, prompts for reusable workflows, and complete for prompt/resource-template arguments."
- : "Use get_caplet for details when needed; use search_tools or list_tools to discover downstream operations.",
+ ? "Use inspect for details when needed; use tools for actions, resources for readable context, prompts for reusable workflows, and complete for prompt/resource-template arguments."
+ : "Use inspect for details when needed; use search_tools or list_tools to discover downstream operations.",
]
.filter(Boolean)
.join(" ");
diff --git a/packages/core/src/cli.ts b/packages/core/src/cli.ts
index 4798be0..eba41cf 100644
--- a/packages/core/src/cli.ts
+++ b/packages/core/src/cli.ts
@@ -34,6 +34,13 @@ import {
resolveCliConfigPaths,
} from "./cli/inspection";
import { installCaplets } from "./cli/install";
+import {
+ formatSetupMenu,
+ runSetup,
+ type SetupCommandRunner,
+ type SetupFormat,
+ type SetupOptions,
+} from "./cli/setup";
import {
type CapletsConfig,
type ConfigSource,
@@ -71,6 +78,7 @@ type CliIO = {
version?: string;
setExitCode?: (code: number) => void;
serve?: (options: ServeOptions) => Promise;
+ runSetupCommand?: SetupCommandRunner;
};
export async function runCli(args: string[], io: CliIO = {}): Promise {
@@ -255,6 +263,36 @@ export function createProgram(io: CliIO = {}): Command {
writeOut(`Created ${localMutationTargetLabel(target, io)}Caplets config at ${path}\n`);
});
+ program
+ .command(cliCommands.setup)
+ .description("Install or configure an agent integration for Caplets.")
+ .argument("[integration]", "integration: codex, claude-code, opencode, pi, or mcp-client")
+ .option("--remote", "configure for a remote Caplets server")
+ .option("--server-url ", "remote Caplets service base URL")
+ .option("--output ", "config path to write for generic MCP setup")
+ .option("--dry-run", "print actions without running commands or writing files")
+ .option("--format ", "output format: plain or json", parseSetupFormat)
+ .action(
+ async (
+ integration: string | undefined,
+ options: {
+ remote?: boolean;
+ serverUrl?: string;
+ output?: string;
+ dryRun?: boolean;
+ format?: SetupFormat;
+ },
+ ) => {
+ if (!integration) {
+ writeOut(formatSetupMenu());
+ return;
+ }
+ const setupOptions: SetupOptions = { ...options, env };
+ if (io.runSetupCommand) setupOptions.runCommand = io.runSetupCommand;
+ writeOut(await runSetup(integration, setupOptions));
+ },
+ );
+
program
.command(cliCommands.list)
.description("List configured Caplets.")
@@ -554,14 +592,14 @@ export function createProgram(io: CliIO = {}): Command {
);
program
- .command(cliCommands.getCaplet)
+ .command(cliCommands.inspect)
.description("Print a configured Caplet card.")
.argument("", "configured Caplet ID")
.option("--format ", "output format: markdown, md, plain, or json", parseOutputFormat)
.action(async (caplet: string, options: { format?: CliOutputFormat }) => {
await executeOperation(
caplet,
- { operation: "get_caplet" },
+ { operation: "inspect" },
{
writeOut,
writeErr,
@@ -1085,7 +1123,7 @@ async function openBrowser(url: string): Promise {
function remoteCommandForOperation(operation: unknown): RemoteCliCommand | undefined {
switch (operation) {
- case "get_caplet":
+ case "inspect":
case "check_backend":
case "list_tools":
case "search_tools":
@@ -1325,6 +1363,11 @@ function parseOutputFormat(value: string): CliOutputFormat {
}
}
+function parseSetupFormat(value: string): SetupFormat {
+ if (value === "plain" || value === "json") return value;
+ throw new CapletsError("REQUEST_INVALID", "setup format must be plain or json");
+}
+
function parseQualifiedTarget(
capletOrTarget: string,
toolArgument?: string | undefined,
@@ -1388,7 +1431,7 @@ function localShadowedCompletionTarget(words: string[], config: CapletsConfig):
cliCommands.getPrompt,
]);
const capletCommands = new Set([
- cliCommands.getCaplet,
+ cliCommands.inspect,
cliCommands.checkBackend,
cliCommands.listTools,
cliCommands.searchTools,
@@ -1749,7 +1792,7 @@ function markdownSummaryForOperation(result: unknown, request: Record;
export const capletIdCommands = new Set([
- cliCommands.getCaplet,
+ cliCommands.inspect,
cliCommands.checkBackend,
cliCommands.listTools,
cliCommands.searchTools,
diff --git a/packages/core/src/cli/completion.ts b/packages/core/src/cli/completion.ts
index f6c03ec..8ec503c 100644
--- a/packages/core/src/cli/completion.ts
+++ b/packages/core/src/cli/completion.ts
@@ -36,6 +36,7 @@ export type CompletionOptions = {
const optionValueSuggestions: Record> = {
"*": { "--format": ["markdown", "md", "plain", "json"] },
serve: { "--transport": ["stdio", "http"] },
+ setup: { "--format": ["plain", "json"] },
"add:mcp": { "--transport": ["http", "sse"] },
"add:cli": { "--include": ["git", "gh", "package"] },
};
@@ -258,6 +259,6 @@ function cmdCompletionScript(): string {
REM caplets cmd completion helper
REM cmd.exe has no native programmable completion API. This doskey macro prints suggestions for the current words.
doskey caplets-complete=caplets __complete --shell cmd -- $* 2^>nul
-REM Usage: caplets-complete get-caplet
+REM Usage: caplets-complete inspect
`;
}
diff --git a/packages/core/src/cli/setup.ts b/packages/core/src/cli/setup.ts
new file mode 100644
index 0000000..22e1e3d
--- /dev/null
+++ b/packages/core/src/cli/setup.ts
@@ -0,0 +1,370 @@
+import { execFile } from "node:child_process";
+import { mkdirSync, writeFileSync } from "node:fs";
+import { dirname } from "node:path";
+import { promisify } from "node:util";
+import { CapletsError } from "../errors";
+
+const execFileAsync = promisify(execFile);
+
+export const setupIntegrationIds = [
+ "codex",
+ "claude-code",
+ "opencode",
+ "pi",
+ "mcp-client",
+] as const;
+
+export type SetupIntegrationId = (typeof setupIntegrationIds)[number];
+export type SetupFormat = "plain" | "json";
+
+export type SetupCommandResult = {
+ stdout: string;
+ stderr: string;
+};
+
+export type SetupCommandRunner = (command: string, args: string[]) => Promise;
+
+export type SetupOptions = {
+ remote?: boolean;
+ serverUrl?: string;
+ output?: string;
+ dryRun?: boolean;
+ env?: NodeJS.ProcessEnv | Record;
+ format?: SetupFormat;
+ runCommand?: SetupCommandRunner;
+};
+
+type SetupAction =
+ | { type: "command"; label: string; command: string; args: string[] }
+ | { type: "writeFile"; label: string; path: string; content: string };
+
+type SetupActionResult = {
+ label: string;
+ command?: string;
+ path?: string;
+ status: "planned" | "completed";
+};
+
+type SetupResult = {
+ integration: SetupIntegrationId;
+ name: string;
+ mode: "local" | "remote";
+ dryRun: boolean;
+ actions: SetupActionResult[];
+ nextSteps: string[];
+};
+
+const localMcpConfig = `{
+ "mcpServers": {
+ "caplets": {
+ "command": "caplets",
+ "args": ["serve"]
+ }
+ }
+}
+`;
+
+export function formatSetupMenu(): string {
+ return [
+ "Usage: caplets setup ",
+ "",
+ "Supported integrations:",
+ " codex Run Codex plugin marketplace and plugin install commands",
+ " claude-code Run Claude Code plugin marketplace and plugin install commands",
+ " opencode Run OpenCode native plugin install",
+ " pi Run Pi extension install",
+ " mcp-client Write a generic MCP client config with --output",
+ "",
+ "Examples:",
+ " caplets setup codex",
+ " caplets setup opencode --dry-run",
+ " caplets setup mcp-client --output ./caplets.mcp.json",
+ "",
+ ].join("\n");
+}
+
+export async function runSetup(integration: string, options: SetupOptions = {}): Promise {
+ const result = await executeSetup(integration, options);
+ if (options.format === "json") return `${JSON.stringify(result, null, 2)}\n`;
+ return formatSetupResult(result);
+}
+
+async function executeSetup(integration: string, options: SetupOptions): Promise {
+ const id = parseSetupIntegrationId(integration);
+ const definition = setupDefinition(id, options);
+ const actions: SetupActionResult[] = [];
+ const runner = options.runCommand ?? defaultSetupCommandRunner;
+
+ for (const action of definition.actions) {
+ if (action.type === "command") {
+ const commandText = formatCommand(action.command, action.args);
+ if (!options.dryRun) {
+ try {
+ await runner(action.command, action.args);
+ } catch (error) {
+ throw new CapletsError(
+ "SERVER_UNAVAILABLE",
+ `Setup action failed: ${commandText}${error instanceof Error ? `: ${error.message}` : ""}`,
+ );
+ }
+ }
+ actions.push({
+ label: action.label,
+ command: commandText,
+ status: options.dryRun ? "planned" : "completed",
+ });
+ continue;
+ }
+
+ if (!options.dryRun) {
+ try {
+ mkdirSync(dirname(action.path), { recursive: true });
+ writeFileSync(action.path, action.content, { flag: "wx", mode: 0o600 });
+ } catch (error) {
+ throw new CapletsError(
+ "CONFIG_INVALID",
+ `Setup action failed: write ${action.path}${error instanceof Error ? `: ${error.message}` : ""}`,
+ );
+ }
+ }
+ actions.push({
+ label: action.label,
+ path: action.path,
+ status: options.dryRun ? "planned" : "completed",
+ });
+ }
+
+ return {
+ integration: id,
+ name: definition.name,
+ mode: options.remote ? "remote" : "local",
+ dryRun: Boolean(options.dryRun),
+ actions,
+ nextSteps: definition.nextSteps,
+ };
+}
+
+function setupDefinition(
+ id: SetupIntegrationId,
+ options: SetupOptions,
+): { name: string; actions: SetupAction[]; nextSteps: string[] } {
+ if (options.remote) return remoteSetupDefinition(id, options);
+
+ switch (id) {
+ case "codex":
+ return {
+ name: "Codex",
+ actions: [
+ {
+ type: "command",
+ label: "Add Caplets marketplace to Codex",
+ command: "codex",
+ args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"],
+ },
+ {
+ type: "command",
+ label: "Install Caplets Codex plugin",
+ command: "codex",
+ args: ["plugin", "add", "caplets@caplets"],
+ },
+ ],
+ nextSteps: [
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ 'Ask Codex: codex "try using the github caplet"',
+ ],
+ };
+ case "claude-code":
+ return {
+ name: "Claude Code",
+ actions: [
+ {
+ type: "command",
+ label: "Add Caplets marketplace to Claude Code",
+ command: "claude",
+ args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"],
+ },
+ {
+ type: "command",
+ label: "Install Caplets Claude Code plugin",
+ command: "claude",
+ args: ["plugin", "install", "caplets@caplets"],
+ },
+ ],
+ nextSteps: [
+ "Restart Claude Code if it was already running.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "opencode":
+ return {
+ name: "OpenCode",
+ actions: [
+ {
+ type: "command",
+ label: "Install OpenCode Caplets plugin globally",
+ command: "opencode",
+ args: ["plugin", "@caplets/opencode", "--global"],
+ },
+ ],
+ nextSteps: [
+ "OpenCode reads local Caplets config and exposes native caplets_ tools.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "pi":
+ return {
+ name: "Pi",
+ actions: [
+ {
+ type: "command",
+ label: "Install Pi Caplets extension",
+ command: "pi",
+ args: ["install", "npm:@caplets/pi"],
+ },
+ ],
+ nextSteps: [
+ "Pi reads local Caplets config and exposes native tools.",
+ "Try a premade Caplet: caplets install spiritledsoftware/caplets github",
+ ],
+ };
+ case "mcp-client":
+ if (!options.output) {
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ "caplets setup mcp-client requires --output because MCP clients do not share one config path",
+ );
+ }
+ return {
+ name: "Any MCP client",
+ actions: [
+ {
+ type: "writeFile",
+ label: "Write generic MCP stdio config",
+ path: options.output,
+ content: localMcpConfig,
+ },
+ ],
+ nextSteps: ["Import the written MCP config into your MCP client."],
+ };
+ }
+}
+
+function remoteSetupDefinition(
+ id: SetupIntegrationId,
+ options: SetupOptions,
+): { name: string; actions: SetupAction[]; nextSteps: string[] } {
+ const serverUrl =
+ nonEmpty(options.serverUrl) ??
+ nonEmpty(options.env?.CAPLETS_SERVER_URL) ??
+ "https://caplets.example.com/caplets";
+
+ if (id === "opencode") {
+ return {
+ name: "OpenCode",
+ actions: [
+ {
+ type: "command",
+ label: "Install OpenCode Caplets plugin globally",
+ command: "opencode",
+ args: ["plugin", "@caplets/opencode", "--global"],
+ },
+ ],
+ nextSteps: [
+ `Run OpenCode with CAPLETS_MODE=remote and CAPLETS_SERVER_URL=${serverUrl}.`,
+ "Keep CAPLETS_SERVER_PASSWORD in your shell or secret manager.",
+ ],
+ };
+ }
+
+ if (id === "pi") {
+ return {
+ name: "Pi",
+ actions: [
+ {
+ type: "command",
+ label: "Install Pi Caplets extension",
+ command: "pi",
+ args: ["install", "npm:@caplets/pi"],
+ },
+ ],
+ nextSteps: [
+ `Start Pi with CAPLETS_MODE=remote and CAPLETS_SERVER_URL=${serverUrl}.`,
+ "Keep CAPLETS_SERVER_PASSWORD in your shell or secret manager.",
+ ],
+ };
+ }
+
+ if (!options.output) {
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ "remote MCP-backed setup requires --output so Caplets can write a client config without guessing your agent's secret storage",
+ );
+ }
+
+ return {
+ name: id === "codex" ? "Codex" : id === "claude-code" ? "Claude Code" : "Any MCP client",
+ actions: [
+ {
+ type: "writeFile",
+ label: "Write remote MCP config",
+ path: options.output,
+ content: `${JSON.stringify(
+ { mcpServers: { caplets: { url: `${serverUrl.replace(/\/$/, "")}/mcp` } } },
+ null,
+ 2,
+ )}\n`,
+ },
+ ],
+ nextSteps: [
+ "Add Basic Auth credentials through your agent's secret mechanism.",
+ "Do not hardcode CAPLETS_SERVER_PASSWORD in a committed config file.",
+ ],
+ };
+}
+
+function parseSetupIntegrationId(value: string): SetupIntegrationId {
+ if (setupIntegrationIds.includes(value as SetupIntegrationId)) {
+ return value as SetupIntegrationId;
+ }
+ throw new CapletsError(
+ "REQUEST_INVALID",
+ `setup integration must be one of: ${setupIntegrationIds.join(", ")}`,
+ );
+}
+
+async function defaultSetupCommandRunner(
+ command: string,
+ args: string[],
+): Promise {
+ const { stdout, stderr } = await execFileAsync(command, args, {
+ encoding: "utf8",
+ windowsHide: true,
+ });
+ return { stdout, stderr };
+}
+
+function formatSetupResult(result: SetupResult): string {
+ const lines = [
+ `${result.dryRun ? "Dry run" : "Completed"} ${result.name} setup (${result.mode})`,
+ "",
+ ];
+ for (const action of result.actions) {
+ if (action.command) lines.push(`- ${action.status}: ${action.command}`);
+ if (action.path) lines.push(`- ${action.status}: wrote ${action.path}`);
+ }
+ if (result.nextSteps.length > 0) {
+ lines.push("", "Next steps:");
+ for (const step of result.nextSteps) lines.push(`- ${step}`);
+ }
+ lines.push("");
+ return lines.join("\n");
+}
+
+function formatCommand(command: string, args: string[]): string {
+ return [command, ...args].join(" ");
+}
+
+function nonEmpty(value: string | undefined): string | undefined {
+ const trimmed = value?.trim();
+ return trimmed ? trimmed : undefined;
+}
diff --git a/packages/core/src/generated-tool-input-schema.ts b/packages/core/src/generated-tool-input-schema.ts
index f6ded34..135d74d 100644
--- a/packages/core/src/generated-tool-input-schema.ts
+++ b/packages/core/src/generated-tool-input-schema.ts
@@ -1,7 +1,7 @@
import { z } from "zod";
export const operations = [
- "get_caplet",
+ "inspect",
"check_backend",
"list_tools",
"search_tools",
@@ -27,7 +27,7 @@ export type CapletSchemaBackend = { backend: string };
export const generatedToolInputDescriptions = {
operation:
- "Wrapper operation: get_caplet, check_backend, list_tools, search_tools, get_tool, call_tool. MCP Caplets also expose resources, prompts, and completions.",
+ "Wrapper operation: inspect, check_backend, list_tools, search_tools, get_tool, call_tool. MCP Caplets also expose resources, prompts, and completions.",
query: "Required for search operations only.",
limit: "Optional list/search result limit.",
tool: "Exact downstream tool name for get_tool or call_tool.",
diff --git a/packages/core/src/native/tools.ts b/packages/core/src/native/tools.ts
index 9855c08..a112395 100644
--- a/packages/core/src/native/tools.ts
+++ b/packages/core/src/native/tools.ts
@@ -15,7 +15,7 @@ export function nativeCapletsSystemGuidance(toolNames: string[]): string {
"Available Caplets native tools:",
tools,
"",
- "Flow: get_caplet when the domain is unfamiliar; use search_tools/list_tools for actions; MCP-backed Caplets may also expose resources, prompts, and completions in their tool schema.",
+ "Flow: inspect when the domain is unfamiliar; use search_tools/list_tools for actions; MCP-backed Caplets may also expose resources, prompts, and completions in their tool schema.",
"Use fields on call_tool when a non-GraphQL downstream outputSchema allows selecting only needed structured paths.",
].join("\n");
}
diff --git a/packages/core/src/remote-control/dispatch.ts b/packages/core/src/remote-control/dispatch.ts
index 3539b01..7f5b74b 100644
--- a/packages/core/src/remote-control/dispatch.ts
+++ b/packages/core/src/remote-control/dispatch.ts
@@ -27,7 +27,7 @@ export type RemoteControlDispatchContext = CapletsEngineOptions & {
type AddKind = "cli" | "mcp" | "openapi" | "graphql" | "http";
const ENGINE_COMMANDS = new Set([
- "get_caplet",
+ "inspect",
"check_backend",
"list_tools",
"search_tools",
diff --git a/packages/core/src/remote-control/types.ts b/packages/core/src/remote-control/types.ts
index 180e395..002014e 100644
--- a/packages/core/src/remote-control/types.ts
+++ b/packages/core/src/remote-control/types.ts
@@ -2,7 +2,7 @@ import type { CapletsErrorCode } from "../errors";
export type RemoteCliCommand =
| "list"
- | "get_caplet"
+ | "inspect"
| "check_backend"
| "list_tools"
| "search_tools"
diff --git a/packages/core/src/result-content.ts b/packages/core/src/result-content.ts
index f448cee..a90f11e 100644
--- a/packages/core/src/result-content.ts
+++ b/packages/core/src/result-content.ts
@@ -232,7 +232,7 @@ function renderDiscoveryWrapper(
lines.push("## Tool", "", renderToolSummary(asRecord(result?.tool)), "");
} else if (context.operation === "check_backend") {
lines.push("## Backend Status", "", renderBackendStatus(result), "");
- } else if (context.operation === "get_caplet") {
+ } else if (context.operation === "inspect") {
lines.push("## Caplet", "", renderCapletSummary(result), "");
}
lines.push("## Full Result", "", jsonFence(value.result));
diff --git a/packages/core/src/tools.ts b/packages/core/src/tools.ts
index 6fd1eab..5509769 100644
--- a/packages/core/src/tools.ts
+++ b/packages/core/src/tools.ts
@@ -45,10 +45,10 @@ export async function handleServerTool(
);
switch (parsed.operation) {
- case "get_caplet":
+ case "inspect":
return jsonResult(
registry.detail(server),
- metadataFor(server, "get_caplet", undefined, startedAt),
+ metadataFor(server, "inspect", undefined, startedAt),
);
case "check_backend": {
const result = await backendFor(
@@ -303,7 +303,7 @@ export function validateOperationRequest(
};
switch (value.operation) {
- case "get_caplet":
+ case "inspect":
case "check_backend":
allowed([]);
return { operation: value.operation };
@@ -409,7 +409,7 @@ function mcpBackendFor(server: CapletConfig, downstream: DownstreamManager): Dow
}
type RequiredOperationRequest =
- | { operation: "get_caplet" | "check_backend" }
+ | { operation: "inspect" | "check_backend" }
| { operation: "list_tools"; limit?: number }
| { operation: "search_tools"; query: string; limit?: number }
| { operation: "get_tool"; tool: string }
diff --git a/packages/core/test/cli-completion.test.ts b/packages/core/test/cli-completion.test.ts
index 90eb7b5..226488d 100644
--- a/packages/core/test/cli-completion.test.ts
+++ b/packages/core/test/cli-completion.test.ts
@@ -80,6 +80,17 @@ describe("CLI completion resolver", () => {
"stdio",
"http",
]);
+ await expect(completeCliWords(["setup", ""])).resolves.toEqual([
+ "codex",
+ "claude-code",
+ "opencode",
+ "pi",
+ "mcp-client",
+ ]);
+ await expect(completeCliWords(["setup", "codex", "--format", ""])).resolves.toEqual([
+ "plain",
+ "json",
+ ]);
await expect(completeCliWords(["call-tool", "github.search", "--format", ""])).resolves.toEqual(
["markdown", "md", "plain", "json"],
);
@@ -112,7 +123,7 @@ describe("CLI completion resolver", () => {
});
dirs.push(dir);
- await expect(completeCliWords(["get-caplet", ""], { configPath })).resolves.toEqual([
+ await expect(completeCliWords(["inspect", ""], { configPath })).resolves.toEqual([
"github",
"repo",
]);
@@ -408,7 +419,7 @@ describe("CLI completion resolver", () => {
it("returns no suggestions instead of throwing when config loading fails", async () => {
await expect(
- completeCliWords(["get-caplet", ""], { configPath: "/missing/config.json" }),
+ completeCliWords(["inspect", ""], { configPath: "/missing/config.json" }),
).resolves.toEqual([]);
});
});
diff --git a/packages/core/test/cli-remote.test.ts b/packages/core/test/cli-remote.test.ts
index 54461a7..aa8f54c 100644
--- a/packages/core/test/cli-remote.test.ts
+++ b/packages/core/test/cli-remote.test.ts
@@ -27,7 +27,7 @@ describe("remote CLI routing", () => {
},
);
- await runCli(["__complete", "--shell", "bash", "--", "get-caplet", ""], {
+ await runCli(["__complete", "--shell", "bash", "--", "inspect", ""], {
env: {
CAPLETS_MODE: "remote",
CAPLETS_SERVER_URL: "http://127.0.0.1:5387/caplets",
@@ -39,7 +39,7 @@ describe("remote CLI routing", () => {
});
expect(requests).toEqual([
- { command: "complete_cli", arguments: { shell: "bash", words: ["get-caplet", ""] } },
+ { command: "complete_cli", arguments: { shell: "bash", words: ["inspect", ""] } },
]);
expect(out.join("")).toBe("github\nlinear\n");
});
@@ -56,14 +56,14 @@ describe("remote CLI routing", () => {
},
);
- await runCli(["__complete", "--shell", "bash", "--", "get-caplet", ""], {
+ await runCli(["__complete", "--shell", "bash", "--", "inspect", ""], {
env: remoteEnv(context),
fetch,
writeOut: (value) => out.push(value),
});
expect(requests).toEqual([
- { command: "complete_cli", arguments: { shell: "bash", words: ["get-caplet", ""] } },
+ { command: "complete_cli", arguments: { shell: "bash", words: ["inspect", ""] } },
]);
expect(out.join("")).toBe("local\nremote\n");
});
@@ -119,7 +119,7 @@ describe("remote CLI routing", () => {
const err: string[] = [];
const fetch = vi.fn(async () => Response.json({ ok: false, error: "server unavailable" }));
- await runCli(["__complete", "--shell", "bash", "--", "get-caplet", ""], {
+ await runCli(["__complete", "--shell", "bash", "--", "inspect", ""], {
env: {
CAPLETS_MODE: "remote",
CAPLETS_SERVER_URL: "http://127.0.0.1:5387/caplets",
@@ -140,7 +140,7 @@ describe("remote CLI routing", () => {
const fetch = vi.fn(async () => Response.json({ ok: true, result: ["remote"] }));
writeFileSync(context.configPath, "{ invalid json");
- await runCli(["__complete", "--shell", "bash", "--", "get-caplet", ""], {
+ await runCli(["__complete", "--shell", "bash", "--", "inspect", ""], {
env: remoteEnv(context),
fetch,
writeOut: (value) => out.push(value),
diff --git a/packages/core/test/cli.test.ts b/packages/core/test/cli.test.ts
index 6bf0665..ec64ac8 100644
--- a/packages/core/test/cli.test.ts
+++ b/packages/core/test/cli.test.ts
@@ -602,7 +602,7 @@ describe("cli init", () => {
writeCliOperationConfig(configPath);
process.env.CAPLETS_CONFIG = configPath;
- await runCli(["get-caplet", "local", "--format", "json"], {
+ await runCli(["inspect", "local", "--format", "json"], {
writeOut: (value) => out.push(value),
});
await runCli(["check-backend", "local", "--format", "json"], {
@@ -765,7 +765,7 @@ describe("cli init", () => {
writeCliOperationConfig(configPath);
process.env.CAPLETS_CONFIG = configPath;
- await runCli(["get-caplet", "local"], { writeOut: (value) => out.push(value) });
+ await runCli(["inspect", "local"], { writeOut: (value) => out.push(value) });
await runCli(["check-backend", "local"], { writeOut: (value) => out.push(value) });
await runCli(["list-tools", "local"], { writeOut: (value) => out.push(value) });
await runCli(["search-tools", "local", "echo", "--limit", "1"], {
@@ -804,7 +804,7 @@ describe("cli init", () => {
writeCliOperationConfig(configPath);
process.env.CAPLETS_CONFIG = configPath;
- await runCli(["get-caplet", "local", "--format", "plain"], {
+ await runCli(["inspect", "local", "--format", "plain"], {
writeOut: (value) => out.push(value),
});
await runCli(["list-tools", "local", "--format", "md"], {
@@ -2163,6 +2163,148 @@ describe("cli init", () => {
});
});
+describe("cli setup", () => {
+ it("prints supported integrations when no integration is provided", async () => {
+ const out: string[] = [];
+
+ await runCli(["setup"], { writeOut: (value) => out.push(value) });
+
+ const text = out.join("");
+ expect(text).toContain("Usage: caplets setup ");
+ expect(text).toContain("codex");
+ expect(text).toContain("claude-code");
+ expect(text).toContain("opencode");
+ expect(text).toContain("pi");
+ expect(text).toContain("mcp-client");
+ expect(text).toContain("--dry-run");
+ });
+
+ it("runs Codex setup commands", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(["setup", "codex"], {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ });
+
+ expect(commands).toEqual([
+ { command: "codex", args: ["plugin", "marketplace", "add", "spiritledsoftware/caplets"] },
+ { command: "codex", args: ["plugin", "add", "caplets@caplets"] },
+ ]);
+ expect(out.join("")).toContain("Completed Codex setup");
+ });
+
+ it("does not execute commands during dry-run", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(["setup", "codex", "--dry-run"], {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ });
+
+ expect(commands).toEqual([]);
+ expect(out.join("")).toContain("Dry run");
+ expect(out.join("")).toContain("codex plugin marketplace add spiritledsoftware/caplets");
+ expect(out.join("")).toContain("codex plugin add caplets@caplets");
+ });
+
+ it("writes a generic MCP client config when output is provided", async () => {
+ const dir = mkdtempSync(join(tmpdir(), "caplets-setup-"));
+ const output = join(dir, "nested", "caplets.mcp.json");
+ const out: string[] = [];
+
+ try {
+ await runCli(["setup", "mcp-client", "--output", output], {
+ writeOut: (value) => out.push(value),
+ });
+
+ expect(JSON.parse(readFileSync(output, "utf8"))).toEqual({
+ mcpServers: { caplets: { command: "caplets", args: ["serve"] } },
+ });
+ expect(out.join("")).toContain(`completed: wrote ${output}`);
+ } finally {
+ rmSync(dir, { recursive: true, force: true });
+ }
+ });
+
+ it("rejects generic MCP client setup without output", async () => {
+ await expect(runCli(["setup", "mcp-client"], { writeErr: () => {} })).rejects.toThrow(
+ expect.objectContaining({
+ code: "REQUEST_INVALID",
+ message: expect.stringContaining("requires --output "),
+ }) as CapletsError,
+ );
+ });
+
+ it("runs remote OpenCode setup and reports JSON output", async () => {
+ const out: string[] = [];
+ const commands: Array<{ command: string; args: string[] }> = [];
+
+ await runCli(
+ [
+ "setup",
+ "opencode",
+ "--remote",
+ "--server-url",
+ "https://caplets.example.test/caplets",
+ "--format",
+ "json",
+ ],
+ {
+ writeOut: (value) => out.push(value),
+ runSetupCommand: async (command, args) => {
+ commands.push({ command, args });
+ return { stdout: "", stderr: "" };
+ },
+ },
+ );
+
+ expect(commands).toEqual([
+ { command: "opencode", args: ["plugin", "@caplets/opencode", "--global"] },
+ ]);
+ expect(JSON.parse(out.join(""))).toMatchObject({
+ integration: "opencode",
+ name: "OpenCode",
+ mode: "remote",
+ dryRun: false,
+ actions: [
+ {
+ command: "opencode plugin @caplets/opencode --global",
+ status: "completed",
+ },
+ ],
+ nextSteps: [
+ "Run OpenCode with CAPLETS_MODE=remote and CAPLETS_SERVER_URL=https://caplets.example.test/caplets.",
+ "Keep CAPLETS_SERVER_PASSWORD in your shell or secret manager.",
+ ],
+ });
+ });
+
+ it("wraps setup command failures with the failed command", async () => {
+ await expect(
+ runCli(["setup", "codex"], {
+ writeErr: () => {},
+ runSetupCommand: async () => {
+ throw new Error("missing codex binary");
+ },
+ }),
+ ).rejects.toThrow(
+ expect.objectContaining({
+ code: "SERVER_UNAVAILABLE",
+ message: expect.stringContaining("codex plugin marketplace add spiritledsoftware/caplets"),
+ }) as CapletsError,
+ );
+ });
+});
+
describe("cli completion commands", () => {
it("prints completion scripts", async () => {
const out: string[] = [];
@@ -2223,7 +2365,7 @@ describe("cli completion commands", () => {
const out: string[] = [];
try {
writeInspectionConfig(configPath);
- await runCli(["__complete", "--shell", "bash", "--", "get-caplet", ""], {
+ await runCli(["__complete", "--shell", "bash", "--", "inspect", ""], {
env: { CAPLETS_CONFIG: configPath },
writeOut: (value) => out.push(value),
});
diff --git a/packages/core/test/config.test.ts b/packages/core/test/config.test.ts
index dc56c83..d60ecd0 100644
--- a/packages/core/test/config.test.ts
+++ b/packages/core/test/config.test.ts
@@ -678,8 +678,8 @@ describe("config", () => {
});
it("keeps repository example Caplets loadable", () => {
- const originalGithubToken = process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
- delete process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
+ const originalGithubToken = process.env.GH_TOKEN;
+ process.env.GH_TOKEN = "test-github-token";
try {
const examples = loadCapletFiles(join(import.meta.dirname, "../../..", "caplets"));
@@ -694,16 +694,9 @@ describe("config", () => {
expect(config.mcpServers.github).toMatchObject({
server: "github",
name: "GitHub",
- command: "docker",
- args: [
- "run",
- "-i",
- "--rm",
- "-e",
- "GITHUB_PERSONAL_ACCESS_TOKEN",
- "ghcr.io/github/github-mcp-server",
- ],
- env: { GITHUB_PERSONAL_ACCESS_TOKEN: "" },
+ transport: "http",
+ url: "https://api.githubcopilot.com/mcp",
+ auth: { type: "bearer", token: "test-github-token" },
});
expect(config.mcpServers.linear).toMatchObject({
server: "linear",
@@ -786,9 +779,9 @@ describe("config", () => {
});
} finally {
if (originalGithubToken === undefined) {
- delete process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
+ delete process.env.GH_TOKEN;
} else {
- process.env.GITHUB_PERSONAL_ACCESS_TOKEN = originalGithubToken;
+ process.env.GH_TOKEN = originalGithubToken;
}
}
});
diff --git a/packages/core/test/native-remote.test.ts b/packages/core/test/native-remote.test.ts
index 2732946..feb26c6 100644
--- a/packages/core/test/native-remote.test.ts
+++ b/packages/core/test/native-remote.test.ts
@@ -424,7 +424,7 @@ describe("createNativeCapletsService remote mode", () => {
});
await service.reload();
- await expect(service.execute("local", { operation: "get_caplet" })).resolves.toEqual(
+ await expect(service.execute("local", { operation: "inspect" })).resolves.toEqual(
expect.objectContaining({ content: expect.any(Array) }),
);
await expect(service.execute("remote-only", { input: true })).resolves.toEqual({
diff --git a/packages/core/test/native.test.ts b/packages/core/test/native.test.ts
index f39c8b3..ef04063 100644
--- a/packages/core/test/native.test.ts
+++ b/packages/core/test/native.test.ts
@@ -61,7 +61,7 @@ describe("native Caplets service", () => {
}
});
- it("executes get_caplet through the shared operation handler", async () => {
+ it("executes inspect through the shared operation handler", async () => {
const { dir, configPath, projectConfigPath } = tempConfig({
mcpServers: {
alpha: {
@@ -76,7 +76,7 @@ describe("native Caplets service", () => {
const service = createNativeCapletsService({ configPath, projectConfigPath });
try {
- const result = await service.execute("alpha", { operation: "get_caplet" });
+ const result = await service.execute("alpha", { operation: "inspect" });
expect(JSON.stringify(result)).toContain("Alpha");
expect(JSON.stringify(result)).not.toContain("super-secret");
@@ -99,7 +99,7 @@ describe("native Caplets service", () => {
const service = createNativeCapletsService({ configPath, projectConfigPath });
try {
- const result = await service.execute("missing", { operation: "get_caplet" });
+ const result = await service.execute("missing", { operation: "inspect" });
expect(JSON.stringify(result)).toContain("server not found: missing");
} finally {
@@ -112,7 +112,7 @@ describe("native Caplets service", () => {
const guidance = nativeCapletsSystemGuidance(["caplets_linear_api__v2"]);
expect(guidance).toContain("caplets_linear_api__v2");
- expect(guidance).toContain("Flow: get_caplet when the domain is unfamiliar");
+ expect(guidance).toContain("Flow: inspect when the domain is unfamiliar");
expect(guidance).toContain(
"Use fields on call_tool when a non-GraphQL downstream outputSchema allows",
);
@@ -134,7 +134,7 @@ describe("native Caplets service", () => {
expect(guidance).toContain("Use caplets_browser for the Browser Caplet capability domain.");
expect(guidance).not.toContain("For unfamiliar tasks, discover safely");
- expect(guidance).not.toContain("Call caplets_browser with operation get_caplet before");
+ expect(guidance).not.toContain("Call caplets_browser with operation inspect before");
});
it("reloads native tool metadata after config changes", async () => {
diff --git a/packages/core/test/registry.test.ts b/packages/core/test/registry.test.ts
index 4d3a9c1..4f9ebd6 100644
--- a/packages/core/test/registry.test.ts
+++ b/packages/core/test/registry.test.ts
@@ -88,7 +88,7 @@ describe("registry", () => {
expect(registry.get("status")?.backend).toBe("http");
const description = capabilityDescription(config.mcpServers.enabled!);
expect(description).toContain("Enabled Server");
- expect(description).toContain("Use get_caplet for details when needed");
+ expect(description).toContain("Use inspect for details when needed");
expect(description).not.toContain("Recommended flow:");
expect(description).not.toContain("secret-arg");
expect(description).not.toContain("secret-env-value");
@@ -100,7 +100,7 @@ describe("registry", () => {
expect(serialized).not.toContain("secret-bearer-value");
const openApiDescription = capabilityDescription(config.openapiEndpoints.users!);
- expect(openApiDescription).toContain("Use get_caplet for details when needed");
+ expect(openApiDescription).toContain("Use inspect for details when needed");
const openApiDetail = registry.detail(config.openapiEndpoints.users!);
expect(openApiDetail).toEqual({
id: "users",
@@ -117,7 +117,7 @@ describe("registry", () => {
expect(JSON.stringify(openApiDetail)).not.toContain("secret-token");
const graphQlDescription = capabilityDescription(config.graphqlEndpoints.catalog!);
- expect(graphQlDescription).toContain("Use get_caplet for details when needed");
+ expect(graphQlDescription).toContain("Use inspect for details when needed");
const graphQlDetail = registry.detail(config.graphqlEndpoints.catalog!);
expect(graphQlDetail).toEqual({
id: "catalog",
@@ -135,7 +135,7 @@ describe("registry", () => {
expect(JSON.stringify(graphQlDetail)).not.toContain("secret-graphql");
const httpDescription = capabilityDescription(config.httpApis.status!);
- expect(httpDescription).toContain("Use get_caplet for details when needed");
+ expect(httpDescription).toContain("Use inspect for details when needed");
const httpDetail = registry.detail(config.httpApis.status!);
expect(httpDetail).toEqual({
id: "status",
@@ -151,7 +151,7 @@ describe("registry", () => {
expect(JSON.stringify(httpDetail)).not.toContain("secret-http");
const cliDescription = capabilityDescription(config.cliTools.repo!);
- expect(cliDescription).toContain("Use get_caplet for details when needed");
+ expect(cliDescription).toContain("Use inspect for details when needed");
const cliDetail = registry.detail(config.cliTools.repo!);
expect(cliDetail).toEqual({
id: "repo",
@@ -167,7 +167,7 @@ describe("registry", () => {
});
const capletSetDescription = capabilityDescription(config.capletSets.nested!);
- expect(capletSetDescription).toContain("Use get_caplet for details when needed");
+ expect(capletSetDescription).toContain("Use inspect for details when needed");
const capletSetDetail = registry.detail(config.capletSets.nested!);
expect(capletSetDetail).toEqual({
id: "nested",
diff --git a/packages/core/test/remote-control-dispatch.test.ts b/packages/core/test/remote-control-dispatch.test.ts
index dc33e64..93c5ba2 100644
--- a/packages/core/test/remote-control-dispatch.test.ts
+++ b/packages/core/test/remote-control-dispatch.test.ts
@@ -42,13 +42,13 @@ describe("dispatchRemoteCliRequest", () => {
]);
});
- it("executes get_caplet through the server engine", async () => {
+ it("executes inspect through the server engine", async () => {
const context = testContext();
const response = await dispatchRemoteCliRequest(
{
- command: "get_caplet",
- arguments: { caplet: "server_status", request: { operation: "get_caplet" } },
+ command: "inspect",
+ arguments: { caplet: "server_status", request: { operation: "inspect" } },
},
context,
);
@@ -343,7 +343,7 @@ describe("dispatchRemoteCliRequest", () => {
);
const response = await dispatchRemoteCliRequest(
- { command: "complete_cli", arguments: { shell: "bash", words: ["get-caplet", ""] } },
+ { command: "complete_cli", arguments: { shell: "bash", words: ["inspect", ""] } },
context,
);
diff --git a/packages/core/test/tools.test.ts b/packages/core/test/tools.test.ts
index ece42ab..06548b6 100644
--- a/packages/core/test/tools.test.ts
+++ b/packages/core/test/tools.test.ts
@@ -124,7 +124,7 @@ describe("generated tool request validation", () => {
};
expect(schema.properties.operation?.enum).toEqual([
- "get_caplet",
+ "inspect",
"check_backend",
"list_tools",
"search_tools",
@@ -200,11 +200,11 @@ describe("generated tool handlers", () => {
},
];
- it("returns get_caplet without starting downstream", async () => {
+ it("returns inspect without starting downstream", async () => {
const downstream = { checkServer: vi.fn(), listTools: vi.fn() } as unknown as DownstreamManager;
const result = (await handleServerTool(
server,
- { operation: "get_caplet" },
+ { operation: "inspect" },
registry,
downstream,
)) as any;
@@ -212,7 +212,7 @@ describe("generated tool handlers", () => {
id: "alpha",
name: "Alpha",
backend: "mcp",
- operation: "get_caplet",
+ operation: "inspect",
status: "ok",
elapsedMs: expect.any(Number),
});
@@ -232,7 +232,7 @@ describe("generated tool handlers", () => {
expect(downstream.listTools).not.toHaveBeenCalled();
});
- it("returns OpenAPI get_caplet without requiring an OpenAPI manager", async () => {
+ it("returns OpenAPI inspect without requiring an OpenAPI manager", async () => {
const openApiConfig = parseConfig({
openapiEndpoints: {
users: {
@@ -249,7 +249,7 @@ describe("generated tool handlers", () => {
const result = (await handleServerTool(
openApiConfig.openapiEndpoints.users!,
- { operation: "get_caplet" },
+ { operation: "inspect" },
openApiRegistry,
downstream,
)) as any;
@@ -263,7 +263,7 @@ describe("generated tool handlers", () => {
});
});
- it("returns HTTP get_caplet without requiring an HTTP manager", async () => {
+ it("returns HTTP inspect without requiring an HTTP manager", async () => {
const httpConfig = parseConfig({
httpApis: {
status: {
@@ -280,7 +280,7 @@ describe("generated tool handlers", () => {
const result = (await handleServerTool(
httpConfig.httpApis.status!,
- { operation: "get_caplet" },
+ { operation: "inspect" },
httpRegistry,
downstream,
)) as any;
diff --git a/packages/opencode/package.json b/packages/opencode/package.json
index 46b8c55..fc4ab2c 100644
--- a/packages/opencode/package.json
+++ b/packages/opencode/package.json
@@ -38,7 +38,7 @@
},
"devDependencies": {
"@types/node": "^25.9.1",
- "@typescript/native-preview": "7.0.0-dev.20260527.1",
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
"rolldown": "^1.0.3",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
diff --git a/packages/opencode/test/opencode.test.ts b/packages/opencode/test/opencode.test.ts
index 1c99aff..574f727 100644
--- a/packages/opencode/test/opencode.test.ts
+++ b/packages/opencode/test/opencode.test.ts
@@ -56,8 +56,8 @@ describe("@caplets/opencode", () => {
const capletsTool = hooks.tool!.caplets_git_hub as {
execute(args: unknown, context: unknown): Promise;
};
- const result = await capletsTool.execute({ operation: "get_caplet" }, {} as never);
- expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "get_caplet" });
+ const result = await capletsTool.execute({ operation: "inspect" }, {} as never);
+ expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "inspect" });
expect(result).toContain('"ok": true');
const output = { system: [] as string[] };
@@ -88,7 +88,7 @@ describe("@caplets/opencode", () => {
execute(args: unknown, context: unknown): Promise;
};
- const result = await capletsTool.execute({ operation: "get_caplet" }, {} as never);
+ const result = await capletsTool.execute({ operation: "inspect" }, {} as never);
expect(result).toContain("Serialization error");
expect(result).toContain("BigInt");
@@ -117,9 +117,7 @@ describe("@caplets/opencode", () => {
execute(args: unknown, context: unknown): Promise;
};
- await expect(capletsTool.execute({ operation: "get_caplet" }, {} as never)).resolves.toBe(
- "null",
- );
+ await expect(capletsTool.execute({ operation: "inspect" }, {} as never)).resolves.toBe("null");
});
it("refreshes system guidance for remaining registered tools only", async () => {
diff --git a/packages/pi/package.json b/packages/pi/package.json
index 35d46ae..099974d 100644
--- a/packages/pi/package.json
+++ b/packages/pi/package.json
@@ -38,7 +38,7 @@
},
"devDependencies": {
"@types/node": "^25.9.1",
- "@typescript/native-preview": "7.0.0-dev.20260527.1",
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
"rolldown": "^1.0.3",
"typescript": "^6.0.3",
"vitest": "^4.1.7"
diff --git a/packages/pi/test/pi.test.ts b/packages/pi/test/pi.test.ts
index 0118337..c772386 100644
--- a/packages/pi/test/pi.test.ts
+++ b/packages/pi/test/pi.test.ts
@@ -138,8 +138,8 @@ describe("@caplets/pi", () => {
expect(tool?.name).toBe("caplets_git_hub");
expect(tool?.promptGuidelines[0]).toContain("caplets_git_hub");
- const result = await tool?.execute("call-1", { operation: "get_caplet" });
- expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "get_caplet" });
+ const result = await tool?.execute("call-1", { operation: "inspect" });
+ expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "inspect" });
expect(result?.details.result).toEqual({ ok: true });
});
@@ -161,10 +161,10 @@ describe("@caplets/pi", () => {
registerTool: (definition) => registered.push(definition as unknown as RegisteredTool),
});
- await expect(registered[0]?.execute("call-1", { operation: "get_caplet" })).rejects.toThrow(
+ await expect(registered[0]?.execute("call-1", { operation: "inspect" })).rejects.toThrow(
"execution failed",
);
- expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "get_caplet" });
+ expect(service.execute).toHaveBeenCalledWith("git-hub", { operation: "inspect" });
});
it("returns serialization errors in tool details", async () => {
@@ -184,7 +184,7 @@ describe("@caplets/pi", () => {
registerTool: (definition) => registered.push(definition as unknown as RegisteredTool),
});
- const result = await registered[0]?.execute("call-1", { operation: "get_caplet" });
+ const result = await registered[0]?.execute("call-1", { operation: "inspect" });
expect(result?.content[0]?.text).toContain("Serialization error");
expect(result?.details.serializationError).toContain("BigInt");
});
@@ -206,7 +206,7 @@ describe("@caplets/pi", () => {
registerTool: (definition) => registered.push(definition as unknown as RegisteredTool),
});
- const result = await registered[0]?.execute("call-1", { operation: "get_caplet" });
+ const result = await registered[0]?.execute("call-1", { operation: "inspect" });
expect(result?.content[0]?.text).toBe("null");
expect(result?.details).toEqual({ result: undefined });
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f6faf2b..77edf9f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -12,14 +12,14 @@ importers:
specifier: ^2.31.0
version: 2.31.0(@types/node@25.9.1)
'@cloudflare/workers-types':
- specifier: ^4.20260527.1
- version: 4.20260527.1
+ specifier: ^4.20260529.1
+ version: 4.20260529.1
'@types/node':
specifier: ^25.9.1
version: 25.9.1
'@typescript/native-preview':
- specifier: 7.0.0-dev.20260527.1
- version: 7.0.0-dev.20260527.1
+ specifier: 7.0.0-dev.20260527.2
+ version: 7.0.0-dev.20260527.2
alchemy:
specifier: 0.93.9
version: 0.93.9(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)(yaml@2.9.0))(workerd@1.20260526.1)
@@ -35,6 +35,9 @@ importers:
oxlint:
specifier: ^1.67.0
version: 1.67.0
+ prettier-plugin-astro:
+ specifier: ^0.14.1
+ version: 0.14.1
rolldown:
specifier: ^1.0.3
version: 1.0.3
@@ -42,8 +45,8 @@ importers:
specifier: ^4.22.3
version: 4.22.3
turbo:
- specifier: ^2.9.15
- version: 2.9.15
+ specifier: ^2.9.16
+ version: 2.9.16
typescript:
specifier: ^6.0.3
version: 6.0.3
@@ -55,13 +58,16 @@ importers:
dependencies:
'@astrojs/check':
specifier: ^0.9.9
- version: 0.9.9(prettier@3.8.3)(typescript@6.0.3)
+ version: 0.9.9(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@6.0.3)
+ '@hugeicons/core-free-icons':
+ specifier: 4.2.0
+ version: 4.2.0
'@tailwindcss/vite':
specifier: ^4.3.0
version: 4.3.0(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)(yaml@2.9.0))
astro:
- specifier: ^6.3.8
- version: 6.3.8(@types/node@25.9.1)(aws4fetch@1.0.20)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(tsx@4.22.3)(yaml@2.9.0)
+ specifier: ^6.4.2
+ version: 6.4.2(@types/node@25.9.1)(aws4fetch@1.0.20)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(tsx@4.22.3)(yaml@2.9.0)
tailwindcss:
specifier: ^4.3.0
version: 4.3.0
@@ -75,15 +81,15 @@ importers:
specifier: workspace:*
version: link:../core
commander:
- specifier: ^14.0.3
- version: 14.0.3
+ specifier: ^15.0.0
+ version: 15.0.0
devDependencies:
'@types/node':
specifier: ^25.9.1
version: 25.9.1
'@typescript/native-preview':
- specifier: 7.0.0-dev.20260527.1
- version: 7.0.0-dev.20260527.1
+ specifier: 7.0.0-dev.20260527.2
+ version: 7.0.0-dev.20260527.2
caplets:
specifier: workspace:*
version: link:../cli
@@ -107,8 +113,8 @@ importers:
specifier: ^25.9.1
version: 25.9.1
'@typescript/native-preview':
- specifier: 7.0.0-dev.20260527.1
- version: 7.0.0-dev.20260527.1
+ specifier: 7.0.0-dev.20260527.2
+ version: 7.0.0-dev.20260527.2
rolldown:
specifier: ^1.0.3
version: 1.0.3
@@ -134,8 +140,8 @@ importers:
specifier: ^1.29.0
version: 1.29.0(zod@4.4.3)
commander:
- specifier: ^14.0.3
- version: 14.0.3
+ specifier: ^15.0.0
+ version: 15.0.0
graphql:
specifier: ^16.14.0
version: 16.14.0
@@ -184,8 +190,8 @@ importers:
specifier: ^25.9.1
version: 25.9.1
'@typescript/native-preview':
- specifier: 7.0.0-dev.20260527.1
- version: 7.0.0-dev.20260527.1
+ specifier: 7.0.0-dev.20260527.2
+ version: 7.0.0-dev.20260527.2
rolldown:
specifier: ^1.0.3
version: 1.0.3
@@ -212,8 +218,8 @@ importers:
specifier: ^25.9.1
version: 25.9.1
'@typescript/native-preview':
- specifier: 7.0.0-dev.20260527.1
- version: 7.0.0-dev.20260527.1
+ specifier: 7.0.0-dev.20260527.2
+ version: 7.0.0-dev.20260527.2
rolldown:
specifier: ^1.0.3
version: 1.0.3
@@ -263,8 +269,8 @@ packages:
'@astrojs/compiler@4.0.0':
resolution: {integrity: sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA==}
- '@astrojs/internal-helpers@0.9.1':
- resolution: {integrity: sha512-1pWuARqYom/TzuU3+0ZugsTrKlUydWKuULmDqSMTuonY+9IRDUEGKX/8PXQ1nBxRq3w85uGtd9q9SXfqEldMIQ==}
+ '@astrojs/internal-helpers@0.10.0':
+ resolution: {integrity: sha512-Ry2R3VPeIN4uPCSA4xQc+e+vsJXkalKpEbDc07hV+a/o5Bs2N/s/uDcPJH/05L19DKh9tAy7e6JM3YZ6Cxfezw==}
'@astrojs/language-server@2.16.10':
resolution: {integrity: sha512-87VQ/5GSdHlRnUA+hGuerYyIGAj+9RbZmATyuKLEUePinUXhQ5YkRnRrHhOD9sSi5JOErLjrLkHnfZFEvGrV8w==}
@@ -278,8 +284,8 @@ packages:
prettier-plugin-astro:
optional: true
- '@astrojs/markdown-remark@7.1.2':
- resolution: {integrity: sha512-caXZ4Dc2St2dW8luEg22GlP0gupLdztCTQE4EzZOxW1pqWXz9mbeJEuHUkgDYcKWW8tjIHkydYDhWLVoxJ327Q==}
+ '@astrojs/markdown-remark@7.2.0':
+ resolution: {integrity: sha512-+YxmVQu1Bd+MFfSzjq1rOJvD9+nIOJzz5YIIhdIH01RrxRkKbyKoEgyIqP3yv51MhzMDgd79QaPv+kCVPT8vHw==}
'@astrojs/prism@4.0.2':
resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==}
@@ -313,88 +319,88 @@ packages:
resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/client-cognito-identity@3.1054.0':
- resolution: {integrity: sha512-B3R1BnF9MtyAyIhI875geixK4SJ1dXwWjf8McBMyMkctaXdvGx5O4YD7MPxGPtbmExrW4tDp6h4wQbDJDLZumw==}
+ '@aws-sdk/client-cognito-identity@3.1056.0':
+ resolution: {integrity: sha512-Fywg6+B39uGiYZRYFEsOXbIeHQ8wvtMqlt6FUwWev8N2H+V0pVdgCKn32pSOzud1i17wnm5gpB2VXZEoyVHc2A==}
engines: {node: '>=20.0.0'}
'@aws-sdk/core@3.974.13':
resolution: {integrity: sha512-+Y5/4tHki0uYgyx8eun146DegRVQBpdKGK5RbV0FTKJPpaKTchvqVxrrRFK6Wk0JksO4iAZKw3eqxGEIwtO98w==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/core@3.974.14':
- resolution: {integrity: sha512-ppamm04uoj3hhNO5IlQSs5D6rWX1fWkzcn6a4pZrojk8Y6ObY9wzLDdT/Eq3gv6O9hOebi9tYTNB8b8fQj9XJw==}
+ '@aws-sdk/core@3.974.15':
+ resolution: {integrity: sha512-UpA0rTGW/tHGITcCqHisbuuEPraYg9GG+mWmXjY5+RxZBMLGe6aL9oe0ix50LztwAcPIkGZLH0yWdMIkCM10hw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-cognito-identity@3.972.37':
- resolution: {integrity: sha512-f8ZRPoATqSVS1LW19KwiWn2/BSTdylXPznAjDI2r7d3+RT880/yRT9uBQhPE+Ba986LiMRvg1AhmFYDwNLk/0A==}
+ '@aws-sdk/credential-provider-cognito-identity@3.972.38':
+ resolution: {integrity: sha512-OHkK6xOx/IHkSbQdDWxnVCLU+j28EFl8wyWgBILQDFAPY8n240C/O4gjmFx+zFU12lL8njgJQ5GWAIWq88CnSQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-env@3.972.39':
resolution: {integrity: sha512-29wX9zpAvEt1vcj0psha+y6ygBHy2V/S72mp6e7q0KARLWXq+pwE/lR6qGkwknQvruh52lXvlqZIga8Hdxkucw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-env@3.972.40':
- resolution: {integrity: sha512-jjT0p0Y7KZtcvExYiPCLJnqM9lkXDV1KBEg/13OE2DXv/9batzlyJHVKUEnRNJccY0O2Sul17E1su38CgdBhGQ==}
+ '@aws-sdk/credential-provider-env@3.972.41':
+ resolution: {integrity: sha512-n1EbJ98yvPWWdHZZv8bRBMqqDQJrtgtxyJ4xLy2Uqrh25BCOZQ7nnS1CsFXvuH8r0b0KVHDZEGEH5FxmEMP8jg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-http@3.972.41':
resolution: {integrity: sha512-IA3CQTjtJkb6u1H4mE4936c8OPBMa9Jggtwe8U2Mqw/vvb/tZ5Ebd0mcZcX0uKWQhOyYo/+qNIwkV5Xh+FeJJA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-http@3.972.42':
- resolution: {integrity: sha512-+3fsKtWybe5BjKEUA3/07oh7Ayfd82IED2+gyyaVfS/4PU78E3TaOQxSGOJ1t7Imefoidw/ne9QA7apX8wEnJg==}
+ '@aws-sdk/credential-provider-http@3.972.43':
+ resolution: {integrity: sha512-TT76RN1NkI9WoyZqCNxOw6/WBMF7pYOTJcXbMokNFU+euSG40Kaf/t/FhDACVZWP+43wEM6ZynIPIkzS1wR1iA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-ini@3.972.43':
resolution: {integrity: sha512-4mzII+3mZEVXXE1xzrLQrCJL7/r62A63bA6SVzZoNL5rqCJghpf+xgGltVrIBBs0n+mOZBKrQl2tRREtvZ5l6A==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-ini@3.972.44':
- resolution: {integrity: sha512-gZFw5wBefCIPg9vpT+gV5FdhfNKhYTVDZa1IsZCcn3SRoYUOJ/E05vwIogkJoonqBL0ttBGi5vhthX7xceekRg==}
+ '@aws-sdk/credential-provider-ini@3.972.45':
+ resolution: {integrity: sha512-sJe5ZWibO4s7RWjFQ8Zol76KxoJcIYyEZH1/wxQSBMSIAAxzaJ8cS/ITAaIHWUQvDKQdt18+cJAHKWB7n1Jmrg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-login@3.972.43':
resolution: {integrity: sha512-HG7kQCwXtbv3oBV61Ins0oNX8KKyvrMqqRkb6ZiAfQHbMuHaiNaEb2KnpKLPkNpqImSBK82UkVE/kaY6IfWikA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-login@3.972.44':
- resolution: {integrity: sha512-QqEGHfQeZgUDqh7zpqHufrZ8T644ELEWvB+4gUdewLyRw4IRF+6CJqeQuRWqucZdQzoQeMh7fNAD9BWxFAdNig==}
+ '@aws-sdk/credential-provider-login@3.972.45':
+ resolution: {integrity: sha512-MZQv4SNjByk1iOKmrqmzcUF/uCB05wjvEHyXKxmGQTUANTIVayX6HPUF0bzkWLvtnkH7sAn9kUCfkXbSpj9sDA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-node@3.972.44':
resolution: {integrity: sha512-sDaBIT0yrNNIPfvlsiTCmANm07zKju+ipWODjEXgZlsjMeIJR3LVp7RDyAOzUoAsTbDfYKDWp+i5WrFiQP6rmQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-node@3.972.45':
- resolution: {integrity: sha512-3YCv52ExXIRz3LAVNysevd+s7akSpg9dl39v9LJ7dOQH+s5rHi3jMZYQyxwMmglxQGMuzYRfQ0o1VSP2UOlIRw==}
+ '@aws-sdk/credential-provider-node@3.972.46':
+ resolution: {integrity: sha512-cS4w0jzDRb1jOlkiJS3y80OxddHzkky/MN9k3NYs5jganNKVLjF0lpvjlwS118oGMr3cdAfOlVdo8gLurTSE7w==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-process@3.972.39':
resolution: {integrity: sha512-2k/amBifLd75eXNwgvPw/2lKYSQ3NhvHQgkVKVjfUq13/eJ3JRtHmznuFenn74OK3sSfp4SMy1YB2w+UVXoKqA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-process@3.972.40':
- resolution: {integrity: sha512-cXaozlgJCOwmE6D7x4npcPdyk7kiFZdrGjN3D6tXXtItJJMNGPafDfAJn4YQmciMooG/X+b0Y6RTqdVVMx26jg==}
+ '@aws-sdk/credential-provider-process@3.972.41':
+ resolution: {integrity: sha512-7I/n1zkysouLOWvkEhjNEP4vMnD2v4kzzr3/3QBdrripEpn7ap1/I5DF3Hou1SUqkKWo1f3oPGMyFAA1FAMvsQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-sso@3.972.43':
resolution: {integrity: sha512-LPc3+Y4vhH1T4x6CMqwCM6hk5+SRf/Lwmgm8INm95wxTtIRHcMwQUVkDzWu4Iw/RSncxYM2BC01OrYbxOPZvyg==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-sso@3.972.44':
- resolution: {integrity: sha512-YePoj5kQuPmE0MHnyftXCfsO8ZSBd2kDr50XEIUrdejSbGFlayYvUuCohdb8drhGhPm6b65o7H1eC26EZhwUvA==}
+ '@aws-sdk/credential-provider-sso@3.972.45':
+ resolution: {integrity: sha512-oHgbz/eFD8IKiksqDsz9ZMU4A59BpQq4QwJedBnGD80ZqYcHPPHZBwjBnxLVkB7iRVVHWpDclR8yWdD2PkQIUA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-web-identity@3.972.43':
resolution: {integrity: sha512-wQtL34lUD/09VXjwAUo2T+I3aEXRDxMB3DKmTJL/Zj0Gi6sLDTrVhae1XVt01yzkquOWajI/sZW72JGDZ1ciTw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-web-identity@3.972.44':
- resolution: {integrity: sha512-Ys/JJe++8Z2Y5meR1taMBaVcrGBA0/XsVTQR+qOKZbdNyg+8Jlv5rYZSwh8SqEHY00goSOZy7PHzZ2rLNQxDLg==}
+ '@aws-sdk/credential-provider-web-identity@3.972.45':
+ resolution: {integrity: sha512-CDhzKdb2onv5bpnjn/acgdNmJOQthPDLsPizU7rZflsEcgMMp8Mlri+U5hdxf8ldvZJpvM3vLU6D56vfJm5AMQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-providers@3.1054.0':
- resolution: {integrity: sha512-/tK0QmOL1vUqOgqRMLTJlvHRAp+7GTfdPgrfgD5T0WBmExdlaFsVwzR7mUQlmYoY8mExqoRH4UEt2I3snsMLrg==}
+ '@aws-sdk/credential-providers@3.1056.0':
+ resolution: {integrity: sha512-Qp7ndCG+dZldiaURze6BM/dLkHQJxwi6WNRR1sR9lhX9jS9QG5ZIOiY3jm6T668vgGqHuNQS7r/P9pimxnHyyg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/eventstream-handler-node@3.972.17':
@@ -413,16 +419,16 @@ packages:
resolution: {integrity: sha512-nWXXJ1r/r8N2Gw1pWolRgED38/A9A8DHR2ETWIv220zh4PZHcybbR4hUVWWktmNXTRHzDJwRluapHn0rZxuoqA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/nested-clients@3.997.12':
- resolution: {integrity: sha512-Js2VYaCM269feB0cs0cGmlIhdOgT9aMqzdBx68lCy6kVCYfzr0T36ovUFDvfUmatkuBeyBJhCwaLBh7P8meH5Q==}
+ '@aws-sdk/nested-clients@3.997.13':
+ resolution: {integrity: sha512-2pA6eyb5nSo/ZD2cayhOTEMoGQYgspq0RI05GDLkzQ3ajZ6isS6waV6E92Am/hz4LIlLUTrbwPLurJ/fuiHvkg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/signature-v4-multi-region@3.996.28':
resolution: {integrity: sha512-qs9z5LqXO/CZC2Lg9SGKpoLU8Rhi+m2pFKZqfO9pytX1clc0katqtsDNupJxFy0xT9wsZSPzM2v1y+/H/zfp5Q==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/signature-v4-multi-region@3.996.29':
- resolution: {integrity: sha512-Few9FoQqOt/0KSvZYP+qdW0dfOhfQ9N+gl2UUDvCPW6mkPKHli9LMbKxWj+wZ5zKPaOoqxuR3Hhy3OTpndkfSw==}
+ '@aws-sdk/signature-v4-multi-region@3.996.30':
+ resolution: {integrity: sha512-HULDLMVzkmTSEv6//7kx2kRevp/VYUpm8hJNNFbmhxDn0fUiGTxVcM9yg31TukvTq8nyOBDUN2gH0o5IRbKjdw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.1048.0':
@@ -433,8 +439,8 @@ packages:
resolution: {integrity: sha512-QqZNB3so7UIDxZtroc85TQaLVxdZRFm0eWM1CSR2N+b06as9TOrilvrlTZuj3guYlxMs6yLOgGxnklJ5qMYtTw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/token-providers@3.1054.0':
- resolution: {integrity: sha512-hG9YKApmZOw+drJ9Nuoaf/OvC8e5W1+3eoLeN5p2uVCZRWsv27teIS0b4kiH6Sfv3WMmamqYJxmE2WMwyp/L/A==}
+ '@aws-sdk/token-providers@3.1056.0':
+ resolution: {integrity: sha512-81duvlltQlsfn5K+o8zILcystBRdbT1G2JJYVCML5NZHBz4CL/zf+sAemCtBh/uh6RQUMyInGeZLQ7/8igZhbA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/types@3.973.9':
@@ -627,8 +633,8 @@ packages:
cpu: [x64]
os: [win32]
- '@cloudflare/workers-types@4.20260527.1':
- resolution: {integrity: sha512-GK+C05N4fGptp1uG+pbjC/7Udonz8EhMEYvYFnVKdLLnEGS9nsmVOFi/RLQr7tq9l/0UEzcWjudzeY2ssuqyIA==}
+ '@cloudflare/workers-types@4.20260529.1':
+ resolution: {integrity: sha512-33n3nsaWELSgn4DLKj1X9dwZc3kVDnO+jF/hLH9fdaXG9mQzKDeUkQaVRWLJXvrPXPa9RaIuSAFO4Zh9YOqOog==}
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
@@ -1335,6 +1341,9 @@ packages:
peerDependencies:
hono: ^4
+ '@hugeicons/core-free-icons@4.2.0':
+ resolution: {integrity: sha512-V1G/Ph9TbmEow+pKnupZRWQjdORR/TGGr3JVRZOWkomdJ/5N6GgLuKPgBDs7G0kZ0//9LL34AGOUzWe3K+umNA==}
+
'@iarna/toml@2.2.5':
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
@@ -1649,6 +1658,9 @@ packages:
'@nodable/entities@2.1.0':
resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==}
+ '@nodable/entities@2.1.1':
+ resolution: {integrity: sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -2323,20 +2335,32 @@ packages:
resolution: {integrity: sha512-3UNRKEyQyAgVgM0LGlerCLm+ChZWZ1GPfde+jBEW6bm6bSBGU1p0EbblaUV3unbhwvidjLA5Zs3sOs7mnZwvAw==}
engines: {node: '>=18.0.0'}
+ '@smithy/core@3.24.5':
+ resolution: {integrity: sha512-Kt8phUg45M15EjhYAbZ+fFikYneijLu9Liugz8ZsYz2i8j0hzGv27LWKpEHYRfvj+LyCOSijpcR/2i8RouV+cA==}
+ engines: {node: '>=18.0.0'}
+
'@smithy/credential-provider-imds@4.3.4':
resolution: {integrity: sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA==}
engines: {node: '>=18.0.0'}
+ '@smithy/credential-provider-imds@4.3.5':
+ resolution: {integrity: sha512-yiF8xHpdkaTfzLVqFzsP6WvNghEK+qZzLYWFD13L2SsFhbXwBGlxdocKF95qjr7s5lE5NRage+EJFK4mAsx88Q==}
+ engines: {node: '>=18.0.0'}
+
'@smithy/fetch-http-handler@5.4.4':
resolution: {integrity: sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ==}
engines: {node: '>=18.0.0'}
+ '@smithy/fetch-http-handler@5.4.5':
+ resolution: {integrity: sha512-SK3VMeH0fibgdTg2QeB+O4p7Yy/2E5HBOHJeC58FshkDdeuX8lOgO7PfjYfLyPLP1ch55j91cQqKBzDS0mRjSQ==}
+ engines: {node: '>=18.0.0'}
+
'@smithy/is-array-buffer@2.2.0':
resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==}
engines: {node: '>=14.0.0'}
- '@smithy/node-config-provider@4.4.4':
- resolution: {integrity: sha512-mD/K1A5WrTZh6I23x1ScYo3K7/+Ujvp/zvLtaZT+xkDeXksWAQ/fKp60SudeUHUHQe/3Q3rgnfedJDqnxSKdpA==}
+ '@smithy/node-config-provider@4.4.5':
+ resolution: {integrity: sha512-c2G9QJ4xVZLwAkAf+WQESSSCkKbtt33ytje1klGvTcBn6cKuqV28E+62wbRPHwuTikkB3LQ7CBnNrayCoJur5A==}
engines: {node: '>=18.0.0'}
'@smithy/node-http-handler@4.7.3':
@@ -2347,10 +2371,18 @@ packages:
resolution: {integrity: sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ==}
engines: {node: '>=18.0.0'}
+ '@smithy/node-http-handler@4.7.5':
+ resolution: {integrity: sha512-3dA9TQ+ybRSZ/m0wnbZhiBy4Dezjgq1Ib/ZZrYTpJDBgpoLLU/SDzZc/g0x0MNAdOJe1wPcM+x2PBRmoOur+Sw==}
+ engines: {node: '>=18.0.0'}
+
'@smithy/signature-v4@5.4.4':
resolution: {integrity: sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==}
engines: {node: '>=18.0.0'}
+ '@smithy/signature-v4@5.4.5':
+ resolution: {integrity: sha512-QBJKWGqIknH0dc9LWpfH1mkdokAx6iXYN3UcQ3eY6uIEyScuoQAhfl94ge7ozUy9WgFUdE8xsvwBjaYBbWmPNA==}
+ engines: {node: '>=18.0.0'}
+
'@smithy/types@4.14.2':
resolution: {integrity: sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==}
engines: {node: '>=18.0.0'}
@@ -2463,33 +2495,33 @@ packages:
peerDependencies:
vite: ^5.2.0 || ^6 || ^7 || ^8
- '@turbo/darwin-64@2.9.15':
- resolution: {integrity: sha512-nnDo9R1Df+s2x6jxlERtbg7xRpuicf8p4J2krcnjeaMBt3q9V41pGXa4t9YM2Y4ozozsVJ+CH405CJUrWIQK4Q==}
+ '@turbo/darwin-64@2.9.16':
+ resolution: {integrity: sha512-jLjApWTSNd7JZ5JaLYfelW1ytnGQOvB7ivl+2RD1xQvJTbi8I9gBjzcga7tDZVPyaxpl10YTfJt3BrYXR18KDw==}
cpu: [x64]
os: [darwin]
- '@turbo/darwin-arm64@2.9.15':
- resolution: {integrity: sha512-fDSx56oqoFuS+yUQw7hqjQTkjrSLdMcplhuLC8HcSkWC6YrpwEmUUYsPYHPxy4ALvLxnmPQuk6XoSD8tdkjP+g==}
+ '@turbo/darwin-arm64@2.9.16':
+ resolution: {integrity: sha512-YPgrn+5HIGzrx0O2a631SV4MBQUe4W/DafMFUuBVgaU32PW9/OTT0ehviF0QSxTXuRJlHvW2eUTemddF5/spmw==}
cpu: [arm64]
os: [darwin]
- '@turbo/linux-64@2.9.15':
- resolution: {integrity: sha512-/bmxn+x/xE+oh0VzEXt/zf2zsORAYZPrL3db5/VrXzYt0Z4wxcvffwJBGlSfla2smfS1BLGBiyWldJlWDXJVXA==}
+ '@turbo/linux-64@2.9.16':
+ resolution: {integrity: sha512-vAEf1H6l26lTpl9FJ/peQo1NUB8RC0sbEJJz5mPcUhHA2bPDup2x3CZPgo/bH8S4cUcBLm4FN3UHd5iUO2RAew==}
cpu: [x64]
os: [linux]
- '@turbo/linux-arm64@2.9.15':
- resolution: {integrity: sha512-cbOaDe1ijz5As+mimOOHgmRMolZZZO7miNBHHp5xdiYMm2Q/Dwu1JVLx/Kw4s7xjocG/oEoHrpHrxpEAIEfNiw==}
+ '@turbo/linux-arm64@2.9.16':
+ resolution: {integrity: sha512-xDBLR2PZg4BrQOchfG6svgpv5FCNJ2TOtT2psLdEJcdKo1BH+pnPs9Xj6pvUjgfkHbuvBOfeE4R6tvxMoQKDHQ==}
cpu: [arm64]
os: [linux]
- '@turbo/windows-64@2.9.15':
- resolution: {integrity: sha512-/Fzm7afui7uK7dFBwrTXKuDhBBTiHk5I+hMVAPMR7cqQyDo2norCNUsN9PdNuYcmzYbhSOxzz498wQYvSAz29w==}
+ '@turbo/windows-64@2.9.16':
+ resolution: {integrity: sha512-NBAJnaUiGdgkSzQwUIdOvkCkcpTSu58G/sBGa0mvBtzfvFOOgrQwepKOOQ8cp6sWM6OcKDNFj2p1dsZA1OWjPg==}
cpu: [x64]
os: [win32]
- '@turbo/windows-arm64@2.9.15':
- resolution: {integrity: sha512-fOHEsLcqVdFXLw2ApWv4gxwfHzkUnpo9rHGml+9+dyHj148m/Bc+556kEvb5+4u6prI1LMd8zEZE2HcO6Jn2VQ==}
+ '@turbo/windows-arm64@2.9.16':
+ resolution: {integrity: sha512-Y7SJppD0Z8wjO3Ec0ZGd9KQ4Yv0BMnA8CIowj5Vp+OEVsosXDG2weK6/t1RRLfJmc2Ozrnd6y4DOgQys+mn3WQ==}
cpu: [arm64]
os: [win32]
@@ -2538,95 +2570,48 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
- '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-bDi6FJ644n3uKdp/ZI7j50ChVyGOsrJrkwihQb6x3yByFQkTINLu3e6ZkY+HveQ2Zw2vy9SGN8E7b3A5iSOO0A==}
- engines: {node: '>=16.20.0'}
- cpu: [arm64]
- os: [darwin]
-
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-3LqSu4DlxkEfeC/Z/29QMCJn5jjkDtXI7LYuxfmjdmAatS6umDKqm8J17fnP/7fyrZUMBTIYRwSDpChGV3G1ew==}
engines: {node: '>=16.20.0'}
cpu: [arm64]
os: [darwin]
- '@typescript/native-preview-darwin-x64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-r6GXrTdalXZu1/b5goMpAe+efZvOfwdE45gl8Tti3fckP9icK3xdiN+VnNi0RL2/c2L86RyN8nGxihaCHGCKbw==}
- engines: {node: '>=16.20.0'}
- cpu: [x64]
- os: [darwin]
-
'@typescript/native-preview-darwin-x64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-H4+sxE9qaBbLF83wMdWE0FsgfK0Pom+/O+/oxqyGzhVkDJlNt3vfpgQZMit48/Gm44AacGfBggJ9Dhbi3aeSFw==}
engines: {node: '>=16.20.0'}
cpu: [x64]
os: [darwin]
- '@typescript/native-preview-linux-arm64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-QJAFyPJgJqJVLbVPHl5xL7FCn3HNPLdpEm8l7KBgiYpltLhU1p/LJ3iN0XpFRAhq9ojWbZebo8t/h8MX35QjTQ==}
- engines: {node: '>=16.20.0'}
- cpu: [arm64]
- os: [linux]
-
'@typescript/native-preview-linux-arm64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-BGUDMjC2Z3TTdZRkGGwhBLelkP5UYgO2rbep8aF4dS3fu7T5lFPPrnfS6EgqJgie+cF5Fsev7xEq8wWyBDM+lg==}
engines: {node: '>=16.20.0'}
cpu: [arm64]
os: [linux]
- '@typescript/native-preview-linux-arm@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-BlfQBatMkZHi3o+atxoUW0czGJNjo9cpO1BoQeB3gxZ7D/cDZHYHmKFSSRx8UxMktwP5k5lPxi0wgA3Ic2mQyQ==}
- engines: {node: '>=16.20.0'}
- cpu: [arm]
- os: [linux]
-
'@typescript/native-preview-linux-arm@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-6I9Cv9ozwfS9zB9vRQDPIYseLX3artEO9jl3yVgLj4ishwlSF4cWAbIsjl5IztPaEgHv8coej/6tX1D0uaBzXg==}
engines: {node: '>=16.20.0'}
cpu: [arm]
os: [linux]
- '@typescript/native-preview-linux-x64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-UFB7ZdK2/vIIi62nfn3JhyGV7qR/qXjKPQaPVXwzCvaPieTZcsNsALjKU0W5WHThyi+5p3U7O3dGE7n6P4q4Yw==}
- engines: {node: '>=16.20.0'}
- cpu: [x64]
- os: [linux]
-
'@typescript/native-preview-linux-x64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-vpazOu+ozlxBo8U57YJMzsOPuxAV8H7fu36KJ8ea8At/D8pdGmOAy5TuB+9OBQV9JDe0OXJMy2kmbhOpmkTAmA==}
engines: {node: '>=16.20.0'}
cpu: [x64]
os: [linux]
- '@typescript/native-preview-win32-arm64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-rp/q9+9H77JQvepC/UpDP8CdeTGSGyhp9BVbmFwqUV2NhMHPldfys3ihY7OQdoVBgWIKQyxEHB+FTr8Z7kre1Q==}
- engines: {node: '>=16.20.0'}
- cpu: [arm64]
- os: [win32]
-
'@typescript/native-preview-win32-arm64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-DBFnFE3V6AITkPO1K1VxXf3yEZKjU2FwtXlNwRqhzDu0rrL2SsJHOSrBDX+OacTxQFzZMxFcpiuhV8jHZALPEg==}
engines: {node: '>=16.20.0'}
cpu: [arm64]
os: [win32]
- '@typescript/native-preview-win32-x64@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-864Pq4qoDcacUJhs2/kQplyfwNO0APUmx1k8qUaJt2P9ZGF0Pu++afJi7OagImHMiEQcmigjmZPuOodOk5YmqQ==}
- engines: {node: '>=16.20.0'}
- cpu: [x64]
- os: [win32]
-
'@typescript/native-preview-win32-x64@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-1tBlErMvQgcMqqYwsx4tytupcjCJcOUXD3vBn1Wb/kAvus1FzWQAFE0fcKBvLfcqLQfTiiEwKKEtbLjGmakqqg==}
engines: {node: '>=16.20.0'}
cpu: [x64]
os: [win32]
- '@typescript/native-preview@7.0.0-dev.20260527.1':
- resolution: {integrity: sha512-j81qKiwCPgMEjtk8uDLP+TDW60l6mugoJ7SNzfHWv1PJ6bUjIAHuag4P1jSLm1IpKuMuB3TTi4f61n7TJi8Jog==}
- engines: {node: '>=16.20.0'}
- hasBin: true
-
'@typescript/native-preview@7.0.0-dev.20260527.2':
resolution: {integrity: sha512-piqkDwikVeizCFqA1lcwI5F4wOAtBdxuliWe77ApBNRyBPPvfCJB+u/HYi9/8t5nd0sWvFs6/qt/AzJ1CCoykQ==}
engines: {node: '>=16.20.0'}
@@ -2823,8 +2808,8 @@ packages:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
- astro@6.3.8:
- resolution: {integrity: sha512-xH2UA8Z17IS+JaqSlSkBor7jO6gd7zXTLdmu06nKpfpDDJFbi/7KZEy3NDmWxmier+6XrCZ9Z4aitO8jhC9oiA==}
+ astro@6.4.2:
+ resolution: {integrity: sha512-8H89CH2dKL5SCU99OCqdU9BGjmPkSJqaPurywj5XMo7eMFGUFD3vsNhdEKnEh4mK4LgGje3/QDTTSIIGst0G0Q==}
engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'}
hasBin: true
@@ -2977,6 +2962,10 @@ packages:
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
engines: {node: '>=20'}
+ commander@15.0.0:
+ resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==}
+ engines: {node: '>=22.12.0'}
+
common-ancestor-path@2.0.0:
resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==}
engines: {node: '>= 18'}
@@ -3249,8 +3238,8 @@ packages:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
- enhanced-resolve@5.22.0:
- resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==}
+ enhanced-resolve@5.22.1:
+ resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==}
engines: {node: '>=10.13.0'}
enquirer@2.4.1:
@@ -3340,8 +3329,8 @@ packages:
eventemitter3@5.0.4:
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
- eventsource-parser@3.0.8:
- resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==}
+ eventsource-parser@3.1.0:
+ resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==}
engines: {node: '>=18.0.0'}
eventsource@3.0.7:
@@ -3579,8 +3568,8 @@ packages:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
- hasown@2.0.3:
- resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
+ hasown@2.0.4:
+ resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
hast-util-from-html@2.0.3:
@@ -3944,6 +3933,10 @@ packages:
resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==}
engines: {node: 20 || >=22}
+ lru-cache@11.5.1:
+ resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==}
+ engines: {node: 20 || >=22}
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -4428,6 +4421,10 @@ packages:
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
+ prettier-plugin-astro@0.14.1:
+ resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==}
+ engines: {node: ^14.15.0 || >=16.0.0}
+
prettier@2.8.8:
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
engines: {node: '>=10.13.0'}
@@ -4632,6 +4629,9 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ s.color@0.0.15:
+ resolution: {integrity: sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==}
+
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
@@ -4641,6 +4641,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ sass-formatter@0.7.9:
+ resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
+
sax@1.6.0:
resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==}
engines: {node: '>=11.0.0'}
@@ -4793,6 +4796,9 @@ packages:
strnum@2.3.0:
resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==}
+ suf-log@2.5.3:
+ resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
+
supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
@@ -4823,12 +4829,12 @@ packages:
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
- tinyclip@0.1.12:
- resolution: {integrity: sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==}
+ tinyclip@0.1.13:
+ resolution: {integrity: sha512-8OqlXQ35euK9+e7L68u8UwcODxkHoIkjbGsgXuARKNyQ5G6xt8nw1YPeMbxMLgCPFkToU+UEK5j05t2t8edKpQ==}
engines: {node: ^16.14.0 || >= 17.3.0}
- tinyexec@1.2.2:
- resolution: {integrity: sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==}
+ tinyexec@1.2.3:
+ resolution: {integrity: sha512-g62dB+w1/OEFnPvmX0yd/HnetYITOL+1nJW7kitOycOeAvmbWC/nu0fwmmQ/kupNojqExzyC/T++pST/jRJ2mQ==}
engines: {node: '>=18'}
tinyglobby@0.2.16:
@@ -4872,8 +4878,8 @@ packages:
engines: {node: '>=18.0.0'}
hasBin: true
- turbo@2.9.15:
- resolution: {integrity: sha512-VpKvD9Z0Hu/xrGUAYX1wnhfpqv835wIwGqeKfulvBPTOcDap0E3nFwyzCAVV85fB1sBcBDEfTP+7FSW7GzwWSQ==}
+ turbo@2.9.16:
+ resolution: {integrity: sha512-NqgRQy6j6dPYcdSdv0q1g9QsZg7SWg87RERM8otw/1AtKU2yTFVClOM7cbwKzOonZr/Ek1blTBucw64L9H0Bwg==}
hasBin: true
type-is@2.1.0:
@@ -5426,9 +5432,9 @@ snapshots:
call-me-maybe: 1.0.2
openapi-types: 12.1.3
- '@astrojs/check@0.9.9(prettier@3.8.3)(typescript@6.0.3)':
+ '@astrojs/check@0.9.9(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@6.0.3)':
dependencies:
- '@astrojs/language-server': 2.16.10(prettier@3.8.3)(typescript@6.0.3)
+ '@astrojs/language-server': 2.16.10(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@6.0.3)
chokidar: 4.0.3
kleur: 4.1.5
typescript: 6.0.3
@@ -5441,11 +5447,18 @@ snapshots:
'@astrojs/compiler@4.0.0': {}
- '@astrojs/internal-helpers@0.9.1':
+ '@astrojs/internal-helpers@0.10.0':
dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ js-yaml: 4.1.1
picomatch: 4.0.4
+ retext-smartypants: 6.2.0
+ shiki: 4.1.0
+ smol-toml: 1.6.1
+ unified: 11.0.5
- '@astrojs/language-server@2.16.10(prettier@3.8.3)(typescript@6.0.3)':
+ '@astrojs/language-server@2.16.10(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@6.0.3)':
dependencies:
'@astrojs/compiler': 2.13.1
'@astrojs/yaml2ts': 0.2.4
@@ -5467,17 +5480,17 @@ snapshots:
vscode-uri: 3.1.0
optionalDependencies:
prettier: 3.8.3
+ prettier-plugin-astro: 0.14.1
transitivePeerDependencies:
- typescript
- '@astrojs/markdown-remark@7.1.2':
+ '@astrojs/markdown-remark@7.2.0':
dependencies:
- '@astrojs/internal-helpers': 0.9.1
+ '@astrojs/internal-helpers': 0.10.0
'@astrojs/prism': 4.0.2
github-slugger: 2.0.0
hast-util-from-html: 2.0.3
hast-util-to-text: 4.0.2
- js-yaml: 4.1.1
mdast-util-definitions: 6.0.0
rehype-raw: 7.0.0
rehype-stringify: 10.0.1
@@ -5485,9 +5498,6 @@ snapshots:
remark-parse: 11.0.0
remark-rehype: 11.1.2
remark-smartypants: 3.0.2
- retext-smartypants: 6.2.0
- shiki: 4.1.0
- smol-toml: 1.6.1
unified: 11.0.5
unist-util-remove-position: 5.0.0
unist-util-visit: 5.1.0
@@ -5561,16 +5571,16 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/client-cognito-identity@3.1054.0':
+ '@aws-sdk/client-cognito-identity@3.1056.0':
dependencies:
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/credential-provider-node': 3.972.45
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/credential-provider-node': 3.972.46
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/fetch-http-handler': 5.4.4
- '@smithy/node-http-handler': 4.7.4
+ '@smithy/core': 3.24.5
+ '@smithy/fetch-http-handler': 5.4.5
+ '@smithy/node-http-handler': 4.7.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5585,22 +5595,22 @@ snapshots:
bowser: 2.14.1
tslib: 2.8.1
- '@aws-sdk/core@3.974.14':
+ '@aws-sdk/core@3.974.15':
dependencies:
'@aws-sdk/types': 3.973.9
'@aws-sdk/xml-builder': 3.972.26
'@aws/lambda-invoke-store': 0.2.4
- '@smithy/core': 3.24.4
- '@smithy/signature-v4': 5.4.4
+ '@smithy/core': 3.24.5
+ '@smithy/signature-v4': 5.4.5
'@smithy/types': 4.14.2
bowser: 2.14.1
tslib: 2.8.1
- '@aws-sdk/credential-provider-cognito-identity@3.972.37':
+ '@aws-sdk/credential-provider-cognito-identity@3.972.38':
dependencies:
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5612,11 +5622,11 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-env@3.972.40':
+ '@aws-sdk/credential-provider-env@3.972.41':
dependencies:
- '@aws-sdk/core': 3.974.14
+ '@aws-sdk/core': 3.974.15
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5630,13 +5640,13 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-http@3.972.42':
+ '@aws-sdk/credential-provider-http@3.972.43':
dependencies:
- '@aws-sdk/core': 3.974.14
+ '@aws-sdk/core': 3.974.15
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/fetch-http-handler': 5.4.4
- '@smithy/node-http-handler': 4.7.4
+ '@smithy/core': 3.24.5
+ '@smithy/fetch-http-handler': 5.4.5
+ '@smithy/node-http-handler': 4.7.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5656,19 +5666,19 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-ini@3.972.44':
+ '@aws-sdk/credential-provider-ini@3.972.45':
dependencies:
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/credential-provider-env': 3.972.40
- '@aws-sdk/credential-provider-http': 3.972.42
- '@aws-sdk/credential-provider-login': 3.972.44
- '@aws-sdk/credential-provider-process': 3.972.40
- '@aws-sdk/credential-provider-sso': 3.972.44
- '@aws-sdk/credential-provider-web-identity': 3.972.44
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/credential-provider-env': 3.972.41
+ '@aws-sdk/credential-provider-http': 3.972.43
+ '@aws-sdk/credential-provider-login': 3.972.45
+ '@aws-sdk/credential-provider-process': 3.972.41
+ '@aws-sdk/credential-provider-sso': 3.972.45
+ '@aws-sdk/credential-provider-web-identity': 3.972.45
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/credential-provider-imds': 4.3.4
+ '@smithy/core': 3.24.5
+ '@smithy/credential-provider-imds': 4.3.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5681,12 +5691,12 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-login@3.972.44':
+ '@aws-sdk/credential-provider-login@3.972.45':
dependencies:
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5704,17 +5714,17 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-node@3.972.45':
+ '@aws-sdk/credential-provider-node@3.972.46':
dependencies:
- '@aws-sdk/credential-provider-env': 3.972.40
- '@aws-sdk/credential-provider-http': 3.972.42
- '@aws-sdk/credential-provider-ini': 3.972.44
- '@aws-sdk/credential-provider-process': 3.972.40
- '@aws-sdk/credential-provider-sso': 3.972.44
- '@aws-sdk/credential-provider-web-identity': 3.972.44
+ '@aws-sdk/credential-provider-env': 3.972.41
+ '@aws-sdk/credential-provider-http': 3.972.43
+ '@aws-sdk/credential-provider-ini': 3.972.45
+ '@aws-sdk/credential-provider-process': 3.972.41
+ '@aws-sdk/credential-provider-sso': 3.972.45
+ '@aws-sdk/credential-provider-web-identity': 3.972.45
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/credential-provider-imds': 4.3.4
+ '@smithy/core': 3.24.5
+ '@smithy/credential-provider-imds': 4.3.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5726,11 +5736,11 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-process@3.972.40':
+ '@aws-sdk/credential-provider-process@3.972.41':
dependencies:
- '@aws-sdk/core': 3.974.14
+ '@aws-sdk/core': 3.974.15
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5744,13 +5754,13 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-sso@3.972.44':
+ '@aws-sdk/credential-provider-sso@3.972.45':
dependencies:
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/nested-clients': 3.997.12
- '@aws-sdk/token-providers': 3.1054.0
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/nested-clients': 3.997.13
+ '@aws-sdk/token-providers': 3.1056.0
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5763,32 +5773,32 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-provider-web-identity@3.972.44':
+ '@aws-sdk/credential-provider-web-identity@3.972.45':
dependencies:
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/credential-providers@3.1054.0':
- dependencies:
- '@aws-sdk/client-cognito-identity': 3.1054.0
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/credential-provider-cognito-identity': 3.972.37
- '@aws-sdk/credential-provider-env': 3.972.40
- '@aws-sdk/credential-provider-http': 3.972.42
- '@aws-sdk/credential-provider-ini': 3.972.44
- '@aws-sdk/credential-provider-login': 3.972.44
- '@aws-sdk/credential-provider-node': 3.972.45
- '@aws-sdk/credential-provider-process': 3.972.40
- '@aws-sdk/credential-provider-sso': 3.972.44
- '@aws-sdk/credential-provider-web-identity': 3.972.44
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/credential-providers@3.1056.0':
+ dependencies:
+ '@aws-sdk/client-cognito-identity': 3.1056.0
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/credential-provider-cognito-identity': 3.972.38
+ '@aws-sdk/credential-provider-env': 3.972.41
+ '@aws-sdk/credential-provider-http': 3.972.43
+ '@aws-sdk/credential-provider-ini': 3.972.45
+ '@aws-sdk/credential-provider-login': 3.972.45
+ '@aws-sdk/credential-provider-node': 3.972.46
+ '@aws-sdk/credential-provider-process': 3.972.41
+ '@aws-sdk/credential-provider-sso': 3.972.45
+ '@aws-sdk/credential-provider-web-identity': 3.972.45
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/credential-provider-imds': 4.3.4
+ '@smithy/core': 3.24.5
+ '@smithy/credential-provider-imds': 4.3.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5829,16 +5839,16 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/nested-clients@3.997.12':
+ '@aws-sdk/nested-clients@3.997.13':
dependencies:
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/signature-v4-multi-region': 3.996.29
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/signature-v4-multi-region': 3.996.30
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
- '@smithy/fetch-http-handler': 5.4.4
- '@smithy/node-http-handler': 4.7.4
+ '@smithy/core': 3.24.5
+ '@smithy/fetch-http-handler': 5.4.5
+ '@smithy/node-http-handler': 4.7.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5850,10 +5860,10 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/signature-v4-multi-region@3.996.29':
+ '@aws-sdk/signature-v4-multi-region@3.996.30':
dependencies:
'@aws-sdk/types': 3.973.9
- '@smithy/signature-v4': 5.4.4
+ '@smithy/signature-v4': 5.4.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -5875,12 +5885,12 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
- '@aws-sdk/token-providers@3.1054.0':
+ '@aws-sdk/token-providers@3.1056.0':
dependencies:
- '@aws-sdk/core': 3.974.14
- '@aws-sdk/nested-clients': 3.997.12
+ '@aws-sdk/core': 3.974.15
+ '@aws-sdk/nested-clients': 3.997.13
'@aws-sdk/types': 3.973.9
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
'@smithy/types': 4.14.2
tslib: 2.8.1
@@ -6126,7 +6136,7 @@ snapshots:
'@cloudflare/workerd-windows-64@1.20260526.1':
optional: true
- '@cloudflare/workers-types@4.20260527.1': {}
+ '@cloudflare/workers-types@4.20260529.1': {}
'@cspotcode/source-map-support@0.8.1':
dependencies:
@@ -6580,6 +6590,8 @@ snapshots:
dependencies:
hono: 4.12.23
+ '@hugeicons/core-free-icons@4.2.0': {}
+
'@iarna/toml@2.2.5': {}
'@img/colour@1.1.0': {}
@@ -6796,7 +6808,7 @@ snapshots:
cors: 2.8.6
cross-spawn: 7.0.6
eventsource: 3.0.7
- eventsource-parser: 3.0.8
+ eventsource-parser: 3.1.0
express: 5.2.1
express-rate-limit: 8.5.2(express@5.2.1)
hono: 4.12.23
@@ -6836,6 +6848,8 @@ snapshots:
'@nodable/entities@2.1.0': {}
+ '@nodable/entities@2.1.1': {}
+
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -7269,25 +7283,43 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
+ '@smithy/core@3.24.5':
+ dependencies:
+ '@aws-crypto/crc32': 5.2.0
+ '@smithy/types': 4.14.2
+ tslib: 2.8.1
+
'@smithy/credential-provider-imds@4.3.4':
dependencies:
'@smithy/core': 3.24.4
'@smithy/types': 4.14.2
tslib: 2.8.1
+ '@smithy/credential-provider-imds@4.3.5':
+ dependencies:
+ '@smithy/core': 3.24.5
+ '@smithy/types': 4.14.2
+ tslib: 2.8.1
+
'@smithy/fetch-http-handler@5.4.4':
dependencies:
'@smithy/core': 3.24.4
'@smithy/types': 4.14.2
tslib: 2.8.1
+ '@smithy/fetch-http-handler@5.4.5':
+ dependencies:
+ '@smithy/core': 3.24.5
+ '@smithy/types': 4.14.2
+ tslib: 2.8.1
+
'@smithy/is-array-buffer@2.2.0':
dependencies:
tslib: 2.8.1
- '@smithy/node-config-provider@4.4.4':
+ '@smithy/node-config-provider@4.4.5':
dependencies:
- '@smithy/core': 3.24.4
+ '@smithy/core': 3.24.5
tslib: 2.8.1
'@smithy/node-http-handler@4.7.3':
@@ -7302,12 +7334,24 @@ snapshots:
'@smithy/types': 4.14.2
tslib: 2.8.1
+ '@smithy/node-http-handler@4.7.5':
+ dependencies:
+ '@smithy/core': 3.24.5
+ '@smithy/types': 4.14.2
+ tslib: 2.8.1
+
'@smithy/signature-v4@5.4.4':
dependencies:
'@smithy/core': 3.24.4
'@smithy/types': 4.14.2
tslib: 2.8.1
+ '@smithy/signature-v4@5.4.5':
+ dependencies:
+ '@smithy/core': 3.24.5
+ '@smithy/types': 4.14.2
+ tslib: 2.8.1
+
'@smithy/types@4.14.2':
dependencies:
tslib: 2.8.1
@@ -7329,7 +7373,7 @@ snapshots:
'@tailwindcss/node@4.3.0':
dependencies:
'@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.22.0
+ enhanced-resolve: 5.22.1
jiti: 2.7.0
lightningcss: 1.32.0
magic-string: 0.30.21
@@ -7394,22 +7438,22 @@ snapshots:
tailwindcss: 4.3.0
vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)(yaml@2.9.0)
- '@turbo/darwin-64@2.9.15':
+ '@turbo/darwin-64@2.9.16':
optional: true
- '@turbo/darwin-arm64@2.9.15':
+ '@turbo/darwin-arm64@2.9.16':
optional: true
- '@turbo/linux-64@2.9.15':
+ '@turbo/linux-64@2.9.16':
optional: true
- '@turbo/linux-arm64@2.9.15':
+ '@turbo/linux-arm64@2.9.16':
optional: true
- '@turbo/windows-64@2.9.15':
+ '@turbo/windows-64@2.9.16':
optional: true
- '@turbo/windows-arm64@2.9.15':
+ '@turbo/windows-arm64@2.9.16':
optional: true
'@tybys/wasm-util@0.10.2':
@@ -7458,58 +7502,27 @@ snapshots:
'@types/unist@3.0.3': {}
- '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-darwin-x64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-darwin-x64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-linux-arm64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-linux-arm64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-linux-arm@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-linux-arm@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-linux-x64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-linux-x64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-win32-arm64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-win32-arm64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview-win32-x64@7.0.0-dev.20260527.1':
- optional: true
-
'@typescript/native-preview-win32-x64@7.0.0-dev.20260527.2':
optional: true
- '@typescript/native-preview@7.0.0-dev.20260527.1':
- optionalDependencies:
- '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260527.1
- '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260527.1
- '@typescript/native-preview-linux-arm': 7.0.0-dev.20260527.1
- '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260527.1
- '@typescript/native-preview-linux-x64': 7.0.0-dev.20260527.1
- '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260527.1
- '@typescript/native-preview-win32-x64': 7.0.0-dev.20260527.1
-
'@typescript/native-preview@7.0.0-dev.20260527.2':
optionalDependencies:
'@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260527.2
@@ -7637,15 +7650,15 @@ snapshots:
alchemy@0.93.9(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)(yaml@2.9.0))(workerd@1.20260526.1):
dependencies:
- '@aws-sdk/credential-providers': 3.1054.0
+ '@aws-sdk/credential-providers': 3.1056.0
'@cloudflare/unenv-preset': 2.7.7(unenv@2.0.0-rc.21)(workerd@1.20260526.1)
- '@cloudflare/workers-types': 4.20260527.1
+ '@cloudflare/workers-types': 4.20260529.1
'@iarna/toml': 2.2.5
'@octokit/rest': 21.1.1
- '@smithy/node-config-provider': 4.4.4
+ '@smithy/node-config-provider': 4.4.5
'@smithy/types': 4.14.2
aws4fetch: 1.0.20
- drizzle-orm: 0.45.2(@cloudflare/workers-types@4.20260527.1)
+ drizzle-orm: 0.45.2(@cloudflare/workers-types@4.20260529.1)
env-paths: 3.0.0
esbuild: 0.25.12
execa: 9.6.1
@@ -7664,7 +7677,7 @@ snapshots:
proper-lockfile: 4.1.2
signal-exit: 4.1.0
unenv: 2.0.0-rc.21
- wrangler: 4.95.0(@cloudflare/workers-types@4.20260527.1)
+ wrangler: 4.95.0(@cloudflare/workers-types@4.20260529.1)
ws: 8.21.0
yaml: 2.9.0
optionalDependencies:
@@ -7736,11 +7749,11 @@ snapshots:
assertion-error@2.0.1: {}
- astro@6.3.8(@types/node@25.9.1)(aws4fetch@1.0.20)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(tsx@4.22.3)(yaml@2.9.0):
+ astro@6.4.2(@types/node@25.9.1)(aws4fetch@1.0.20)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.4)(tsx@4.22.3)(yaml@2.9.0):
dependencies:
'@astrojs/compiler': 4.0.0
- '@astrojs/internal-helpers': 0.9.1
- '@astrojs/markdown-remark': 7.1.2
+ '@astrojs/internal-helpers': 0.10.0
+ '@astrojs/markdown-remark': 7.2.0
'@astrojs/telemetry': 3.3.2
'@capsizecss/unpack': 4.0.0
'@clack/prompts': 1.4.0
@@ -7780,8 +7793,8 @@ snapshots:
shiki: 4.1.0
smol-toml: 1.6.1
svgo: 4.0.1
- tinyclip: 0.1.12
- tinyexec: 1.2.2
+ tinyclip: 0.1.13
+ tinyexec: 1.2.3
tinyglobby: 0.2.16
ultrahtml: 1.6.0
unifont: 0.7.4
@@ -7959,6 +7972,8 @@ snapshots:
commander@14.0.3: {}
+ commander@15.0.0: {}
+
common-ancestor-path@2.0.0: {}
content-disposition@1.1.0: {}
@@ -8079,9 +8094,9 @@ snapshots:
domelementtype: 2.3.0
domhandler: 5.0.3
- drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260527.1):
+ drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260529.1):
optionalDependencies:
- '@cloudflare/workers-types': 4.20260527.1
+ '@cloudflare/workers-types': 4.20260529.1
dset@3.1.4: {}
@@ -8125,7 +8140,7 @@ snapshots:
encodeurl@2.0.0: {}
- enhanced-resolve@5.22.0:
+ enhanced-resolve@5.22.1:
dependencies:
graceful-fs: 4.2.11
tapable: 2.3.3
@@ -8289,11 +8304,11 @@ snapshots:
eventemitter3@5.0.4: {}
- eventsource-parser@3.0.8: {}
+ eventsource-parser@3.1.0: {}
eventsource@3.0.7:
dependencies:
- eventsource-parser: 3.0.8
+ eventsource-parser: 3.1.0
execa@9.6.1:
dependencies:
@@ -8393,14 +8408,14 @@ snapshots:
fast-xml-parser@5.7.3:
dependencies:
- '@nodable/entities': 2.1.0
+ '@nodable/entities': 2.1.1
fast-xml-builder: 1.2.0
path-expression-matcher: 1.5.0
strnum: 2.3.0
fast-xml-parser@5.8.0:
dependencies:
- '@nodable/entities': 2.1.0
+ '@nodable/entities': 2.1.1
fast-xml-builder: 1.2.0
path-expression-matcher: 1.5.0
strnum: 2.3.0
@@ -8521,7 +8536,7 @@ snapshots:
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
- hasown: 2.0.3
+ hasown: 2.0.4
math-intrinsics: 1.1.0
get-proto@1.0.1:
@@ -8603,7 +8618,7 @@ snapshots:
has-symbols@1.1.0: {}
- hasown@2.0.3:
+ hasown@2.0.4:
dependencies:
function-bind: 1.1.2
@@ -8932,7 +8947,7 @@ snapshots:
listr2: 10.2.1
picomatch: 4.0.4
string-argv: 0.3.2
- tinyexec: 1.2.2
+ tinyexec: 1.2.3
optionalDependencies:
yaml: 2.9.0
@@ -8968,6 +8983,8 @@ snapshots:
lru-cache@11.5.0: {}
+ lru-cache@11.5.1: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -9623,6 +9640,12 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
+ prettier-plugin-astro@0.14.1:
+ dependencies:
+ '@astrojs/compiler': 2.13.1
+ prettier: 3.8.3
+ sass-formatter: 0.7.9
+
prettier@2.8.8: {}
prettier@3.8.3: {}
@@ -9914,12 +9937,18 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
+ s.color@0.0.15: {}
+
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
safer-buffer@2.1.2: {}
+ sass-formatter@0.7.9:
+ dependencies:
+ suf-log: 2.5.3
+
sax@1.6.0: {}
semver@7.8.1: {}
@@ -10116,6 +10145,10 @@ snapshots:
strnum@2.3.0: {}
+ suf-log@2.5.3:
+ dependencies:
+ s.color: 0.0.15
+
supports-color@10.2.2: {}
supports-color@7.2.0:
@@ -10142,9 +10175,9 @@ snapshots:
tinybench@2.9.0: {}
- tinyclip@0.1.12: {}
+ tinyclip@0.1.13: {}
- tinyexec@1.2.2: {}
+ tinyexec@1.2.3: {}
tinyglobby@0.2.16:
dependencies:
@@ -10177,14 +10210,14 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
- turbo@2.9.15:
+ turbo@2.9.16:
optionalDependencies:
- '@turbo/darwin-64': 2.9.15
- '@turbo/darwin-arm64': 2.9.15
- '@turbo/linux-64': 2.9.15
- '@turbo/linux-arm64': 2.9.15
- '@turbo/windows-64': 2.9.15
- '@turbo/windows-arm64': 2.9.15
+ '@turbo/darwin-64': 2.9.16
+ '@turbo/darwin-arm64': 2.9.16
+ '@turbo/linux-64': 2.9.16
+ '@turbo/linux-arm64': 2.9.16
+ '@turbo/windows-64': 2.9.16
+ '@turbo/windows-arm64': 2.9.16
type-is@2.1.0:
dependencies:
@@ -10298,7 +10331,7 @@ snapshots:
chokidar: 5.0.0
destr: 2.0.5
h3: 1.15.11
- lru-cache: 11.5.0
+ lru-cache: 11.5.1
node-fetch-native: 1.6.7
ofetch: 1.5.1
ufo: 1.6.4
@@ -10368,7 +10401,7 @@ snapshots:
picomatch: 4.0.4
std-env: 4.1.0
tinybench: 2.9.0
- tinyexec: 1.2.2
+ tinyexec: 1.2.3
tinyglobby: 0.2.16
tinyrainbow: 3.1.0
vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.3)(yaml@2.9.0)
@@ -10506,7 +10539,7 @@ snapshots:
'@cloudflare/workerd-linux-arm64': 1.20260526.1
'@cloudflare/workerd-windows-64': 1.20260526.1
- wrangler@4.95.0(@cloudflare/workers-types@4.20260527.1):
+ wrangler@4.95.0(@cloudflare/workers-types@4.20260529.1):
dependencies:
'@cloudflare/kv-asset-handler': 0.5.0
'@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260526.1)
@@ -10518,7 +10551,7 @@ snapshots:
unenv: 2.0.0-rc.24
workerd: 1.20260526.1
optionalDependencies:
- '@cloudflare/workers-types': 4.20260527.1
+ '@cloudflare/workers-types': 4.20260529.1
fsevents: 2.3.3
transitivePeerDependencies:
- bufferutil
diff --git a/scripts/commit-byterover-context.test.ts b/scripts/commit-byterover-context.test.ts
index a707533..40ae6fd 100644
--- a/scripts/commit-byterover-context.test.ts
+++ b/scripts/commit-byterover-context.test.ts
@@ -22,5 +22,10 @@ test("ByteRover check warning is advisory and includes manual commit command", (
});
test("ByteRover context commits use a conventional docs commit message", () => {
- expect(buildCommitArgs()).toEqual(["commit", "-m", "docs(agents): byterover context"]);
+ expect(buildCommitArgs()).toEqual([
+ "commit",
+ "--no-verify",
+ "-m",
+ "docs(agents): byterover context",
+ ]);
});
diff --git a/scripts/commit-byterover-context.ts b/scripts/commit-byterover-context.ts
index 25fa2f9..d6b4e7c 100644
--- a/scripts/commit-byterover-context.ts
+++ b/scripts/commit-byterover-context.ts
@@ -13,7 +13,7 @@ export function checkByteRoverStatus(porcelainOutput: string): ByteRoverStatus {
}
export function buildCommitArgs(): string[] {
- return ["commit", "-m", commitMessage];
+ return ["commit", "--no-verify", "-m", commitMessage];
}
export function formatCheckWarning(): string {