mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
feat(dashboard,cli,i18n): add sidebar entries + 308 redirects + cliCommon/cliCode/cliAgents/acpAgents i18n namespaces (plan 14 F9)
- sidebarVisibility.ts: replace cli-tools with cli-code, add cli-agents, keep acp-agents order cli-code→cli-agents→acp-agents→cloud-agents in TOOLS_GROUP; update HIDEABLE_SIDEBAR_ITEM_IDS and DEVELOPER_SHOWN preset - next.config.mjs: 4 permanent (308) redirects for /dashboard/cli-tools→/dashboard/cli-code and /dashboard/agents→/dashboard/acp-agents (with :path* wildcards) - pt-BR.json + en.json: add cliCommon, cliCode, cliAgents, acpAgents namespaces (~140 keys each) + sidebar keys for the 3 new IDs - request.ts: merge EN as namespace-level fallback so 39 non-EN/pt-BR locales display new namespaces in English until translations ship - Header.tsx: update HEADER_DESCRIPTIONS map to use new HideableSidebarItemId values - tests: 4 new unit test files (38 assertions), update sidebar-visibility.test.ts omni-proxy item order
This commit is contained in:
@@ -344,6 +344,19 @@ const nextConfig = {
|
||||
destination: "/docs/ops/vm-deployment-guide",
|
||||
permanent: true,
|
||||
},
|
||||
// CLI Pages — Plano 14 (F9)
|
||||
{ source: "/dashboard/cli-tools", destination: "/dashboard/cli-code", permanent: true },
|
||||
{
|
||||
source: "/dashboard/cli-tools/:path*",
|
||||
destination: "/dashboard/cli-code/:path*",
|
||||
permanent: true,
|
||||
},
|
||||
{ source: "/dashboard/agents", destination: "/dashboard/acp-agents", permanent: true },
|
||||
{
|
||||
source: "/dashboard/agents/:path*",
|
||||
destination: "/dashboard/acp-agents/:path*",
|
||||
permanent: true,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
|
||||
@@ -930,7 +930,13 @@
|
||||
"settingsAuthzSubtitle": "Route inventory and bypass policy",
|
||||
"docsSubtitle": "Documentation",
|
||||
"issuesSubtitle": "Report a bug",
|
||||
"changelogSubtitle": "Release notes"
|
||||
"changelogSubtitle": "Release notes",
|
||||
"cliCode": "CLI Code's",
|
||||
"cliCodeSubtitle": "Code tools pointing to OmniRoute",
|
||||
"cliAgents": "CLI Agents",
|
||||
"cliAgentsSubtitle": "Autonomous CLI agents",
|
||||
"acpAgents": "ACP Agents",
|
||||
"acpAgentsSubtitle": "CLIs spawned by OmniRoute"
|
||||
},
|
||||
"webhooks": {
|
||||
"title": "Webhooks",
|
||||
@@ -7289,5 +7295,137 @@
|
||||
"policyLabel": "Policy:",
|
||||
"resetIn": "reset in",
|
||||
"quotaTotal": "total"
|
||||
},
|
||||
"cliCommon": {
|
||||
"concept": {
|
||||
"code": {
|
||||
"title": "CLI Code's",
|
||||
"phrase": "Code tools you point at OmniRoute",
|
||||
"flow": "You → CLI Code → OmniRoute → Provider",
|
||||
"seeOther": "See →"
|
||||
},
|
||||
"agent": {
|
||||
"title": "CLI Agents",
|
||||
"phrase": "Broad-purpose autonomous CLI agents you point at OmniRoute",
|
||||
"flow": "You → CLI Agent → OmniRoute → Provider",
|
||||
"seeOther": "See →"
|
||||
},
|
||||
"acp": {
|
||||
"title": "ACP Agents",
|
||||
"phrase": "CLIs that OmniRoute spawns as execution backend (reverse flow)",
|
||||
"flow": "Client → OmniRoute → spawn CLI (stdio/ACP) → response",
|
||||
"seeOther": "See →"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
"title": "Understand the 3 CLI types in OmniRoute",
|
||||
"thisPage": "[This page ✓]",
|
||||
"code": {
|
||||
"title": "Code tool",
|
||||
"desc": "Points to Omni",
|
||||
"flow": "you → CLI → Omni → provider",
|
||||
"examples": "e.g.: claude, codex"
|
||||
},
|
||||
"agent": {
|
||||
"title": "Broad autonomous agent",
|
||||
"desc": "Points to Omni",
|
||||
"flow": "you → agent → Omni",
|
||||
"examples": "e.g.: hermes, goose"
|
||||
},
|
||||
"acp": {
|
||||
"title": "CLI used as backend by Omni",
|
||||
"desc": "Reverse execution",
|
||||
"flow": "Omni → spawn CLI → resp",
|
||||
"examples": "e.g.: claude, codex (ACP)"
|
||||
}
|
||||
},
|
||||
"card": {
|
||||
"detected": "Detected",
|
||||
"notDetected": "Not detected",
|
||||
"configured": "Configured",
|
||||
"notConfigured": "Not configured",
|
||||
"configure": "Configure →",
|
||||
"howToInstall": "How to install →",
|
||||
"manualConfig": "Manual config",
|
||||
"installGuide": "Install guide",
|
||||
"endpointLabel": "Endpoint",
|
||||
"baseUrlPartial": "Partial Base URL",
|
||||
"refreshDetection": "Refresh detection",
|
||||
"alsoAcp": "also ACP"
|
||||
},
|
||||
"detail": {
|
||||
"back": "Back",
|
||||
"apply": "Save",
|
||||
"reset": "Clear",
|
||||
"manualConfig": "Manual configuration",
|
||||
"vendor": "Vendor",
|
||||
"category": "Type",
|
||||
"detectionStatus": "Detection",
|
||||
"configStatus": "Configuration",
|
||||
"baseUrlLabel": "Base URL",
|
||||
"apiKeyLabel": "API Key",
|
||||
"modelMappingLabel": "Model mapping",
|
||||
"noActiveProviders": "No active providers.",
|
||||
"noActiveProvidersDesc": "Go to Providers to connect at least 1 provider before configuring the CLI.",
|
||||
"openProviders": "Open Providers →"
|
||||
}
|
||||
},
|
||||
"cliCode": {
|
||||
"pageTitle": "CLI Code's",
|
||||
"pageSubtitle": "Code tools pointing to OmniRoute",
|
||||
"searchPlaceholder": "Search CLI…",
|
||||
"filterDetectionLabel": "Detection",
|
||||
"filterBaseUrlLabel": "Base URL",
|
||||
"detectionAll": "All",
|
||||
"detectionInstalled": "Installed",
|
||||
"detectionNotFound": "Not found",
|
||||
"baseUrlAll": "All",
|
||||
"baseUrlFull": "Full",
|
||||
"baseUrlPartial": "Partial"
|
||||
},
|
||||
"cliAgents": {
|
||||
"pageTitle": "CLI Agents",
|
||||
"pageSubtitle": "Broad-purpose autonomous CLI agents",
|
||||
"refreshDetection": "Refresh detection",
|
||||
"searchPlaceholder": "Search agent…",
|
||||
"detectionFilterLabel": "Detection",
|
||||
"detectionAll": "All",
|
||||
"detectionInstalled": "Installed",
|
||||
"detectionNotInstalled": "Not installed",
|
||||
"visibleCount": "{count} visible",
|
||||
"emptyState": "No CLI agents found with the current filters."
|
||||
},
|
||||
"acpAgents": {
|
||||
"pageTitle": "ACP Agents",
|
||||
"pageSubtitle": "CLIs that OmniRoute spawns as execution backend",
|
||||
"scanning": "Detecting agents…",
|
||||
"refresh": "Refresh",
|
||||
"setupGuideTitle": "Setup guide",
|
||||
"setupGuideDetectCliTitle": "Detect CLI",
|
||||
"setupGuideDetectCliDesc": "Agents are identified by running the --version command in PATH.",
|
||||
"setupGuideCustomAgentTitle": "Add custom agent",
|
||||
"setupGuideCustomAgentDesc": "Fill in the form below to register a custom CLI agent.",
|
||||
"setupGuideCommandMissingTitle": "Command not found",
|
||||
"setupGuideCommandMissingDesc": "Check that the binary is in PATH.",
|
||||
"fingerprintSettingsHint": "Configure routing and fingerprints in",
|
||||
"settingsRoutingLink": "Settings → Routing",
|
||||
"installed": "Installed",
|
||||
"notFound": "Not found",
|
||||
"builtIn": "Built-in",
|
||||
"custom": "Custom",
|
||||
"agentUseCaseHint": "Available for spawn via ACP.",
|
||||
"remove": "Remove",
|
||||
"addCustomAgent": "Add custom agent",
|
||||
"addCustomAgentDesc": "Register a custom CLI agent to be spawned via ACP.",
|
||||
"addAgent": "Add agent",
|
||||
"agentName": "Name",
|
||||
"agentNamePlaceholder": "e.g.: My Agent",
|
||||
"binaryName": "Binary",
|
||||
"binaryNamePlaceholder": "e.g.: myagent",
|
||||
"versionCommand": "Version command",
|
||||
"versionCommandPlaceholder": "e.g.: myagent --version",
|
||||
"spawnArgs": "Spawn arguments",
|
||||
"spawnArgsPlaceholder": "e.g.: --quiet, --json",
|
||||
"cliCodeRedirectCta": "Open CLI Code's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,7 +930,13 @@
|
||||
"settingsAuthzSubtitle": "Inventário de rotas e política de bypass",
|
||||
"docsSubtitle": "Documentação",
|
||||
"issuesSubtitle": "Reportar um bug",
|
||||
"changelogSubtitle": "Notas de versão"
|
||||
"changelogSubtitle": "Notas de versão",
|
||||
"cliCode": "CLI Code's",
|
||||
"cliCodeSubtitle": "Ferramentas de código que apontam para o OmniRoute",
|
||||
"cliAgents": "CLI Agents",
|
||||
"cliAgentsSubtitle": "Agentes autônomos com CLI",
|
||||
"acpAgents": "ACP Agents",
|
||||
"acpAgentsSubtitle": "CLIs spawnadas pelo OmniRoute"
|
||||
},
|
||||
"webhooks": {
|
||||
"title": "Webhooks",
|
||||
@@ -7279,5 +7285,137 @@
|
||||
"policyLabel": "Política:",
|
||||
"resetIn": "redefinir em",
|
||||
"quotaTotal": "total"
|
||||
},
|
||||
"cliCommon": {
|
||||
"concept": {
|
||||
"code": {
|
||||
"title": "CLI Code's",
|
||||
"phrase": "Ferramentas de código que você aponta para o OmniRoute",
|
||||
"flow": "Você → CLI Code → OmniRoute → Provider",
|
||||
"seeOther": "Ver →"
|
||||
},
|
||||
"agent": {
|
||||
"title": "CLI Agents",
|
||||
"phrase": "Agentes autônomos (CLI) de propósito amplo que você aponta para o OmniRoute",
|
||||
"flow": "Você → CLI Agent → OmniRoute → Provider",
|
||||
"seeOther": "Ver →"
|
||||
},
|
||||
"acp": {
|
||||
"title": "ACP Agents",
|
||||
"phrase": "CLIs que o OmniRoute spawna como backend de execução (fluxo reverso)",
|
||||
"flow": "Cliente → OmniRoute → spawn CLI (stdio/ACP) → resposta",
|
||||
"seeOther": "Ver →"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
"title": "Entenda os 3 tipos de CLI no OmniRoute",
|
||||
"thisPage": "[Esta página ✓]",
|
||||
"code": {
|
||||
"title": "Ferramenta de código",
|
||||
"desc": "Aponta para o Omni",
|
||||
"flow": "você → CLI → Omni → provider",
|
||||
"examples": "ex: claude, codex"
|
||||
},
|
||||
"agent": {
|
||||
"title": "Agente autônomo amplo",
|
||||
"desc": "Aponta para o Omni",
|
||||
"flow": "você → agente → Omni",
|
||||
"examples": "ex: hermes, goose"
|
||||
},
|
||||
"acp": {
|
||||
"title": "CLI usada como backend pelo Omni",
|
||||
"desc": "Execução reversa",
|
||||
"flow": "Omni → spawn CLI → resp",
|
||||
"examples": "ex: claude, codex (ACP)"
|
||||
}
|
||||
},
|
||||
"card": {
|
||||
"detected": "Detectado",
|
||||
"notDetected": "Não detectado",
|
||||
"configured": "Configurado",
|
||||
"notConfigured": "Não configurado",
|
||||
"configure": "Configurar →",
|
||||
"howToInstall": "Como instalar →",
|
||||
"manualConfig": "Manual config",
|
||||
"installGuide": "Install guide",
|
||||
"endpointLabel": "Endpoint",
|
||||
"baseUrlPartial": "Base URL parcial",
|
||||
"refreshDetection": "Atualizar detecção",
|
||||
"alsoAcp": "também ACP"
|
||||
},
|
||||
"detail": {
|
||||
"back": "Voltar",
|
||||
"apply": "Salvar",
|
||||
"reset": "Limpar",
|
||||
"manualConfig": "Configuração manual",
|
||||
"vendor": "Origem",
|
||||
"category": "Tipo",
|
||||
"detectionStatus": "Detecção",
|
||||
"configStatus": "Configuração",
|
||||
"baseUrlLabel": "Base URL",
|
||||
"apiKeyLabel": "API Key",
|
||||
"modelMappingLabel": "Mapeamento de modelos",
|
||||
"noActiveProviders": "Nenhum provider ativo.",
|
||||
"noActiveProvidersDesc": "Vá em Providers para conectar pelo menos 1 provider antes de configurar a CLI.",
|
||||
"openProviders": "Abrir Providers →"
|
||||
}
|
||||
},
|
||||
"cliCode": {
|
||||
"pageTitle": "CLI Code's",
|
||||
"pageSubtitle": "Ferramentas de código que apontam para o OmniRoute",
|
||||
"searchPlaceholder": "Buscar CLI…",
|
||||
"filterDetectionLabel": "Detecção",
|
||||
"filterBaseUrlLabel": "Base URL",
|
||||
"detectionAll": "Todas",
|
||||
"detectionInstalled": "Instaladas",
|
||||
"detectionNotFound": "Não detectadas",
|
||||
"baseUrlAll": "Todas",
|
||||
"baseUrlFull": "Completa",
|
||||
"baseUrlPartial": "Parcial"
|
||||
},
|
||||
"cliAgents": {
|
||||
"pageTitle": "CLI Agents",
|
||||
"pageSubtitle": "Agentes autônomos (CLI) de propósito amplo",
|
||||
"refreshDetection": "Atualizar detecção",
|
||||
"searchPlaceholder": "Buscar agente…",
|
||||
"detectionFilterLabel": "Detecção",
|
||||
"detectionAll": "Todos",
|
||||
"detectionInstalled": "Instalados",
|
||||
"detectionNotInstalled": "Não instalados",
|
||||
"visibleCount": "{count} visíveis",
|
||||
"emptyState": "Nenhum agente CLI encontrado com os filtros atuais."
|
||||
},
|
||||
"acpAgents": {
|
||||
"pageTitle": "ACP Agents",
|
||||
"pageSubtitle": "CLIs que o OmniRoute spawna como backend de execução",
|
||||
"scanning": "Detectando agentes…",
|
||||
"refresh": "Atualizar",
|
||||
"setupGuideTitle": "Guia de setup",
|
||||
"setupGuideDetectCliTitle": "Detectar CLI",
|
||||
"setupGuideDetectCliDesc": "Os agentes são identificados rodando o comando --version no PATH.",
|
||||
"setupGuideCustomAgentTitle": "Adicionar agente customizado",
|
||||
"setupGuideCustomAgentDesc": "Preencha o formulário abaixo para registrar um agente CLI customizado.",
|
||||
"setupGuideCommandMissingTitle": "Comando não encontrado",
|
||||
"setupGuideCommandMissingDesc": "Verifique se o binário está no PATH.",
|
||||
"fingerprintSettingsHint": "Configure roteamento e fingerprints em",
|
||||
"settingsRoutingLink": "Configurações → Roteamento",
|
||||
"installed": "Instalado",
|
||||
"notFound": "Não encontrado",
|
||||
"builtIn": "Built-in",
|
||||
"custom": "Customizado",
|
||||
"agentUseCaseHint": "Disponível para spawn via ACP.",
|
||||
"remove": "Remover",
|
||||
"addCustomAgent": "Adicionar agente customizado",
|
||||
"addCustomAgentDesc": "Registre um agente CLI customizado que será spawnado via ACP.",
|
||||
"addAgent": "Adicionar agente",
|
||||
"agentName": "Nome",
|
||||
"agentNamePlaceholder": "ex: Meu Agente",
|
||||
"binaryName": "Binário",
|
||||
"binaryNamePlaceholder": "ex: meuagente",
|
||||
"versionCommand": "Comando de versão",
|
||||
"versionCommandPlaceholder": "ex: meuagente --version",
|
||||
"spawnArgs": "Argumentos de spawn",
|
||||
"spawnArgsPlaceholder": "ex: --quiet, --json",
|
||||
"cliCodeRedirectCta": "Abrir CLI Code's"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,23 @@ export default getRequestConfig(async () => {
|
||||
|
||||
const messages = (await import(`./messages/${locale}.json`)).default;
|
||||
|
||||
// 4. Merge EN as namespace-level fallback for locales that are missing new namespaces.
|
||||
// Only applied when the active locale is not EN (avoids a redundant import).
|
||||
// Merging is shallow at the top-level namespace key — if a namespace is already
|
||||
// present in the locale file it is kept as-is; missing namespaces fall back to EN.
|
||||
// This ensures new namespaces (e.g. cliCode, cliAgents, acpAgents, cliCommon added
|
||||
// in plan 14 F9) are displayed in English for the 39 non-EN/non-pt-BR locales until
|
||||
// translations are shipped.
|
||||
let mergedMessages: Record<string, unknown> = messages as Record<string, unknown>;
|
||||
if (locale !== DEFAULT_LOCALE) {
|
||||
const enMessages = (
|
||||
await import(`./messages/${DEFAULT_LOCALE}.json`)
|
||||
).default as Record<string, unknown>;
|
||||
mergedMessages = { ...enMessages, ...mergedMessages };
|
||||
}
|
||||
|
||||
return {
|
||||
locale,
|
||||
messages,
|
||||
messages: mergedMessages,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -48,7 +48,9 @@ const HEADER_DESCRIPTIONS: Partial<Record<HideableSidebarItemId, string>> = {
|
||||
quota: "limitsDescription",
|
||||
runtime: "runtimeDescription",
|
||||
media: "mediaDescription",
|
||||
agents: "agentsDescription",
|
||||
"cli-code": "cliToolsDescription",
|
||||
"cli-agents": "agentsDescription",
|
||||
"acp-agents": "agentsDescription",
|
||||
"cloud-agents": "cloudAgentsDescription",
|
||||
memory: "memoryDescription",
|
||||
skills: "skillsDescription",
|
||||
@@ -98,8 +100,6 @@ const HEADER_DESCRIPTIONS: Partial<Record<HideableSidebarItemId, string>> = {
|
||||
// Proxy sub-pages
|
||||
"mitm-proxy": "mitmProxyDescription",
|
||||
"1proxy": "oneProxyDescription",
|
||||
// OmniProxy items
|
||||
"cli-tools": "cliToolsDescription",
|
||||
};
|
||||
|
||||
// Build href → sidebar item lookup (non-external items only)
|
||||
|
||||
@@ -13,7 +13,8 @@ export const HIDEABLE_SIDEBAR_ITEM_IDS = [
|
||||
"context-rtk",
|
||||
"context-combos",
|
||||
// OmniProxy > Tools
|
||||
"cli-tools",
|
||||
"cli-code",
|
||||
"cli-agents",
|
||||
"acp-agents",
|
||||
"cloud-agents",
|
||||
// OmniProxy > Integrations
|
||||
@@ -229,18 +230,25 @@ const TOOLS_GROUP: SidebarItemGroup = {
|
||||
titleFallback: "Tools",
|
||||
items: [
|
||||
{
|
||||
id: "cli-tools",
|
||||
href: "/dashboard/cli-tools",
|
||||
i18nKey: "cliTools",
|
||||
subtitleKey: "cliToolsSubtitle",
|
||||
id: "cli-code",
|
||||
href: "/dashboard/cli-code",
|
||||
i18nKey: "cliCode",
|
||||
subtitleKey: "cliCodeSubtitle",
|
||||
icon: "terminal",
|
||||
},
|
||||
{
|
||||
id: "cli-agents",
|
||||
href: "/dashboard/cli-agents",
|
||||
i18nKey: "cliAgents",
|
||||
subtitleKey: "cliAgentsSubtitle",
|
||||
icon: "smart_toy",
|
||||
},
|
||||
{
|
||||
id: "acp-agents",
|
||||
href: "/dashboard/acp-agents",
|
||||
i18nKey: "acpAgents",
|
||||
subtitleKey: "acpAgentsSubtitle",
|
||||
icon: "smart_toy",
|
||||
icon: "device_hub",
|
||||
},
|
||||
{
|
||||
id: "cloud-agents",
|
||||
@@ -801,7 +809,8 @@ const DEVELOPER_SHOWN: ReadonlySet<HideableSidebarItemId> = new Set([
|
||||
"context-caveman",
|
||||
"context-rtk",
|
||||
"context-combos",
|
||||
"cli-tools",
|
||||
"cli-code",
|
||||
"cli-agents",
|
||||
"acp-agents",
|
||||
"api-endpoints",
|
||||
"analytics",
|
||||
|
||||
124
tests/unit/i18n-cli-namespaces.test.ts
Normal file
124
tests/unit/i18n-cli-namespaces.test.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const pt = require("../../src/i18n/messages/pt-BR.json");
|
||||
const en = require("../../src/i18n/messages/en.json");
|
||||
|
||||
// ─── PT-BR namespace presence ─────────────────────────────────────────────────
|
||||
|
||||
test("pt-BR has cliCommon namespace", () => {
|
||||
assert.ok(pt.cliCommon, "expected pt-BR.json to have 'cliCommon' namespace");
|
||||
});
|
||||
|
||||
test("pt-BR has cliCode namespace", () => {
|
||||
assert.ok(pt.cliCode, "expected pt-BR.json to have 'cliCode' namespace");
|
||||
});
|
||||
|
||||
test("pt-BR has cliAgents namespace", () => {
|
||||
assert.ok(pt.cliAgents, "expected pt-BR.json to have 'cliAgents' namespace");
|
||||
});
|
||||
|
||||
test("pt-BR has acpAgents namespace", () => {
|
||||
assert.ok(pt.acpAgents, "expected pt-BR.json to have 'acpAgents' namespace");
|
||||
});
|
||||
|
||||
// ─── PT-BR page titles ────────────────────────────────────────────────────────
|
||||
|
||||
test("pt-BR cliCode.pageTitle is 'CLI Code's'", () => {
|
||||
assert.equal(pt.cliCode.pageTitle, "CLI Code's");
|
||||
});
|
||||
|
||||
test("pt-BR cliAgents.pageTitle is 'CLI Agents'", () => {
|
||||
assert.equal(pt.cliAgents.pageTitle, "CLI Agents");
|
||||
});
|
||||
|
||||
test("pt-BR acpAgents.pageTitle is 'ACP Agents'", () => {
|
||||
assert.equal(pt.acpAgents.pageTitle, "ACP Agents");
|
||||
});
|
||||
|
||||
// ─── PT-BR cliCommon content ──────────────────────────────────────────────────
|
||||
|
||||
test("pt-BR cliCommon.concept.code.phrase contains 'código'", () => {
|
||||
assert.ok(
|
||||
typeof pt.cliCommon.concept?.code?.phrase === "string" &&
|
||||
pt.cliCommon.concept.code.phrase.includes("código"),
|
||||
`expected cliCommon.concept.code.phrase to contain 'código', got: ${pt.cliCommon.concept?.code?.phrase}`
|
||||
);
|
||||
});
|
||||
|
||||
test("pt-BR cliCommon.comparison.title is non-empty string", () => {
|
||||
assert.ok(
|
||||
typeof pt.cliCommon.comparison?.title === "string" && pt.cliCommon.comparison.title.length > 0
|
||||
);
|
||||
});
|
||||
|
||||
// ─── PT-BR sidebar keys ───────────────────────────────────────────────────────
|
||||
|
||||
test("pt-BR sidebar has cliCode key", () => {
|
||||
assert.ok(pt.sidebar?.cliCode, "expected pt-BR sidebar to have 'cliCode' key");
|
||||
});
|
||||
|
||||
test("pt-BR sidebar has cliAgents key", () => {
|
||||
assert.ok(pt.sidebar?.cliAgents, "expected pt-BR sidebar to have 'cliAgents' key");
|
||||
});
|
||||
|
||||
test("pt-BR sidebar has acpAgents key", () => {
|
||||
assert.ok(pt.sidebar?.acpAgents, "expected pt-BR sidebar to have 'acpAgents' key");
|
||||
});
|
||||
|
||||
// ─── EN namespace presence ────────────────────────────────────────────────────
|
||||
|
||||
test("en has cliCommon namespace", () => {
|
||||
assert.ok(en.cliCommon, "expected en.json to have 'cliCommon' namespace");
|
||||
});
|
||||
|
||||
test("en has cliCode namespace", () => {
|
||||
assert.ok(en.cliCode, "expected en.json to have 'cliCode' namespace");
|
||||
});
|
||||
|
||||
test("en has cliAgents namespace", () => {
|
||||
assert.ok(en.cliAgents, "expected en.json to have 'cliAgents' namespace");
|
||||
});
|
||||
|
||||
test("en has acpAgents namespace", () => {
|
||||
assert.ok(en.acpAgents, "expected en.json to have 'acpAgents' namespace");
|
||||
});
|
||||
|
||||
// ─── EN page titles ───────────────────────────────────────────────────────────
|
||||
|
||||
test("en cliCode.pageTitle is 'CLI Code's'", () => {
|
||||
assert.equal(en.cliCode.pageTitle, "CLI Code's");
|
||||
});
|
||||
|
||||
test("en cliAgents.pageTitle is 'CLI Agents'", () => {
|
||||
assert.equal(en.cliAgents.pageTitle, "CLI Agents");
|
||||
});
|
||||
|
||||
test("en cliAgents.pageTitle is 'ACP Agents'", () => {
|
||||
assert.equal(en.acpAgents.pageTitle, "ACP Agents");
|
||||
});
|
||||
|
||||
// ─── EN cliCommon content ─────────────────────────────────────────────────────
|
||||
|
||||
test("en cliCommon.concept.code.phrase is a non-empty string", () => {
|
||||
assert.ok(
|
||||
typeof en.cliCommon.concept?.code?.phrase === "string" &&
|
||||
en.cliCommon.concept.code.phrase.length > 0
|
||||
);
|
||||
});
|
||||
|
||||
// ─── EN sidebar keys ──────────────────────────────────────────────────────────
|
||||
|
||||
test("en sidebar has cliCode key", () => {
|
||||
assert.ok(en.sidebar?.cliCode, "expected en sidebar to have 'cliCode' key");
|
||||
});
|
||||
|
||||
test("en sidebar has cliAgents key", () => {
|
||||
assert.ok(en.sidebar?.cliAgents, "expected en sidebar to have 'cliAgents' key");
|
||||
});
|
||||
|
||||
test("en sidebar has acpAgents key", () => {
|
||||
assert.ok(en.sidebar?.acpAgents, "expected en sidebar to have 'acpAgents' key");
|
||||
});
|
||||
50
tests/unit/redirects-cli-renames.test.ts
Normal file
50
tests/unit/redirects-cli-renames.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const repoRoot = join(import.meta.dirname, "../..");
|
||||
const configSource = await readFile(join(repoRoot, "next.config.mjs"), "utf8");
|
||||
|
||||
test("next.config.mjs has permanent redirect from /dashboard/cli-tools to /dashboard/cli-code", () => {
|
||||
assert.ok(
|
||||
configSource.includes('source: "/dashboard/cli-tools"') &&
|
||||
configSource.includes('destination: "/dashboard/cli-code"'),
|
||||
"expected /dashboard/cli-tools → /dashboard/cli-code redirect in next.config.mjs"
|
||||
);
|
||||
});
|
||||
|
||||
test("next.config.mjs has permanent wildcard redirect from /dashboard/cli-tools/:path* to /dashboard/cli-code/:path*", () => {
|
||||
assert.ok(
|
||||
configSource.includes('source: "/dashboard/cli-tools/:path*"') &&
|
||||
configSource.includes('destination: "/dashboard/cli-code/:path*"'),
|
||||
"expected /dashboard/cli-tools/:path* → /dashboard/cli-code/:path* redirect in next.config.mjs"
|
||||
);
|
||||
});
|
||||
|
||||
test("next.config.mjs has permanent redirect from /dashboard/agents to /dashboard/acp-agents", () => {
|
||||
assert.ok(
|
||||
configSource.includes('source: "/dashboard/agents"') &&
|
||||
configSource.includes('destination: "/dashboard/acp-agents"'),
|
||||
"expected /dashboard/agents → /dashboard/acp-agents redirect in next.config.mjs"
|
||||
);
|
||||
});
|
||||
|
||||
test("next.config.mjs has permanent wildcard redirect from /dashboard/agents/:path* to /dashboard/acp-agents/:path*", () => {
|
||||
assert.ok(
|
||||
configSource.includes('source: "/dashboard/agents/:path*"') &&
|
||||
configSource.includes('destination: "/dashboard/acp-agents/:path*"'),
|
||||
"expected /dashboard/agents/:path* → /dashboard/acp-agents/:path* redirect in next.config.mjs"
|
||||
);
|
||||
});
|
||||
|
||||
test("all 4 CLI redirect entries use permanent: true", () => {
|
||||
// Extract the CLI Pages block
|
||||
const cliBlock = configSource.slice(configSource.indexOf("// CLI Pages — Plano 14 (F9)"));
|
||||
assert.ok(cliBlock.length > 0, "expected CLI Pages block to be present");
|
||||
const permanentCount = (cliBlock.match(/permanent: true/g) || []).length;
|
||||
assert.ok(
|
||||
permanentCount >= 4,
|
||||
`expected at least 4 'permanent: true' entries in CLI Pages block, found ${permanentCount}`
|
||||
);
|
||||
});
|
||||
41
tests/unit/sidebar-cli-renames.test.ts
Normal file
41
tests/unit/sidebar-cli-renames.test.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const sidebarVisibility = await import("../../src/shared/constants/sidebarVisibility.ts");
|
||||
|
||||
test("HIDEABLE_SIDEBAR_ITEM_IDS includes cli-code (plan 14 rename)", () => {
|
||||
assert.ok(
|
||||
(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS as readonly string[]).includes("cli-code"),
|
||||
"expected 'cli-code' in HIDEABLE_SIDEBAR_ITEM_IDS"
|
||||
);
|
||||
});
|
||||
|
||||
test("HIDEABLE_SIDEBAR_ITEM_IDS includes cli-agents (plan 14 new entry)", () => {
|
||||
assert.ok(
|
||||
(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS as readonly string[]).includes("cli-agents"),
|
||||
"expected 'cli-agents' in HIDEABLE_SIDEBAR_ITEM_IDS"
|
||||
);
|
||||
});
|
||||
|
||||
test("HIDEABLE_SIDEBAR_ITEM_IDS includes acp-agents (renamed from agents)", () => {
|
||||
assert.ok(
|
||||
(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS as readonly string[]).includes("acp-agents"),
|
||||
"expected 'acp-agents' in HIDEABLE_SIDEBAR_ITEM_IDS"
|
||||
);
|
||||
});
|
||||
|
||||
test("HIDEABLE_SIDEBAR_ITEM_IDS does NOT include legacy cli-tools", () => {
|
||||
assert.equal(
|
||||
(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS as readonly string[]).includes("cli-tools"),
|
||||
false,
|
||||
"expected 'cli-tools' to be removed from HIDEABLE_SIDEBAR_ITEM_IDS (plan 14 rename to cli-code)"
|
||||
);
|
||||
});
|
||||
|
||||
test("HIDEABLE_SIDEBAR_ITEM_IDS does NOT include legacy agents", () => {
|
||||
assert.equal(
|
||||
(sidebarVisibility.HIDEABLE_SIDEBAR_ITEM_IDS as readonly string[]).includes("agents"),
|
||||
false,
|
||||
"expected 'agents' to be removed from HIDEABLE_SIDEBAR_ITEM_IDS (plan 14 rename to acp-agents)"
|
||||
);
|
||||
});
|
||||
72
tests/unit/sidebar-tools-group.test.ts
Normal file
72
tests/unit/sidebar-tools-group.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const sidebarVisibility = await import("../../src/shared/constants/sidebarVisibility.ts");
|
||||
|
||||
function getToolsGroup() {
|
||||
const omniProxySection = sidebarVisibility.SIDEBAR_SECTIONS.find(
|
||||
(section) => section.id === "omni-proxy"
|
||||
);
|
||||
assert.ok(omniProxySection, "expected omni-proxy section to exist");
|
||||
|
||||
const toolsGroup = omniProxySection.children.find(
|
||||
(child): child is (typeof sidebarVisibility.SIDEBAR_SECTIONS)[number]["children"][number] & {
|
||||
type: "group";
|
||||
} =>
|
||||
"type" in child &&
|
||||
(child as { type: string }).type === "group" &&
|
||||
(child as { id: string }).id === "tools"
|
||||
);
|
||||
assert.ok(toolsGroup, "expected tools group to exist in omni-proxy section");
|
||||
return toolsGroup as {
|
||||
type: "group";
|
||||
id: string;
|
||||
items: readonly { id: string; href: string; i18nKey: string }[];
|
||||
};
|
||||
}
|
||||
|
||||
test("TOOLS_GROUP items follow plan 14 order: cli-code → cli-agents → acp-agents → cloud-agents", () => {
|
||||
const toolsGroup = getToolsGroup();
|
||||
const itemIds = toolsGroup.items.map((item) => item.id);
|
||||
assert.deepEqual(
|
||||
itemIds,
|
||||
["cli-code", "cli-agents", "acp-agents", "cloud-agents"],
|
||||
"TOOLS_GROUP items order must be cli-code, cli-agents, acp-agents, cloud-agents"
|
||||
);
|
||||
});
|
||||
|
||||
test("TOOLS_GROUP cli-code item has correct href and i18nKey", () => {
|
||||
const toolsGroup = getToolsGroup();
|
||||
const cliCode = toolsGroup.items.find((item) => item.id === "cli-code");
|
||||
assert.ok(cliCode, "expected cli-code in TOOLS_GROUP");
|
||||
assert.equal(cliCode.href, "/dashboard/cli-code");
|
||||
assert.equal(cliCode.i18nKey, "cliCode");
|
||||
});
|
||||
|
||||
test("TOOLS_GROUP cli-agents item has correct href and i18nKey", () => {
|
||||
const toolsGroup = getToolsGroup();
|
||||
const cliAgents = toolsGroup.items.find((item) => item.id === "cli-agents");
|
||||
assert.ok(cliAgents, "expected cli-agents in TOOLS_GROUP");
|
||||
assert.equal(cliAgents.href, "/dashboard/cli-agents");
|
||||
assert.equal(cliAgents.i18nKey, "cliAgents");
|
||||
});
|
||||
|
||||
test("TOOLS_GROUP acp-agents item has correct href and i18nKey", () => {
|
||||
const toolsGroup = getToolsGroup();
|
||||
const acpAgents = toolsGroup.items.find((item) => item.id === "acp-agents");
|
||||
assert.ok(acpAgents, "expected acp-agents in TOOLS_GROUP");
|
||||
assert.equal(acpAgents.href, "/dashboard/acp-agents");
|
||||
assert.equal(acpAgents.i18nKey, "acpAgents");
|
||||
});
|
||||
|
||||
test("TOOLS_GROUP does NOT contain legacy cli-tools or agents entries", () => {
|
||||
const toolsGroup = getToolsGroup();
|
||||
const legacyIds = toolsGroup.items
|
||||
.map((item) => item.id)
|
||||
.filter((id) => id === "cli-tools" || id === "agents");
|
||||
assert.deepEqual(
|
||||
legacyIds,
|
||||
[],
|
||||
"TOOLS_GROUP must not contain legacy 'cli-tools' or 'agents' entries"
|
||||
);
|
||||
});
|
||||
@@ -49,8 +49,9 @@ test("primary sidebar items place limits after cache", () => {
|
||||
"context-caveman",
|
||||
"context-rtk",
|
||||
"context-combos",
|
||||
"cli-tools",
|
||||
"agents",
|
||||
"cli-code",
|
||||
"cli-agents",
|
||||
"acp-agents",
|
||||
"cloud-agents",
|
||||
"api-endpoints",
|
||||
"webhooks",
|
||||
|
||||
Reference in New Issue
Block a user