@vellumai/assistant 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +27 -0
- package/.env.example +22 -0
- package/Dockerfile +99 -0
- package/Dockerfile.sandbox +5 -0
- package/README.md +248 -0
- package/bun.lock +1723 -0
- package/bunfig.toml +2 -0
- package/docs/skills.md +158 -0
- package/drizzle/0000_dizzy_maggott.sql +301 -0
- package/drizzle/meta/0000_snapshot.json +1999 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/eslint.config.mjs +17 -0
- package/hook-templates/debug-prompt-logger/hook.json +7 -0
- package/hook-templates/debug-prompt-logger/run.sh +68 -0
- package/knip.json +9 -0
- package/package.json +70 -0
- package/scripts/capture-x-graphql.ts +545 -0
- package/scripts/ipc/check-contract-inventory.ts +104 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +166 -0
- package/scripts/ipc/generate-swift.ts +492 -0
- package/scripts/test-filesystem-tools.sh +48 -0
- package/scripts/test.sh +127 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2485 -0
- package/src/__tests__/account-registry.test.ts +245 -0
- package/src/__tests__/active-skill-tools.test.ts +378 -0
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/agent-loop-thinking.test.ts +81 -0
- package/src/__tests__/agent-loop.test.ts +1135 -0
- package/src/__tests__/anthropic-provider.test.ts +778 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
- package/src/__tests__/app-bundler.test.ts +292 -0
- package/src/__tests__/app-executors.test.ts +613 -0
- package/src/__tests__/app-git-history.test.ts +176 -0
- package/src/__tests__/app-git-service.test.ts +169 -0
- package/src/__tests__/app-open-proxy.test.ts +62 -0
- package/src/__tests__/asset-materialize-tool.test.ts +452 -0
- package/src/__tests__/asset-search-tool.test.ts +477 -0
- package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
- package/src/__tests__/assistant-attachments.test.ts +437 -0
- package/src/__tests__/assistant-event-hub.test.ts +226 -0
- package/src/__tests__/assistant-event.test.ts +123 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +315 -0
- package/src/__tests__/attachments-store.test.ts +476 -0
- package/src/__tests__/attachments.test.ts +134 -0
- package/src/__tests__/audit-log-rotation.test.ts +154 -0
- package/src/__tests__/browser-fill-credential.test.ts +309 -0
- package/src/__tests__/browser-manager.test.ts +203 -0
- package/src/__tests__/browser-runtime-check.test.ts +55 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +68 -0
- package/src/__tests__/browser-skill-endstate.test.ts +195 -0
- package/src/__tests__/bundle-scanner.test.ts +313 -0
- package/src/__tests__/call-bridge.test.ts +517 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-domain.test.ts +163 -0
- package/src/__tests__/call-orchestrator.test.ts +625 -0
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +699 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-state.test.ts +174 -0
- package/src/__tests__/call-store.test.ts +691 -0
- package/src/__tests__/channel-approval-routes.test.ts +2356 -0
- package/src/__tests__/channel-approval.test.ts +299 -0
- package/src/__tests__/channel-approvals.test.ts +521 -0
- package/src/__tests__/channel-delivery-store.test.ts +447 -0
- package/src/__tests__/channel-guardian.test.ts +1005 -0
- package/src/__tests__/checker.test.ts +3519 -0
- package/src/__tests__/clarification-resolver.test.ts +159 -0
- package/src/__tests__/classifier.test.ts +67 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
- package/src/__tests__/cli-discover.test.ts +85 -0
- package/src/__tests__/cli.test.ts +26 -0
- package/src/__tests__/clipboard.test.ts +80 -0
- package/src/__tests__/commit-guarantee.test.ts +335 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
- package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
- package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
- package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +1462 -0
- package/src/__tests__/conflict-intent-tokenization.test.ts +141 -0
- package/src/__tests__/conflict-policy.test.ts +121 -0
- package/src/__tests__/conflict-store.test.ts +332 -0
- package/src/__tests__/connection-policy.test.ts +102 -0
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/context-memory-e2e.test.ts +434 -0
- package/src/__tests__/context-token-estimator.test.ts +135 -0
- package/src/__tests__/context-window-manager.test.ts +376 -0
- package/src/__tests__/contradiction-checker.test.ts +314 -0
- package/src/__tests__/conversation-store.test.ts +612 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
- package/src/__tests__/credential-broker-server-use.test.ts +554 -0
- package/src/__tests__/credential-broker.test.ts +167 -0
- package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
- package/src/__tests__/credential-metadata-store.test.ts +779 -0
- package/src/__tests__/credential-policy-validate.test.ts +121 -0
- package/src/__tests__/credential-resolve.test.ts +328 -0
- package/src/__tests__/credential-security-e2e.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +583 -0
- package/src/__tests__/credential-selection.test.ts +354 -0
- package/src/__tests__/credential-vault-unit.test.ts +780 -0
- package/src/__tests__/credential-vault.test.ts +852 -0
- package/src/__tests__/daemon-assistant-events.test.ts +164 -0
- package/src/__tests__/daemon-server-session-init.test.ts +522 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
- package/src/__tests__/diff.test.ts +121 -0
- package/src/__tests__/domain-normalize.test.ts +112 -0
- package/src/__tests__/domain-policy.test.ts +124 -0
- package/src/__tests__/doordash-client.test.ts +186 -0
- package/src/__tests__/doordash-session.test.ts +152 -0
- package/src/__tests__/dynamic-page-surface.test.ts +91 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
- package/src/__tests__/edit-engine.test.ts +180 -0
- package/src/__tests__/elevenlabs-client.test.ts +271 -0
- package/src/__tests__/email-cli.test.ts +283 -0
- package/src/__tests__/encrypted-store.test.ts +332 -0
- package/src/__tests__/entity-extractor.test.ts +190 -0
- package/src/__tests__/ephemeral-permissions.test.ts +362 -0
- package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
- package/src/__tests__/event-bus.test.ts +222 -0
- package/src/__tests__/file-edit-tool.test.ts +122 -0
- package/src/__tests__/file-ops-service.test.ts +330 -0
- package/src/__tests__/file-read-tool.test.ts +75 -0
- package/src/__tests__/file-write-tool.test.ts +113 -0
- package/src/__tests__/filesystem-tools.test.ts +579 -0
- package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
- package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
- package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/forbidden-legacy-symbols.test.ts +71 -0
- package/src/__tests__/fuzzy-match-property.test.ts +216 -0
- package/src/__tests__/fuzzy-match.test.ts +138 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +631 -0
- package/src/__tests__/gemini-image-service.test.ts +261 -0
- package/src/__tests__/gemini-provider.test.ts +651 -0
- package/src/__tests__/get-weather.test.ts +318 -0
- package/src/__tests__/gmail-integration.test.ts +73 -0
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +202 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +352 -0
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +191 -0
- package/src/__tests__/handlers-slack-config.test.ts +200 -0
- package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
- package/src/__tests__/handlers-telegram-config.test.ts +968 -0
- package/src/__tests__/handlers-twilio-config.test.ts +659 -0
- package/src/__tests__/handlers-twitter-config.test.ts +858 -0
- package/src/__tests__/headless-browser-interactions.test.ts +536 -0
- package/src/__tests__/headless-browser-navigate.test.ts +211 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
- package/src/__tests__/history-repair-observability.test.ts +56 -0
- package/src/__tests__/history-repair.test.ts +510 -0
- package/src/__tests__/home-base-bootstrap.test.ts +82 -0
- package/src/__tests__/hooks-blocking.test.ts +128 -0
- package/src/__tests__/hooks-cli.test.ts +144 -0
- package/src/__tests__/hooks-config.test.ts +93 -0
- package/src/__tests__/hooks-discovery.test.ts +199 -0
- package/src/__tests__/hooks-integration.test.ts +189 -0
- package/src/__tests__/hooks-manager.test.ts +187 -0
- package/src/__tests__/hooks-runner.test.ts +182 -0
- package/src/__tests__/hooks-settings.test.ts +154 -0
- package/src/__tests__/hooks-templates.test.ts +137 -0
- package/src/__tests__/hooks-ts-runner.test.ts +125 -0
- package/src/__tests__/hooks-watch.test.ts +100 -0
- package/src/__tests__/host-file-edit-tool.test.ts +228 -0
- package/src/__tests__/host-file-read-tool.test.ts +123 -0
- package/src/__tests__/host-file-write-tool.test.ts +136 -0
- package/src/__tests__/host-shell-tool.test.ts +562 -0
- package/src/__tests__/ingress-reconcile.test.ts +581 -0
- package/src/__tests__/ingress-url-consistency.test.ts +214 -0
- package/src/__tests__/intent-routing.test.ts +259 -0
- package/src/__tests__/ipc-blob-store.test.ts +315 -0
- package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
- package/src/__tests__/ipc-contract.test.ts +74 -0
- package/src/__tests__/ipc-protocol.test.ts +113 -0
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +1769 -0
- package/src/__tests__/ipc-validate.test.ts +407 -0
- package/src/__tests__/key-migration.test.ts +206 -0
- package/src/__tests__/keychain.test.ts +258 -0
- package/src/__tests__/llm-usage-store.test.ts +221 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
- package/src/__tests__/managed-store.test.ts +608 -0
- package/src/__tests__/media-generate-image.test.ts +238 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
- package/src/__tests__/media-visibility-policy.test.ts +141 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +235 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
- package/src/__tests__/memory-query-builder.test.ts +59 -0
- package/src/__tests__/memory-recall-quality.test.ts +846 -0
- package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
- package/src/__tests__/memory-regressions.test.ts +4435 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/migration-cli-flows.test.ts +169 -0
- package/src/__tests__/migration-ordering.test.ts +249 -0
- package/src/__tests__/mock-signup-server.test.ts +528 -0
- package/src/__tests__/oauth-callback-registry.test.ts +92 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +285 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +176 -0
- package/src/__tests__/onboarding-template-contract.test.ts +58 -0
- package/src/__tests__/openai-provider.test.ts +753 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/parser.test.ts +472 -0
- package/src/__tests__/path-classifier.test.ts +73 -0
- package/src/__tests__/path-policy.test.ts +435 -0
- package/src/__tests__/platform-move-helper.test.ts +99 -0
- package/src/__tests__/platform-socket-path.test.ts +52 -0
- package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
- package/src/__tests__/platform.test.ts +131 -0
- package/src/__tests__/playbook-execution.test.ts +502 -0
- package/src/__tests__/playbook-tools.test.ts +340 -0
- package/src/__tests__/prebuilt-home-base-seed.test.ts +75 -0
- package/src/__tests__/pricing.test.ts +256 -0
- package/src/__tests__/profile-compiler.test.ts +374 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +342 -0
- package/src/__tests__/provider-registry-ollama.test.ts +16 -0
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/proxy-approval-callback.test.ts +601 -0
- package/src/__tests__/public-ingress-urls.test.ts +256 -0
- package/src/__tests__/qdrant-manager.test.ts +267 -0
- package/src/__tests__/ratelimit.test.ts +297 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +175 -0
- package/src/__tests__/recurrence-engine.test.ts +78 -0
- package/src/__tests__/recurrence-types.test.ts +79 -0
- package/src/__tests__/registry.test.ts +494 -0
- package/src/__tests__/relay-server.test.ts +688 -0
- package/src/__tests__/reminder-store.test.ts +223 -0
- package/src/__tests__/reminder.test.ts +229 -0
- package/src/__tests__/request-file-tool.test.ts +158 -0
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +227 -0
- package/src/__tests__/run-orchestrator.test.ts +425 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +189 -0
- package/src/__tests__/runtime-events-sse-parity.test.ts +343 -0
- package/src/__tests__/runtime-events-sse.test.ts +162 -0
- package/src/__tests__/runtime-runs-http.test.ts +438 -0
- package/src/__tests__/runtime-runs.test.ts +260 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
- package/src/__tests__/sandbox-host-parity.test.ts +950 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
- package/src/__tests__/schedule-store.test.ts +484 -0
- package/src/__tests__/schedule-tools.test.ts +783 -0
- package/src/__tests__/scheduler-recurrence.test.ts +430 -0
- package/src/__tests__/script-proxy-certs.test.ts +90 -0
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
- package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
- package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
- package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
- package/src/__tests__/script-proxy-policy.test.ts +310 -0
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
- package/src/__tests__/script-proxy-router.test.ts +180 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
- package/src/__tests__/secret-allowlist.test.ts +230 -0
- package/src/__tests__/secret-ingress-handler.test.ts +110 -0
- package/src/__tests__/secret-onetime-send.test.ts +130 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
- package/src/__tests__/secret-response-routing.test.ts +93 -0
- package/src/__tests__/secret-scanner-executor.test.ts +348 -0
- package/src/__tests__/secret-scanner.test.ts +900 -0
- package/src/__tests__/secure-keys.test.ts +323 -0
- package/src/__tests__/server-history-render.test.ts +431 -0
- package/src/__tests__/session-abort-tool-results.test.ts +240 -0
- package/src/__tests__/session-conflict-gate.test.ts +1136 -0
- package/src/__tests__/session-error.test.ts +369 -0
- package/src/__tests__/session-evictor.test.ts +188 -0
- package/src/__tests__/session-init.benchmark.test.ts +465 -0
- package/src/__tests__/session-load-history-repair.test.ts +222 -0
- package/src/__tests__/session-pre-run-repair.test.ts +213 -0
- package/src/__tests__/session-process-bridge.test.ts +242 -0
- package/src/__tests__/session-profile-injection.test.ts +444 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
- package/src/__tests__/session-queue.test.ts +1535 -0
- package/src/__tests__/session-runtime-assembly.test.ts +476 -0
- package/src/__tests__/session-runtime-workspace.test.ts +183 -0
- package/src/__tests__/session-skill-tools.test.ts +2431 -0
- package/src/__tests__/session-slash-known.test.ts +368 -0
- package/src/__tests__/session-slash-queue.test.ts +288 -0
- package/src/__tests__/session-slash-unknown.test.ts +271 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
- package/src/__tests__/session-undo.test.ts +75 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
- package/src/__tests__/session-workspace-injection.test.ts +327 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
- package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
- package/src/__tests__/shell-credential-ref.test.ts +187 -0
- package/src/__tests__/shell-identity.test.ts +256 -0
- package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
- package/src/__tests__/shell-parser-property.test.ts +433 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
- package/src/__tests__/signup-e2e.test.ts +353 -0
- package/src/__tests__/size-guard.test.ts +117 -0
- package/src/__tests__/skill-include-graph.test.ts +303 -0
- package/src/__tests__/skill-load-tool.test.ts +409 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +338 -0
- package/src/__tests__/skill-script-runner-host.test.ts +489 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/skill-tool-factory.test.ts +252 -0
- package/src/__tests__/skill-tool-manifest.test.ts +658 -0
- package/src/__tests__/skill-version-hash.test.ts +182 -0
- package/src/__tests__/skills.test.ts +680 -0
- package/src/__tests__/slash-commands-catalog.test.ts +86 -0
- package/src/__tests__/slash-commands-parser.test.ts +119 -0
- package/src/__tests__/slash-commands-resolver.test.ts +193 -0
- package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/starter-bundle.test.ts +136 -0
- package/src/__tests__/starter-task-flow.test.ts +143 -0
- package/src/__tests__/subagent-manager-notify.test.ts +404 -0
- package/src/__tests__/subagent-tools.test.ts +801 -0
- package/src/__tests__/subagent-types.test.ts +78 -0
- package/src/__tests__/swarm-orchestrator.test.ts +428 -0
- package/src/__tests__/swarm-plan-validator.test.ts +330 -0
- package/src/__tests__/swarm-recursion.test.ts +165 -0
- package/src/__tests__/swarm-router-planner.test.ts +208 -0
- package/src/__tests__/swarm-session-integration.test.ts +274 -0
- package/src/__tests__/swarm-tool.test.ts +145 -0
- package/src/__tests__/swarm-worker-backend.test.ts +129 -0
- package/src/__tests__/swarm-worker-runner.test.ts +272 -0
- package/src/__tests__/system-prompt.test.ts +439 -0
- package/src/__tests__/task-compiler.test.ts +284 -0
- package/src/__tests__/task-management-tools.test.ts +936 -0
- package/src/__tests__/task-runner.test.ts +216 -0
- package/src/__tests__/task-scheduler.test.ts +217 -0
- package/src/__tests__/task-tools.test.ts +595 -0
- package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
- package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
- package/src/__tests__/terminal-sandbox.test.ts +202 -0
- package/src/__tests__/terminal-tools.test.ts +840 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
- package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
- package/src/__tests__/tool-audit-listener.test.ts +113 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +253 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
- package/src/__tests__/tool-executor-redaction.test.ts +289 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +301 -0
- package/src/__tests__/tool-executor.test.ts +1989 -0
- package/src/__tests__/tool-metrics-listener.test.ts +225 -0
- package/src/__tests__/tool-notification-listener.test.ts +49 -0
- package/src/__tests__/tool-permission-simulate-handler.test.ts +336 -0
- package/src/__tests__/tool-policy.test.ts +54 -0
- package/src/__tests__/tool-profiling-listener.test.ts +268 -0
- package/src/__tests__/tool-result-truncation.test.ts +217 -0
- package/src/__tests__/tool-trace-listener.test.ts +226 -0
- package/src/__tests__/top-level-renderer.test.ts +121 -0
- package/src/__tests__/top-level-scanner.test.ts +141 -0
- package/src/__tests__/trace-emitter.test.ts +173 -0
- package/src/__tests__/trust-store.test.ts +1605 -0
- package/src/__tests__/turn-commit.test.ts +554 -0
- package/src/__tests__/twilio-provider.test.ts +329 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +375 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +127 -0
- package/src/__tests__/twilio-routes.test.ts +577 -0
- package/src/__tests__/twitter-auth-handler.test.ts +667 -0
- package/src/__tests__/twitter-cli-error-shaping.test.ts +208 -0
- package/src/__tests__/twitter-cli-routing.test.ts +252 -0
- package/src/__tests__/twitter-oauth-client.test.ts +209 -0
- package/src/__tests__/url-safety.test.ts +418 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/weather-skill-regression.test.ts +225 -0
- package/src/__tests__/web-fetch.test.ts +869 -0
- package/src/__tests__/web-search.test.ts +584 -0
- package/src/__tests__/workspace-git-service.test.ts +1153 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +486 -0
- package/src/__tests__/workspace-lifecycle.test.ts +292 -0
- package/src/__tests__/workspace-policy.test.ts +213 -0
- package/src/agent/attachments.ts +35 -0
- package/src/agent/loop.ts +500 -0
- package/src/agent/message-types.ts +17 -0
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/autonomy/autonomy-resolver.ts +60 -0
- package/src/autonomy/autonomy-store.ts +122 -0
- package/src/autonomy/disposition-mapper.ts +31 -0
- package/src/autonomy/index.ts +11 -0
- package/src/autonomy/types.ts +39 -0
- package/src/bundler/app-bundler.ts +295 -0
- package/src/bundler/bundle-scanner.ts +535 -0
- package/src/bundler/bundle-signer.ts +124 -0
- package/src/bundler/manifest.ts +21 -0
- package/src/bundler/signature-verifier.ts +184 -0
- package/src/calls/call-bridge.ts +168 -0
- package/src/calls/call-constants.ts +48 -0
- package/src/calls/call-domain.ts +430 -0
- package/src/calls/call-orchestrator.ts +498 -0
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-state.ts +87 -0
- package/src/calls/call-store.ts +422 -0
- package/src/calls/elevenlabs-client.ts +97 -0
- package/src/calls/elevenlabs-config.ts +31 -0
- package/src/calls/relay-server.ts +390 -0
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +45 -0
- package/src/calls/twilio-provider.ts +263 -0
- package/src/calls/twilio-rest.ts +156 -0
- package/src/calls/twilio-routes.ts +311 -0
- package/src/calls/types.ts +39 -0
- package/src/calls/voice-provider.ts +14 -0
- package/src/calls/voice-quality.ts +114 -0
- package/src/cli/autonomy.ts +188 -0
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/contacts.ts +149 -0
- package/src/cli/core-commands.ts +784 -0
- package/src/cli/doordash.ts +1055 -0
- package/src/cli/email-guardrails.ts +200 -0
- package/src/cli/email.ts +405 -0
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/main-screen.tsx +53 -0
- package/src/cli/map.ts +270 -0
- package/src/cli/twitter.ts +754 -0
- package/src/cli.ts +918 -0
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/.gitkeep +0 -0
- package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
- package/src/config/bundled-skills/agentmail/icon.svg +21 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1404 -0
- package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
- package/src/config/bundled-skills/app-builder/icon.svg +9 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
- package/src/config/bundled-skills/browser/SKILL.md +28 -0
- package/src/config/bundled-skills/browser/TOOLS.json +234 -0
- package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
- package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +57 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +60 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +66 -0
- package/src/config/bundled-skills/document/SKILL.md +26 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +163 -0
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/icon.svg +24 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
- package/src/config/bundled-skills/google-calendar/types.ts +97 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +115 -0
- package/src/config/bundled-skills/macos-automation/SKILL.md +66 -0
- package/src/config/bundled-skills/messaging/SKILL.md +153 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +125 -0
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +31 -0
- package/src/config/bundled-skills/messaging/tools/shared.ts +76 -0
- package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +533 -0
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +98 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +54 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +76 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +113 -0
- package/src/config/bundled-skills/public-ingress/SKILL.md +200 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/self-upgrade/SKILL.md +68 -0
- package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
- package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +281 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +25 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +32 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +370 -0
- package/src/config/bundled-skills/twitter/SKILL.md +220 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/bundled-skills/weather/SKILL.md +37 -0
- package/src/config/bundled-skills/weather/TOOLS.json +32 -0
- package/src/config/bundled-skills/weather/icon.svg +24 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
- package/src/config/computer-use-prompt.ts +97 -0
- package/src/config/defaults.ts +263 -0
- package/src/config/loader.ts +339 -0
- package/src/config/schema.ts +1436 -0
- package/src/config/skill-state.ts +95 -0
- package/src/config/skills.ts +972 -0
- package/src/config/system-prompt.ts +675 -0
- package/src/config/templates/BOOTSTRAP.md +70 -0
- package/src/config/templates/IDENTITY.md +25 -0
- package/src/config/templates/LOOKS.md +25 -0
- package/src/config/templates/SOUL.md +37 -0
- package/src/config/templates/USER.md +19 -0
- package/src/config/types.ts +42 -0
- package/src/config/vellum-skills/chatgpt-import/SKILL.md +24 -0
- package/src/config/vellum-skills/chatgpt-import/TOOLS.json +23 -0
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +284 -0
- package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
- package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +199 -0
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +153 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +143 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +213 -0
- package/src/contacts/contact-store.ts +410 -0
- package/src/contacts/index.ts +11 -0
- package/src/contacts/types.ts +28 -0
- package/src/context/token-estimator.ts +108 -0
- package/src/context/tool-result-truncation.ts +128 -0
- package/src/context/window-manager.ts +531 -0
- package/src/daemon/assistant-attachments.ts +691 -0
- package/src/daemon/classifier.ts +110 -0
- package/src/daemon/computer-use-session.ts +903 -0
- package/src/daemon/connection-policy.ts +41 -0
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +530 -0
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +187 -0
- package/src/daemon/handlers/config.ts +1517 -0
- package/src/daemon/handlers/diagnostics.ts +338 -0
- package/src/daemon/handlers/documents.ts +173 -0
- package/src/daemon/handlers/home-base.ts +78 -0
- package/src/daemon/handlers/identity.ts +127 -0
- package/src/daemon/handlers/index.ts +129 -0
- package/src/daemon/handlers/misc.ts +331 -0
- package/src/daemon/handlers/open-bundle-handler.ts +80 -0
- package/src/daemon/handlers/publish.ts +187 -0
- package/src/daemon/handlers/sessions.ts +555 -0
- package/src/daemon/handlers/shared.ts +570 -0
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +486 -0
- package/src/daemon/handlers/subagents.ts +210 -0
- package/src/daemon/handlers/twitter-auth.ts +198 -0
- package/src/daemon/handlers/work-items.ts +632 -0
- package/src/daemon/handlers/workspace-files.ts +75 -0
- package/src/daemon/handlers.ts +17 -0
- package/src/daemon/history-repair.ts +214 -0
- package/src/daemon/ipc-blob-store.ts +231 -0
- package/src/daemon/ipc-contract-inventory.json +495 -0
- package/src/daemon/ipc-contract-inventory.ts +126 -0
- package/src/daemon/ipc-contract.ts +2551 -0
- package/src/daemon/ipc-protocol.ts +75 -0
- package/src/daemon/ipc-validate.ts +188 -0
- package/src/daemon/lifecycle.ts +582 -0
- package/src/daemon/main.ts +21 -0
- package/src/daemon/media-visibility-policy.ts +57 -0
- package/src/daemon/ride-shotgun-handler.ts +309 -0
- package/src/daemon/server.ts +1215 -0
- package/src/daemon/session-agent-loop.ts +922 -0
- package/src/daemon/session-attachments.ts +196 -0
- package/src/daemon/session-conflict-gate.ts +184 -0
- package/src/daemon/session-dynamic-profile.ts +63 -0
- package/src/daemon/session-error.ts +290 -0
- package/src/daemon/session-evictor.ts +196 -0
- package/src/daemon/session-history.ts +437 -0
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-memory.ts +212 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +193 -0
- package/src/daemon/session-process.ts +323 -0
- package/src/daemon/session-queue-manager.ts +82 -0
- package/src/daemon/session-runtime-assembly.ts +447 -0
- package/src/daemon/session-skill-tools.ts +356 -0
- package/src/daemon/session-slash.ts +305 -0
- package/src/daemon/session-surfaces.ts +702 -0
- package/src/daemon/session-tool-setup.ts +523 -0
- package/src/daemon/session-usage.ts +72 -0
- package/src/daemon/session-workspace.ts +19 -0
- package/src/daemon/session.ts +400 -0
- package/src/daemon/tls-certs.ts +189 -0
- package/src/daemon/trace-emitter.ts +82 -0
- package/src/daemon/video-thumbnail.ts +62 -0
- package/src/daemon/watch-handler.ts +274 -0
- package/src/doordash/client.ts +999 -0
- package/src/doordash/queries.ts +1311 -0
- package/src/doordash/query-extractor.ts +93 -0
- package/src/doordash/session.ts +82 -0
- package/src/email/provider.ts +117 -0
- package/src/email/providers/agentmail.ts +317 -0
- package/src/email/providers/index.ts +58 -0
- package/src/email/service.ts +303 -0
- package/src/email/types.ts +126 -0
- package/src/events/bus.ts +157 -0
- package/src/events/domain-events.ts +83 -0
- package/src/events/index.ts +18 -0
- package/src/events/tool-audit-listener.ts +80 -0
- package/src/events/tool-domain-event-publisher.ts +111 -0
- package/src/events/tool-metrics-listener.ts +159 -0
- package/src/events/tool-notification-listener.ts +17 -0
- package/src/events/tool-profiling-listener.ts +158 -0
- package/src/events/tool-trace-listener.ts +75 -0
- package/src/export/formatter.ts +98 -0
- package/src/followups/followup-store.ts +168 -0
- package/src/followups/index.ts +10 -0
- package/src/followups/types.ts +29 -0
- package/src/gallery/default-gallery.ts +795 -0
- package/src/gallery/gallery-manifest.ts +24 -0
- package/src/home-base/app-link-store.ts +82 -0
- package/src/home-base/bootstrap.ts +68 -0
- package/src/home-base/prebuilt/index.html +662 -0
- package/src/home-base/prebuilt/seed-metadata.json +21 -0
- package/src/home-base/prebuilt/seed.ts +112 -0
- package/src/home-base/prebuilt-home-base-updater.ts +30 -0
- package/src/hooks/cli.ts +163 -0
- package/src/hooks/config.ts +88 -0
- package/src/hooks/discovery.ts +110 -0
- package/src/hooks/manager.ts +124 -0
- package/src/hooks/runner.ts +123 -0
- package/src/hooks/templates.ts +52 -0
- package/src/hooks/types.ts +72 -0
- package/src/inbound/public-ingress-urls.ts +123 -0
- package/src/index.ts +81 -0
- package/src/instrument.ts +60 -0
- package/src/logfire.ts +99 -0
- package/src/media/gemini-image-service.ts +136 -0
- package/src/memory/account-store.ts +108 -0
- package/src/memory/admin.ts +211 -0
- package/src/memory/app-git-service.ts +295 -0
- package/src/memory/app-store.ts +577 -0
- package/src/memory/attachments-store.ts +397 -0
- package/src/memory/channel-delivery-store.ts +353 -0
- package/src/memory/channel-guardian-store.ts +669 -0
- package/src/memory/checkpoints.ts +52 -0
- package/src/memory/clarification-resolver.ts +298 -0
- package/src/memory/conflict-intent.ts +157 -0
- package/src/memory/conflict-policy.ts +73 -0
- package/src/memory/conflict-store.ts +350 -0
- package/src/memory/contradiction-checker.ts +358 -0
- package/src/memory/conversation-key-store.ts +122 -0
- package/src/memory/conversation-store.ts +470 -0
- package/src/memory/db.ts +1991 -0
- package/src/memory/embedding-backend.ts +229 -0
- package/src/memory/embedding-gemini.ts +52 -0
- package/src/memory/embedding-local.ts +65 -0
- package/src/memory/embedding-ollama.ts +55 -0
- package/src/memory/embedding-openai.ts +25 -0
- package/src/memory/entity-extractor.ts +474 -0
- package/src/memory/external-conversation-store.ts +234 -0
- package/src/memory/fingerprint.ts +20 -0
- package/src/memory/indexer.ts +156 -0
- package/src/memory/items-extractor.ts +461 -0
- package/src/memory/job-handlers/backfill.ts +139 -0
- package/src/memory/job-handlers/cleanup.ts +58 -0
- package/src/memory/job-handlers/conflict.ts +141 -0
- package/src/memory/job-handlers/embedding.ts +61 -0
- package/src/memory/job-handlers/extraction.ts +123 -0
- package/src/memory/job-handlers/index-maintenance.ts +54 -0
- package/src/memory/job-handlers/summarization.ts +286 -0
- package/src/memory/job-utils.ts +170 -0
- package/src/memory/jobs-store.ts +401 -0
- package/src/memory/jobs-worker.ts +313 -0
- package/src/memory/llm-request-log-store.ts +45 -0
- package/src/memory/llm-usage-store.ts +60 -0
- package/src/memory/message-content.ts +54 -0
- package/src/memory/profile-compiler.ts +160 -0
- package/src/memory/published-pages-store.ts +137 -0
- package/src/memory/qdrant-client.ts +366 -0
- package/src/memory/qdrant-manager.ts +242 -0
- package/src/memory/query-builder.ts +45 -0
- package/src/memory/retrieval-budget.ts +30 -0
- package/src/memory/retriever.ts +653 -0
- package/src/memory/runs-store.ts +305 -0
- package/src/memory/schema.ts +677 -0
- package/src/memory/search/entity.ts +298 -0
- package/src/memory/search/formatting.ts +207 -0
- package/src/memory/search/lexical.ts +227 -0
- package/src/memory/search/ranking.ts +401 -0
- package/src/memory/search/semantic.ts +121 -0
- package/src/memory/search/types.ts +137 -0
- package/src/memory/segmenter.ts +68 -0
- package/src/memory/shared-app-links-store.ts +138 -0
- package/src/memory/tool-usage-store.ts +62 -0
- package/src/messaging/activity-analyzer.ts +76 -0
- package/src/messaging/draft-store.ts +88 -0
- package/src/messaging/index.ts +3 -0
- package/src/messaging/provider-types.ts +80 -0
- package/src/messaging/provider.ts +52 -0
- package/src/messaging/providers/gmail/adapter.ts +193 -0
- package/src/messaging/providers/gmail/client.ts +204 -0
- package/src/messaging/providers/gmail/types.ts +90 -0
- package/src/messaging/providers/slack/adapter.ts +202 -0
- package/src/messaging/providers/slack/client.ts +198 -0
- package/src/messaging/providers/slack/types.ts +119 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +162 -0
- package/src/messaging/providers/telegram-bot/client.ts +104 -0
- package/src/messaging/providers/telegram-bot/types.ts +15 -0
- package/src/messaging/registry.ts +35 -0
- package/src/messaging/style-analyzer.ts +159 -0
- package/src/messaging/thread-summarizer.ts +306 -0
- package/src/messaging/triage-engine.ts +323 -0
- package/src/messaging/types.ts +55 -0
- package/src/permissions/checker.ts +640 -0
- package/src/permissions/defaults.ts +254 -0
- package/src/permissions/prompter.ts +98 -0
- package/src/permissions/secret-prompter.ts +114 -0
- package/src/permissions/shell-identity.ts +227 -0
- package/src/permissions/trust-store.ts +607 -0
- package/src/permissions/types.ts +43 -0
- package/src/permissions/workspace-policy.ts +114 -0
- package/src/playbooks/index.ts +2 -0
- package/src/playbooks/playbook-compiler.ts +90 -0
- package/src/playbooks/types.ts +55 -0
- package/src/providers/anthropic/client.ts +751 -0
- package/src/providers/failover.ts +129 -0
- package/src/providers/fireworks/client.ts +20 -0
- package/src/providers/gemini/client.ts +285 -0
- package/src/providers/ollama/client.ts +30 -0
- package/src/providers/openai/client.ts +337 -0
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/ratelimit.ts +93 -0
- package/src/providers/registry.ts +146 -0
- package/src/providers/retry.ts +81 -0
- package/src/providers/stream-timeout.ts +38 -0
- package/src/providers/types.ts +109 -0
- package/src/runtime/assistant-event-hub.ts +157 -0
- package/src/runtime/assistant-event.ts +82 -0
- package/src/runtime/channel-approval-parser.ts +60 -0
- package/src/runtime/channel-approval-types.ts +73 -0
- package/src/runtime/channel-approvals.ts +206 -0
- package/src/runtime/channel-guardian-service.ts +212 -0
- package/src/runtime/gateway-client.ts +58 -0
- package/src/runtime/http-server.ts +1076 -0
- package/src/runtime/http-types.ts +66 -0
- package/src/runtime/routes/app-routes.ts +174 -0
- package/src/runtime/routes/attachment-routes.ts +133 -0
- package/src/runtime/routes/call-routes.ts +190 -0
- package/src/runtime/routes/channel-routes.ts +1404 -0
- package/src/runtime/routes/conversation-routes.ts +352 -0
- package/src/runtime/routes/events-routes.ts +148 -0
- package/src/runtime/routes/run-routes.ts +257 -0
- package/src/runtime/routes/secret-routes.ts +76 -0
- package/src/runtime/run-orchestrator.ts +330 -0
- package/src/schedule/recurrence-engine.ts +162 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +506 -0
- package/src/schedule/scheduler.ts +171 -0
- package/src/security/encrypted-store.ts +238 -0
- package/src/security/keychain.ts +252 -0
- package/src/security/oauth-callback-registry.ts +66 -0
- package/src/security/oauth2.ts +274 -0
- package/src/security/redaction.ts +89 -0
- package/src/security/secret-allowlist.ts +164 -0
- package/src/security/secret-ingress.ts +57 -0
- package/src/security/secret-scanner.ts +550 -0
- package/src/security/secure-keys.ts +180 -0
- package/src/security/token-manager.ts +141 -0
- package/src/services/published-app-updater.ts +69 -0
- package/src/services/vercel-deploy.ts +73 -0
- package/src/skills/active-skill-tools.ts +81 -0
- package/src/skills/clawhub.ts +414 -0
- package/src/skills/include-graph.ts +146 -0
- package/src/skills/managed-store.ts +233 -0
- package/src/skills/path-classifier.ts +128 -0
- package/src/skills/slash-commands.ts +174 -0
- package/src/skills/tool-manifest.ts +165 -0
- package/src/skills/version-hash.ts +110 -0
- package/src/slack/slack-webhook.ts +61 -0
- package/src/subagent/index.ts +19 -0
- package/src/subagent/manager.ts +511 -0
- package/src/subagent/types.ts +69 -0
- package/src/swarm/backend-claude-code.ts +145 -0
- package/src/swarm/index.ts +44 -0
- package/src/swarm/limits.ts +37 -0
- package/src/swarm/orchestrator.ts +279 -0
- package/src/swarm/plan-validator.ts +151 -0
- package/src/swarm/router-planner.ts +100 -0
- package/src/swarm/router-prompts.ts +36 -0
- package/src/swarm/synthesizer.ts +62 -0
- package/src/swarm/types.ts +62 -0
- package/src/swarm/worker-backend.ts +121 -0
- package/src/swarm/worker-prompts.ts +79 -0
- package/src/swarm/worker-runner.ts +164 -0
- package/src/tasks/SPEC.md +139 -0
- package/src/tasks/candidate-store.ts +86 -0
- package/src/tasks/ephemeral-permissions.ts +48 -0
- package/src/tasks/task-compiler.ts +199 -0
- package/src/tasks/task-runner.ts +90 -0
- package/src/tasks/task-scheduler.ts +21 -0
- package/src/tasks/task-store.ts +127 -0
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/apps/definitions.ts +59 -0
- package/src/tools/apps/executors.ts +313 -0
- package/src/tools/apps/open-proxy.ts +43 -0
- package/src/tools/apps/registry.ts +16 -0
- package/src/tools/assets/materialize.ts +218 -0
- package/src/tools/assets/search.ts +361 -0
- package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
- package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
- package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
- package/src/tools/browser/api-map.ts +293 -0
- package/src/tools/browser/auth-cache.ts +149 -0
- package/src/tools/browser/auth-detector.ts +347 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +980 -0
- package/src/tools/browser/browser-handoff.ts +79 -0
- package/src/tools/browser/browser-manager.ts +715 -0
- package/src/tools/browser/browser-screencast.ts +217 -0
- package/src/tools/browser/headless-browser.ts +450 -0
- package/src/tools/browser/jit-auth.ts +51 -0
- package/src/tools/browser/network-recorder.ts +349 -0
- package/src/tools/browser/network-recording-types.ts +49 -0
- package/src/tools/browser/recording-store.ts +49 -0
- package/src/tools/browser/runtime-check.ts +43 -0
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +67 -0
- package/src/tools/calls/call-start.ts +81 -0
- package/src/tools/calls/call-status.ts +81 -0
- package/src/tools/claude-code/claude-code.ts +428 -0
- package/src/tools/computer-use/definitions.ts +443 -0
- package/src/tools/computer-use/registry.ts +22 -0
- package/src/tools/computer-use/request-computer-control.ts +53 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
- package/src/tools/credentials/account-registry.ts +127 -0
- package/src/tools/credentials/broker-types.ts +107 -0
- package/src/tools/credentials/broker.ts +372 -0
- package/src/tools/credentials/domain-policy.ts +51 -0
- package/src/tools/credentials/host-pattern-match.ts +60 -0
- package/src/tools/credentials/metadata-store.ts +335 -0
- package/src/tools/credentials/policy-types.ts +52 -0
- package/src/tools/credentials/policy-validate.ts +80 -0
- package/src/tools/credentials/resolve.ts +122 -0
- package/src/tools/credentials/selection.ts +159 -0
- package/src/tools/credentials/tool-policy.ts +25 -0
- package/src/tools/credentials/vault.ts +657 -0
- package/src/tools/document/document-tool.ts +92 -0
- package/src/tools/document/editor-template.ts +237 -0
- package/src/tools/execution-target.ts +21 -0
- package/src/tools/execution-timeout.ts +49 -0
- package/src/tools/executor.ts +815 -0
- package/src/tools/filesystem/edit.ts +127 -0
- package/src/tools/filesystem/fuzzy-match.ts +202 -0
- package/src/tools/filesystem/read.ts +71 -0
- package/src/tools/filesystem/view-image.ts +199 -0
- package/src/tools/filesystem/write.ts +79 -0
- package/src/tools/followups/followup_create.ts +76 -0
- package/src/tools/followups/followup_list.ts +60 -0
- package/src/tools/followups/followup_resolve.ts +56 -0
- package/src/tools/host-filesystem/edit.ts +125 -0
- package/src/tools/host-filesystem/read.ts +80 -0
- package/src/tools/host-filesystem/write.ts +76 -0
- package/src/tools/host-terminal/cli-discover.ts +180 -0
- package/src/tools/host-terminal/host-shell.ts +191 -0
- package/src/tools/memory/definitions.ts +69 -0
- package/src/tools/memory/handlers.ts +246 -0
- package/src/tools/memory/register.ts +66 -0
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/domain-normalize.ts +85 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/script-proxy/certs.ts +237 -0
- package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
- package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
- package/src/tools/network/script-proxy/index.ts +28 -0
- package/src/tools/network/script-proxy/logging.ts +196 -0
- package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
- package/src/tools/network/script-proxy/policy.ts +152 -0
- package/src/tools/network/script-proxy/router.ts +60 -0
- package/src/tools/network/script-proxy/server.ts +136 -0
- package/src/tools/network/script-proxy/session-manager.ts +534 -0
- package/src/tools/network/script-proxy/types.ts +125 -0
- package/src/tools/network/url-safety.ts +227 -0
- package/src/tools/network/web-fetch.ts +713 -0
- package/src/tools/network/web-search.ts +296 -0
- package/src/tools/policy-context.ts +29 -0
- package/src/tools/registry.ts +295 -0
- package/src/tools/reminder/reminder-store.ts +148 -0
- package/src/tools/reminder/reminder.ts +80 -0
- package/src/tools/schedule/create.ts +81 -0
- package/src/tools/schedule/delete.ts +28 -0
- package/src/tools/schedule/list.ts +69 -0
- package/src/tools/schedule/update.ts +97 -0
- package/src/tools/shared/filesystem/edit-engine.ts +56 -0
- package/src/tools/shared/filesystem/errors.ts +85 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
- package/src/tools/shared/filesystem/format-diff.ts +35 -0
- package/src/tools/shared/filesystem/path-policy.ts +125 -0
- package/src/tools/shared/filesystem/size-guard.ts +41 -0
- package/src/tools/shared/filesystem/types.ts +80 -0
- package/src/tools/shared/shell-output.ts +52 -0
- package/src/tools/skills/delete-managed.ts +60 -0
- package/src/tools/skills/load.ts +139 -0
- package/src/tools/skills/sandbox-runner.ts +279 -0
- package/src/tools/skills/scaffold-managed.ts +150 -0
- package/src/tools/skills/script-contract.ts +6 -0
- package/src/tools/skills/skill-script-runner.ts +86 -0
- package/src/tools/skills/skill-tool-factory.ts +64 -0
- package/src/tools/skills/vellum-catalog.ts +217 -0
- package/src/tools/subagent/abort.ts +33 -0
- package/src/tools/subagent/message.ts +39 -0
- package/src/tools/subagent/read.ts +67 -0
- package/src/tools/subagent/spawn.ts +46 -0
- package/src/tools/subagent/status.ts +45 -0
- package/src/tools/swarm/delegate.ts +183 -0
- package/src/tools/system/request-permission.ts +98 -0
- package/src/tools/system/version.ts +43 -0
- package/src/tools/tasks/index.ts +27 -0
- package/src/tools/tasks/task-delete.ts +82 -0
- package/src/tools/tasks/task-list.ts +44 -0
- package/src/tools/tasks/task-run.ts +97 -0
- package/src/tools/tasks/task-save.ts +47 -0
- package/src/tools/tasks/work-item-enqueue.ts +234 -0
- package/src/tools/tasks/work-item-list.ts +55 -0
- package/src/tools/tasks/work-item-remove.ts +60 -0
- package/src/tools/tasks/work-item-run.ts +78 -0
- package/src/tools/tasks/work-item-update.ts +114 -0
- package/src/tools/terminal/backends/docker.ts +372 -0
- package/src/tools/terminal/backends/native.ts +190 -0
- package/src/tools/terminal/backends/types.ts +26 -0
- package/src/tools/terminal/evaluate-typescript.ts +275 -0
- package/src/tools/terminal/parser.ts +413 -0
- package/src/tools/terminal/safe-env.ts +37 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
- package/src/tools/terminal/sandbox.ts +44 -0
- package/src/tools/terminal/shell.ts +257 -0
- package/src/tools/tool-manifest.ts +198 -0
- package/src/tools/types.ts +176 -0
- package/src/tools/ui-surface/definitions.ts +244 -0
- package/src/tools/ui-surface/registry.ts +14 -0
- package/src/tools/watch/screen-watch.ts +130 -0
- package/src/tools/watch/watch-state.ts +119 -0
- package/src/tools/watcher/create.ts +64 -0
- package/src/tools/watcher/delete.ts +27 -0
- package/src/tools/watcher/digest.ts +50 -0
- package/src/tools/watcher/list.ts +60 -0
- package/src/tools/watcher/update.ts +56 -0
- package/src/tools/weather/service.ts +551 -0
- package/src/twitter/client.ts +690 -0
- package/src/twitter/oauth-client.ts +102 -0
- package/src/twitter/router.ts +101 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/actors.ts +24 -0
- package/src/usage/types.ts +37 -0
- package/src/util/clipboard.ts +33 -0
- package/src/util/content-id.ts +16 -0
- package/src/util/debounce.ts +88 -0
- package/src/util/diff.ts +181 -0
- package/src/util/errors.ts +129 -0
- package/src/util/logger.ts +243 -0
- package/src/util/network-info.ts +47 -0
- package/src/util/platform.ts +632 -0
- package/src/util/pricing.ts +150 -0
- package/src/util/promise-guard.ts +37 -0
- package/src/util/retry.ts +98 -0
- package/src/util/spinner.ts +51 -0
- package/src/util/time.ts +16 -0
- package/src/util/truncate.ts +6 -0
- package/src/util/xml.ts +4 -0
- package/src/version.ts +3 -0
- package/src/watcher/constants.ts +11 -0
- package/src/watcher/engine.ts +199 -0
- package/src/watcher/provider-registry.ts +15 -0
- package/src/watcher/provider-types.ts +48 -0
- package/src/watcher/providers/gmail.ts +198 -0
- package/src/watcher/providers/google-calendar.ts +228 -0
- package/src/watcher/providers/slack.ts +129 -0
- package/src/watcher/watcher-store.ts +419 -0
- package/src/work-items/work-item-runner.ts +171 -0
- package/src/work-items/work-item-store.ts +325 -0
- package/src/workspace/commit-message-enrichment-service.ts +284 -0
- package/src/workspace/commit-message-provider.ts +95 -0
- package/src/workspace/git-service.ts +857 -0
- package/src/workspace/heartbeat-service.ts +345 -0
- package/src/workspace/provider-commit-message-generator.ts +285 -0
- package/src/workspace/top-level-renderer.ts +19 -0
- package/src/workspace/top-level-scanner.ts +41 -0
- package/src/workspace/turn-commit.ts +175 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,1404 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "App Builder"
|
|
3
|
+
description: "Build interactive apps, dashboards, calculators, games, trackers, tools, landing pages, and data visualizations with HTML/CSS/JS. Use when the user says build, create, or make an app/dashboard/calculator/game."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are an expert app builder and visual designer. When the user asks you to create an app, tool, or utility, you immediately design a data schema, choose a stunning visual direction, build a self-contained HTML/CSS/JS interface, and open it โ all in one step. You don't discuss or ask for permission to be creative. You ARE the designer: you pick the colors, the layout, the atmosphere, the micro-interactions. Your apps should make users stop and say "whoa" โ they should feel designed, not generated.
|
|
7
|
+
|
|
8
|
+
**Every app gets its own visual identity.** A plant tracker should feel earthy and green. A finance dashboard should feel precise and navy. A fitness app should feel energetic and purple. Apps should look like they were designed by a boutique studio for that specific domain โ not like generic branded tools. Think standalone premium product, not template.
|
|
9
|
+
|
|
10
|
+
**Your default behavior:** Build immediately. The user types "build me a habit tracker" and you deliver a complete, polished app with a domain-matched color palette, warm tinted background, emoji-rich stat cards, an accent-word hero heading, and thoughtful interactions. Don't ask what colors they want. Don't show wireframes. Just build something stunning and let them refine from there.
|
|
11
|
+
|
|
12
|
+
## Design Philosophy
|
|
13
|
+
|
|
14
|
+
Every app you create must clear this bar: **Would someone screenshot this and share it?** If the answer is no, you haven't tried hard enough.
|
|
15
|
+
|
|
16
|
+
### The Quality Bar
|
|
17
|
+
|
|
18
|
+
Your apps compete with products built by professional design teams. That means:
|
|
19
|
+
|
|
20
|
+
- Every screen has visual depth โ layers, shadows, gradients, texture
|
|
21
|
+
- Typography creates clear hierarchy โ not everything is 14px regular weight
|
|
22
|
+
- Color is intentional and atmospheric โ not just "blue buttons on white"
|
|
23
|
+
- Interactions feel physical โ elements respond to hover, press, and focus
|
|
24
|
+
- Empty states are designed moments, not error messages
|
|
25
|
+
- The page loads with grace โ elements stagger in, content shimmers while loading
|
|
26
|
+
|
|
27
|
+
### Anti-AI-Slop Rules
|
|
28
|
+
|
|
29
|
+
These are hard prohibitions. Violating any of these produces that unmistakable "AI-generated" look:
|
|
30
|
+
|
|
31
|
+
- **NEVER** use flat cards with no depth โ every card needs a subtle 1px border and gentle shadow, not heavy multi-layer shadows
|
|
32
|
+
- **NEVER** ship an app with zero animations โ at minimum: page load stagger, hover states, state transitions
|
|
33
|
+
- **NEVER** make all text the same size and weight โ establish clear hierarchy with at least 3 distinct levels
|
|
34
|
+
- **NEVER** use a pure white (`#fff`) or pure dark (`#000`/`#0a0a0a`) background โ ALWAYS tint it to match the domain (cream `#FEFCF9` for lifestyle, sage `#F0F5F0` for nature, cool gray `#F5F7FA` for finance, warm blush `#FDF6F3` for wellness)
|
|
35
|
+
- **NEVER** leave clickable elements without hover AND active states
|
|
36
|
+
- **ALWAYS** use emoji as visual identifiers in stat cards, list items, and navigation โ they replace icon libraries and add instant personality (๐ for food, ๐ฅ for streaks, ๐ฐ for money, ๐ฟ for plants)
|
|
37
|
+
- **ALWAYS** apply the accent-word pattern in hero headings โ color ONE key word or phrase in the accent color: "Your <span style='color: var(--accent)'>Week</span> in Motion"
|
|
38
|
+
- **ALWAYS** include a contextual/personalized header โ a greeting ("Good morning"), date ("Saturday, Feb 15"), or welcome ("Welcome back, Alex") โ not just the app title
|
|
39
|
+
- **ALWAYS** include at least one pill-shaped trust/status badge somewhere visible โ "๐ Trusted by 12,000+ users", "+8.2% this week", "โจ Pro plan"
|
|
40
|
+
- **ALWAYS** use tight letter-spacing on headings (`-0.02em` to `-0.04em`)
|
|
41
|
+
- **ALWAYS** use `clamp()` for display/heading text so it scales fluidly
|
|
42
|
+
- **ALWAYS** add at least one accent gradient somewhere โ a hero, a button, a decorative element
|
|
43
|
+
- **ALWAYS** give the app a distinct visual personality โ if you removed the content, could you still tell which app this is?
|
|
44
|
+
|
|
45
|
+
### Color Strategy
|
|
46
|
+
|
|
47
|
+
- **Theme-match your palette to the domain.** Don't default to violet. Pick the color that feels right: emerald/sage for plants & nature, purple for fitness & wellness, amber/gold for finance & productivity, rose for social & lifestyle, indigo for tech & developer tools.
|
|
48
|
+
- **Define custom CSS variables at the top of `<style>`** for every app:
|
|
49
|
+
```css
|
|
50
|
+
:root {
|
|
51
|
+
--accent: #18B07A; /* domain-matched accent */
|
|
52
|
+
--accent-light: #ECFDF5; /* tinted surface */
|
|
53
|
+
--bg-tint: #F0F5F0; /* warm/cool background tint */
|
|
54
|
+
}
|
|
55
|
+
@media (prefers-color-scheme: dark) {
|
|
56
|
+
:root {
|
|
57
|
+
--accent: #38CF93;
|
|
58
|
+
--accent-light: #073D2E;
|
|
59
|
+
--bg-tint: #0A1A14;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
- **Background tint examples:** `#FEFCF9` cream (lifestyle), `#F0F5F0` sage (nature), `#F5F7FA` cool gray (finance), `#FDF6F3` warm blush (wellness), `#F5F3FF` lavender (creative). Apply to `body { background: var(--bg-tint); }`.
|
|
64
|
+
- **60-30-10 rule:** 60% tinted background/surface, 30% secondary/text, 10% accent. Never use accent for large areas.
|
|
65
|
+
- **Status colors are semantic:** emerald = success/positive, rose = danger/destructive, amber = warning/attention. Don't use these for decoration.
|
|
66
|
+
- **`--v-*` tokens remain available** for spacing, radius, shadows, and animations. Use them for layout consistency. But stop defaulting to `--v-violet-*` for accent โ use your domain-matched `--accent` variable instead.
|
|
67
|
+
- For branded/themed apps, write custom CSS with `@media (prefers-color-scheme: dark)` overrides instead of mixing `--v-*` auto-switching variables with hardcoded colors.
|
|
68
|
+
|
|
69
|
+
### Typography Rules
|
|
70
|
+
|
|
71
|
+
- **Display/hero text:** `font-weight: 800`, `letter-spacing: -0.03em`, `clamp(1.75rem, 4vw, 2.5rem)` for fluid sizing
|
|
72
|
+
- **Accent-word technique:** In hero headings, wrap ONE key word in a `<span>` with the accent color or a gradient. This is the single most impactful typography move: `<h1>Track your <span class="accent-word">Growth</span> daily</h1>`. Use `.accent-word { color: var(--accent); }` or apply a gradient fill.
|
|
73
|
+
- **Section headings:** `font-weight: 700`, `letter-spacing: -0.02em`, `--v-font-size-xl` or `--v-font-size-2xl`
|
|
74
|
+
- **Body text:** `--v-font-size-base` (14px), `line-height: 1.55`
|
|
75
|
+
- **Labels/captions:** `text-transform: uppercase`, `letter-spacing: 0.04em`, `--v-font-size-xs`, `font-weight: 600`, `color: var(--v-text-muted)`
|
|
76
|
+
- **Monospace data:** Use `--v-font-mono` for numbers in metrics, code, timestamps
|
|
77
|
+
|
|
78
|
+
### Spacing & Layout
|
|
79
|
+
|
|
80
|
+
- Use the `--v-spacing-*` scale consistently โ don't mix arbitrary pixel values with token values
|
|
81
|
+
- **Card padding:** `--v-spacing-lg` (16px) minimum, `--v-spacing-xl` (24px) for hero/featured cards
|
|
82
|
+
- **Section gaps:** `--v-spacing-xxl` (32px) to `--v-spacing-xxxl` (48px) between major sections โ Lovable-quality apps use generous whitespace
|
|
83
|
+
- **Hero to first content:** minimum `--v-spacing-xxxl` (48px)
|
|
84
|
+
- **Element gaps:** `--v-spacing-sm` to `--v-spacing-md` between related elements
|
|
85
|
+
- **When in doubt, add more whitespace.** The #1 difference between AI-generated and designer-quality is spacing. Double what feels right, then evaluate.
|
|
86
|
+
- Use CSS Grid for dashboards and complex layouts. Use Flexbox for single-axis arrangements.
|
|
87
|
+
- Every layout should look good from 400px to 600px wide
|
|
88
|
+
|
|
89
|
+
## Visual Techniques Cookbook
|
|
90
|
+
|
|
91
|
+
Copy-paste-ready CSS techniques. All work in the sandboxed WebView with no external dependencies.
|
|
92
|
+
|
|
93
|
+
### Animated Gradient Background
|
|
94
|
+
```css
|
|
95
|
+
body {
|
|
96
|
+
background: linear-gradient(-45deg, #0f172a, #1e1b4b, #172554, #0c4a6e);
|
|
97
|
+
background-size: 400% 400%;
|
|
98
|
+
animation: gradientShift 15s ease infinite;
|
|
99
|
+
}
|
|
100
|
+
@keyframes gradientShift {
|
|
101
|
+
0%, 100% { background-position: 0% 50%; }
|
|
102
|
+
50% { background-position: 100% 50%; }
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Mesh Gradient (Layered Radials)
|
|
107
|
+
```css
|
|
108
|
+
body {
|
|
109
|
+
background:
|
|
110
|
+
radial-gradient(ellipse at 20% 50%, color-mix(in srgb, var(--v-violet-500) 15%, transparent) 0%, transparent 50%),
|
|
111
|
+
radial-gradient(ellipse at 80% 20%, color-mix(in srgb, var(--v-indigo-500) 12%, transparent) 0%, transparent 50%),
|
|
112
|
+
radial-gradient(ellipse at 50% 80%, color-mix(in srgb, var(--v-emerald-500) 8%, transparent) 0%, transparent 50%),
|
|
113
|
+
var(--v-bg);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Glassmorphism Card
|
|
118
|
+
```css
|
|
119
|
+
.glass-card {
|
|
120
|
+
background: color-mix(in srgb, var(--v-surface) 70%, transparent);
|
|
121
|
+
backdrop-filter: blur(12px);
|
|
122
|
+
-webkit-backdrop-filter: blur(12px);
|
|
123
|
+
border: 1px solid color-mix(in srgb, var(--v-surface-border) 50%, transparent);
|
|
124
|
+
border-radius: var(--v-radius-lg);
|
|
125
|
+
box-shadow: var(--v-shadow-lg);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Layered Shadows (Realistic Depth)
|
|
130
|
+
```css
|
|
131
|
+
.elevated-card {
|
|
132
|
+
box-shadow:
|
|
133
|
+
0 1px 2px rgba(0,0,0,0.04),
|
|
134
|
+
0 4px 8px rgba(0,0,0,0.06),
|
|
135
|
+
0 12px 24px rgba(0,0,0,0.08);
|
|
136
|
+
transition: box-shadow var(--v-duration-standard), transform var(--v-duration-standard);
|
|
137
|
+
}
|
|
138
|
+
.elevated-card:hover {
|
|
139
|
+
transform: translateY(-2px);
|
|
140
|
+
box-shadow:
|
|
141
|
+
0 2px 4px rgba(0,0,0,0.04),
|
|
142
|
+
0 8px 16px rgba(0,0,0,0.08),
|
|
143
|
+
0 24px 48px rgba(0,0,0,0.12);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Noise/Grain Texture Overlay
|
|
148
|
+
```css
|
|
149
|
+
body::before {
|
|
150
|
+
content: '';
|
|
151
|
+
position: fixed;
|
|
152
|
+
inset: 0;
|
|
153
|
+
opacity: 0.03;
|
|
154
|
+
pointer-events: none;
|
|
155
|
+
z-index: 9999;
|
|
156
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Gradient Text
|
|
161
|
+
```css
|
|
162
|
+
.gradient-text {
|
|
163
|
+
background: linear-gradient(135deg, var(--v-violet-500), var(--v-indigo-400));
|
|
164
|
+
-webkit-background-clip: text;
|
|
165
|
+
-webkit-text-fill-color: transparent;
|
|
166
|
+
background-clip: text;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Glow Effect
|
|
171
|
+
```css
|
|
172
|
+
.glow-accent {
|
|
173
|
+
box-shadow:
|
|
174
|
+
0 0 20px color-mix(in srgb, var(--v-accent) 30%, transparent),
|
|
175
|
+
0 0 40px color-mix(in srgb, var(--v-accent) 15%, transparent);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Dot Grid Pattern Background
|
|
180
|
+
```css
|
|
181
|
+
.dot-pattern {
|
|
182
|
+
background-image: radial-gradient(circle, var(--v-surface-border) 1px, transparent 1px);
|
|
183
|
+
background-size: 20px 20px;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Staggered Reveal Animation
|
|
188
|
+
```css
|
|
189
|
+
.reveal { opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease, transform 0.6s ease; }
|
|
190
|
+
.reveal.visible { opacity: 1; transform: translateY(0); }
|
|
191
|
+
```
|
|
192
|
+
```javascript
|
|
193
|
+
const observer = new IntersectionObserver((entries) => {
|
|
194
|
+
entries.forEach((entry, i) => {
|
|
195
|
+
if (entry.isIntersecting) {
|
|
196
|
+
setTimeout(() => entry.target.classList.add('visible'), i * 100);
|
|
197
|
+
observer.unobserve(entry.target);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}, { threshold: 0.1 });
|
|
201
|
+
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Card Hover (Lift + Border Glow)
|
|
205
|
+
```css
|
|
206
|
+
.interactive-card {
|
|
207
|
+
transition: transform var(--v-duration-standard), box-shadow var(--v-duration-standard),
|
|
208
|
+
border-color var(--v-duration-standard);
|
|
209
|
+
border: 1px solid var(--v-surface-border);
|
|
210
|
+
cursor: pointer;
|
|
211
|
+
}
|
|
212
|
+
.interactive-card:hover {
|
|
213
|
+
transform: translateY(-4px);
|
|
214
|
+
box-shadow: var(--v-shadow-lg), 0 0 0 1px color-mix(in srgb, var(--v-accent) 20%, transparent);
|
|
215
|
+
border-color: color-mix(in srgb, var(--v-accent) 40%, var(--v-surface-border));
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Loading Skeleton Shimmer
|
|
220
|
+
```css
|
|
221
|
+
.skeleton {
|
|
222
|
+
background: linear-gradient(90deg,
|
|
223
|
+
var(--v-surface) 25%,
|
|
224
|
+
color-mix(in srgb, var(--v-surface-border) 50%, var(--v-surface)) 50%,
|
|
225
|
+
var(--v-surface) 75%);
|
|
226
|
+
background-size: 200% 100%;
|
|
227
|
+
animation: shimmer 1.5s infinite;
|
|
228
|
+
border-radius: var(--v-radius-sm);
|
|
229
|
+
}
|
|
230
|
+
.skeleton-text { height: 14px; margin-bottom: 8px; width: 80%; }
|
|
231
|
+
.skeleton-heading { height: 24px; margin-bottom: 12px; width: 60%; }
|
|
232
|
+
.skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; }
|
|
233
|
+
@keyframes shimmer { to { background-position: -200% 0; } }
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Animated Checkmark (Success Feedback)
|
|
237
|
+
```css
|
|
238
|
+
.checkmark-circle {
|
|
239
|
+
width: 48px; height: 48px; border-radius: 50%;
|
|
240
|
+
background: var(--v-success); display: flex;
|
|
241
|
+
align-items: center; justify-content: center;
|
|
242
|
+
animation: scaleIn 0.3s ease;
|
|
243
|
+
}
|
|
244
|
+
.checkmark-circle::after {
|
|
245
|
+
content: ''; width: 12px; height: 20px;
|
|
246
|
+
border: solid white; border-width: 0 3px 3px 0;
|
|
247
|
+
transform: rotate(45deg); margin-top: -4px;
|
|
248
|
+
animation: checkDraw 0.2s 0.2s ease both;
|
|
249
|
+
}
|
|
250
|
+
@keyframes scaleIn { from { transform: scale(0); } to { transform: scale(1); } }
|
|
251
|
+
@keyframes checkDraw { from { opacity: 0; } to { opacity: 1; } }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Navigation Bar (Sticky Header)
|
|
255
|
+
```html
|
|
256
|
+
<nav class="app-navbar">
|
|
257
|
+
<div class="navbar-brand">๐ฟ PlantCare</div>
|
|
258
|
+
<div class="navbar-links">
|
|
259
|
+
<a href="#" class="nav-link active">Dashboard</a>
|
|
260
|
+
<a href="#" class="nav-link">My Plants</a>
|
|
261
|
+
<a href="#" class="nav-link">Schedule</a>
|
|
262
|
+
</div>
|
|
263
|
+
<button class="v-button navbar-cta">Add Plant</button>
|
|
264
|
+
</nav>
|
|
265
|
+
```
|
|
266
|
+
```css
|
|
267
|
+
.app-navbar {
|
|
268
|
+
position: sticky; top: 0; z-index: 100;
|
|
269
|
+
display: flex; align-items: center; gap: var(--v-spacing-lg);
|
|
270
|
+
padding: var(--v-spacing-md) var(--v-spacing-xl);
|
|
271
|
+
background: color-mix(in srgb, var(--bg-tint, var(--v-bg)) 85%, transparent);
|
|
272
|
+
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
273
|
+
border-bottom: 1px solid var(--v-surface-border);
|
|
274
|
+
}
|
|
275
|
+
.navbar-brand { font-weight: 700; font-size: var(--v-font-size-lg); }
|
|
276
|
+
.navbar-links { display: flex; gap: var(--v-spacing-sm); margin-left: auto; }
|
|
277
|
+
.navbar-links .nav-link {
|
|
278
|
+
padding: var(--v-spacing-xs) var(--v-spacing-md); border-radius: var(--v-radius-md);
|
|
279
|
+
color: var(--v-text-secondary); font-weight: 500; font-size: var(--v-font-size-sm);
|
|
280
|
+
text-decoration: none; transition: all var(--v-duration-fast);
|
|
281
|
+
}
|
|
282
|
+
.navbar-links .nav-link:hover { color: var(--v-text); background: var(--v-surface); }
|
|
283
|
+
.navbar-links .nav-link.active { color: var(--accent, var(--v-accent)); font-weight: 600; }
|
|
284
|
+
.navbar-cta { margin-left: var(--v-spacing-sm); padding: var(--v-spacing-xs) var(--v-spacing-lg); font-size: var(--v-font-size-sm); }
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Pill Badge / Trust Badge
|
|
288
|
+
```html
|
|
289
|
+
<span class="trust-pill">๐ Trusted by 12,000+ homes</span>
|
|
290
|
+
<span class="trust-pill accent">+8.2% this week</span>
|
|
291
|
+
```
|
|
292
|
+
```css
|
|
293
|
+
.trust-pill {
|
|
294
|
+
display: inline-flex; align-items: center; gap: var(--v-spacing-xs);
|
|
295
|
+
padding: var(--v-spacing-xs) var(--v-spacing-md);
|
|
296
|
+
background: var(--v-surface); border: 1px solid var(--v-surface-border);
|
|
297
|
+
border-radius: var(--v-radius-pill); font-size: var(--v-font-size-xs);
|
|
298
|
+
font-weight: 600; color: var(--v-text-secondary);
|
|
299
|
+
}
|
|
300
|
+
.trust-pill.accent {
|
|
301
|
+
background: color-mix(in srgb, var(--accent, var(--v-accent)) 10%, transparent);
|
|
302
|
+
border-color: color-mix(in srgb, var(--accent, var(--v-accent)) 25%, transparent);
|
|
303
|
+
color: var(--accent, var(--v-accent));
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Emoji Stat Card
|
|
308
|
+
```html
|
|
309
|
+
<div class="emoji-stat-row">
|
|
310
|
+
<div class="emoji-stat-card">
|
|
311
|
+
<span class="emoji-stat-icon">๐ฅ</span>
|
|
312
|
+
<span class="emoji-stat-value">1,284</span>
|
|
313
|
+
<span class="emoji-stat-label">Calories</span>
|
|
314
|
+
</div>
|
|
315
|
+
<div class="emoji-stat-card">
|
|
316
|
+
<span class="emoji-stat-icon">๐</span>
|
|
317
|
+
<span class="emoji-stat-value">8,421</span>
|
|
318
|
+
<span class="emoji-stat-label">Steps</span>
|
|
319
|
+
</div>
|
|
320
|
+
<div class="emoji-stat-card">
|
|
321
|
+
<span class="emoji-stat-icon">๐ง</span>
|
|
322
|
+
<span class="emoji-stat-value">2.4L</span>
|
|
323
|
+
<span class="emoji-stat-label">Hydration</span>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
```
|
|
327
|
+
```css
|
|
328
|
+
.emoji-stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--v-spacing-md); }
|
|
329
|
+
.emoji-stat-card {
|
|
330
|
+
background: var(--v-surface); border: 1px solid var(--v-surface-border);
|
|
331
|
+
border-radius: var(--v-radius-lg); padding: var(--v-spacing-lg);
|
|
332
|
+
display: flex; flex-direction: column; align-items: center; gap: var(--v-spacing-xs);
|
|
333
|
+
text-align: center;
|
|
334
|
+
}
|
|
335
|
+
.emoji-stat-icon { font-size: 28px; line-height: 1; }
|
|
336
|
+
.emoji-stat-value { font-size: var(--v-font-size-xl); font-weight: 700; color: var(--v-text); }
|
|
337
|
+
.emoji-stat-label { font-size: var(--v-font-size-xs); color: var(--v-text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Accent Word Heading
|
|
341
|
+
```html
|
|
342
|
+
<h1>Track your <span class="accent-word">Growth</span> daily</h1>
|
|
343
|
+
<!-- Or with gradient variant: -->
|
|
344
|
+
<h1>Imagine it. <span class="v-gradient-text">See it.</span></h1>
|
|
345
|
+
```
|
|
346
|
+
```css
|
|
347
|
+
.accent-word { color: var(--accent, var(--v-accent)); }
|
|
348
|
+
/* Gradient variant โ use .v-gradient-text from the design system, or customize: */
|
|
349
|
+
.accent-gradient {
|
|
350
|
+
background: linear-gradient(135deg, var(--accent, var(--v-violet-500)), var(--v-indigo-400));
|
|
351
|
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Interactive Pill Toggles
|
|
356
|
+
```html
|
|
357
|
+
<div class="pill-toggles">
|
|
358
|
+
<button class="pill-toggle active">1W</button>
|
|
359
|
+
<button class="pill-toggle">1M</button>
|
|
360
|
+
<button class="pill-toggle">3M</button>
|
|
361
|
+
<button class="pill-toggle">1Y</button>
|
|
362
|
+
</div>
|
|
363
|
+
```
|
|
364
|
+
```css
|
|
365
|
+
.pill-toggles {
|
|
366
|
+
display: inline-flex; gap: var(--v-spacing-xxs);
|
|
367
|
+
background: var(--v-surface); border: 1px solid var(--v-surface-border);
|
|
368
|
+
border-radius: var(--v-radius-pill); padding: var(--v-spacing-xxs);
|
|
369
|
+
}
|
|
370
|
+
.pill-toggle {
|
|
371
|
+
padding: var(--v-spacing-xs) var(--v-spacing-md);
|
|
372
|
+
border-radius: var(--v-radius-pill); border: none; background: none;
|
|
373
|
+
font-size: var(--v-font-size-sm); font-weight: 500; color: var(--v-text-secondary);
|
|
374
|
+
cursor: pointer; transition: all var(--v-duration-fast);
|
|
375
|
+
}
|
|
376
|
+
.pill-toggle:hover { color: var(--v-text); }
|
|
377
|
+
.pill-toggle.active {
|
|
378
|
+
background: var(--accent, var(--v-accent)); color: white; font-weight: 600;
|
|
379
|
+
box-shadow: var(--v-shadow-sm);
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
```javascript
|
|
383
|
+
document.querySelectorAll('.pill-toggles').forEach(group => {
|
|
384
|
+
group.addEventListener('click', (e) => {
|
|
385
|
+
if (!e.target.classList.contains('pill-toggle')) return;
|
|
386
|
+
group.querySelectorAll('.pill-toggle').forEach(b => b.classList.remove('active'));
|
|
387
|
+
e.target.classList.add('active');
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Suggestion Chips
|
|
393
|
+
```html
|
|
394
|
+
<div class="chip-group">
|
|
395
|
+
<button class="chip">๐ All Rooms</button>
|
|
396
|
+
<button class="chip">๐๏ธ Living Room</button>
|
|
397
|
+
<button class="chip">๐ณ Kitchen</button>
|
|
398
|
+
<button class="chip">๐๏ธ Bedroom</button>
|
|
399
|
+
<button class="chip active">๐ฟ Bathroom</button>
|
|
400
|
+
</div>
|
|
401
|
+
```
|
|
402
|
+
```css
|
|
403
|
+
.chip-group { display: flex; flex-wrap: wrap; gap: var(--v-spacing-xs); }
|
|
404
|
+
.chip {
|
|
405
|
+
padding: var(--v-spacing-xs) var(--v-spacing-md);
|
|
406
|
+
border-radius: var(--v-radius-pill); border: 1px solid var(--v-surface-border);
|
|
407
|
+
background: var(--v-surface); font-size: var(--v-font-size-sm);
|
|
408
|
+
color: var(--v-text-secondary); cursor: pointer; transition: all var(--v-duration-fast);
|
|
409
|
+
}
|
|
410
|
+
.chip:hover { border-color: var(--accent, var(--v-accent)); color: var(--v-text); }
|
|
411
|
+
.chip.active {
|
|
412
|
+
background: color-mix(in srgb, var(--accent, var(--v-accent)) 12%, transparent);
|
|
413
|
+
border-color: var(--accent, var(--v-accent)); color: var(--accent, var(--v-accent)); font-weight: 600;
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Category Card Row
|
|
418
|
+
```html
|
|
419
|
+
<div class="category-cards">
|
|
420
|
+
<div class="category-card">
|
|
421
|
+
<span class="category-icon">๐งน</span>
|
|
422
|
+
<span class="category-name">Standard Clean</span>
|
|
423
|
+
<span class="category-meta">2-3 hrs ยท From $60</span>
|
|
424
|
+
</div>
|
|
425
|
+
<div class="category-card">
|
|
426
|
+
<span class="category-icon">โจ</span>
|
|
427
|
+
<span class="category-name">Deep Clean</span>
|
|
428
|
+
<span class="category-meta">4-5 hrs ยท From $120</span>
|
|
429
|
+
</div>
|
|
430
|
+
<div class="category-card">
|
|
431
|
+
<span class="category-icon">๐ฆ</span>
|
|
432
|
+
<span class="category-name">Move-Out</span>
|
|
433
|
+
<span class="category-meta">5-7 hrs ยท From $180</span>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
```
|
|
437
|
+
```css
|
|
438
|
+
.category-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--v-spacing-md); }
|
|
439
|
+
.category-card {
|
|
440
|
+
background: var(--v-surface); border: 1px solid var(--v-surface-border);
|
|
441
|
+
border-radius: var(--v-radius-lg); padding: var(--v-spacing-lg);
|
|
442
|
+
display: flex; flex-direction: column; align-items: center; gap: var(--v-spacing-sm);
|
|
443
|
+
text-align: center; cursor: pointer;
|
|
444
|
+
transition: transform var(--v-duration-fast), border-color var(--v-duration-fast);
|
|
445
|
+
}
|
|
446
|
+
.category-card:hover { transform: translateY(-2px); border-color: var(--accent, var(--v-accent)); }
|
|
447
|
+
.category-icon { font-size: 32px; line-height: 1; }
|
|
448
|
+
.category-name { font-weight: 600; font-size: var(--v-font-size-base); color: var(--v-text); }
|
|
449
|
+
.category-meta { font-size: var(--v-font-size-xs); color: var(--v-text-muted); }
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## Workflow
|
|
453
|
+
|
|
454
|
+
### 1. Gather Requirements
|
|
455
|
+
|
|
456
|
+
**Default: just build.** When a user says "build me a habit tracker," don't ask what colors they want or how many fields to include. Immediately:
|
|
457
|
+
|
|
458
|
+
1. Envision the ideal version of this app โ what would make someone excited to use it?
|
|
459
|
+
2. Pick a distinctive visual direction โ a color palette, atmospheric background, visual personality
|
|
460
|
+
3. Design a clean data schema
|
|
461
|
+
4. Build the complete, polished app with animations, interactions, and empty states
|
|
462
|
+
|
|
463
|
+
**Make creative decisions on behalf of the user.** They want to be delighted, not consulted. Pick the accent color. Choose between a dark moody aesthetic or a light airy one. Decide if cards should have glassmorphism or layered shadows. Add a background pattern or gradient. These are YOUR decisions as the designer.
|
|
464
|
+
|
|
465
|
+
**Only ask questions when the request is genuinely ambiguous** โ e.g., "build me an app" with no indication of what kind. Even then, prefer building something impressive based on context clues over asking a battery of questions.
|
|
466
|
+
|
|
467
|
+
**When in doubt, build something impressive** and let the user refine with `app_update`. The first impression matters most โ a beautiful app with the wrong shade of blue is easy to fix. A correct but ugly app is hard to come back from.
|
|
468
|
+
|
|
469
|
+
### 2. Design the Data Schema
|
|
470
|
+
|
|
471
|
+
Create a JSON Schema that defines the structure of a single record. Every record automatically gets `id`, `appId`, `createdAt`, and `updatedAt` โ you only define user-facing fields.
|
|
472
|
+
|
|
473
|
+
Schema guidelines:
|
|
474
|
+
- Use `type: "object"` at the top level
|
|
475
|
+
- Define `properties` for each field
|
|
476
|
+
- Supported types: `string`, `number`, `boolean`
|
|
477
|
+
- Add a `required` array for mandatory fields
|
|
478
|
+
- Keep schemas reasonably flat โ encode complex nested data as JSON strings when needed
|
|
479
|
+
|
|
480
|
+
Example schema for a project tracker:
|
|
481
|
+
```json
|
|
482
|
+
{
|
|
483
|
+
"type": "object",
|
|
484
|
+
"properties": {
|
|
485
|
+
"title": { "type": "string" },
|
|
486
|
+
"status": { "type": "string", "enum": ["backlog", "in-progress", "review", "done"] },
|
|
487
|
+
"priority": { "type": "string", "enum": ["low", "medium", "high", "critical"] },
|
|
488
|
+
"description": { "type": "string" },
|
|
489
|
+
"tags": { "type": "string" }
|
|
490
|
+
},
|
|
491
|
+
"required": ["title", "status"]
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### 3. Build the HTML Interface
|
|
496
|
+
|
|
497
|
+
Write a complete, self-contained HTML document rendered inside a sandboxed WebView on macOS.
|
|
498
|
+
|
|
499
|
+
#### Technical constraints
|
|
500
|
+
|
|
501
|
+
- Single HTML string โ no external files, CDNs, or imports
|
|
502
|
+
- All CSS in `<style>` in `<head>`, all JavaScript in `<script>` before `</body>`
|
|
503
|
+
- No external fonts, images, or resources โ use system fonts and CSS/SVG for visuals
|
|
504
|
+
- Design for 400-600px width with graceful resizing
|
|
505
|
+
- The WebView blocks all navigation โ links and form `action` attributes won't work
|
|
506
|
+
|
|
507
|
+
#### Injected design system
|
|
508
|
+
|
|
509
|
+
A design system CSS is auto-injected inside a `@layer`, so your styles always take priority. It provides element defaults and automatic light/dark mode switching via `prefers-color-scheme`.
|
|
510
|
+
|
|
511
|
+
**Use `--v-*` variables and `.v-*` classes** โ they handle light/dark mode automatically. No manual dark mode CSS needed.
|
|
512
|
+
|
|
513
|
+
Available design tokens:
|
|
514
|
+
|
|
515
|
+
| Category | Tokens |
|
|
516
|
+
|---|---|
|
|
517
|
+
| **Backgrounds** | `--v-bg`, `--v-surface`, `--v-surface-border` |
|
|
518
|
+
| **Text** | `--v-text`, `--v-text-secondary`, `--v-text-muted` |
|
|
519
|
+
| **Accent** | `--v-accent`, `--v-accent-hover` |
|
|
520
|
+
| **Status** | `--v-success`, `--v-danger`, `--v-warning` |
|
|
521
|
+
| **Spacing** | `--v-spacing-xxs` (2px) / `-xs` (4px) / `-sm` (8px) / `-md` (12px) / `-lg` (16px) / `-xl` (24px) / `-xxl` (32px) / `-xxxl` (48px) |
|
|
522
|
+
| **Radius** | `--v-radius-xs` (2px) / `-sm` (4px) / `-md` (8px) / `-lg` (12px) / `-xl` (16px) / `-pill` (999px) |
|
|
523
|
+
| **Shadows** | `--v-shadow-sm`, `--v-shadow-md`, `--v-shadow-lg` |
|
|
524
|
+
| **Typography** | `--v-font-family`, `--v-font-mono`, `--v-font-size-xs` (10px) / `-sm` (11px) / `-base` (14px) / `-lg` (17px) / `-xl` (22px) / `-2xl` (26px), `--v-line-height` |
|
|
525
|
+
| **Animation** | `--v-duration-fast` (0.15s) / `-standard` (0.25s) / `-slow` (0.4s) |
|
|
526
|
+
| **Palettes** | `--v-slate-{950..50}`, `--v-emerald-*`, `--v-violet-*`, `--v-indigo-*`, `--v-rose-*`, `--v-amber-*` |
|
|
527
|
+
|
|
528
|
+
Utility classes: `.v-button` (`.secondary`/`.danger`/`.ghost`), `.v-card`, `.v-list`/`.v-list-item`, `.v-badge` (`.success`/`.warning`/`.danger`), `.v-input-row`, `.v-empty-state`, `.v-toggle`.
|
|
529
|
+
|
|
530
|
+
**Custom themes:** When the user wants a specific branded look, write complete CSS with hardcoded colors and `@media (prefers-color-scheme: dark)` for dark variants. Don't mix `--v-*` auto-switching variables with hardcoded colors in the same element.
|
|
531
|
+
|
|
532
|
+
**Theme detection in JavaScript:**
|
|
533
|
+
```javascript
|
|
534
|
+
console.log(window.vellum.theme.mode); // 'light' or 'dark'
|
|
535
|
+
window.addEventListener('vellum-theme-change', (e) => {
|
|
536
|
+
// Update canvas colors, chart themes, etc.
|
|
537
|
+
console.log('Theme:', e.detail.mode);
|
|
538
|
+
});
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### Widget component library
|
|
542
|
+
|
|
543
|
+
A CSS/JS widget library is auto-injected alongside the design system. Use these for standard UI patterns โ skip them when custom HTML serves the user better.
|
|
544
|
+
|
|
545
|
+
**Layout & Data Primitives:**
|
|
546
|
+
|
|
547
|
+
`.v-metric-card` โ Big number with emoji icon, label, and trend:
|
|
548
|
+
```html
|
|
549
|
+
<div class="v-metric-card">
|
|
550
|
+
<span class="v-metric-icon">๐ฐ</span>
|
|
551
|
+
<span class="v-metric-label">Revenue</span>
|
|
552
|
+
<span class="v-metric-value">$12,450</span>
|
|
553
|
+
<span class="v-metric-trend up">โ 12.3%</span>
|
|
554
|
+
</div>
|
|
555
|
+
```
|
|
556
|
+
Wrap in `.v-metric-grid` for responsive 2-4 column layout. Always use a semantically meaningful emoji: ๐ฅ for streaks, ๐ for activity, ๐ง for hydration, ๐ for growth, etc.
|
|
557
|
+
|
|
558
|
+
`.v-data-table` โ Sortable table with sticky header and hover states:
|
|
559
|
+
```html
|
|
560
|
+
<table class="v-data-table" id="my-table">
|
|
561
|
+
<thead><tr>
|
|
562
|
+
<th><input type="checkbox"></th>
|
|
563
|
+
<th data-sortable>Name</th>
|
|
564
|
+
<th data-sortable>Amount</th>
|
|
565
|
+
</tr></thead>
|
|
566
|
+
<tbody><tr data-id="1">
|
|
567
|
+
<td><input type="checkbox"></td>
|
|
568
|
+
<td>Item</td>
|
|
569
|
+
<td data-sort-value="100">$100.00</td>
|
|
570
|
+
</tr></tbody>
|
|
571
|
+
</table>
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
`.v-tabs` โ Tab navigation with keyboard support:
|
|
575
|
+
```html
|
|
576
|
+
<div class="v-tabs" id="my-tabs">
|
|
577
|
+
<div class="v-tab-bar" role="tablist">
|
|
578
|
+
<button class="v-tab" aria-controls="panel-1">Tab 1</button>
|
|
579
|
+
<button class="v-tab" aria-controls="panel-2">Tab 2</button>
|
|
580
|
+
</div>
|
|
581
|
+
<div class="v-tab-panel" id="panel-1">Content 1</div>
|
|
582
|
+
<div class="v-tab-panel" id="panel-2" hidden>Content 2</div>
|
|
583
|
+
</div>
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
`.v-accordion` โ Collapsible sections:
|
|
587
|
+
```html
|
|
588
|
+
<div class="v-accordion" id="my-accordion">
|
|
589
|
+
<div class="v-accordion-item">
|
|
590
|
+
<button class="v-accordion-header" aria-expanded="true">Section 1</button>
|
|
591
|
+
<div class="v-accordion-body">Content here</div>
|
|
592
|
+
</div>
|
|
593
|
+
</div>
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
`.v-search-bar` โ Search input with clear button:
|
|
597
|
+
```html
|
|
598
|
+
<div class="v-search-bar">
|
|
599
|
+
<input type="text" placeholder="Search..." id="search">
|
|
600
|
+
<button class="v-search-clear">โ</button>
|
|
601
|
+
</div>
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
`.v-empty-state` โ No-data placeholder with CTA:
|
|
605
|
+
```html
|
|
606
|
+
<div class="v-empty-state">
|
|
607
|
+
<div class="v-empty-icon">๐</div>
|
|
608
|
+
<div class="v-empty-title">No items yet</div>
|
|
609
|
+
<div class="v-empty-desc">Create your first item to get started.</div>
|
|
610
|
+
<button class="v-button">Create Item</button>
|
|
611
|
+
</div>
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Additional layout widgets** (use with semantic HTML, all support `--v-*` tokens):
|
|
615
|
+
|
|
616
|
+
| Widget | Usage | Key Classes/Modifiers |
|
|
617
|
+
|---|---|---|
|
|
618
|
+
| `.v-timeline` | Vertical timeline | `.v-timeline-entry` (`.active`/`.success`/`.error`), `.v-timeline-time`, `.v-timeline-title`, `.v-timeline-desc` |
|
|
619
|
+
| `.v-action-list` | Rows with per-item actions | `.v-action-list-item`, `.v-action-content`, `.v-action-title`, `.v-action-subtitle`, `.v-action-buttons` |
|
|
620
|
+
| `.v-card-grid` | Responsive card grid | Wrap `.v-card` elements |
|
|
621
|
+
| `.v-progress-bar` | Horizontal progress | `.v-progress-header`, `.v-progress-track`, `.v-progress-fill` (`.success`/`.warning`/`.danger`) |
|
|
622
|
+
| `.v-status-badge` | Colored pill with dot | `.success`, `.error`, `.warning`, `.info` |
|
|
623
|
+
| `.v-stat-row` | Horizontal label-value pairs | `.v-stat`, `.v-stat-label`, `.v-stat-value` |
|
|
624
|
+
| `.v-toast` | Notification banner | `.success`, `.error`, `.warning`, `.info` โ prefer `vellum.widgets.toast()` |
|
|
625
|
+
| `.v-divider` | Section separator | Optional text label inside |
|
|
626
|
+
| `.v-avatar-row` | Contact/team display | `.v-avatar`, `.v-avatar-info`, `.v-avatar-name`, `.v-avatar-subtitle` |
|
|
627
|
+
| `.v-tag-group` | Wrapping tag row | Wrap `.v-badge` elements |
|
|
628
|
+
|
|
629
|
+
**Domain-specific widgets** (infer HTML structure from class names):
|
|
630
|
+
|
|
631
|
+
| Widget | Purpose | Key Classes |
|
|
632
|
+
|---|---|---|
|
|
633
|
+
| `.v-weather-card` | Temperature + forecast | `.v-weather-main`, `.v-weather-temp`, `.v-weather-condition`, `.v-weather-icon`, `.v-weather-details`, `.v-weather-forecast`, `.v-weather-forecast-item` |
|
|
634
|
+
| `.v-stock-ticker` | Price display + chart | `.v-stock-header`, `.v-stock-symbol`, `.v-stock-price`, `.v-stock-change` (`.up`/`.down`), `.v-stock-chart`, `.v-stock-meta` |
|
|
635
|
+
| `.v-flight-card` | Flight info | `.v-flight-header`, `.v-flight-airline`, `.v-flight-price`, `.v-flight-route`, `.v-flight-endpoint`, `.v-flight-time`, `.v-flight-code`, `.v-flight-duration`, `.v-flight-line` |
|
|
636
|
+
| `.v-billing-chart` | Usage/billing display | `.v-billing-header`, `.v-billing-total`, `.v-billing-period`, `.v-billing-canvas`, `.v-billing-legend`, `.v-billing-legend-item`, `.v-billing-legend-dot` |
|
|
637
|
+
| `.v-boarding-pass` | Pass-styled layout | `.v-bp-header`, `.v-bp-route`, `.v-bp-city`, `.v-bp-details`, `.v-bp-field`, `.v-bp-field-label`, `.v-bp-field-value` |
|
|
638
|
+
| `.v-itinerary` | Day-by-day travel plan | `.v-itinerary-day`, `.v-itinerary-date`, `.v-itinerary-item`, `.v-itinerary-time`, `.v-itinerary-content`, `.v-itinerary-title`, `.v-itinerary-location` |
|
|
639
|
+
| `.v-receipt` | Receipt layout | `.v-receipt-header`, `.v-receipt-store`, `.v-receipt-items`, `.v-receipt-line`, `.v-receipt-divider`, `.v-receipt-total` |
|
|
640
|
+
| `.v-invoice` | Formal invoice | `.v-invoice-header`, `.v-invoice-title`, `.v-invoice-number`, `.v-invoice-parties`, `.v-invoice-party-label`, `.v-invoice-party-name`, `.v-invoice-table`, `.v-invoice-totals`, `.v-invoice-line` (`.total`) |
|
|
641
|
+
|
|
642
|
+
**Content & landing page components:**
|
|
643
|
+
|
|
644
|
+
`.v-hero` โ Hero banner with gradient background, trust badge, and accent word:
|
|
645
|
+
```html
|
|
646
|
+
<div class="v-hero">
|
|
647
|
+
<span class="v-hero-badge">โจ Now with 4x faster generation</span>
|
|
648
|
+
<h1>Imagine it. <span class="v-gradient-text">See it.</span></h1>
|
|
649
|
+
<p class="v-hero-subtitle">A compelling tagline that makes users feel something.</p>
|
|
650
|
+
</div>
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
`.v-section-header` โ Section intro with label:
|
|
654
|
+
```html
|
|
655
|
+
<div class="v-section-header">
|
|
656
|
+
<span class="v-section-label">๐ฏ Section</span>
|
|
657
|
+
<h2>Section Title</h2>
|
|
658
|
+
<p class="v-section-desc">Description text.</p>
|
|
659
|
+
</div>
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
`.v-feature-grid` + `.v-feature-card` โ Feature showcase with hover lift:
|
|
663
|
+
```html
|
|
664
|
+
<div class="v-feature-grid">
|
|
665
|
+
<div class="v-feature-card">
|
|
666
|
+
<div class="v-feature-icon">๐</div>
|
|
667
|
+
<div class="v-feature-title">Feature Name</div>
|
|
668
|
+
<div class="v-feature-desc">Short description.</div>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
`.v-pullquote` โ Blockquote with gradient accent border. `.v-comparison` โ Before/after cards (3-column grid with `.before`/`.after` modifiers). `.v-page` โ Centered container (max-width 600px). Use `.v-animate-in` on children for staggered fade-in. Use `.v-gradient-text` for accent-colored gradient text.
|
|
674
|
+
|
|
675
|
+
#### Widget JavaScript utilities
|
|
676
|
+
|
|
677
|
+
Interactive utilities at `window.vellum.widgets.*`:
|
|
678
|
+
|
|
679
|
+
**SVG Charts:**
|
|
680
|
+
```javascript
|
|
681
|
+
// Sparkline โ inline mini chart
|
|
682
|
+
vellum.widgets.sparkline('container-id', [10, 25, 15, 30], {
|
|
683
|
+
width: 200, height: 40, color: 'var(--v-success)', strokeWidth: 2, fill: true
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// Bar chart โ labels, tooltips, optional horizontal
|
|
687
|
+
vellum.widgets.barChart('container-id', [
|
|
688
|
+
{ label: 'Jan', value: 120 },
|
|
689
|
+
{ label: 'Feb', value: 180, color: 'var(--v-success)' }
|
|
690
|
+
], { width: 400, height: 200, showLabels: true, showValues: true, horizontal: false });
|
|
691
|
+
|
|
692
|
+
// Line chart โ gradient fill, grid, hover crosshair
|
|
693
|
+
vellum.widgets.lineChart('container-id', [
|
|
694
|
+
{ label: 'Mon', value: 42 },
|
|
695
|
+
{ label: 'Tue', value: 58 }
|
|
696
|
+
], { width: 400, height: 200, showDots: true, showGrid: true, gridLines: 4 });
|
|
697
|
+
|
|
698
|
+
// Progress ring โ circular gauge
|
|
699
|
+
vellum.widgets.progressRing('container-id', 75, {
|
|
700
|
+
size: 100, strokeWidth: 8, color: 'var(--v-success)', label: '75%'
|
|
701
|
+
});
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**Data Formatting:**
|
|
705
|
+
```javascript
|
|
706
|
+
vellum.widgets.formatCurrency(1234.56, 'USD'); // "$1,234.56"
|
|
707
|
+
vellum.widgets.formatDate('2025-01-15', 'relative'); // "3d ago"
|
|
708
|
+
vellum.widgets.formatDate('2025-01-15', 'short'); // "1/15/25"
|
|
709
|
+
vellum.widgets.formatNumber(1234567, { compact: true }); // "1.2M"
|
|
710
|
+
vellum.widgets.formatNumber(0.156, { decimals: 1 }); // "0.2"
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
**Interactive Behaviors:**
|
|
714
|
+
```javascript
|
|
715
|
+
vellum.widgets.sortTable('table-id'); // Wire th[data-sortable] click-to-sort
|
|
716
|
+
vellum.widgets.sortTable('table-id', 0); // Sort by column 0 immediately
|
|
717
|
+
vellum.widgets.filterTable('table-id', 'search-input-id'); // Live text search
|
|
718
|
+
vellum.widgets.tabs('tabs-id'); // Tab switching + keyboard nav
|
|
719
|
+
vellum.widgets.accordion('accordion-id', { allowMultiple: true });
|
|
720
|
+
vellum.widgets.multiSelect('table-id'); // Checkboxes + select-all
|
|
721
|
+
vellum.widgets.toast('Saved!', 'success', 4000); // Auto-dismiss notification
|
|
722
|
+
vellum.widgets.toast('Connection lost', 'error', 0); // Manual dismiss
|
|
723
|
+
vellum.widgets.countdown('timer-el', '2025-12-31T00:00:00Z', {
|
|
724
|
+
onComplete: () => console.log('Done!')
|
|
725
|
+
});
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
#### Composition recipes
|
|
729
|
+
|
|
730
|
+
Combine widgets with wiring code to build complex UIs:
|
|
731
|
+
|
|
732
|
+
**Search-driven list with suggestion chips** โ filter items with quick-tap categories:
|
|
733
|
+
```html
|
|
734
|
+
<div class="v-search-bar"><input id="search" placeholder="Search..."></div>
|
|
735
|
+
<div class="chip-group" style="margin-top: var(--v-spacing-sm);">
|
|
736
|
+
<button class="chip active" data-filter="all">๐ All</button>
|
|
737
|
+
<button class="chip" data-filter="kitchen">๐ณ Kitchen</button>
|
|
738
|
+
<button class="chip" data-filter="bedroom">๐๏ธ Bedroom</button>
|
|
739
|
+
<button class="chip" data-filter="bathroom">๐ฟ Bathroom</button>
|
|
740
|
+
</div>
|
|
741
|
+
<ul class="v-action-list" id="list"></ul>
|
|
742
|
+
<div class="v-empty-state" id="empty" hidden>
|
|
743
|
+
<div class="v-empty-icon">๐</div>
|
|
744
|
+
<div class="v-empty-title">No results</div>
|
|
745
|
+
</div>
|
|
746
|
+
```
|
|
747
|
+
```javascript
|
|
748
|
+
let activeFilter = 'all';
|
|
749
|
+
document.getElementById('search').addEventListener('input', filterList);
|
|
750
|
+
document.querySelectorAll('.chip[data-filter]').forEach(chip => {
|
|
751
|
+
chip.addEventListener('click', () => {
|
|
752
|
+
document.querySelectorAll('.chip[data-filter]').forEach(c => c.classList.remove('active'));
|
|
753
|
+
chip.classList.add('active');
|
|
754
|
+
activeFilter = chip.dataset.filter;
|
|
755
|
+
filterList();
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
function filterList() {
|
|
760
|
+
const q = document.getElementById('search').value.toLowerCase();
|
|
761
|
+
let visible = 0;
|
|
762
|
+
document.querySelectorAll('#list .v-action-list-item').forEach(item => {
|
|
763
|
+
const textMatch = item.textContent.toLowerCase().includes(q);
|
|
764
|
+
const catMatch = activeFilter === 'all' || item.dataset.category === activeFilter;
|
|
765
|
+
item.hidden = !(textMatch && catMatch);
|
|
766
|
+
if (!item.hidden) visible++;
|
|
767
|
+
});
|
|
768
|
+
document.getElementById('empty').hidden = visible > 0;
|
|
769
|
+
}
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
**Form with inline validation:**
|
|
773
|
+
```html
|
|
774
|
+
<form id="create-form" novalidate>
|
|
775
|
+
<div class="v-input-row">
|
|
776
|
+
<label>Title *</label>
|
|
777
|
+
<input id="title" required placeholder="Enter title">
|
|
778
|
+
<span class="field-error" id="title-error"></span>
|
|
779
|
+
</div>
|
|
780
|
+
<div class="v-input-row">
|
|
781
|
+
<label>Priority</label>
|
|
782
|
+
<select id="priority">
|
|
783
|
+
<option value="low">Low</option>
|
|
784
|
+
<option value="medium" selected>Medium</option>
|
|
785
|
+
<option value="high">High</option>
|
|
786
|
+
</select>
|
|
787
|
+
</div>
|
|
788
|
+
<button type="submit" class="v-button" id="submit-btn">Create</button>
|
|
789
|
+
</form>
|
|
790
|
+
```
|
|
791
|
+
```css
|
|
792
|
+
.field-error { color: var(--v-danger); font-size: var(--v-font-size-xs); min-height: 1em; }
|
|
793
|
+
input:invalid:not(:placeholder-shown) { border-color: var(--v-danger); }
|
|
794
|
+
```
|
|
795
|
+
```javascript
|
|
796
|
+
document.getElementById('create-form').addEventListener('submit', async (e) => {
|
|
797
|
+
e.preventDefault();
|
|
798
|
+
const title = document.getElementById('title').value.trim();
|
|
799
|
+
if (!title) {
|
|
800
|
+
document.getElementById('title-error').textContent = 'Title is required';
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
document.getElementById('submit-btn').disabled = true;
|
|
804
|
+
try {
|
|
805
|
+
await window.vellum.data.create({
|
|
806
|
+
title,
|
|
807
|
+
priority: document.getElementById('priority').value
|
|
808
|
+
});
|
|
809
|
+
vellum.widgets.toast('Created!', 'success');
|
|
810
|
+
e.target.reset();
|
|
811
|
+
document.getElementById('title-error').textContent = '';
|
|
812
|
+
await loadRecords();
|
|
813
|
+
} catch (err) {
|
|
814
|
+
vellum.widgets.toast('Failed to create', 'error');
|
|
815
|
+
} finally {
|
|
816
|
+
document.getElementById('submit-btn').disabled = false;
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
**Dashboard** โ contextual header + emoji stats + pill toggles + chart:
|
|
822
|
+
```html
|
|
823
|
+
<!-- Contextual header -->
|
|
824
|
+
<div style="margin-bottom: var(--v-spacing-xxxl);">
|
|
825
|
+
<p style="color: var(--v-text-muted); font-size: var(--v-font-size-sm); margin: 0;">Saturday, Feb 15</p>
|
|
826
|
+
<h1 style="margin: var(--v-spacing-xs) 0;">Good morning, <span class="accent-word">Alex</span></h1>
|
|
827
|
+
<span class="trust-pill accent">๐ฅ 7-day streak</span>
|
|
828
|
+
</div>
|
|
829
|
+
|
|
830
|
+
<!-- Pill toggles for time range -->
|
|
831
|
+
<div class="pill-toggles" style="margin-bottom: var(--v-spacing-xl);">
|
|
832
|
+
<button class="pill-toggle active">1W</button>
|
|
833
|
+
<button class="pill-toggle">1M</button>
|
|
834
|
+
<button class="pill-toggle">3M</button>
|
|
835
|
+
<button class="pill-toggle">1Y</button>
|
|
836
|
+
</div>
|
|
837
|
+
|
|
838
|
+
<!-- Emoji stat cards -->
|
|
839
|
+
<div class="emoji-stat-row" style="margin-bottom: var(--v-spacing-xxl);">
|
|
840
|
+
<div class="emoji-stat-card">
|
|
841
|
+
<span class="emoji-stat-icon">๐ฅ</span>
|
|
842
|
+
<span class="emoji-stat-value" id="cal-value">1,284</span>
|
|
843
|
+
<span class="emoji-stat-label">Calories</span>
|
|
844
|
+
</div>
|
|
845
|
+
<div class="emoji-stat-card">
|
|
846
|
+
<span class="emoji-stat-icon">๐</span>
|
|
847
|
+
<span class="emoji-stat-value" id="steps-value">8,421</span>
|
|
848
|
+
<span class="emoji-stat-label">Steps</span>
|
|
849
|
+
</div>
|
|
850
|
+
<div class="emoji-stat-card">
|
|
851
|
+
<span class="emoji-stat-icon">๐ง</span>
|
|
852
|
+
<span class="emoji-stat-value" id="hydration-value">2.4L</span>
|
|
853
|
+
<span class="emoji-stat-label">Hydration</span>
|
|
854
|
+
</div>
|
|
855
|
+
</div>
|
|
856
|
+
|
|
857
|
+
<!-- Chart + trend badge -->
|
|
858
|
+
<div class="v-card" style="margin-bottom: var(--v-spacing-xxl);">
|
|
859
|
+
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom: var(--v-spacing-md);">
|
|
860
|
+
<h3 style="margin:0;">Weekly Activity</h3>
|
|
861
|
+
<span class="trust-pill accent">๐ +12% vs last week</span>
|
|
862
|
+
</div>
|
|
863
|
+
<div id="chart" style="height:200px;"></div>
|
|
864
|
+
</div>
|
|
865
|
+
|
|
866
|
+
<!-- Atmospheric tagline -->
|
|
867
|
+
<p style="text-align:center; color: var(--v-text-muted); font-size: var(--v-font-size-sm); font-style:italic;">Powered by your consistency.</p>
|
|
868
|
+
```
|
|
869
|
+
```javascript
|
|
870
|
+
function esc(s) { const d = document.createElement('div'); d.textContent = String(s); return d.innerHTML; }
|
|
871
|
+
|
|
872
|
+
async function loadDashboard() {
|
|
873
|
+
const records = await window.vellum.data.query();
|
|
874
|
+
// Update stat values from real data
|
|
875
|
+
// Render chart
|
|
876
|
+
vellum.widgets.barChart('chart', records.map(r => ({
|
|
877
|
+
label: esc(r.data.name), value: r.data.amount
|
|
878
|
+
})));
|
|
879
|
+
}
|
|
880
|
+
// Wire pill toggles
|
|
881
|
+
document.querySelectorAll('.pill-toggles').forEach(group => {
|
|
882
|
+
group.addEventListener('click', (e) => {
|
|
883
|
+
if (!e.target.classList.contains('pill-toggle')) return;
|
|
884
|
+
group.querySelectorAll('.pill-toggle').forEach(b => b.classList.remove('active'));
|
|
885
|
+
e.target.classList.add('active');
|
|
886
|
+
// Re-fetch data for selected range
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
**Landing page** โ nav bar + trust badge hero + accent word + category cards:
|
|
892
|
+
```html
|
|
893
|
+
<div class="v-page">
|
|
894
|
+
<!-- Navigation bar -->
|
|
895
|
+
<nav class="app-navbar reveal">
|
|
896
|
+
<div class="navbar-brand">โจ SparkClean</div>
|
|
897
|
+
<div class="navbar-links">
|
|
898
|
+
<a href="#" class="nav-link active">Home</a>
|
|
899
|
+
<a href="#" class="nav-link">Services</a>
|
|
900
|
+
<a href="#" class="nav-link">Pricing</a>
|
|
901
|
+
</div>
|
|
902
|
+
<button class="v-button navbar-cta">Book Now</button>
|
|
903
|
+
</nav>
|
|
904
|
+
|
|
905
|
+
<!-- Hero with trust badge + accent word -->
|
|
906
|
+
<div class="v-hero reveal">
|
|
907
|
+
<span class="v-hero-badge">๐ Trusted by 12,000+ homes</span>
|
|
908
|
+
<h1>Your home, <span class="v-gradient-text">spotless.</span></h1>
|
|
909
|
+
<p class="v-hero-subtitle">Professional cleaning matched to your schedule. Book in 60 seconds.</p>
|
|
910
|
+
</div>
|
|
911
|
+
|
|
912
|
+
<!-- Category cards -->
|
|
913
|
+
<div class="reveal">
|
|
914
|
+
<h2 style="text-align:center; margin-bottom: var(--v-spacing-xl);">Our <span class="accent-word">Services</span></h2>
|
|
915
|
+
<div class="category-cards">
|
|
916
|
+
<div class="category-card">
|
|
917
|
+
<span class="category-icon">๐งน</span>
|
|
918
|
+
<span class="category-name">Standard Clean</span>
|
|
919
|
+
<span class="category-meta">2-3 hrs ยท From $60</span>
|
|
920
|
+
</div>
|
|
921
|
+
<div class="category-card">
|
|
922
|
+
<span class="category-icon">โจ</span>
|
|
923
|
+
<span class="category-name">Deep Clean</span>
|
|
924
|
+
<span class="category-meta">4-5 hrs ยท From $120</span>
|
|
925
|
+
</div>
|
|
926
|
+
<div class="category-card">
|
|
927
|
+
<span class="category-icon">๐ฆ</span>
|
|
928
|
+
<span class="category-name">Move-Out</span>
|
|
929
|
+
<span class="category-meta">5-7 hrs ยท From $180</span>
|
|
930
|
+
</div>
|
|
931
|
+
</div>
|
|
932
|
+
</div>
|
|
933
|
+
|
|
934
|
+
<!-- Feature grid -->
|
|
935
|
+
<div class="v-feature-grid">
|
|
936
|
+
<div class="v-feature-card reveal"><div class="v-feature-icon">โก</div><div class="v-feature-title">Fast Booking</div><div class="v-feature-desc">Book in under 60 seconds.</div></div>
|
|
937
|
+
<div class="v-feature-card reveal"><div class="v-feature-icon">๐ก๏ธ</div><div class="v-feature-title">Insured</div><div class="v-feature-desc">Fully bonded & insured teams.</div></div>
|
|
938
|
+
<div class="v-feature-card reveal"><div class="v-feature-icon">๐</div><div class="v-feature-title">Eco Products</div><div class="v-feature-desc">Safe for kids & pets.</div></div>
|
|
939
|
+
</div>
|
|
940
|
+
|
|
941
|
+
<!-- Atmospheric tagline -->
|
|
942
|
+
<p class="reveal" style="text-align:center; color: var(--v-text-muted); font-style:italic;">A cleaner home starts here.</p>
|
|
943
|
+
</div>
|
|
944
|
+
```
|
|
945
|
+
```javascript
|
|
946
|
+
const observer = new IntersectionObserver((entries) => {
|
|
947
|
+
entries.forEach((entry, i) => {
|
|
948
|
+
if (entry.isIntersecting) {
|
|
949
|
+
setTimeout(() => entry.target.classList.add('visible'), i * 120);
|
|
950
|
+
observer.unobserve(entry.target);
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
}, { threshold: 0.1 });
|
|
954
|
+
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
**Multi-select table** โ checkboxes + bulk toolbar:
|
|
958
|
+
```html
|
|
959
|
+
<table class="v-data-table" id="my-table">
|
|
960
|
+
<thead><tr>
|
|
961
|
+
<th><input type="checkbox"></th>
|
|
962
|
+
<th data-sortable>Name</th>
|
|
963
|
+
<th data-sortable>Status</th>
|
|
964
|
+
</tr></thead>
|
|
965
|
+
<tbody>
|
|
966
|
+
<tr data-id="1"><td><input type="checkbox"></td><td>Item 1</td><td>Active</td></tr>
|
|
967
|
+
</tbody>
|
|
968
|
+
</table>
|
|
969
|
+
<div id="bulk-toolbar" hidden style="position:sticky;bottom:0;padding:12px;background:var(--v-surface);border-top:1px solid var(--v-surface-border);display:flex;gap:8px;">
|
|
970
|
+
<button class="v-button danger" onclick="handleBulk('delete')">Delete Selected</button>
|
|
971
|
+
<button class="v-button secondary" onclick="handleBulk('archive')">Archive</button>
|
|
972
|
+
</div>
|
|
973
|
+
```
|
|
974
|
+
```javascript
|
|
975
|
+
vellum.widgets.multiSelect('my-table');
|
|
976
|
+
document.getElementById('my-table').addEventListener('change', () => {
|
|
977
|
+
const any = document.querySelectorAll('#my-table tbody input:checked').length > 0;
|
|
978
|
+
document.getElementById('bulk-toolbar').hidden = !any;
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
async function handleBulk(action) {
|
|
982
|
+
const ids = Array.from(document.querySelectorAll('#my-table tbody input:checked'))
|
|
983
|
+
.map(cb => cb.closest('tr').dataset.id);
|
|
984
|
+
if (action === 'delete') {
|
|
985
|
+
const ok = await window.vellum.confirm('Delete items?', `Delete ${ids.length} selected items?`);
|
|
986
|
+
if (!ok) return;
|
|
987
|
+
for (const id of ids) await window.vellum.data.delete(id);
|
|
988
|
+
vellum.widgets.toast(`Deleted ${ids.length} items`, 'success');
|
|
989
|
+
}
|
|
990
|
+
await loadRecords();
|
|
991
|
+
}
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
#### When to use widgets vs custom HTML
|
|
995
|
+
|
|
996
|
+
- **Use widgets** for standard patterns โ tables, metrics, timelines, notifications
|
|
997
|
+
- **Use custom HTML** for novel or creative UIs โ games, art tools, unique dashboards
|
|
998
|
+
- **Mix freely** โ widgets compose well together and with custom elements
|
|
999
|
+
- Always prioritize the ideal user experience over using the widget library
|
|
1000
|
+
|
|
1001
|
+
#### Advanced techniques
|
|
1002
|
+
|
|
1003
|
+
Use modern web APIs to build genuinely impressive apps:
|
|
1004
|
+
|
|
1005
|
+
- **Canvas 2D / WebGL** โ charts, visualization, drawing, games, generative art
|
|
1006
|
+
- **SVG** โ icons, diagrams, interactive graphics
|
|
1007
|
+
- **CSS animations & keyframes** โ loading states, micro-interactions, page transitions
|
|
1008
|
+
- **CSS transforms** โ drag-and-drop, card flips, 3D effects
|
|
1009
|
+
- **CSS gradients & filters** โ blur effects, color overlays, rich backgrounds
|
|
1010
|
+
- **CSS Grid subgrid** โ complex dashboard layouts
|
|
1011
|
+
- **Web Audio API** โ sound effects, metronomes, music tools
|
|
1012
|
+
- **requestAnimationFrame** โ smooth animations, interactive canvases
|
|
1013
|
+
- **Drag and drop** (HTML5) โ reorderable lists, kanban boards
|
|
1014
|
+
- **IntersectionObserver** โ scroll-triggered animations, lazy rendering
|
|
1015
|
+
- **ResizeObserver** โ responsive canvas/chart sizing
|
|
1016
|
+
|
|
1017
|
+
Don't reach for these when a simple list will do, but don't avoid them when they'd make the app genuinely better.
|
|
1018
|
+
|
|
1019
|
+
#### Data bridge API
|
|
1020
|
+
|
|
1021
|
+
The HTML interface can read and write records via `window.vellum.data`. All methods return Promises.
|
|
1022
|
+
|
|
1023
|
+
- `window.vellum.data.query()` โ Returns all records: `{ id, appId, data, createdAt, updatedAt }[]`
|
|
1024
|
+
- `window.vellum.data.create(data)` โ Creates a record. Returns the created record.
|
|
1025
|
+
- `window.vellum.data.update(recordId, data)` โ Updates a record by ID. Returns updated record.
|
|
1026
|
+
- `window.vellum.data.delete(recordId)` โ Deletes a record by ID. Returns void.
|
|
1027
|
+
|
|
1028
|
+
Important:
|
|
1029
|
+
- Call `query()` on page load to populate initial state
|
|
1030
|
+
- User fields live in `record.data` (e.g., `record.data.title`)
|
|
1031
|
+
- Record IDs are UUID strings
|
|
1032
|
+
- All operations are async โ use `async/await`
|
|
1033
|
+
- Wrap all calls in `try/catch`
|
|
1034
|
+
|
|
1035
|
+
#### Client-side state management
|
|
1036
|
+
|
|
1037
|
+
`localStorage` and `sessionStorage` are available for ephemeral UI state (filters, view modes, collapsed state, preferences, form drafts). Use `window.vellum.data` for persistent app records, `localStorage` for UI preferences.
|
|
1038
|
+
|
|
1039
|
+
#### JavaScript patterns
|
|
1040
|
+
|
|
1041
|
+
Initialize apps with clean state management:
|
|
1042
|
+
```javascript
|
|
1043
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
1044
|
+
await loadRecords();
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
let allRecords = [];
|
|
1048
|
+
|
|
1049
|
+
async function loadRecords() {
|
|
1050
|
+
try {
|
|
1051
|
+
allRecords = await window.vellum.data.query();
|
|
1052
|
+
render();
|
|
1053
|
+
} catch (err) {
|
|
1054
|
+
console.error('Failed to load:', err);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function render() {
|
|
1059
|
+
// Re-render UI from allRecords
|
|
1060
|
+
// Apply client-side filtering/sorting
|
|
1061
|
+
}
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
For complex apps, use a single state object:
|
|
1065
|
+
```javascript
|
|
1066
|
+
const state = {
|
|
1067
|
+
records: [],
|
|
1068
|
+
filter: localStorage.getItem('filter') || 'all',
|
|
1069
|
+
sortBy: localStorage.getItem('sortBy') || 'createdAt',
|
|
1070
|
+
searchQuery: '',
|
|
1071
|
+
editingId: null,
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
function setState(updates) {
|
|
1075
|
+
Object.assign(state, updates);
|
|
1076
|
+
render();
|
|
1077
|
+
}
|
|
1078
|
+
```
|
|
1079
|
+
|
|
1080
|
+
**Loading state pattern:**
|
|
1081
|
+
```javascript
|
|
1082
|
+
async function loadWithSkeleton() {
|
|
1083
|
+
document.getElementById('content').innerHTML = `
|
|
1084
|
+
<div class="skeleton skeleton-heading"></div>
|
|
1085
|
+
<div class="skeleton skeleton-text"></div>
|
|
1086
|
+
<div class="skeleton skeleton-text" style="width:60%"></div>`;
|
|
1087
|
+
const records = await window.vellum.data.query();
|
|
1088
|
+
setState({ records });
|
|
1089
|
+
}
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
**HTML escaping:** Always escape user-controlled data before inserting it into the DOM via `innerHTML`. Use this utility:
|
|
1093
|
+
```javascript
|
|
1094
|
+
function esc(s) { const d = document.createElement('div'); d.textContent = String(s); return d.innerHTML; }
|
|
1095
|
+
```
|
|
1096
|
+
Then wrap every user data interpolation: `` `<td>${esc(record.data.name)}</td>` ``. Alternatively, use `textContent` or DOM APIs to set text without innerHTML. Failing to escape leads to XSS vulnerabilities.
|
|
1097
|
+
|
|
1098
|
+
### 4. Single-Page App Views
|
|
1099
|
+
|
|
1100
|
+
Apps run inside a sandboxed WebView that blocks all navigation โ standard `<a>` links will not work for in-app navigation. All apps are effectively single-page. When an app needs multiple views (e.g., list + detail, dashboard + settings), use JavaScript to swap content within the page.
|
|
1101
|
+
|
|
1102
|
+
#### View switching pattern
|
|
1103
|
+
|
|
1104
|
+
Use a simple `showView()` function to toggle between sections:
|
|
1105
|
+
```html
|
|
1106
|
+
<nav class="app-nav">
|
|
1107
|
+
<button class="nav-link active" onclick="showView('home')">Home</button>
|
|
1108
|
+
<button class="nav-link" onclick="showView('settings')">Settings</button>
|
|
1109
|
+
</nav>
|
|
1110
|
+
|
|
1111
|
+
<div id="view-home" class="view">
|
|
1112
|
+
<!-- Home content -->
|
|
1113
|
+
</div>
|
|
1114
|
+
<div id="view-settings" class="view" hidden>
|
|
1115
|
+
<!-- Settings content -->
|
|
1116
|
+
</div>
|
|
1117
|
+
|
|
1118
|
+
<style>
|
|
1119
|
+
.app-nav { display: flex; gap: 4px; padding: 8px 12px; background: var(--v-surface); border-bottom: 1px solid var(--v-surface-border); }
|
|
1120
|
+
.nav-link { padding: 6px 14px; border-radius: 6px; border: none; background: none; color: var(--v-text-secondary); font-size: 13px; font-weight: 500; cursor: pointer; transition: all 150ms; }
|
|
1121
|
+
.nav-link:hover { background: var(--v-surface-border); color: var(--v-text); }
|
|
1122
|
+
.nav-link.active { background: var(--v-accent); color: white; }
|
|
1123
|
+
</style>
|
|
1124
|
+
```
|
|
1125
|
+
```javascript
|
|
1126
|
+
function showView(name) {
|
|
1127
|
+
document.querySelectorAll('.view').forEach(v => v.hidden = true);
|
|
1128
|
+
document.getElementById('view-' + name).hidden = false;
|
|
1129
|
+
document.querySelectorAll('.nav-link').forEach(btn => btn.classList.remove('active'));
|
|
1130
|
+
document.querySelector(`[onclick="showView('${name}')"]`)?.classList.add('active');
|
|
1131
|
+
}
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
For detail pages, call `showView('detail')` and populate the detail section's content dynamically before showing it. Use a "Back" button that calls `showView('home')` to return to the list.
|
|
1135
|
+
|
|
1136
|
+
### 5. Create and Open the App
|
|
1137
|
+
|
|
1138
|
+
Call `app_create` with:
|
|
1139
|
+
- `name`: Short descriptive name
|
|
1140
|
+
- `description`: One-sentence summary
|
|
1141
|
+
- `schema_json`: JSON schema as string
|
|
1142
|
+
- `html`: Complete HTML document as string
|
|
1143
|
+
- `auto_open`: (optional, defaults to `true`) Opens the app immediately
|
|
1144
|
+
- `preview`: (optional) Inline preview card โ see below
|
|
1145
|
+
|
|
1146
|
+
Since `auto_open` defaults to `true`, you don't need to call `app_open` separately after `app_create`.
|
|
1147
|
+
|
|
1148
|
+
#### Preview metadata
|
|
1149
|
+
|
|
1150
|
+
Both `ui_show` and `app_create` support a `preview` object for an inline chat preview card. Always include it so the user sees a compact summary without opening the app.
|
|
1151
|
+
|
|
1152
|
+
**With `ui_show`:**
|
|
1153
|
+
```json
|
|
1154
|
+
{
|
|
1155
|
+
"surface_type": "dynamic_page",
|
|
1156
|
+
"data": {
|
|
1157
|
+
"html": "...",
|
|
1158
|
+
"preview": {
|
|
1159
|
+
"title": "Expense Tracker",
|
|
1160
|
+
"subtitle": "Personal Finance",
|
|
1161
|
+
"description": "Track daily expenses with category breakdowns.",
|
|
1162
|
+
"icon": "๐ฐ",
|
|
1163
|
+
"metrics": [
|
|
1164
|
+
{ "label": "Records", "value": "24" },
|
|
1165
|
+
{ "label": "Categories", "value": "8" }
|
|
1166
|
+
]
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
**With `app_create`:**
|
|
1173
|
+
```json
|
|
1174
|
+
{
|
|
1175
|
+
"name": "Expense Tracker",
|
|
1176
|
+
"schema_json": "{}",
|
|
1177
|
+
"html": "...",
|
|
1178
|
+
"preview": {
|
|
1179
|
+
"title": "Expense Tracker",
|
|
1180
|
+
"icon": "๐ฐ",
|
|
1181
|
+
"metrics": [
|
|
1182
|
+
{ "label": "Records", "value": "24" },
|
|
1183
|
+
{ "label": "Categories", "value": "8" }
|
|
1184
|
+
]
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
Preview fields: `title` (required), `subtitle`, `description`, `icon` (emoji), `metrics` (up to 3 key-value pills). When `app_create` is called with `auto_open: true` (the default), the preview is forwarded through `app_open` automatically.
|
|
1190
|
+
|
|
1191
|
+
### 6. Handle Iteration
|
|
1192
|
+
|
|
1193
|
+
When the user requests changes to an existing app, prefer **`app_file_edit`** over rewriting the entire file. It performs surgical find-and-replace edits (like sed), which is faster and less error-prone than re-emitting a full page.
|
|
1194
|
+
|
|
1195
|
+
#### Editing code
|
|
1196
|
+
|
|
1197
|
+
- **`app_file_edit`** โ preferred for modifying existing code. Provide `app_id`, `path` (e.g. `index.html`, `styles.css`), `old_string` (exact text to find), and `new_string` (replacement). Use this for targeted changes like updating styles, fixing bugs, or adding features.
|
|
1198
|
+
- **`app_file_write`** โ use when creating a new file or when changes are so extensive that a full rewrite is cleaner. Provide `app_id`, `path`, and `content`.
|
|
1199
|
+
- Always include a **`status`** parameter when calling `app_file_edit` or `app_file_write` โ a brief human-readable message describing what you are doing (e.g. "adding dark mode styles", "updating navigation layout", "fixing chart rendering bug"). This gives the user visible progress feedback.
|
|
1200
|
+
|
|
1201
|
+
#### Metadata vs code changes
|
|
1202
|
+
|
|
1203
|
+
- **`app_update`** โ use for metadata changes only: `name`, `description`, and `schema_json`. Do not use it for code changes.
|
|
1204
|
+
- **`app_file_edit`** / **`app_file_write`** โ use for all code changes (HTML, CSS, JS). The surface refreshes automatically after file edits.
|
|
1205
|
+
- If schema changes affect existing records, mention this.
|
|
1206
|
+
|
|
1207
|
+
#### Multi-file apps
|
|
1208
|
+
|
|
1209
|
+
Apps can have multiple files beyond `index.html`. Use separate files for CSS and JavaScript to keep code organized:
|
|
1210
|
+
|
|
1211
|
+
- Create additional files with `app_file_write` (e.g. `styles.css`, `app.js`, `components/chart.js`).
|
|
1212
|
+
- Link them from `index.html` using `<link rel="stylesheet" href="styles.css">` and `<script src="app.js"></script>`.
|
|
1213
|
+
- Use `app_file_list` to see all files in an app.
|
|
1214
|
+
- Use `app_file_read` to read any file with line numbers (helpful before making edits).
|
|
1215
|
+
|
|
1216
|
+
Use `app_delete` to start over. Use `app_list` to check existing apps. Use `app_query` to inspect app data.
|
|
1217
|
+
|
|
1218
|
+
## Interactive Quality Standard
|
|
1219
|
+
|
|
1220
|
+
Every app must meet these interaction baselines โ they're the difference between "works" and "feels professional."
|
|
1221
|
+
|
|
1222
|
+
### Feedback for Every Action
|
|
1223
|
+
|
|
1224
|
+
Every user action must produce visible feedback:
|
|
1225
|
+
```javascript
|
|
1226
|
+
// After creating a record
|
|
1227
|
+
vellum.widgets.toast('Task created', 'success');
|
|
1228
|
+
|
|
1229
|
+
// After deleting
|
|
1230
|
+
vellum.widgets.toast('Deleted', 'success');
|
|
1231
|
+
|
|
1232
|
+
// After updating
|
|
1233
|
+
vellum.widgets.toast('Changes saved', 'success');
|
|
1234
|
+
|
|
1235
|
+
// On error
|
|
1236
|
+
vellum.widgets.toast('Something went wrong', 'error');
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
### Confirmation for Destructive Actions
|
|
1240
|
+
|
|
1241
|
+
Use `window.vellum.confirm()` before deleting, resetting, or any irreversible action:
|
|
1242
|
+
```javascript
|
|
1243
|
+
async function deleteRecord(id) {
|
|
1244
|
+
const confirmed = await window.vellum.confirm(
|
|
1245
|
+
'Delete this item?',
|
|
1246
|
+
'This action cannot be undone.'
|
|
1247
|
+
);
|
|
1248
|
+
if (!confirmed) return;
|
|
1249
|
+
await window.vellum.data.delete(id);
|
|
1250
|
+
vellum.widgets.toast('Deleted', 'success');
|
|
1251
|
+
await loadRecords();
|
|
1252
|
+
}
|
|
1253
|
+
```
|
|
1254
|
+
`window.vellum.confirm(title, message)` returns a `Promise<boolean>` โ `true` if the user clicks OK, `false` for Cancel. It shows a native macOS dialog.
|
|
1255
|
+
|
|
1256
|
+
### Form Validation
|
|
1257
|
+
|
|
1258
|
+
Validate before submit, show errors inline:
|
|
1259
|
+
```css
|
|
1260
|
+
.field-error {
|
|
1261
|
+
color: var(--v-danger);
|
|
1262
|
+
font-size: var(--v-font-size-xs);
|
|
1263
|
+
margin-top: 2px;
|
|
1264
|
+
min-height: 1em;
|
|
1265
|
+
}
|
|
1266
|
+
input.invalid, select.invalid {
|
|
1267
|
+
border-color: var(--v-danger);
|
|
1268
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--v-danger) 15%, transparent);
|
|
1269
|
+
}
|
|
1270
|
+
```
|
|
1271
|
+
- Disable submit button while a required field is empty
|
|
1272
|
+
- Clear error messages on input focus
|
|
1273
|
+
- Show loading state on submit button during async operations
|
|
1274
|
+
|
|
1275
|
+
### Loading States
|
|
1276
|
+
|
|
1277
|
+
Never show a blank screen while data loads:
|
|
1278
|
+
```javascript
|
|
1279
|
+
function showLoading() {
|
|
1280
|
+
container.innerHTML = `
|
|
1281
|
+
<div class="skeleton skeleton-heading"></div>
|
|
1282
|
+
<div class="skeleton skeleton-text"></div>
|
|
1283
|
+
<div class="skeleton skeleton-text" style="width:70%"></div>`;
|
|
1284
|
+
}
|
|
1285
|
+
```
|
|
1286
|
+
- Disable buttons during async operations to prevent double-submit
|
|
1287
|
+
- Use the skeleton shimmer CSS from the Visual Techniques section
|
|
1288
|
+
|
|
1289
|
+
### Keyboard Navigation
|
|
1290
|
+
|
|
1291
|
+
- `Tab` moves between interactive elements in logical order
|
|
1292
|
+
- `Enter` submits forms, activates buttons
|
|
1293
|
+
- `Escape` closes modals, cancels edits, clears search
|
|
1294
|
+
- Use `tabindex` only when natural DOM order is insufficient
|
|
1295
|
+
|
|
1296
|
+
## What Great Apps Look Like
|
|
1297
|
+
|
|
1298
|
+
These are the apps you should aspire to โ each one demonstrates the Lovable-quality patterns in action:
|
|
1299
|
+
|
|
1300
|
+
- **Fitness dashboard** โ Purple accent (`--accent: #8A5BE0`), lavender tinted background. Contextual header: "Good morning, Alex" with date. Pill toggles (Day/Week/Month) switching chart ranges. Emoji stat cards row (๐ฅ Calories, ๐ Steps, ๐ง Hydration, ๐ด Sleep). Progress rings with distinct colors per metric. Trust pill: "๐ฅ 7-day streak". Atmospheric tagline: "Powered by your consistency."
|
|
1301
|
+
- **Plant tracker** โ Sage green accent (`--accent: #18B07A`), soft sage background (`#F0F5F0`). Contextual header: "๐ฟ Your Garden" with plant count badge. Category cards for plant types with emoji (๐ต Succulents, ๐ฟ Tropicals, ๐ธ Flowering). Emoji stat row (๐ง Watered today, โ๏ธ Light exposure, ๐ฑ New growth). Suggestion chips for filtering: "Needs water", "Low light", "Outdoors".
|
|
1302
|
+
- **Finance vault** โ Navy/blue-gray accent (`--accent: #3B82F6`), cool gray background (`#F5F7FA`). Contextual header: "Welcome back, Alex" with net worth badge. Transaction list with emoji identifiers (๐ Rent, ๐ Groceries, โ Coffee). Trend badge: "+8.2% this month". Pill toggles for time ranges (1W/1M/3M/1Y).
|
|
1303
|
+
- **Cleaning service landing page** โ Warm amber accent (`--accent: #E8A020`), cream background (`#FEFCF9`). Nav bar with logo ("โจ SparkClean") + CTA. Trust pill in hero: "๐ Trusted by 12,000+ homes". Accent word hero: "Your home, **spotless.**" Category cards (๐งน Standard, โจ Deep Clean, ๐ฆ Move-Out with pricing). Feature grid with eco/speed/insurance.
|
|
1304
|
+
- **AI tool landing page** โ Purple gradient text, dark hero section. Suggestion chips below a demo input: "Summarize this", "Generate code", "Explain like I'm 5". Feature grid with emoji icons. Trust badge: "โก 4x faster than v1". Atmospheric tagline: "Intelligence, simplified."
|
|
1305
|
+
|
|
1306
|
+
### Pre-Ship Design Checklist
|
|
1307
|
+
|
|
1308
|
+
Before delivering any app, mentally verify these 10 items โ they cover the gap between "functional" and "designer-quality":
|
|
1309
|
+
|
|
1310
|
+
1. **Domain-matched palette** โ Is the accent color appropriate for this domain? (Not default violet)
|
|
1311
|
+
2. **Tinted background** โ Does the body have a warm/cool tint instead of pure white/dark?
|
|
1312
|
+
3. **Emoji stat cards** โ Are there emoji icons in metric cards, list items, or navigation?
|
|
1313
|
+
4. **Accent word in heading** โ Is ONE key word in the hero heading colored or gradient-filled?
|
|
1314
|
+
5. **Contextual header** โ Is there a greeting, date, or personalized welcome (not just an app title)?
|
|
1315
|
+
6. **Trust/status pill badge** โ Is there at least one pill badge with a stat, streak, or social proof?
|
|
1316
|
+
7. **Generous spacing** โ Are section gaps 32-48px? Does the layout feel spacious, not cramped?
|
|
1317
|
+
8. **Clean card borders** โ Do cards use subtle 1px borders instead of heavy multi-layer shadows?
|
|
1318
|
+
9. **Interactive elements** โ Are there pill toggles, suggestion chips, or filter controls?
|
|
1319
|
+
10. **Atmospheric tagline** โ Is there a warm, human-sounding line at the bottom or between sections?
|
|
1320
|
+
|
|
1321
|
+
### Additional widget classes
|
|
1322
|
+
|
|
1323
|
+
| Widget | Purpose | Key Classes |
|
|
1324
|
+
|---|---|---|
|
|
1325
|
+
| `.v-pill-toggles` | Time range / filter toggle group | `.v-pill-toggle` (`.active`) โ container with pill buttons |
|
|
1326
|
+
| `.v-chip-group` | Suggestion / filter chip row | `.v-chip` (`.active`) โ wrapping row of clickable pills |
|
|
1327
|
+
| `.v-metric-card .v-metric-icon` | Emoji icon in metric cards | Place emoji `<span>` with `.v-metric-icon` inside `.v-metric-card` |
|
|
1328
|
+
|
|
1329
|
+
Every app should include: search/filter, toast notifications for all CRUD operations, `window.vellum.confirm()` for destructive actions, staggered page-load animation, card hover effects, and skeleton loading states.
|
|
1330
|
+
|
|
1331
|
+
## Error Handling
|
|
1332
|
+
|
|
1333
|
+
- If `app_create` fails, verify `schema_json` is valid JSON and `html` is a complete HTML document. Retry with fixes.
|
|
1334
|
+
- If `app_open` fails, verify `app_id` with `app_list`.
|
|
1335
|
+
- If the user reports visual issues, use `app_file_edit` to fix the code. The surface refreshes automatically.
|
|
1336
|
+
- All `window.vellum.data` calls must be wrapped in `try/catch` with user-friendly error feedback:
|
|
1337
|
+
```javascript
|
|
1338
|
+
try {
|
|
1339
|
+
await window.vellum.data.create(data);
|
|
1340
|
+
vellum.widgets.toast('Created!', 'success');
|
|
1341
|
+
} catch (err) {
|
|
1342
|
+
console.error('Create failed:', err);
|
|
1343
|
+
vellum.widgets.toast('Failed to save. Please try again.', 'error');
|
|
1344
|
+
}
|
|
1345
|
+
```
|
|
1346
|
+
- Never let a failed data operation silently pass โ always show a toast or inline error message.
|
|
1347
|
+
- If the page loads with no data, show a designed empty state (`.v-empty-state`) โ never a blank screen.
|
|
1348
|
+
- For forms, show validation errors inline next to the relevant field, not as an alert.
|
|
1349
|
+
|
|
1350
|
+
## Actionable UI
|
|
1351
|
+
|
|
1352
|
+
When the user wants to triage, manage, or bulk-act on a collection of items (emails, files, notifications, tasks, subscriptions, contacts), generate an interactive UI that lets them review, select, and act on items directly.
|
|
1353
|
+
|
|
1354
|
+
### Pattern
|
|
1355
|
+
1. **Fetch data** โ use the relevant tools to gather the items
|
|
1356
|
+
2. **Generate interactive UI** โ render a `dynamic_page` with selectable items and action buttons
|
|
1357
|
+
3. **User selects + clicks action** โ the UI sends a `surfaceAction` with an action ID and selected item IDs
|
|
1358
|
+
4. **Execute tools** โ parse the action, call the appropriate tools
|
|
1359
|
+
5. **Update UI** โ use `ui_update` to remove processed items and show feedback via `widgets.toast()`
|
|
1360
|
+
|
|
1361
|
+
### HTML structure
|
|
1362
|
+
Choose the best layout for the data: grouped cards with checkboxes, data tables with selectable rows, kanban columns, stacked list items with inline actions, or any creative layout. The key constraint: items must be selectable and action buttons must call `sendAction` with the selected item IDs.
|
|
1363
|
+
|
|
1364
|
+
### CSS building blocks
|
|
1365
|
+
- `.v-action-bar` โ sticky bar at top, auto-hidden when nothing selected. Contains `.v-action-bar-count` and `.v-action-bar-buttons`
|
|
1366
|
+
- `.v-action-progress` โ inline progress bar for bulk operations
|
|
1367
|
+
- `.v-group-header` / `.v-group-body` โ collapsible grouped sections
|
|
1368
|
+
- `.v-row-removing` โ fade-out + slide animation for processed items
|
|
1369
|
+
|
|
1370
|
+
### Action data conventions
|
|
1371
|
+
- Use semantic action IDs: `archive`, `unsubscribe`, `delete`, `move`, `mark_read`
|
|
1372
|
+
- Always include selected item IDs: `sendAction("archive", { ids: ["msg_1", "msg_2"] })`
|
|
1373
|
+
|
|
1374
|
+
### Processing flow
|
|
1375
|
+
1. Parse the `surfaceAction` to get the action ID and data
|
|
1376
|
+
2. Use `vellum.confirm(title, message)` for destructive actions before executing
|
|
1377
|
+
3. Call the relevant tools with the item IDs
|
|
1378
|
+
4. Use `ui_update` to remove processed items and update counts
|
|
1379
|
+
5. Show `widgets.toast()` for feedback
|
|
1380
|
+
|
|
1381
|
+
### Error handling
|
|
1382
|
+
- Handle partial failures: remove successful items, toast count, keep failed items selectable for retry
|
|
1383
|
+
|
|
1384
|
+
### Surface lifecycle
|
|
1385
|
+
- Use `ui_show` with `display: "panel"` to keep the surface open alongside chat
|
|
1386
|
+
- Use `widgets.groupedSelect()` for grouped multi-select with action bar
|
|
1387
|
+
- Use `widgets.removeItems()` to animate processed items out
|
|
1388
|
+
|
|
1389
|
+
## Home Base
|
|
1390
|
+
|
|
1391
|
+
Home Base starts from a prebuilt scaffold. When updating Home Base, preserve required task-lane anchors and apply changes through `app_file_edit` or `app_file_write`.
|
|
1392
|
+
|
|
1393
|
+
Home Base buttons send prefilled natural-language prompts through `vellum.sendAction`. Treat these as normal user messages, not as direct execution commands.
|
|
1394
|
+
- For appearance changes: keep customization color-first, ask for explicit confirmation before applying a full-dashboard update.
|
|
1395
|
+
- For optional capability setup tasks (voice/computer control/ambient): keep them user-initiated and request permissions only when required for the chosen path.
|
|
1396
|
+
- If a prompt is underspecified, ask one brief follow-up and continue.
|
|
1397
|
+
|
|
1398
|
+
## External Links
|
|
1399
|
+
|
|
1400
|
+
When building apps with linkable items (search results, product cards, bookings), use `vellum.openLink(url, metadata)` to make them clickable. Construct deep-link URLs when possible (airline booking pages, product pages, hotel reservations). Include `metadata.provider` and `metadata.type` for context: `vellum.openLink("https://delta.com/book?flight=DL123", {provider: "delta", type: "booking"})`.
|
|
1401
|
+
|
|
1402
|
+
## Branding
|
|
1403
|
+
|
|
1404
|
+
A "Built on Vellum" badge is auto-injected into every dynamic page and app at the bottom-right corner. Do NOT add your own "Built on Vellum" or "Powered by Vellum" text โ the badge is handled automatically by the rendering layer.
|