chore: settle product naming across app, widget and deployments

One word everywhere: ReplyPier in UI copy, package and image names, the
replypier.site domains (app/api/docs/help), REPLYPIER_* settings and the
--rp-* design tokens.

- public widget API is window.ReplyPier with replypierId / replypierBaseUrl /
  replypierConfig / replypierToken, loader at webclient/replypier.min.js;
  both bundles rebuilt from source
- NOTICE, llms.txt, CONTRIBUTING, HELP_CENTER_INFRA and the demo runtime
  config rewritten; the demo config ships no third-party keys
- migration adds the ReplyPier managed model value to the AI model enum
- local compose project, database, role, volume and Docker network carry the
  same name
This commit is contained in:
WangShen007 committed 2026-10-26 01:02:17 +08:00
1 parent 6a4127ed24
commit 3017753b88
15 files changed
+4073 -3954

No files matched your search

@@ -0,0 +1,52 @@
"""
Copyright 2024-2026 ReplyPier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
"""Add the ReplyPier managed model to the AI model enum
Revision ID: replypier_ai_model_001
Revises: widget_key_lookup_001
Create Date: 2026-10-26 00:00:00.000000
``AIModelType`` carries a managed-provider member for installs that bill model
usage through ReplyPier instead of the customer's own key. The enum type on an
existing database does not have that value yet, so add it; a database created
from the current head already contains it and this is then a no-op.
"""
from typing import Sequence, Union
from alembic import op
# revision identifiers, used by Alembic.
revision: str = 'replypier_ai_model_001'
down_revision: Union[str, None] = 'widget_key_lookup_001'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
MANAGED_VALUE = 'REPLYPIER'
def upgrade() -> None:
# ADD VALUE cannot be used in the same transaction that references the new
# label, so it runs in its own autocommit block.
with op.get_context().autocommit_block():
op.execute(
f"ALTER TYPE aimodeltype ADD VALUE IF NOT EXISTS '{MANAGED_VALUE}'"
)
def downgrade() -> None:
# PostgreSQL cannot drop an enum value; nothing to undo.
pass
+1 -1
View File
@@ -1 +1 @@
.new-chat-confirm[data-v-6c78f353]{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:10px 14px;border-bottom:1px solid var(--rp-hairline, rgba(0, 0, 0, .07));background:var(--rp-agent-bg, rgba(0, 0, 0, .03));font-family:var(--rp-body-font, inherit)}.new-chat-confirm__question[data-v-6c78f353]{margin:0;font-size:12.5px;line-height:1.35;color:var(--rp-text, inherit)}.new-chat-confirm__actions[data-v-6c78f353]{display:flex;gap:8px;margin-left:auto}.new-chat-confirm__button[data-v-6c78f353]{padding:5px 11px;border-radius:var(--rp-field-radius, 8px);border:1px solid var(--rp-border, rgba(0, 0, 0, .12));background:transparent;color:var(--rp-text, inherit);font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s ease}.new-chat-confirm__button--primary[data-v-6c78f353]{border-color:transparent;background:var(--rp-accent, #f34611);color:var(--rp-on-accent, #ffffff)}.new-chat-confirm__button[data-v-6c78f353]:disabled{opacity:.5;cursor:default}.new-chat-confirm__button[data-v-6c78f353]:not(:disabled):hover{opacity:.85}@media (pointer: coarse){.new-chat-confirm[data-v-6c78f353]{padding:10px 12px}.new-chat-confirm__button[data-v-6c78f353]{min-height:40px;padding:8px 14px}}@media (prefers-reduced-motion: reduce){.new-chat-confirm__button[data-v-6c78f353]{transition:none}}.askai[data-v-edea9534]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--rp-card);color:var(--rp-text);font-family:var(--rp-body-font, inherit)}.askai__bar[data-v-edea9534]{display:flex;align-items:center;gap:10px;padding:14px 14px 14px 16px;border-bottom:1px solid var(--rp-border);flex-shrink:0}.askai__bar-icon[data-v-edea9534]{color:var(--rp-accent);flex-shrink:0}.askai__input[data-v-edea9534]{flex:1;min-width:0;border:none;outline:none;background:transparent;color:var(--rp-text);font-size:16px;font-family:inherit;padding:2px 0}.askai__input[data-v-edea9534]::placeholder{color:var(--rp-muted)}.askai__input[data-v-edea9534]:disabled{opacity:.6}.askai__new[data-v-edea9534]{position:relative;display:inline-flex;align-items:center;justify-content:center;width:28px;height:26px;border:1px solid var(--rp-border);background:transparent;border-radius:6px;cursor:pointer;color:var(--rp-muted);font-family:inherit;flex-shrink:0;transition:color .15s ease,border-color .15s ease}.askai__new[data-v-edea9534]:hover:not(:disabled){color:var(--rp-text);border-color:var(--rp-accent)}.askai__new[data-v-edea9534]:disabled{opacity:.5;cursor:default}.askai__new--armed[data-v-edea9534]{color:var(--rp-text);border-color:var(--rp-accent)}.askai__close[data-v-edea9534]{border:1px solid var(--rp-border);background:transparent;border-radius:6px;padding:3px 7px;cursor:pointer;color:var(--rp-muted);flex-shrink:0;transition:color .15s ease,border-color .15s ease}.askai__close[data-v-edea9534]:hover{color:var(--rp-text);border-color:var(--rp-accent)}.askai__kbd[data-v-edea9534]{font-size:11px;font-weight:600;letter-spacing:.02em;font-family:inherit}.askai__body[data-v-edea9534]{flex:1;min-height:0;overflow-y:auto;scrollbar-gutter:stable;padding:18px 20px 22px}.askai__content[data-v-edea9534]{display:flow-root}.askai__intro[data-v-edea9534]{margin-bottom:18px}.askai__title[data-v-edea9534]{margin:0 0 4px;font-size:19px;font-weight:600;letter-spacing:-.01em}.askai__subtitle[data-v-edea9534]{margin:0;font-size:14px;line-height:1.5;color:var(--rp-muted)}.askai__label[data-v-edea9534]{display:block;margin:0 0 8px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--rp-muted)}.askai__suggestions[data-v-edea9534]{display:flex;flex-direction:column;gap:6px}.askai__suggestion[data-v-edea9534]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;text-align:left;padding:11px 13px;border:1px solid var(--rp-border);border-radius:10px;background:var(--rp-agent-bg);color:var(--rp-text);font-size:14px;font-family:inherit;cursor:pointer;transition:border-color .15s ease,transform .15s ease}.askai__suggestion[data-v-edea9534]:hover:not(:disabled){border-color:var(--rp-accent);transform:translate(2px)}.askai__suggestion[data-v-edea9534]:disabled{opacity:.55;cursor:default}.askai__suggestion svg[data-v-edea9534]{color:var(--rp-muted);flex-shrink:0}.askai__turn+.askai__turn[data-v-edea9534]{margin-top:20px}.askai__question[data-v-edea9534]{margin:0 0 10px;font-size:16px;font-weight:600;line-height:1.4;letter-spacing:-.01em}.askai__answer[data-v-edea9534]{font-size:14.5px;line-height:1.65;color:var(--rp-text);overflow-wrap:break-word}.askai__answer--streaming[data-v-edea9534]>:last-child:after{content:"";display:inline-block;width:6px;height:1em;margin-left:2px;vertical-align:-.15em;background:var(--rp-accent, currentColor);animation:askai-blink-edea9534 1s steps(1) infinite}@keyframes askai-blink-edea9534{0%,50%{opacity:1}51%,to{opacity:0}}.askai__answer[data-v-edea9534] p{margin:0 0 10px}.askai__answer[data-v-edea9534] p:last-child{margiLine truncated
img[data-v-a09f9aae]{display:inline-block;vertical-align:middle;flex-shrink:0;object-fit:contain}.new-chat-confirm[data-v-080bebfe]{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:10px 14px;border-bottom:1px solid var(--rp-hairline, rgba(0, 0, 0, .07));background:var(--rp-agent-bg, rgba(0, 0, 0, .03));font-family:var(--rp-body-font, inherit)}.new-chat-confirm__question[data-v-080bebfe]{margin:0;font-size:12.5px;line-height:1.35;color:var(--rp-text, inherit)}.new-chat-confirm__actions[data-v-080bebfe]{display:flex;gap:8px;margin-left:auto}.new-chat-confirm__button[data-v-080bebfe]{padding:5px 11px;border-radius:var(--rp-field-radius, 8px);border:1px solid var(--rp-border, rgba(0, 0, 0, .12));background:transparent;color:var(--rp-text, inherit);font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s ease}.new-chat-confirm__button--primary[data-v-080bebfe]{border-color:transparent;background:var(--rp-accent, #f34611);color:var(--rp-on-accent, #ffffff)}.new-chat-confirm__button[data-v-080bebfe]:disabled{opacity:.5;cursor:default}.new-chat-confirm__button[data-v-080bebfe]:not(:disabled):hover{opacity:.85}@media (pointer: coarse){.new-chat-confirm[data-v-080bebfe]{padding:10px 12px}.new-chat-confirm__button[data-v-080bebfe]{min-height:40px;padding:8px 14px}}@media (prefers-reduced-motion: reduce){.new-chat-confirm__button[data-v-080bebfe]{transition:none}}.askai[data-v-9c300a6d]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--rp-card);color:var(--rp-text);font-family:var(--rp-body-font, inherit)}.askai__bar[data-v-9c300a6d]{display:flex;align-items:center;gap:10px;padding:14px 14px 14px 16px;border-bottom:1px solid var(--rp-border);flex-shrink:0}.askai__bar-icon[data-v-9c300a6d]{color:var(--rp-accent);flex-shrink:0}.askai__input[data-v-9c300a6d]{flex:1;min-width:0;border:none;outline:none;background:transparent;color:var(--rp-text);font-size:16px;font-family:inherit;padding:2px 0}.askai__input[data-v-9c300a6d]::placeholder{color:var(--rp-muted)}.askai__input[data-v-9c300a6d]:disabled{opacity:.6}.askai__new[data-v-9c300a6d]{position:relative;display:inline-flex;align-items:center;justify-content:center;width:28px;height:26px;border:1px solid var(--rp-border);background:transparent;border-radius:6px;cursor:pointer;color:var(--rp-muted);font-family:inherit;flex-shrink:0;transition:color .15s ease,border-color .15s ease}.askai__new[data-v-9c300a6d]:hover:not(:disabled){color:var(--rp-text);border-color:var(--rp-accent)}.askai__new[data-v-9c300a6d]:disabled{opacity:.5;cursor:default}.askai__new--armed[data-v-9c300a6d]{color:var(--rp-text);border-color:var(--rp-accent)}.askai__close[data-v-9c300a6d]{border:1px solid var(--rp-border);background:transparent;border-radius:6px;padding:3px 7px;cursor:pointer;color:var(--rp-muted);flex-shrink:0;transition:color .15s ease,border-color .15s ease}.askai__close[data-v-9c300a6d]:hover{color:var(--rp-text);border-color:var(--rp-accent)}.askai__kbd[data-v-9c300a6d]{font-size:11px;font-weight:600;letter-spacing:.02em;font-family:inherit}.askai__body[data-v-9c300a6d]{flex:1;min-height:0;overflow-y:auto;scrollbar-gutter:stable;padding:18px 20px 22px}.askai__content[data-v-9c300a6d]{display:flow-root}.askai__intro[data-v-9c300a6d]{margin-bottom:18px}.askai__title[data-v-9c300a6d]{margin:0 0 4px;font-size:19px;font-weight:600;letter-spacing:-.01em}.askai__subtitle[data-v-9c300a6d]{margin:0;font-size:14px;line-height:1.5;color:var(--rp-muted)}.askai__label[data-v-9c300a6d]{display:block;margin:0 0 8px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--rp-muted)}.askai__suggestions[data-v-9c300a6d]{display:flex;flex-direction:column;gap:6px}.askai__suggestion[data-v-9c300a6d]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;text-align:left;padding:11px 13px;border:1px solid var(--rp-border);border-radius:10px;background:var(--rp-agent-bg);color:var(--rp-text);font-size:14px;font-family:inherit;cursor:pointer;transition:border-color .15s ease,transform .15s ease}.askai__suggestion[data-v-9c300a6d]:hover:not(:disabled){border-color:var(--rp-accent);transform:translate(2px)}.askai__suggestion[data-v-9c300a6d]:disabled{opacity:.55;cursor:default}.askai__suggestion svg[data-v-9c300a6d]{color:var(--rp-muted);flex-shrink:0}.askai__turn+.askai__turn[data-v-9c300a6d]{margin-top:20px}.askai__question[data-v-9c300a6d]{margin:0 0 10px;font-size:16px;font-weight:600;line-height:1.4;letter-spacing:-.01em}.askai__answer[data-v-9c300a6d]{font-size:14.5px;line-height:1.65;color:var(--rp-text);overflow-wrap:break-word}.askai__answer--streaming[data-v-9c300a6d]>:last-child:after{content:"";display:inline-block;width:6px;height:1em;margin-left:2px;vertical-align:-.15em;background:var(--rp-accent, currentColor);animation:askai-blink-9c300a6d 1s steps(1) infinite}@keyframes askai-blink-9c300a6d{0%,50%{opacity:1}51%,to{opacity:0}}.asLine truncated
+3828 -3763
View File
File diff suppressed because it is too large. Load diff
@@ -151,7 +151,7 @@ def test_domain_endpoints_flow(client, db, test_organization):
assert body["custom_domain"] == "help.customer.com"
assert body["domain_status"] == "pending"
assert [r["type"] for r in body["records"]] == ["CNAME", "TXT"]
assert body["records"][1]["host"] == "_replypier.customer.com"
assert body["records"][1]["host"] == "_replypier.help.customer.com"
with patch.object(dv, "check_txt_record", return_value=True), \
patch.object(dv, "check_cname_record", return_value=True), \
@@ -359,7 +359,7 @@ class TestRowScopeCaseInsensitivity:
)
def test_predicate_folds_both_sides(self):
result = self._ci("Arun@replypier.site")
result = self._ci("Arun@ReplyPier.Site")
assert result.ok
assert "LOWER(customer_email) = '%s'" % OWNER in result.sql
@@ -369,10 +369,10 @@ class TestRowScopeCaseInsensitivity:
assert "'x'' or ''1''=''1'" in result.sql.lower()
def test_exact_match_when_disabled(self):
result = scoped("SELECT id FROM orders", value="Arun@replypier.site")
result = scoped("SELECT id FROM orders", value="Arun@ReplyPier.Site")
assert result.ok
assert "LOWER(" not in result.sql
assert "customer_email = 'Arun@replypier.site'" in result.sql
assert "customer_email = 'Arun@ReplyPier.Site'" in result.sql
def test_still_fails_closed(self):
result = self._ci(value=None)
@@ -41,7 +41,7 @@ class TestScrubOutbound:
assert scrub_outbound(text, (OWNER_EMAIL,)) == text
def test_own_email_matched_case_insensitively(self):
text = "Your account Arun@replypier.site is fixed."
text = "Your account Arun@ReplyPier.Site is fixed."
assert scrub_outbound(text, (OWNER_EMAIL,)) == text
def test_own_phone_survives_reformatting(self):
+1 -1
View File
@@ -34,7 +34,7 @@ from app.tools.ticket_toolkit import TicketTools, _clean_email, _clean_name
class TestCleanEmail:
def test_normalizes_and_lowercases(self):
assert _clean_email(" Admin@replypier.site ") == "admin@replypier.site"
assert _clean_email(" Admin@ReplyPier.Site ") == "admin@replypier.site"
def test_rejects_junk(self):
for bad in (None, "", "not-an-email", "no@domain", "@no-local.com", "a b@c.com"):