From b37a94c86c14b80ec60a6660f7d177dc1a84a674 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:05:22 -0400 Subject: [PATCH 01/13] docs: align readme with landing page --- README.md | 96 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 454dbe2..f0bb503 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@

Caplets

- Capability cards for coding agents.
- Wrap sprawling tool stacks behind focused, progressive-disclosure interfaces. + Skillify your backends.
+ Turn MCP servers, APIs, and commands into focused agent capabilities.

@@ -15,6 +15,10 @@ Node 22+

+

+ caplets.dev +

+

MCP · OpenAPI · GraphQL · HTTP · CLI

@@ -22,38 +26,21 @@ --- -Caplets turns sprawling tool setups into focused capability cards for coding agents. -Connect MCP servers, OpenAPI specs, GraphQL endpoints, HTTP actions, and curated CLI -commands without flooding the model with every downstream operation up front. +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. -Instead of exposing a flat wall of tools, Caplets shows one top-level tool per capability. -The agent chooses a domain first, then uses scoped operations like `search_tools`, -`get_tool`, and `call_tool` only when it needs more detail. +To skillify a backend is to wrap it 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. -For MCP-backed Caplets, the scoped operation set also includes resource discovery/reading, -prompt listing/rendering, resource-template discovery, and completion for prompt or template -arguments. Non-MCP backends continue to expose only tool/action operations. +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. ## Quick Start Caplets requires Node.js 22 or newer. ```sh -pnpm add -g caplets +npm install -g caplets caplets init -``` - -Add a capability from an existing system: - -```sh -# Wrap an MCP server caplets add mcp docs --command npx --arg -y --arg @upstash/context7-mcp - -# Convert useful repository commands into curated tools -caplets add cli repo-tools --repo . --include git,gh,package - -# Install ready-made Caplets from a repository -caplets install spiritledsoftware/caplets github linear context7 +caplets serve ``` Connect Caplets to any MCP client: @@ -69,10 +56,19 @@ Connect Caplets to any MCP client: } ``` -Ask your agent to use Caplets. It will see a compact capability list first, then inspect -only the backend it needs. +Ask your agent to use Caplets. It will see a compact capability list first, then inspect only the backend it needs. + +You can also add capabilities from existing systems: + +```sh +# Convert useful repository commands into curated tools +caplets add cli repo-tools --repo . --include git,gh,package + +# Install ready-made Caplets from a repository +caplets install spiritledsoftware/caplets github linear context7 +``` -You can also invoke configured Caplets directly from the CLI for agent-friendly scripts and smoke tests: +Configured Caplets can be invoked directly from the CLI for agent-friendly scripts and smoke tests: ```sh caplets get-caplet context7 @@ -244,12 +240,16 @@ version, and customize them with the project. ## Why It Matters -Large MCP setups can make agents harder to steer. If every downstream server exposes -every tool up front, the model starts with a noisy flat list, duplicate tool names, and -a larger context surface before it knows which capability matters. +Flat tool lists make agents guess before they understand. If every downstream server exposes every operation up front, the model starts with a noisy list, duplicate tool names, and a larger context surface before it knows which capability matters. + +Caplets turns that flat wall into a staged path: -Caplets turns that flat tool wall into progressive disclosure: one capability card first, -then scoped discovery only after the agent chooses the relevant domain. +1. **Choose** a capability, such as `github`. +2. **Inspect** matching operations with `search_tools` or `list_tools`. +3. **Resolve** the exact schema with `get_tool`. +4. **Invoke** with `call_tool` while preserving downstream content, structured data, and error state. + +A backend enters agent context as a focused card with source, status, and next actions, not a wall of operations. ## Benchmark @@ -290,18 +290,30 @@ CAPLETS_BENCH_LIVE=1 pnpm benchmark:live:opencode -- --model openai/gpt-5.5-fast ## Design Model -Caplets combines two ideas that work well separately but leave a gap together: agent -skills and MCP servers. +Caplets combines two ideas that work well separately but leave a gap together: agent skills and MCP servers. + +Agent skills are great at progressive disclosure. They show an agent a compact capability card first, then let it read deeper instructions only when that skill is relevant. MCP servers are great at live tool execution, but most clients expose their tools as one flat list up front. That means a powerful MCP setup can flood the agent with every tool from every server before it knows which capability area matters. + +Caplets borrows the skill-shaped discovery model and applies it to MCP, OpenAPI, GraphQL, HTTP, and CLI backends. Each backend becomes a skill-like capability card first; its actual operations stay hidden until the agent chooses that capability and asks to search, list, inspect, or call them. + +A capability is safe for agents when it reveals itself in stages: + +- **Discoverable as one capability:** source, status, auth posture, and next actions are visible before any downstream tool list enters context. +- **Inspectable before invocation:** agents search inside the selected capability, then inspect exact tool schemas before any call is made. +- **Lossless after the call:** Caplets preserves structured content, resource links, images, and downstream error state instead of flattening results away. + +## Trust Before Invocation + +Caplets keeps trust mechanics visible before an agent calls a backend. -Agent skills are great at progressive disclosure. They show an agent a compact capability -card first, then let it read deeper instructions only when that skill is relevant. MCP -servers are great at live tool execution, but most clients expose their tools as one flat -list up front. That means a powerful MCP setup can flood the agent with every tool from -every server before it knows which capability area matters. +| Mechanic | Example | Why it matters | +| -------- | ---------------------------------- | ------------------------------------------------------------------------------- | +| Source | `.caplets/config.json` | Users can see where the capability came from before trusting it. | +| Auth | `GITHUB_TOKEN: redacted` | Secrets stay hidden while auth state remains inspectable. | +| Timeout | `30s boundary` | Slow or stuck backends fail visibly instead of disappearing into agent context. | +| Error | `safe message + raw detail scoped` | Recovery information stays useful without leaking sensitive configuration. | -Caplets borrows the skill-shaped discovery model and applies it to MCP. Each downstream -server becomes a skill-like capability card first; its actual MCP tools stay hidden until -the agent chooses that server and asks to search, list, inspect, or call them. +If a backend fails, Caplets keeps the error scoped to the capability, preserves useful recovery detail, and redacts sensitive configuration before it reaches the agent. ## Capabilities From f3634495ff35ecd92dbb82e90cfa016ac9f315cf Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:18:49 -0400 Subject: [PATCH 02/13] docs: address readme review feedback --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f0bb503..61a61ef 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Caplets requires Node.js 22 or newer. ```sh npm install -g caplets caplets init -caplets add mcp docs --command npx --arg -y --arg @upstash/context7-mcp caplets serve ``` @@ -58,9 +57,12 @@ Connect Caplets to any MCP client: Ask your agent to use Caplets. It will see a compact capability list first, then inspect only the backend it needs. -You can also add capabilities from existing systems: +Add capabilities from existing systems when you are ready to skillify a backend: ```sh +# Wrap an MCP server +caplets add mcp docs --command npx --arg -y --arg @upstash/context7-mcp + # Convert useful repository commands into curated tools caplets add cli repo-tools --repo . --include git,gh,package @@ -244,7 +246,7 @@ Flat tool lists make agents guess before they understand. If every downstream se Caplets turns that flat wall into a staged path: -1. **Choose** a capability, such as `github`. +1. **Choose** a capability, such as `GitHub`. 2. **Inspect** matching operations with `search_tools` or `list_tools`. 3. **Resolve** the exact schema with `get_tool`. 4. **Invoke** with `call_tool` while preserving downstream content, structured data, and error state. From 135bb8c986e86438815be3d2b9d9056a259561be Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:37:28 -0400 Subject: [PATCH 03/13] docs: refine capability tagline --- README.md | 6 +++--- apps/landing/src/pages/index.astro | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 61a61ef..f4455f2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

Caplets

- Skillify your backends.
+ Give agents capabilities, not tool walls.
Turn MCP servers, APIs, and commands into focused agent capabilities.

@@ -28,7 +28,7 @@ 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. -To skillify a backend is to wrap it 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. +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. 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. @@ -57,7 +57,7 @@ Connect Caplets to any MCP client: Ask your agent to use Caplets. It will see a compact capability list first, then inspect only the backend it needs. -Add capabilities from existing systems when you are ready to skillify a backend: +Add capabilities from existing systems when you are ready to give agents a focused tool surface: ```sh # Wrap an MCP server diff --git a/apps/landing/src/pages/index.astro b/apps/landing/src/pages/index.astro index fa30677..099192d 100644 --- a/apps/landing/src/pages/index.astro +++ b/apps/landing/src/pages/index.astro @@ -183,14 +183,14 @@ const installSteps = [

Capability cards for coding agents

-

Skillify your backends.

+

Give agents capabilities, not tool walls.

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.

- To skillify a backend is to wrap it as a capability an agent can discover, inspect, call, - and recover from one step at a time. + Caplets wraps each tool source as a capability an agent can discover, inspect, call, and + recover from one step at a time.

Install Caplets @@ -265,7 +265,7 @@ const installSteps = [
-

What skillify means

+

What capability-shaped means

A backend becomes safe for agents when it reveals itself in stages.

From d47c356f4db91b7b1474ece6d4d4a0c9f93b37ea Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:42:30 -0400 Subject: [PATCH 04/13] docs: clarify landing page copy --- apps/landing/src/pages/index.astro | 58 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/apps/landing/src/pages/index.astro b/apps/landing/src/pages/index.astro index 099192d..b5f8c7f 100644 --- a/apps/landing/src/pages/index.astro +++ b/apps/landing/src/pages/index.astro @@ -9,7 +9,7 @@ const heroTrace = { steps: [ { label: "get_caplet", - detail: "Expose one card before any downstream tool list enters context.", + detail: "Show one capability card before any downstream tool list enters context.", result: "search_tools · get_tool · call_tool", }, { @@ -19,29 +19,29 @@ const heroTrace = { }, { label: 'get_tool("create_pull_request")', - detail: "Inspect the preserved schema before an agent can invoke the operation.", + detail: "Inspect the exact schema before an agent can invoke the operation.", result: "title · body · base · head · reviewers?", }, { label: "call_tool(arguments)", - detail: "Forward the call and keep downstream content, structured data, and errors intact.", + detail: "Forward the call and keep content, structured data, and errors intact.", result: "structuredContent + content", }, ], }; -const skillifyFramework = [ +const capabilityFramework = [ { - title: "Discoverable as one capability", - copy: "A backend enters the agent context as a focused card with source, status, and next actions, not a flat wall of operations.", + 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.", }, { - title: "Inspectable before invocation", - copy: "Agents search inside the selected capability, then inspect exact tool schemas before any call is made.", + title: "Schemas before calls", + copy: "Agents search inside one capability, then inspect the exact tool schema before they invoke anything.", }, { - title: "Lossless after the call", - copy: "Caplets preserves structured content, resource links, images, and downstream error state instead of flattening results away.", + title: "Results stay intact", + copy: "Caplets preserves structured content, resource links, images, and downstream errors instead of flattening results away.", }, ]; @@ -59,7 +59,7 @@ const trustMechanics = [ { label: "Timeout", value: "30s boundary", - copy: "Slow or stuck backends fail visibly instead of disappearing into agent context.", + copy: "Slow or stuck tools fail visibly instead of disappearing into agent context." }, { label: "Error", @@ -68,7 +68,7 @@ const trustMechanics = [ }, ]; -const backends = ["MCP", "OpenAPI", "GraphQL", "HTTP", "CLI"]; +const sources = ["MCP", "OpenAPI", "GraphQL", "HTTP", "CLI"]; const agentSetups = [ { id: "claude-code", @@ -189,8 +189,8 @@ const installSteps = [ 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. + 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.

Install Caplets @@ -198,8 +198,8 @@ const installSteps = [
-
Backends
-
{backends.join(" · ")}
+
Sources
+
{sources.join(" · ")}
Clients
@@ -239,20 +239,20 @@ const installSteps = [
-

The wall of tools problem

-

Flat tool lists make agents guess before they understand.

+

The tool wall problem

+

Flat tool lists force agents to choose before they understand.

Before

-

Every downstream operation arrives at once.

+

Every operation enters context before the agent knows which one matters.

After

-

Agents inspect a capability path one step at a time.

+

Agents choose a capability, then inspect only the operations inside it.

  1. Choosegithub
  2. Inspectsearch_tools
  3. @@ -265,11 +265,11 @@ const installSteps = [
    -

    What capability-shaped means

    -

    A backend becomes safe for agents when it reveals itself in stages.

    +

    Capability-shaped tools

    +

    A tool source is safer for agents when it reveals itself in stages.

    - {skillifyFramework.map((point, index) => ( + {capabilityFramework.map((point, index) => (

    0{index + 1}

    {point.title}

    @@ -296,7 +296,7 @@ const installSteps = [
    Safe recovery example

    - If a backend fails, Caplets keeps the error scoped to the capability, preserves useful + 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.

    @@ -304,8 +304,8 @@ const installSteps = [
    -

    Native where it helps

    -

    Use Caplets from the agent you already run.

    +

    Works where agents work

    +

    Run Caplets from the coding agent you already use.

    @@ -368,8 +368,8 @@ const installSteps = [
    -

    Start with one capability

    -

    Install, add a backend, serve capabilities.

    +

    Start with one tool source

    +

    Install Caplets, add a source, serve capabilities.

    Caplets can run as a universal MCP server, a native Pi or OpenCode tool layer, or a remote HTTP service for shared environments. @@ -400,7 +400,7 @@ const installSteps = [

    -

    Caplets turns sprawling tool setups into focused capability cards.

    +

    Caplets gives agents capabilities, not tool walls.

    npm package Config docs
    From 3f21287a5c7367dfb7c8675a1fffb99ca6ddc605 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:46:12 -0400 Subject: [PATCH 05/13] chore: ignore landing app in changesets --- .changeset/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/config.json b/.changeset/config.json index ec98e35..cd68275 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,5 +7,5 @@ "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": [] + "ignore": ["@caplets/landing"] } From a24aa0aed31f81c007d736b23a6d31d4049bcf80 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:47:45 -0400 Subject: [PATCH 06/13] ci: remove duplicate changeset check --- .github/workflows/changeset-reminder.yml | 35 ------------------------ .github/workflows/ci.yml | 2 +- 2 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 .github/workflows/changeset-reminder.yml diff --git a/.github/workflows/changeset-reminder.yml b/.github/workflows/changeset-reminder.yml deleted file mode 100644 index 9e2e495..0000000 --- a/.github/workflows/changeset-reminder.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Changeset Reminder - -on: - pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled] - -permissions: - pull-requests: write - contents: read - -jobs: - remind: - name: Remind - runs-on: ubuntu-latest - if: contains(github.event.pull_request.labels.*.name, 'no changeset') == false - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v6 - - - name: Setup Node - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Check changeset - run: pnpm changeset status --since=origin/main diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a112172..1e61c69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: changeset: name: Changeset runs-on: ubuntu-latest - if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'no changeset') == false + if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, '[no changeset]') == false steps: - name: Checkout uses: actions/checkout@v6 From 2fb07470b7a87109c2ba86611f8638dbd5f6653c Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:48:08 -0400 Subject: [PATCH 07/13] docs(agents): byterover context --- .../design/caplets/caplets_module_findings.md | 106 ++++++++++++++++++ .../design/caplets/formatting_check.md | 22 ++++ .brv/context-tree/design/caplets/hero_copy.md | 22 ++++ .../design/caplets/landing_positioning.md | 22 ++++ .../design/caplets/quick_start.md | 22 ++++ .../design/caplets/readme_header_badges.md | 22 ++++ .brv/context-tree/design/caplets/readme_md.md | 22 ++++ .../design/caplets/readme_section.md | 22 ++++ .brv/context-tree/facts/ci/ci.md | 20 ++++ .../facts/extracted_facts/extracted_facts.md | 24 ++++ .../facts/mcp_example/mcp_example.md | 20 ++++ .../minimal_quick_start.md | 20 ++++ .../pnpm_format_check/pnpm_format_check.md | 20 ++++ .../facts/pnpm_verify/pnpm_verify.md | 20 ++++ .brv/context-tree/facts/pr_93/pr_93.md | 20 ++++ .../facts/review_threads/review_threads.md | 20 ++++ .../staged_path_example.md | 20 ++++ .../src/caplets/caplets_module_findings.md | 29 +++++ 18 files changed, 473 insertions(+) create mode 100644 .brv/context-tree/design/caplets/caplets_module_findings.md create mode 100644 .brv/context-tree/design/caplets/formatting_check.md create mode 100644 .brv/context-tree/design/caplets/hero_copy.md create mode 100644 .brv/context-tree/design/caplets/landing_positioning.md create mode 100644 .brv/context-tree/design/caplets/quick_start.md create mode 100644 .brv/context-tree/design/caplets/readme_header_badges.md create mode 100644 .brv/context-tree/design/caplets/readme_md.md create mode 100644 .brv/context-tree/design/caplets/readme_section.md create mode 100644 .brv/context-tree/facts/ci/ci.md create mode 100644 .brv/context-tree/facts/extracted_facts/extracted_facts.md create mode 100644 .brv/context-tree/facts/mcp_example/mcp_example.md create mode 100644 .brv/context-tree/facts/minimal_quick_start/minimal_quick_start.md create mode 100644 .brv/context-tree/facts/pnpm_format_check/pnpm_format_check.md create mode 100644 .brv/context-tree/facts/pnpm_verify/pnpm_verify.md create mode 100644 .brv/context-tree/facts/pr_93/pr_93.md create mode 100644 .brv/context-tree/facts/review_threads/review_threads.md create mode 100644 .brv/context-tree/facts/staged_path_example/staged_path_example.md create mode 100644 .brv/context-tree/src/caplets/caplets_module_findings.md diff --git a/.brv/context-tree/design/caplets/caplets_module_findings.md b/.brv/context-tree/design/caplets/caplets_module_findings.md new file mode 100644 index 0000000..8031dd6 --- /dev/null +++ b/.brv/context-tree/design/caplets/caplets_module_findings.md @@ -0,0 +1,106 @@ +--- +title: Caplets Module Findings +summary: Extracted and organized factual statements about the caplets module +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:45:38.837Z' +updatedAt: '2026-05-28T16:45:38.837Z' +--- +## Reason +Curate extracted facts from caplets module context + +## Raw Concept +**Task:** +Document caplets module findings + +**Timestamp:** 2026-05-28T16:45:38.834Z + +## Narrative +### Structure +Aggregated facts from caplets module extraction + +### Highlights +PRODUCT.md, DESIGN.md, context loader, IMPECCABLE_CONTEXT_DIR, load-context.mjs, loader output, loader execution, context reload, live.mjs, craft task, design register, register identification, register inference, reference files, shared design laws, color model, hex colors, neutral tinting, design strategy, theme choice, line length, hierarchy, spacing, cards usage, nested cards, containers, animation, easing, side-stripe borders, gradient text, glassmorphism, hero-metric template, identical card grids, modal usage, copy, punctuation, failures, Category-reflex check, First-order reflex, Second-order reflex, `craft` command, `shape` command, `teach` command, `document` command, `extract` command, `critique` command, `audit` command, `polish` command, `bolder` command, `quieter` command, `distill` command, `harden` command, `onboard` command, `animate` command, `colorize` command, `typeset` command, `layout` command, `delight` command, `overdrive` command, `clarify` command, `adapt` command, `optimize` command, `live` command, management commands, Pin command, Unpin command, pin.mjs script, landing page update, index.astro, proof data, build process, pnpm format:check, pnpm typecheck, pnpm build, pnpm verify + +## Facts +- **PRODUCT.md**: PRODUCT.md is required and contains users, brand, tone, anti-references, and strategic principles. +- **DESIGN.md**: DESIGN.md is optional but strongly recommended and includes colors, typography, elevation, and components. +- **context loader**: The loader looks at the project root by default and falls back to .agents/context/ and docs/ if the root is clean. +- **IMPECCABLE_CONTEXT_DIR**: The context directory can be overridden with IMPECCABLE_CONTEXT_DIR=path/to/dir (absolute or relative to cwd). +- **load-context.mjs**: Both PRODUCT.md and DESIGN.md can be loaded in one call using node {{scripts_path}}/load-context.mjs. +- **loader output**: The output of the loader must not be piped through head, tail, grep, or jq. +- **loader execution**: If the loader output is already present in the session history, it should not be re-run. +- **context reload**: A fresh load is required after running {{command_prefix}}impeccable teach, {{command_prefix}}impeccable document, or when the user manually edits a file. +- **live.mjs**: If {{command_prefix}}impeccable live has been run, do not also run load-context.mjs in the same session. +- **PRODUCT.md**: If PRODUCT.md is missing, empty, or contains only placeholder [TODO] markers (<200 characters), run {{command_prefix}}impeccable teach and then resume the original task with fresh context. +- **craft task**: If the original task was {{command_prefix}}impeccable craft, resume into {{command_prefix}}impeccable shape before any implementation work after teaching. +- **DESIGN.md**: If DESIGN.md is missing, prompt the user once per session to run {{command_prefix}}impeccable document for more on‑brand output, then continue. +- **design register**: Every design task is classified as either brand (marketing, landing, campaign, long‑form content, portfolio) or product (app UI, admin, dashboard, tool). +- **register identification**: Design registration should be identified before designing, using priority: task cue, surface in focus, then register field in PRODUCT.md. +- **register inference**: If PRODUCT.md lacks a register field, infer it from the Users and Product Purpose sections, cache it for the session, and suggest running {{command_prefix}}impeccable teach to add the field explicitly. +- **reference files**: Load the matching reference file: reference/brand.md for brand tasks or reference/product.md for product tasks. +- **shared design laws**: Shared design laws apply to all designs; match implementation complexity to aesthetic vision—maximalism requires elaborate code, minimalism requires precision. +- **color model**: Use OKLCH. +- **hex colors**: Never use #000 or #fff. +- **neutral tinting**: Tint every neutral toward the brand hue (chroma 0.005–0.01 is enough). +- **design strategy**: Restrained: tinted neutrals + one accent ≤10%. +- **design strategy**: Committed: one saturated color carries 30–60% of the surface. +- **design strategy**: Full palette: 3–4 named roles, each used deliberately. +- **design strategy**: Drenched: the surface IS the color. +- **theme choice**: Dark vs. light is never a default. +- **line length**: Cap body line length at 65–75ch. +- **hierarchy**: Hierarchy through scale + weight contrast (≥1.25 ratio between steps). +- **spacing**: Vary spacing for rhythm. +- **cards usage**: Cards are the lazy answer. Use them only when they're truly the best affordance. +- **nested cards**: Nested cards are always wrong. +- **containers**: Don't wrap everything in a container. +- **animation**: Don't animate CSS layout properties. +- **easing**: Ease out with exponential curves (ease-out-quart / quint / expo). No bounce, no elastic. +- **side-stripe borders**: Side-stripe borders greater than 1px as a colored accent are never intentional. +- **gradient text**: Gradient text using background-clip: text combined with a gradient background is decorative, never meaningful. +- **glassmorphism**: Glassmorphism as default is banned. +- **hero-metric template**: The hero-metric template is a SaaS cliché. +- **identical card grids**: Identical card grids are banned. +- **modal usage**: Modal as first thought is usually laziness. +- **copy**: Every word earns its place. +- **punctuation**: No em dashes; use commas, colons, semicolons, periods, or parentheses. +- **failures**: Register-specific failures live in each reference. +- **Category-reflex check**: Category-reflex check runs at two altitudes; the second one catches what the first one misses. +- **First-order reflex**: First-order reflex occurs if someone could guess the theme and palette from the category alone. +- **Second-order reflex**: Second-order reflex occurs if someone could guess the aesthetic family from category-plus-anti-references. +- **`craft` command**: `craft [feature]` shapes and builds a feature end-to-end. +- **`shape` command**: `shape [feature]` plans UX/UI before writing code. +- **`teach` command**: `teach` sets up PRODUCT.md and DESIGN.md context. +- **`document` command**: `document` generates DESIGN.md from existing project code. +- **`extract` command**: `extract [target]` pulls reusable tokens and components into design system. +- **`critique` command**: `critique [target]` performs UX design review with heuristic scoring. +- **`audit` command**: `audit [target]` conducts technical quality checks such as accessibility, performance, and responsiveness. +- **`polish` command**: `polish [target]` provides a final quality pass before shipping. +- **`bolder` command**: `bolder [target]` amplifies safe or bland designs. +- **`quieter` command**: `quieter [target]` tones down aggressive or overstimulating designs. +- **`distill` command**: `distill [target]` strips to essence and removes complexity. +- **`harden` command**: `harden [target]` makes designs production-ready, handling errors, i18n, and edge cases. +- **`onboard` command**: `onboard [target]` designs first-run flows, empty states, and activation. +- **`animate` command**: `animate [target]` adds purposeful animations and motion. +- **`colorize` command**: `colorize [target]` adds strategic color to monochromatic UIs. +- **`typeset` command**: `typeset [target]` improves typography hierarchy and fonts. +- **`layout` command**: `layout [target]` fixes spacing, rhythm, and visual hierarchy. +- **`delight` command**: `delight [target]` adds personality and memorable touches. +- **`overdrive` command**: `overdrive [target]` pushes past conventional limits. +- **`clarify` command**: `clarify [target]` improves UX copy, labels, and error messages. +- **`adapt` command**: `adapt [target]` adapts designs for different devices and screen sizes. +- **`optimize` command**: `optimize [target]` diagnoses and fixes UI performance issues. +- **`live` command**: `live` enables visual variant mode to pick elements in the browser and generate alternatives. +- **management commands**: Two management commands are `pin ` and `unpin `. +- **Pin command**: Pin creates a standalone shortcut so `{{command_prefix}}` invokes `{{command_prefix}}impeccable ` directly. +- **Unpin command**: Unpin removes the shortcut created by Pin. +- **pin.mjs script**: The script writes to every harness directory present in the project. +- **landing page update**: Clarified `apps/landing/` copy and pushed it to PR #93. +- **index.astro**: Replaced remaining “backend” phrasing with clearer “tool source” language in `apps/landing/src/pages/index.astro`. +- **proof data**: Renamed the proof data from `skillifyFramework` to `capabilityFramework`. +- **build process**: Verification commands `pnpm format:check`, `pnpm typecheck`, `pnpm build`, and `pnpm verify` all passed. +- **pnpm format:check**: `pnpm format:check -- apps/landing/src/pages/index.astro` passed +- **pnpm typecheck**: `pnpm --filter @caplets/landing typecheck` passed +- **pnpm build**: `pnpm --filter @caplets/landing build` passed +- **pnpm verify**: `pnpm verify` passed diff --git a/.brv/context-tree/design/caplets/formatting_check.md b/.brv/context-tree/design/caplets/formatting_check.md new file mode 100644 index 0000000..36b2c26 --- /dev/null +++ b/.brv/context-tree/design/caplets/formatting_check.md @@ -0,0 +1,22 @@ +--- +title: Formatting check +summary: Facts about formatting check +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.789Z' +updatedAt: '2026-05-28T16:03:02.789Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about formatting check + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **formatting check**: Ran formatting check successfully: pnpm format:check -- README.md. diff --git a/.brv/context-tree/design/caplets/hero_copy.md b/.brv/context-tree/design/caplets/hero_copy.md new file mode 100644 index 0000000..e474421 --- /dev/null +++ b/.brv/context-tree/design/caplets/hero_copy.md @@ -0,0 +1,22 @@ +--- +title: Hero copy +summary: Facts about hero copy +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.759Z' +updatedAt: '2026-05-28T16:03:02.759Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about hero copy + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **hero copy**: Updated hero copy to “Skillify your backends.” diff --git a/.brv/context-tree/design/caplets/landing_positioning.md b/.brv/context-tree/design/caplets/landing_positioning.md new file mode 100644 index 0000000..037a755 --- /dev/null +++ b/.brv/context-tree/design/caplets/landing_positioning.md @@ -0,0 +1,22 @@ +--- +title: Landing positioning +summary: Facts about landing positioning +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.763Z' +updatedAt: '2026-05-28T16:03:02.763Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about landing positioning + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **landing positioning**: Matched landing positioning around staged discovery: one card, searchable tools, inspectable schemas, preserved results. diff --git a/.brv/context-tree/design/caplets/quick_start.md b/.brv/context-tree/design/caplets/quick_start.md new file mode 100644 index 0000000..dd3350d --- /dev/null +++ b/.brv/context-tree/design/caplets/quick_start.md @@ -0,0 +1,22 @@ +--- +title: Quick Start +summary: Facts about Quick Start +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.770Z' +updatedAt: '2026-05-28T16:03:02.770Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about Quick Start + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **Quick Start**: Updated Quick Start to match landing install flow using npm install -g caplets. diff --git a/.brv/context-tree/design/caplets/readme_header_badges.md b/.brv/context-tree/design/caplets/readme_header_badges.md new file mode 100644 index 0000000..b5c1c49 --- /dev/null +++ b/.brv/context-tree/design/caplets/readme_header_badges.md @@ -0,0 +1,22 @@ +--- +title: README header badges +summary: Facts about README header badges +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.755Z' +updatedAt: '2026-05-28T16:03:02.755Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about README header badges + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **README header badges**: Added https://caplets.dev near the README header badges. diff --git a/.brv/context-tree/design/caplets/readme_md.md b/.brv/context-tree/design/caplets/readme_md.md new file mode 100644 index 0000000..41f16c8 --- /dev/null +++ b/.brv/context-tree/design/caplets/readme_md.md @@ -0,0 +1,22 @@ +--- +title: README.md +summary: Facts about README.md +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.747Z' +updatedAt: '2026-05-28T16:03:02.747Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about README.md + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **README.md**: Updated README.md to align with apps/landing/ messaging and added the landing page link. diff --git a/.brv/context-tree/design/caplets/readme_section.md b/.brv/context-tree/design/caplets/readme_section.md new file mode 100644 index 0000000..513dae2 --- /dev/null +++ b/.brv/context-tree/design/caplets/readme_section.md @@ -0,0 +1,22 @@ +--- +title: README section +summary: Facts about README section +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:03:02.773Z' +updatedAt: '2026-05-28T16:03:02.773Z' +--- +## Reason +Curate extracted facts from context + +## Raw Concept +**Task:** +Document facts about README section + +## Narrative +### Highlights +Extracted 1 facts. + +## Facts +- **README section**: Added “Trust Before Invocation” section based on landing content. diff --git a/.brv/context-tree/facts/ci/ci.md b/.brv/context-tree/facts/ci/ci.md new file mode 100644 index 0000000..1d35d63 --- /dev/null +++ b/.brv/context-tree/facts/ci/ci.md @@ -0,0 +1,20 @@ +--- +title: CI +summary: Facts about CI +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.986Z' +updatedAt: '2026-05-28T16:21:51.986Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for CI + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **CI**: CI was still running when checked. diff --git a/.brv/context-tree/facts/extracted_facts/extracted_facts.md b/.brv/context-tree/facts/extracted_facts/extracted_facts.md new file mode 100644 index 0000000..e653bd8 --- /dev/null +++ b/.brv/context-tree/facts/extracted_facts/extracted_facts.md @@ -0,0 +1,24 @@ +--- +title: extracted_facts +summary: Aggregated factual statements from user conversation +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:46:02.415Z' +updatedAt: '2026-05-28T16:46:02.415Z' +--- +## Reason +Curate extracted facts from RLM context + +## Raw Concept +**Task:** +Curate extracted factual statements from conversation + +**Flow:** +extraction -> dedup -> upsert + +**Timestamp:** 2026-05-28T16:46:02.411Z + +## Narrative +### Structure +Aggregated factual statements grouped by subject diff --git a/.brv/context-tree/facts/mcp_example/mcp_example.md b/.brv/context-tree/facts/mcp_example/mcp_example.md new file mode 100644 index 0000000..3ef7628 --- /dev/null +++ b/.brv/context-tree/facts/mcp_example/mcp_example.md @@ -0,0 +1,20 @@ +--- +title: MCP example +summary: Facts about MCP example +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.966Z' +updatedAt: '2026-05-28T16:21:51.966Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for MCP example + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **MCP example**: Moved that MCP example into the optional backend examples section. diff --git a/.brv/context-tree/facts/minimal_quick_start/minimal_quick_start.md b/.brv/context-tree/facts/minimal_quick_start/minimal_quick_start.md new file mode 100644 index 0000000..609c19f --- /dev/null +++ b/.brv/context-tree/facts/minimal_quick_start/minimal_quick_start.md @@ -0,0 +1,20 @@ +--- +title: Minimal Quick Start +summary: Facts about minimal Quick Start +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.964Z' +updatedAt: '2026-05-28T16:21:51.964Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for minimal Quick Start + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **minimal Quick Start**: Removed the optional Context7 `caplets add mcp docs ...` command from the minimal Quick Start. diff --git a/.brv/context-tree/facts/pnpm_format_check/pnpm_format_check.md b/.brv/context-tree/facts/pnpm_format_check/pnpm_format_check.md new file mode 100644 index 0000000..8d932ef --- /dev/null +++ b/.brv/context-tree/facts/pnpm_format_check/pnpm_format_check.md @@ -0,0 +1,20 @@ +--- +title: Pnpm format check +summary: Facts about pnpm format check +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.969Z' +updatedAt: '2026-05-28T16:21:51.969Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for pnpm format check + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **pnpm format check**: `pnpm format:check -- README.md` passed. diff --git a/.brv/context-tree/facts/pnpm_verify/pnpm_verify.md b/.brv/context-tree/facts/pnpm_verify/pnpm_verify.md new file mode 100644 index 0000000..42cab7f --- /dev/null +++ b/.brv/context-tree/facts/pnpm_verify/pnpm_verify.md @@ -0,0 +1,20 @@ +--- +title: Pnpm verify +summary: Facts about pnpm verify +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.971Z' +updatedAt: '2026-05-28T16:21:51.971Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for pnpm verify + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **pnpm verify**: `pnpm verify` passed. diff --git a/.brv/context-tree/facts/pr_93/pr_93.md b/.brv/context-tree/facts/pr_93/pr_93.md new file mode 100644 index 0000000..17be082 --- /dev/null +++ b/.brv/context-tree/facts/pr_93/pr_93.md @@ -0,0 +1,20 @@ +--- +title: 'PR #93' +summary: 'Facts about PR #93' +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.960Z' +updatedAt: '2026-05-28T16:21:51.960Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for PR #93 + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **PR #93**: Addressed PR review feedback and pushed updates to PR #93. diff --git a/.brv/context-tree/facts/review_threads/review_threads.md b/.brv/context-tree/facts/review_threads/review_threads.md new file mode 100644 index 0000000..02669a3 --- /dev/null +++ b/.brv/context-tree/facts/review_threads/review_threads.md @@ -0,0 +1,20 @@ +--- +title: Review threads +summary: Facts about review threads +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.983Z' +updatedAt: '2026-05-28T16:21:51.983Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for review threads + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **review threads**: Replied to both inline review threads and added a PR summary comment. diff --git a/.brv/context-tree/facts/staged_path_example/staged_path_example.md b/.brv/context-tree/facts/staged_path_example/staged_path_example.md new file mode 100644 index 0000000..6b82499 --- /dev/null +++ b/.brv/context-tree/facts/staged_path_example/staged_path_example.md @@ -0,0 +1,20 @@ +--- +title: Staged-path example +summary: Facts about staged-path example +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:21:51.967Z' +updatedAt: '2026-05-28T16:21:51.967Z' +--- +## Reason +Curated factual statements extracted from PR review context + +## Raw Concept +**Task:** +Document facts for staged-path example + +**Timestamp:** 2026-05-28T16:21:51.958Z + +## Facts +- **staged-path example**: Changed the staged-path example from `github` to `GitHub`. diff --git a/.brv/context-tree/src/caplets/caplets_module_findings.md b/.brv/context-tree/src/caplets/caplets_module_findings.md new file mode 100644 index 0000000..056844e --- /dev/null +++ b/.brv/context-tree/src/caplets/caplets_module_findings.md @@ -0,0 +1,29 @@ +--- +title: Caplets Module Findings +summary: Extracted key facts and narratives from caplets module +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:06:53.148Z' +updatedAt: '2026-05-28T16:06:53.148Z' +--- +## Reason +Curate extracted facts from caplets source + +## Raw Concept +**Task:** +Document caplets module insights + +**Timestamp:** 2026-05-28T16:06:53.146Z + +## Narrative +### Highlights +The assistant is using the finishing-a-development-branch skill to complete the work | A pull request was opened at https://github.com/spiritledsoftware/caplets/pull/93 | The pull request targets the branch docs/align-readme-with-landing | The commit b37a94c with message "docs: align readme with landing page" was included in the PR | The verification command pnpm verify passed | Files under .brv/context-tree/... remain untracked and were not included in the commit + +## Facts +- **assistant**: The assistant is using the finishing-a-development-branch skill to complete the work +- **PR 93**: A pull request was opened at https://github.com/spiritledsoftware/caplets/pull/93 +- **docs/align-readme-with-landing**: The pull request targets the branch docs/align-readme-with-landing +- **b37a94c**: The commit b37a94c with message "docs: align readme with landing page" was included in the PR +- **pnpm verify**: The verification command pnpm verify passed +- **untracked files**: Files under .brv/context-tree/... remain untracked and were not included in the commit From ab9efe5dee2b341b5660eab93680e21bc34868f0 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:57:58 -0400 Subject: [PATCH 08/13] feat(agents): commit byterover context from hook --- .husky/post-commit | 2 + .husky/pre-push | 1 + scripts/commit-byterover-context.test.ts | 32 +++++++++ scripts/commit-byterover-context.ts | 85 ++++++++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100755 .husky/post-commit create mode 100644 scripts/commit-byterover-context.test.ts create mode 100644 scripts/commit-byterover-context.ts diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 0000000..bea6e6c --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1,2 @@ +pnpm exec tsx ./scripts/commit-byterover-context.ts + diff --git a/.husky/pre-push b/.husky/pre-push index 347ade0..9936862 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1 +1,2 @@ pnpm verify +pnpm exec tsx ./scripts/commit-byterover-context.ts --check diff --git a/scripts/commit-byterover-context.test.ts b/scripts/commit-byterover-context.test.ts new file mode 100644 index 0000000..e76d64b --- /dev/null +++ b/scripts/commit-byterover-context.test.ts @@ -0,0 +1,32 @@ +import { readFile } from "node:fs/promises"; +import { expect, test } from "vitest"; + +import { + buildCommitArgs, + checkByteRoverStatus, + formatCheckWarning, +} from "./commit-byterover-context"; + +test("ByteRover status check reports clean when git returns no .brv changes", () => { + expect(checkByteRoverStatus("")).toEqual({ hasChanges: false }); +}); + +test("ByteRover status check reports changes from porcelain output", () => { + expect(checkByteRoverStatus(" M .brv/context.md\n?? .brv/new.md\n")).toEqual({ + hasChanges: true, + }); +}); + +test("ByteRover check warning is advisory and includes manual commit command", () => { + expect(formatCheckWarning()).toContain("ByteRover context has uncommitted changes"); + expect(formatCheckWarning()).toContain("pnpm exec tsx ./scripts/commit-byterover-context.ts"); +}); + +test("ByteRover context commits use a conventional docs commit message", () => { + expect(buildCommitArgs()).toEqual(["commit", "-m", "docs(agents): byterover context"]); +}); + +test("ByteRover context script has a Node shebang for direct hook execution", async () => { + const script = await readFile(new URL("./commit-byterover-context.ts", import.meta.url), "utf8"); + expect(script.startsWith("#!/usr/bin/env node\n")).toBe(true); +}); diff --git a/scripts/commit-byterover-context.ts b/scripts/commit-byterover-context.ts new file mode 100644 index 0000000..c75c440 --- /dev/null +++ b/scripts/commit-byterover-context.ts @@ -0,0 +1,85 @@ +#!/usr/bin/env node +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const recursionGuardEnv = "BYTEROVER_CONTEXT_COMMIT"; +const commitMessage = "docs(agents): byterover context"; + +export type ByteRoverStatus = { + hasChanges: boolean; +}; + +export function checkByteRoverStatus(porcelainOutput: string): ByteRoverStatus { + return { hasChanges: porcelainOutput.trim().length > 0 }; +} + +export function buildCommitArgs(): string[] { + return ["commit", "-m", commitMessage]; +} + +export function formatCheckWarning(): string { + return [ + "ByteRover context has uncommitted changes.", + "These changes are advisory and will not block this push.", + "Run `pnpm exec tsx ./scripts/commit-byterover-context.ts` to commit them.", + ].join("\n"); +} + +function runGit(args: string[], env: NodeJS.ProcessEnv = process.env): string { + const result = spawnSync("git", args, { + encoding: "utf8", + env, + stdio: ["ignore", "pipe", "pipe"], + }); + + if (result.status !== 0) { + const detail = result.stderr.trim() || result.stdout.trim(); + throw new Error(`git ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`); + } + + return result.stdout; +} + +function isCheckMode(args: string[]): boolean { + return args.includes("--check"); +} + +export function main(args = process.argv.slice(2)): number { + if (process.env[recursionGuardEnv] === "1") { + return 0; + } + + const status = checkByteRoverStatus(runGit(["status", "--porcelain", "--", ".brv"])); + + if (!status.hasChanges) { + return 0; + } + + if (isCheckMode(args)) { + console.warn(formatCheckWarning()); + return 0; + } + + runGit(["add", "--", ".brv"]); + const stagedStatus = checkByteRoverStatus( + runGit(["diff", "--cached", "--name-status", "--", ".brv"]), + ); + + if (!stagedStatus.hasChanges) { + return 0; + } + + runGit(buildCommitArgs(), { ...process.env, [recursionGuardEnv]: "1" }); + return 0; +} + +const currentFilePath = fileURLToPath(import.meta.url); + +if (process.argv[1] === currentFilePath) { + try { + process.exitCode = main(); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} From 947a9ecac43fdf455299554098045f8b331c0da6 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 12:57:58 -0400 Subject: [PATCH 09/13] docs(agents): byterover context --- .brv/context-tree/facts/project/179803b.md | 20 +++++++++ .brv/context-tree/facts/project/ab9efe5.md | 20 +++++++++ .../facts/project/extracted_facts.md | 26 ++++++++++++ .../facts/project/post_commit_hook_brv.md | 41 +++++++++++++++++++ .../facts/project/uncategorized.md | 25 +++++++++++ 5 files changed, 132 insertions(+) create mode 100644 .brv/context-tree/facts/project/179803b.md create mode 100644 .brv/context-tree/facts/project/ab9efe5.md create mode 100644 .brv/context-tree/facts/project/extracted_facts.md create mode 100644 .brv/context-tree/facts/project/post_commit_hook_brv.md create mode 100644 .brv/context-tree/facts/project/uncategorized.md diff --git a/.brv/context-tree/facts/project/179803b.md b/.brv/context-tree/facts/project/179803b.md new file mode 100644 index 0000000..01b6c55 --- /dev/null +++ b/.brv/context-tree/facts/project/179803b.md @@ -0,0 +1,20 @@ +--- +title: 179803b +summary: Facts about 179803b +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:59:16.797Z' +updatedAt: '2026-05-28T16:59:16.797Z' +--- +## Reason +Curated facts extracted from context + +## Raw Concept +**Task:** +Document facts for 179803b + +**Timestamp:** 2026-05-28T16:59:16.794Z + +## Facts +- **179803b**: Commit 179803b docs(agents): byterover context was automatically created by the new post-commit hook for .brv/ changes diff --git a/.brv/context-tree/facts/project/ab9efe5.md b/.brv/context-tree/facts/project/ab9efe5.md new file mode 100644 index 0000000..dfc0c48 --- /dev/null +++ b/.brv/context-tree/facts/project/ab9efe5.md @@ -0,0 +1,20 @@ +--- +title: ab9efe5 +summary: Facts about ab9efe5 +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:59:16.795Z' +updatedAt: '2026-05-28T16:59:16.795Z' +--- +## Reason +Curated facts extracted from context + +## Raw Concept +**Task:** +Document facts for ab9efe5 + +**Timestamp:** 2026-05-28T16:59:16.794Z + +## Facts +- **ab9efe5**: Commit ab9efe5 feat(agents): commit byterover context from hook implements scripts/commit-byterover-context.ts, adds tests in scripts/commit-byterover-context.test.ts, adds warn-only .brv/ check to .husky/pre-push, and includes .husky/post-commit diff --git a/.brv/context-tree/facts/project/extracted_facts.md b/.brv/context-tree/facts/project/extracted_facts.md new file mode 100644 index 0000000..86187c0 --- /dev/null +++ b/.brv/context-tree/facts/project/extracted_facts.md @@ -0,0 +1,26 @@ +--- +title: Extracted Facts +summary: Curated factual statements extracted from source context +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:47:59.662Z' +updatedAt: '2026-05-28T16:47:59.662Z' +--- +## Reason +Store extracted factual statements from context + +## Raw Concept +**Task:** +Curate extracted factual statements from provided context + +**Timestamp:** 2026-05-28T16:47:59.660Z + +## Facts +- **changesets**: Changesets supports excluding packages via `.changeset/config.json`. +- **config**: Added "ignore": ["@caplets/landing"] to the config. +- **changeset status**: `pnpm changeset status --since=origin/main` now passes with no changeset needed for landing-only changes. +- **PR**: Pushed to PR #93 in commit `3f21287 chore: ignore landing app in changesets`. +- **changeset status**: `pnpm changeset status --since=origin/main` passed. +- **format check**: `pnpm format:check -- .changeset/config.json` passed. +- **verification**: `pnpm verify` passed. diff --git a/.brv/context-tree/facts/project/post_commit_hook_brv.md b/.brv/context-tree/facts/project/post_commit_hook_brv.md new file mode 100644 index 0000000..8520625 --- /dev/null +++ b/.brv/context-tree/facts/project/post_commit_hook_brv.md @@ -0,0 +1,41 @@ +--- +title: post_commit_hook_brv +summary: Post-commit hook auto-commits .brv context and pre-push verifies no uncommitted .brv changes +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:56:48.398Z' +updatedAt: '2026-05-28T16:56:48.398Z' +--- +## Reason +Document design of post-commit hook to commit .brv changes and pre-push check + +## Raw Concept +**Task:** +Implement git hooks for automatic .brv context commits and verification before push + +**Files:** +- .husky/post-commit +- .husky/pre-push +- scripts/commit-byterover-context.ts + +**Flow:** +post-commit -> detect .brv changes -> stage .brv -> commit with docs(agents): byterover context; pre-push -> verify .brv clean before push + +**Timestamp:** 2026-05-28T16:56:15.853Z + +**Author:** assistant + +## Narrative +### Structure +post-commit runs tsx script; script checks git status, stages .brv, makes conventional commit; pre-push runs verify then ensures .brv clean + +### Highlights +Avoid recursion via BYTEROVER_CONTEXT_COMMIT env var; fail push if .brv has uncommitted changes + +## Facts +- **husky_post_commit**: .husky/post-commit runs pnpm exec tsx ./scripts/commit-byterover-context.ts [project] +- **husky_pre_push**: .husky/pre-push runs pnpm verify [project] +- **script_detection**: commit-byterover-context.ts detects .brv changes via git status --porcelain -- .brv [project] +- **script_commit**: Script stages .brv and creates docs(agents): byterover context commit [project] +- **pre_push_check**: Pre-push check fails if .brv has uncommitted changes [project] diff --git a/.brv/context-tree/facts/project/uncategorized.md b/.brv/context-tree/facts/project/uncategorized.md new file mode 100644 index 0000000..ed64ded --- /dev/null +++ b/.brv/context-tree/facts/project/uncategorized.md @@ -0,0 +1,25 @@ +--- +title: uncategorized +summary: Facts about uncategorized +tags: [] +related: [] +keywords: [] +createdAt: '2026-05-28T16:59:16.799Z' +updatedAt: '2026-05-28T16:59:16.799Z' +--- +## Reason +Curated facts extracted from context + +## Raw Concept +**Task:** +Document facts for uncategorized + +**Timestamp:** 2026-05-28T16:59:16.794Z + +## Facts +- pnpm test scripts/commit-byterover-context.test.ts passed with 5 tests +- pnpm format:check passed +- pnpm lint passed +- pnpm typecheck passed +- Post-commit behavior now commits .brv/ changes as docs(agents): byterover context +- Pre-push behavior now runs pnpm verify and then warns about uncommitted .brv/ changes without blocking the push From e19a1400fd7992122dab6fcc528db39d6e25b99d Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 13:53:25 -0400 Subject: [PATCH 10/13] ci: fix preview deploys, teardown, add www. domain --- .github/workflows/deploy.yml | 13 ++++++++++-- .github/workflows/pr-preview-deploy.yml | 28 +++++++++++++++++++++++++ alchemy.run.ts | 24 +++++++++++---------- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7337bc0..0561586 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,8 +1,17 @@ name: Deploy on: - release: - types: [published] + push: + branches: + - main + paths: + - .github/workflows/deploy.yml + - alchemy.run.ts + - apps/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - scripts/alchemy-*.ts workflow_dispatch: permissions: diff --git a/.github/workflows/pr-preview-deploy.yml b/.github/workflows/pr-preview-deploy.yml index b3278b2..d8729ea 100644 --- a/.github/workflows/pr-preview-deploy.yml +++ b/.github/workflows/pr-preview-deploy.yml @@ -4,6 +4,19 @@ on: pull_request: branches: - main + paths: + - .github/workflows/pr-preview-deploy.yml + - alchemy.run.ts + - apps/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - scripts/alchemy-*.ts + types: + - opened + - synchronize + - reopened + - closed permissions: contents: read @@ -36,6 +49,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Deploy preview + if: ${{ github.event.action != 'closed' }} run: pnpm run alchemy:deploy env: ALCHEMY_STAGE: pr-${{ github.event.pull_request.number }} @@ -47,3 +61,17 @@ jobs: GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }} GITHUB_TOKEN: ${{ github.token }} PULL_REQUEST: ${{ github.event.pull_request.number }} + + - name: Destroy preview + if: ${{ github.event.action == 'closed' }} + run: pnpm run alchemy:destroy + env: + ALCHEMY_STAGE: pr-${{ github.event.pull_request.number }} + ALCHEMY_PASSWORD: ${{ secrets.ALCHEMY_PASSWORD }} + ALCHEMY_STATE_TOKEN: ${{ secrets.ALCHEMY_STATE_TOKEN }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }} + GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }} + GITHUB_TOKEN: ${{ github.token }} + PULL_REQUEST: ${{ github.event.pull_request.number }} diff --git a/alchemy.run.ts b/alchemy.run.ts index 9d767fd..46c5bce 100644 --- a/alchemy.run.ts +++ b/alchemy.run.ts @@ -3,34 +3,36 @@ import { Astro } from "alchemy/cloudflare"; import { GitHubComment } from "alchemy/github"; import { CloudflareStateStore } from "alchemy/state"; -const baseDomain = "caplets.dev"; +const globalBaseDomain = "caplets.dev"; const app = await alchemy("caplets", { stateStore: (scope) => new CloudflareStateStore(scope), password: process.env.ALCHEMY_PASSWORD!, }); -const landingPageDomain = app.stage === "prod" ? baseDomain : `${app.stage}.preview.${baseDomain}`; -const [repositoryOwnerFromSlug, repositoryNameFromSlug] = - process.env.GITHUB_REPOSITORY?.split("/") ?? []; -const repositoryOwner = process.env.GITHUB_REPOSITORY_OWNER ?? repositoryOwnerFromSlug; -const repositoryName = process.env.GITHUB_REPOSITORY_NAME ?? repositoryNameFromSlug; -const pullRequestNumber = process.env.PULL_REQUEST - ? Number.parseInt(process.env.PULL_REQUEST, 10) - : undefined; +const baseDomain = + app.stage === "prod" ? globalBaseDomain : `${app.stage}.preview.${globalBaseDomain}`; +const landingPageDomain = baseDomain; export const landingPage = await Astro("landing-page", { cwd: "apps/landing", dev: { command: "pnpm run dev" + (process.env.SSH_CONNECTION ? " --host 0.0.0.0" : ""), }, - domains: [landingPageDomain], + domains: [landingPageDomain, `www.${landingPageDomain}`], }); console.log({ - "Landing Page URL": landingPage.url, + "Landing Page URL": `https://${landingPageDomain}`, }); +const [repositoryOwnerFromSlug, repositoryNameFromSlug] = + process.env.GITHUB_REPOSITORY?.split("/") ?? []; +const repositoryOwner = process.env.GITHUB_REPOSITORY_OWNER ?? repositoryOwnerFromSlug; +const repositoryName = process.env.GITHUB_REPOSITORY_NAME ?? repositoryNameFromSlug; +const pullRequestNumber = process.env.PULL_REQUEST + ? Number.parseInt(process.env.PULL_REQUEST, 10) + : undefined; if (pullRequestNumber) { if (!repositoryOwner || !repositoryName) { throw new Error("Missing GitHub repository metadata for preview comment."); From b65a84e06fac4b471c4ea2e7e7b7bdb4b9659e16 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 14:03:09 -0400 Subject: [PATCH 11/13] ci: lint-staged --- .husky/pre-commit | 4 +- .lintstagedrc.json | 3 + package.json | 2 + pnpm-lock.yaml | 176 ++++++++++++++++++++++++++++ scripts/commit-byterover-context.ts | 1 - 5 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 .lintstagedrc.json diff --git a/.husky/pre-commit b/.husky/pre-commit index 5a27ebf..f2efcca 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1 @@ -pnpm run format:check -pnpm run lint -pnpm run typecheck +pnpm run lint:staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..69abf9b --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,3 @@ +{ + "*.{js,jsx,ts,tsx,mjs,cjs,json,jsonc,md,yml,yaml,css,astro}": ["oxfmt --check", "oxlint"] +} diff --git a/package.json b/package.json index 43ee679..fe386db 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "format:check": "oxfmt --check .", "lint": "oxlint .", "lint:fix": "oxlint --fix .", + "lint:staged": "lint-staged", "prepare": "husky", "release": "turbo build && changeset publish", "schema:check": "tsx ./scripts/generate-config-schema.ts --check", @@ -36,6 +37,7 @@ "@typescript/native-preview": "7.0.0-dev.20260527.1", "alchemy": "0.93.9", "husky": "^9.1.7", + "lint-staged": "^17.0.5", "oxfmt": "^0.52.0", "oxlint": "^1.67.0", "rolldown": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c1932c..f6faf2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: husky: specifier: ^9.1.7 version: 9.1.7 + lint-staged: + specifier: ^17.0.5 + version: 17.0.5 oxfmt: specifier: ^0.52.0 version: 0.52.0 @@ -2775,6 +2778,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2936,6 +2943,14 @@ packages: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3221,6 +3236,9 @@ packages: emmet@2.4.11: resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3251,6 +3269,10 @@ packages: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} @@ -3696,6 +3718,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3881,6 +3907,15 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lint-staged@17.0.5: + resolution: {integrity: sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw==} + engines: {node: '>=22.22.1'} + hasBin: true + + listr2@10.2.1: + resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} + engines: {node: '>=22.13.0'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -3888,6 +3923,10 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + loglevel@1.9.2: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} @@ -4076,6 +4115,10 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + miniflare@4.20260424.0: resolution: {integrity: sha512-B6MKBBd5TJ19daUc3Ae9rWctn1nDA/VCXykXfCsp9fTxyfGxnZY27tJs1caxgE9MWEMMKGbGHouqVtgKbKGxmw==} engines: {node: '>=18.0.0'} @@ -4196,6 +4239,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + oniguruma-parser@0.12.2: resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} @@ -4513,6 +4560,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + retext-latin@4.0.0: resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} @@ -4537,6 +4588,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rolldown@1.0.3: resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4659,6 +4713,14 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} + smol-toml@1.6.1: resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} engines: {node: '>= 18'} @@ -4686,6 +4748,10 @@ packages: std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4694,6 +4760,14 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} + engines: {node: '>=20'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -5201,6 +5275,10 @@ packages: '@cloudflare/workers-types': optional: true + wrap-ansi@10.0.0: + resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} + engines: {node: '>=20'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5209,6 +5287,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -7621,6 +7703,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -7844,6 +7930,15 @@ snapshots: ci-info@4.4.0: {} + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@5.2.0: + dependencies: + slice-ansi: 8.0.0 + string-width: 8.2.1 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -8022,6 +8117,8 @@ snapshots: '@emmetio/abbreviation': 2.3.3 '@emmetio/css-abbreviation': 2.1.8 + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -8044,6 +8141,8 @@ snapshots: env-paths@3.0.0: {} + environment@1.1.0: {} + error-stack-parser-es@1.0.5: {} es-define-property@1.0.1: {} @@ -8671,6 +8770,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.6.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -8824,12 +8927,37 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lint-staged@17.0.5: + dependencies: + listr2: 10.2.1 + picomatch: 4.0.4 + string-argv: 0.3.2 + tinyexec: 1.2.2 + optionalDependencies: + yaml: 2.9.0 + + listr2@10.2.1: + dependencies: + cli-truncate: 5.2.0 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 10.0.0 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 lodash.startcase@4.4.0: {} + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + loglevel@1.9.2: {} long@5.3.2: {} @@ -9188,6 +9316,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mimic-function@5.0.1: {} + miniflare@4.20260424.0: dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -9312,6 +9442,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + oniguruma-parser@0.12.2: {} oniguruma-to-es@4.3.6: @@ -9659,6 +9793,11 @@ snapshots: resolve-pkg-maps@1.0.0: {} + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + retext-latin@4.0.0: dependencies: '@types/nlcst': 2.0.3 @@ -9690,6 +9829,8 @@ snapshots: reusify@1.1.0: {} + rfdc@1.4.1: {} + rolldown@1.0.3: dependencies: '@oxc-project/types': 0.133.0 @@ -9898,6 +10039,16 @@ snapshots: slash@3.0.0: {} + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + slice-ansi@8.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + smol-toml@1.6.1: {} source-map-js@1.2.1: {} @@ -9917,6 +10068,8 @@ snapshots: std-env@4.1.0: {} + string-argv@0.3.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -9929,6 +10082,17 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.2.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string-width@8.2.1: + dependencies: + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -10360,6 +10524,12 @@ snapshots: - bufferutil - utf-8-validate + wrap-ansi@10.0.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 8.2.1 + strip-ansi: 7.2.0 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -10372,6 +10542,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.2.0 + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrappy@1.0.2: {} ws@8.18.0: {} diff --git a/scripts/commit-byterover-context.ts b/scripts/commit-byterover-context.ts index c75c440..25fa2f9 100644 --- a/scripts/commit-byterover-context.ts +++ b/scripts/commit-byterover-context.ts @@ -1,4 +1,3 @@ -#!/usr/bin/env node import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; From 2bace62fe5122ff55830dea80f2ab94861b5a3c0 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 14:04:40 -0400 Subject: [PATCH 12/13] fix: script tests --- scripts/commit-byterover-context.test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/commit-byterover-context.test.ts b/scripts/commit-byterover-context.test.ts index e76d64b..a707533 100644 --- a/scripts/commit-byterover-context.test.ts +++ b/scripts/commit-byterover-context.test.ts @@ -1,4 +1,3 @@ -import { readFile } from "node:fs/promises"; import { expect, test } from "vitest"; import { @@ -25,8 +24,3 @@ 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"]); }); - -test("ByteRover context script has a Node shebang for direct hook execution", async () => { - const script = await readFile(new URL("./commit-byterover-context.ts", import.meta.url), "utf8"); - expect(script.startsWith("#!/usr/bin/env node\n")).toBe(true); -}); From e076c4416ce9ff4f8816d5210c5a487f1aad34e3 Mon Sep 17 00:00:00 2001 From: Ian Pascoe Date: Thu, 28 May 2026 14:09:24 -0400 Subject: [PATCH 13/13] ci: fix preview URL --- alchemy.run.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alchemy.run.ts b/alchemy.run.ts index 46c5bce..ed65db3 100644 --- a/alchemy.run.ts +++ b/alchemy.run.ts @@ -14,6 +14,7 @@ const baseDomain = app.stage === "prod" ? globalBaseDomain : `${app.stage}.preview.${globalBaseDomain}`; const landingPageDomain = baseDomain; +const landingPageUrl = `https://${landingPageDomain}`; export const landingPage = await Astro("landing-page", { cwd: "apps/landing", dev: { @@ -23,7 +24,7 @@ export const landingPage = await Astro("landing-page", { }); console.log({ - "Landing Page URL": `https://${landingPageDomain}`, + "Landing Page URL": landingPageUrl, }); const [repositoryOwnerFromSlug, repositoryNameFromSlug] = @@ -46,7 +47,7 @@ if (pullRequestNumber) { Your changes have been deployed to a preview environment: -**🌐 Landing Page:** ${landingPage.url} +**🌐 Landing Page:** ${landingPageUrl} Built from commit ${process.env.GITHUB_SHA?.slice(0, 7) ?? "unknown"}