Files
elizaos--eliza/plugins/plugin-cloud-apps/AGENTS.md
T
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

160 lines
9.8 KiB
Markdown

# @elizaos/plugin-cloud-apps
Lets an Eliza agent **manage the user's Eliza Cloud Apps from any connector**
(in-app chat, Discord, Telegram, cloud-hosted) through the shared AgentRuntime
pipeline. One plugin registration exposes the whole app lifecycle — list,
create, deploy (with a live-verification gate), monetize, take/withdraw
earnings, rotate keys, buy + manage custom domains, and the growth surfaces
(frontend hosting, ad slots, influencer bookings) — as planner actions plus a
context provider.
It is a **client of `@elizaos/cloud-sdk`** (`ElizaCloudClient`), not of the
cloud backend directly. Read the root `AGENTS.md` for repo-wide rules; this doc
is specific to the plugin.
## Auth
Reads `ELIZAOS_CLOUD_API_KEY` (+ optional `ELIZAOS_CLOUD_BASE_URL`, defaults to
`https://www.elizacloud.ai/api/v1`) via `runtime.getSetting` — the same
credentials `plugin-elizacloud` uses. With no key, `validate` returns false,
every action degrades gracefully with a "no key" message, and the provider
stays empty. Construction lives in `src/client.ts` (`getCloudClient`).
## Layout
```
src/
index.ts Plugin registration: the actions[] array + CLOUD_APPS provider.
client.ts getCloudClient (SDK construction), resolveCloudApiKey/BaseUrl/SiteBaseUrl,
reference resolution (generic matchByReference + matchAppByReference/
resolveApp — id → exact name/slug → whole-word-in-sentence → fragment;
ties = ambiguous; BOOK_INFLUENCER reuses it for profiles),
and the app formatters (formatAppLine/formatAppDetail).
safety.ts Two-phase confirm state machine for destructive/paid actions:
readStructuredConfirmation (planner boolean, NEVER prose parsing),
persist/find/deleteCloudAppConfirmation (task-backed, room-scoped),
CONFIRM_TTL_MS + pendingExpired (shared 15-min pending TTL; expired
pendings refuse the bare confirm and are re-stated/re-quoted),
conflictingConfirmTarget/Amount/Domain (frozen-target guard: a confirm
whose own params name a different target/amount refuses + clears the
pending instead of executing the frozen snapshot),
confirmationPrompt, buildConnectorCta (label+https URL only — never a
secret/amount). CloudAppConfirmationAction is the gated-action union.
deploy-gate.ts runDeployGate: poll deploy status → READY, then reachability-probe the
authoritative production_url before claiming live (pure + injectable).
reachability.ts probeReachable + respondedLive (2xx / non-gateway-down = live).
app-facts.ts record/removeAppDeployFact — durable "app is live at <url>" memory fact.
domain-facts.ts record/remove/hasInterruptedDomainPurchase — durable marker for a 502
persist_failed_recoverable buy so the free recovery stays reachable.
domain-intent.ts Pure domain helpers: extractDomainReferences (boundary-guarded),
resolveDomainTargetApp (sole-app default), cloudErrorInfo (duck-typed
CloudApiError), usdFromCents, formatDomainLine.
providers/cloud-apps.ts CLOUD_APPS provider (app inventory into planner context) + a 60s
WeakMap cache with invalidateAppsCache(runtime).
actions/ One file per action (see below).
__tests__/ bun test suites (helpers.ts fakes ONLY the SDK boundary).
test/scenarios/ cloud-apps-structured-confirm.scenario.ts — real SDK over a loopback
cloud, proving the two-phase confirm on the pr-deterministic lane.
```
## Actions
**Read-core**
- `LIST_CLOUD_APPS` — list the user's apps (name / url / status).
- `GET_APP` — details for one app by name or id.
- Provider `CLOUD_APPS` — injects the app inventory into planner context.
**Create → deploy → live loop + safe delete**
- `CREATE_APP` — create from name/description/monetization intent.
- `DEPLOY_APP` — deploy + COMPLETION GATE (READY, then `/health` 2xx on the
authoritative `production_url`) before claiming live; records a deploy fact.
- `GET_APP_DEPLOY_STATUS` — DRAFT/BUILDING/DEPLOYING/READY/ERROR + url.
- `DELETE_APP` — DESTRUCTIVE: two-phase connector-agnostic confirm; honest
partial-failure reporting; invalidates cache + removes the deploy fact.
**Manage (edit / monetize / earnings / money-out / key rotation)**
- `UPDATE_APP` — rename / edit description, logo, website, email.
- `UPDATE_MONETIZATION` — enable/disable + markup % / purchase share %; range-guarded.
- `GET_APP_EARNINGS` — READ-ONLY: withdrawable / pending / lifetime / withdrawn.
- `WITHDRAW_APP_EARNINGS` — MONEY-OUT: two-phase confirm + dashboard CTA; the
safe, idempotent, server-gated request endpoint fires on confirm.
- `REGENERATE_APP_API_KEY` — SECURITY: two-phase confirm; new key shown ONCE, never logged.
**Domains (check → buy → list)**
- `CHECK_APP_DOMAIN` — READ-ONLY availability + purchase/renewal price quote.
- `BUY_APP_DOMAIN` — MONEY-OUT: read-only quote first, two-phase confirm with a
15-min quote TTL + confirm-time price re-check; maps the server's idempotent
replay / refund-on-registrar-failure / no-charge-recovery outcomes to honest
replies; interrupted purchases are tracked in `domain-facts.ts`.
- `LIST_APP_DOMAINS` — READ-ONLY: registrar/status/SSL/verification per domain
(with the exact `_eliza-cloud-verify` TXT record for unverified external domains).
**Growth surfaces**
- `DEPLOY_FRONTEND` / `ROLLBACK_FRONTEND` / `LIST_FRONTEND_DEPLOYMENTS` — managed
frontend hosting (publish/rollback app frontends on Cloud).
- `CREATE_AD_SLOT` / `LIST_AD_SLOTS` — SSP ad inventory for monetized apps.
- `CREATE_INFLUENCER_PROFILE` / `LIST_INFLUENCERS` / `BOOK_INFLUENCER` — influencer
marketing marketplace.
- `BACKUP_APP` — export an app's config snapshot.
## Commands
```bash
bun run --cwd plugins/plugin-cloud-apps test # bun test __tests__ (SDK boundary faked)
bun run --cwd plugins/plugin-cloud-apps typecheck # tsgo --noEmit
bun run --cwd plugins/plugin-cloud-apps lint # biome check --write
bun run --cwd plugins/plugin-cloud-apps build # bun build.ts
```
## Conventions / gotchas
- **Every money/destructive action uses the `safety.ts` two-phase confirm.** The
first ask NEVER mutates — it runs read-only pre-checks and returns a
confirmation prompt naming the exact target (+ amount/domain/price), storing a
room-scoped pending task. The mutation fires only when a later turn carries the
planner's structured `confirm: true` for that pending task, using the params
FROZEN at the first ask — never re-parsed from the follow-up text, never from
English keyword matching (so non-English confirmations work).
- **A confirm that names a DIFFERENT target/amount refuses (frozen-target
guard).** When the confirm turn's own structured params clearly name another
target than the frozen snapshot ("yes — delete Beta Dashboard" while the
pending delete is for Acme Bot; a different domain, influencer, or a
different structured amount), the gated action refuses, clears the pending,
and asks the user to re-state — it never executes the frozen target the user
is no longer talking about, and never silently switches to the new one.
Helpers: `conflictingConfirmTarget` / `conflictingConfirmAmount` /
`conflictingConfirmDomain` (safety.ts). Deliberately lenient: bare confirms,
partial names of the SAME target, and generic filler ("my app") never block,
and prose is never parsed.
- **Secrets/money never transit the connector.** CTAs (`buildConnectorCta`) carry
a label + an https URL only. Created/rotated API keys are surfaced once and
never logged.
- **Cache invalidation is an invariant.** Any action that mutates app inventory
or deploy/monetization state calls `invalidateAppsCache(runtime)`; server-side
writes that change `apps` rows must evict `appsService` caches too (the app row
is cached ~5 min via `getById`; a missed eviction was a real payment-gate
staleness bug — #11213).
- **`validate` is only the API-key check.** All real validation lives in the
handler; every exit calls `callback` AND returns an `ActionResult` with
`userFacingText` (and `verifiedUserFacing: true` on truthful outcomes).
- **Deploy "done" ≠ 202-accepted.** It is READY status + a live reachability
probe of the authoritative `production_url` (`deploy-gate.ts`).
- **Tests fake ONLY the SDK.** `__tests__/helpers.ts` provides `FakeElizaCloudClient`
+ keyed/unkeyed/memory runtimes; the actions/formatters/confirm-machine run for
real. Adding an SDK method means adding its `*Fn`/state/setter/fake method.
- **Live e2e:** the app lifecycle + charges + attribution run against real staging
in `packages/cloud/api/test/e2e/group-i/l/n`; see that dir's live-staging runbook.
## ⛔ NON-NEGOTIABLE — evidence, trajectories & real end-to-end tests
The binding, repo-wide standard is **[AGENTS.md](../../AGENTS.md)** — read
it. Nothing here is *done* until a reviewer can confirm it works **without reading
the code**, from the artifacts you attach: real-LLM trajectories for
action/prompt changes (`packages/scenario-runner/bin/eliza-scenarios run …`
against a **live** model, read by hand), the real request→response traces + the
domain artifacts the change produced (app rows, deploy status, credit/earnings
ledger rows, domain records), and — for anything user-exercisable — before/after
UI proof. "Tests pass" and "CI green" are not proof. No TODOs, stubs, or
"follow-ups"; clear blockers by the hard path. Artifacts →
attached inline in the PR (MP4 video, JPG screenshots, logs in `<details>`), or mark a row `N/A - <reason>`.