feat(06-02): replace Paperclip brand + CEO display strings in UI components

- AgentDetail: 10 strings replaced (Paperclip→VOCAB.appName, CEO→VOCAB.ceo, board approval→owner approval)
- RoutineDetail: 8 error messages + select company + secret banner replaced
- DesignGuide: 3 strings replaced (Paperclip, Paperclip App, CEO Agent)
- agent-config-primitives: 3 tooltip strings replaced
- AccountingModelCard, JsonSchemaForm, ProjectProperties, OnboardingWizard: 1 each
- openclaw-gateway/config-fields: 2 strings replaced
- Added VOCAB import to all files missing it
This commit is contained in:
Mikkel Georgsen 2026-03-31 13:25:46 +02:00
parent cb5d14d6f8
commit 31c9fe8671
10 changed files with 40 additions and 33 deletions

View file

@ -1,4 +1,5 @@
import { useState } from "react";
import { VOCAB } from "@paperclipai/branding";
import { Eye, EyeOff } from "lucide-react";
import type { AdapterConfigFieldsProps } from "../types";
import {
@ -134,7 +135,7 @@ export function OpenClawGatewayConfigFields({
{!isCreate && (
<>
<Field label="Paperclip API URL override">
<Field label={`${VOCAB.appName} API URL override`}>
<DraftInput
value={
eff(
@ -226,7 +227,7 @@ export function OpenClawGatewayConfigFields({
<Field label="Device auth">
<div className="text-xs text-muted-foreground leading-relaxed">
Always enabled for gateway agents. Paperclip persists a device key during onboarding so pairing approvals
{`Always enabled for gateway agents. ${VOCAB.appName} persists a device key during onboarding so pairing approvals`}
remain stable across runs.
</div>
</Field>

View file

@ -1,4 +1,5 @@
import { Database, Gauge, ReceiptText } from "lucide-react";
import { VOCAB } from "@paperclipai/branding";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
const SURFACES = [
@ -34,7 +35,7 @@ export function AccountingModelCard() {
Accounting model
</CardTitle>
<CardDescription className="max-w-2xl text-sm leading-6">
Paperclip now separates request-level inference usage from account-level finance events.
{`${VOCAB.appName} now separates request-level inference usage from account-level finance events.`}
That keeps provider reporting honest when the biller is OpenRouter, Cloudflare, Bedrock, or another intermediary.
</CardDescription>
</CardHeader>

View file

@ -1,4 +1,5 @@
import React, { useCallback, useMemo, useState } from "react";
import { VOCAB } from "@paperclipai/branding";
import {
ChevronDown,
ChevronRight,
@ -494,7 +495,7 @@ const SecretField = React.memo(({
label={label}
description={
description ||
"This secret is stored securely via the Paperclip secret provider."
`This secret is stored securely via the ${VOCAB.appName} secret provider.`
}
required={isRequired}
error={error}

View file

@ -1051,7 +1051,7 @@ export function OnboardingWizard() {
<p className="text-[11px] text-amber-900/90 leading-relaxed">
Claude failed while{" "}
<span className="font-mono">ANTHROPIC_API_KEY</span>{" "}
is set. You can clear it in this CEO adapter config
is set. You can clear it in this {VOCAB.ceo} adapter config
and retry the probe.
</p>
<Button

View file

@ -1,4 +1,5 @@
import { useState } from "react";
import { VOCAB } from "@paperclipai/branding";
import { Link } from "@/lib/router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { Project } from "@paperclipai/shared";
@ -687,7 +688,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
{codebase.effectiveLocalFolder}
</div>
{codebase.origin === "managed_checkout" && (
<div className="text-[11px] text-muted-foreground">Paperclip-managed folder.</div>
<div className="text-[11px] text-muted-foreground">{`${VOCAB.appName}-managed folder.`}</div>
)}
</div>
<div className="flex items-center gap-1">
@ -719,7 +720,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
{hasAdditionalLegacyWorkspaces && (
<div className="text-[11px] text-muted-foreground">
Additional legacy workspace records exist on this project. Paperclip is using the primary workspace as the codebase view.
{`Additional legacy workspace records exist on this project. ${VOCAB.appName} is using the primary workspace as the codebase view.`}
</div>
)}

View file

@ -1,4 +1,5 @@
import { useState, useRef, useEffect, useCallback } from "react";
import { VOCAB } from "@paperclipai/branding";
import {
Tooltip,
TooltipTrigger,
@ -33,7 +34,7 @@ export const help: Record<string, string> = {
dangerouslySkipPermissions: "Run unattended by auto-approving adapter permission prompts when supported.",
dangerouslyBypassSandbox: "Run Codex without sandbox restrictions. Required for filesystem/network access.",
search: "Enable Codex web search capability during runs.",
workspaceStrategy: "How Paperclip should realize an execution workspace for this agent. Keep project_primary for normal cwd execution, or use git_worktree for issue-scoped isolated checkouts.",
workspaceStrategy: `How ${VOCAB.appName} should realize an execution workspace for this agent. Keep project_primary for normal cwd execution, or use git_worktree for issue-scoped isolated checkouts.`,
workspaceBaseRef: "Base git ref used when creating a worktree branch. Leave blank to use the resolved workspace ref or HEAD.",
workspaceBranchTemplate: "Template for naming derived branches. Supports {{issue.identifier}}, {{issue.title}}, {{agent.name}}, {{project.id}}, {{workspace.repoRef}}, and {{slug}}.",
worktreeParentDir: "Directory where derived worktrees should be created. Absolute, ~-prefixed, and repo-relative paths are supported.",
@ -44,8 +45,8 @@ export const help: Record<string, string> = {
args: "Command-line arguments, comma-separated.",
extraArgs: "Extra CLI arguments for local adapters, comma-separated.",
envVars: "Environment variables injected into the adapter process. Use plain values or secret references.",
bootstrapPrompt: "Only sent when Paperclip starts a fresh session. Use this for stable setup guidance that should not be repeated on every heartbeat.",
payloadTemplateJson: "Optional JSON merged into remote adapter request payloads before Paperclip adds its standard wake and workspace fields.",
bootstrapPrompt: `Only sent when ${VOCAB.appName} starts a fresh session. Use this for stable setup guidance that should not be repeated on every heartbeat.`,
payloadTemplateJson: `Optional JSON merged into remote adapter request payloads before ${VOCAB.appName} adds its standard wake and workspace fields.`,
webhookUrl: "The URL that receives POST requests when the agent is invoked.",
heartbeatInterval: "Run this agent automatically on a timer. Useful for periodic tasks like checking for new work.",
intervalSec: "Seconds between automatic heartbeat invocations.",

View file

@ -925,7 +925,7 @@ export function AgentDetail() {
{actionError && <p className="text-sm text-destructive">{actionError}</p>}
{isPendingApproval && (
<p className="text-sm text-amber-500">
This agent is pending board approval and cannot be invoked yet.
This agent is pending owner approval and cannot be invoked yet.
</p>
)}
@ -1479,11 +1479,11 @@ function ConfigurationTab({
const taskAssignLocked = agent.role === "ceo" || canCreateAgents;
const taskAssignHint =
taskAssignSource === "ceo_role"
? "Enabled automatically for CEO agents."
? `Enabled automatically for ${VOCAB.ceo} agents.`
: taskAssignSource === "agent_creator"
? "Enabled automatically while this agent can create new agents."
: taskAssignSource === "explicit_grant"
? "Enabled via explicit company permission grant."
? `Enabled via explicit ${VOCAB.company.toLowerCase()} permission grant.`
: "Disabled unless explicitly granted.";
return (
@ -1927,7 +1927,7 @@ function PromptsTab({
<HelpCircle className="h-3 w-3 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent side="right" sideOffset={4}>
Managed: Paperclip stores and serves the instructions bundle. External: you provide a path on disk where the instructions live.
{`Managed: ${VOCAB.appName} stores and serves the instructions bundle. External: you provide a path on disk where the instructions live.`}
</TooltipContent>
</Tooltip>
</span>
@ -1982,7 +1982,7 @@ function PromptsTab({
<HelpCircle className="h-3 w-3 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent side="right" sideOffset={4}>
The absolute directory on disk where the instructions bundle lives. In managed mode this is set by Paperclip automatically.
{`The absolute directory on disk where the instructions bundle lives. In managed mode this is set by ${VOCAB.appName} automatically.`}
</TooltipContent>
</Tooltip>
</span>
@ -2512,9 +2512,9 @@ function AgentSkillsTab({
const unsupportedSkillMessage = useMemo(() => {
if (skillSnapshot?.mode !== "unsupported") return null;
if (agent.adapterType === "openclaw_gateway") {
return "Paperclip cannot manage OpenClaw skills here. Visit your OpenClaw instance to manage this agent's skills.";
return `${VOCAB.appName} cannot manage OpenClaw skills here. Visit your OpenClaw instance to manage this agent's skills.`;
}
return "Paperclip cannot manage skills for this adapter yet. Manage them in the adapter directly.";
return `${VOCAB.appName} cannot manage skills for this adapter yet. Manage them in the adapter directly.`;
}, [agent.adapterType, skillSnapshot?.mode]);
const hasUnsavedChanges = !arraysEqual(skillDraft, lastSavedSkills);
const saveStatusLabel = syncSkills.isPending
@ -2672,7 +2672,7 @@ function AgentSkillsTab({
<section className="border-y border-border">
<div className="border-b border-border bg-muted/40 px-3 py-2">
<span className="text-xs font-medium text-muted-foreground">
Required by Paperclip
{`Required by ${VOCAB.appName}`}
</span>
</div>
{requiredSkillRows.map(renderSkillRow)}
@ -2683,7 +2683,7 @@ function AgentSkillsTab({
<section className="border-y border-border">
<div className="border-b border-border bg-muted/40 px-3 py-2">
<span className="text-xs font-medium text-muted-foreground">
User-installed skills, not managed by Paperclip
{`User-installed skills, not managed by ${VOCAB.appName}`}
</span>
</div>
{unmanagedSkillRows.map(renderSkillRow)}
@ -3969,7 +3969,7 @@ function KeysTab({ agentId, companyId }: { agentId: string; companyId?: string }
Create API Key
</h3>
<p className="text-xs text-muted-foreground">
API keys allow this agent to authenticate calls to the Paperclip server.
{`API keys allow this agent to authenticate calls to the ${VOCAB.appName} server.`}
</p>
<div className="flex items-center gap-2">
<Input

View file

@ -1,4 +1,5 @@
import { useState } from "react";
import { VOCAB } from "@paperclipai/branding";
import {
BookOpen,
Bot,
@ -194,7 +195,7 @@ export function DesignGuide() {
<div>
<h2 className="text-xl font-bold">Design Guide</h2>
<p className="text-sm text-muted-foreground mt-1">
Every component, style, and pattern used across Paperclip.
{`Every component, style, and pattern used across ${VOCAB.appName}.`}
</p>
</div>
@ -736,7 +737,7 @@ export function DesignGuide() {
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="#">Paperclip App</BreadcrumbLink>
<BreadcrumbLink href="#">{`${VOCAB.appName} App`}</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
@ -943,7 +944,7 @@ export function DesignGuide() {
<SubSection title="Initials derivation">
<div className="flex flex-col gap-2">
<Identity name="CEO Agent" size="sm" />
<Identity name={`${VOCAB.ceo} Agent`} size="sm" />
<Identity name="Alpha" size="sm" />
<Identity name="Quality Assurance Lead" size="sm" />
</div>

View file

@ -331,7 +331,7 @@ export function NewAgent() {
{/* Footer */}
<div className="border-t border-border px-4 py-3">
{isFirstAgent && (
<p className="text-xs text-muted-foreground mb-2">This will be the CEO</p>
<p className="text-xs text-muted-foreground mb-2">{`This will be the ${VOCAB.ceo}`}</p>
)}
{formError && (
<p className="text-xs text-destructive mb-2">{formError}</p>

View file

@ -1,4 +1,5 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { VOCAB } from "@paperclipai/branding";
import { Link, useLocation, useNavigate, useParams } from "@/lib/router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
@ -402,7 +403,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to save routine",
body: error instanceof Error ? error.message : "Paperclip could not save the routine.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not save the routine.`,
tone: "error",
});
},
@ -423,7 +424,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Routine run failed",
body: error instanceof Error ? error.message : "Paperclip could not start the routine run.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not start the routine run.`,
tone: "error",
});
},
@ -445,7 +446,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to update routine",
body: error instanceof Error ? error.message : "Paperclip could not update the routine.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not update the routine.`,
tone: "error",
});
},
@ -486,7 +487,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to add trigger",
body: error instanceof Error ? error.message : "Paperclip could not create the trigger.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not create the trigger.`,
tone: "error",
});
},
@ -504,7 +505,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to update trigger",
body: error instanceof Error ? error.message : "Paperclip could not update the trigger.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not update the trigger.`,
tone: "error",
});
},
@ -522,7 +523,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to delete trigger",
body: error instanceof Error ? error.message : "Paperclip could not delete the trigger.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not delete the trigger.`,
tone: "error",
});
},
@ -544,7 +545,7 @@ export function RoutineDetail() {
onError: (error) => {
pushToast({
title: "Failed to rotate webhook secret",
body: error instanceof Error ? error.message : "Paperclip could not rotate the webhook secret.",
body: error instanceof Error ? error.message : `${VOCAB.appName} could not rotate the webhook secret.`,
tone: "error",
});
},
@ -584,7 +585,7 @@ export function RoutineDetail() {
const currentProject = editDraft.projectId ? projectById.get(editDraft.projectId) ?? null : null;
if (!selectedCompanyId) {
return <EmptyState icon={Repeat} message="Select a company to view routines." />;
return <EmptyState icon={Repeat} message={`Select a ${VOCAB.company.toLowerCase()} to view routines.`} />;
}
if (isLoading) {
@ -673,7 +674,7 @@ export function RoutineDetail() {
<div className="rounded-lg border border-blue-500/30 bg-blue-500/5 p-4 space-y-3 text-sm">
<div>
<p className="font-medium">{secretMessage.title}</p>
<p className="text-xs text-muted-foreground">Save this now. Paperclip will not show the secret value again.</p>
<p className="text-xs text-muted-foreground">{`Save this now. ${VOCAB.appName} will not show the secret value again.`}</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">