cynarAI 2c6b5c3d7b
chore: remove legacy orchestrator, trading and one-off leftovers (#109)
* chore: remove legacy orchestrator, trading and one-off script leftovers

The repository still carried the pre-evOo prototype: a Python orchestrator,
the old HTML "evoo-platform" cockpit (whose test ran in the root unit
suite), an apex-trading package, the hot-reload deploy.sh for it, a
permissions manifest, an architecture note with local file links, agent
handoff notes, a Steve Jobs persona template and about ninety one-off
scripts that probe a developer database with hard-coded local URLs. None
of it is used by the product, CI or the real deploy in ops/evo-deploy.

Delete those files, drop the evoo-platform test glob from the root vitest
config, the Cockpit section from .env.example and the dead biome and
gitignore entries, and update the docs that listed the removed tools.
scripts/start-tmux.sh no longer starts the removed sentinel and resolves
the checkout from its own location instead of a machine-specific path;
scripts/seed-ollama.ts requires DATABASE_URL instead of falling back to a
local URL with a username.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* fix(web): drop trading and persona prompts from the conversation shell

The web shell still showed leftovers from the trading prototype: composer
chips with German trading and "Steve Jobs" prompts, trading suggestion
chips under the empty conversation line, a German trading hero for the
empty transcript, and a German "data protection" status panel in the
sidebar. They suggested actions the product does not have and added
persistent chrome.

Remove the composer chips and their helper, the empty-state chips and the
hero (the empty conversation keeps its existing one-line start hint), the
sidebar trading indicator and the data trust panel. The new-bot E2E now
asserts the plain empty state; the sidebar spec no longer expects the
trading status, and the placeholder Steve Jobs spec with no assertions is
gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* refactor: remove the trading bot status integration

With the sidebar trading indicator gone, the only remaining consumer of
the trading bot status was a banner in General settings that reused the
same component. evOo is a personal assistant; a status proxy and poller
for one external trading service, configured through service-specific
TRADING_BOT_URL and VITE_TRADING_BOT_URL variables, does not belong in
the core product.

Remove the settings banner and its prop plumbing, the web poller, the
indicator component, the /api/trading-bot/status proxy, the shared core
contract, the env loading and both variables from .env.example, together
with their tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* chore: remove one-off database scripts and a stale review note

packages/db carried four hand-run scripts outside the package build that
query or seed a developer database with a hard-coded connection string,
one of them for a specific account. docs/VOICE-FIRST-REVIEW.md was a
one-time verification note for a workflow that no longer exists and
named private machines and local paths. Nothing references them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* chore: replace machine-specific paths and addresses with placeholders

ORIGIN.md pinned the intended checkout to an absolute path under a
personal home directory, docs/LOCAL-SETUP.md listed folders on one
developer's machine, and two tests used what looks like a real tailnet
address. Use a home-relative path, drop the machine-specific folder list,
and use 100.100.100.100 in the tests; it is still inside 100.64.0.0/10,
so both tests check the same thing as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* test(web): drop the trading status from the shell contrast test

main's contrast test now waits for the sidebar trading status before
measuring; this branch removes that status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-10-04 01:13:52 +02:00

195 lines
8.1 KiB
TypeScript

import {
resolveCloudAgentProvider,
resolveDeploymentModel,
resolveSandboxProvider,
} from "@rakazo/adapters";
import {
resolveAuthSecret,
resolveEncryptionKey,
resolveScreenProxySecret,
resolveSupervisorToken,
} from "@rakazo/core";
export { resolveCloudAgentProvider, resolveSandboxProvider } from "@rakazo/adapters";
export interface AppEnv {
nodeEnv: string;
desktopStackToken?: string;
databaseUrl: string;
realtimeDatabaseUrl: string;
authSecret: string;
authUrl: string;
webOrigin: string;
privacyPolicyUrl?: string;
apiUrl: string;
apiHost: string;
signupsEnabled: string | undefined;
signupAllowlist: string | undefined;
onboardingScanHome: string | undefined;
encryptionKey: string;
dataDir: string;
/** Opt-in Pi JSONL session recording under DATA_DIR/pi-sessions. Default off. */
piSessionRecording: boolean;
sandboxSupervisorUrl: string;
sandboxSupervisorToken: string | undefined;
screenProxySecret: string;
sandboxProvider: string;
cloudAgentProvider: string;
cloudAgentSpaceId: string | undefined;
cursorApiKey: string | undefined;
agentRuntime: string;
deploymentModelKey: string | undefined;
e2bApiKey: string | undefined;
daytonaApiKey: string | undefined;
daytonaApiUrl: string | undefined;
daytonaTarget: string | undefined;
boxApiKey: string | undefined;
boxApiUrl: string | undefined;
composioApiKey: string | undefined;
/** Optional integrations.sh-compatible catalog base URL. */
integrationsCatalogUrl: string | undefined;
pipedreamClientId: string | undefined;
pipedreamClientSecret: string | undefined;
pipedreamProjectId: string | undefined;
pipedreamEnvironment: "development" | "production";
sendblueApiKeyId: string | undefined;
sendblueApiSecret: string | undefined;
sendblueSigningSecret: string | undefined;
sendbluePhoneNumber: string | undefined;
smtpUrl: string | undefined;
emailFrom: string | undefined;
emailEmulator: boolean;
slackBotToken: string | undefined;
slackSigningSecret: string | undefined;
whatsappAccessToken: string | undefined;
whatsappPhoneNumberId: string | undefined;
whatsappAppSecret: string | undefined;
whatsappVerifyToken: string | undefined;
telegramBotToken: string | undefined;
telegramWebhookSecret: string | undefined;
larkAppId: string | undefined;
larkAppSecret: string | undefined;
larkVerificationToken: string | undefined;
larkEncryptKey: string | undefined;
larkDomain: string | undefined;
/** Unknown chat senders auto-provision their own accounts when true. */
messagingOpenSignup: boolean;
/** Bot that owns team/external chat rooms on the messaging surface. */
teamChatBotId: string | undefined;
/** Optional model override for ambient engagement judging. */
teamChatJudgeProvider: string | undefined;
teamChatJudgeModel: string | undefined;
defaultProvider: string;
defaultModel: string;
wakeupDriver: string;
mcpStdioEnabled: boolean;
mcpStdioAllowedCommands: string[];
port: number;
gitSha: string | undefined;
/** Private Compose control-network URL for the opt-in updater sidecar. */
updaterUrl: string | undefined;
/** Bearer shared with the updater; never sent to the browser. */
updaterToken: string | undefined;
/** Current application image tag; used for compose manual-upgrade command selection. */
imageTag: string | undefined;
}
export function loadEnv(source: NodeJS.ProcessEnv = process.env): AppEnv {
const authSecret = resolveAuthSecret(source);
const sandboxProvider = resolveSandboxProvider(source);
const cloudAgentProvider = resolveCloudAgentProvider(source);
const deploymentModel = resolveDeploymentModel(source);
const updaterUrl = optional(source.RAKAZO_UPDATER_URL);
const updaterToken = optional(source.RAKAZO_UPDATER_TOKEN);
return {
nodeEnv: source.NODE_ENV ?? "",
databaseUrl: required(source, "DATABASE_URL"),
realtimeDatabaseUrl: source.REALTIME_DATABASE_URL ?? required(source, "DATABASE_URL"),
desktopStackToken: optional(source.RAKAZO_DESKTOP_STACK_TOKEN),
authSecret,
authUrl: source.BETTER_AUTH_URL ?? source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
webOrigin: source.WEB_ORIGIN ?? "http://127.0.0.1:5173",
privacyPolicyUrl: optional(source.PRIVACY_POLICY_URL),
apiUrl: source.API_URL ?? "http://127.0.0.1:3100",
apiHost: source.API_HOST ?? "127.0.0.1",
signupsEnabled: source.SIGNUPS_ENABLED,
signupAllowlist: source.SIGNUP_ALLOWLIST,
onboardingScanHome: optional(source.ONBOARDING_SCAN_HOME),
encryptionKey: resolveEncryptionKey(source),
dataDir: source.DATA_DIR ?? "./data",
piSessionRecording: source.PI_SESSION_RECORDING === "true",
sandboxSupervisorUrl: source.SANDBOX_SUPERVISOR_URL ?? "http://127.0.0.1:7091",
sandboxSupervisorToken:
sandboxProvider === "docker" ? resolveSupervisorToken(source) : undefined,
screenProxySecret: resolveScreenProxySecret(source),
sandboxProvider,
cloudAgentProvider,
cloudAgentSpaceId: optional(source.CLOUD_AGENT_SPACE_ID),
cursorApiKey: optional(source.CURSOR_API_KEY),
agentRuntime: source.AGENT_RUNTIME ?? "pi",
// Provider, model and key resolve together: see resolveDeploymentModel.
deploymentModelKey: deploymentModel.key,
e2bApiKey: source.E2B_API_KEY,
daytonaApiKey: source.DAYTONA_API_KEY,
daytonaApiUrl: source.DAYTONA_API_URL,
daytonaTarget: source.DAYTONA_TARGET,
boxApiKey: source.BOX_API_KEY,
boxApiUrl: source.BOX_API_URL ?? source.BOX_BASE_URL,
composioApiKey: source.COMPOSIO_API_KEY,
integrationsCatalogUrl: optional(source.INTEGRATIONS_CATALOG_URL),
pipedreamClientId: optional(source.PIPEDREAM_CLIENT_ID),
pipedreamClientSecret: optional(source.PIPEDREAM_CLIENT_SECRET),
pipedreamProjectId: optional(source.PIPEDREAM_PROJECT_ID),
pipedreamEnvironment:
source.PIPEDREAM_ENVIRONMENT === "production" ? "production" : "development",
sendblueApiKeyId: optional(source.SENDBLUE_API_KEY_ID),
sendblueApiSecret: optional(source.SENDBLUE_API_SECRET),
sendblueSigningSecret: optional(source.SENDBLUE_SIGNING_SECRET),
sendbluePhoneNumber: optional(source.SENDBLUE_PHONE_NUMBER),
smtpUrl: optional(source.SMTP_URL),
emailFrom: optional(source.EMAIL_FROM),
emailEmulator: source.EMAIL_EMULATOR === "true" && source.NODE_ENV !== "production",
slackBotToken: optional(source.SLACK_BOT_TOKEN),
slackSigningSecret: optional(source.SLACK_SIGNING_SECRET),
whatsappAccessToken: optional(source.WHATSAPP_ACCESS_TOKEN),
whatsappPhoneNumberId: optional(source.WHATSAPP_PHONE_NUMBER_ID),
whatsappAppSecret: optional(source.WHATSAPP_APP_SECRET),
whatsappVerifyToken: optional(source.WHATSAPP_VERIFY_TOKEN),
telegramBotToken: optional(source.TELEGRAM_BOT_TOKEN),
telegramWebhookSecret: optional(source.TELEGRAM_WEBHOOK_SECRET_TOKEN),
larkAppId: optional(source.LARK_APP_ID),
larkAppSecret: optional(source.LARK_APP_SECRET),
larkVerificationToken: optional(source.LARK_VERIFICATION_TOKEN),
larkEncryptKey: optional(source.LARK_ENCRYPT_KEY),
larkDomain: optional(source.LARK_DOMAIN),
messagingOpenSignup: source.MESSAGING_OPEN_SIGNUP === "true",
teamChatBotId: optional(source.TEAM_CHAT_BOT_ID) ?? optional(source.SLACK_RAKAZO_BOT_ID),
teamChatJudgeProvider: optional(source.TEAM_CHAT_JUDGE_PROVIDER),
teamChatJudgeModel: optional(source.TEAM_CHAT_JUDGE_MODEL),
defaultProvider: deploymentModel.provider,
defaultModel: deploymentModel.model,
wakeupDriver: source.WAKEUP_DRIVER ?? "graphile",
mcpStdioEnabled: source.MCP_STDIO_ENABLED === "true",
mcpStdioAllowedCommands: (source.MCP_STDIO_ALLOWED_COMMANDS ?? "")
.split(",")
.map((value) => value.trim())
.filter(Boolean),
port: Number(source.API_PORT ?? 3100),
gitSha: optional(source.GIT_SHA) ?? optional(source.RAKAZO_GIT_SHA),
updaterUrl,
updaterToken,
imageTag: optional(source.RAKAZO_IMAGE_TAG),
};
}
function required(source: NodeJS.ProcessEnv, key: string): string {
const value = source[key];
if (!value) throw new Error(`Missing ${key}`);
return value;
}
function optional(value: string | undefined): string | undefined {
const trimmed = value?.trim();
return trimmed || undefined;
}