diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f67e369fe..f5ce3be7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -206,7 +206,7 @@ jobs: node-version: 22 cache: npm - run: npm ci - - run: npx tsx apps/cockpit/scripts/deploy-smoke.ts --url https://cockpit.cacheplane.ai --dry-run + - run: npx tsx apps/cockpit/scripts/deploy-smoke.ts --url https://cockpit.threadplane.ai --dry-run examples-chat-smoke: name: examples/chat — python smoke @@ -456,7 +456,7 @@ jobs: run: | mkdir -p .vercel cat > .vercel/project.json < .vercel/project.json < .vercel/project.json < .vercel/project.json < Agent UI for Angular — agent UI primitives for Angular @@ -108,7 +108,7 @@ That's it. `chat.messages()` and `chat.status()` are Angular Signals. Bind them

Agent UI for Angular architecture: Angular Component → agent() → StreamManager Bridge → LangGraph Platform, with signals returned reactively @@ -120,11 +120,11 @@ That's it. `chat.messages()` and `chat.status()` are Angular Signals. Bind them ## Documentation -- [Agent Quickstart](https://cacheplane.ai/docs/agent/getting-started/quickstart) -- [agent() API](https://cacheplane.ai/docs/agent/api/agent) -- [Chat Introduction](https://cacheplane.ai/docs/chat/getting-started/introduction) -- [Human-in-the-Loop / Interrupts](https://cacheplane.ai/docs/agent/guides/interrupts) -- [Subgraph and Subagent Streaming](https://cacheplane.ai/docs/agent/guides/subgraphs) +- [Agent Quickstart](https://threadplane.ai/docs/agent/getting-started/quickstart) +- [agent() API](https://threadplane.ai/docs/agent/api/agent) +- [Chat Introduction](https://threadplane.ai/docs/chat/getting-started/introduction) +- [Human-in-the-Loop / Interrupts](https://threadplane.ai/docs/agent/guides/interrupts) +- [Subgraph and Subagent Streaming](https://threadplane.ai/docs/agent/guides/subgraphs) --- diff --git a/apps/cockpit/e2e/production-smoke.spec.ts b/apps/cockpit/e2e/production-smoke.spec.ts index 5e7b214e5..9488e2800 100644 --- a/apps/cockpit/e2e/production-smoke.spec.ts +++ b/apps/cockpit/e2e/production-smoke.spec.ts @@ -5,20 +5,20 @@ import { expect, test } from '@playwright/test'; * example apps are reachable after production deploy. * * Requires: - * BASE_URL - e.g. https://cockpit.cacheplane.ai - * EXAMPLES_URL - e.g. https://examples.cacheplane.ai + * BASE_URL - e.g. https://cockpit.threadplane.ai + * EXAMPLES_URL - e.g. https://examples.threadplane.ai * OPENAI_API_KEY - optional; enables the single live-provider canary * * Run: - * BASE_URL=https://cockpit.cacheplane.ai \ - * EXAMPLES_URL=https://examples.cacheplane.ai \ + * BASE_URL=https://cockpit.threadplane.ai \ + * EXAMPLES_URL=https://examples.threadplane.ai \ * npx playwright test apps/cockpit/e2e/production-smoke.spec.ts */ -const COCKPIT_URL = process.env['BASE_URL'] ?? 'https://cockpit.cacheplane.ai'; +const COCKPIT_URL = process.env['BASE_URL'] ?? 'https://cockpit.threadplane.ai'; const EXAMPLES_URL = - process.env['EXAMPLES_URL'] ?? 'https://examples.cacheplane.ai'; -const DEMO_URL = process.env['DEMO_URL'] ?? 'https://demo.cacheplane.ai'; + process.env['EXAMPLES_URL'] ?? 'https://examples.threadplane.ai'; +const DEMO_URL = process.env['DEMO_URL'] ?? 'https://demo.threadplane.ai'; const CHAT_CAPABILITIES = [ 'langgraph/streaming', diff --git a/apps/cockpit/scripts/deploy-smoke.spec.ts b/apps/cockpit/scripts/deploy-smoke.spec.ts index 9c1720157..de71b6db9 100644 --- a/apps/cockpit/scripts/deploy-smoke.spec.ts +++ b/apps/cockpit/scripts/deploy-smoke.spec.ts @@ -6,7 +6,7 @@ describe('deploy smoke helper', () => { expect( parseDeploySmokeArgs([ '--url', - 'https://cockpit.cacheplane.ai', + 'https://cockpit.threadplane.ai', '--dry-run', '--retries', '5', @@ -14,7 +14,7 @@ describe('deploy smoke helper', () => { '1000', ]) ).toEqual({ - url: 'https://cockpit.cacheplane.ai', + url: 'https://cockpit.threadplane.ai', expectedTitle: 'Cockpit', dryRun: true, retries: 5, @@ -25,11 +25,11 @@ describe('deploy smoke helper', () => { it('formats dry-run output without performing a network request', async () => { await expect( runDeploySmoke({ - url: 'https://cockpit.cacheplane.ai', + url: 'https://cockpit.threadplane.ai', expectedTitle: 'Cockpit', dryRun: true, }) - ).resolves.toBe('dry-run:https://cockpit.cacheplane.ai:Cockpit'); + ).resolves.toBe('dry-run:https://cockpit.threadplane.ai:Cockpit'); }); it('retries until the deployment responds with the expected title', async () => { @@ -46,13 +46,13 @@ describe('deploy smoke helper', () => { await expect( runDeploySmoke({ - url: 'https://cockpit.cacheplane.ai', + url: 'https://cockpit.threadplane.ai', retries: 1, retryDelayMs: 1, fetchImpl, sleep, }) - ).resolves.toBe('pass:https://cockpit.cacheplane.ai:Cockpit'); + ).resolves.toBe('pass:https://cockpit.threadplane.ai:Cockpit'); expect(fetchImpl).toHaveBeenCalledTimes(2); expect(sleep).toHaveBeenCalledTimes(1); diff --git a/apps/cockpit/src/app/opengraph-image.tsx b/apps/cockpit/src/app/opengraph-image.tsx index 5aae5efe1..6587bcb45 100644 --- a/apps/cockpit/src/app/opengraph-image.tsx +++ b/apps/cockpit/src/app/opengraph-image.tsx @@ -129,7 +129,7 @@ export default async function OpenGraphImage() { }} > 🛩️ - cockpit.cacheplane.ai + cockpit.threadplane.ai diff --git a/apps/cockpit/src/lib/content-bundle.spec.ts b/apps/cockpit/src/lib/content-bundle.spec.ts index 1e61d58a9..070553220 100644 --- a/apps/cockpit/src/lib/content-bundle.spec.ts +++ b/apps/cockpit/src/lib/content-bundle.spec.ts @@ -28,10 +28,10 @@ describe('resolveRuntimeUrl', () => { }); it('uses NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL when set', () => { - vi.stubEnv('NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL', 'https://examples.cacheplane.ai'); + vi.stubEnv('NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL', 'https://examples.threadplane.ai'); expect( resolveRuntimeUrl({ runtimeUrl: 'langgraph/streaming', devPort: 4300 }) - ).toBe('https://examples.cacheplane.ai/langgraph/streaming'); + ).toBe('https://examples.threadplane.ai/langgraph/streaming'); }); it('falls back to localhost with devPort when no env var is set', () => { @@ -49,7 +49,7 @@ describe('resolveRuntimeUrl', () => { }); it('returns null when runtimeUrl is undefined even with env var set', () => { - vi.stubEnv('NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL', 'https://examples.cacheplane.ai'); + vi.stubEnv('NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL', 'https://examples.threadplane.ai'); expect( resolveRuntimeUrl({ runtimeUrl: undefined, devPort: undefined }) ).toBeNull(); diff --git a/apps/cockpit/src/lib/content-bundle.ts b/apps/cockpit/src/lib/content-bundle.ts index c017f9401..d9fbee109 100644 --- a/apps/cockpit/src/lib/content-bundle.ts +++ b/apps/cockpit/src/lib/content-bundle.ts @@ -46,7 +46,7 @@ export function resolveRuntimeUrl(options: { } const baseUrl = process.env['NEXT_PUBLIC_COCKPIT_RUNTIME_BASE_URL'] - ?? 'https://examples.cacheplane.ai'; + ?? 'https://examples.threadplane.ai'; if (baseUrl && runtimeUrl) { return `${baseUrl}/${runtimeUrl}`; diff --git a/apps/minting-service/LICENSE b/apps/minting-service/LICENSE index a1fe3d1ad..792c43677 100644 --- a/apps/minting-service/LICENSE +++ b/apps/minting-service/LICENSE @@ -1,15 +1,15 @@ Commercial License -Copyright (c) 2026 Brian Love d/b/a cacheplane. All rights reserved. +Copyright (c) 2026 Brian Love d/b/a ThreadPlane. All rights reserved. This Commercial License ("License") governs commercial use of the -cacheplane minting service ("Software"), located in apps/minting-service/ +ThreadPlane minting service ("Software"), located in apps/minting-service/ of the angular-agent-framework repository. This License applies solely to the minting service component and does not govern any other part of the repository, which is released separately under the MIT License. Use of the Software for commercial purposes requires a valid license -purchased from cacheplane. +purchased from ThreadPlane. --- LICENSE TIERS --- @@ -34,7 +34,7 @@ purchased from cacheplane. --- TERMS --- -Grant of License. Subject to payment of the applicable license fee, cacheplane +Grant of License. Subject to payment of the applicable license fee, ThreadPlane grants you a non-exclusive, non-transferable, worldwide license to use, reproduce, and distribute the Software solely as integrated into your applications, in accordance with the scope of the purchased tier. @@ -47,7 +47,7 @@ Restrictions. You may not: No Redistribution. You may not distribute the Software or make it available to third parties as a service, package, or SDK, whether modified or -unmodified, without a separate written agreement with cacheplane. +unmodified, without a separate written agreement with ThreadPlane. Warranty Disclaimer. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. CACHEPLANE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING @@ -66,5 +66,5 @@ Deschutes County, United States, without regard to conflict of law principles. --- PURCHASING --- To purchase a license or inquire about Enterprise terms: - Website: https://cacheplane.ai/pricing + Website: https://threadplane.ai/pricing Email: hello@cacheplane.ai diff --git a/apps/minting-service/README.md b/apps/minting-service/README.md index 2b3ed7f23..fd4c3fe06 100644 --- a/apps/minting-service/README.md +++ b/apps/minting-service/README.md @@ -1,6 +1,6 @@ # @cacheplane/minting-service -License minting service for Cacheplane. Receives Stripe webhooks, signs +License minting service for ThreadPlane. Receives Stripe webhooks, signs Ed25519 license tokens via `@cacheplane/licensing`, persists them to Postgres via `@cacheplane/db`, and emails them to customers via Resend. diff --git a/apps/minting-service/src/lib/email.spec.ts b/apps/minting-service/src/lib/email.spec.ts index 0931c56f4..edc039fdf 100644 --- a/apps/minting-service/src/lib/email.spec.ts +++ b/apps/minting-service/src/lib/email.spec.ts @@ -22,7 +22,7 @@ describe('renderLicenseEmail', () => { token: 't.s', expiresAt: new Date('2027-04-20T00:00:00Z'), }); - expect(out.subject).toBe('Your Cacheplane license — developer-seat (3 seats)'); + expect(out.subject).toBe('Your ThreadPlane license — developer-seat (3 seats)'); }); it('subject uses singular seat for seats === 1', () => { @@ -32,7 +32,7 @@ describe('renderLicenseEmail', () => { token: 't.s', expiresAt: new Date('2027-04-20T00:00:00Z'), }); - expect(out.subject).toBe('Your Cacheplane license — app-deployment (1 seat)'); + expect(out.subject).toBe('Your ThreadPlane license — app-deployment (1 seat)'); }); it('includes ISO 8601 UTC expiry in text body', () => { diff --git a/apps/minting-service/src/lib/email.ts b/apps/minting-service/src/lib/email.ts index 9ef683986..441d8dce8 100644 --- a/apps/minting-service/src/lib/email.ts +++ b/apps/minting-service/src/lib/email.ts @@ -20,10 +20,10 @@ export interface RenderedEmail { */ export function renderLicenseEmail(vars: LicenseEmailVars): RenderedEmail { const seatWord = vars.seats === 1 ? 'seat' : 'seats'; - const subject = `Your Cacheplane license — ${vars.tier} (${vars.seats} ${seatWord})`; + const subject = `Your ThreadPlane license — ${vars.tier} (${vars.seats} ${seatWord})`; const expiresIso = vars.expiresAt.toISOString(); - const text = `Thanks for subscribing to Cacheplane. + const text = `Thanks for subscribing to ThreadPlane. Your license token is below. Set it as the CACHEPLANE_LICENSE environment variable in your application: @@ -42,13 +42,13 @@ Installation: Or in a .env file: CACHEPLANE_LICENSE= -Docs: https://cacheplane.dev/docs/licensing +Docs: https://threadplane.ai/docs/licensing Questions: reply to this email. --- The Cacheplane team +-- The ThreadPlane team `; - const html = `

Thanks for subscribing to Cacheplane.

+ const html = `

Thanks for subscribing to ThreadPlane.

Your license token is below. Set it as the CACHEPLANE_LICENSE environment variable in your application:

-----BEGIN CACHEPLANE LICENSE-----
 ${escapeHtml(vars.token)}
@@ -58,9 +58,9 @@ ${escapeHtml(vars.token)}
 Expires: ${escapeHtml(expiresIso)}

Installation:

export CACHEPLANE_LICENSE="<paste token above>"
-

Docs: cacheplane.dev/docs/licensing
+

Docs: threadplane.ai/docs/licensing
Questions: reply to this email.

-

-- The Cacheplane team

+

-- The ThreadPlane team

`; return { subject, text, html }; diff --git a/apps/minting-service/src/lib/tier.ts b/apps/minting-service/src/lib/tier.ts index 801d0d6da..27dee632c 100644 --- a/apps/minting-service/src/lib/tier.ts +++ b/apps/minting-service/src/lib/tier.ts @@ -6,7 +6,7 @@ export type MintableTier = Extract | null | undefined): MintableTier { diff --git a/apps/website/content/AGENTS.md.template b/apps/website/content/AGENTS.md.template index a9b911704..a867ab1b6 100644 --- a/apps/website/content/AGENTS.md.template +++ b/apps/website/content/AGENTS.md.template @@ -40,4 +40,4 @@ export class ChatComponent { - Testing: use `MockAgentTransport` — never mock `agent()` itself ## Version check -If this file is stale, fetch the latest: https://cacheplane.ai/llms-full.txt +If this file is stale, fetch the latest: https://threadplane.ai/llms-full.txt diff --git a/apps/website/content/CLAUDE.md.template b/apps/website/content/CLAUDE.md.template index a9b911704..a867ab1b6 100644 --- a/apps/website/content/CLAUDE.md.template +++ b/apps/website/content/CLAUDE.md.template @@ -40,4 +40,4 @@ export class ChatComponent { - Testing: use `MockAgentTransport` — never mock `agent()` itself ## Version check -If this file is stale, fetch the latest: https://cacheplane.ai/llms-full.txt +If this file is stale, fetch the latest: https://threadplane.ai/llms-full.txt diff --git a/apps/website/content/docs/agent/api/api-docs.json b/apps/website/content/docs/agent/api/api-docs.json index 6280daabb..4e95aea37 100644 --- a/apps/website/content/docs/agent/api/api-docs.json +++ b/apps/website/content/docs/agent/api/api-docs.json @@ -575,7 +575,7 @@ { "name": "license", "type": "string", - "description": "Signed license token from cacheplane.dev. Optional; omitted in dev.", + "description": "Signed license token from threadplane.ai. Optional; omitted in dev.", "optional": true }, { diff --git a/apps/website/content/docs/chat/api/api-docs.json b/apps/website/content/docs/chat/api/api-docs.json index ea318860c..2a4a7b524 100644 --- a/apps/website/content/docs/chat/api/api-docs.json +++ b/apps/website/content/docs/chat/api/api-docs.json @@ -5555,7 +5555,7 @@ { "name": "license", "type": "string", - "description": "Signed license token from cacheplane.dev. Optional; omitted in dev.", + "description": "Signed license token from threadplane.ai. Optional; omitted in dev.", "optional": true }, { diff --git a/apps/website/content/docs/chat/api/chat-config.mdx b/apps/website/content/docs/chat/api/chat-config.mdx index aab09dfa3..4a7d04192 100644 --- a/apps/website/content/docs/chat/api/chat-config.mdx +++ b/apps/website/content/docs/chat/api/chat-config.mdx @@ -19,7 +19,7 @@ interface ChatConfig { avatarLabel?: string; /** Shared assistant display name for consumers that read CHAT_CONFIG (default: "Assistant"). */ assistantName?: string; - /** Signed license token from cacheplane.dev. Optional; omitted in dev. */ + /** Signed license token from threadplane.ai. Optional; omitted in dev. */ license?: string; } ``` @@ -80,7 +80,7 @@ provideChat({ renderRegistry }); license?: string ``` -A signed license token from cacheplane.dev. It is optional in development and should be provided from your production configuration. +A signed license token from threadplane.ai. It is optional in development and should be provided from your production configuration. **Example:** diff --git a/apps/website/content/docs/chat/getting-started/introduction.mdx b/apps/website/content/docs/chat/getting-started/introduction.mdx index 5940ecfee..ff0d83c4c 100644 --- a/apps/website/content/docs/chat/getting-started/introduction.mdx +++ b/apps/website/content/docs/chat/getting-started/introduction.mdx @@ -3,7 +3,7 @@ `@ngaf/chat` is the Angular UI component library for building chat interfaces on top of a runtime-neutral `Agent` contract. It provides a complete set of composable, Signal-driven components that render messages, handle user input, display tool calls, manage interrupts, and support generative UI -- all styled with CSS custom properties and built for Angular 20+. -This guide explains the library's two-tier architecture, how it relates to the rest of the Cacheplane stack, and when to reach for the all-in-one composition versus assembling primitives yourself. +This guide explains the library's two-tier architecture, how it relates to the rest of the ThreadPlane stack, and when to reach for the all-in-one composition versus assembling primitives yourself. ## Two-Tier Architecture @@ -42,7 +42,7 @@ Compositions are opinionated, styled components that combine primitives into rea ## How the Stack Fits Together -`@ngaf/chat` sits between your application and two other Cacheplane libraries: +`@ngaf/chat` sits between your application and two other ThreadPlane libraries: ``` Your App diff --git a/apps/website/content/docs/chat/guides/configuration.mdx b/apps/website/content/docs/chat/guides/configuration.mdx index a5f1a3522..834d0154d 100644 --- a/apps/website/content/docs/chat/guides/configuration.mdx +++ b/apps/website/content/docs/chat/guides/configuration.mdx @@ -44,7 +44,7 @@ interface ChatConfig { /** Override the default assistant display name (default: "Assistant"). */ assistantName?: string; - /** Signed license token from cacheplane.dev. Optional in development. */ + /** Signed license token from threadplane.ai. Optional in development. */ license?: string; } ``` diff --git a/apps/website/content/docs/licensing/guides/setup.mdx b/apps/website/content/docs/licensing/guides/setup.mdx index 2de2add48..fe80f35ba 100644 --- a/apps/website/content/docs/licensing/guides/setup.mdx +++ b/apps/website/content/docs/licensing/guides/setup.mdx @@ -48,7 +48,7 @@ It warns once per package and status for: - `expired`; - `tampered`. -The warning prefix is `[cacheplane]`, and the package keeps running. +The warning prefix is `[threadplane]`, and the package keeps running. You can inject a custom warning sink: diff --git a/apps/website/content/docs/render/api/api-docs.json b/apps/website/content/docs/render/api/api-docs.json index faee0368f..f7f500d39 100644 --- a/apps/website/content/docs/render/api/api-docs.json +++ b/apps/website/content/docs/render/api/api-docs.json @@ -266,7 +266,7 @@ { "name": "license", "type": "string", - "description": "Signed license token from cacheplane.dev. Optional; omitted in dev.", + "description": "Signed license token from threadplane.ai. Optional; omitted in dev.", "optional": true }, { diff --git a/apps/website/content/docs/telemetry/guides/node.mdx b/apps/website/content/docs/telemetry/guides/node.mdx index bf6463880..733ce4bda 100644 --- a/apps/website/content/docs/telemetry/guides/node.mdx +++ b/apps/website/content/docs/telemetry/guides/node.mdx @@ -65,7 +65,7 @@ await captureStreamErrored({ `captureEvent()` sends to: ```text -https://cacheplane.ai/api/ingest +https://threadplane.ai/api/ingest ``` unless `NGAF_TELEMETRY_INGEST_URL` is set. diff --git a/apps/website/content/docs/telemetry/reference/events.mdx b/apps/website/content/docs/telemetry/reference/events.mdx index a7f26b179..1f9642469 100644 --- a/apps/website/content/docs/telemetry/reference/events.mdx +++ b/apps/website/content/docs/telemetry/reference/events.mdx @@ -86,4 +86,4 @@ Node delivery sends: } ``` -The public ingest key is a routing identifier accepted by the Cacheplane ingest proxy. It is not a secret. +The public ingest key is a routing identifier accepted by the ThreadPlane ingest proxy. It is not a secret. diff --git a/apps/website/e2e/primitives.spec.ts b/apps/website/e2e/primitives.spec.ts index 7f9362523..3d008f780 100644 --- a/apps/website/e2e/primitives.spec.ts +++ b/apps/website/e2e/primitives.spec.ts @@ -46,7 +46,7 @@ test.describe('UI primitives showcase', () => { test('renders BrowserFrame with URL pill', async ({ page }) => { const frame = page.locator('[data-ui="browser-frame"]'); await expect(frame).toBeVisible(); - await expect(frame).toContainText('cockpit.cacheplane.ai'); + await expect(frame).toContainText('cockpit.threadplane.ai'); }); test('renders Section with tinted surface variant', async ({ page }) => { diff --git a/apps/website/e2e/website.spec.ts b/apps/website/e2e/website.spec.ts index a35ec5e44..d99e768eb 100644 --- a/apps/website/e2e/website.spec.ts +++ b/apps/website/e2e/website.spec.ts @@ -95,7 +95,7 @@ test('robots.txt allows crawling and points at the sitemap', async ({ request }) const body = await response.text(); expect(body).toContain('User-Agent: *'); expect(body).toContain('Allow: /'); - expect(body).toContain('Sitemap: https://cacheplane.ai/sitemap.xml'); + expect(body).toContain('Sitemap: https://threadplane.ai/sitemap.xml'); }); test('sitemap.xml includes configured docs pages', async ({ request }) => { @@ -103,9 +103,9 @@ test('sitemap.xml includes configured docs pages', async ({ request }) => { expect(response.ok()).toBe(true); const body = await response.text(); - expect(body).toContain('https://cacheplane.ai/docs'); - expect(body).toContain('https://cacheplane.ai/docs/agent/getting-started/introduction'); - expect(body).toContain('https://cacheplane.ai/docs/render/a2ui/overview'); + expect(body).toContain('https://threadplane.ai/docs'); + expect(body).toContain('https://threadplane.ai/docs/agent/getting-started/introduction'); + expect(body).toContain('https://threadplane.ai/docs/render/a2ui/overview'); }); test('docs pages render canonical and social metadata', async ({ page }) => { @@ -113,7 +113,7 @@ test('docs pages render canonical and social metadata', async ({ page }) => { await expect(page.locator('link[rel="canonical"]')).toHaveAttribute( 'href', - 'https://cacheplane.ai/docs/agent/guides/streaming', + 'https://threadplane.ai/docs/agent/guides/streaming', ); await expect(page.locator('meta[property="og:title"]')).toHaveAttribute( 'content', @@ -121,7 +121,7 @@ test('docs pages render canonical and social metadata', async ({ page }) => { ); await expect(page.locator('meta[property="og:url"]')).toHaveAttribute( 'content', - 'https://cacheplane.ai/docs/agent/guides/streaming', + 'https://threadplane.ai/docs/agent/guides/streaming', ); await expect(page.locator('meta[name="twitter:title"]')).toHaveAttribute( 'content', diff --git a/apps/website/emails/angular-download.ts b/apps/website/emails/angular-download.ts index 161d3c11a..31093ee78 100644 --- a/apps/website/emails/angular-download.ts +++ b/apps/website/emails/angular-download.ts @@ -1,6 +1,6 @@ import { wrapEmail, esc } from './email-wrapper'; -const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/angular.pdf'; +const DOWNLOAD_URL = 'https://threadplane.ai/whitepapers/angular.pdf'; export function angularDownloadHtml(name?: string): string { return wrapEmail({ diff --git a/apps/website/emails/chat-download.ts b/apps/website/emails/chat-download.ts index f4e497062..64de83197 100644 --- a/apps/website/emails/chat-download.ts +++ b/apps/website/emails/chat-download.ts @@ -1,6 +1,6 @@ import { wrapEmail, esc } from './email-wrapper'; -const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/chat.pdf'; +const DOWNLOAD_URL = 'https://threadplane.ai/whitepapers/chat.pdf'; export function chatDownloadHtml(name?: string): string { return wrapEmail({ diff --git a/apps/website/emails/drip-angular-followup.ts b/apps/website/emails/drip-angular-followup.ts index 42d03bd20..145470dff 100644 --- a/apps/website/emails/drip-angular-followup.ts +++ b/apps/website/emails/drip-angular-followup.ts @@ -9,7 +9,7 @@ export function dripAngularFollowupHtml(day: number): { subject: string; html: s

Angular Guide Follow-up

Did you read Chapter 2 on the agent() API?

Chapter 2 dives into the agent() API — the signal-native primitive that connects your Angular component directly to a LangGraph streaming run. It's the chapter most teams bookmark first when they see how little boilerplate is required.

- Read the Docs → + Read the Docs → `, showUnsubscribe: true, }), @@ -24,7 +24,7 @@ export function dripAngularFollowupHtml(day: number): { subject: string; html: s

Comparison

LangGraph Angular SDK vs @ngaf/langgraph

The LangGraph JS SDK gives you a streaming client. @ngaf/langgraph gives you signal-native state, thread persistence, interrupt flows, and a full test harness — all wired together and optimized for Angular's change detection model. See the full comparison on our product page.

- See the Comparison → + See the Comparison → `, showUnsubscribe: true, }), @@ -44,7 +44,7 @@ export function dripAngularFollowupHtml(day: number): { subject: string; html: s

Month 1 · First agent in staging

Month 3 · Production deployment

- Learn About the Pilot → + Learn About the Pilot → `, showUnsubscribe: true, }), diff --git a/apps/website/emails/drip-chat-followup.ts b/apps/website/emails/drip-chat-followup.ts index 2e6dd462b..e61d144a5 100644 --- a/apps/website/emails/drip-chat-followup.ts +++ b/apps/website/emails/drip-chat-followup.ts @@ -9,7 +9,7 @@ export function dripChatFollowupHtml(day: number): { subject: string; html: stri

Chat Guide Follow-up

Did you read Chapter 2 on batteries-included components?

Chapter 2 covers the batteries-included component library — message bubbles, streaming indicators, thread lists, and input controls that are pre-wired to LangGraph state. Drop them in and your chat UI works on day one.

- Read the Docs → + Read the Docs → `, showUnsubscribe: true, }), @@ -24,7 +24,7 @@ export function dripChatFollowupHtml(day: number): { subject: string; html: stri

The Sprint Tax

The sprint tax: why every team rebuilds chat from scratch

Most teams spend 2–4 sprints building a chat UI before a single agent feature lands. Streaming state management, optimistic updates, thread history, error recovery — it's the same work every time. @ngaf/chat eliminates the sprint tax so your team ships features from day one.

- See How It Works → + See How It Works → `, showUnsubscribe: true, }), @@ -44,7 +44,7 @@ export function dripChatFollowupHtml(day: number): { subject: string; html: stri

Month 1 · First agent in staging

Month 3 · Production deployment

- Learn About the Pilot → + Learn About the Pilot → `, showUnsubscribe: true, }), diff --git a/apps/website/emails/drip-render-followup.ts b/apps/website/emails/drip-render-followup.ts index 4583b4934..d9989f64a 100644 --- a/apps/website/emails/drip-render-followup.ts +++ b/apps/website/emails/drip-render-followup.ts @@ -9,7 +9,7 @@ export function dripRenderFollowupHtml(day: number): { subject: string; html: st

Render Guide Follow-up

Did you read Chapter 2 on declarative UI specs?

Chapter 2 covers declarative UI specs — how agents emit structured JSON that maps directly to your component registry instead of generating raw HTML. It's the foundation that makes generative UI predictable and testable.

- Read the Docs → + Read the Docs → `, showUnsubscribe: true, }), @@ -24,7 +24,7 @@ export function dripRenderFollowupHtml(day: number): { subject: string; html: st

Architecture

Why tight coupling between agents and UI kills iteration speed

When an agent generates UI directly — raw HTML, string templates, hardcoded component names — every model change breaks the frontend and every UI change breaks the prompt. Decoupling via a declarative spec layer means agents and UI teams can iterate independently. See how @ngaf/render makes this the default.

- See How It Works → + See How It Works → `, showUnsubscribe: true, }), @@ -44,7 +44,7 @@ export function dripRenderFollowupHtml(day: number): { subject: string; html: st

Month 1 · First agent in staging

Month 3 · Production deployment

- Learn About the Pilot → + Learn About the Pilot → `, showUnsubscribe: true, }), diff --git a/apps/website/emails/drip-whitepaper-followup.ts b/apps/website/emails/drip-whitepaper-followup.ts index 8a6ec7472..ca8b71356 100644 --- a/apps/website/emails/drip-whitepaper-followup.ts +++ b/apps/website/emails/drip-whitepaper-followup.ts @@ -9,7 +9,7 @@ export function dripWhitepaperFollowupHtml(day: number): { subject: string; html

Whitepaper Follow-up

Did you get a chance to read Chapter 3?

Chapter 3 covers tool-call rendering — how to surface agent actions as real UI instead of raw JSON. It's the chapter most teams bookmark first.

- Read the Guide → + Read the Guide → `, showUnsubscribe: true, }), @@ -24,7 +24,7 @@ export function dripWhitepaperFollowupHtml(day: number): { subject: string; html

Production Readiness

The gap between demo and production

Half of GenAI projects die after proof of concept. The gap isn't the model — it's the frontend production path: streaming state, thread persistence, human approval flows, and deterministic testing.

- See How It Works → + See How It Works → `, showUnsubscribe: true, }), @@ -44,7 +44,7 @@ export function dripWhitepaperFollowupHtml(day: number): { subject: string; html

Month 1 · First agent in staging

Month 3 · Production deployment

- Learn About the Pilot → + Learn About the Pilot → `, showUnsubscribe: true, }), diff --git a/apps/website/emails/email-wrapper.ts b/apps/website/emails/email-wrapper.ts index 44c5772e4..499589bac 100644 --- a/apps/website/emails/email-wrapper.ts +++ b/apps/website/emails/email-wrapper.ts @@ -19,7 +19,7 @@ export function wrapEmail(opts: { ${opts.body}

Agent UI for Angular — Signal-native streaming for LangGraph.

- ${opts.showUnsubscribe ? '

Unsubscribe

' : ''} + ${opts.showUnsubscribe ? '

Unsubscribe

' : ''}
diff --git a/apps/website/emails/newsletter-welcome.ts b/apps/website/emails/newsletter-welcome.ts index bd87a1cd7..a7ef2b8c9 100644 --- a/apps/website/emails/newsletter-welcome.ts +++ b/apps/website/emails/newsletter-welcome.ts @@ -5,7 +5,7 @@ export function newsletterWelcomeHtml(): string { body: `

Welcome to Agent UI for Angular updates

You'll receive updates on new capabilities, production patterns, and Angular agent best practices. We keep it focused and infrequent — no spam.

- Explore the Docs + Explore the Docs `, }); } diff --git a/apps/website/emails/render-download.ts b/apps/website/emails/render-download.ts index e87c75c31..5c808af84 100644 --- a/apps/website/emails/render-download.ts +++ b/apps/website/emails/render-download.ts @@ -1,6 +1,6 @@ import { wrapEmail, esc } from './email-wrapper'; -const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/render.pdf'; +const DOWNLOAD_URL = 'https://threadplane.ai/whitepapers/render.pdf'; export function renderDownloadHtml(name?: string): string { return wrapEmail({ diff --git a/apps/website/emails/whitepaper-download.ts b/apps/website/emails/whitepaper-download.ts index 5a1978fe9..78879de2c 100644 --- a/apps/website/emails/whitepaper-download.ts +++ b/apps/website/emails/whitepaper-download.ts @@ -1,6 +1,6 @@ import { wrapEmail, esc } from './email-wrapper'; -const DOWNLOAD_URL = 'https://cacheplane.ai/whitepaper.pdf'; +const DOWNLOAD_URL = 'https://threadplane.ai/whitepaper.pdf'; export function whitepaperDownloadHtml(name?: string): string { return wrapEmail({ diff --git a/apps/website/lib/resend.ts b/apps/website/lib/resend.ts index a95e9f2bb..f073b3fbc 100644 --- a/apps/website/lib/resend.ts +++ b/apps/website/lib/resend.ts @@ -11,8 +11,8 @@ function getResend(): Resend | null { } export const AUDIENCE_ID = process.env.RESEND_AUDIENCE_ID || ''; -export const FROM = process.env.RESEND_FROM || 'Agent UI for Angular '; -export const NOTIFY_TO = process.env.RESEND_NOTIFY_TO || 'hello@cacheplane.io'; +export const FROM = process.env.RESEND_FROM || 'Agent UI for Angular '; +export const NOTIFY_TO = process.env.RESEND_NOTIFY_TO || 'hello@cacheplane.ai'; /** Send an email via Resend. No-ops when API key is missing. */ export async function sendEmail(opts: { from: string; to: string; subject: string; html: string; scheduledAt?: string }) { diff --git a/apps/website/public/AGENTS.md b/apps/website/public/AGENTS.md index 6c894c853..7d6935072 100644 --- a/apps/website/public/AGENTS.md +++ b/apps/website/public/AGENTS.md @@ -40,4 +40,4 @@ export class ChatComponent { - Testing: use `MockAgentTransport` — never mock `agent()` itself ## Version check -If this file is stale, fetch the latest: https://cacheplane.ai/llms-full.txt +If this file is stale, fetch the latest: https://threadplane.ai/llms-full.txt diff --git a/apps/website/public/CLAUDE.md b/apps/website/public/CLAUDE.md index 6c894c853..7d6935072 100644 --- a/apps/website/public/CLAUDE.md +++ b/apps/website/public/CLAUDE.md @@ -40,4 +40,4 @@ export class ChatComponent { - Testing: use `MockAgentTransport` — never mock `agent()` itself ## Version check -If this file is stale, fetch the latest: https://cacheplane.ai/llms-full.txt +If this file is stale, fetch the latest: https://threadplane.ai/llms-full.txt diff --git a/apps/website/public/assets/hero.svg b/apps/website/public/assets/hero.svg index b64ae1feb..2c3f1d39f 100644 --- a/apps/website/public/assets/hero.svg +++ b/apps/website/public/assets/hero.svg @@ -13,7 +13,7 @@ font-weight="700" letter-spacing="-2" fill="#EEF1FF" - >cacheplane + >threadplane @ngaf/langgraph · Production Readiness Guide

From
Prototype
to
Production

The Angular Agent Readiness Guide

-
cacheplane.ai · 2026
+
threadplane.ai · 2026
diff --git a/apps/website/public/whitepapers/angular-preview.html b/apps/website/public/whitepapers/angular-preview.html index 665efb33a..e5f2695aa 100644 --- a/apps/website/public/whitepapers/angular-preview.html +++ b/apps/website/public/whitepapers/angular-preview.html @@ -23,7 +23,7 @@
@ngaf/langgraph · Enterprise Guide

The
Enterprise
Guide
to
Agent
Streaming
in
Angular

Ship LangGraph agents in Angular — without building the plumbing

-
cacheplane.ai · 2026
+
threadplane.ai · 2026
diff --git a/apps/website/public/whitepapers/chat-preview.html b/apps/website/public/whitepapers/chat-preview.html index 1753b138d..cf920a5c9 100644 --- a/apps/website/public/whitepapers/chat-preview.html +++ b/apps/website/public/whitepapers/chat-preview.html @@ -23,7 +23,7 @@
@ngaf/chat · Enterprise Guide

The
Enterprise
Guide
to
Agent
Chat
Interfaces
in
Angular

Production agent chat UI in days, not sprints

-
cacheplane.ai · 2026
+
threadplane.ai · 2026
diff --git a/apps/website/public/whitepapers/render-preview.html b/apps/website/public/whitepapers/render-preview.html index 4317523bd..ffe5a1ba6 100644 --- a/apps/website/public/whitepapers/render-preview.html +++ b/apps/website/public/whitepapers/render-preview.html @@ -23,7 +23,7 @@
@ngaf/render · Enterprise Guide

The
Enterprise
Guide
to
Generative
UI
in
Angular

Agents that render UI — without coupling to your frontend

-
cacheplane.ai · 2026
+
threadplane.ai · 2026
diff --git a/apps/website/scripts/capture-screenshots.ts b/apps/website/scripts/capture-screenshots.ts index a32db0570..b630bfd43 100644 --- a/apps/website/scripts/capture-screenshots.ts +++ b/apps/website/scripts/capture-screenshots.ts @@ -2,7 +2,7 @@ * Capture product screenshots from the live cockpit demo * for use in the marketing site's BrowserFrame placeholders. * - * Captures cockpit.cacheplane.ai in each of its 4 modes (Run, Code, + * Captures cockpit.threadplane.ai in each of its 4 modes (Run, Code, * Docs, API) at 2× DPR, then crops the cockpit content well, optimizes * to WebP, and writes to apps/website/public/screenshots/. * @@ -10,7 +10,7 @@ * pnpm tsx apps/website/scripts/capture-screenshots.ts * * Optional flags: - * --url Override the cockpit URL (default cockpit.cacheplane.ai) + * --url Override the cockpit URL (default cockpit.threadplane.ai) * --keep-png Keep the intermediate PNG files (for debugging) * * The script is idempotent — it overwrites existing files in @@ -25,7 +25,7 @@ import { dirname, join } from 'node:path'; import { existsSync } from 'node:fs'; const DEFAULT_COCKPIT_URL = - 'https://cockpit.cacheplane.ai/langgraph/core-capabilities/streaming/overview/python'; + 'https://cockpit.threadplane.ai/langgraph/core-capabilities/streaming/overview/python'; interface CaptureTarget { /** Output filename (without extension). */ diff --git a/apps/website/scripts/generate-whitepaper.ts b/apps/website/scripts/generate-whitepaper.ts index 8d1ad7a07..67dd779de 100644 --- a/apps/website/scripts/generate-whitepaper.ts +++ b/apps/website/scripts/generate-whitepaper.ts @@ -11,7 +11,7 @@ if (!process.env['ANTHROPIC_API_KEY'] && loadEnvFile && fs.existsSync('.env')) { const client = new Anthropic(); const MODEL = process.env['ANTHROPIC_MODEL'] ?? 'claude-opus-4-5'; -const CURRENT_API_CONTEXT = `You are writing public technical whitepapers for Cacheplane Agent UI for Angular. +const CURRENT_API_CONTEXT = `You are writing public technical whitepapers for ThreadPlane Agent UI for Angular. Use only the current API surface: - Package names are @ngaf/langgraph, @ngaf/render, @ngaf/chat, and @ngaf/ag-ui. @@ -601,7 +601,7 @@ function buildHTML(
${config.eyebrow}

${config.title.replace(/ /g, '
')}

${config.subtitle}

-
cacheplane.ai · ${new Date().getFullYear()}
+
threadplane.ai · ${new Date().getFullYear()}
@@ -681,7 +681,7 @@ async function generateWhitepaper(config: WhitepaperConfig): Promise { // ── Main ───────────────────────────────────────────────────────────────── async function main() { - console.log('Cacheplane White Paper Generator\n'); + console.log('ThreadPlane White Paper Generator\n'); console.log(`Model: ${MODEL}`); const paperArg = process.argv.find(a => a.startsWith('--paper='))?.split('=')[1] diff --git a/apps/website/src/app/api/email-preview/route.ts b/apps/website/src/app/api/email-preview/route.ts index 64a6b1847..273198076 100644 --- a/apps/website/src/app/api/email-preview/route.ts +++ b/apps/website/src/app/api/email-preview/route.ts @@ -20,7 +20,7 @@ const TEMPLATES: Record { subject: string; html: string }> = { html: newsletterWelcomeHtml(), }), 'lead-notification': () => ({ - subject: 'New lead: Brian at Cacheplane', + subject: 'New lead: Brian at ThreadPlane', html: leadNotificationHtml({ name: 'Sample Lead', email: 'demo@example.com', diff --git a/apps/website/src/app/api/ingest/route.spec.ts b/apps/website/src/app/api/ingest/route.spec.ts index 950ebc872..96a4ff08e 100644 --- a/apps/website/src/app/api/ingest/route.spec.ts +++ b/apps/website/src/app/api/ingest/route.spec.ts @@ -20,7 +20,7 @@ describe('/api/ingest', () => { it('accepts neutral browser telemetry payloads without requiring the public ingest key', async () => { shutdown.mockResolvedValue(undefined); - const response = await POST(new Request('https://cacheplane.ai/api/ingest', { + const response = await POST(new Request('https://threadplane.ai/api/ingest', { method: 'POST', body: JSON.stringify({ event: 'ngaf:browser_chat_init', diff --git a/apps/website/src/app/blog/[slug]/opengraph-image.tsx b/apps/website/src/app/blog/[slug]/opengraph-image.tsx index 273624fff..6ab822c68 100644 --- a/apps/website/src/app/blog/[slug]/opengraph-image.tsx +++ b/apps/website/src/app/blog/[slug]/opengraph-image.tsx @@ -3,7 +3,7 @@ import { getPostBySlug } from '../../../lib/blog'; import { getAuthor } from '../../../lib/blog-authors'; export const runtime = 'nodejs'; -export const alt = 'Cacheplane blog post'; +export const alt = 'ThreadPlane blog post'; export const size = { width: 1200, height: 630 }; export const contentType = 'image/png'; @@ -61,7 +61,7 @@ export default async function og({ params }: Params) { fontSize: 64, }} > - Cacheplane + ThreadPlane ), size, @@ -103,7 +103,7 @@ export default async function og({ params }: Params) { opacity: 0.6, }} > - Cacheplane Blog + ThreadPlane Blog
{ const { slug } = await params; const post = getPostBySlug(slug); if (!post || post.frontmatter.draft) { - return { title: 'Post not found — Cacheplane' }; + return { title: 'Post not found — ThreadPlane' }; } return createPageMetadata({ - title: `${post.frontmatter.title} — Cacheplane`, + title: `${post.frontmatter.title} — ThreadPlane`, description: post.frontmatter.description, pathname: `/blog/${post.slug}`, type: 'article', diff --git a/apps/website/src/app/blog/page.tsx b/apps/website/src/app/blog/page.tsx index 6aba612a3..469c2202a 100644 --- a/apps/website/src/app/blog/page.tsx +++ b/apps/website/src/app/blog/page.tsx @@ -5,7 +5,7 @@ import { PostCard } from '../../components/blog/PostCard'; import { TagChips } from '../../components/blog/TagChips'; export const metadata = createPageMetadata({ - title: 'Blog — Cacheplane', + title: 'Blog — ThreadPlane', description: 'Long-form writing on agent UI for Angular: streaming, generative UI, threads, interrupts, production patterns.', pathname: '/blog', @@ -39,7 +39,7 @@ export default function BlogIndexPage() { marginBottom: 12, }} > - Notes from Cacheplane + Notes from ThreadPlane

Writing on agent UI for Angular — production patterns, design choices, diff --git a/apps/website/src/app/blog/rss.xml/route.ts b/apps/website/src/app/blog/rss.xml/route.ts index a411f4aa7..bab3ed0d7 100644 --- a/apps/website/src/app/blog/rss.xml/route.ts +++ b/apps/website/src/app/blog/rss.xml/route.ts @@ -31,7 +31,7 @@ export async function GET() { const xml = ` - ${escapeXml('Cacheplane Blog')} + ${escapeXml('ThreadPlane Blog')} ${SITE_ORIGIN}/blog ${escapeXml('Writing on agent UI for Angular.')} diff --git a/apps/website/src/app/chat/page.tsx b/apps/website/src/app/chat/page.tsx index 1f7fe30ae..6512f544a 100644 --- a/apps/website/src/app/chat/page.tsx +++ b/apps/website/src/app/chat/page.tsx @@ -52,7 +52,7 @@ export default async function ChatPage() {

-
@@ -83,7 +83,7 @@ export default async function ChatPage() { ]} cta={{ label: 'See @ngaf/chat docs', href: '/docs/chat/getting-started/introduction' }} visual={ - +
streaming diff --git a/apps/website/src/app/contact/page.tsx b/apps/website/src/app/contact/page.tsx index d036c8c10..f50eaec85 100644 --- a/apps/website/src/app/contact/page.tsx +++ b/apps/website/src/app/contact/page.tsx @@ -11,11 +11,11 @@ import { SlaCard } from '../../components/contact/SlaCard'; import { AltChannelRow } from '../../components/contact/AltChannelRow'; export const metadata: Metadata = { - title: 'Talk to an engineer — Cacheplane', + title: 'Talk to an engineer — ThreadPlane', description: "Tell us what you're shipping. We'll reply within one business day — usually with code, not a calendar invite.", openGraph: { - title: 'Talk to an engineer — Cacheplane', + title: 'Talk to an engineer — ThreadPlane', description: "Tell us what you're shipping. We'll reply within one business day.", type: 'website', }, diff --git a/apps/website/src/app/dev/primitives/page.tsx b/apps/website/src/app/dev/primitives/page.tsx index 0bddebcfc..0d15dff5f 100644 --- a/apps/website/src/app/dev/primitives/page.tsx +++ b/apps/website/src/app/dev/primitives/page.tsx @@ -89,7 +89,7 @@ export default function PrimitivesDevPage() {

BrowserFrame

- +
🛩️ - cacheplane.ai + threadplane.ai
diff --git a/apps/website/src/app/page.tsx b/apps/website/src/app/page.tsx index e5eb3fff4..64288c248 100644 --- a/apps/website/src/app/page.tsx +++ b/apps/website/src/app/page.tsx @@ -41,7 +41,7 @@ export default async function HomePage() { ]} cta={{ label: 'Read the streaming guide', href: '/docs/agent/api/agent' }} visual={ - + Cockpit reference app — Angular streaming guide with provideAgent setup + Cockpit reference app — API reference rendered as structured cards + Cockpit reference app — live chat surface ready to receive a message { fetchMock.mockReset(); vi.stubGlobal('fetch', fetchMock); Object.defineProperty(document, 'referrer', { - value: 'https://cacheplane.ai/pricing', + value: 'https://threadplane.ai/pricing', configurable: true, }); }); @@ -55,7 +55,7 @@ describe('ContactForm', () => { expect(body.email).toBe('jane@acme.com'); expect(body.source_page).toBe('home_hero'); expect(body.track).toBe('enterprise'); - expect(body.referrer_host).toBe('cacheplane.ai'); + expect(body.referrer_host).toBe('threadplane.ai'); expect(trackMock).toHaveBeenCalledWith( 'marketing:lead_form_submit', diff --git a/apps/website/src/components/landing/FinalCTA.tsx b/apps/website/src/components/landing/FinalCTA.tsx index 105e51c2f..c60d4c125 100644 --- a/apps/website/src/components/landing/FinalCTA.tsx +++ b/apps/website/src/components/landing/FinalCTA.tsx @@ -8,7 +8,7 @@ interface FinalCTAProps { headline?: string; /** Sub-headline. Defaults to the homepage closer. */ subtext?: string; - /** Primary CTA. Defaults to "Try the demo →" → demo.cacheplane.ai. */ + /** Primary CTA. Defaults to "Try the demo →" → demo.threadplane.ai. */ primary?: { label: string; href: string; external?: boolean }; /** Optional secondary CTA. Defaults to "See each feature in action →" → cockpit. */ secondary?: { label: string; href: string; external?: boolean } | null; @@ -16,8 +16,8 @@ interface FinalCTAProps { caption?: string | null; } -const DEFAULT_PRIMARY = { label: 'Try the demo →', href: 'https://demo.cacheplane.ai', external: true }; -const DEFAULT_SECONDARY = { label: 'See each feature in action →', href: 'https://cockpit.cacheplane.ai', external: true }; +const DEFAULT_PRIMARY = { label: 'Try the demo →', href: 'https://demo.threadplane.ai', external: true }; +const DEFAULT_SECONDARY = { label: 'See each feature in action →', href: 'https://cockpit.threadplane.ai', external: true }; export function FinalCTA({ headline = 'Stop stalling on agentic Angular.', diff --git a/apps/website/src/components/landing/Hero.tsx b/apps/website/src/components/landing/Hero.tsx index 7b1a4f778..216ea86c3 100644 --- a/apps/website/src/components/landing/Hero.tsx +++ b/apps/website/src/components/landing/Hero.tsx @@ -137,14 +137,14 @@ export function Hero() { maxWidth: '60ch', }} > - Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. Cacheplane solves the Angular UI layer. + Not another backend agent runtime. Keep LangGraph, Genkit, Mastra, CrewAI, or your own service. ThreadPlane solves the Angular UI layer.

{/* Right column — layered collage (preserved verbatim from prior Hero.tsx) */}