@w3kits-com/plugin-opendesign 0.1.8 → 0.1.10
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/dist/404/index.html +1 -1
- package/dist/404.html +1 -1
- package/dist/__next.$oc$slug.__PAGE__.txt +3 -3
- package/dist/__next.$oc$slug.txt +3 -3
- package/dist/__next._full.txt +11 -11
- package/dist/__next._head.txt +4 -4
- package/dist/__next._index.txt +5 -5
- package/dist/__next._tree.txt +1 -1
- package/dist/__w3kits/assets/design-systems/README.md +103 -0
- package/dist/__w3kits/assets/design-systems/_schema/AGENTS.md +179 -0
- package/dist/__w3kits/assets/design-systems/_schema/defaults.css +100 -0
- package/dist/__w3kits/assets/design-systems/_schema/tokens.schema.ts +275 -0
- package/dist/__w3kits/assets/design-systems/agentic/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/airbnb/DESIGN.md +393 -0
- package/dist/__w3kits/assets/design-systems/airbnb/components.html +1373 -0
- package/dist/__w3kits/assets/design-systems/airbnb/tokens.css +261 -0
- package/dist/__w3kits/assets/design-systems/airtable/DESIGN.md +92 -0
- package/dist/__w3kits/assets/design-systems/ant/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/apple/DESIGN.md +250 -0
- package/dist/__w3kits/assets/design-systems/apple/components.html +749 -0
- package/dist/__w3kits/assets/design-systems/apple/tokens.css +286 -0
- package/dist/__w3kits/assets/design-systems/application/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/arc/DESIGN.md +152 -0
- package/dist/__w3kits/assets/design-systems/artistic/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/atelier-zero/DESIGN.md +316 -0
- package/dist/__w3kits/assets/design-systems/bento/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/binance/DESIGN.md +348 -0
- package/dist/__w3kits/assets/design-systems/bmw/DESIGN.md +183 -0
- package/dist/__w3kits/assets/design-systems/bmw-m/DESIGN.md +246 -0
- package/dist/__w3kits/assets/design-systems/bold/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/brutalism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/bugatti/DESIGN.md +271 -0
- package/dist/__w3kits/assets/design-systems/cafe/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/cal/DESIGN.md +262 -0
- package/dist/__w3kits/assets/design-systems/canva/DESIGN.md +157 -0
- package/dist/__w3kits/assets/design-systems/cisco/DESIGN.md +201 -0
- package/dist/__w3kits/assets/design-systems/claude/DESIGN.md +315 -0
- package/dist/__w3kits/assets/design-systems/clay/DESIGN.md +307 -0
- package/dist/__w3kits/assets/design-systems/claymorphism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/clean/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/clickhouse/DESIGN.md +284 -0
- package/dist/__w3kits/assets/design-systems/cohere/DESIGN.md +269 -0
- package/dist/__w3kits/assets/design-systems/coinbase/DESIGN.md +132 -0
- package/dist/__w3kits/assets/design-systems/colorful/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/composio/DESIGN.md +310 -0
- package/dist/__w3kits/assets/design-systems/contemporary/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/corporate/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/cosmic/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/creative/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/cursor/DESIGN.md +312 -0
- package/dist/__w3kits/assets/design-systems/cursor/components.html +654 -0
- package/dist/__w3kits/assets/design-systems/cursor/tokens.css +218 -0
- package/dist/__w3kits/assets/design-systems/dashboard/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/default/DESIGN.md +62 -0
- package/dist/__w3kits/assets/design-systems/default/components.html +523 -0
- package/dist/__w3kits/assets/design-systems/default/tokens.css +200 -0
- package/dist/__w3kits/assets/design-systems/discord/DESIGN.md +162 -0
- package/dist/__w3kits/assets/design-systems/discord/components.html +359 -0
- package/dist/__w3kits/assets/design-systems/discord/tokens.css +125 -0
- package/dist/__w3kits/assets/design-systems/dithered/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/doodle/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/dramatic/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/duolingo/DESIGN.md +154 -0
- package/dist/__w3kits/assets/design-systems/editorial/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/elegant/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/elevenlabs/DESIGN.md +268 -0
- package/dist/__w3kits/assets/design-systems/energetic/DESIGN.md +72 -0
- package/dist/__w3kits/assets/design-systems/enterprise/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/expo/DESIGN.md +284 -0
- package/dist/__w3kits/assets/design-systems/expressive/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/fantasy/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/ferrari/DESIGN.md +317 -0
- package/dist/__w3kits/assets/design-systems/figma/DESIGN.md +223 -0
- package/dist/__w3kits/assets/design-systems/figma/components.html +344 -0
- package/dist/__w3kits/assets/design-systems/figma/tokens.css +126 -0
- package/dist/__w3kits/assets/design-systems/flat/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/framer/DESIGN.md +249 -0
- package/dist/__w3kits/assets/design-systems/friendly/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/futuristic/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/github/DESIGN.md +155 -0
- package/dist/__w3kits/assets/design-systems/github/components.html +383 -0
- package/dist/__w3kits/assets/design-systems/github/tokens.css +125 -0
- package/dist/__w3kits/assets/design-systems/glassmorphism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/gradient/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/hashicorp/DESIGN.md +281 -0
- package/dist/__w3kits/assets/design-systems/hud/DESIGN.md +173 -0
- package/dist/__w3kits/assets/design-systems/huggingface/DESIGN.md +149 -0
- package/dist/__w3kits/assets/design-systems/ibm/DESIGN.md +335 -0
- package/dist/__w3kits/assets/design-systems/intercom/DESIGN.md +149 -0
- package/dist/__w3kits/assets/design-systems/kami/DESIGN.md +410 -0
- package/dist/__w3kits/assets/design-systems/kami/components.html +601 -0
- package/dist/__w3kits/assets/design-systems/kami/tokens.css +272 -0
- package/dist/__w3kits/assets/design-systems/kraken/DESIGN.md +128 -0
- package/dist/__w3kits/assets/design-systems/lamborghini/DESIGN.md +291 -0
- package/dist/__w3kits/assets/design-systems/levels/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/linear-app/DESIGN.md +370 -0
- package/dist/__w3kits/assets/design-systems/linear-app/components.html +370 -0
- package/dist/__w3kits/assets/design-systems/linear-app/tokens.css +130 -0
- package/dist/__w3kits/assets/design-systems/lingo/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/loom/DESIGN.md +201 -0
- package/dist/__w3kits/assets/design-systems/lovable/DESIGN.md +301 -0
- package/dist/__w3kits/assets/design-systems/luxury/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/mastercard/DESIGN.md +368 -0
- package/dist/__w3kits/assets/design-systems/material/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/meta/DESIGN.md +369 -0
- package/dist/__w3kits/assets/design-systems/minimal/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/minimax/DESIGN.md +260 -0
- package/dist/__w3kits/assets/design-systems/mintlify/DESIGN.md +329 -0
- package/dist/__w3kits/assets/design-systems/miro/DESIGN.md +111 -0
- package/dist/__w3kits/assets/design-systems/mission-control/DESIGN.md +474 -0
- package/dist/__w3kits/assets/design-systems/mistral-ai/DESIGN.md +264 -0
- package/dist/__w3kits/assets/design-systems/modern/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/mongodb/DESIGN.md +269 -0
- package/dist/__w3kits/assets/design-systems/mono/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/neobrutalism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/neon/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/neumorphism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/nike/DESIGN.md +366 -0
- package/dist/__w3kits/assets/design-systems/notion/DESIGN.md +312 -0
- package/dist/__w3kits/assets/design-systems/notion/components.html +413 -0
- package/dist/__w3kits/assets/design-systems/notion/tokens.css +130 -0
- package/dist/__w3kits/assets/design-systems/nvidia/DESIGN.md +296 -0
- package/dist/__w3kits/assets/design-systems/ollama/DESIGN.md +270 -0
- package/dist/__w3kits/assets/design-systems/openai/DESIGN.md +140 -0
- package/dist/__w3kits/assets/design-systems/openai/components.html +382 -0
- package/dist/__w3kits/assets/design-systems/openai/tokens.css +133 -0
- package/dist/__w3kits/assets/design-systems/opencode-ai/DESIGN.md +284 -0
- package/dist/__w3kits/assets/design-systems/pacman/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/paper/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/perspective/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/pinterest/DESIGN.md +233 -0
- package/dist/__w3kits/assets/design-systems/playstation/DESIGN.md +367 -0
- package/dist/__w3kits/assets/design-systems/posthog/DESIGN.md +259 -0
- package/dist/__w3kits/assets/design-systems/premium/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/professional/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/publication/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/raycast/DESIGN.md +271 -0
- package/dist/__w3kits/assets/design-systems/refined/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/renault/DESIGN.md +314 -0
- package/dist/__w3kits/assets/design-systems/replicate/DESIGN.md +264 -0
- package/dist/__w3kits/assets/design-systems/resend/DESIGN.md +306 -0
- package/dist/__w3kits/assets/design-systems/retro/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/revolut/DESIGN.md +188 -0
- package/dist/__w3kits/assets/design-systems/runwayml/DESIGN.md +247 -0
- package/dist/__w3kits/assets/design-systems/sanity/DESIGN.md +360 -0
- package/dist/__w3kits/assets/design-systems/sentry/DESIGN.md +265 -0
- package/dist/__w3kits/assets/design-systems/shadcn/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/shopify/DESIGN.md +353 -0
- package/dist/__w3kits/assets/design-systems/shopify/components.html +342 -0
- package/dist/__w3kits/assets/design-systems/shopify/tokens.css +141 -0
- package/dist/__w3kits/assets/design-systems/simple/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/skeumorphism/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/slack/DESIGN.md +363 -0
- package/dist/__w3kits/assets/design-systems/slack/components.html +387 -0
- package/dist/__w3kits/assets/design-systems/slack/tokens.css +127 -0
- package/dist/__w3kits/assets/design-systems/sleek/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/spacex/DESIGN.md +197 -0
- package/dist/__w3kits/assets/design-systems/spacious/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/spotify/DESIGN.md +249 -0
- package/dist/__w3kits/assets/design-systems/spotify/components.html +365 -0
- package/dist/__w3kits/assets/design-systems/spotify/tokens.css +127 -0
- package/dist/__w3kits/assets/design-systems/starbucks/DESIGN.md +583 -0
- package/dist/__w3kits/assets/design-systems/storytelling/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/stripe/DESIGN.md +325 -0
- package/dist/__w3kits/assets/design-systems/stripe/components.html +1018 -0
- package/dist/__w3kits/assets/design-systems/stripe/tokens.css +295 -0
- package/dist/__w3kits/assets/design-systems/supabase/DESIGN.md +258 -0
- package/dist/__w3kits/assets/design-systems/superhuman/DESIGN.md +255 -0
- package/dist/__w3kits/assets/design-systems/tesla/DESIGN.md +289 -0
- package/dist/__w3kits/assets/design-systems/tetris/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/theverge/DESIGN.md +342 -0
- package/dist/__w3kits/assets/design-systems/together-ai/DESIGN.md +266 -0
- package/dist/__w3kits/assets/design-systems/totality-festival/DESIGN.md +206 -0
- package/dist/__w3kits/assets/design-systems/trading-terminal/DESIGN.md +178 -0
- package/dist/__w3kits/assets/design-systems/uber/DESIGN.md +298 -0
- package/dist/__w3kits/assets/design-systems/uber/components.html +347 -0
- package/dist/__w3kits/assets/design-systems/uber/tokens.css +131 -0
- package/dist/__w3kits/assets/design-systems/urdu/DESIGN.md +1002 -0
- package/dist/__w3kits/assets/design-systems/vercel/DESIGN.md +313 -0
- package/dist/__w3kits/assets/design-systems/vercel/components.html +839 -0
- package/dist/__w3kits/assets/design-systems/vercel/tokens.css +270 -0
- package/dist/__w3kits/assets/design-systems/vibrant/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/vintage/DESIGN.md +71 -0
- package/dist/__w3kits/assets/design-systems/vodafone/DESIGN.md +426 -0
- package/dist/__w3kits/assets/design-systems/voltagent/DESIGN.md +326 -0
- package/dist/__w3kits/assets/design-systems/warm-editorial/DESIGN.md +65 -0
- package/dist/__w3kits/assets/design-systems/warp/DESIGN.md +256 -0
- package/dist/__w3kits/assets/design-systems/webex/DESIGN.md +207 -0
- package/dist/__w3kits/assets/design-systems/webflow/DESIGN.md +95 -0
- package/dist/__w3kits/assets/design-systems/wechat/DESIGN.md +302 -0
- package/dist/__w3kits/assets/design-systems/wired/DESIGN.md +281 -0
- package/dist/__w3kits/assets/design-systems/wise/DESIGN.md +176 -0
- package/dist/__w3kits/assets/design-systems/x-ai/DESIGN.md +260 -0
- package/dist/__w3kits/assets/design-systems/xiaohongshu/DESIGN.md +402 -0
- package/dist/__w3kits/assets/design-systems/zapier/DESIGN.md +331 -0
- package/dist/__w3kits/assets/design-templates/AGENTS.md +34 -0
- package/dist/__w3kits/assets/design-templates/audio-jingle/SKILL.md +132 -0
- package/dist/__w3kits/assets/design-templates/audio-jingle/example.html +128 -0
- package/dist/__w3kits/assets/design-templates/blog-post/SKILL.md +81 -0
- package/dist/__w3kits/assets/design-templates/blog-post/example.html +80 -0
- package/dist/__w3kits/assets/design-templates/clinical-case-report/SKILL.md +209 -0
- package/dist/__w3kits/assets/design-templates/clinical-case-report/example.html +698 -0
- package/dist/__w3kits/assets/design-templates/clinical-case-report/examples/example-stemi.html +698 -0
- package/dist/__w3kits/assets/design-templates/clinical-case-report/references/case-formats.md +94 -0
- package/dist/__w3kits/assets/design-templates/clinical-case-report/references/checklist.md +41 -0
- package/dist/__w3kits/assets/design-templates/critique/SKILL.md +258 -0
- package/dist/__w3kits/assets/design-templates/critique/example.html +671 -0
- package/dist/__w3kits/assets/design-templates/dashboard/SKILL.md +76 -0
- package/dist/__w3kits/assets/design-templates/dashboard/example.html +118 -0
- package/dist/__w3kits/assets/design-templates/dating-web/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/dating-web/example.html +265 -0
- package/dist/__w3kits/assets/design-templates/dcf-valuation/SKILL.md +140 -0
- package/dist/__w3kits/assets/design-templates/dcf-valuation/references/sector-wacc.md +42 -0
- package/dist/__w3kits/assets/design-templates/digital-eguide/SKILL.md +95 -0
- package/dist/__w3kits/assets/design-templates/digital-eguide/example.html +204 -0
- package/dist/__w3kits/assets/design-templates/docs-page/SKILL.md +80 -0
- package/dist/__w3kits/assets/design-templates/docs-page/example.html +122 -0
- package/dist/__w3kits/assets/design-templates/email-marketing/SKILL.md +85 -0
- package/dist/__w3kits/assets/design-templates/email-marketing/example.html +159 -0
- package/dist/__w3kits/assets/design-templates/eng-runbook/SKILL.md +51 -0
- package/dist/__w3kits/assets/design-templates/eng-runbook/example.html +250 -0
- package/dist/__w3kits/assets/design-templates/finance-report/SKILL.md +62 -0
- package/dist/__w3kits/assets/design-templates/finance-report/example.html +242 -0
- package/dist/__w3kits/assets/design-templates/flowai-live-dashboard-template/SKILL.md +87 -0
- package/dist/__w3kits/assets/design-templates/flowai-live-dashboard-template/assets/template.html +387 -0
- package/dist/__w3kits/assets/design-templates/flowai-live-dashboard-template/example.html +13 -0
- package/dist/__w3kits/assets/design-templates/flowai-live-dashboard-template/references/checklist.md +35 -0
- package/dist/__w3kits/assets/design-templates/gamified-app/SKILL.md +109 -0
- package/dist/__w3kits/assets/design-templates/gamified-app/example.html +292 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/SKILL.md +130 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/example.html +473 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/references/README.md +10 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/references/artifact-example.json +15 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/references/example-data.json +138 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/references/provenance-example.json +92 -0
- package/dist/__w3kits/assets/design-templates/github-dashboard/references/template.html +473 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/README.en.md +119 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/README.md +120 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/README.pt-BR.md +121 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/SKILL.md +314 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/assets/example-slides.html +318 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/assets/template.html +647 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/references/checklist.md +265 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/references/components.md +363 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/references/layouts.md +630 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/references/styles.md +195 -0
- package/dist/__w3kits/assets/design-templates/guizang-ppt/references/themes.md +122 -0
- package/dist/__w3kits/assets/design-templates/hr-onboarding/SKILL.md +52 -0
- package/dist/__w3kits/assets/design-templates/hr-onboarding/example.html +219 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/.clawscan-allow +12 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/README.md +234 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/README.pt-BR.md +239 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/README.zh-CN.md +238 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/SKILL.md +251 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/animations.css +138 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/_util.js +63 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/chain-react.js +41 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/confetti-cannon.js +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/constellation.js +44 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/counter-explosion.js +58 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/data-stream.js +45 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/firework.js +51 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/galaxy-swirl.js +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/gradient-blob.js +39 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/knowledge-graph.js +69 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/letter-explode.js +50 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/magnetic-field.js +40 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/matrix-rain.js +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/neural-net.js +75 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/orbit-ring.js +38 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/particle-burst.js +42 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/shockwave.js +39 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/sparkle-trail.js +62 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/starfield.js +30 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/typewriter-multi.js +51 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx/word-cascade.js +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/animations/fx-runtime.js +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/base.css +150 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/fonts.css +9 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/runtime.js +960 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/academic-paper.css +23 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/arctic-cool.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/aurora.css +20 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/bauhaus.css +16 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/blueprint.css +19 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/catppuccin-latte.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/catppuccin-mocha.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/corporate-clean.css +19 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/cyberpunk-neon.css +23 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/dracula.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/editorial-serif.css +18 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/engineering-whiteprint.css +26 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/glassmorphism.css +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/gruvbox-dark.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/japanese-minimal.css +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/magazine-bold.css +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/memphis-pop.css +20 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/midcentury.css +19 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/minimal-white.css +16 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/neo-brutalism.css +17 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/news-broadcast.css +20 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/nord.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/pitch-deck-vc.css +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/rainbow-gradient.css +16 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/retro-tv.css +22 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/rose-pine.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/sharp-mono.css +17 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/soft-pastel.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/solarized-light.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/sunset-warm.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/swiss-grid.css +17 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/terminal-green.css +18 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/tokyo-night.css +14 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/vaporwave.css +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/xiaohongshu-white.css +16 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/assets/themes/y2k-chrome.css +20 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/_theme-cell.html +56 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/animations.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/hero.gif +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/layouts-live.gif +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/layouts.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/montage-animations.html +61 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/montage-layouts.html +72 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/montage-templates.html +72 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/montage-themes.html +38 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/presenter-mode.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/templates.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/docs/readme/themes.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/examples/demo-deck/index.html +161 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/animations.md +147 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/authoring-guide.md +141 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/full-decks.md +98 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/layouts.md +103 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/presenter-mode.md +240 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/references/themes.md +107 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/new-deck.sh +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/render.sh +71 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_01.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_02.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_03.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_04.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_05.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_06.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_07.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_08.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_09.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_10.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_11.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_12.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_13.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_14.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_15.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_16.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_17.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_18.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_19.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/animation-showcase/animation-showcase_20.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_01.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_02.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_03.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_04.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_05.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_06.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_07.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_08.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_09.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_10.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_11.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_12.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_13.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_14.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_15.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_16.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_17.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_18.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_19.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_20.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_21.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_22.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_23.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_24.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_25.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_26.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_27.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_28.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_29.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_30.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_31.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_32.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_33.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_34.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_35.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/scripts/verify-output/theme-showcase/theme-showcase_36.png +0 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/animation-showcase.html +172 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/deck.html +69 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/course-module/README.md +8 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/course-module/index.html +189 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/course-module/style.css +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/dir-key-nav-minimal/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/dir-key-nav-minimal/index.html +138 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/dir-key-nav-minimal/style.css +60 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/graphify-dark-graph/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/graphify-dark-graph/index.html +180 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/graphify-dark-graph/style.css +54 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/hermes-cyber-terminal/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/hermes-cyber-terminal/index.html +199 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/hermes-cyber-terminal/style.css +55 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/knowledge-arch-blueprint/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/knowledge-arch-blueprint/index.html +190 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/knowledge-arch-blueprint/style.css +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/obsidian-claude-gradient/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/obsidian-claude-gradient/index.html +144 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/obsidian-claude-gradient/style.css +59 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/pitch-deck/README.md +9 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/pitch-deck/index.html +148 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/pitch-deck/style.css +40 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/presenter-mode-reveal/README.md +102 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/presenter-mode-reveal/index.html +187 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/presenter-mode-reveal/style.css +216 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/product-launch/README.md +8 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/product-launch/index.html +121 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/product-launch/style.css +39 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/tech-sharing/README.md +8 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/tech-sharing/index.html +156 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/tech-sharing/style.css +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/testing-safety-alert/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/testing-safety-alert/index.html +183 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/testing-safety-alert/style.css +62 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/weekly-report/README.md +8 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/weekly-report/index.html +127 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/weekly-report/style.css +55 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-pastel-card/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-pastel-card/index.html +147 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-pastel-card/style.css +66 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-post/README.md +9 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-post/index.html +133 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-post/style.css +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-white-editorial/README.md +11 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-white-editorial/index.html +187 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks/xhs-white-editorial/style.css +63 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/full-decks-index.html +82 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/layout-showcase.html +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/arch-diagram.html +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/big-quote.html +18 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/bullets.html +19 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/chart-bar.html +30 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/chart-line.html +35 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/chart-pie.html +36 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/chart-radar.html +31 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/code.html +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/comparison.html +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/cover.html +32 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/cta.html +27 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/diff.html +35 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/flow-diagram.html +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/gantt.html +29 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/image-grid.html +34 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/image-hero.html +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/kpi-grid.html +19 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/mindmap.html +38 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/process-steps.html +27 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/pros-cons.html +31 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/roadmap.html +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/section-divider.html +17 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/stat-highlight.html +17 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/table.html +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/terminal.html +35 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/thanks.html +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/three-column.html +18 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/timeline.html +32 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/toc.html +26 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/todo-checklist.html +33 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/single-page/two-column.html +39 -0
- package/dist/__w3kits/assets/design-templates/html-ppt/templates/theme-showcase.html +151 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-course-module/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-course-module/example.html +542 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-dir-key-nav-minimal/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-dir-key-nav-minimal/example.html +366 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-graphify-dark-graph/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-graphify-dark-graph/example.html +402 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-hermes-cyber-terminal/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-hermes-cyber-terminal/example.html +422 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-knowledge-arch-blueprint/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-knowledge-arch-blueprint/example.html +407 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-obsidian-claude-gradient/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-obsidian-claude-gradient/example.html +371 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-pitch-deck/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-pitch-deck/example.html +495 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-presenter-mode-reveal/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-presenter-mode-reveal/example.html +725 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-product-launch/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-product-launch/example.html +467 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-taste-brutalist/SKILL.md +70 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-taste-brutalist/example.html +774 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-taste-editorial/SKILL.md +60 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-taste-editorial/example.html +490 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-tech-sharing/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-tech-sharing/example.html +512 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-testing-safety-alert/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-testing-safety-alert/example.html +413 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-weekly-report/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-weekly-report/example.html +489 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-pastel-card/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-pastel-card/example.html +381 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-post/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-post/example.html +487 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-white-editorial/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-xhs-white-editorial/example.html +418 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-8-bit-orbit/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-8-bit-orbit/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-8-bit-orbit/example.html +1640 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-8-bit-orbit/template.json +48 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-biennale-yellow/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-biennale-yellow/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-biennale-yellow/example.html +833 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-biennale-yellow/template.json +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-block-frame/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-block-frame/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-block-frame/example.html +1453 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-block-frame/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-blue-professional/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-blue-professional/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-blue-professional/example.html +1423 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-blue-professional/template.json +44 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-bold-poster/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-bold-poster/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-bold-poster/example.html +876 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-bold-poster/template.json +45 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-broadside/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-broadside/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-broadside/example.html +2144 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-broadside/template.json +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-capsule/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-capsule/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-capsule/example.html +1413 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-capsule/template.json +51 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cartesian/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cartesian/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cartesian/example.html +1136 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cartesian/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cobalt-grid/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cobalt-grid/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cobalt-grid/example.html +1205 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-cobalt-grid/template.json +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-coral/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-coral/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-coral/example.html +1487 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-coral/template.json +45 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-creative-mode/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-creative-mode/SKILL.md +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-creative-mode/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-creative-mode/example.html +636 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-creative-mode/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-daisy-days/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-daisy-days/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-daisy-days/example.html +469 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-daisy-days/template.json +54 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-editorial-tri-tone/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-editorial-tri-tone/SKILL.md +98 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-editorial-tri-tone/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-editorial-tri-tone/example.html +737 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-editorial-tri-tone/template.json +44 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-grove/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-grove/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-grove/example.html +1676 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-grove/template.json +51 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-long-table/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-long-table/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-long-table/example.html +1192 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-long-table/template.json +50 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-mat/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-mat/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-mat/example.html +1372 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-mat/template.json +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-monochrome/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-monochrome/SKILL.md +91 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-monochrome/example.html +2596 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-monochrome/template.json +50 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-neo-grid-bold/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-neo-grid-bold/SKILL.md +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-neo-grid-bold/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-neo-grid-bold/example.html +865 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-neo-grid-bold/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-peoples-platform/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-peoples-platform/SKILL.md +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-peoples-platform/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-peoples-platform/example.html +825 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-peoples-platform/template.json +48 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/SKILL.md +100 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/assets/styles.css +668 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/example.html +443 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pin-and-paper/template.json +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pink-script/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pink-script/SKILL.md +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pink-script/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pink-script/example.html +658 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-pink-script/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-playful/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-playful/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-playful/example.html +1355 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-playful/template.json +43 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-raw-grid/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-raw-grid/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-raw-grid/example.html +1121 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-raw-grid/template.json +46 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-windows/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-windows/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-windows/example.html +1287 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-windows/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-zine/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-zine/SKILL.md +93 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-zine/example.html +1058 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-retro-zine/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-sakura-chroma/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-sakura-chroma/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-sakura-chroma/example.html +1405 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-sakura-chroma/template.json +54 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-scatterbrain/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-scatterbrain/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-scatterbrain/example.html +1320 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-scatterbrain/template.json +50 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-signal/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-signal/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-signal/example.html +2558 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-signal/template.json +50 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-soft-editorial/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-soft-editorial/SKILL.md +98 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-soft-editorial/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-soft-editorial/example.html +1183 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-soft-editorial/template.json +47 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-stencil-tablet/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-stencil-tablet/SKILL.md +99 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-stencil-tablet/assets/deck-stage.js +619 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-stencil-tablet/example.html +954 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-stencil-tablet/template.json +52 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-studio/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-studio/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-studio/example.html +1606 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-studio/template.json +49 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-vellum/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-vellum/SKILL.md +91 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-vellum/example.html +1091 -0
- package/dist/__w3kits/assets/design-templates/html-ppt-zhangzara-vellum/template.json +50 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/SKILL.md +500 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/data-in-motion.md +19 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/house-style.md +71 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/bold-energetic.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/clean-corporate.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/dark-premium.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/jewel-rich.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/monochrome.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/nature-earth.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/neon-electric.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/pastel-soft.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/palettes/warm-editorial.md +14 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/patterns.md +118 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/audio-reactive.md +76 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/captions.md +132 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/css-patterns.md +373 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/dynamic-techniques.md +90 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/html-in-canvas.md +146 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/motion-principles.md +69 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transcript-guide.md +151 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/catalog.md +117 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-3d.md +12 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-blur.md +51 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-cover.md +43 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-destruction.md +95 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-dissolve.md +66 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-distortion.md +45 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-grid.md +10 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-light.md +49 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-mechanical.md +30 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-other.md +25 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-push.md +41 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-radial.md +37 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions/css-scale.md +24 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/transitions.md +112 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/tts.md +75 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/references/typography.md +175 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/scripts/animation-map.mjs +601 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/scripts/contrast-report.mjs +338 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/scripts/package-loader.mjs +269 -0
- package/dist/__w3kits/assets/design-templates/hyperframes/visual-styles.md +211 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/SKILL.md +161 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/assets/template.html +436 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/example.html +1181 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/references/attribution.md +35 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/references/checklist.md +39 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/references/compliance.md +60 -0
- package/dist/__w3kits/assets/design-templates/ib-pitch-book/references/conventions.md +36 -0
- package/dist/__w3kits/assets/design-templates/image-poster/SKILL.md +104 -0
- package/dist/__w3kits/assets/design-templates/image-poster/example.html +113 -0
- package/dist/__w3kits/assets/design-templates/invoice/SKILL.md +48 -0
- package/dist/__w3kits/assets/design-templates/invoice/example.html +214 -0
- package/dist/__w3kits/assets/design-templates/kami-deck/README.md +72 -0
- package/dist/__w3kits/assets/design-templates/kami-deck/SKILL.md +196 -0
- package/dist/__w3kits/assets/design-templates/kami-deck/example.html +1101 -0
- package/dist/__w3kits/assets/design-templates/kami-landing/README.md +69 -0
- package/dist/__w3kits/assets/design-templates/kami-landing/SKILL.md +234 -0
- package/dist/__w3kits/assets/design-templates/kami-landing/example.html +673 -0
- package/dist/__w3kits/assets/design-templates/kanban-board/SKILL.md +50 -0
- package/dist/__w3kits/assets/design-templates/kanban-board/example.html +270 -0
- package/dist/__w3kits/assets/design-templates/last30days/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/last30days/SKILL.md +142 -0
- package/dist/__w3kits/assets/design-templates/last30days/references/save-html-brief.md +50 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/briefing.py +264 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/last30days.py +938 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/__init__.py +1 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/bird_x.py +443 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/bluesky.py +249 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/categories.py +283 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/chrome_cookies.py +265 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/cluster.py +271 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/competitors.py +199 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/cookie_extract.py +379 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/dates.py +120 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/dedupe.py +130 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/entity_extract.py +127 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/env.py +650 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/fanout.py +85 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/fusion.py +207 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/github.py +921 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/grounding.py +259 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/hackernews.py +301 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/html_render.py +674 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/http.py +204 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/instagram.py +500 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/log.py +28 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/normalize.py +499 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/perplexity.py +164 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/pinterest.py +182 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/pipeline.py +1069 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/planner.py +712 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/polymarket.py +786 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/preflight.py +119 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/providers.py +464 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/quality_nudge.py +190 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/query.py +117 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/reddit.py +703 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/reddit_enrich.py +322 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/reddit_public.py +377 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/relevance.py +168 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/render.py +1722 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/rerank.py +425 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/resolve.py +258 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/safari_cookies.py +182 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/schema.py +319 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/setup_wizard.py +535 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/signals.py +251 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/snippet.py +51 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/subproc.py +94 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/threads.py +224 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/tiktok.py +677 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/truthsocial.py +168 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/ui.py +610 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/LICENSE +21 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/bird-search.mjs +147 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/cookies.js +220 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/features.json +17 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/paginate-cursor.js +37 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/query-ids.json +20 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/runtime-features.js +151 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/runtime-query-ids.js +264 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-base.js +129 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-constants.js +50 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-features.js +347 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-search.js +157 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-types.js +2 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/lib/twitter-client-utils.js +511 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/vendor/bird-search/package.json +13 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/xai_x.py +228 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/xiaohongshu_api.py +162 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/xquik.py +227 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/xurl_x.py +172 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/lib/youtube_yt.py +967 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/store.py +787 -0
- package/dist/__w3kits/assets/design-templates/last30days/scripts/watchlist.py +299 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/SKILL.md +136 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/assets/templates/clinic-console/README.md +342 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/assets/templates/clinic-console/data.json +165 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/assets/templates/clinic-console/template.html +548 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/baby-health-live.html +761 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/competitor-radar-live.html +1006 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/crm-table-live.html +1174 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/crypto-dashboard.html +2316 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/monday-operator-live.html +919 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/stock-dashboard.html +2246 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/stock-portfolio-live/artifact.json +16 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/stock-portfolio-live/data.json +453 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/stock-portfolio-live/provenance.json +19 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/examples/stock-portfolio-live/template.html +1071 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/references/artifact-schema.md +99 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/references/connector-policy.md +119 -0
- package/dist/__w3kits/assets/design-templates/live-artifact/references/refresh-contract.md +78 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/SKILL.md +203 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/assets/template.html +643 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/example.html +946 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/references/checklist.md +83 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/references/components.md +212 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/references/connectors.md +171 -0
- package/dist/__w3kits/assets/design-templates/live-dashboard/references/layouts.md +92 -0
- package/dist/__w3kits/assets/design-templates/magazine-poster/SKILL.md +88 -0
- package/dist/__w3kits/assets/design-templates/magazine-poster/example.html +207 -0
- package/dist/__w3kits/assets/design-templates/meeting-notes/SKILL.md +47 -0
- package/dist/__w3kits/assets/design-templates/meeting-notes/example.html +234 -0
- package/dist/__w3kits/assets/design-templates/mobile-app/SKILL.md +102 -0
- package/dist/__w3kits/assets/design-templates/mobile-app/assets/template.html +442 -0
- package/dist/__w3kits/assets/design-templates/mobile-app/example.html +92 -0
- package/dist/__w3kits/assets/design-templates/mobile-app/references/checklist.md +46 -0
- package/dist/__w3kits/assets/design-templates/mobile-app/references/layouts.md +312 -0
- package/dist/__w3kits/assets/design-templates/mobile-onboarding/SKILL.md +54 -0
- package/dist/__w3kits/assets/design-templates/mobile-onboarding/example.html +206 -0
- package/dist/__w3kits/assets/design-templates/motion-frames/SKILL.md +90 -0
- package/dist/__w3kits/assets/design-templates/motion-frames/example.html +221 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/README.md +119 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/SKILL.md +321 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/about.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/capabilities.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/cta.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/hero.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/image-manifest.json +168 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/imagegen-prompts.md +246 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/lab-1.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/lab-2.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/lab-3.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/lab-4.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/lab-5.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/method-1.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/method-2.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/method-3.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/method-4.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/testimonial.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/work-1.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/assets/work-2.png +0 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/example.html +2645 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/inputs.example.json +365 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/schema.ts +447 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/scripts/compose.ts +821 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/scripts/imagegen.ts +325 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/scripts/placeholder.ts +174 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing/styles.css +1858 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/README.md +118 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/SKILL.md +222 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/example.html +2900 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/inputs.example.json +210 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/schema.ts +128 -0
- package/dist/__w3kits/assets/design-templates/open-design-landing-deck/scripts/compose.ts +1056 -0
- package/dist/__w3kits/assets/design-templates/orbit-general/SKILL.md +203 -0
- package/dist/__w3kits/assets/design-templates/orbit-general/example.html +1302 -0
- package/dist/__w3kits/assets/design-templates/orbit-github/SKILL.md +167 -0
- package/dist/__w3kits/assets/design-templates/orbit-github/example.html +770 -0
- package/dist/__w3kits/assets/design-templates/orbit-gmail/SKILL.md +170 -0
- package/dist/__w3kits/assets/design-templates/orbit-gmail/example.html +643 -0
- package/dist/__w3kits/assets/design-templates/orbit-linear/SKILL.md +177 -0
- package/dist/__w3kits/assets/design-templates/orbit-linear/example.html +571 -0
- package/dist/__w3kits/assets/design-templates/orbit-notion/SKILL.md +186 -0
- package/dist/__w3kits/assets/design-templates/orbit-notion/example.html +529 -0
- package/dist/__w3kits/assets/design-templates/pm-spec/SKILL.md +52 -0
- package/dist/__w3kits/assets/design-templates/pm-spec/example.html +248 -0
- package/dist/__w3kits/assets/design-templates/pricing-page/SKILL.md +79 -0
- package/dist/__w3kits/assets/design-templates/pricing-page/example.html +127 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/SKILL.md +233 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/assets/template.html +488 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/examples/README.md +18 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/examples/example-atlas.html +499 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/examples/example-bluehouse.html +495 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/examples/example-helix.html +480 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/examples/example-holm.html +513 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/references/checklist.md +112 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/references/components.md +143 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/references/layouts.md +457 -0
- package/dist/__w3kits/assets/design-templates/replit-deck/references/themes.md +326 -0
- package/dist/__w3kits/assets/design-templates/saas-landing/SKILL.md +124 -0
- package/dist/__w3kits/assets/design-templates/saas-landing/example.html +153 -0
- package/dist/__w3kits/assets/design-templates/simple-deck/SKILL.md +120 -0
- package/dist/__w3kits/assets/design-templates/simple-deck/assets/template.html +353 -0
- package/dist/__w3kits/assets/design-templates/simple-deck/example.html +141 -0
- package/dist/__w3kits/assets/design-templates/simple-deck/references/checklist.md +55 -0
- package/dist/__w3kits/assets/design-templates/simple-deck/references/layouts.md +201 -0
- package/dist/__w3kits/assets/design-templates/social-carousel/SKILL.md +92 -0
- package/dist/__w3kits/assets/design-templates/social-carousel/example.html +219 -0
- package/dist/__w3kits/assets/design-templates/social-media-dashboard/.preview/hero.png +0 -0
- package/dist/__w3kits/assets/design-templates/social-media-dashboard/SKILL.md +118 -0
- package/dist/__w3kits/assets/design-templates/social-media-dashboard/example.html +1534 -0
- package/dist/__w3kits/assets/design-templates/social-media-matrix-tracker-template/SKILL.md +107 -0
- package/dist/__w3kits/assets/design-templates/social-media-matrix-tracker-template/assets/template.html +1258 -0
- package/dist/__w3kits/assets/design-templates/social-media-matrix-tracker-template/example.html +1258 -0
- package/dist/__w3kits/assets/design-templates/social-media-matrix-tracker-template/references/checklist.md +25 -0
- package/dist/__w3kits/assets/design-templates/sprite-animation/SKILL.md +95 -0
- package/dist/__w3kits/assets/design-templates/sprite-animation/example.html +271 -0
- package/dist/__w3kits/assets/design-templates/team-okrs/SKILL.md +47 -0
- package/dist/__w3kits/assets/design-templates/team-okrs/example.html +207 -0
- package/dist/__w3kits/assets/design-templates/trading-analysis-dashboard-template/SKILL.md +78 -0
- package/dist/__w3kits/assets/design-templates/trading-analysis-dashboard-template/assets/template.html +284 -0
- package/dist/__w3kits/assets/design-templates/trading-analysis-dashboard-template/example.html +22 -0
- package/dist/__w3kits/assets/design-templates/trading-analysis-dashboard-template/references/checklist.md +32 -0
- package/dist/__w3kits/assets/design-templates/tweaks/SKILL.md +240 -0
- package/dist/__w3kits/assets/design-templates/tweaks/assets/wrap.html +437 -0
- package/dist/__w3kits/assets/design-templates/tweaks/example.html +750 -0
- package/dist/__w3kits/assets/design-templates/video-shortform/SKILL.md +128 -0
- package/dist/__w3kits/assets/design-templates/video-shortform/example.html +90 -0
- package/dist/__w3kits/assets/design-templates/waitlist-page/SKILL.md +229 -0
- package/dist/__w3kits/assets/design-templates/waitlist-page/assets/template.html +457 -0
- package/dist/__w3kits/assets/design-templates/waitlist-page/example.html +400 -0
- package/dist/__w3kits/assets/design-templates/waitlist-page/references/checklist.md +42 -0
- package/dist/__w3kits/assets/design-templates/web-prototype/SKILL.md +97 -0
- package/dist/__w3kits/assets/design-templates/web-prototype/assets/template.html +338 -0
- package/dist/__w3kits/assets/design-templates/web-prototype/example.html +81 -0
- package/dist/__w3kits/assets/design-templates/web-prototype/references/checklist.md +44 -0
- package/dist/__w3kits/assets/design-templates/web-prototype/references/layouts.md +247 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-brutalist/SKILL.md +61 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-brutalist/example.html +449 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-editorial/SKILL.md +60 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-editorial/example.html +392 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-soft/SKILL.md +63 -0
- package/dist/__w3kits/assets/design-templates/web-prototype-taste-soft/example.html +542 -0
- package/dist/__w3kits/assets/design-templates/weekly-update/SKILL.md +50 -0
- package/dist/__w3kits/assets/design-templates/weekly-update/example.html +320 -0
- package/dist/__w3kits/assets/design-templates/wireframe-sketch/SKILL.md +97 -0
- package/dist/__w3kits/assets/design-templates/wireframe-sketch/example.html +256 -0
- package/dist/__w3kits/assets/design-templates/x-research/SKILL.md +116 -0
- package/dist/__w3kits/assets/skills/8-bit-orbit-video-template/SKILL.md +73 -0
- package/dist/__w3kits/assets/skills/8-bit-orbit-video-template/assets/default-showcase.mp4 +0 -0
- package/dist/__w3kits/assets/skills/8-bit-orbit-video-template/assets/template.html +506 -0
- package/dist/__w3kits/assets/skills/8-bit-orbit-video-template/example.html +43 -0
- package/dist/__w3kits/assets/skills/8-bit-orbit-video-template/references/checklist.md +21 -0
- package/dist/__w3kits/assets/skills/AGENTS.md +54 -0
- package/dist/__w3kits/assets/skills/README.md +25 -0
- package/dist/__w3kits/assets/skills/ad-creative/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/after-hours-editorial-template/SKILL.md +79 -0
- package/dist/__w3kits/assets/skills/after-hours-editorial-template/assets/template.html +173 -0
- package/dist/__w3kits/assets/skills/after-hours-editorial-template/example.html +12 -0
- package/dist/__w3kits/assets/skills/after-hours-editorial-template/references/checklist.md +25 -0
- package/dist/__w3kits/assets/skills/agent-browser/SKILL.md +193 -0
- package/dist/__w3kits/assets/skills/ai-music-album/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/algorithmic-art/SKILL.md +44 -0
- package/dist/__w3kits/assets/skills/apple-hig/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/artifacts-builder/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/brainstorming/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/brand-guidelines/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/canvas-design/SKILL.md +45 -0
- package/dist/__w3kits/assets/skills/color-expert/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/competitive-ads-extractor/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/copywriting/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/creative-director/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/d3-visualization/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/design-brief/SKILL.md +252 -0
- package/dist/__w3kits/assets/skills/design-consultation/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/design-md/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/design-review/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/digits-fintech-swiss-template/SKILL.md +68 -0
- package/dist/__w3kits/assets/skills/digits-fintech-swiss-template/assets/template.html +111 -0
- package/dist/__w3kits/assets/skills/digits-fintech-swiss-template/example.html +44 -0
- package/dist/__w3kits/assets/skills/digits-fintech-swiss-template/references/checklist.md +23 -0
- package/dist/__w3kits/assets/skills/doc/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/docx/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/domain-name-brainstormer/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/editorial-burgundy-principles-template/SKILL.md +71 -0
- package/dist/__w3kits/assets/skills/editorial-burgundy-principles-template/assets/template.html +94 -0
- package/dist/__w3kits/assets/skills/editorial-burgundy-principles-template/example.html +49 -0
- package/dist/__w3kits/assets/skills/editorial-burgundy-principles-template/references/checklist.md +22 -0
- package/dist/__w3kits/assets/skills/enhance-prompt/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/fal-3d/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-generate/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-image-edit/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-kling-o3/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/fal-lip-sync/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-realtime/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/fal-restore/SKILL.md +44 -0
- package/dist/__w3kits/assets/skills/fal-train/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-tryon/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-upscale/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-video-edit/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/fal-vision/SKILL.md +44 -0
- package/dist/__w3kits/assets/skills/faq-page/SKILL.md +113 -0
- package/dist/__w3kits/assets/skills/faq-page/example.html +517 -0
- package/dist/__w3kits/assets/skills/field-notes-editorial-template/SKILL.md +78 -0
- package/dist/__w3kits/assets/skills/field-notes-editorial-template/assets/template.html +287 -0
- package/dist/__w3kits/assets/skills/field-notes-editorial-template/example.html +138 -0
- package/dist/__w3kits/assets/skills/field-notes-editorial-template/references/checklist.md +28 -0
- package/dist/__w3kits/assets/skills/figma-code-connect-components/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/figma-create-design-system-rules/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/figma-create-new-file/SKILL.md +41 -0
- package/dist/__w3kits/assets/skills/figma-generate-design/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/figma-generate-library/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/figma-implement-design/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/figma-use/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/flutter-animating-apps/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/frontend-design/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/frontend-dev/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/frontend-skill/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/frontend-slides/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/full-page-screenshot/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/gif-sticker-maker/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/gsap-core/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/gsap-react/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/gsap-scrolltrigger/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/gsap-timeline/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/hand-drawn-diagrams/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/hatch-pet/LICENSE.txt +201 -0
- package/dist/__w3kits/assets/skills/hatch-pet/README.md +56 -0
- package/dist/__w3kits/assets/skills/hatch-pet/SKILL.md +355 -0
- package/dist/__w3kits/assets/skills/hatch-pet/agents/openai.yaml +4 -0
- package/dist/__w3kits/assets/skills/hatch-pet/references/animation-rows.md +29 -0
- package/dist/__w3kits/assets/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/dist/__w3kits/assets/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/generate_pet_images.py +295 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/prepare_pet_run.py +674 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/test_generate_pet_images.py +136 -0
- package/dist/__w3kits/assets/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/dist/__w3kits/assets/skills/html-ppt-retro-quarterly-review/SKILL.md +79 -0
- package/dist/__w3kits/assets/skills/html-ppt-retro-quarterly-review/assets/template.html +164 -0
- package/dist/__w3kits/assets/skills/html-ppt-retro-quarterly-review/example.html +139 -0
- package/dist/__w3kits/assets/skills/html-ppt-retro-quarterly-review/references/checklist.md +23 -0
- package/dist/__w3kits/assets/skills/image-enhancer/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/imagegen/SKILL.md +44 -0
- package/dist/__w3kits/assets/skills/imagen/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/login-flow/SKILL.md +48 -0
- package/dist/__w3kits/assets/skills/login-flow/example.html +362 -0
- package/dist/__w3kits/assets/skills/login-flow/references/checklist.md +19 -0
- package/dist/__w3kits/assets/skills/marketing-psychology/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/minimax-docx/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/minimax-pdf/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/nanobanana-ppt/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/paywall-upgrade-cro/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/pdf/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/pixelbin-media/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/plan-design-review/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/platform-design/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/pptx/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/pptx-generator/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/SKILL.md +254 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/references/audit-table-template.md +58 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/references/font-discipline.md +363 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/references/layout-discipline.md +371 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/scripts/extract_pptx.py +134 -0
- package/dist/__w3kits/assets/skills/pptx-html-fidelity-audit/scripts/verify_layout.py +144 -0
- package/dist/__w3kits/assets/skills/release-notes-one-pager/SKILL.md +107 -0
- package/dist/__w3kits/assets/skills/release-notes-one-pager/assets/template.html +342 -0
- package/dist/__w3kits/assets/skills/release-notes-one-pager/example.html +156 -0
- package/dist/__w3kits/assets/skills/release-notes-one-pager/references/checklist.md +41 -0
- package/dist/__w3kits/assets/skills/release-notes-one-pager/references/layouts.md +299 -0
- package/dist/__w3kits/assets/skills/remotion/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/replicate/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/screenshot/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/screenshots-marketing/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/shadcn-ui/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/shader-dev/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/slack-gif-creator/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/slides/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/sora/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/speech/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/stitch-loop/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/swiftui-design/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/swiss-creative-mode-template/SKILL.md +79 -0
- package/dist/__w3kits/assets/skills/swiss-creative-mode-template/assets/template.html +375 -0
- package/dist/__w3kits/assets/skills/swiss-creative-mode-template/example.html +70 -0
- package/dist/__w3kits/assets/skills/swiss-creative-mode-template/references/checklist.md +33 -0
- package/dist/__w3kits/assets/skills/swiss-user-research-video-template/SKILL.md +81 -0
- package/dist/__w3kits/assets/skills/swiss-user-research-video-template/assets/template.html +265 -0
- package/dist/__w3kits/assets/skills/swiss-user-research-video-template/example.html +265 -0
- package/dist/__w3kits/assets/skills/swiss-user-research-video-template/references/checklist.md +24 -0
- package/dist/__w3kits/assets/skills/taste-skill/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/theme-factory/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/threejs/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/ui-skills/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/ui-ux-pro-max/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/venice-audio-music/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/venice-audio-speech/SKILL.md +43 -0
- package/dist/__w3kits/assets/skills/venice-image-edit/SKILL.md +41 -0
- package/dist/__w3kits/assets/skills/venice-image-generate/SKILL.md +41 -0
- package/dist/__w3kits/assets/skills/venice-video/SKILL.md +41 -0
- package/dist/__w3kits/assets/skills/video-downloader/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/web-artifacts-builder/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/web-design-guidelines/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/wpds/SKILL.md +42 -0
- package/dist/__w3kits/assets/skills/youtube-clipper/SKILL.md +42 -0
- package/dist/__w3kits/daemon-proxy-sw.js +45 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/acp.d.ts +59 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/acp.js +595 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/acp.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/active-context-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/active-context-routes.js +64 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/active-context-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/agents.d.ts +9 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/agents.js +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/agents.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/analytics.d.ts +32 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/analytics.js +140 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/analytics.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-config.d.ts +34 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-config.js +305 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-config.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-version.d.ts +26 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-version.js +94 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/app-version.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-manifest.d.ts +13 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-manifest.js +244 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-manifest.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-stub-guard.d.ts +50 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-stub-guard.js +252 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/artifact-stub-guard.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/browser-open.d.ts +16 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/browser-open.js +57 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/browser-open.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/chat-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/chat-routes.js +983 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/chat-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-design-import.d.ts +4 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-design-import.js +217 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-design-import.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-diagnostics.d.ts +14 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-diagnostics.js +96 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-diagnostics.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-stream.d.ts +27 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-stream.js +255 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/claude-stream.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cli.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cli.js +681 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cli.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/codex-pets.d.ts +26 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/codex-pets.js +234 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/codex-pets.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/community-pets-sync.d.ts +15 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/community-pets-sync.js +233 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/community-pets-sync.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectionTest.d.ts +31 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectionTest.js +1252 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectionTest.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/catalog.d.ts +121 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/catalog.js +102 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/catalog.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-config.d.ts +14 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-config.js +101 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-config.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-curation.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-curation.js +120 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-curation.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-descriptions.d.ts +15 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-descriptions.js +765 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio-descriptions.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio.d.ts +114 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio.js +1328 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/composio.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/routes.d.ts +23 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/routes.js +735 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/service.d.ts +173 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/service.js +714 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/connectors/service.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/constants.d.ts +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/constants.js +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/constants.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/copilot-stream.d.ts +29 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/copilot-stream.js +129 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/copilot-stream.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/craft.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/craft.js +47 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/craft.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-bad.d.ts +20 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-bad.js +30 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-bad.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-good.d.ts +42 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-good.js +52 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/adapters/synthetic-good.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/run-nightly.d.ts +24 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/run-nightly.js +90 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/__fixtures__/run-nightly.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/adapter-degraded.d.ts +69 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/adapter-degraded.js +110 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/adapter-degraded.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-handler.d.ts +24 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-handler.js +195 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-handler.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-writer.d.ts +79 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-writer.js +142 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/artifact-writer.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/config.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/config.js +72 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/config.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance-history.d.ts +48 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance-history.js +119 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance-history.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance.d.ts +103 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance.js +190 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/conformance.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/errors.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/errors.js +23 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/errors.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/interrupt-handler.d.ts +20 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/interrupt-handler.js +110 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/interrupt-handler.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/orchestrator.d.ts +72 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/orchestrator.js +806 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/orchestrator.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parser.d.ts +34 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parser.js +7 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parser.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parsers/v1.d.ts +48 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parsers/v1.js +526 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/parsers/v1.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/persistence.d.ts +101 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/persistence.js +238 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/persistence.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/ratchet.d.ts +100 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/ratchet.js +192 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/ratchet.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/rollout.d.ts +93 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/rollout.js +125 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/rollout.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/run-registry.d.ts +59 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/run-registry.js +58 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/run-registry.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/scoreboard.d.ts +39 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/scoreboard.js +62 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/scoreboard.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/spawn-inputs.d.ts +33 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/spawn-inputs.js +40 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/spawn-inputs.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/transcript.d.ts +30 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/transcript.js +153 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/critique/transcript.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cwd-aliases.d.ts +22 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cwd-aliases.js +131 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/cwd-aliases.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/db.d.ts +449 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/db.js +1142 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/db.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy-routes.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy-routes.js +201 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy.d.ts +288 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy.js +1816 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/deploy.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-preview.d.ts +12 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-preview.js +603 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-preview.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-showcase.d.ts +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-showcase.js +844 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-system-showcase.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-systems.d.ts +73 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-systems.js +266 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/design-systems.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/document-preview.d.ts +26 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/document-preview.js +286 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/document-preview.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/elevenlabs-voices.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/elevenlabs-voices.js +108 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/elevenlabs-voices.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/finalize-design.d.ts +151 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/finalize-design.js +547 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/finalize-design.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/frontmatter.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/frontmatter.js +155 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/frontmatter.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/home-expansion.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/home-expansion.js +39 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/home-expansion.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/import-export-routes.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/import-export-routes.js +482 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/import-export-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/inline-assets.d.ts +50 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/inline-assets.js +332 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/inline-assets.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/json-event-stream.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/json-event-stream.js +405 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/json-event-stream.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-bridge.d.ts +35 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-bridge.js +273 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-bridge.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-trace.d.ts +110 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-trace.js +479 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/langfuse-trace.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/legacy-data-migrator.d.ts +90 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/legacy-data-migrator.js +340 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/legacy-data-migrator.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/library-install.d.ts +36 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/library-install.js +174 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/library-install.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/linked-dirs.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/linked-dirs.js +62 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/linked-dirs.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/lint-artifact.d.ts +44 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/lint-artifact.js +952 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/lint-artifact.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifact-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifact-routes.js +305 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifact-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh-service.d.ts +23 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh-service.js +178 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh-service.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh.d.ts +92 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh.js +641 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/refresh.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/render.d.ts +15 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/render.js +68 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/render.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/schema.d.ts +144 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/schema.js +702 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/schema.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/store.d.ts +214 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/store.js +1002 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/live-artifacts/store.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/logging/critique.d.ts +57 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/logging/critique.js +30 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/logging/critique.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-config.d.ts +88 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-config.js +878 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-config.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-daemon-url.d.ts +22 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-daemon-url.js +44 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-daemon-url.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-install-info.d.ts +29 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-install-info.js +60 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-install-info.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-live-artifacts-server.d.ts +19 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-live-artifacts-server.js +238 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-live-artifacts-server.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-oauth.d.ts +155 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-oauth.js +412 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-oauth.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-routes.js +365 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-tokens.d.ts +59 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-tokens.js +189 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp-tokens.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp.d.ts +52 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp.js +847 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/mcp.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-config.d.ts +69 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-config.js +408 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-config.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-models.d.ts +31 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-models.js +136 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-models.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-routes.js +316 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-tasks.d.ts +65 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-tasks.js +199 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media-tasks.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media.d.ts +56 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media.js +2065 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/media.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-extractions.d.ts +26 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-extractions.js +233 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-extractions.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-llm.d.ts +7 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-llm.js +809 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory-llm.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory.d.ts +70 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory.js +654 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/memory.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/metrics/index.d.ts +51 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/metrics/index.js +111 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/metrics/index.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/native-folder-dialog.d.ts +6 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/native-folder-dialog.js +32 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/native-folder-dialog.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit-agent-summary.d.ts +7 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit-agent-summary.js +34 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit-agent-summary.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit.d.ts +93 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit.js +400 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/orbit.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/origin-validation.d.ts +21 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/origin-validation.js +149 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/origin-validation.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pdf-export.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pdf-export.js +43 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pdf-export.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pi-rpc.d.ts +93 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pi-rpc.js +475 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/pi-rpc.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-routes.d.ts +14 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-routes.js +867 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-watchers.d.ts +52 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-watchers.js +162 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/project-watchers.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/projects.d.ts +90 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/projects.js +1186 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/projects.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompt-templates.d.ts +24 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompt-templates.js +122 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompt-templates.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/deck-framework.d.ts +38 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/deck-framework.js +373 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/deck-framework.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/directions.d.ts +68 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/directions.js +237 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/directions.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/discovery.d.ts +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/discovery.js +262 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/discovery.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/media-contract.d.ts +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/media-contract.js +359 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/media-contract.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/official-system.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/official-system.js +124 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/official-system.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/panel.d.ts +48 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/panel.js +196 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/panel.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/research-contract.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/research-contract.js +52 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/research-contract.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/system.d.ts +97 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/system.js +598 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/prompts/system.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/providerModels.d.ts +6 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/providerModels.js +284 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/providerModels.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/qoder-stream.d.ts +13 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/qoder-stream.js +162 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/qoder-stream.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/redact.d.ts +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/redact.js +179 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/redact.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/cli-args.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/cli-args.js +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/cli-args.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/index.d.ts +14 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/index.js +78 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/index.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/tavily.d.ts +19 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/tavily.js +78 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/research/tavily.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/route-context-contract.d.ts +16 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/route-context-contract.js +4 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/route-context-contract.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routine-routes.d.ts +37 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routine-routes.js +212 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routine-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routines.d.ts +100 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routines.js +390 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/routines.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runs.d.ts +59 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runs.js +217 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runs.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/auth.d.ts +9 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/auth.js +58 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/auth.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/capabilities.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/capabilities.js +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/capabilities.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/claude.d.ts +17 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/claude.js +75 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/claude.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/codex.d.ts +15 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/codex.js +82 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/codex.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/copilot.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/copilot.js +68 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/copilot.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/cursor-agent.d.ts +16 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/cursor-agent.js +46 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/cursor-agent.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/deepseek.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/deepseek.js +54 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/deepseek.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/devin.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/devin.js +43 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/devin.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/gemini.d.ts +14 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/gemini.js +37 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/gemini.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/hermes.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/hermes.js +27 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/hermes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kilo.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kilo.js +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kilo.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kimi.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kimi.js +24 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kimi.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kiro.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kiro.js +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/kiro.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/opencode.d.ts +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/opencode.js +43 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/opencode.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/pi.d.ts +19 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/pi.js +88 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/pi.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qoder.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qoder.js +49 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qoder.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qwen.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qwen.js +26 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/qwen.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/shared.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/shared.js +44 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/shared.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/vibe.d.ts +10 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/vibe.js +18 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/defs/vibe.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/detection.d.ts +9 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/detection.js +180 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/detection.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/env.d.ts +3 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/env.js +38 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/env.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/executables.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/executables.js +155 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/executables.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/invocation.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/invocation.js +21 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/invocation.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/launch.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/launch.js +147 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/launch.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/mcp.d.ts +13 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/mcp.js +13 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/mcp.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/metadata.d.ts +4 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/metadata.js +90 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/metadata.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/models.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/models.js +43 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/models.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/paths.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/paths.js +22 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/paths.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/prompt-budget.d.ts +4 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/prompt-budget.js +202 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/prompt-budget.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/registry.d.ts +3 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/registry.js +45 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/registry.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/resolution.d.ts +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/resolution.js +13 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/resolution.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/types.d.ts +62 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/types.js +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/runtimes/types.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server-context.d.ts +93 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server-context.js +2 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server-context.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server.d.ts +160 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server.js +4384 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/server.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/index.d.ts +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/index.js +21 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/index.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/server.d.ts +23 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/server.js +175 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/sidecar/server.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/skills.d.ts +100 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/skills.js +836 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/skills.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/static-resource-routes.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/static-resource-routes.js +593 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/static-resource-routes.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tool-tokens.d.ts +47 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tool-tokens.js +131 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tool-tokens.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools/connectors.d.ts +12 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools/connectors.js +124 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools/connectors.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-connectors-cli.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-connectors-cli.js +270 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-connectors-cli.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-live-artifacts-cli.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-live-artifacts-cli.js +282 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/tools-live-artifacts-cli.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/transcript-export.d.ts +16 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/transcript-export.js +388 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/dist/transcript-export.js.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/apps/daemon/package.json +62 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/browser-vfs/dist/index.d.ts +108 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/browser-vfs/dist/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/browser-vfs/dist/index.mjs +413 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/browser-vfs/package.json +12 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/artifact-id.d.ts +5 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/artifact-id.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/events.d.ts +250 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/events.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/index.d.ts +4 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/index.mjs +186 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/public-params.d.ts +26 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/analytics/public-params.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/app-config.d.ts +44 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/app-config.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/artifacts.d.ts +34 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/artifacts.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/chat.d.ts +158 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/chat.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/comments.d.ts +65 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/comments.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/connectionTest.d.ts +49 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/connectionTest.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/connectionTest.mjs +83 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/connectors.d.ts +133 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/connectors.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/files.d.ts +43 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/files.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/finalize.d.ts +50 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/finalize.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/finalize.mjs +5 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/live-artifacts.d.ts +151 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/live-artifacts.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/mcp.d.ts +117 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/mcp.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/memory.d.ts +233 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/memory.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/orbit.d.ts +22 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/orbit.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/orbit.mjs +0 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/projects.d.ts +286 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/projects.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/providerModels.d.ts +19 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/providerModels.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/providerModels.mjs +0 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/proxy.d.ts +24 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/proxy.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/registry.d.ts +156 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/registry.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/research.d.ts +35 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/research.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/research.mjs +9 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/routines.d.ts +104 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/routines.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/version.d.ts +11 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/api/version.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/common.d.ts +33 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/common.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/critique.d.ts +344 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/critique.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/critique.mjs +182 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/errors.d.ts +40 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/errors.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/examples.d.ts +20 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/examples.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/index.d.ts +31 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/index.mjs +2072 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/deck-framework.d.ts +39 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/deck-framework.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/directions.d.ts +69 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/directions.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/discovery.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/discovery.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/media-contract.d.ts +2 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/media-contract.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/official-system.d.ts +12 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/official-system.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/system.d.ts +58 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/prompts/system.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/chat.d.ts +96 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/chat.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/common.d.ts +8 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/common.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/proxy.d.ts +6 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/sse/proxy.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/tasks.d.ts +12 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/dist/tasks.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/contracts/package.json +40 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/platform/dist/index.d.ts +68 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/platform/dist/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/platform/dist/index.mjs +397 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/platform/package.json +12 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar/dist/index.d.ts +144 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar/dist/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar/dist/index.mjs +412 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar/package.json +12 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar-proto/dist/index.d.ts +291 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar-proto/dist/index.d.ts.map +1 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar-proto/dist/index.mjs +315 -0
- package/dist/__w3kits/webcontainer-runtime/node_modules/@open-design/sidecar-proto/package.json +12 -0
- package/dist/__w3kits/webcontainer-runtime/package.json +20 -0
- package/dist/__w3kits/webcontainer-runtime.json +68 -0
- package/dist/_next/static/chunks/0axqck9-llseo.js +1 -0
- package/dist/_next/static/chunks/0xl644~f.h0hd.js +1 -0
- package/dist/_next/static/chunks/{0kf4c9h~6b0ok.js → 0xykzmwq7w9.b.js} +1 -1
- package/dist/_not-found/__next._full.txt +10 -10
- package/dist/_not-found/__next._head.txt +4 -4
- package/dist/_not-found/__next._index.txt +5 -5
- package/dist/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dist/_not-found/__next._not-found.txt +3 -3
- package/dist/_not-found/__next._tree.txt +1 -1
- package/dist/_not-found/index.html +1 -1
- package/dist/_not-found/index.txt +10 -10
- package/dist/browser-daemon.js +113 -7
- package/dist/index.html +1 -1
- package/dist/index.txt +11 -11
- package/package.json +3 -2
- package/dist/_next/static/chunks/04x4~r_ltq17a.js +0 -1
- package/dist/_next/static/chunks/05_595ph9d4yp.js +0 -1
- package/dist/w3kits-daemon-sw.js +0 -77
- /package/dist/_next/static/{ptaOAJFvinIcai1ShQRcW → zDhAhlvmD2uhNsdWY6CQB}/_buildManifest.js +0 -0
- /package/dist/_next/static/{ptaOAJFvinIcai1ShQRcW → zDhAhlvmD2uhNsdWY6CQB}/_clientMiddlewareManifest.js +0 -0
- /package/dist/_next/static/{ptaOAJFvinIcai1ShQRcW → zDhAhlvmD2uhNsdWY6CQB}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,4384 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import multer from 'multer';
|
|
3
|
+
import { execFile, spawn } from 'node:child_process';
|
|
4
|
+
import { createHmac, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import net from 'node:net';
|
|
11
|
+
import { composeSystemPrompt, renderCodexImagegenOverride, shouldRenderCodexImagegenOverride, } from './prompts/system.js';
|
|
12
|
+
import { resolveProjectRelativePath } from './home-expansion.js';
|
|
13
|
+
import { createCommandInvocation } from '@open-design/platform';
|
|
14
|
+
import { buildLiveArtifactsMcpServersForAgent, checkPromptArgvBudget, checkWindowsCmdShimCommandLineBudget, checkWindowsDirectExeCommandLineBudget, detectAgents, getAgentDef, isKnownModel, applyAgentLaunchEnv, resolveAgentLaunch, sanitizeCustomModel, spawnEnvForAgent, } from './agents.js';
|
|
15
|
+
import { migrateLegacyDataDirSync } from './legacy-data-migrator.js';
|
|
16
|
+
import { findSkillById, listSkills } from './skills.js';
|
|
17
|
+
import { validateLinkedDirs } from './linked-dirs.js';
|
|
18
|
+
import { buildWindowsFolderDialogCommand, parseFolderDialogStdout } from './native-folder-dialog.js';
|
|
19
|
+
import { listDesignSystems, readDesignSystem, resolveDesignSystemAssets, } from './design-systems.js';
|
|
20
|
+
import { composeMemoryBody, deleteMemoryEntry, extractFromMessage, listMemoryEntries, maskMemoryExtractionConfig, memoryDir, memoryEvents, readMemoryConfig, readMemoryEntry, readMemoryIndex, upsertMemoryEntry, writeMemoryConfig, writeMemoryIndex, } from './memory.js';
|
|
21
|
+
import { clearExtractions as clearMemoryExtractions, listExtractions as listMemoryExtractions, removeExtraction as removeMemoryExtraction, } from './memory-extractions.js';
|
|
22
|
+
import { attachAcpSession } from './acp.js';
|
|
23
|
+
import { attachPiRpcSession } from './pi-rpc.js';
|
|
24
|
+
import { createClaudeStreamHandler } from './claude-stream.js';
|
|
25
|
+
import { diagnoseClaudeCliFailure } from './claude-diagnostics.js';
|
|
26
|
+
import { loadCritiqueConfigFromEnv } from './critique/config.js';
|
|
27
|
+
import { reconcileStaleRuns } from './critique/persistence.js';
|
|
28
|
+
import { runOrchestrator } from './critique/orchestrator.js';
|
|
29
|
+
import { createRunRegistry } from './critique/run-registry.js';
|
|
30
|
+
import { handleCritiqueInterrupt } from './critique/interrupt-handler.js';
|
|
31
|
+
import { handleCritiqueArtifact } from './critique/artifact-handler.js';
|
|
32
|
+
import { getCritiqueMetrics, register } from './metrics/index.js';
|
|
33
|
+
import { readConformanceHistory } from './critique/conformance-history.js';
|
|
34
|
+
import { evaluateRollout } from './critique/ratchet.js';
|
|
35
|
+
import { isCritiqueEnabled, parseEnvEnabled, parseRolloutPhase, } from './critique/rollout.js';
|
|
36
|
+
import { narrowProjectCritiqueOverride } from './critique/spawn-inputs.js';
|
|
37
|
+
import { createCopilotStreamHandler } from './copilot-stream.js';
|
|
38
|
+
import { createJsonEventStreamHandler } from './json-event-stream.js';
|
|
39
|
+
import { classifyAgentAuthFailure, cursorAuthGuidance } from './runtimes/auth.js';
|
|
40
|
+
import { createQoderStreamHandler } from './qoder-stream.js';
|
|
41
|
+
import { subscribe as subscribeFileEvents } from './project-watchers.js';
|
|
42
|
+
import { createChatRunService } from './runs.js';
|
|
43
|
+
import { reportRunCompletedFromDaemon } from './langfuse-bridge.js';
|
|
44
|
+
import { createAnalyticsService, readAnalyticsContext, readPublicConfigResponse, } from './analytics.js';
|
|
45
|
+
import { redactSecrets, testAgentConnection, testProviderConnection, validateBaseUrl, } from './connectionTest.js';
|
|
46
|
+
import { listProviderModels } from './providerModels.js';
|
|
47
|
+
import { importClaudeDesignZip } from './claude-design-import.js';
|
|
48
|
+
import { finalizeDesignPackage, FinalizePackageLockedError, FinalizeUpstreamError, } from './finalize-design.js';
|
|
49
|
+
import { buildDocumentPreview } from './document-preview.js';
|
|
50
|
+
import { lintArtifact, renderFindingsForAgent } from './lint-artifact.js';
|
|
51
|
+
import { loadCraftSections } from './craft.js';
|
|
52
|
+
import { stageActiveSkill } from './cwd-aliases.js';
|
|
53
|
+
import { buildDesktopPdfExportInput } from './pdf-export.js';
|
|
54
|
+
import { generateMedia } from './media.js';
|
|
55
|
+
import { listElevenLabsVoiceOptions } from './elevenlabs-voices.js';
|
|
56
|
+
import { searchResearch, ResearchError } from './research/index.js';
|
|
57
|
+
import { renderResearchCommandContract } from './prompts/research-contract.js';
|
|
58
|
+
import { AUDIO_DURATIONS_SEC, AUDIO_MODELS_BY_KIND, IMAGE_MODELS, MEDIA_ASPECTS, MEDIA_PROVIDERS, VIDEO_LENGTHS_SEC, VIDEO_MODELS, } from './media-models.js';
|
|
59
|
+
import { readMaskedConfig, writeConfig } from './media-config.js';
|
|
60
|
+
import { deleteMediaTask, getMediaTask, insertMediaTask, listMediaTasksByProject, listRecentMediaTasks, reconcileMediaTasksOnBoot, updateMediaTask, } from './media-tasks.js';
|
|
61
|
+
import { buildAcpMcpServers, buildClaudeMcpJson, isManagedProjectCwd, readMcpConfig, } from './mcp-config.js';
|
|
62
|
+
import { PendingAuthCache, refreshAccessToken, } from './mcp-oauth.js';
|
|
63
|
+
import { isTokenExpired, readAllTokens, setToken, } from './mcp-tokens.js';
|
|
64
|
+
import { agentCliEnvForAgent, readAppConfig, writeAppConfig } from './app-config.js';
|
|
65
|
+
import { OrbitService, formatLocalProjectTimestamp, renderOrbitTemplateSystemPrompt } from './orbit.js';
|
|
66
|
+
import { buildOrbitNoLiveArtifactSummary } from './orbit-agent-summary.js';
|
|
67
|
+
import { RoutineService, } from './routines.js';
|
|
68
|
+
import { buildProjectArchive, buildBatchArchive, decodeMultipartFilename, deleteProjectFile, detectEntryFile, ensureProject, isSafeId, listFiles, mimeFor, parseByteRange, projectDir, readProjectFile, renameProjectFile, removeProjectDir, sanitizeName, searchProjectFiles, resolveProjectDir, resolveProjectFilePath, writeProjectFile, } from './projects.js';
|
|
69
|
+
import { validateArtifactManifestInput } from './artifact-manifest.js';
|
|
70
|
+
import { readCurrentAppVersionInfo } from './app-version.js';
|
|
71
|
+
import { deleteConversation, deletePreviewComment, deleteProject as dbDeleteProject, deleteTemplate, getConversation, getDeployment, getDeploymentById, getProject, getTemplate, insertConversation, insertProject, insertRoutineRun, insertTemplate, findTemplateByNameAndProject, updateTemplate, listProjectsAwaitingInput, listConversations, listDeployments, listLatestProjectRunStatuses, listMessages, listPreviewComments, listProjects, listRoutines, listTabs, listTemplates, getLatestRoutineRun, openDatabase, setTabs, updateConversation, updatePreviewCommentStatus, updateProject, updateRoutineRun, upsertDeployment, upsertMessage, upsertPreviewComment, } from './db.js';
|
|
72
|
+
import { createLiveArtifact, deleteLiveArtifact, ensureLiveArtifactPreview, getLiveArtifact, LiveArtifactRefreshLockError, LiveArtifactStoreValidationError, listLiveArtifacts, listLiveArtifactRefreshLogEntries, readLiveArtifactCode, recoverStaleLiveArtifactRefreshes, updateLiveArtifact, } from './live-artifacts/store.js';
|
|
73
|
+
import { LiveArtifactRefreshUnavailableError, refreshLiveArtifact } from './live-artifacts/refresh-service.js';
|
|
74
|
+
import { LiveArtifactRefreshAbortError } from './live-artifacts/refresh.js';
|
|
75
|
+
import { registerConnectorRoutes } from './connectors/routes.js';
|
|
76
|
+
import { registerActiveContextRoutes } from './active-context-routes.js';
|
|
77
|
+
import { registerMcpRoutes } from './mcp-routes.js';
|
|
78
|
+
import { registerLiveArtifactRoutes } from './live-artifact-routes.js';
|
|
79
|
+
import { registerDeployRoutes, registerDeploymentCheckRoutes } from './deploy-routes.js';
|
|
80
|
+
import { registerMediaRoutes } from './media-routes.js';
|
|
81
|
+
import { registerProjectRoutes, registerProjectArtifactRoutes, registerProjectFileRoutes, registerProjectUploadRoutes } from './project-routes.js';
|
|
82
|
+
import { registerFinalizeRoutes, registerImportRoutes, registerProjectExportRoutes } from './import-export-routes.js';
|
|
83
|
+
import { registerChatRoutes } from './chat-routes.js';
|
|
84
|
+
import { registerStaticResourceRoutes } from './static-resource-routes.js';
|
|
85
|
+
import { registerRoutineRoutes, routineDbRowToContract } from './routine-routes.js';
|
|
86
|
+
import { assertServerContextSatisfiesRoutes } from './route-context-contract.js';
|
|
87
|
+
import { configureConnectorCredentialStore, ConnectorServiceError, FileConnectorCredentialStore } from './connectors/service.js';
|
|
88
|
+
import { composioConnectorProvider } from './connectors/composio.js';
|
|
89
|
+
import { configureComposioConfigStore } from './connectors/composio-config.js';
|
|
90
|
+
import { CHAT_TOOL_ENDPOINTS, CHAT_TOOL_OPERATIONS, toolTokenRegistry } from './tool-tokens.js';
|
|
91
|
+
import { aggregateCloudflarePagesStatus, buildDeployFileSet, checkDeploymentUrl, CLOUDFLARE_PAGES_PROVIDER_ID, cloudflarePagesProjectNameForProject, DeployError, deployToCloudflarePages, deployToVercel, isDeployProviderId, listCloudflarePagesZones, prepareDeployPreflight, publicDeployConfigForProvider, readDeployConfig, readCloudflarePagesDomain, VERCEL_PROVIDER_ID, writeDeployConfig, } from './deploy.js';
|
|
92
|
+
import { allowedBrowserPorts, configuredAllowedOrigins, isAllowedBrowserOrigin, isLocalSameOrigin, } from './origin-validation.js';
|
|
93
|
+
/** @typedef {import('@open-design/contracts').ApiErrorCode} ApiErrorCode */
|
|
94
|
+
/** @typedef {import('@open-design/contracts').ApiError} ApiError */
|
|
95
|
+
/** @typedef {import('@open-design/contracts').ApiErrorResponse} ApiErrorResponse */
|
|
96
|
+
/** @typedef {import('@open-design/contracts').ChatRequest} ChatRequest */
|
|
97
|
+
/** @typedef {import('@open-design/contracts').ChatSseEvent} ChatSseEvent */
|
|
98
|
+
/** @typedef {import('@open-design/contracts').ProxyStreamRequest} ProxyStreamRequest */
|
|
99
|
+
/** @typedef {import('@open-design/contracts').ProxySseEvent} ProxySseEvent */
|
|
100
|
+
/** @typedef {import('@open-design/contracts').ProjectConversationCreatedSsePayload} ProjectConversationCreatedSsePayload */
|
|
101
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
102
|
+
const __dirname = path.dirname(__filename);
|
|
103
|
+
const require = createRequire(import.meta.url);
|
|
104
|
+
const DAEMON_CLI_PATH_ENV = 'OD_DAEMON_CLI_PATH';
|
|
105
|
+
export function resolveProjectRoot(moduleDir) {
|
|
106
|
+
const base = path.basename(moduleDir);
|
|
107
|
+
const daemonDir = base === 'dist' || base === 'src' ? path.dirname(moduleDir) : moduleDir;
|
|
108
|
+
return path.resolve(daemonDir, '../..');
|
|
109
|
+
}
|
|
110
|
+
function cleanOptionalPath(value) {
|
|
111
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
112
|
+
? path.resolve(value)
|
|
113
|
+
: null;
|
|
114
|
+
}
|
|
115
|
+
export function resolveDaemonCliPath(env = process.env) {
|
|
116
|
+
const configured = cleanOptionalPath(env[DAEMON_CLI_PATH_ENV]) ?? cleanOptionalPath(env.OD_BIN);
|
|
117
|
+
if (configured)
|
|
118
|
+
return configured;
|
|
119
|
+
const packageJsonPath = require.resolve('@open-design/daemon/package.json');
|
|
120
|
+
return path.join(path.dirname(packageJsonPath), 'dist', 'cli.js');
|
|
121
|
+
}
|
|
122
|
+
const PROJECT_ROOT = resolveProjectRoot(__dirname);
|
|
123
|
+
const RESOURCE_ROOT_ENV = 'OD_RESOURCE_ROOT';
|
|
124
|
+
let desktopAuthSecret = null;
|
|
125
|
+
let desktopAuthEverRegistered = process.env.OD_REQUIRE_DESKTOP_AUTH === '1';
|
|
126
|
+
const consumedImportNonces = new Map();
|
|
127
|
+
const DESKTOP_IMPORT_TOKEN_TTL_MS = 60_000;
|
|
128
|
+
const DESKTOP_IMPORT_TOKEN_FIELD_SEP = '~';
|
|
129
|
+
export function setDesktopAuthSecret(secret) {
|
|
130
|
+
desktopAuthSecret = secret;
|
|
131
|
+
if (secret != null) {
|
|
132
|
+
desktopAuthEverRegistered = true;
|
|
133
|
+
}
|
|
134
|
+
consumedImportNonces.clear();
|
|
135
|
+
}
|
|
136
|
+
export function isDesktopAuthRegistered() {
|
|
137
|
+
return desktopAuthSecret != null;
|
|
138
|
+
}
|
|
139
|
+
export function isDesktopAuthGateActive() {
|
|
140
|
+
return desktopAuthEverRegistered;
|
|
141
|
+
}
|
|
142
|
+
export function resetDesktopAuthForTests() {
|
|
143
|
+
desktopAuthSecret = null;
|
|
144
|
+
desktopAuthEverRegistered = process.env.OD_REQUIRE_DESKTOP_AUTH === '1';
|
|
145
|
+
consumedImportNonces.clear();
|
|
146
|
+
}
|
|
147
|
+
function pruneExpiredImportNonces(now) {
|
|
148
|
+
for (const [nonce, exp] of consumedImportNonces) {
|
|
149
|
+
if (exp <= now)
|
|
150
|
+
consumedImportNonces.delete(nonce);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function timingSafeStringEquals(a, b) {
|
|
154
|
+
const bufA = Buffer.from(a, 'utf8');
|
|
155
|
+
const bufB = Buffer.from(b, 'utf8');
|
|
156
|
+
if (bufA.length !== bufB.length)
|
|
157
|
+
return false;
|
|
158
|
+
return timingSafeEqual(bufA, bufB);
|
|
159
|
+
}
|
|
160
|
+
export function signDesktopImportToken(secret, baseDir, options) {
|
|
161
|
+
const signature = createHmac('sha256', secret)
|
|
162
|
+
.update(`${baseDir}\n${options.nonce}\n${options.exp}`)
|
|
163
|
+
.digest('base64url');
|
|
164
|
+
return [options.nonce, options.exp, signature].join(DESKTOP_IMPORT_TOKEN_FIELD_SEP);
|
|
165
|
+
}
|
|
166
|
+
export function verifyDesktopImportToken(secret, baseDir, token, now, consumedNonces) {
|
|
167
|
+
if (typeof token !== 'string' || token.length === 0) {
|
|
168
|
+
return { ok: false, reason: 'token missing' };
|
|
169
|
+
}
|
|
170
|
+
const parts = token.split(DESKTOP_IMPORT_TOKEN_FIELD_SEP);
|
|
171
|
+
if (parts.length !== 3) {
|
|
172
|
+
return { ok: false, reason: 'token shape invalid' };
|
|
173
|
+
}
|
|
174
|
+
const [nonce, expISO, signature] = parts;
|
|
175
|
+
if (nonce.length === 0 || expISO.length === 0 || signature.length === 0) {
|
|
176
|
+
return { ok: false, reason: 'token shape invalid' };
|
|
177
|
+
}
|
|
178
|
+
const expMs = Date.parse(expISO);
|
|
179
|
+
if (!Number.isFinite(expMs)) {
|
|
180
|
+
return { ok: false, reason: 'token expiry invalid' };
|
|
181
|
+
}
|
|
182
|
+
if (expMs <= now) {
|
|
183
|
+
return { ok: false, reason: 'token expired' };
|
|
184
|
+
}
|
|
185
|
+
if (expMs - now > DESKTOP_IMPORT_TOKEN_TTL_MS * 2) {
|
|
186
|
+
return { ok: false, reason: 'token expiry exceeds permitted window' };
|
|
187
|
+
}
|
|
188
|
+
const expected = createHmac('sha256', secret)
|
|
189
|
+
.update(`${baseDir}\n${nonce}\n${expISO}`)
|
|
190
|
+
.digest('base64url');
|
|
191
|
+
if (!timingSafeStringEquals(expected, signature)) {
|
|
192
|
+
return { ok: false, reason: 'token signature invalid' };
|
|
193
|
+
}
|
|
194
|
+
if (consumedNonces.has(nonce)) {
|
|
195
|
+
return { ok: false, reason: 'token nonce already used' };
|
|
196
|
+
}
|
|
197
|
+
return { ok: true, nonce, exp: expMs };
|
|
198
|
+
}
|
|
199
|
+
export function composeLiveInstructionPrompt({ daemonSystemPrompt, runtimeToolPrompt, clientSystemPrompt, finalPromptOverride, }) {
|
|
200
|
+
const override = typeof finalPromptOverride === 'string'
|
|
201
|
+
? finalPromptOverride.trim()
|
|
202
|
+
: '';
|
|
203
|
+
const parts = [daemonSystemPrompt, runtimeToolPrompt, clientSystemPrompt]
|
|
204
|
+
.map((part) => (typeof part === 'string' ? part.trim() : ''))
|
|
205
|
+
.map((part) => override && part.includes(override)
|
|
206
|
+
? part.split(override).join('').trim()
|
|
207
|
+
: part)
|
|
208
|
+
.filter(Boolean);
|
|
209
|
+
if (override) {
|
|
210
|
+
parts.push(override);
|
|
211
|
+
}
|
|
212
|
+
return parts.join('\n\n---\n\n');
|
|
213
|
+
}
|
|
214
|
+
export function resolveResearchCommandContract(research, message) {
|
|
215
|
+
if (!research || !research.enabled)
|
|
216
|
+
return '';
|
|
217
|
+
const researchQuery = typeof research.query === 'string' && research.query.trim()
|
|
218
|
+
? research.query
|
|
219
|
+
: message;
|
|
220
|
+
return renderResearchCommandContract({
|
|
221
|
+
query: researchQuery,
|
|
222
|
+
maxSources: typeof research.maxSources === 'number' ? research.maxSources : undefined,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
export function resolveCodexGeneratedImagesDir(agentId, metadata, env = process.env, homeDir = os.homedir()) {
|
|
226
|
+
if (!shouldRenderCodexImagegenOverride(agentId, metadata))
|
|
227
|
+
return null;
|
|
228
|
+
const rawCodexHome = typeof env?.CODEX_HOME === 'string' && env.CODEX_HOME.trim().length > 0
|
|
229
|
+
? env.CODEX_HOME.trim()
|
|
230
|
+
: path.join(homeDir, '.codex');
|
|
231
|
+
const codexHome = rawCodexHome.startsWith('~/')
|
|
232
|
+
? path.join(homeDir, rawCodexHome.slice(2))
|
|
233
|
+
: rawCodexHome;
|
|
234
|
+
return path.resolve(codexHome, 'generated_images');
|
|
235
|
+
}
|
|
236
|
+
function isMissingPathError(err) {
|
|
237
|
+
return (err &&
|
|
238
|
+
typeof err === 'object' &&
|
|
239
|
+
'code' in err &&
|
|
240
|
+
err.code === 'ENOENT');
|
|
241
|
+
}
|
|
242
|
+
function collectProtectedDirRoots(protectedDirs, { realpathSync, statSync, }) {
|
|
243
|
+
const roots = [];
|
|
244
|
+
for (const raw of Array.isArray(protectedDirs) ? protectedDirs : []) {
|
|
245
|
+
if (typeof raw !== 'string' || raw.trim().length === 0)
|
|
246
|
+
continue;
|
|
247
|
+
const resolved = path.resolve(raw);
|
|
248
|
+
roots.push(resolved);
|
|
249
|
+
try {
|
|
250
|
+
const canonical = realpathSync(resolved);
|
|
251
|
+
try {
|
|
252
|
+
if (statSync(canonical).isDirectory())
|
|
253
|
+
roots.push(canonical);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
roots.push(canonical);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// A missing protected root cannot be the canonical target of a symlink.
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return Array.from(new Set(roots));
|
|
264
|
+
}
|
|
265
|
+
function findContainingProtectedRoot(candidate, protectedRoots) {
|
|
266
|
+
return protectedRoots.find((root) => isPathWithin(root, candidate)) ?? null;
|
|
267
|
+
}
|
|
268
|
+
export function validateCodexGeneratedImagesDir(codexGeneratedImagesDir, { protectedDirs = [], mkdirSync = fs.mkdirSync, lstatSync = fs.lstatSync, statSync = fs.statSync, realpathSync = fs.realpathSync.native, warn = console.warn, } = {}) {
|
|
269
|
+
if (typeof codexGeneratedImagesDir !== 'string' ||
|
|
270
|
+
codexGeneratedImagesDir.trim().length === 0) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
const resolved = path.resolve(codexGeneratedImagesDir);
|
|
274
|
+
const protectedRoots = collectProtectedDirRoots(protectedDirs, {
|
|
275
|
+
realpathSync,
|
|
276
|
+
statSync,
|
|
277
|
+
});
|
|
278
|
+
const warnSkipped = (reason) => warn(`[od] codex generated_images allowlist skipped: ${reason}`);
|
|
279
|
+
const protectedRoot = findContainingProtectedRoot(resolved, protectedRoots);
|
|
280
|
+
if (protectedRoot) {
|
|
281
|
+
warnSkipped(`${resolved} is inside protected root ${protectedRoot}`);
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
let existingTargetStat = null;
|
|
286
|
+
try {
|
|
287
|
+
existingTargetStat = lstatSync(resolved);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
if (!isMissingPathError(err))
|
|
291
|
+
throw err;
|
|
292
|
+
}
|
|
293
|
+
if (existingTargetStat?.isSymbolicLink()) {
|
|
294
|
+
warnSkipped(`${resolved} is a symlink`);
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
if (existingTargetStat && !existingTargetStat.isDirectory()) {
|
|
298
|
+
warnSkipped(`${resolved} is not a directory`);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
const parent = path.dirname(resolved);
|
|
302
|
+
const protectedParentRoot = findContainingProtectedRoot(parent, protectedRoots);
|
|
303
|
+
if (protectedParentRoot) {
|
|
304
|
+
warnSkipped(`${parent} is inside protected root ${protectedParentRoot}`);
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
mkdirSync(parent, { recursive: true });
|
|
308
|
+
const canonicalParent = realpathSync(parent);
|
|
309
|
+
const canonicalCandidate = path.join(canonicalParent, path.basename(resolved));
|
|
310
|
+
const protectedCanonicalParentRoot = findContainingProtectedRoot(canonicalCandidate, protectedRoots);
|
|
311
|
+
if (protectedCanonicalParentRoot) {
|
|
312
|
+
warnSkipped(`${canonicalCandidate} resolves inside protected root ${protectedCanonicalParentRoot}`);
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
mkdirSync(resolved, { recursive: true });
|
|
316
|
+
if (lstatSync(resolved).isSymbolicLink()) {
|
|
317
|
+
warnSkipped(`${resolved} is a symlink`);
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
if (!statSync(resolved).isDirectory()) {
|
|
321
|
+
warnSkipped(`${resolved} is not a directory`);
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
const canonicalDir = realpathSync(resolved);
|
|
325
|
+
const protectedCanonicalRoot = findContainingProtectedRoot(canonicalDir, protectedRoots);
|
|
326
|
+
if (protectedCanonicalRoot) {
|
|
327
|
+
warnSkipped(`${canonicalDir} resolves inside protected root ${protectedCanonicalRoot}`);
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
return canonicalDir;
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
const message = err instanceof Error ? err.message : String(err ?? 'unknown error');
|
|
334
|
+
warn(`[od] codex generated_images allowlist mkdir failed: ${message}`);
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
export function resolveChatExtraAllowedDirs({ agentId, skillsDir, designSystemsDir, linkedDirs = [], codexGeneratedImagesDir, existsSync = fs.existsSync, }) {
|
|
339
|
+
const isCodex = typeof agentId === 'string' && agentId.trim().toLowerCase() === 'codex';
|
|
340
|
+
const candidates = isCodex
|
|
341
|
+
? [codexGeneratedImagesDir]
|
|
342
|
+
: [
|
|
343
|
+
skillsDir,
|
|
344
|
+
designSystemsDir,
|
|
345
|
+
...(Array.isArray(linkedDirs) ? linkedDirs : []),
|
|
346
|
+
];
|
|
347
|
+
return Array.from(new Set(candidates.filter((d) => typeof d === 'string' && d.length > 0 && existsSync(d))));
|
|
348
|
+
}
|
|
349
|
+
export function resolveGrantedCodexImagegenOverride({ agentId, metadata, codexGeneratedImagesDir, extraAllowedDirs = [], }) {
|
|
350
|
+
if (typeof codexGeneratedImagesDir !== 'string' ||
|
|
351
|
+
codexGeneratedImagesDir.length === 0 ||
|
|
352
|
+
!Array.isArray(extraAllowedDirs) ||
|
|
353
|
+
!extraAllowedDirs.includes(codexGeneratedImagesDir)) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
return renderCodexImagegenOverride(agentId, metadata);
|
|
357
|
+
}
|
|
358
|
+
export function normalizeCommentAttachments(input) {
|
|
359
|
+
if (!Array.isArray(input))
|
|
360
|
+
return [];
|
|
361
|
+
return input
|
|
362
|
+
.map((raw, index) => {
|
|
363
|
+
if (!raw || typeof raw !== 'object')
|
|
364
|
+
return null;
|
|
365
|
+
const filePath = cleanString(raw.filePath);
|
|
366
|
+
const elementId = cleanString(raw.elementId);
|
|
367
|
+
const selector = cleanString(raw.selector);
|
|
368
|
+
const label = cleanString(raw.label);
|
|
369
|
+
const screenshotPath = cleanString(raw.screenshotPath);
|
|
370
|
+
const markKind = normalizeVisualMarkKind(raw.markKind);
|
|
371
|
+
const intent = compactString(raw.intent, 220);
|
|
372
|
+
const comment = cleanString(raw.comment) || intent;
|
|
373
|
+
const selectionKind = raw.selectionKind === 'visual' ? 'visual' : raw.selectionKind === 'pod' ? 'pod' : 'element';
|
|
374
|
+
if (!filePath || !elementId || !comment)
|
|
375
|
+
return null;
|
|
376
|
+
if (selectionKind !== 'visual' && !selector)
|
|
377
|
+
return null;
|
|
378
|
+
if (selectionKind === 'visual' && !screenshotPath)
|
|
379
|
+
return null;
|
|
380
|
+
const podMembers = selectionKind === 'pod' ? normalizeAttachmentPodMembers(raw.podMembers) : [];
|
|
381
|
+
const memberCount = selectionKind === 'pod'
|
|
382
|
+
? (podMembers.length > 0
|
|
383
|
+
? podMembers.length
|
|
384
|
+
: Number.isFinite(raw.memberCount)
|
|
385
|
+
? Math.max(0, Math.round(raw.memberCount))
|
|
386
|
+
: 0)
|
|
387
|
+
: 0;
|
|
388
|
+
return {
|
|
389
|
+
id: cleanString(raw.id) || `comment-${index + 1}`,
|
|
390
|
+
order: Number.isFinite(raw.order)
|
|
391
|
+
? Math.max(1, Math.round(raw.order))
|
|
392
|
+
: index + 1,
|
|
393
|
+
filePath,
|
|
394
|
+
elementId,
|
|
395
|
+
selector,
|
|
396
|
+
label,
|
|
397
|
+
comment,
|
|
398
|
+
currentText: compactString(raw.currentText, 160),
|
|
399
|
+
pagePosition: normalizeAttachmentPosition(raw.pagePosition),
|
|
400
|
+
htmlHint: compactString(raw.htmlHint, 180),
|
|
401
|
+
selectionKind,
|
|
402
|
+
memberCount,
|
|
403
|
+
podMembers,
|
|
404
|
+
screenshotPath: selectionKind === 'visual' ? screenshotPath : undefined,
|
|
405
|
+
markKind: selectionKind === 'visual' ? markKind : undefined,
|
|
406
|
+
intent: selectionKind === 'visual'
|
|
407
|
+
? intent || visualAnnotationIntent(markKind)
|
|
408
|
+
: undefined,
|
|
409
|
+
source: raw.source === 'board-batch' ? 'board-batch' : 'saved-comment',
|
|
410
|
+
};
|
|
411
|
+
})
|
|
412
|
+
.filter(Boolean)
|
|
413
|
+
.sort((a, b) => a.order - b.order);
|
|
414
|
+
}
|
|
415
|
+
export function renderCommentAttachmentHint(commentAttachments) {
|
|
416
|
+
if (!commentAttachments.length)
|
|
417
|
+
return '';
|
|
418
|
+
const lines = [
|
|
419
|
+
'',
|
|
420
|
+
'',
|
|
421
|
+
'<attached-preview-comments>',
|
|
422
|
+
'Scope: treat each attachment as the default refinement target. For visual marks, inspect the screenshot and modify the marked region first. Preserve unrelated areas.',
|
|
423
|
+
];
|
|
424
|
+
for (const item of commentAttachments) {
|
|
425
|
+
const targetKind = item.selectionKind === 'visual' ? 'visual' : item.selectionKind === 'pod' ? 'pod' : 'element';
|
|
426
|
+
lines.push('', `${item.order}. ${item.elementId}`, `targetKind: ${targetKind}`, `file: ${item.filePath}`, `label: ${item.label || '(unlabeled)'}`, `position: ${formatAttachmentPosition(item.pagePosition)}`, `currentText: ${item.currentText || '(empty)'}`, `htmlHint: ${item.htmlHint || '(none)'}`, `comment: ${item.comment}`);
|
|
427
|
+
if (targetKind === 'visual') {
|
|
428
|
+
lines.push(`screenshot: ${item.screenshotPath}`, `markKind: ${item.markKind || 'stroke'}`, `intent: ${item.intent || visualAnnotationIntent(item.markKind || 'stroke')}`);
|
|
429
|
+
if (item.selector)
|
|
430
|
+
lines.push(`selector: ${item.selector}`);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
lines.splice(lines.length - 4, 0, `selector: ${item.selector}`);
|
|
434
|
+
}
|
|
435
|
+
if (targetKind === 'pod') {
|
|
436
|
+
lines.push(`memberCount: ${item.memberCount || item.podMembers.length || 0}`);
|
|
437
|
+
item.podMembers.slice(0, 8).forEach((member, memberIndex) => {
|
|
438
|
+
lines.push(`member.${memberIndex + 1}: ${member.elementId} | ${member.label || '(unlabeled)'} | ${member.selector}`);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
lines.push('</attached-preview-comments>');
|
|
443
|
+
return lines.join('\n');
|
|
444
|
+
}
|
|
445
|
+
function cleanString(value) {
|
|
446
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
447
|
+
}
|
|
448
|
+
function normalizeVisualMarkKind(value) {
|
|
449
|
+
return value === 'click' || value === 'click+stroke' || value === 'stroke'
|
|
450
|
+
? value
|
|
451
|
+
: 'stroke';
|
|
452
|
+
}
|
|
453
|
+
function visualAnnotationIntent(markKind) {
|
|
454
|
+
if (markKind === 'click') {
|
|
455
|
+
return 'The screenshot has a blue focus box around the picked element; modify that picked part first.';
|
|
456
|
+
}
|
|
457
|
+
if (markKind === 'click+stroke') {
|
|
458
|
+
return 'The screenshot has a blue focus box and red strokes; together they identify the part the user wants changed.';
|
|
459
|
+
}
|
|
460
|
+
return 'The screenshot has red strokes that identify the visual region the user wants changed.';
|
|
461
|
+
}
|
|
462
|
+
function compactString(value, max) {
|
|
463
|
+
const text = cleanString(value).replace(/\s+/g, ' ');
|
|
464
|
+
return text.length > max ? `${text.slice(0, max - 3)}...` : text;
|
|
465
|
+
}
|
|
466
|
+
function normalizeAttachmentPosition(input) {
|
|
467
|
+
const value = input && typeof input === 'object' ? input : {};
|
|
468
|
+
return {
|
|
469
|
+
x: finiteAttachmentNumber(value.x),
|
|
470
|
+
y: finiteAttachmentNumber(value.y),
|
|
471
|
+
width: finiteAttachmentNumber(value.width),
|
|
472
|
+
height: finiteAttachmentNumber(value.height),
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function normalizeAttachmentPodMembers(input) {
|
|
476
|
+
if (!Array.isArray(input))
|
|
477
|
+
return [];
|
|
478
|
+
return input
|
|
479
|
+
.map((member) => {
|
|
480
|
+
if (!member || typeof member !== 'object')
|
|
481
|
+
return null;
|
|
482
|
+
const elementId = cleanString(member.elementId);
|
|
483
|
+
const selector = cleanString(member.selector);
|
|
484
|
+
const label = cleanString(member.label);
|
|
485
|
+
if (!elementId || !selector)
|
|
486
|
+
return null;
|
|
487
|
+
return {
|
|
488
|
+
elementId,
|
|
489
|
+
selector,
|
|
490
|
+
label,
|
|
491
|
+
text: compactString(member.text, 160),
|
|
492
|
+
position: normalizeAttachmentPosition(member.position),
|
|
493
|
+
htmlHint: compactString(member.htmlHint, 180),
|
|
494
|
+
};
|
|
495
|
+
})
|
|
496
|
+
.filter(Boolean);
|
|
497
|
+
}
|
|
498
|
+
function finiteAttachmentNumber(value) {
|
|
499
|
+
return Number.isFinite(value) ? Math.round(value) : 0;
|
|
500
|
+
}
|
|
501
|
+
function formatAttachmentPosition(position) {
|
|
502
|
+
return `x=${position.x}, y=${position.y}, width=${position.width}, height=${position.height}`;
|
|
503
|
+
}
|
|
504
|
+
function isPathWithin(base, target) {
|
|
505
|
+
const relativePath = path.relative(path.resolve(base), path.resolve(target));
|
|
506
|
+
return (relativePath === '' ||
|
|
507
|
+
(relativePath.length > 0 &&
|
|
508
|
+
!relativePath.startsWith('..') &&
|
|
509
|
+
!path.isAbsolute(relativePath)));
|
|
510
|
+
}
|
|
511
|
+
function resolveProcessResourcesPath() {
|
|
512
|
+
if (typeof process.resourcesPath === 'string' &&
|
|
513
|
+
process.resourcesPath.length > 0) {
|
|
514
|
+
return process.resourcesPath;
|
|
515
|
+
}
|
|
516
|
+
// Packaged daemon sidecars run under the bundled Node binary rather than the
|
|
517
|
+
// Electron root process, so `process.resourcesPath` is unavailable there.
|
|
518
|
+
// Infer the macOS app Resources directory from that bundled Node path.
|
|
519
|
+
const resourcesMarker = `${path.sep}Contents${path.sep}Resources${path.sep}`;
|
|
520
|
+
const markerIndex = process.execPath.indexOf(resourcesMarker);
|
|
521
|
+
if (markerIndex !== -1) {
|
|
522
|
+
return process.execPath.slice(0, markerIndex + resourcesMarker.length - 1);
|
|
523
|
+
}
|
|
524
|
+
const normalizedExecPath = process.execPath.toLowerCase();
|
|
525
|
+
const windowsResourceBinMarker = `${path.sep}resources${path.sep}open-design${path.sep}bin${path.sep}`.toLowerCase();
|
|
526
|
+
const windowsMarkerIndex = normalizedExecPath.indexOf(windowsResourceBinMarker);
|
|
527
|
+
if (windowsMarkerIndex !== -1) {
|
|
528
|
+
return process.execPath.slice(0, windowsMarkerIndex + `${path.sep}resources`.length);
|
|
529
|
+
}
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
export function resolveDaemonResourceRoot({ configured = process.env[RESOURCE_ROOT_ENV], safeBases = [PROJECT_ROOT, resolveProcessResourcesPath()], } = {}) {
|
|
533
|
+
if (!configured || configured.length === 0)
|
|
534
|
+
return null;
|
|
535
|
+
const resolved = path.resolve(configured);
|
|
536
|
+
const normalizedSafeBases = safeBases
|
|
537
|
+
.filter((base) => typeof base === 'string' && base.length > 0)
|
|
538
|
+
.map((base) => path.resolve(base));
|
|
539
|
+
if (!normalizedSafeBases.some((base) => isPathWithin(base, resolved))) {
|
|
540
|
+
throw new Error(`${RESOURCE_ROOT_ENV} must be under the workspace root or app resources path`);
|
|
541
|
+
}
|
|
542
|
+
return resolved;
|
|
543
|
+
}
|
|
544
|
+
function resolveDaemonResourceDir(resourceRoot, segment, fallback) {
|
|
545
|
+
return resourceRoot ? path.join(resourceRoot, segment) : fallback;
|
|
546
|
+
}
|
|
547
|
+
const DAEMON_RESOURCE_ROOT = resolveDaemonResourceRoot();
|
|
548
|
+
// Built web app lives in `out/` — that's where Next.js writes the static
|
|
549
|
+
// export configured in next.config.ts. The folder name used to be `dist/`
|
|
550
|
+
// when this project shipped with Vite; the daemon serves whatever the
|
|
551
|
+
// frontend toolchain emits, no further config needed.
|
|
552
|
+
const STATIC_DIR = path.join(PROJECT_ROOT, 'apps', 'web', 'out');
|
|
553
|
+
const OD_BIN = resolveDaemonCliPath();
|
|
554
|
+
const OD_NODE_BIN = process.execPath;
|
|
555
|
+
const SKILLS_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'skills', path.join(PROJECT_ROOT, 'skills'));
|
|
556
|
+
const DESIGN_SYSTEMS_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'design-systems', path.join(PROJECT_ROOT, 'design-systems'));
|
|
557
|
+
// Renderable templates pulled out of `skills/` by the skills/design-templates
|
|
558
|
+
// split (PR #955) so the EntryView Templates tab gets the large rendering
|
|
559
|
+
// catalogue and Settings → Skills only carries functional skills the agent
|
|
560
|
+
// invokes mid-task. See specs/current/skills-and-design-templates.md.
|
|
561
|
+
const DESIGN_TEMPLATES_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'design-templates', path.join(PROJECT_ROOT, 'design-templates'));
|
|
562
|
+
const CRAFT_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'craft', path.join(PROJECT_ROOT, 'craft'));
|
|
563
|
+
// User-installed skills and design systems live under the runtime data dir
|
|
564
|
+
// so they respect OD_DATA_DIR overrides (test isolation, packaged runs).
|
|
565
|
+
// Defined after RUNTIME_DATA_DIR is resolved below.
|
|
566
|
+
const FRAMES_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'frames', path.join(PROJECT_ROOT, 'assets', 'frames'));
|
|
567
|
+
// Curated pets baked into the repo via `scripts/bake-community-pets.ts`.
|
|
568
|
+
// `listCodexPets` scans this in addition to `~/.codex/pets/` so the
|
|
569
|
+
// "Recently hatched" grid is non-empty out-of-the-box and users do not
|
|
570
|
+
// need to hit the "Download community pets" button to try a few pets.
|
|
571
|
+
const BUNDLED_PETS_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'community-pets', path.join(PROJECT_ROOT, 'assets', 'community-pets'));
|
|
572
|
+
const PROMPT_TEMPLATES_DIR = resolveDaemonResourceDir(DAEMON_RESOURCE_ROOT, 'prompt-templates', path.join(PROJECT_ROOT, 'prompt-templates'));
|
|
573
|
+
export function resolveDataDir(raw, projectRoot) {
|
|
574
|
+
if (!raw)
|
|
575
|
+
return path.join(projectRoot, '.od');
|
|
576
|
+
// expandHomePrefix is shared with media-config.ts so OD_DATA_DIR and
|
|
577
|
+
// OD_MEDIA_CONFIG_DIR can never split state under a $HOME-style value.
|
|
578
|
+
// Some launchers (systemd unit files, NixOS modules, certain Docker
|
|
579
|
+
// entrypoints, Windows scheduled tasks) pass OD_DATA_DIR with literal
|
|
580
|
+
// $HOME or ${HOME} because the variable is never expanded by a shell;
|
|
581
|
+
// expandHomePrefix turns those (and the ~ shorthand, with both / and \
|
|
582
|
+
// separators) into os.homedir() before path.resolve runs so launch
|
|
583
|
+
// surfaces stay consistent.
|
|
584
|
+
const resolved = resolveProjectRelativePath(raw, projectRoot);
|
|
585
|
+
try {
|
|
586
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
587
|
+
fs.accessSync(resolved, fs.constants.W_OK);
|
|
588
|
+
}
|
|
589
|
+
catch (err) {
|
|
590
|
+
const e = err;
|
|
591
|
+
const currentUser = (() => {
|
|
592
|
+
try {
|
|
593
|
+
return os.userInfo().username;
|
|
594
|
+
}
|
|
595
|
+
catch {
|
|
596
|
+
return process.env.USER ?? process.env.LOGNAME ?? 'unknown';
|
|
597
|
+
}
|
|
598
|
+
})();
|
|
599
|
+
const parentDir = path.dirname(resolved);
|
|
600
|
+
throw new Error([
|
|
601
|
+
`OD_DATA_DIR "${resolved}" is not writable: ${e.message}`,
|
|
602
|
+
`Current user: ${currentUser}`,
|
|
603
|
+
`Check whether the folder or one of its parents is owned by another user, is a symlink to a protected location, or was previously created with sudo.`,
|
|
604
|
+
`Try: ls -ld "${parentDir}" "${resolved}"`,
|
|
605
|
+
`If the folder should belong to you, fix ownership/permissions, for example: sudo chown -R "${currentUser}":staff "${parentDir}" && chmod -R u+rwX "${parentDir}"`,
|
|
606
|
+
].join(' '));
|
|
607
|
+
}
|
|
608
|
+
return resolved;
|
|
609
|
+
}
|
|
610
|
+
const RUNTIME_DATA_DIR = resolveDataDir(process.env.OD_DATA_DIR, PROJECT_ROOT);
|
|
611
|
+
// Canonical (realpath-resolved) form of RUNTIME_DATA_DIR for the few callers
|
|
612
|
+
// that compare it against a user-supplied realpath() result. On macOS, /var
|
|
613
|
+
// is a symlink to /private/var, so an import realpath lands in /private/var
|
|
614
|
+
// and would never start-with the raw RUNTIME_DATA_DIR. Keep RUNTIME_DATA_DIR
|
|
615
|
+
// itself as the stable, user-shaped path so OD_DATA_DIR resolution stays
|
|
616
|
+
// predictable; only this canonical alias is used for symlink-aware checks.
|
|
617
|
+
const RUNTIME_DATA_DIR_CANONICAL = (() => {
|
|
618
|
+
try {
|
|
619
|
+
return fs.realpathSync(RUNTIME_DATA_DIR);
|
|
620
|
+
}
|
|
621
|
+
catch {
|
|
622
|
+
return RUNTIME_DATA_DIR;
|
|
623
|
+
}
|
|
624
|
+
})();
|
|
625
|
+
// One-shot legacy data migration. When OD_LEGACY_DATA_DIR is set and the
|
|
626
|
+
// new data root is fresh (no app.sqlite), copy the 0.3.x .od/ payload
|
|
627
|
+
// across before SQLite opens. Synchronous on purpose: openDatabase below
|
|
628
|
+
// would race an async copy. See apps/daemon/src/legacy-data-migrator.ts
|
|
629
|
+
// and https://github.com/nexu-io/open-design/issues/710.
|
|
630
|
+
migrateLegacyDataDirSync({
|
|
631
|
+
legacyDir: process.env.OD_LEGACY_DATA_DIR,
|
|
632
|
+
dataDir: RUNTIME_DATA_DIR,
|
|
633
|
+
});
|
|
634
|
+
const ARTIFACTS_DIR = path.join(RUNTIME_DATA_DIR, 'artifacts');
|
|
635
|
+
// Critique Theater artifacts intentionally live outside the static
|
|
636
|
+
// `/artifacts` tree. The per-run artifact endpoint is the sanctioned
|
|
637
|
+
// read path so project-membership, size, and CSP guards cannot be bypassed.
|
|
638
|
+
const CRITIQUE_ARTIFACTS_DIR = path.join(RUNTIME_DATA_DIR, 'critique-artifacts');
|
|
639
|
+
const PROJECTS_DIR = path.join(RUNTIME_DATA_DIR, 'projects');
|
|
640
|
+
const USER_SKILLS_DIR = path.join(RUNTIME_DATA_DIR, 'skills');
|
|
641
|
+
const USER_DESIGN_SYSTEMS_DIR = path.join(RUNTIME_DATA_DIR, 'design-systems');
|
|
642
|
+
// User-imported design templates mirror USER_SKILLS_DIR but are scanned
|
|
643
|
+
// against DESIGN_TEMPLATES_DIR rather than SKILLS_DIR so the EntryView
|
|
644
|
+
// Templates surface and the Settings → Skills surface stay decoupled.
|
|
645
|
+
const USER_DESIGN_TEMPLATES_DIR = path.join(RUNTIME_DATA_DIR, 'design-templates');
|
|
646
|
+
// Multi-root tuples used everywhere the daemon resolves a skill / template
|
|
647
|
+
// id without knowing which surface it came from. SKILL_ROOTS drives
|
|
648
|
+
// Settings → Skills; DESIGN_TEMPLATE_ROOTS drives the EntryView Templates
|
|
649
|
+
// gallery; ALL_SKILL_LIKE_ROOTS spans both for chat run system-prompt
|
|
650
|
+
// composition and the orbit template resolver, where stored project ids
|
|
651
|
+
// can resolve to either root after the split.
|
|
652
|
+
const SKILL_ROOTS = [USER_SKILLS_DIR, SKILLS_DIR];
|
|
653
|
+
const DESIGN_TEMPLATE_ROOTS = [USER_DESIGN_TEMPLATES_DIR, DESIGN_TEMPLATES_DIR];
|
|
654
|
+
const ALL_SKILL_LIKE_ROOTS = [
|
|
655
|
+
USER_SKILLS_DIR,
|
|
656
|
+
USER_DESIGN_TEMPLATES_DIR,
|
|
657
|
+
SKILLS_DIR,
|
|
658
|
+
DESIGN_TEMPLATES_DIR,
|
|
659
|
+
];
|
|
660
|
+
fs.mkdirSync(PROJECTS_DIR, { recursive: true });
|
|
661
|
+
for (const dir of [USER_SKILLS_DIR, USER_DESIGN_SYSTEMS_DIR, USER_DESIGN_TEMPLATES_DIR]) {
|
|
662
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
663
|
+
}
|
|
664
|
+
fs.mkdirSync(CRITIQUE_ARTIFACTS_DIR, { recursive: true });
|
|
665
|
+
const orbitService = new OrbitService(RUNTIME_DATA_DIR);
|
|
666
|
+
let routineService = null;
|
|
667
|
+
// In-memory OAuth state cache. Lives for the daemon process's lifetime.
|
|
668
|
+
// Maps the OAuth `state` parameter we generated in /api/mcp/oauth/start
|
|
669
|
+
// to the verifier + endpoint info needed to finish the exchange when the
|
|
670
|
+
// browser hits /api/mcp/oauth/callback.
|
|
671
|
+
const mcpPendingAuth = new PendingAuthCache();
|
|
672
|
+
/**
|
|
673
|
+
* Resolve the daemon's public base URL — the origin the user's browser
|
|
674
|
+
* (or the OAuth provider) reaches us at. Order of precedence:
|
|
675
|
+
*
|
|
676
|
+
* 1. `OD_PUBLIC_BASE_URL` env var. Cloud and packaged-electron deployments
|
|
677
|
+
* set this to the externally-routable URL (e.g. `https://app.example.com`).
|
|
678
|
+
* 2. `req.protocol://req.get('host')` from the inbound request. Works in
|
|
679
|
+
* local dev and most reverse-proxy setups (Express respects
|
|
680
|
+
* `trust proxy` so X-Forwarded-* headers are honored).
|
|
681
|
+
*
|
|
682
|
+
* The OAuth callback URI is derived from this — it MUST be reachable from
|
|
683
|
+
* the user's browser, otherwise the redirect after auth lands on
|
|
684
|
+
* ERR_CONNECTION_REFUSED. Misconfiguration is loud: the OAuth provider
|
|
685
|
+
* will reject `redirect_uri` mismatches.
|
|
686
|
+
*/
|
|
687
|
+
function getPublicBaseUrl(req) {
|
|
688
|
+
const env = process.env.OD_PUBLIC_BASE_URL;
|
|
689
|
+
if (env && /^https?:\/\//i.test(env)) {
|
|
690
|
+
return env.replace(/\/+$/u, '');
|
|
691
|
+
}
|
|
692
|
+
const proto = req.protocol || 'http';
|
|
693
|
+
const host = req.get('host');
|
|
694
|
+
if (!host)
|
|
695
|
+
return `http://localhost:${process.env.OD_PORT ?? '7456'}`;
|
|
696
|
+
return `${proto}://${host}`;
|
|
697
|
+
}
|
|
698
|
+
function mcpOAuthCallbackUrl(req) {
|
|
699
|
+
return `${getPublicBaseUrl(req)}/api/mcp/oauth/callback`;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Refresh an expired token using the OAuth client context that the original
|
|
703
|
+
* authorization-code exchange persisted alongside the token. Refresh tokens
|
|
704
|
+
* are bound (RFC 6749 §6) to the client that received them, so we MUST
|
|
705
|
+
* refresh against the same `tokenEndpoint` / `clientId` / `clientSecret`
|
|
706
|
+
* pair — re-running discovery with a different redirect URI would risk
|
|
707
|
+
* registering a new client_id that the upstream then rejects the refresh
|
|
708
|
+
* for. Tokens persisted before that context was recorded can't be safely
|
|
709
|
+
* refreshed; the caller treats `null` as "needs reconnect".
|
|
710
|
+
*/
|
|
711
|
+
async function refreshAndPersistToken(dataDir, serverId, current) {
|
|
712
|
+
if (!current.refreshToken)
|
|
713
|
+
return null;
|
|
714
|
+
if (!current.tokenEndpoint || !current.clientId)
|
|
715
|
+
return null;
|
|
716
|
+
const tokenResp = await refreshAccessToken({
|
|
717
|
+
tokenEndpoint: current.tokenEndpoint,
|
|
718
|
+
clientId: current.clientId,
|
|
719
|
+
clientSecret: current.clientSecret,
|
|
720
|
+
refreshToken: current.refreshToken,
|
|
721
|
+
scope: current.scope,
|
|
722
|
+
resource: current.resourceUrl,
|
|
723
|
+
});
|
|
724
|
+
const next = {
|
|
725
|
+
accessToken: tokenResp.access_token,
|
|
726
|
+
refreshToken: tokenResp.refresh_token ?? current.refreshToken,
|
|
727
|
+
tokenType: tokenResp.token_type ?? 'Bearer',
|
|
728
|
+
scope: tokenResp.scope ?? current.scope,
|
|
729
|
+
expiresAt: typeof tokenResp.expires_in === 'number'
|
|
730
|
+
? Date.now() + tokenResp.expires_in * 1000
|
|
731
|
+
: undefined,
|
|
732
|
+
savedAt: Date.now(),
|
|
733
|
+
tokenEndpoint: current.tokenEndpoint,
|
|
734
|
+
clientId: current.clientId,
|
|
735
|
+
clientSecret: current.clientSecret,
|
|
736
|
+
authServerIssuer: current.authServerIssuer,
|
|
737
|
+
redirectUri: current.redirectUri,
|
|
738
|
+
resourceUrl: current.resourceUrl,
|
|
739
|
+
};
|
|
740
|
+
await setToken(dataDir, serverId, next);
|
|
741
|
+
return next;
|
|
742
|
+
}
|
|
743
|
+
const activeChatAgentEventSinks = new Map();
|
|
744
|
+
const activeProjectEventSinks = new Map();
|
|
745
|
+
function emitChatAgentEvent(runId, payload) {
|
|
746
|
+
const sink = activeChatAgentEventSinks.get(runId);
|
|
747
|
+
if (!sink)
|
|
748
|
+
return false;
|
|
749
|
+
return sink(payload);
|
|
750
|
+
}
|
|
751
|
+
function emitLiveArtifactEvent(grant, action, artifact) {
|
|
752
|
+
if (!artifact?.id)
|
|
753
|
+
return false;
|
|
754
|
+
const payload = {
|
|
755
|
+
type: 'live_artifact',
|
|
756
|
+
action,
|
|
757
|
+
projectId: artifact.projectId ?? grant.projectId,
|
|
758
|
+
artifactId: artifact.id,
|
|
759
|
+
title: artifact.title ?? artifact.id,
|
|
760
|
+
refreshStatus: artifact.refreshStatus,
|
|
761
|
+
};
|
|
762
|
+
let emitted = emitProjectEvent(payload.projectId, payload);
|
|
763
|
+
if (grant?.runId)
|
|
764
|
+
emitted = emitChatAgentEvent(grant.runId, payload) || emitted;
|
|
765
|
+
return emitted;
|
|
766
|
+
}
|
|
767
|
+
function emitLiveArtifactRefreshEvent(grant, payload) {
|
|
768
|
+
if (!payload?.artifactId)
|
|
769
|
+
return false;
|
|
770
|
+
const event = {
|
|
771
|
+
type: 'live_artifact_refresh',
|
|
772
|
+
projectId: grant.projectId,
|
|
773
|
+
...payload,
|
|
774
|
+
};
|
|
775
|
+
let emitted = emitProjectEvent(grant.projectId, event);
|
|
776
|
+
if (grant?.runId)
|
|
777
|
+
emitted = emitChatAgentEvent(grant.runId, event) || emitted;
|
|
778
|
+
return emitted;
|
|
779
|
+
}
|
|
780
|
+
// Broadcast an event to every SSE subscriber currently watching the given
|
|
781
|
+
// project's `/api/projects/:id/events` stream. The payload's `type` field
|
|
782
|
+
// becomes the SSE event name (see project-routes.ts). Used for live-artifact
|
|
783
|
+
// events and `conversation-created` events emitted by routine runs (#1361).
|
|
784
|
+
function emitProjectEvent(projectId, payload) {
|
|
785
|
+
const sinks = activeProjectEventSinks.get(projectId);
|
|
786
|
+
if (!sinks || sinks.size === 0)
|
|
787
|
+
return false;
|
|
788
|
+
for (const sink of Array.from(sinks)) {
|
|
789
|
+
try {
|
|
790
|
+
sink(payload);
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
sinks.delete(sink);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (sinks.size === 0)
|
|
797
|
+
activeProjectEventSinks.delete(projectId);
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
// Windows ENAMETOOLONG mitigation constants
|
|
801
|
+
const CMD_BAT_RE = /\.(cmd|bat)$/i;
|
|
802
|
+
const PROMPT_TEMP_FILE = () => '.od-prompt-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8) + '.md';
|
|
803
|
+
const promptFileBootstrap = (fp) => `Your full instructions are stored in the file: ${fp.replace(/\\/g, '/')}. ` +
|
|
804
|
+
'Open that file first and follow every instruction in it exactly — ' +
|
|
805
|
+
'it contains the system prompt, design system, skill workflow, and user request. ' +
|
|
806
|
+
'Do not begin your response until you have read the entire file.';
|
|
807
|
+
// Load Critique Theater config once at startup so a bad OD_CRITIQUE_* value
|
|
808
|
+
// surfaces immediately as a boot-time RangeError instead of silently at
|
|
809
|
+
// run time. Default: enabled=false (M0 dark launch).
|
|
810
|
+
const critiqueCfg = loadCritiqueConfigFromEnv();
|
|
811
|
+
// Tracks adapter streamFormat values that have already received a one-time
|
|
812
|
+
// warning explaining why the Critique Theater orchestrator was bypassed.
|
|
813
|
+
// Adapter denylist for orchestrator routing is implicit: anything that is
|
|
814
|
+
// not the 'plain' streamFormat falls through to legacy single-pass.
|
|
815
|
+
const critiqueWarnedAdapters = new Set();
|
|
816
|
+
// In-process registry of in-flight critique runs so the interrupt endpoint
|
|
817
|
+
// can cascade an AbortController to the matching orchestrator invocation.
|
|
818
|
+
// Created once per process; not persisted across daemon restarts.
|
|
819
|
+
const critiqueRunRegistry = createRunRegistry();
|
|
820
|
+
export const SSE_KEEPALIVE_INTERVAL_MS = 25_000;
|
|
821
|
+
export function createAgentRuntimeEnv(baseEnv, daemonUrl, toolTokenGrant = null, nodeBin = process.execPath) {
|
|
822
|
+
const env = {
|
|
823
|
+
...baseEnv,
|
|
824
|
+
OD_DAEMON_URL: daemonUrl,
|
|
825
|
+
OD_NODE_BIN: nodeBin,
|
|
826
|
+
};
|
|
827
|
+
if (toolTokenGrant?.token) {
|
|
828
|
+
env.OD_TOOL_TOKEN = toolTokenGrant.token;
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
delete env.OD_TOOL_TOKEN;
|
|
832
|
+
}
|
|
833
|
+
return env;
|
|
834
|
+
}
|
|
835
|
+
export function createAgentRuntimeToolPrompt(daemonUrl, toolTokenGrant = null) {
|
|
836
|
+
const tokenLine = toolTokenGrant?.token
|
|
837
|
+
? '- `OD_TOOL_TOKEN` is available in your environment for this run. Use it only through project wrapper commands; do not print, persist, or override it.'
|
|
838
|
+
: '- `OD_TOOL_TOKEN` is not available for this run, so `/api/tools/*` wrapper commands may be unavailable.';
|
|
839
|
+
return [
|
|
840
|
+
'## Runtime tool environment',
|
|
841
|
+
'',
|
|
842
|
+
`- Daemon URL: \`${daemonUrl}\` (also available as \`OD_DAEMON_URL\`).`,
|
|
843
|
+
'- `OD_NODE_BIN` is the absolute path to the Node-compatible runtime that started the daemon; packaged desktop installs provide this even when the user has no system `node` on PATH.',
|
|
844
|
+
'- `OD_BIN` is the absolute path to the Open Design CLI script. On POSIX shells run wrappers with `"$OD_NODE_BIN" "$OD_BIN" tools ...`; do not call bare `od`, which may resolve to the system octal-dump command on Unix-like systems.',
|
|
845
|
+
'- On PowerShell use `& $env:OD_NODE_BIN $env:OD_BIN tools ...`; on cmd.exe use `"%OD_NODE_BIN%" "%OD_BIN%" tools ...`.',
|
|
846
|
+
tokenLine,
|
|
847
|
+
'- Prefer project wrapper commands through `OD_NODE_BIN` + `OD_BIN` over raw HTTP. The wrappers read these environment values automatically.',
|
|
848
|
+
].join('\n');
|
|
849
|
+
}
|
|
850
|
+
export function normalizeProjectDisplayStatus(status) {
|
|
851
|
+
return status === 'starting' || status === 'queued' ? 'running' : status;
|
|
852
|
+
}
|
|
853
|
+
export function composeProjectDisplayStatus(baseStatus, awaitingInputProjects, projectId) {
|
|
854
|
+
if (baseStatus.value === 'succeeded' &&
|
|
855
|
+
awaitingInputProjects.has(projectId)) {
|
|
856
|
+
return { ...baseStatus, value: 'awaiting_input' };
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
...baseStatus,
|
|
860
|
+
value: normalizeProjectDisplayStatus(baseStatus.value),
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* @param {ApiErrorCode} code
|
|
865
|
+
* @param {string} message
|
|
866
|
+
* @param {Omit<ApiError, 'code' | 'message'>} [init]
|
|
867
|
+
* @returns {ApiError}
|
|
868
|
+
*/
|
|
869
|
+
export function createCompatApiError(code, message, init = {}) {
|
|
870
|
+
return { code, message, ...init };
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* @param {ApiErrorCode} code
|
|
874
|
+
* @param {string} message
|
|
875
|
+
* @param {Omit<ApiError, 'code' | 'message'>} [init]
|
|
876
|
+
* @returns {ApiErrorResponse}
|
|
877
|
+
*/
|
|
878
|
+
export function createCompatApiErrorResponse(code, message, init = {}) {
|
|
879
|
+
return { error: createCompatApiError(code, message, init) };
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* @param {import('express').Response} res
|
|
883
|
+
* @param {number} status
|
|
884
|
+
* @param {ApiErrorCode} code
|
|
885
|
+
* @param {string} message
|
|
886
|
+
* @param {Omit<ApiError, 'code' | 'message'>} [init]
|
|
887
|
+
*/
|
|
888
|
+
function sendApiError(res, status, code, message, init = {}) {
|
|
889
|
+
return res
|
|
890
|
+
.status(status)
|
|
891
|
+
.json(createCompatApiErrorResponse(code, message, init));
|
|
892
|
+
}
|
|
893
|
+
const TERMINAL_RUN_STATUSES = new Set(['succeeded', 'failed', 'canceled']);
|
|
894
|
+
export function shouldReportRunCompletedFromMessage(saved, body = {}) {
|
|
895
|
+
return Boolean(saved &&
|
|
896
|
+
saved.runId &&
|
|
897
|
+
typeof saved.runStatus === 'string' &&
|
|
898
|
+
TERMINAL_RUN_STATUSES.has(saved.runStatus) &&
|
|
899
|
+
body?.telemetryFinalized === true);
|
|
900
|
+
}
|
|
901
|
+
export function telemetryPromptFromRunRequest(message, currentPrompt) {
|
|
902
|
+
return typeof currentPrompt === 'string' ? currentPrompt : message;
|
|
903
|
+
}
|
|
904
|
+
export function createFinalizedMessageTelemetryReporter({ design, db, dataDir, reportedRuns, getAppVersion = () => null, report = reportRunCompletedFromDaemon, }) {
|
|
905
|
+
return (saved, body = {}) => {
|
|
906
|
+
if (!shouldReportRunCompletedFromMessage(saved, body))
|
|
907
|
+
return;
|
|
908
|
+
const run = design.runs.get(saved.runId);
|
|
909
|
+
if (!run || reportedRuns.has(run.id))
|
|
910
|
+
return;
|
|
911
|
+
reportedRuns.add(run.id);
|
|
912
|
+
void report({
|
|
913
|
+
db,
|
|
914
|
+
dataDir,
|
|
915
|
+
run,
|
|
916
|
+
persistedRunStatus: saved.runStatus,
|
|
917
|
+
persistedEndedAt: saved.endedAt,
|
|
918
|
+
appVersion: getAppVersion(),
|
|
919
|
+
});
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
const CLOUDFLARE_PAGES_PROJECT_METADATA_KEY = 'cloudflarePagesProjectName';
|
|
923
|
+
function cloudflarePagesDeploymentMetadata(projectName) {
|
|
924
|
+
const normalized = typeof projectName === 'string' ? projectName.trim() : '';
|
|
925
|
+
return normalized
|
|
926
|
+
? { [CLOUDFLARE_PAGES_PROJECT_METADATA_KEY]: normalized }
|
|
927
|
+
: undefined;
|
|
928
|
+
}
|
|
929
|
+
function cloudflarePagesProjectNameFromDeployment(deployment) {
|
|
930
|
+
const value = deployment?.providerMetadata?.[CLOUDFLARE_PAGES_PROJECT_METADATA_KEY];
|
|
931
|
+
if (typeof value === 'string' && value.trim())
|
|
932
|
+
return value.trim();
|
|
933
|
+
return cloudflarePagesProjectNameFromUrl(deployment?.url);
|
|
934
|
+
}
|
|
935
|
+
function cloudflarePagesProjectNameFromUrl(rawUrl) {
|
|
936
|
+
if (typeof rawUrl !== 'string' || !rawUrl.trim())
|
|
937
|
+
return '';
|
|
938
|
+
try {
|
|
939
|
+
const host = new URL(rawUrl).hostname.toLowerCase();
|
|
940
|
+
if (!host.endsWith('.pages.dev'))
|
|
941
|
+
return '';
|
|
942
|
+
const labels = host.slice(0, -'.pages.dev'.length).split('.').filter(Boolean);
|
|
943
|
+
return labels.at(-1) || '';
|
|
944
|
+
}
|
|
945
|
+
catch {
|
|
946
|
+
return '';
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
function cloudflarePagesProjectNameForDeploy(db, projectId, projectName, prior) {
|
|
950
|
+
const priorName = cloudflarePagesProjectNameFromDeployment(prior);
|
|
951
|
+
if (priorName)
|
|
952
|
+
return priorName;
|
|
953
|
+
for (const deployment of listDeployments(db, projectId)) {
|
|
954
|
+
if (deployment.providerId !== CLOUDFLARE_PAGES_PROVIDER_ID)
|
|
955
|
+
continue;
|
|
956
|
+
const stableName = cloudflarePagesProjectNameFromDeployment(deployment);
|
|
957
|
+
if (stableName)
|
|
958
|
+
return stableName;
|
|
959
|
+
}
|
|
960
|
+
return cloudflarePagesProjectNameForProject(projectId, projectName);
|
|
961
|
+
}
|
|
962
|
+
function publicDeployment(deployment) {
|
|
963
|
+
if (!deployment || typeof deployment !== 'object')
|
|
964
|
+
return deployment;
|
|
965
|
+
const { providerMetadata: _providerMetadata, ...publicShape } = deployment;
|
|
966
|
+
return publicShape;
|
|
967
|
+
}
|
|
968
|
+
function publicDeployments(deployments) {
|
|
969
|
+
return (deployments || []).map(publicDeployment);
|
|
970
|
+
}
|
|
971
|
+
async function checkCloudflarePagesDeploymentLinks(existing) {
|
|
972
|
+
const current = existing.cloudflarePages || {};
|
|
973
|
+
const projectName = current.projectName || cloudflarePagesProjectNameFromDeployment(existing);
|
|
974
|
+
const config = await readDeployConfig(CLOUDFLARE_PAGES_PROVIDER_ID);
|
|
975
|
+
const pagesDevUrl = current.pagesDev?.url || existing.url;
|
|
976
|
+
const pagesDevResult = await checkDeploymentUrl(pagesDevUrl);
|
|
977
|
+
const pagesDev = {
|
|
978
|
+
...(current.pagesDev || {}),
|
|
979
|
+
url: pagesDevUrl,
|
|
980
|
+
status: pagesDevResult.reachable ? 'ready' : pagesDevResult.status || 'link-delayed',
|
|
981
|
+
statusMessage: pagesDevResult.reachable
|
|
982
|
+
? 'Public link is ready.'
|
|
983
|
+
: pagesDevResult.statusMessage || current.pagesDev?.statusMessage || 'Cloudflare Pages is still preparing the pages.dev link.',
|
|
984
|
+
reachableAt: pagesDevResult.reachable ? Date.now() : current.pagesDev?.reachableAt,
|
|
985
|
+
};
|
|
986
|
+
let customDomain = current.customDomain;
|
|
987
|
+
if (customDomain?.url && customDomain.status !== 'conflict') {
|
|
988
|
+
let pagesDomain = null;
|
|
989
|
+
if (config?.token && config?.accountId && projectName) {
|
|
990
|
+
try {
|
|
991
|
+
pagesDomain = await readCloudflarePagesDomain({ ...config, projectName }, customDomain.hostname);
|
|
992
|
+
}
|
|
993
|
+
catch {
|
|
994
|
+
pagesDomain = null;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
const customResult = await checkDeploymentUrl(customDomain.url);
|
|
998
|
+
const pagesDomainStatus = pagesDomain?.status || customDomain.pagesDomainStatus;
|
|
999
|
+
const failedByApi = ['error', 'blocked', 'deactivated'].includes(String(pagesDomainStatus || '').toLowerCase());
|
|
1000
|
+
const activeByApi = String(pagesDomainStatus || '').toLowerCase() === 'active';
|
|
1001
|
+
const readyByReachability = customResult.reachable && activeByApi;
|
|
1002
|
+
customDomain = {
|
|
1003
|
+
...customDomain,
|
|
1004
|
+
domainStatus: pagesDomain
|
|
1005
|
+
? pagesDomain.status === 'active'
|
|
1006
|
+
? 'active'
|
|
1007
|
+
: failedByApi
|
|
1008
|
+
? 'failed'
|
|
1009
|
+
: 'pending'
|
|
1010
|
+
: customDomain.domainStatus,
|
|
1011
|
+
pagesDomainStatus,
|
|
1012
|
+
validationData: pagesDomain?.validation_data ?? customDomain.validationData,
|
|
1013
|
+
verificationData: pagesDomain?.verification_data ?? customDomain.verificationData,
|
|
1014
|
+
status: readyByReachability
|
|
1015
|
+
? 'ready'
|
|
1016
|
+
: customDomain.status === 'failed' || failedByApi
|
|
1017
|
+
? 'failed'
|
|
1018
|
+
: 'pending',
|
|
1019
|
+
statusMessage: readyByReachability
|
|
1020
|
+
? 'Custom domain is ready.'
|
|
1021
|
+
: failedByApi
|
|
1022
|
+
? 'Cloudflare Pages reported a custom-domain error.'
|
|
1023
|
+
: customResult.statusMessage || customDomain.statusMessage || 'Custom domain is still being prepared.',
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
const cloudflarePages = {
|
|
1027
|
+
...current,
|
|
1028
|
+
projectName,
|
|
1029
|
+
pagesDev,
|
|
1030
|
+
...(customDomain ? { customDomain } : {}),
|
|
1031
|
+
};
|
|
1032
|
+
const aggregate = aggregateCloudflarePagesStatus(pagesDev, customDomain);
|
|
1033
|
+
return {
|
|
1034
|
+
url: pagesDev.url,
|
|
1035
|
+
status: aggregate.status,
|
|
1036
|
+
statusMessage: aggregate.statusMessage,
|
|
1037
|
+
cloudflarePages,
|
|
1038
|
+
providerMetadata: {
|
|
1039
|
+
...(existing.providerMetadata || {}),
|
|
1040
|
+
cloudflarePages,
|
|
1041
|
+
},
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
// Filename slug for the Content-Disposition header on archive downloads.
|
|
1045
|
+
// Browsers reject quotes and control bytes; we keep Unicode letters/digits
|
|
1046
|
+
// so a project name with non-ASCII characters (e.g. "café-design")
|
|
1047
|
+
// survives instead of becoming a row of underscores.
|
|
1048
|
+
function sanitizeArchiveFilename(raw) {
|
|
1049
|
+
const cleaned = String(raw ?? '')
|
|
1050
|
+
.replace(/[\\/:*?"<>|]/g, '_')
|
|
1051
|
+
.replace(/[\u0000-\u001f\u007f]/g, '')
|
|
1052
|
+
.replace(/\s+/g, '-')
|
|
1053
|
+
.replace(/^-+|-+$/g, '')
|
|
1054
|
+
.slice(0, 80);
|
|
1055
|
+
return cleaned;
|
|
1056
|
+
}
|
|
1057
|
+
function sendLiveArtifactRouteError(res, err) {
|
|
1058
|
+
if (err instanceof LiveArtifactStoreValidationError) {
|
|
1059
|
+
return sendApiError(res, 400, 'LIVE_ARTIFACT_INVALID', err.message, {
|
|
1060
|
+
details: { kind: 'validation', issues: err.issues },
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
if (err instanceof LiveArtifactRefreshLockError) {
|
|
1064
|
+
return sendApiError(res, 409, 'REFRESH_LOCKED', err.message, {
|
|
1065
|
+
details: { artifactId: err.artifactId },
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
if (err instanceof LiveArtifactRefreshUnavailableError) {
|
|
1069
|
+
return sendApiError(res, 400, 'LIVE_ARTIFACT_REFRESH_UNAVAILABLE', err.message);
|
|
1070
|
+
}
|
|
1071
|
+
if (err instanceof LiveArtifactRefreshAbortError) {
|
|
1072
|
+
return sendApiError(res, err.kind === 'cancelled' ? 499 : 504, 'LIVE_ARTIFACT_REFRESH_TIMEOUT', err.message, {
|
|
1073
|
+
details: { kind: err.kind, timeoutMs: err.timeoutMs ?? null, step: err.step ?? null },
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
if (err instanceof ConnectorServiceError) {
|
|
1077
|
+
return sendApiError(res, err.status, err.code, err.message, err.details === undefined ? {} : { details: err.details });
|
|
1078
|
+
}
|
|
1079
|
+
if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') {
|
|
1080
|
+
return sendApiError(res, 404, 'LIVE_ARTIFACT_NOT_FOUND', 'live artifact not found');
|
|
1081
|
+
}
|
|
1082
|
+
return sendApiError(res, 500, 'LIVE_ARTIFACT_STORAGE_FAILED', String(err));
|
|
1083
|
+
}
|
|
1084
|
+
function normalizeLocalAuthority(value) {
|
|
1085
|
+
if (typeof value !== 'string')
|
|
1086
|
+
return null;
|
|
1087
|
+
const trimmed = value.trim();
|
|
1088
|
+
if (!trimmed || /[\s/@]/.test(trimmed) || trimmed.includes(','))
|
|
1089
|
+
return null;
|
|
1090
|
+
try {
|
|
1091
|
+
const parsed = new URL(`http://${trimmed}`);
|
|
1092
|
+
const hostname = parsed.hostname.toLowerCase().replace(/\.$/, '');
|
|
1093
|
+
if (!hostname || parsed.username || parsed.password || parsed.pathname !== '/')
|
|
1094
|
+
return null;
|
|
1095
|
+
return { hostname, port: parsed.port };
|
|
1096
|
+
}
|
|
1097
|
+
catch {
|
|
1098
|
+
return null;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
function isLoopbackHostname(hostname) {
|
|
1102
|
+
const normalized = String(hostname || '').toLowerCase().replace(/^\[|\]$/g, '').replace(/\.$/, '');
|
|
1103
|
+
if (normalized === 'localhost')
|
|
1104
|
+
return true;
|
|
1105
|
+
if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1')
|
|
1106
|
+
return true;
|
|
1107
|
+
if (net.isIP(normalized) === 4)
|
|
1108
|
+
return normalized === '127.0.0.1' || normalized.startsWith('127.');
|
|
1109
|
+
return false;
|
|
1110
|
+
}
|
|
1111
|
+
function isLoopbackPeerAddress(address) {
|
|
1112
|
+
if (typeof address !== 'string')
|
|
1113
|
+
return false;
|
|
1114
|
+
const normalized = address.trim().toLowerCase().replace(/^\[|\]$/g, '');
|
|
1115
|
+
if (!normalized)
|
|
1116
|
+
return false;
|
|
1117
|
+
if (normalized.startsWith('::ffff:'))
|
|
1118
|
+
return isLoopbackPeerAddress(normalized.slice('::ffff:'.length));
|
|
1119
|
+
if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1')
|
|
1120
|
+
return true;
|
|
1121
|
+
if (net.isIP(normalized) === 4)
|
|
1122
|
+
return normalized === '127.0.0.1' || normalized.startsWith('127.');
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
function localOriginFromHeader(value) {
|
|
1126
|
+
if (typeof value !== 'string')
|
|
1127
|
+
return null;
|
|
1128
|
+
const trimmed = value.trim();
|
|
1129
|
+
if (!trimmed || trimmed === 'null' || trimmed.includes(','))
|
|
1130
|
+
return null;
|
|
1131
|
+
try {
|
|
1132
|
+
const parsed = new URL(trimmed);
|
|
1133
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
|
|
1134
|
+
return null;
|
|
1135
|
+
if (parsed.pathname !== '/' || parsed.search || parsed.hash || parsed.username || parsed.password)
|
|
1136
|
+
return null;
|
|
1137
|
+
if (!isLoopbackHostname(parsed.hostname))
|
|
1138
|
+
return null;
|
|
1139
|
+
return parsed.origin;
|
|
1140
|
+
}
|
|
1141
|
+
catch {
|
|
1142
|
+
return null;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
function validateLocalDaemonRequest(req) {
|
|
1146
|
+
if (!isLoopbackPeerAddress(req.socket?.remoteAddress)) {
|
|
1147
|
+
return {
|
|
1148
|
+
ok: false,
|
|
1149
|
+
message: 'request peer must be a loopback address',
|
|
1150
|
+
details: { peer: 'remoteAddress' },
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
const host = normalizeLocalAuthority(req.get('host'));
|
|
1154
|
+
if (!host || !isLoopbackHostname(host.hostname)) {
|
|
1155
|
+
return {
|
|
1156
|
+
ok: false,
|
|
1157
|
+
message: 'request host must be a loopback daemon address',
|
|
1158
|
+
details: { header: 'host' },
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
const originHeader = req.get('origin');
|
|
1162
|
+
if (originHeader !== undefined && !localOriginFromHeader(originHeader)) {
|
|
1163
|
+
return {
|
|
1164
|
+
ok: false,
|
|
1165
|
+
message: 'request origin must be a loopback daemon origin',
|
|
1166
|
+
details: { header: 'origin' },
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
return { ok: true, origin: localOriginFromHeader(originHeader) };
|
|
1170
|
+
}
|
|
1171
|
+
function requireLocalDaemonRequest(req, res, next) {
|
|
1172
|
+
const validation = validateLocalDaemonRequest(req);
|
|
1173
|
+
if (!validation.ok) {
|
|
1174
|
+
return sendApiError(res, 403, 'FORBIDDEN', validation.message, validation.details ? { details: validation.details } : {});
|
|
1175
|
+
}
|
|
1176
|
+
res.setHeader('Vary', 'Origin');
|
|
1177
|
+
if (validation.origin) {
|
|
1178
|
+
res.setHeader('Access-Control-Allow-Origin', validation.origin);
|
|
1179
|
+
}
|
|
1180
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
1181
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
1182
|
+
res.setHeader('Access-Control-Max-Age', '600');
|
|
1183
|
+
next();
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Render the small HTML page that the OAuth callback returns to the
|
|
1187
|
+
* user's browser tab. It posts a message back to the opener (the
|
|
1188
|
+
* Settings dialog window) and offers a manual close button. We keep
|
|
1189
|
+
* the markup pure HTML/CSS — no external scripts, no React — so the
|
|
1190
|
+
* page works even if the opener was closed and the user just sees a
|
|
1191
|
+
* static success/failure screen.
|
|
1192
|
+
*/
|
|
1193
|
+
function renderOAuthResultPage(opts) {
|
|
1194
|
+
const ok = Boolean(opts.ok);
|
|
1195
|
+
const title = ok ? 'Connected' : 'Authorization failed';
|
|
1196
|
+
const heading = ok ? '✅ Connected' : '⚠️ Authorization failed';
|
|
1197
|
+
const body = ok
|
|
1198
|
+
? `Your MCP server <code>${escapeHtml(opts.serverId ?? '')}</code> is now connected. You can close this tab and return to Open Design.`
|
|
1199
|
+
: escapeHtml(opts.message ?? 'Authorization could not be completed.');
|
|
1200
|
+
const accent = ok ? '#1a7f37' : '#cf222e';
|
|
1201
|
+
const payload = ok
|
|
1202
|
+
? { type: 'mcp-oauth', ok: true, serverId: opts.serverId ?? null }
|
|
1203
|
+
: { type: 'mcp-oauth', ok: false, message: opts.message ?? null };
|
|
1204
|
+
return `<!doctype html>
|
|
1205
|
+
<html lang="en">
|
|
1206
|
+
<head>
|
|
1207
|
+
<meta charset="utf-8" />
|
|
1208
|
+
<title>${escapeHtml(title)} — Open Design</title>
|
|
1209
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1210
|
+
<style>
|
|
1211
|
+
:root { color-scheme: light dark; }
|
|
1212
|
+
html, body { height: 100%; margin: 0; }
|
|
1213
|
+
body {
|
|
1214
|
+
display: flex; align-items: center; justify-content: center;
|
|
1215
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, sans-serif;
|
|
1216
|
+
background: #f6f7f9; color: #1f2328; padding: 24px;
|
|
1217
|
+
}
|
|
1218
|
+
@media (prefers-color-scheme: dark) {
|
|
1219
|
+
body { background: #0d1117; color: #e6edf3; }
|
|
1220
|
+
.card { background: #161b22; border-color: #30363d; }
|
|
1221
|
+
code { background: #1f242c; }
|
|
1222
|
+
}
|
|
1223
|
+
.card {
|
|
1224
|
+
max-width: 420px; width: 100%; padding: 28px 28px 22px; border-radius: 12px;
|
|
1225
|
+
background: white; border: 1px solid #d0d7de; box-shadow: 0 8px 24px rgba(0,0,0,.06);
|
|
1226
|
+
text-align: left;
|
|
1227
|
+
}
|
|
1228
|
+
h1 { margin: 0 0 8px; font-size: 18px; color: ${accent}; }
|
|
1229
|
+
p { margin: 0 0 16px; font-size: 14px; line-height: 1.55; }
|
|
1230
|
+
code { background: #f3f4f6; padding: 1px 6px; border-radius: 4px; font-size: 12.5px; }
|
|
1231
|
+
button {
|
|
1232
|
+
appearance: none; border: 1px solid #d0d7de; background: white;
|
|
1233
|
+
border-radius: 8px; padding: 8px 14px; font-size: 13px; cursor: pointer;
|
|
1234
|
+
}
|
|
1235
|
+
button:hover { background: #f6f8fa; }
|
|
1236
|
+
@media (prefers-color-scheme: dark) {
|
|
1237
|
+
button { background: #21262d; border-color: #30363d; color: #e6edf3; }
|
|
1238
|
+
button:hover { background: #30363d; }
|
|
1239
|
+
}
|
|
1240
|
+
</style>
|
|
1241
|
+
</head>
|
|
1242
|
+
<body>
|
|
1243
|
+
<div class="card">
|
|
1244
|
+
<h1>${escapeHtml(heading)}</h1>
|
|
1245
|
+
<p>${body}</p>
|
|
1246
|
+
<button type="button" onclick="window.close()">Close this tab</button>
|
|
1247
|
+
</div>
|
|
1248
|
+
<script>
|
|
1249
|
+
try {
|
|
1250
|
+
var payload = ${JSON.stringify(payload)};
|
|
1251
|
+
if (window.opener && !window.opener.closed) {
|
|
1252
|
+
window.opener.postMessage(payload, '*');
|
|
1253
|
+
}
|
|
1254
|
+
if (window.BroadcastChannel) {
|
|
1255
|
+
var bc = new BroadcastChannel('open-design-mcp-oauth');
|
|
1256
|
+
bc.postMessage(payload);
|
|
1257
|
+
bc.close();
|
|
1258
|
+
}
|
|
1259
|
+
} catch (e) { /* ignore postMessage failures */ }
|
|
1260
|
+
</script>
|
|
1261
|
+
</body>
|
|
1262
|
+
</html>`;
|
|
1263
|
+
}
|
|
1264
|
+
function escapeHtml(s) {
|
|
1265
|
+
return String(s ?? '')
|
|
1266
|
+
.replace(/&/g, '&')
|
|
1267
|
+
.replace(/</g, '<')
|
|
1268
|
+
.replace(/>/g, '>')
|
|
1269
|
+
.replace(/"/g, '"')
|
|
1270
|
+
.replace(/'/g, ''');
|
|
1271
|
+
}
|
|
1272
|
+
function setLiveArtifactPreviewHeaders(res) {
|
|
1273
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
1274
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
1275
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
1276
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
1277
|
+
res.setHeader('Content-Security-Policy', [
|
|
1278
|
+
"default-src 'none'",
|
|
1279
|
+
"base-uri 'none'",
|
|
1280
|
+
"script-src 'none'",
|
|
1281
|
+
"object-src 'none'",
|
|
1282
|
+
"connect-src 'none'",
|
|
1283
|
+
"form-action 'none'",
|
|
1284
|
+
"frame-ancestors 'self'",
|
|
1285
|
+
"img-src 'self' data: blob:",
|
|
1286
|
+
"font-src 'self' data:",
|
|
1287
|
+
"style-src 'unsafe-inline'",
|
|
1288
|
+
'sandbox allow-same-origin',
|
|
1289
|
+
].join('; '));
|
|
1290
|
+
}
|
|
1291
|
+
function setLiveArtifactCodeHeaders(res) {
|
|
1292
|
+
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
1293
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
1294
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
1295
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
1296
|
+
}
|
|
1297
|
+
function bearerTokenFromRequest(req) {
|
|
1298
|
+
const header = req.get('authorization');
|
|
1299
|
+
if (typeof header !== 'string')
|
|
1300
|
+
return undefined;
|
|
1301
|
+
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
1302
|
+
return match?.[1];
|
|
1303
|
+
}
|
|
1304
|
+
function authorizeToolRequest(req, res, operation) {
|
|
1305
|
+
const endpoint = req.path;
|
|
1306
|
+
const validation = toolTokenRegistry.validate(bearerTokenFromRequest(req), { endpoint, operation });
|
|
1307
|
+
if (!validation.ok) {
|
|
1308
|
+
const status = validation.code === 'TOOL_ENDPOINT_DENIED' || validation.code === 'TOOL_OPERATION_DENIED' ? 403 : 401;
|
|
1309
|
+
sendApiError(res, status, validation.code, validation.message, {
|
|
1310
|
+
details: { endpoint, operation },
|
|
1311
|
+
});
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
return validation.grant;
|
|
1315
|
+
}
|
|
1316
|
+
function requestProjectOverride(projectId, tokenProjectId) {
|
|
1317
|
+
return typeof projectId === 'string' && projectId.length > 0 && projectId !== tokenProjectId;
|
|
1318
|
+
}
|
|
1319
|
+
function requestRunOverride(runId, tokenRunId) {
|
|
1320
|
+
return typeof runId === 'string' && runId.length > 0 && runId !== tokenRunId;
|
|
1321
|
+
}
|
|
1322
|
+
function openNativeFolderDialog() {
|
|
1323
|
+
return new Promise((resolve) => {
|
|
1324
|
+
const platform = process.platform;
|
|
1325
|
+
if (platform === 'darwin') {
|
|
1326
|
+
execFile('osascript', ['-e', 'POSIX path of (choose folder with prompt "Select a code folder to link")'], { timeout: 120_000 }, (err, stdout) => {
|
|
1327
|
+
if (err)
|
|
1328
|
+
return resolve(null);
|
|
1329
|
+
const p = stdout.trim().replace(/\/$/, '');
|
|
1330
|
+
resolve(p || null);
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
else if (platform === 'linux') {
|
|
1334
|
+
execFile('zenity', ['--file-selection', '--directory', '--title=Select a code folder to link'], { timeout: 120_000 }, (err, stdout) => {
|
|
1335
|
+
if (err)
|
|
1336
|
+
return resolve(null);
|
|
1337
|
+
const p = stdout.trim();
|
|
1338
|
+
resolve(p || null);
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
else if (platform === 'win32') {
|
|
1342
|
+
const command = buildWindowsFolderDialogCommand();
|
|
1343
|
+
execFile(command.command, command.args, { timeout: 120_000 }, (err, stdout) => {
|
|
1344
|
+
resolve(parseFolderDialogStdout(err, stdout));
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
else {
|
|
1348
|
+
resolve(null);
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* @param {ApiErrorCode} code
|
|
1354
|
+
* @param {string} message
|
|
1355
|
+
* @param {Omit<ApiError, 'code' | 'message'>} [init]
|
|
1356
|
+
*/
|
|
1357
|
+
function createSseErrorPayload(code, message, init = {}) {
|
|
1358
|
+
return { message, error: createCompatApiError(code, message, init) };
|
|
1359
|
+
}
|
|
1360
|
+
const UPLOAD_DIR = path.join(os.tmpdir(), 'od-uploads');
|
|
1361
|
+
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
|
|
1362
|
+
fs.mkdirSync(ARTIFACTS_DIR, { recursive: true });
|
|
1363
|
+
const upload = multer({
|
|
1364
|
+
storage: multer.diskStorage({
|
|
1365
|
+
destination: UPLOAD_DIR,
|
|
1366
|
+
filename: (_req, file, cb) => {
|
|
1367
|
+
file.originalname = decodeMultipartFilename(file.originalname);
|
|
1368
|
+
const safe = sanitizeName(file.originalname);
|
|
1369
|
+
cb(null, `${Date.now()}-${Math.random().toString(36).slice(2, 8)}-${safe}`);
|
|
1370
|
+
},
|
|
1371
|
+
}),
|
|
1372
|
+
limits: { fileSize: 20 * 1024 * 1024 },
|
|
1373
|
+
});
|
|
1374
|
+
const importUpload = multer({
|
|
1375
|
+
storage: multer.diskStorage({
|
|
1376
|
+
destination: UPLOAD_DIR,
|
|
1377
|
+
filename: (_req, file, cb) => {
|
|
1378
|
+
file.originalname = decodeMultipartFilename(file.originalname);
|
|
1379
|
+
const safe = sanitizeName(file.originalname);
|
|
1380
|
+
cb(null, `${Date.now()}-${Math.random().toString(36).slice(2, 8)}-${safe}`);
|
|
1381
|
+
},
|
|
1382
|
+
}),
|
|
1383
|
+
limits: { fileSize: 100 * 1024 * 1024 },
|
|
1384
|
+
});
|
|
1385
|
+
// Project-scoped multi-file upload. Lands files directly in the project
|
|
1386
|
+
// folder (flat — same shape FileWorkspace expects), so the composer's
|
|
1387
|
+
// pasted/dropped/picked images become referenceable filenames the agent
|
|
1388
|
+
// can Read or @-mention without any cross-folder gymnastics.
|
|
1389
|
+
// Bridge between the multer upload-storage destination (built at module
|
|
1390
|
+
// init) and the per-process project DB (instantiated inside startServer).
|
|
1391
|
+
// startServer() sets this so the upload destination can route attachments
|
|
1392
|
+
// into the right project root, including folder-imported projects whose
|
|
1393
|
+
// files live under metadata.baseDir.
|
|
1394
|
+
let projectMetadataLookup = null;
|
|
1395
|
+
const projectUpload = multer({
|
|
1396
|
+
storage: multer.diskStorage({
|
|
1397
|
+
destination: async (req, _file, cb) => {
|
|
1398
|
+
try {
|
|
1399
|
+
// Route uploads into the project's actual root: for folder-imported
|
|
1400
|
+
// projects (metadata.baseDir set) attachments need to land alongside
|
|
1401
|
+
// the user's files so the agent can read them via the same path
|
|
1402
|
+
// it sees. projectMetadataLookup is populated at startServer() boot
|
|
1403
|
+
// and keyed by project id; null fallback gives the standard
|
|
1404
|
+
// .od/projects/<id>/ behavior for non-imported projects.
|
|
1405
|
+
const meta = projectMetadataLookup?.(req.params.id) ?? null;
|
|
1406
|
+
const dir = await ensureProject(PROJECTS_DIR, req.params.id, meta);
|
|
1407
|
+
cb(null, dir);
|
|
1408
|
+
}
|
|
1409
|
+
catch (err) {
|
|
1410
|
+
cb(err, '');
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
filename: (_req, file, cb) => {
|
|
1414
|
+
// multer@1 hands us latin1-decoded multipart filenames; restore the
|
|
1415
|
+
// original UTF-8 so the response (and the on-disk name) preserves
|
|
1416
|
+
// non-ASCII characters instead of mangling them. Then run the
|
|
1417
|
+
// shared sanitiser and prepend a base36 timestamp so multiple
|
|
1418
|
+
// uploads with the same original name don't clobber each other.
|
|
1419
|
+
file.originalname = decodeMultipartFilename(file.originalname);
|
|
1420
|
+
const safe = sanitizeName(file.originalname);
|
|
1421
|
+
cb(null, `${Date.now().toString(36)}-${safe}`);
|
|
1422
|
+
},
|
|
1423
|
+
}),
|
|
1424
|
+
limits: { fileSize: 200 * 1024 * 1024 }, // 200MB — covers the largest design assets we expect (PPTX/PDF/raw images)
|
|
1425
|
+
});
|
|
1426
|
+
function handleProjectUpload(req, res, next) {
|
|
1427
|
+
projectUpload.array('files', 12)(req, res, (err) => {
|
|
1428
|
+
if (err) {
|
|
1429
|
+
return sendMulterError(res, err);
|
|
1430
|
+
}
|
|
1431
|
+
next();
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
function sendMulterError(res, err) {
|
|
1435
|
+
if (err instanceof multer.MulterError) {
|
|
1436
|
+
const code = err.code || 'UPLOAD_ERROR';
|
|
1437
|
+
const statusByCode = {
|
|
1438
|
+
LIMIT_FILE_SIZE: 413,
|
|
1439
|
+
LIMIT_FILE_COUNT: 400,
|
|
1440
|
+
LIMIT_UNEXPECTED_FILE: 400,
|
|
1441
|
+
LIMIT_PART_COUNT: 400,
|
|
1442
|
+
LIMIT_FIELD_KEY: 400,
|
|
1443
|
+
LIMIT_FIELD_VALUE: 400,
|
|
1444
|
+
LIMIT_FIELD_COUNT: 400,
|
|
1445
|
+
MISSING_FIELD_NAME: 400,
|
|
1446
|
+
};
|
|
1447
|
+
const errorByCode = {
|
|
1448
|
+
LIMIT_FILE_SIZE: 'file too large',
|
|
1449
|
+
LIMIT_FILE_COUNT: 'too many files',
|
|
1450
|
+
LIMIT_UNEXPECTED_FILE: 'unexpected file field',
|
|
1451
|
+
LIMIT_PART_COUNT: 'too many form parts',
|
|
1452
|
+
LIMIT_FIELD_KEY: 'field name too long',
|
|
1453
|
+
LIMIT_FIELD_VALUE: 'field value too long',
|
|
1454
|
+
LIMIT_FIELD_COUNT: 'too many form fields',
|
|
1455
|
+
MISSING_FIELD_NAME: 'missing field name',
|
|
1456
|
+
};
|
|
1457
|
+
const status = statusByCode[code] ?? 400;
|
|
1458
|
+
const message = errorByCode[code] ?? 'upload failed';
|
|
1459
|
+
return sendApiError(res, status, code === 'LIMIT_FILE_SIZE' ? 'PAYLOAD_TOO_LARGE' : 'BAD_REQUEST', message, { details: { legacyCode: code } });
|
|
1460
|
+
}
|
|
1461
|
+
if (err) {
|
|
1462
|
+
return sendApiError(res, 500, 'INTERNAL_ERROR', 'upload failed');
|
|
1463
|
+
}
|
|
1464
|
+
return sendApiError(res, 500, 'INTERNAL_ERROR', 'upload failed');
|
|
1465
|
+
}
|
|
1466
|
+
const mediaTasks = new Map();
|
|
1467
|
+
const TASK_TTL_AFTER_DONE_MS = 10 * 60 * 1000;
|
|
1468
|
+
const MEDIA_TERMINAL_STATUSES = new Set(['done', 'failed', 'interrupted']);
|
|
1469
|
+
function hydrateMediaTask(row) {
|
|
1470
|
+
const task = {
|
|
1471
|
+
id: row.id,
|
|
1472
|
+
projectId: row.projectId,
|
|
1473
|
+
status: row.status,
|
|
1474
|
+
surface: row.surface,
|
|
1475
|
+
model: row.model,
|
|
1476
|
+
progress: Array.isArray(row.progress) ? row.progress.slice() : [],
|
|
1477
|
+
file: row.file ?? null,
|
|
1478
|
+
error: row.error ?? null,
|
|
1479
|
+
startedAt: row.startedAt,
|
|
1480
|
+
endedAt: row.endedAt,
|
|
1481
|
+
waiters: new Set(),
|
|
1482
|
+
};
|
|
1483
|
+
mediaTasks.set(task.id, task);
|
|
1484
|
+
return task;
|
|
1485
|
+
}
|
|
1486
|
+
function getLiveMediaTask(db, taskId) {
|
|
1487
|
+
const cached = mediaTasks.get(taskId);
|
|
1488
|
+
if (cached)
|
|
1489
|
+
return cached;
|
|
1490
|
+
const row = getMediaTask(db, taskId);
|
|
1491
|
+
return row ? hydrateMediaTask(row) : null;
|
|
1492
|
+
}
|
|
1493
|
+
function createMediaTask(db, taskId, projectId, info = {}) {
|
|
1494
|
+
const task = {
|
|
1495
|
+
id: taskId,
|
|
1496
|
+
projectId,
|
|
1497
|
+
status: 'queued',
|
|
1498
|
+
surface: info.surface,
|
|
1499
|
+
model: info.model,
|
|
1500
|
+
progress: [],
|
|
1501
|
+
file: null,
|
|
1502
|
+
error: null,
|
|
1503
|
+
startedAt: Date.now(),
|
|
1504
|
+
endedAt: null,
|
|
1505
|
+
waiters: new Set(),
|
|
1506
|
+
};
|
|
1507
|
+
mediaTasks.set(taskId, task);
|
|
1508
|
+
insertMediaTask(db, {
|
|
1509
|
+
id: taskId,
|
|
1510
|
+
projectId,
|
|
1511
|
+
status: task.status,
|
|
1512
|
+
surface: task.surface,
|
|
1513
|
+
model: task.model,
|
|
1514
|
+
progress: task.progress,
|
|
1515
|
+
file: task.file,
|
|
1516
|
+
error: task.error,
|
|
1517
|
+
startedAt: task.startedAt,
|
|
1518
|
+
endedAt: task.endedAt,
|
|
1519
|
+
});
|
|
1520
|
+
return task;
|
|
1521
|
+
}
|
|
1522
|
+
function persistMediaTask(db, task) {
|
|
1523
|
+
updateMediaTask(db, task.id, {
|
|
1524
|
+
status: task.status,
|
|
1525
|
+
surface: task.surface,
|
|
1526
|
+
model: task.model,
|
|
1527
|
+
progress: task.progress,
|
|
1528
|
+
file: task.file,
|
|
1529
|
+
error: task.error,
|
|
1530
|
+
startedAt: task.startedAt,
|
|
1531
|
+
endedAt: task.endedAt,
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
function appendTaskProgress(db, task, line) {
|
|
1535
|
+
task.progress.push(line);
|
|
1536
|
+
persistMediaTask(db, task);
|
|
1537
|
+
notifyTaskWaiters(db, task);
|
|
1538
|
+
}
|
|
1539
|
+
function notifyTaskWaiters(db, task) {
|
|
1540
|
+
const wakers = Array.from(task.waiters);
|
|
1541
|
+
for (const w of wakers) {
|
|
1542
|
+
try {
|
|
1543
|
+
w();
|
|
1544
|
+
}
|
|
1545
|
+
catch {
|
|
1546
|
+
// Never let one bad waiter block the rest.
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
if (MEDIA_TERMINAL_STATUSES.has(task.status) &&
|
|
1550
|
+
!task._gcScheduled) {
|
|
1551
|
+
task._gcScheduled = true;
|
|
1552
|
+
setTimeout(() => {
|
|
1553
|
+
if (task.waiters.size === 0) {
|
|
1554
|
+
mediaTasks.delete(task.id);
|
|
1555
|
+
deleteMediaTask(db, task.id);
|
|
1556
|
+
}
|
|
1557
|
+
}, TASK_TTL_AFTER_DONE_MS).unref?.();
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
function mediaTaskSnapshot(task, since = 0) {
|
|
1561
|
+
const snapshot = {
|
|
1562
|
+
taskId: task.id,
|
|
1563
|
+
status: task.status,
|
|
1564
|
+
startedAt: task.startedAt,
|
|
1565
|
+
endedAt: task.endedAt,
|
|
1566
|
+
progress: task.progress.slice(since),
|
|
1567
|
+
nextSince: task.progress.length,
|
|
1568
|
+
};
|
|
1569
|
+
if (task.status === 'done')
|
|
1570
|
+
snapshot.file = task.file;
|
|
1571
|
+
if (task.status === 'failed' || task.status === 'interrupted') {
|
|
1572
|
+
snapshot.error = task.error;
|
|
1573
|
+
}
|
|
1574
|
+
return snapshot;
|
|
1575
|
+
}
|
|
1576
|
+
export function createSseResponse(res, { keepAliveIntervalMs = SSE_KEEPALIVE_INTERVAL_MS } = {}) {
|
|
1577
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
1578
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
1579
|
+
res.setHeader('Connection', 'keep-alive');
|
|
1580
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
1581
|
+
res.flushHeaders?.();
|
|
1582
|
+
const canWrite = () => !res.destroyed && !res.writableEnded;
|
|
1583
|
+
const writeKeepAlive = () => {
|
|
1584
|
+
if (canWrite()) {
|
|
1585
|
+
res.write(': keepalive\n\n');
|
|
1586
|
+
return true;
|
|
1587
|
+
}
|
|
1588
|
+
return false;
|
|
1589
|
+
};
|
|
1590
|
+
let heartbeat = null;
|
|
1591
|
+
if (keepAliveIntervalMs > 0) {
|
|
1592
|
+
heartbeat = setInterval(writeKeepAlive, keepAliveIntervalMs);
|
|
1593
|
+
heartbeat.unref?.();
|
|
1594
|
+
}
|
|
1595
|
+
const cleanup = () => {
|
|
1596
|
+
if (heartbeat) {
|
|
1597
|
+
clearInterval(heartbeat);
|
|
1598
|
+
heartbeat = null;
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
res.on('close', cleanup);
|
|
1602
|
+
res.on('finish', cleanup);
|
|
1603
|
+
return {
|
|
1604
|
+
/** @param {ChatSseEvent['event'] | ProxySseEvent['event'] | string} event */
|
|
1605
|
+
send(event, data, id = null) {
|
|
1606
|
+
if (!canWrite())
|
|
1607
|
+
return false;
|
|
1608
|
+
// Assemble the full SSE event into a single write so id/event/data land
|
|
1609
|
+
// in one TCP chunk. Three separate writes would let `event: <type>` flush
|
|
1610
|
+
// ahead of the `data:` payload, which produces partial events for
|
|
1611
|
+
// consumers that read chunk-by-chunk (e.g. tests using a Response body
|
|
1612
|
+
// reader with a substring marker).
|
|
1613
|
+
const idLine = id !== null && id !== undefined ? `id: ${id}\n` : '';
|
|
1614
|
+
res.write(`${idLine}event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
1615
|
+
return true;
|
|
1616
|
+
},
|
|
1617
|
+
writeKeepAlive,
|
|
1618
|
+
cleanup,
|
|
1619
|
+
end() {
|
|
1620
|
+
cleanup();
|
|
1621
|
+
if (canWrite()) {
|
|
1622
|
+
res.end();
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
const DEFAULT_CHAT_RUN_INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000;
|
|
1628
|
+
const MAX_CHAT_RUN_INACTIVITY_TIMEOUT_MS = 24 * 60 * 60 * 1000;
|
|
1629
|
+
function resolveChatRunInactivityTimeoutMs() {
|
|
1630
|
+
const raw = Number(process.env.OD_CHAT_RUN_INACTIVITY_TIMEOUT_MS);
|
|
1631
|
+
// This watchdog observes child stdout/stderr/SSE activity, not real CPU or
|
|
1632
|
+
// filesystem progress. Keep the default long enough for agents that spend
|
|
1633
|
+
// several minutes silently writing large artifacts.
|
|
1634
|
+
if (!Number.isFinite(raw))
|
|
1635
|
+
return DEFAULT_CHAT_RUN_INACTIVITY_TIMEOUT_MS;
|
|
1636
|
+
// Node clamps delays larger than a signed 32-bit integer down to 1ms, which
|
|
1637
|
+
// makes an oversized override fail almost immediately while reporting a huge
|
|
1638
|
+
// timeout. Keep explicit overrides bounded to a practical, timer-safe value.
|
|
1639
|
+
return Math.min(MAX_CHAT_RUN_INACTIVITY_TIMEOUT_MS, Math.max(0, Math.floor(raw)));
|
|
1640
|
+
}
|
|
1641
|
+
function resolveChatRunShutdownGraceMs() {
|
|
1642
|
+
const raw = Number(process.env.OD_CHAT_RUN_SHUTDOWN_GRACE_MS);
|
|
1643
|
+
if (!Number.isFinite(raw))
|
|
1644
|
+
return 3_000;
|
|
1645
|
+
return Math.max(0, Math.floor(raw));
|
|
1646
|
+
}
|
|
1647
|
+
function resolveAcpStageTimeoutMs() {
|
|
1648
|
+
// Per-stage silence watchdog for ACP chat sessions. Defaults are owned by
|
|
1649
|
+
// `attachAcpSession` in acp.ts; this resolver only applies when an operator
|
|
1650
|
+
// sets `OD_ACP_STAGE_TIMEOUT_MS`. Bounded to the same 24h ceiling as the
|
|
1651
|
+
// outer chat inactivity watchdog so an oversized override doesn't get
|
|
1652
|
+
// clamped to 1ms by Node's signed-32-bit delay limit.
|
|
1653
|
+
const raw = Number(process.env.OD_ACP_STAGE_TIMEOUT_MS);
|
|
1654
|
+
if (!Number.isFinite(raw))
|
|
1655
|
+
return undefined;
|
|
1656
|
+
return Math.min(MAX_CHAT_RUN_INACTIVITY_TIMEOUT_MS, Math.max(0, Math.floor(raw)));
|
|
1657
|
+
}
|
|
1658
|
+
export async function startServer({ port = 7456, host = process.env.OD_BIND_HOST || '127.0.0.1', returnServer = false, desktopPdfExporter = null, } = {}) {
|
|
1659
|
+
let resolvedPort = port;
|
|
1660
|
+
let daemonShuttingDown = false;
|
|
1661
|
+
const extraAllowedOrigins = configuredAllowedOrigins();
|
|
1662
|
+
const app = express();
|
|
1663
|
+
app.use(express.json({ limit: '4mb' }));
|
|
1664
|
+
// Multi-directory scanning shared by every skill / template surface. The
|
|
1665
|
+
// helpers delegate to listSkills(roots) which walks roots in priority
|
|
1666
|
+
// order, tags each entry with the SkillSource ('user' for the user
|
|
1667
|
+
// root, 'built-in' for the bundled root) the contracts package
|
|
1668
|
+
// declares, and lets a user-imported entry shadow a built-in one of
|
|
1669
|
+
// the same id without erasing the built-in copy.
|
|
1670
|
+
async function listAllSkills() {
|
|
1671
|
+
return listSkills(SKILL_ROOTS);
|
|
1672
|
+
}
|
|
1673
|
+
async function listAllDesignTemplates() {
|
|
1674
|
+
return listSkills(DESIGN_TEMPLATE_ROOTS);
|
|
1675
|
+
}
|
|
1676
|
+
// Spans both roots so chat run system-prompt composition and the orbit
|
|
1677
|
+
// template resolver can resolve a stored project.skillId regardless of
|
|
1678
|
+
// which surface created the project after the skills/design-templates
|
|
1679
|
+
// split. Keep in sync with SKILL_ROOTS + DESIGN_TEMPLATE_ROOTS above.
|
|
1680
|
+
async function listAllSkillLikeEntries() {
|
|
1681
|
+
return listSkills(ALL_SKILL_LIKE_ROOTS);
|
|
1682
|
+
}
|
|
1683
|
+
async function listAllDesignSystems() {
|
|
1684
|
+
const builtIn = (await listDesignSystems(DESIGN_SYSTEMS_DIR)).map((s) => ({
|
|
1685
|
+
...s,
|
|
1686
|
+
source: 'built-in',
|
|
1687
|
+
}));
|
|
1688
|
+
let installed = [];
|
|
1689
|
+
try {
|
|
1690
|
+
installed = (await listDesignSystems(USER_DESIGN_SYSTEMS_DIR)).map((s) => ({ ...s, source: 'installed' }));
|
|
1691
|
+
}
|
|
1692
|
+
catch {
|
|
1693
|
+
// User directory may not exist yet or be unreadable.
|
|
1694
|
+
}
|
|
1695
|
+
const seen = new Set(builtIn.map((s) => s.id));
|
|
1696
|
+
return [...builtIn, ...installed.filter((s) => !seen.has(s.id))];
|
|
1697
|
+
}
|
|
1698
|
+
// Chrome may strip the port from the Origin header on same-origin GET
|
|
1699
|
+
// requests. Only use this as a fallback for safe, idempotent GET requests;
|
|
1700
|
+
// mutating routes always require an exact origin/host match.
|
|
1701
|
+
function isPortlessLoopbackOrigin(origin) {
|
|
1702
|
+
return /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])$/.test(origin);
|
|
1703
|
+
}
|
|
1704
|
+
// Routes that serve content to sandboxed iframes (Origin: null) for
|
|
1705
|
+
// read-only purposes. All other /api routes reject Origin: null.
|
|
1706
|
+
const _NULL_ORIGIN_SAFE_GET_RE = /^\/projects\/[^/]+\/raw\/|^\/codex-pets\/[^/]+\/spritesheet$/;
|
|
1707
|
+
// Reject cross-origin requests to API endpoints.
|
|
1708
|
+
// Health/version remain open for monitoring probes.
|
|
1709
|
+
// Non-browser clients (no Origin header) are always allowed.
|
|
1710
|
+
app.use('/api', (req, res, next) => {
|
|
1711
|
+
// Live artifact previews have stricter local-daemon validation and
|
|
1712
|
+
// loopback CORS handling on the route itself. Let that middleware produce
|
|
1713
|
+
// the structured error shape and preflight headers for preview embeds.
|
|
1714
|
+
if (/^\/live-artifacts\/[^/]+\/preview$/.test(req.path))
|
|
1715
|
+
return next();
|
|
1716
|
+
const origin = req.headers.origin;
|
|
1717
|
+
// Non-browser client → allow.
|
|
1718
|
+
if (origin == null || origin === '')
|
|
1719
|
+
return next();
|
|
1720
|
+
// Origin: null (sandboxed iframes). Only allowed for safe, read-only
|
|
1721
|
+
// routes that set their own CORS headers for canvas drawing.
|
|
1722
|
+
if (origin === 'null') {
|
|
1723
|
+
const isSafeReadOnly = req.method === 'GET' && _NULL_ORIGIN_SAFE_GET_RE.test(req.path);
|
|
1724
|
+
if (!isSafeReadOnly) {
|
|
1725
|
+
return res.status(403).json({ error: 'Origin: null not allowed for this route' });
|
|
1726
|
+
}
|
|
1727
|
+
return next();
|
|
1728
|
+
}
|
|
1729
|
+
// Fail-closed: block all browser origins until port is resolved.
|
|
1730
|
+
if (!resolvedPort) {
|
|
1731
|
+
return res.status(403).json({ error: 'Server initializing' });
|
|
1732
|
+
}
|
|
1733
|
+
const ports = allowedBrowserPorts(resolvedPort);
|
|
1734
|
+
if (!isAllowedBrowserOrigin(origin, req.headers.host, ports, host, extraAllowedOrigins)) {
|
|
1735
|
+
if (req.method !== 'GET' || !isPortlessLoopbackOrigin(String(origin))) {
|
|
1736
|
+
return res.status(403).json({ error: 'Cross-origin requests are not allowed' });
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
next();
|
|
1740
|
+
});
|
|
1741
|
+
const db = openDatabase(PROJECT_ROOT, { dataDir: RUNTIME_DATA_DIR });
|
|
1742
|
+
// Wire the upload-destination bridge to this db so multer can route
|
|
1743
|
+
// file uploads into baseDir-rooted projects' actual folders.
|
|
1744
|
+
projectMetadataLookup = (id) => {
|
|
1745
|
+
try {
|
|
1746
|
+
return getProject(db, id)?.metadata ?? null;
|
|
1747
|
+
}
|
|
1748
|
+
catch {
|
|
1749
|
+
return null;
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
configureConnectorCredentialStore(new FileConnectorCredentialStore(RUNTIME_DATA_DIR));
|
|
1753
|
+
configureComposioConfigStore(RUNTIME_DATA_DIR);
|
|
1754
|
+
composioConnectorProvider.configureCatalogCache(RUNTIME_DATA_DIR);
|
|
1755
|
+
composioConnectorProvider.startCatalogRefreshLoop();
|
|
1756
|
+
// RoutineService persistence is a thin adapter over the SQLite helpers.
|
|
1757
|
+
// Routines are stored as DB rows; the service holds in-memory timers and
|
|
1758
|
+
// delegates "list me everything" / "record a run" back to SQLite.
|
|
1759
|
+
routineService = new RoutineService({
|
|
1760
|
+
list: () => listRoutines(db).map((row) => routineDbRowToContract(row, null)),
|
|
1761
|
+
insertRun: (run) => {
|
|
1762
|
+
insertRoutineRun(db, {
|
|
1763
|
+
id: run.id,
|
|
1764
|
+
routineId: run.routineId,
|
|
1765
|
+
trigger: run.trigger,
|
|
1766
|
+
status: run.status,
|
|
1767
|
+
projectId: run.projectId,
|
|
1768
|
+
conversationId: run.conversationId,
|
|
1769
|
+
agentRunId: run.agentRunId,
|
|
1770
|
+
startedAt: run.startedAt,
|
|
1771
|
+
completedAt: run.completedAt,
|
|
1772
|
+
summary: run.summary,
|
|
1773
|
+
error: run.error,
|
|
1774
|
+
});
|
|
1775
|
+
},
|
|
1776
|
+
updateRun: (id, patch) => {
|
|
1777
|
+
updateRoutineRun(db, id, patch);
|
|
1778
|
+
},
|
|
1779
|
+
getLatestRun: (routineId) => getLatestRoutineRun(db, routineId),
|
|
1780
|
+
});
|
|
1781
|
+
let daemonUrl = `http://127.0.0.1:${port}`;
|
|
1782
|
+
// Boot reconcile: any critique_runs row left in 'running' state by a prior
|
|
1783
|
+
// daemon crash gets flipped to 'interrupted' with rounds_json.recoveryReason
|
|
1784
|
+
// = 'daemon_restart' so the spec's daemon-restart-mid-run failure mode is
|
|
1785
|
+
// honored on every boot. staleAfterMs comes from CritiqueConfig, not a
|
|
1786
|
+
// hardcoded constant.
|
|
1787
|
+
const reconciledStaleRuns = reconcileStaleRuns(db, { staleAfterMs: critiqueCfg.totalTimeoutMs });
|
|
1788
|
+
if (reconciledStaleRuns > 0) {
|
|
1789
|
+
console.warn(`[critique] reconcileStaleRuns flipped ${reconciledStaleRuns} stale running row(s) to interrupted`);
|
|
1790
|
+
}
|
|
1791
|
+
const mediaReconcile = reconcileMediaTasksOnBoot(db, {
|
|
1792
|
+
terminalTtlMs: TASK_TTL_AFTER_DONE_MS,
|
|
1793
|
+
});
|
|
1794
|
+
if (mediaReconcile.interrupted > 0 || mediaReconcile.deleted > 0) {
|
|
1795
|
+
console.warn(`[media] reconcileMediaTasksOnBoot interrupted ${mediaReconcile.interrupted} task(s), ` +
|
|
1796
|
+
`deleted ${mediaReconcile.deleted} expired terminal task(s)`);
|
|
1797
|
+
}
|
|
1798
|
+
mediaTasks.clear();
|
|
1799
|
+
for (const row of listRecentMediaTasks(db, { terminalTtlMs: TASK_TTL_AFTER_DONE_MS })) {
|
|
1800
|
+
hydrateMediaTask(row);
|
|
1801
|
+
}
|
|
1802
|
+
if (process.env.OD_CODEX_DISABLE_PLUGINS === '1') {
|
|
1803
|
+
console.log('[od] Codex plugins disabled via OD_CODEX_DISABLE_PLUGINS=1');
|
|
1804
|
+
}
|
|
1805
|
+
// Warm agent-capability probes (e.g. whether the installed Claude Code
|
|
1806
|
+
// build advertises --include-partial-messages) so the first /api/chat
|
|
1807
|
+
// hits a populated cache even if /api/agents hasn't been called yet.
|
|
1808
|
+
void readAppConfig(RUNTIME_DATA_DIR)
|
|
1809
|
+
.then((config) => {
|
|
1810
|
+
orbitService.configure(config.orbit);
|
|
1811
|
+
return detectAgents(config.agentCliEnv ?? {});
|
|
1812
|
+
})
|
|
1813
|
+
.catch(() => detectAgents().catch(() => { }));
|
|
1814
|
+
await recoverStaleLiveArtifactRefreshes({ projectsRoot: PROJECTS_DIR }).catch((error) => {
|
|
1815
|
+
console.warn('[od] Failed to recover stale live artifact refreshes:', error);
|
|
1816
|
+
});
|
|
1817
|
+
if (fs.existsSync(STATIC_DIR)) {
|
|
1818
|
+
app.use(express.static(STATIC_DIR));
|
|
1819
|
+
}
|
|
1820
|
+
app.get('/api/health', async (_req, res) => {
|
|
1821
|
+
const versionInfo = await readCurrentAppVersionInfo();
|
|
1822
|
+
res.json({ ok: true, version: versionInfo.version });
|
|
1823
|
+
});
|
|
1824
|
+
app.get('/api/version', async (_req, res) => {
|
|
1825
|
+
const version = await readCurrentAppVersionInfo();
|
|
1826
|
+
res.json({ version });
|
|
1827
|
+
});
|
|
1828
|
+
// Prometheus scrape endpoint (Phase 12). Returns the full exposition
|
|
1829
|
+
// format string. Operators put this behind their existing auth proxy;
|
|
1830
|
+
// there is no built-in authn on the daemon HTTP server. To disable
|
|
1831
|
+
// the endpoint entirely (air-gapped installs, regulatory contexts),
|
|
1832
|
+
// set `OD_METRICS_ENDPOINT=disabled`; the route is registered only
|
|
1833
|
+
// when that env value is not the literal string 'disabled'.
|
|
1834
|
+
if (process.env.OD_METRICS_ENDPOINT !== 'disabled') {
|
|
1835
|
+
app.get('/api/metrics', async (_req, res) => {
|
|
1836
|
+
res.setHeader('Content-Type', register.contentType);
|
|
1837
|
+
res.send(await getCritiqueMetrics());
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
// Phase 16 ratchet endpoint. Returns the rolling conformance window
|
|
1841
|
+
// and the ratchet's current recommendation. Operator-driven by
|
|
1842
|
+
// design: the recommendation does not flip OD_CRITIQUE_ROLLOUT_PHASE
|
|
1843
|
+
// automatically, it surfaces so a deploy-pipeline follow-up can
|
|
1844
|
+
// consume it. Tunables come from query string; defaults are the
|
|
1845
|
+
// spec values (14 days, 0.90 shipped, 0.95 clean-parse).
|
|
1846
|
+
// Codex + lefarcen P1 on PR #1499: clamp query inputs before the
|
|
1847
|
+
// evaluator sees them so a request like `?windowDays=0` falls back to
|
|
1848
|
+
// the spec default rather than producing a zero-evidence promotion.
|
|
1849
|
+
// The evaluator also defends at its own entry; both are intentional
|
|
1850
|
+
// (belt + suspenders) so a future caller that bypasses this route
|
|
1851
|
+
// cannot reach an unguarded code path either.
|
|
1852
|
+
const parsePositiveInt = (raw, fallback) => {
|
|
1853
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
1854
|
+
return fallback;
|
|
1855
|
+
const n = Number(raw);
|
|
1856
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
|
|
1857
|
+
};
|
|
1858
|
+
const parseRate = (raw, fallback) => {
|
|
1859
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
1860
|
+
return fallback;
|
|
1861
|
+
const n = Number(raw);
|
|
1862
|
+
return Number.isFinite(n) && n >= 0 && n <= 1 ? n : fallback;
|
|
1863
|
+
};
|
|
1864
|
+
app.get('/api/critique/conformance', async (req, res) => {
|
|
1865
|
+
try {
|
|
1866
|
+
const windowDays = parsePositiveInt(req.query.windowDays, 14);
|
|
1867
|
+
const shippedThreshold = parseRate(req.query.shippedThreshold, 0.90);
|
|
1868
|
+
const cleanParseThreshold = parseRate(req.query.cleanParseThreshold, 0.95);
|
|
1869
|
+
const history = await readConformanceHistory(RUNTIME_DATA_DIR, windowDays);
|
|
1870
|
+
const decision = evaluateRollout({
|
|
1871
|
+
current: parseRolloutPhase(process.env.OD_CRITIQUE_ROLLOUT_PHASE),
|
|
1872
|
+
history,
|
|
1873
|
+
windowDays,
|
|
1874
|
+
shippedThreshold,
|
|
1875
|
+
cleanParseThreshold,
|
|
1876
|
+
});
|
|
1877
|
+
res.json({ window: { days: windowDays, history }, decision });
|
|
1878
|
+
}
|
|
1879
|
+
catch (err) {
|
|
1880
|
+
sendApiError(res, 500, 'INTERNAL_ERROR', err instanceof Error ? err.message : String(err));
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1883
|
+
registerConnectorRoutes(app, {
|
|
1884
|
+
sendApiError,
|
|
1885
|
+
authorizeToolRequest,
|
|
1886
|
+
projectsRoot: PROJECTS_DIR,
|
|
1887
|
+
requireLocalDaemonRequest,
|
|
1888
|
+
composio: composioConnectorProvider,
|
|
1889
|
+
});
|
|
1890
|
+
// ---- Projects (DB-backed) -------------------------------------------------
|
|
1891
|
+
// ----- Memory store -----------------------------------------------------
|
|
1892
|
+
// Markdown-on-disk memory under <dataDir>/memory/. The daemon folds these
|
|
1893
|
+
// into every system prompt (gated by `enabled`) and the chat run loop
|
|
1894
|
+
// calls `/api/memory/extract` after each turn to sediment new facts.
|
|
1895
|
+
app.get('/api/memory', async (_req, res) => {
|
|
1896
|
+
try {
|
|
1897
|
+
const [config, index, entries] = await Promise.all([
|
|
1898
|
+
readMemoryConfig(RUNTIME_DATA_DIR),
|
|
1899
|
+
readMemoryIndex(RUNTIME_DATA_DIR),
|
|
1900
|
+
listMemoryEntries(RUNTIME_DATA_DIR),
|
|
1901
|
+
]);
|
|
1902
|
+
res.json({
|
|
1903
|
+
enabled: config.enabled,
|
|
1904
|
+
rootDir: memoryDir(RUNTIME_DATA_DIR),
|
|
1905
|
+
index,
|
|
1906
|
+
entries,
|
|
1907
|
+
extraction: maskMemoryExtractionConfig(config.extraction),
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
catch (err) {
|
|
1911
|
+
res.status(500).json({ error: String(err) });
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
// Static sub-resources (`/index`, `/config`, `/extract`) registered
|
|
1915
|
+
// BEFORE the `:id` catch-alls so an `index` / `config` / `extract` slug
|
|
1916
|
+
// can't shadow the real handlers.
|
|
1917
|
+
app.put('/api/memory/index', async (req, res) => {
|
|
1918
|
+
try {
|
|
1919
|
+
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
1920
|
+
const index = typeof body.index === 'string' ? body.index : '';
|
|
1921
|
+
await writeMemoryIndex(RUNTIME_DATA_DIR, index);
|
|
1922
|
+
res.json({ index });
|
|
1923
|
+
}
|
|
1924
|
+
catch (err) {
|
|
1925
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
app.patch('/api/memory/config', async (req, res) => {
|
|
1929
|
+
try {
|
|
1930
|
+
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
1931
|
+
const patch = {};
|
|
1932
|
+
if (typeof body.enabled === 'boolean')
|
|
1933
|
+
patch.enabled = body.enabled;
|
|
1934
|
+
// Three-state extraction handling so the UI can: (a) leave the
|
|
1935
|
+
// override alone (omit `extraction`), (b) clear it back to
|
|
1936
|
+
// auto-pick (`extraction: null`), or (c) commit a custom override
|
|
1937
|
+
// (`extraction: { provider, ... }`). For the apiKey field we
|
|
1938
|
+
// need *four* states because the masked GET surfaces only an
|
|
1939
|
+
// `apiKeyTail` (the secret never round-trips):
|
|
1940
|
+
// - field absent → preserve the stored key (UI re-saves
|
|
1941
|
+
// a settings form without re-typing
|
|
1942
|
+
// the secret).
|
|
1943
|
+
// - field === '' → CLEAR the stored key (the picker's
|
|
1944
|
+
// drift-resync effect fires this when
|
|
1945
|
+
// the user clears their BYOK chat
|
|
1946
|
+
// API key — keeping the old daemon-
|
|
1947
|
+
// side credential would silently keep
|
|
1948
|
+
// calling the provider after the user
|
|
1949
|
+
// intentionally removed it from the
|
|
1950
|
+
// chat picker, which the reviewer
|
|
1951
|
+
// flagged as a credential-sync bug).
|
|
1952
|
+
// - field === 'sk-…' → replace with the new key.
|
|
1953
|
+
// - provider differs → ignore stored key entirely.
|
|
1954
|
+
if (Object.prototype.hasOwnProperty.call(body, 'extraction')) {
|
|
1955
|
+
if (body.extraction === null) {
|
|
1956
|
+
patch.extraction = null;
|
|
1957
|
+
}
|
|
1958
|
+
else if (body.extraction && typeof body.extraction === 'object') {
|
|
1959
|
+
const incoming = body.extraction;
|
|
1960
|
+
const current = await readMemoryConfig(RUNTIME_DATA_DIR);
|
|
1961
|
+
const apiKeyOmitted = !Object.prototype.hasOwnProperty.call(incoming, 'apiKey');
|
|
1962
|
+
const sameProvider = !!current.extraction
|
|
1963
|
+
&& current.extraction.provider === incoming.provider;
|
|
1964
|
+
let nextApiKey = '';
|
|
1965
|
+
if (typeof incoming.apiKey === 'string' && incoming.apiKey) {
|
|
1966
|
+
nextApiKey = incoming.apiKey;
|
|
1967
|
+
}
|
|
1968
|
+
else if (apiKeyOmitted && sameProvider) {
|
|
1969
|
+
nextApiKey = current.extraction.apiKey ?? '';
|
|
1970
|
+
}
|
|
1971
|
+
patch.extraction = {
|
|
1972
|
+
provider: incoming.provider,
|
|
1973
|
+
model: typeof incoming.model === 'string' ? incoming.model : undefined,
|
|
1974
|
+
baseUrl: typeof incoming.baseUrl === 'string'
|
|
1975
|
+
? incoming.baseUrl
|
|
1976
|
+
: undefined,
|
|
1977
|
+
apiKey: nextApiKey,
|
|
1978
|
+
// Azure-only; ignored by the validator for the other providers.
|
|
1979
|
+
// We forward whatever the UI sent (or the previously-stored
|
|
1980
|
+
// value when the UI omits the field) so re-saving an azure
|
|
1981
|
+
// override without re-typing the api-version doesn't blank it.
|
|
1982
|
+
apiVersion: typeof incoming.apiVersion === 'string'
|
|
1983
|
+
? incoming.apiVersion
|
|
1984
|
+
: current.extraction?.apiVersion,
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
const next = await writeMemoryConfig(RUNTIME_DATA_DIR, patch);
|
|
1989
|
+
res.json({
|
|
1990
|
+
enabled: next.enabled,
|
|
1991
|
+
extraction: maskMemoryExtractionConfig(next.extraction),
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
catch (err) {
|
|
1995
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
// SSE feed of memory mutations. The web settings panel subscribes to
|
|
1999
|
+
// this and re-fetches on every event; toast UIs can listen for
|
|
2000
|
+
// `kind === 'extract'` and surface a small "Memory updated (N new)"
|
|
2001
|
+
// notification. Payload shape: MemoryChangeEvent (see ./memory.ts).
|
|
2002
|
+
//
|
|
2003
|
+
// The same connection also forwards `extraction` events — one per LLM
|
|
2004
|
+
// extraction phase transition — so the settings panel can render a
|
|
2005
|
+
// live "recent extractions" list. We multiplex on a single SSE stream
|
|
2006
|
+
// so the browser opens one connection instead of two.
|
|
2007
|
+
app.get('/api/memory/events', async (_req, res) => {
|
|
2008
|
+
const sse = createSseResponse(res);
|
|
2009
|
+
sse.send('connected', { at: Date.now() });
|
|
2010
|
+
const onChange = (event) => {
|
|
2011
|
+
sse.send('change', event);
|
|
2012
|
+
};
|
|
2013
|
+
const onExtraction = (event) => {
|
|
2014
|
+
sse.send('extraction', event);
|
|
2015
|
+
};
|
|
2016
|
+
memoryEvents.on('change', onChange);
|
|
2017
|
+
memoryEvents.on('extraction', onExtraction);
|
|
2018
|
+
res.on('close', () => {
|
|
2019
|
+
memoryEvents.off('change', onChange);
|
|
2020
|
+
memoryEvents.off('extraction', onExtraction);
|
|
2021
|
+
});
|
|
2022
|
+
});
|
|
2023
|
+
// Recent LLM-extraction attempts (newest first; capped server-side).
|
|
2024
|
+
// Surfaces skip reasons, in-flight calls, success counts, and errors
|
|
2025
|
+
// so the settings panel can show "why didn't memory update?" at a
|
|
2026
|
+
// glance instead of leaving the user to guess.
|
|
2027
|
+
app.get('/api/memory/extractions', async (_req, res) => {
|
|
2028
|
+
try {
|
|
2029
|
+
res.json({ extractions: listMemoryExtractions() });
|
|
2030
|
+
}
|
|
2031
|
+
catch (err) {
|
|
2032
|
+
res.status(500).json({ error: String(err) });
|
|
2033
|
+
}
|
|
2034
|
+
});
|
|
2035
|
+
// Drop the entire extraction history. Registered BEFORE the `:id`
|
|
2036
|
+
// catch-all so a literal "/api/memory/extractions" can still be
|
|
2037
|
+
// cleared with `curl -X DELETE`.
|
|
2038
|
+
app.delete('/api/memory/extractions', async (_req, res) => {
|
|
2039
|
+
try {
|
|
2040
|
+
const removed = clearMemoryExtractions();
|
|
2041
|
+
res.json({ removed });
|
|
2042
|
+
}
|
|
2043
|
+
catch (err) {
|
|
2044
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
app.delete('/api/memory/extractions/:id', async (req, res) => {
|
|
2048
|
+
try {
|
|
2049
|
+
const removed = removeMemoryExtraction(req.params.id);
|
|
2050
|
+
res.json({ removed });
|
|
2051
|
+
}
|
|
2052
|
+
catch (err) {
|
|
2053
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
// Imperative extract — used by CLI chats internally and by BYOK /
|
|
2057
|
+
// API-mode chats from the web app, which never reach the chat-run
|
|
2058
|
+
// path on the daemon. Mirrors the two-phase hook the daemon's chat
|
|
2059
|
+
// route applies inline:
|
|
2060
|
+
//
|
|
2061
|
+
// - Pre-turn (only `userMessage` supplied): run the synchronous
|
|
2062
|
+
// heuristic regex pack so explicit "remember: X" / "我是 X"
|
|
2063
|
+
// markers land in memory before the prompt is composed, and the
|
|
2064
|
+
// same turn's assistant reply already reflects them.
|
|
2065
|
+
// - Post-turn (`userMessage` + `assistantMessage` supplied): queue
|
|
2066
|
+
// the LLM extractor in the background — it speaks SSE /
|
|
2067
|
+
// extraction-history on its own and may take several seconds, so
|
|
2068
|
+
// we don't block the HTTP response on it. The heuristic is
|
|
2069
|
+
// skipped on this branch because the caller already ran it
|
|
2070
|
+
// pre-turn; running it twice would double the
|
|
2071
|
+
// `recordHeuristic({...})` rows in the extraction history for
|
|
2072
|
+
// every turn.
|
|
2073
|
+
//
|
|
2074
|
+
// External callers (curl, replay tools) that pass only
|
|
2075
|
+
// `userMessage` keep the legacy behaviour: heuristic-only.
|
|
2076
|
+
app.post('/api/memory/extract', async (req, res) => {
|
|
2077
|
+
try {
|
|
2078
|
+
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
2079
|
+
const userMessage = typeof body.userMessage === 'string' ? body.userMessage : '';
|
|
2080
|
+
const assistantMessage = typeof body.assistantMessage === 'string' ? body.assistantMessage : '';
|
|
2081
|
+
const hasAssistant = assistantMessage.trim().length > 0;
|
|
2082
|
+
const changed = hasAssistant
|
|
2083
|
+
? []
|
|
2084
|
+
: await extractFromMessage(RUNTIME_DATA_DIR, userMessage);
|
|
2085
|
+
// BYOK chat config — only forwarded by the web app for API-mode
|
|
2086
|
+
// chats. We strip the surface to the five fields pickProvider()
|
|
2087
|
+
// actually consumes and validate the provider against the four
|
|
2088
|
+
// shapes the extractor speaks; an unknown / missing provider
|
|
2089
|
+
// means "let the legacy chain decide" so a malformed payload
|
|
2090
|
+
// can't override the env / media-config fallbacks.
|
|
2091
|
+
const rawChat = body.chatProvider;
|
|
2092
|
+
let chatProvider = null;
|
|
2093
|
+
if (rawChat && typeof rawChat === 'object') {
|
|
2094
|
+
const provider = rawChat.provider;
|
|
2095
|
+
if (provider === 'anthropic'
|
|
2096
|
+
|| provider === 'openai'
|
|
2097
|
+
|| provider === 'azure'
|
|
2098
|
+
|| provider === 'google'
|
|
2099
|
+
|| provider === 'ollama') {
|
|
2100
|
+
chatProvider = {
|
|
2101
|
+
provider,
|
|
2102
|
+
apiKey: typeof rawChat.apiKey === 'string' ? rawChat.apiKey : '',
|
|
2103
|
+
baseUrl: typeof rawChat.baseUrl === 'string' ? rawChat.baseUrl : '',
|
|
2104
|
+
apiVersion: typeof rawChat.apiVersion === 'string' ? rawChat.apiVersion : '',
|
|
2105
|
+
model: typeof rawChat.model === 'string' ? rawChat.model : '',
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
let attemptedLLM = false;
|
|
2110
|
+
if (userMessage.trim().length > 0 && hasAssistant) {
|
|
2111
|
+
attemptedLLM = true;
|
|
2112
|
+
void import('./memory-llm.js')
|
|
2113
|
+
.then(({ extractWithLLM }) => extractWithLLM(RUNTIME_DATA_DIR, { userMessage, assistantMessage }, {
|
|
2114
|
+
projectRoot: PROJECT_ROOT,
|
|
2115
|
+
chatAgentId: null,
|
|
2116
|
+
chatProvider,
|
|
2117
|
+
}))
|
|
2118
|
+
.catch((err) => console.warn('[memory-llm] background failed (http extract)', err));
|
|
2119
|
+
}
|
|
2120
|
+
res.json({ changed, attemptedLLM });
|
|
2121
|
+
}
|
|
2122
|
+
catch (err) {
|
|
2123
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
// Composed memory body for the system prompt. Daemon-side chat runs
|
|
2127
|
+
// call `composeMemoryBody()` directly; the web app (BYOK / API mode)
|
|
2128
|
+
// can't import daemon internals, so this endpoint exposes the same
|
|
2129
|
+
// string the daemon would have folded into the system prompt for a
|
|
2130
|
+
// CLI run. `ProjectView.composedSystemPrompt()` calls it before each
|
|
2131
|
+
// BYOK turn and passes the result into `composeSystemPrompt`'s
|
|
2132
|
+
// `memoryBody` field — without this, the Memory tab is a no-op for
|
|
2133
|
+
// BYOK users even though the UI saves model/index/entries for them.
|
|
2134
|
+
app.get('/api/memory/system-prompt', async (_req, res) => {
|
|
2135
|
+
try {
|
|
2136
|
+
const body = await composeMemoryBody(RUNTIME_DATA_DIR);
|
|
2137
|
+
res.json({ body });
|
|
2138
|
+
}
|
|
2139
|
+
catch (err) {
|
|
2140
|
+
res.status(500).json({ error: String((err && err.message) || err) });
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
app.post('/api/memory', async (req, res) => {
|
|
2144
|
+
try {
|
|
2145
|
+
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
2146
|
+
const entry = await upsertMemoryEntry(RUNTIME_DATA_DIR, body);
|
|
2147
|
+
res.json({ entry });
|
|
2148
|
+
}
|
|
2149
|
+
catch (err) {
|
|
2150
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
app.get('/api/memory/:id', async (req, res) => {
|
|
2154
|
+
try {
|
|
2155
|
+
const entry = await readMemoryEntry(RUNTIME_DATA_DIR, req.params.id);
|
|
2156
|
+
if (!entry)
|
|
2157
|
+
return res.status(404).json({ error: 'memory not found' });
|
|
2158
|
+
res.json({ entry });
|
|
2159
|
+
}
|
|
2160
|
+
catch (err) {
|
|
2161
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
app.put('/api/memory/:id', async (req, res) => {
|
|
2165
|
+
try {
|
|
2166
|
+
const body = req.body && typeof req.body === 'object' ? req.body : {};
|
|
2167
|
+
const entry = await upsertMemoryEntry(RUNTIME_DATA_DIR, {
|
|
2168
|
+
...body,
|
|
2169
|
+
id: req.params.id,
|
|
2170
|
+
});
|
|
2171
|
+
res.json({ entry });
|
|
2172
|
+
}
|
|
2173
|
+
catch (err) {
|
|
2174
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2175
|
+
}
|
|
2176
|
+
});
|
|
2177
|
+
app.delete('/api/memory/:id', async (req, res) => {
|
|
2178
|
+
try {
|
|
2179
|
+
await deleteMemoryEntry(RUNTIME_DATA_DIR, req.params.id);
|
|
2180
|
+
res.json({ ok: true });
|
|
2181
|
+
}
|
|
2182
|
+
catch (err) {
|
|
2183
|
+
res.status(400).json({ error: String((err && err.message) || err) });
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
2186
|
+
const analyticsService = createAnalyticsService({ dataDir: RUNTIME_DATA_DIR });
|
|
2187
|
+
const design = {
|
|
2188
|
+
runs: createChatRunService({ createSseResponse, createSseErrorPayload }),
|
|
2189
|
+
analytics: analyticsService,
|
|
2190
|
+
getAppVersion: () => cachedAppVersion?.version ?? '0.0.0',
|
|
2191
|
+
readAnalyticsContext,
|
|
2192
|
+
};
|
|
2193
|
+
// PostHog runtime config — gated on BOTH a server-side key (POSTHOG_KEY)
|
|
2194
|
+
// and the user's opt-in metrics consent (Privacy → "Share usage data").
|
|
2195
|
+
// The web bundle short-circuits when enabled=false so opt-out behaviour
|
|
2196
|
+
// is instant after the user toggles metrics off and reloads.
|
|
2197
|
+
app.get('/api/analytics/config', async (_req, res) => {
|
|
2198
|
+
const baseline = readPublicConfigResponse();
|
|
2199
|
+
if (!baseline.enabled) {
|
|
2200
|
+
res.json(baseline);
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
try {
|
|
2204
|
+
const appCfg = await readAppConfig(RUNTIME_DATA_DIR);
|
|
2205
|
+
const consentGranted = appCfg.telemetry?.metrics === true;
|
|
2206
|
+
if (!consentGranted) {
|
|
2207
|
+
res.json({ enabled: false, key: null, host: null });
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
// Echo the installationId so the web client uses the same anonymous
|
|
2211
|
+
// id PostHog already saw on prior runs (and that Langfuse uses too).
|
|
2212
|
+
const installationId = typeof appCfg.installationId === 'string' && appCfg.installationId
|
|
2213
|
+
? appCfg.installationId
|
|
2214
|
+
: null;
|
|
2215
|
+
res.json({ ...baseline, installationId });
|
|
2216
|
+
}
|
|
2217
|
+
catch {
|
|
2218
|
+
// If the config file is unreadable, fail closed — no events.
|
|
2219
|
+
res.json({ enabled: false, key: null, host: null });
|
|
2220
|
+
}
|
|
2221
|
+
});
|
|
2222
|
+
// Tracks runs whose completion has already been forwarded to Langfuse so
|
|
2223
|
+
// repeated message updates only emit one trace per run.
|
|
2224
|
+
const reportedRuns = new Set();
|
|
2225
|
+
// App-version snapshot read once at server start for Langfuse trace metadata.
|
|
2226
|
+
let cachedAppVersion = null;
|
|
2227
|
+
void (async () => {
|
|
2228
|
+
try {
|
|
2229
|
+
cachedAppVersion = await readCurrentAppVersionInfo();
|
|
2230
|
+
}
|
|
2231
|
+
catch {
|
|
2232
|
+
// Telemetry is best-effort; appVersion is omitted when unavailable.
|
|
2233
|
+
}
|
|
2234
|
+
})();
|
|
2235
|
+
const reportFinalizedMessage = createFinalizedMessageTelemetryReporter({
|
|
2236
|
+
design,
|
|
2237
|
+
db,
|
|
2238
|
+
dataDir: RUNTIME_DATA_DIR,
|
|
2239
|
+
reportedRuns,
|
|
2240
|
+
getAppVersion: () => cachedAppVersion,
|
|
2241
|
+
});
|
|
2242
|
+
const validateExternalApiBaseUrl = (baseUrl) => validateBaseUrl(baseUrl);
|
|
2243
|
+
const resolvedPortRef = {
|
|
2244
|
+
get current() {
|
|
2245
|
+
return resolvedPort;
|
|
2246
|
+
},
|
|
2247
|
+
};
|
|
2248
|
+
const daemonUrlRef = {
|
|
2249
|
+
get current() {
|
|
2250
|
+
return daemonUrl;
|
|
2251
|
+
},
|
|
2252
|
+
};
|
|
2253
|
+
const httpDeps = {
|
|
2254
|
+
sendApiError,
|
|
2255
|
+
sendMulterError,
|
|
2256
|
+
sendLiveArtifactRouteError,
|
|
2257
|
+
createSseResponse,
|
|
2258
|
+
requireLocalDaemonRequest,
|
|
2259
|
+
isLocalSameOrigin,
|
|
2260
|
+
resolvedPortRef,
|
|
2261
|
+
};
|
|
2262
|
+
const pathDeps = {
|
|
2263
|
+
PROJECT_ROOT,
|
|
2264
|
+
PROJECTS_DIR,
|
|
2265
|
+
ARTIFACTS_DIR,
|
|
2266
|
+
RUNTIME_DATA_DIR,
|
|
2267
|
+
RUNTIME_DATA_DIR_CANONICAL,
|
|
2268
|
+
DESIGN_SYSTEMS_DIR,
|
|
2269
|
+
USER_DESIGN_SYSTEMS_DIR,
|
|
2270
|
+
DESIGN_TEMPLATES_DIR,
|
|
2271
|
+
USER_DESIGN_TEMPLATES_DIR,
|
|
2272
|
+
SKILLS_DIR,
|
|
2273
|
+
USER_SKILLS_DIR,
|
|
2274
|
+
PROMPT_TEMPLATES_DIR,
|
|
2275
|
+
BUNDLED_PETS_DIR,
|
|
2276
|
+
OD_BIN,
|
|
2277
|
+
};
|
|
2278
|
+
const nodeDeps = { fs, path };
|
|
2279
|
+
const idDeps = { randomId, randomUUID };
|
|
2280
|
+
const uploadDeps = { upload, importUpload, handleProjectUpload };
|
|
2281
|
+
const projectStoreDeps = {
|
|
2282
|
+
getProject,
|
|
2283
|
+
insertProject,
|
|
2284
|
+
updateProject,
|
|
2285
|
+
dbDeleteProject,
|
|
2286
|
+
removeProjectDir,
|
|
2287
|
+
validateLinkedDirs,
|
|
2288
|
+
};
|
|
2289
|
+
const projectFileDeps = {
|
|
2290
|
+
ensureProject,
|
|
2291
|
+
listFiles,
|
|
2292
|
+
searchProjectFiles,
|
|
2293
|
+
readProjectFile,
|
|
2294
|
+
resolveProjectDir,
|
|
2295
|
+
resolveProjectFilePath,
|
|
2296
|
+
parseByteRange,
|
|
2297
|
+
renameProjectFile,
|
|
2298
|
+
deleteProjectFile,
|
|
2299
|
+
writeProjectFile,
|
|
2300
|
+
sanitizeName,
|
|
2301
|
+
listTabs,
|
|
2302
|
+
setTabs,
|
|
2303
|
+
};
|
|
2304
|
+
const conversationDeps = {
|
|
2305
|
+
insertConversation,
|
|
2306
|
+
getConversation,
|
|
2307
|
+
listConversations,
|
|
2308
|
+
updateConversation,
|
|
2309
|
+
deleteConversation,
|
|
2310
|
+
listMessages,
|
|
2311
|
+
upsertMessage,
|
|
2312
|
+
listPreviewComments,
|
|
2313
|
+
upsertPreviewComment,
|
|
2314
|
+
updatePreviewCommentStatus,
|
|
2315
|
+
deletePreviewComment,
|
|
2316
|
+
};
|
|
2317
|
+
const templateDeps = { getTemplate, listTemplates, deleteTemplate, insertTemplate, findTemplateByNameAndProject, updateTemplate };
|
|
2318
|
+
const projectStatusDeps = {
|
|
2319
|
+
listLatestProjectRunStatuses,
|
|
2320
|
+
listProjectsAwaitingInput,
|
|
2321
|
+
normalizeProjectDisplayStatus,
|
|
2322
|
+
composeProjectDisplayStatus,
|
|
2323
|
+
listProjects,
|
|
2324
|
+
};
|
|
2325
|
+
const projectEventDeps = { subscribeFileEvents, activeProjectEventSinks };
|
|
2326
|
+
const importDeps = { importClaudeDesignZip, projectDir, detectEntryFile };
|
|
2327
|
+
const projectExportDeps = {
|
|
2328
|
+
buildProjectArchive,
|
|
2329
|
+
buildBatchArchive,
|
|
2330
|
+
buildDesktopPdfExportInput,
|
|
2331
|
+
desktopPdfExporter,
|
|
2332
|
+
daemonUrlRef,
|
|
2333
|
+
sanitizeArchiveFilename,
|
|
2334
|
+
};
|
|
2335
|
+
const artifactDeps = {
|
|
2336
|
+
sanitizeSlug,
|
|
2337
|
+
lintArtifact,
|
|
2338
|
+
renderFindingsForAgent,
|
|
2339
|
+
validateArtifactManifestInput,
|
|
2340
|
+
};
|
|
2341
|
+
const deployDeps = {
|
|
2342
|
+
VERCEL_PROVIDER_ID,
|
|
2343
|
+
CLOUDFLARE_PAGES_PROVIDER_ID,
|
|
2344
|
+
isDeployProviderId,
|
|
2345
|
+
publicDeployConfigForProvider,
|
|
2346
|
+
readDeployConfig,
|
|
2347
|
+
writeDeployConfig,
|
|
2348
|
+
listCloudflarePagesZones,
|
|
2349
|
+
DeployError,
|
|
2350
|
+
listDeployments,
|
|
2351
|
+
publicDeployments,
|
|
2352
|
+
getDeployment,
|
|
2353
|
+
getDeploymentById,
|
|
2354
|
+
buildDeployFileSet,
|
|
2355
|
+
cloudflarePagesProjectNameForDeploy,
|
|
2356
|
+
cloudflarePagesProjectNameFromDeployment,
|
|
2357
|
+
checkCloudflarePagesDeploymentLinks,
|
|
2358
|
+
checkDeploymentUrl,
|
|
2359
|
+
deployToCloudflarePages,
|
|
2360
|
+
deployToVercel,
|
|
2361
|
+
upsertDeployment,
|
|
2362
|
+
publicDeployment,
|
|
2363
|
+
cloudflarePagesDeploymentMetadata,
|
|
2364
|
+
prepareDeployPreflight,
|
|
2365
|
+
};
|
|
2366
|
+
const mediaDeps = {
|
|
2367
|
+
MEDIA_PROVIDERS,
|
|
2368
|
+
IMAGE_MODELS,
|
|
2369
|
+
VIDEO_MODELS,
|
|
2370
|
+
AUDIO_MODELS_BY_KIND,
|
|
2371
|
+
MEDIA_ASPECTS,
|
|
2372
|
+
VIDEO_LENGTHS_SEC,
|
|
2373
|
+
AUDIO_DURATIONS_SEC,
|
|
2374
|
+
readMaskedConfig,
|
|
2375
|
+
writeConfig,
|
|
2376
|
+
generateMedia,
|
|
2377
|
+
mediaTasks,
|
|
2378
|
+
createMediaTask: (taskId, projectId, info) => createMediaTask(db, taskId, projectId, info),
|
|
2379
|
+
persistMediaTask: (task) => persistMediaTask(db, task),
|
|
2380
|
+
appendTaskProgress: (task, line) => appendTaskProgress(db, task, line),
|
|
2381
|
+
notifyTaskWaiters: (task) => notifyTaskWaiters(db, task),
|
|
2382
|
+
getLiveMediaTask: (taskId) => getLiveMediaTask(db, taskId),
|
|
2383
|
+
mediaTaskSnapshot,
|
|
2384
|
+
listMediaTasksByProject,
|
|
2385
|
+
listElevenLabsVoiceOptions,
|
|
2386
|
+
};
|
|
2387
|
+
const appConfigDeps = { readAppConfig, writeAppConfig };
|
|
2388
|
+
const orbitDeps = { orbitService };
|
|
2389
|
+
const nativeDialogDeps = { openNativeFolderDialog };
|
|
2390
|
+
const researchDeps = { searchResearch, ResearchError };
|
|
2391
|
+
const liveArtifactDeps = {
|
|
2392
|
+
createLiveArtifact,
|
|
2393
|
+
listLiveArtifacts,
|
|
2394
|
+
updateLiveArtifact,
|
|
2395
|
+
refreshLiveArtifact,
|
|
2396
|
+
emitLiveArtifactEvent,
|
|
2397
|
+
emitLiveArtifactRefreshEvent,
|
|
2398
|
+
readLiveArtifactCode,
|
|
2399
|
+
setLiveArtifactCodeHeaders,
|
|
2400
|
+
ensureLiveArtifactPreview,
|
|
2401
|
+
setLiveArtifactPreviewHeaders,
|
|
2402
|
+
getLiveArtifact,
|
|
2403
|
+
listLiveArtifactRefreshLogEntries,
|
|
2404
|
+
deleteLiveArtifact,
|
|
2405
|
+
};
|
|
2406
|
+
const authDeps = {
|
|
2407
|
+
authorizeToolRequest,
|
|
2408
|
+
consumedImportNonces,
|
|
2409
|
+
desktopAuthSecret: () => desktopAuthSecret,
|
|
2410
|
+
isDesktopAuthGateActive,
|
|
2411
|
+
pruneExpiredImportNonces,
|
|
2412
|
+
requestProjectOverride,
|
|
2413
|
+
requestRunOverride,
|
|
2414
|
+
verifyDesktopImportToken,
|
|
2415
|
+
};
|
|
2416
|
+
const finalizeDeps = {
|
|
2417
|
+
finalizeDesignPackage,
|
|
2418
|
+
FinalizePackageLockedError,
|
|
2419
|
+
FinalizeUpstreamError,
|
|
2420
|
+
redactSecrets,
|
|
2421
|
+
};
|
|
2422
|
+
const validationDeps = { isSafeId, validateExternalApiBaseUrl, validateBaseUrl };
|
|
2423
|
+
const agentDeps = {
|
|
2424
|
+
listProviderModels,
|
|
2425
|
+
testProviderConnection,
|
|
2426
|
+
testAgentConnection,
|
|
2427
|
+
getAgentDef,
|
|
2428
|
+
isKnownModel,
|
|
2429
|
+
sanitizeCustomModel,
|
|
2430
|
+
};
|
|
2431
|
+
const critiqueDeps = {
|
|
2432
|
+
handleCritiqueArtifact,
|
|
2433
|
+
handleCritiqueInterrupt,
|
|
2434
|
+
critiqueArtifactsRoot: CRITIQUE_ARTIFACTS_DIR,
|
|
2435
|
+
critiqueResponseCapBytes: critiqueCfg.parserMaxBlockBytes,
|
|
2436
|
+
critiqueRunRegistry,
|
|
2437
|
+
};
|
|
2438
|
+
// External services
|
|
2439
|
+
registerMcpRoutes(app, {
|
|
2440
|
+
http: httpDeps,
|
|
2441
|
+
paths: pathDeps,
|
|
2442
|
+
mcp: { pendingAuth: mcpPendingAuth, daemonUrlRef },
|
|
2443
|
+
});
|
|
2444
|
+
// Project workspace
|
|
2445
|
+
registerActiveContextRoutes(app, {
|
|
2446
|
+
db,
|
|
2447
|
+
http: httpDeps,
|
|
2448
|
+
projectStore: projectStoreDeps,
|
|
2449
|
+
});
|
|
2450
|
+
registerProjectRoutes(app, {
|
|
2451
|
+
db,
|
|
2452
|
+
design,
|
|
2453
|
+
http: httpDeps,
|
|
2454
|
+
paths: pathDeps,
|
|
2455
|
+
projectStore: projectStoreDeps,
|
|
2456
|
+
projectFiles: projectFileDeps,
|
|
2457
|
+
conversations: conversationDeps,
|
|
2458
|
+
templates: templateDeps,
|
|
2459
|
+
status: projectStatusDeps,
|
|
2460
|
+
events: projectEventDeps,
|
|
2461
|
+
ids: idDeps,
|
|
2462
|
+
telemetry: { reportFinalizedMessage },
|
|
2463
|
+
});
|
|
2464
|
+
registerImportRoutes(app, {
|
|
2465
|
+
db,
|
|
2466
|
+
http: httpDeps,
|
|
2467
|
+
uploads: uploadDeps,
|
|
2468
|
+
node: nodeDeps,
|
|
2469
|
+
ids: idDeps,
|
|
2470
|
+
paths: pathDeps,
|
|
2471
|
+
imports: importDeps,
|
|
2472
|
+
auth: authDeps,
|
|
2473
|
+
projectStore: projectStoreDeps,
|
|
2474
|
+
conversations: conversationDeps,
|
|
2475
|
+
projectFiles: projectFileDeps,
|
|
2476
|
+
});
|
|
2477
|
+
// Resource catalog
|
|
2478
|
+
registerStaticResourceRoutes(app, {
|
|
2479
|
+
http: httpDeps,
|
|
2480
|
+
paths: pathDeps,
|
|
2481
|
+
resources: {
|
|
2482
|
+
listAllSkills,
|
|
2483
|
+
listAllDesignTemplates,
|
|
2484
|
+
listAllSkillLikeEntries,
|
|
2485
|
+
listAllDesignSystems,
|
|
2486
|
+
mimeFor,
|
|
2487
|
+
},
|
|
2488
|
+
});
|
|
2489
|
+
registerProjectArtifactRoutes(app, {
|
|
2490
|
+
http: httpDeps,
|
|
2491
|
+
uploads: uploadDeps,
|
|
2492
|
+
paths: pathDeps,
|
|
2493
|
+
node: nodeDeps,
|
|
2494
|
+
artifacts: artifactDeps,
|
|
2495
|
+
});
|
|
2496
|
+
registerLiveArtifactRoutes(app, {
|
|
2497
|
+
db,
|
|
2498
|
+
http: httpDeps,
|
|
2499
|
+
paths: pathDeps,
|
|
2500
|
+
auth: authDeps,
|
|
2501
|
+
liveArtifacts: liveArtifactDeps,
|
|
2502
|
+
projectStore: projectStoreDeps,
|
|
2503
|
+
});
|
|
2504
|
+
app.use('/artifacts', express.static(ARTIFACTS_DIR));
|
|
2505
|
+
registerDeployRoutes(app, {
|
|
2506
|
+
db,
|
|
2507
|
+
http: httpDeps,
|
|
2508
|
+
paths: pathDeps,
|
|
2509
|
+
ids: idDeps,
|
|
2510
|
+
deploy: deployDeps,
|
|
2511
|
+
projectStore: projectStoreDeps,
|
|
2512
|
+
});
|
|
2513
|
+
registerFinalizeRoutes(app, {
|
|
2514
|
+
db,
|
|
2515
|
+
http: httpDeps,
|
|
2516
|
+
paths: pathDeps,
|
|
2517
|
+
projectStore: projectStoreDeps,
|
|
2518
|
+
validation: validationDeps,
|
|
2519
|
+
finalize: finalizeDeps,
|
|
2520
|
+
});
|
|
2521
|
+
registerDeploymentCheckRoutes(app, { db, http: httpDeps, deploy: deployDeps });
|
|
2522
|
+
app.use('/frames', express.static(FRAMES_DIR));
|
|
2523
|
+
registerProjectExportRoutes(app, {
|
|
2524
|
+
db,
|
|
2525
|
+
http: httpDeps,
|
|
2526
|
+
paths: pathDeps,
|
|
2527
|
+
projectStore: projectStoreDeps,
|
|
2528
|
+
exports: projectExportDeps,
|
|
2529
|
+
projectFiles: projectFileDeps,
|
|
2530
|
+
validation: validationDeps,
|
|
2531
|
+
});
|
|
2532
|
+
registerProjectFileRoutes(app, {
|
|
2533
|
+
db,
|
|
2534
|
+
http: httpDeps,
|
|
2535
|
+
paths: pathDeps,
|
|
2536
|
+
uploads: uploadDeps,
|
|
2537
|
+
node: nodeDeps,
|
|
2538
|
+
projectStore: projectStoreDeps,
|
|
2539
|
+
projectFiles: projectFileDeps,
|
|
2540
|
+
documents: { buildDocumentPreview },
|
|
2541
|
+
artifacts: artifactDeps,
|
|
2542
|
+
});
|
|
2543
|
+
registerMediaRoutes(app, {
|
|
2544
|
+
db,
|
|
2545
|
+
http: httpDeps,
|
|
2546
|
+
paths: pathDeps,
|
|
2547
|
+
ids: idDeps,
|
|
2548
|
+
media: mediaDeps,
|
|
2549
|
+
appConfig: appConfigDeps,
|
|
2550
|
+
orbit: orbitDeps,
|
|
2551
|
+
nativeDialogs: nativeDialogDeps,
|
|
2552
|
+
projectStore: projectStoreDeps,
|
|
2553
|
+
projectFiles: projectFileDeps,
|
|
2554
|
+
conversations: conversationDeps,
|
|
2555
|
+
research: researchDeps,
|
|
2556
|
+
});
|
|
2557
|
+
registerProjectUploadRoutes(app, { http: httpDeps, uploads: uploadDeps, node: nodeDeps });
|
|
2558
|
+
const composeDaemonSystemPrompt = async ({ agentId, projectId, skillId, designSystemId, streamFormat, connectedExternalMcp, }) => {
|
|
2559
|
+
const project = typeof projectId === 'string' && projectId
|
|
2560
|
+
? getProject(db, projectId)
|
|
2561
|
+
: null;
|
|
2562
|
+
const effectiveSkillId = typeof skillId === 'string' && skillId ? skillId : project?.skillId;
|
|
2563
|
+
const effectiveDesignSystemId = typeof designSystemId === 'string' && designSystemId
|
|
2564
|
+
? designSystemId
|
|
2565
|
+
: project?.designSystemId;
|
|
2566
|
+
const metadata = project?.metadata;
|
|
2567
|
+
let skillBody;
|
|
2568
|
+
let skillName;
|
|
2569
|
+
let skillMode;
|
|
2570
|
+
let skillCraftRequires = [];
|
|
2571
|
+
let activeSkillDir = null;
|
|
2572
|
+
// Per-skill Critique Theater override sourced from
|
|
2573
|
+
// `od.critique.policy` in the resolved skill's SKILL.md frontmatter.
|
|
2574
|
+
// `null` means the skill has no opinion and the lower-priority tiers
|
|
2575
|
+
// (project override, env override, rollout phase default) decide.
|
|
2576
|
+
let skillCritiquePolicy = null;
|
|
2577
|
+
if (effectiveSkillId) {
|
|
2578
|
+
// Span both functional skills and design templates so a project
|
|
2579
|
+
// saved against either surface keeps its system prompt after the
|
|
2580
|
+
// skills/design-templates split. See specs/current/skills-and-design-templates.md.
|
|
2581
|
+
const skill = findSkillById(await listAllSkillLikeEntries(), effectiveSkillId);
|
|
2582
|
+
if (skill) {
|
|
2583
|
+
skillBody = skill.body;
|
|
2584
|
+
skillName = skill.name;
|
|
2585
|
+
skillMode = skill.mode;
|
|
2586
|
+
activeSkillDir = skill.dir;
|
|
2587
|
+
skillCritiquePolicy = skill.critiquePolicy;
|
|
2588
|
+
if (Array.isArray(skill.craftRequires))
|
|
2589
|
+
skillCraftRequires = skill.craftRequires;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
let craftBody;
|
|
2593
|
+
let craftSections;
|
|
2594
|
+
if (skillCraftRequires.length > 0) {
|
|
2595
|
+
const loaded = await loadCraftSections(CRAFT_DIR, skillCraftRequires);
|
|
2596
|
+
if (loaded.body) {
|
|
2597
|
+
craftBody = loaded.body;
|
|
2598
|
+
craftSections = loaded.sections;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
// Personal-memory body is always recomputed at compose time so a
|
|
2602
|
+
// memory the user just edited in settings shows up on the very next
|
|
2603
|
+
// run. composeMemoryBody returns '' when memory is disabled or
|
|
2604
|
+
// empty; the composer drops the block on a falsy value.
|
|
2605
|
+
let memoryBody = '';
|
|
2606
|
+
try {
|
|
2607
|
+
memoryBody = await composeMemoryBody(RUNTIME_DATA_DIR);
|
|
2608
|
+
}
|
|
2609
|
+
catch (err) {
|
|
2610
|
+
console.warn('[memory] composeMemoryBody failed', err);
|
|
2611
|
+
}
|
|
2612
|
+
// User-level custom instructions from app-config.json.
|
|
2613
|
+
let userInstructions = '';
|
|
2614
|
+
try {
|
|
2615
|
+
const appCfg = await readAppConfig(RUNTIME_DATA_DIR);
|
|
2616
|
+
if (appCfg.customInstructions)
|
|
2617
|
+
userInstructions = appCfg.customInstructions;
|
|
2618
|
+
}
|
|
2619
|
+
catch (err) {
|
|
2620
|
+
console.warn('[custom-instructions] readAppConfig failed', err);
|
|
2621
|
+
}
|
|
2622
|
+
// Project-level custom instructions from the projects table.
|
|
2623
|
+
const projectInstructions = project?.customInstructions ?? '';
|
|
2624
|
+
let designSystemBody;
|
|
2625
|
+
let designSystemTitle;
|
|
2626
|
+
// Compiled (tokens.css + components.html) form of the active brand.
|
|
2627
|
+
// Default-on as of PR-D — every chat that picks a brand with
|
|
2628
|
+
// `tokens.css` + `components.html` siblings (today: `default` and
|
|
2629
|
+
// `kami`; every other brand falls through silently because the
|
|
2630
|
+
// files are absent) gets the structured token contract appended to
|
|
2631
|
+
// the system prompt automatically.
|
|
2632
|
+
//
|
|
2633
|
+
// `OD_DESIGN_TOKEN_CHANNEL=0` is the kill switch: it forces the
|
|
2634
|
+
// daemon back to the pre-PR-C DESIGN.md-only path for every brand,
|
|
2635
|
+
// including the structured ones. Any other value (unset, `1`,
|
|
2636
|
+
// `true`, etc.) keeps the new default. Drift on prose-only brands
|
|
2637
|
+
// is pinned by `scripts/check-design-system-flag-parity.ts`.
|
|
2638
|
+
let designSystemTokensCss;
|
|
2639
|
+
let designSystemFixtureHtml;
|
|
2640
|
+
if (effectiveDesignSystemId) {
|
|
2641
|
+
const systems = await listAllDesignSystems();
|
|
2642
|
+
const summary = systems.find((s) => s.id === effectiveDesignSystemId);
|
|
2643
|
+
designSystemTitle = summary?.title;
|
|
2644
|
+
designSystemBody =
|
|
2645
|
+
(await readDesignSystem(DESIGN_SYSTEMS_DIR, effectiveDesignSystemId)) ??
|
|
2646
|
+
(await readDesignSystem(USER_DESIGN_SYSTEMS_DIR, effectiveDesignSystemId)) ??
|
|
2647
|
+
undefined;
|
|
2648
|
+
// Single seam: env gate + built-in→user-installed fallback chain
|
|
2649
|
+
// live together inside `resolveDesignSystemAssets` so the whole
|
|
2650
|
+
// server-side asset-resolution path can be tested end-to-end
|
|
2651
|
+
// from real disk fixtures (see `tests/design-system-assets.test.ts`).
|
|
2652
|
+
const assets = await resolveDesignSystemAssets(effectiveDesignSystemId, DESIGN_SYSTEMS_DIR, USER_DESIGN_SYSTEMS_DIR);
|
|
2653
|
+
designSystemTokensCss = assets.tokensCss;
|
|
2654
|
+
designSystemFixtureHtml = assets.fixtureHtml;
|
|
2655
|
+
}
|
|
2656
|
+
const template = metadata?.kind === 'template' && typeof metadata.templateId === 'string'
|
|
2657
|
+
? (getTemplate(db, metadata.templateId) ?? undefined)
|
|
2658
|
+
: undefined;
|
|
2659
|
+
let audioVoiceOptions = [];
|
|
2660
|
+
let audioVoiceOptionsError;
|
|
2661
|
+
if (metadata?.kind === 'audio' &&
|
|
2662
|
+
metadata?.audioKind === 'speech' &&
|
|
2663
|
+
metadata?.audioModel === 'elevenlabs-v3' &&
|
|
2664
|
+
!metadata?.voice) {
|
|
2665
|
+
try {
|
|
2666
|
+
audioVoiceOptions = await listElevenLabsVoiceOptions(PROJECT_ROOT, { limit: 100 });
|
|
2667
|
+
}
|
|
2668
|
+
catch (err) {
|
|
2669
|
+
audioVoiceOptionsError = err && err.message ? err.message : String(err);
|
|
2670
|
+
console.warn('[elevenlabs] voice option lookup failed:', audioVoiceOptionsError);
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
// Thread the critique config plus the active design-system / skill data
|
|
2674
|
+
// into the composer when critique is enabled. Without this the spawned
|
|
2675
|
+
// child receives the legacy single-pass prompt and the parser waits for
|
|
2676
|
+
// <CRITIQUE_RUN> tags the model was never told to emit. The composer
|
|
2677
|
+
// itself ignores these fields when the top-line gate is false, so the
|
|
2678
|
+
// legacy path stays untouched.
|
|
2679
|
+
//
|
|
2680
|
+
// Top-line gate (post-Phase-15 wireup): the daemon now routes every
|
|
2681
|
+
// candidate run through the rollout resolver instead of reading the
|
|
2682
|
+
// env-var flag directly. The resolver carries the full priority
|
|
2683
|
+
// matrix: skill `od.critique.policy` veto > project override > env
|
|
2684
|
+
// override > rollout phase default. On a fresh install with M0
|
|
2685
|
+
// dark-launch defaults the resolver returns `false`, so prod traffic
|
|
2686
|
+
// is unchanged until an operator flips the env var or a project
|
|
2687
|
+
// opts in. The skill-policy input is sourced from
|
|
2688
|
+
// `od.critique.policy` in the active skill's SKILL.md frontmatter
|
|
2689
|
+
// (parsed in `skills.ts:normalizeCritiquePolicy`). The project
|
|
2690
|
+
// override input is sourced from the `critiqueTheaterEnabled`
|
|
2691
|
+
// field on the project's metadata blob, which is what the M1
|
|
2692
|
+
// Settings toggle writes through the existing settings endpoint.
|
|
2693
|
+
// Both inputs collapse to `null` when the skill / project has
|
|
2694
|
+
// not expressed an opinion, which is the resolver's "fall through
|
|
2695
|
+
// to env / phase default" signal.
|
|
2696
|
+
// Per-project override: the M1 Settings toggle writes
|
|
2697
|
+
// `critiqueTheaterEnabled` onto the project's metadata blob via
|
|
2698
|
+
// the existing settings round-trip. A boolean wins outright; any
|
|
2699
|
+
// other type (missing key, malformed value) collapses to `null`
|
|
2700
|
+
// so the resolver falls through to the env / phase tiers exactly
|
|
2701
|
+
// the way it did when the toggle had never been touched.
|
|
2702
|
+
const projectCritiqueOverride = narrowProjectCritiqueOverride(metadata);
|
|
2703
|
+
const critiqueEnabledForRun = isCritiqueEnabled({
|
|
2704
|
+
phase: parseRolloutPhase(process.env.OD_CRITIQUE_ROLLOUT_PHASE),
|
|
2705
|
+
skillPolicy: skillCritiquePolicy,
|
|
2706
|
+
projectOverride: projectCritiqueOverride,
|
|
2707
|
+
envOverride: parseEnvEnabled(process.env.OD_CRITIQUE_ENABLED),
|
|
2708
|
+
});
|
|
2709
|
+
const critiqueBrand = critiqueEnabledForRun
|
|
2710
|
+
&& typeof designSystemTitle === 'string'
|
|
2711
|
+
&& typeof designSystemBody === 'string'
|
|
2712
|
+
? { name: designSystemTitle, design_md: designSystemBody }
|
|
2713
|
+
: undefined;
|
|
2714
|
+
const critiqueSkill = critiqueEnabledForRun && typeof effectiveSkillId === 'string'
|
|
2715
|
+
? { id: effectiveSkillId }
|
|
2716
|
+
: undefined;
|
|
2717
|
+
// Single-source-of-truth eligibility check. The composer downstream
|
|
2718
|
+
// appends <CRITIQUE_RUN> instructions only when this check passes, and
|
|
2719
|
+
// the spawn path routes runs through runOrchestrator(...) only when the
|
|
2720
|
+
// SAME flag is true, so prompt and orchestrator stay in lockstep.
|
|
2721
|
+
//
|
|
2722
|
+
// Non-plain adapters (claude-stream-json, copilot-stream-json,
|
|
2723
|
+
// json-event-stream, acp-json-rpc, pi-rpc) emit their own wrapper
|
|
2724
|
+
// protocol; the v1 critique parser only understands plain stdout. The
|
|
2725
|
+
// spawn path falls through to legacy generation for those, so the
|
|
2726
|
+
// panel addendum has to be suppressed here too: otherwise the model
|
|
2727
|
+
// is instructed to emit Critique Theater tags that no orchestrator
|
|
2728
|
+
// consumes.
|
|
2729
|
+
const isMediaSurface = skillMode === 'image' ||
|
|
2730
|
+
skillMode === 'video' ||
|
|
2731
|
+
skillMode === 'audio' ||
|
|
2732
|
+
metadata?.kind === 'image' ||
|
|
2733
|
+
metadata?.kind === 'video' ||
|
|
2734
|
+
metadata?.kind === 'audio';
|
|
2735
|
+
const isPlainAdapter = (streamFormat ?? 'plain') === 'plain';
|
|
2736
|
+
const critiqueShouldRun = critiqueEnabledForRun
|
|
2737
|
+
&& critiqueBrand !== undefined
|
|
2738
|
+
&& critiqueSkill !== undefined
|
|
2739
|
+
&& !isMediaSurface
|
|
2740
|
+
&& isPlainAdapter;
|
|
2741
|
+
// Only thread the critique fields when the run is actually eligible;
|
|
2742
|
+
// otherwise the composer's own internal eligibility check (cfg.enabled
|
|
2743
|
+
// && brand && skill && !isMediaSurface) might still fire on
|
|
2744
|
+
// non-plain adapters and we'd emit the panel for a run the orchestrator
|
|
2745
|
+
// skips. Gating the threading itself keeps composer + orchestrator in
|
|
2746
|
+
// exact lockstep regardless of which side enforces eligibility.
|
|
2747
|
+
const prompt = composeSystemPrompt({
|
|
2748
|
+
agentId,
|
|
2749
|
+
includeCodexImagegenOverride: false,
|
|
2750
|
+
skillBody,
|
|
2751
|
+
skillName,
|
|
2752
|
+
skillMode,
|
|
2753
|
+
designSystemBody,
|
|
2754
|
+
designSystemTitle,
|
|
2755
|
+
designSystemTokensCss,
|
|
2756
|
+
designSystemFixtureHtml,
|
|
2757
|
+
craftBody,
|
|
2758
|
+
craftSections,
|
|
2759
|
+
memoryBody,
|
|
2760
|
+
metadata,
|
|
2761
|
+
template,
|
|
2762
|
+
audioVoiceOptions,
|
|
2763
|
+
audioVoiceOptionsError,
|
|
2764
|
+
// critiqueCfg.enabled is loaded from OD_CRITIQUE_ENABLED only, so a
|
|
2765
|
+
// run that the resolver enabled via phase / project / skill (env
|
|
2766
|
+
// unset) would have critiqueShouldRun = true while critiqueCfg.enabled
|
|
2767
|
+
// remains false. Without this override the composer's own gate
|
|
2768
|
+
// (cfg.enabled) drops the panel addendum, the orchestrator still
|
|
2769
|
+
// launches, and the parser waits for <CRITIQUE_RUN> tags the model
|
|
2770
|
+
// was never told to emit (codex P2 on PR #1338). Build a derived
|
|
2771
|
+
// config that pins enabled to the resolver decision so the composer
|
|
2772
|
+
// and the orchestrator agree on every eligibility input.
|
|
2773
|
+
critique: critiqueShouldRun ? { ...critiqueCfg, enabled: true } : undefined,
|
|
2774
|
+
critiqueBrand: critiqueShouldRun ? critiqueBrand : undefined,
|
|
2775
|
+
critiqueSkill: critiqueShouldRun ? critiqueSkill : undefined,
|
|
2776
|
+
streamFormat,
|
|
2777
|
+
connectedExternalMcp: Array.isArray(connectedExternalMcp)
|
|
2778
|
+
? connectedExternalMcp
|
|
2779
|
+
: undefined,
|
|
2780
|
+
userInstructions,
|
|
2781
|
+
projectInstructions,
|
|
2782
|
+
});
|
|
2783
|
+
// The chat handler also needs to know where the active skill lives
|
|
2784
|
+
// on disk so it can stage a per-project copy of its side files
|
|
2785
|
+
// before spawning the agent. Returning that here avoids a second
|
|
2786
|
+
// `listSkills()` scan in `startChatRun`. critiqueShouldRun threads
|
|
2787
|
+
// the same panel-eligibility decision down to the spawn-path
|
|
2788
|
+
// orchestrator gate so prompt and orchestrator stay in lockstep.
|
|
2789
|
+
return { prompt, activeSkillDir, critiqueShouldRun };
|
|
2790
|
+
};
|
|
2791
|
+
const startChatRun = async (chatBody, run) => {
|
|
2792
|
+
/** @type {Partial<ChatRequest> & { imagePaths?: string[] }} */
|
|
2793
|
+
chatBody = chatBody || {};
|
|
2794
|
+
const { agentId, message, currentPrompt, systemPrompt, imagePaths = [], projectId, conversationId, assistantMessageId, clientRequestId, skillId, designSystemId, attachments = [], commentAttachments = [], model, reasoning, research, } = chatBody;
|
|
2795
|
+
if (typeof projectId === 'string' && projectId)
|
|
2796
|
+
run.projectId = projectId;
|
|
2797
|
+
if (typeof conversationId === 'string' && conversationId)
|
|
2798
|
+
run.conversationId = conversationId;
|
|
2799
|
+
if (typeof assistantMessageId === 'string' && assistantMessageId)
|
|
2800
|
+
run.assistantMessageId = assistantMessageId;
|
|
2801
|
+
if (typeof clientRequestId === 'string' && clientRequestId)
|
|
2802
|
+
run.clientRequestId = clientRequestId;
|
|
2803
|
+
if (typeof agentId === 'string' && agentId)
|
|
2804
|
+
run.agentId = agentId;
|
|
2805
|
+
// Stash the original user prompt + per-turn config so the
|
|
2806
|
+
// langfuse-bridge report path can include them without reaching back
|
|
2807
|
+
// into chatBody across the createChatRunService boundary. Each field
|
|
2808
|
+
// is optional and only set when the chat body actually carried it.
|
|
2809
|
+
const telemetryPrompt = telemetryPromptFromRunRequest(message, currentPrompt);
|
|
2810
|
+
if (typeof telemetryPrompt === 'string')
|
|
2811
|
+
run.userPrompt = telemetryPrompt;
|
|
2812
|
+
if (typeof model === 'string' && model)
|
|
2813
|
+
run.model = model;
|
|
2814
|
+
if (typeof reasoning === 'string' && reasoning)
|
|
2815
|
+
run.reasoning = reasoning;
|
|
2816
|
+
if (typeof skillId === 'string' && skillId)
|
|
2817
|
+
run.skillId = skillId;
|
|
2818
|
+
if (typeof designSystemId === 'string' && designSystemId)
|
|
2819
|
+
run.designSystemId = designSystemId;
|
|
2820
|
+
const def = getAgentDef(agentId);
|
|
2821
|
+
if (!def)
|
|
2822
|
+
return design.runs.fail(run, 'AGENT_UNAVAILABLE', `unknown agent: ${agentId}`);
|
|
2823
|
+
if (!def.bin)
|
|
2824
|
+
return design.runs.fail(run, 'AGENT_UNAVAILABLE', 'agent has no binary');
|
|
2825
|
+
const safeCommentAttachments = normalizeCommentAttachments(commentAttachments);
|
|
2826
|
+
if ((typeof message !== 'string' || !message.trim()) &&
|
|
2827
|
+
safeCommentAttachments.length === 0) {
|
|
2828
|
+
return design.runs.fail(run, 'BAD_REQUEST', 'message required');
|
|
2829
|
+
}
|
|
2830
|
+
if (run.cancelRequested || design.runs.isTerminal(run.status))
|
|
2831
|
+
return;
|
|
2832
|
+
const runId = run.id;
|
|
2833
|
+
// Auto-memory hook. Pulls explicit "remember:" / "我是 X" / "I prefer Y"
|
|
2834
|
+
// markers out of the just-arrived user message and writes them as MD
|
|
2835
|
+
// files under <dataDir>/memory/. We await so the very next
|
|
2836
|
+
// composeSystemPrompt() call (a few lines below) re-reads memory from
|
|
2837
|
+
// disk and a marker inside this turn's message is reflected in this
|
|
2838
|
+
// turn's prompt. Failures are swallowed — memory is best-effort and
|
|
2839
|
+
// must never block the agent run.
|
|
2840
|
+
if (typeof message === 'string' && message.trim().length > 0) {
|
|
2841
|
+
try {
|
|
2842
|
+
await extractFromMessage(RUNTIME_DATA_DIR, message);
|
|
2843
|
+
}
|
|
2844
|
+
catch (err) {
|
|
2845
|
+
console.warn('[memory] extractFromMessage failed', err);
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
// Resolve the project working directory (creating the folder if it
|
|
2849
|
+
// doesn't exist yet). Without one we don't pass cwd to spawn — the
|
|
2850
|
+
// agent then runs in whatever inherited dir, which still lets API
|
|
2851
|
+
// mode work but loses file-tool addressability.
|
|
2852
|
+
// For git-linked projects (metadata.baseDir), use that folder directly
|
|
2853
|
+
// so the agent writes back to the user's original source tree.
|
|
2854
|
+
let cwd = null;
|
|
2855
|
+
let existingProjectFiles = [];
|
|
2856
|
+
if (typeof projectId === 'string' && projectId) {
|
|
2857
|
+
try {
|
|
2858
|
+
const chatProject = getProject(db, projectId);
|
|
2859
|
+
const chatMeta = chatProject?.metadata;
|
|
2860
|
+
if (chatMeta?.baseDir) {
|
|
2861
|
+
cwd = path.normalize(chatMeta.baseDir);
|
|
2862
|
+
existingProjectFiles = await listFiles(PROJECTS_DIR, projectId, { metadata: chatMeta });
|
|
2863
|
+
}
|
|
2864
|
+
else {
|
|
2865
|
+
cwd = await ensureProject(PROJECTS_DIR, projectId);
|
|
2866
|
+
existingProjectFiles = await listFiles(PROJECTS_DIR, projectId);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
catch {
|
|
2870
|
+
cwd = null;
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
if (run.cancelRequested || design.runs.isTerminal(run.status))
|
|
2874
|
+
return;
|
|
2875
|
+
// Sanitise supplied image paths: must live under UPLOAD_DIR.
|
|
2876
|
+
const safeImages = imagePaths.filter((p) => {
|
|
2877
|
+
const resolved = path.resolve(p);
|
|
2878
|
+
return (resolved.startsWith(UPLOAD_DIR + path.sep) && fs.existsSync(resolved));
|
|
2879
|
+
});
|
|
2880
|
+
// Project-scoped attachments: project-relative paths inside cwd. Each
|
|
2881
|
+
// is run through the same path-traversal guard the file CRUD endpoints
|
|
2882
|
+
// use, then existence-checked. Whatever survives shows up as an
|
|
2883
|
+
// explicit list at the bottom of the user message so the agent knows
|
|
2884
|
+
// to Read it.
|
|
2885
|
+
const safeAttachments = cwd
|
|
2886
|
+
? (Array.isArray(attachments) ? attachments : [])
|
|
2887
|
+
.filter((p) => typeof p === 'string' && p.length > 0)
|
|
2888
|
+
.filter((p) => {
|
|
2889
|
+
try {
|
|
2890
|
+
const abs = path.resolve(cwd, p);
|
|
2891
|
+
return ((abs === cwd || abs.startsWith(cwd + path.sep)) &&
|
|
2892
|
+
fs.existsSync(abs));
|
|
2893
|
+
}
|
|
2894
|
+
catch {
|
|
2895
|
+
return false;
|
|
2896
|
+
}
|
|
2897
|
+
})
|
|
2898
|
+
: [];
|
|
2899
|
+
// Local code agents don't accept a separate "system" channel the way the
|
|
2900
|
+
// Messages API does — we fold the skill + design-system prompt into the
|
|
2901
|
+
// user message. The <artifact> wrapping instruction comes from
|
|
2902
|
+
// systemPrompt. We also stitch in the cwd hint so the agent knows
|
|
2903
|
+
// where its file tools should write, and the attachment list so it
|
|
2904
|
+
// doesn't have to guess what the user just dropped in.
|
|
2905
|
+
// Also ship the current file listing so the agent can pick a unique
|
|
2906
|
+
// filename instead of clobbering a previous artifact.
|
|
2907
|
+
const filesListBlock = existingProjectFiles.length
|
|
2908
|
+
? `\nFiles already in this folder (do NOT overwrite unless the user asks; pick a fresh, descriptive name for new artifacts):\n${existingProjectFiles
|
|
2909
|
+
.map((f) => `- ${f.name}`)
|
|
2910
|
+
.join('\n')}`
|
|
2911
|
+
: '\nThis folder is empty. Choose a clear, descriptive filename for whatever you create.';
|
|
2912
|
+
const projectRecord = typeof projectId === 'string' && projectId
|
|
2913
|
+
? getProject(db, projectId)
|
|
2914
|
+
: null;
|
|
2915
|
+
const linkedDirs = (() => {
|
|
2916
|
+
if (!Array.isArray(projectRecord?.metadata?.linkedDirs))
|
|
2917
|
+
return [];
|
|
2918
|
+
const v = validateLinkedDirs(projectRecord.metadata.linkedDirs);
|
|
2919
|
+
return v.dirs ?? [];
|
|
2920
|
+
})();
|
|
2921
|
+
const cwdHint = cwd
|
|
2922
|
+
? `\n\nYour working directory: ${cwd}\nWrite project files relative to it (e.g. \`index.html\`, \`assets/x.png\`). The user can browse those files in real time.${filesListBlock}`
|
|
2923
|
+
: '';
|
|
2924
|
+
const linkedDirsHint = linkedDirs.length > 0
|
|
2925
|
+
? `\n\nLinked code folders (read-only reference code the user wants you to see):\n${linkedDirs.map((d) => `- \`${d}\``).join('\n')}`
|
|
2926
|
+
: '';
|
|
2927
|
+
const attachmentHint = safeAttachments.length
|
|
2928
|
+
? `\n\nAttached project files: ${safeAttachments.map((p) => `\`${p}\``).join(', ')}`
|
|
2929
|
+
: '';
|
|
2930
|
+
const toolTokenGrant = cwd && typeof projectId === 'string' && projectId
|
|
2931
|
+
? toolTokenRegistry.mint({
|
|
2932
|
+
runId,
|
|
2933
|
+
projectId,
|
|
2934
|
+
allowedEndpoints: CHAT_TOOL_ENDPOINTS,
|
|
2935
|
+
allowedOperations: CHAT_TOOL_OPERATIONS,
|
|
2936
|
+
})
|
|
2937
|
+
: null;
|
|
2938
|
+
let toolTokenRevoked = false;
|
|
2939
|
+
const revokeToolToken = (reason) => {
|
|
2940
|
+
if (toolTokenRevoked || !toolTokenGrant)
|
|
2941
|
+
return;
|
|
2942
|
+
toolTokenRevoked = true;
|
|
2943
|
+
toolTokenRegistry.revokeToken(toolTokenGrant.token, reason);
|
|
2944
|
+
};
|
|
2945
|
+
const runtimeToolPrompt = createAgentRuntimeToolPrompt(daemonUrl, toolTokenGrant);
|
|
2946
|
+
const commentHint = renderCommentAttachmentHint(safeCommentAttachments);
|
|
2947
|
+
// Resolve external MCP config + stored OAuth tokens up-front so the
|
|
2948
|
+
// system prompt can warn the model away from Claude Code's synthetic
|
|
2949
|
+
// `*_authenticate` / `*_complete_authentication` tools for any
|
|
2950
|
+
// server the daemon already holds a valid Bearer for. We re-use both
|
|
2951
|
+
// values further down at .mcp.json write time — see the spawn block
|
|
2952
|
+
// below — instead of re-reading.
|
|
2953
|
+
let externalMcpConfig = { servers: [] };
|
|
2954
|
+
try {
|
|
2955
|
+
externalMcpConfig = await readMcpConfig(RUNTIME_DATA_DIR);
|
|
2956
|
+
}
|
|
2957
|
+
catch (err) {
|
|
2958
|
+
console.warn('[mcp-config] read failed:', err && err.message ? err.message : err);
|
|
2959
|
+
}
|
|
2960
|
+
const enabledExternalMcp = externalMcpConfig.servers.filter((s) => s.enabled);
|
|
2961
|
+
const oauthTokensForSpawn = {};
|
|
2962
|
+
try {
|
|
2963
|
+
const stored = await readAllTokens(RUNTIME_DATA_DIR);
|
|
2964
|
+
for (const [serverId, tok] of Object.entries(stored)) {
|
|
2965
|
+
if (!enabledExternalMcp.find((s) => s.id === serverId))
|
|
2966
|
+
continue;
|
|
2967
|
+
// Default to the persisted access token; null it out if expired so
|
|
2968
|
+
// we never inject a stale `Authorization: Bearer …` header. The
|
|
2969
|
+
// model treats a server with a Bearer pinned as connected and
|
|
2970
|
+
// discourages re-auth, which is the worst possible UX when the
|
|
2971
|
+
// token is going to 401 every call.
|
|
2972
|
+
let access = isTokenExpired(tok) ? null : tok.accessToken;
|
|
2973
|
+
if (isTokenExpired(tok) && tok.refreshToken) {
|
|
2974
|
+
try {
|
|
2975
|
+
const refreshed = await refreshAndPersistToken(RUNTIME_DATA_DIR, serverId, tok);
|
|
2976
|
+
if (refreshed)
|
|
2977
|
+
access = refreshed.accessToken;
|
|
2978
|
+
}
|
|
2979
|
+
catch (err) {
|
|
2980
|
+
console.warn('[mcp-oauth] refresh failed for', serverId, err && err.message ? err.message : err);
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
if (access) {
|
|
2984
|
+
oauthTokensForSpawn[serverId] = access;
|
|
2985
|
+
}
|
|
2986
|
+
else {
|
|
2987
|
+
console.warn('[mcp-oauth] skipping expired token for', serverId, '— reconnect required');
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
catch (err) {
|
|
2992
|
+
console.warn('[mcp-tokens] read failed:', err && err.message ? err.message : err);
|
|
2993
|
+
}
|
|
2994
|
+
const connectedExternalMcp = enabledExternalMcp
|
|
2995
|
+
.filter((s) => typeof oauthTokensForSpawn[s.id] === 'string')
|
|
2996
|
+
.map((s) => ({ id: s.id, label: s.label }));
|
|
2997
|
+
const { prompt: daemonSystemPrompt, activeSkillDir, critiqueShouldRun } = await composeDaemonSystemPrompt({
|
|
2998
|
+
agentId,
|
|
2999
|
+
projectId,
|
|
3000
|
+
skillId,
|
|
3001
|
+
designSystemId,
|
|
3002
|
+
streamFormat: def?.streamFormat ?? 'plain',
|
|
3003
|
+
connectedExternalMcp,
|
|
3004
|
+
});
|
|
3005
|
+
// Make skill side files reachable through three layers, in order of
|
|
3006
|
+
// preference. The skill preamble emitted by `withSkillRootPreamble()`
|
|
3007
|
+
// advertises both the cwd-relative path (1) and the absolute path
|
|
3008
|
+
// (2/3) so the agent can pick whichever works.
|
|
3009
|
+
//
|
|
3010
|
+
// 1. CWD-relative copy. Stage the *active* skill into
|
|
3011
|
+
// `<cwd>/.od-skills/<folder>/` so any agent CLI — not just the
|
|
3012
|
+
// ones that honour `--add-dir` — can reach those files via a
|
|
3013
|
+
// path inside its working directory. We copy (not symlink) so
|
|
3014
|
+
// the staged directory is a true write barrier — agents cannot
|
|
3015
|
+
// mutate the shipped repo resource through their cwd.
|
|
3016
|
+
// 2. `--add-dir` allowlist. For non-Codex agents, pass `SKILLS_DIR`
|
|
3017
|
+
// and `DESIGN_SYSTEMS_DIR` so the absolute fallback path in the
|
|
3018
|
+
// preamble is reachable when staging fails (e.g. the project has
|
|
3019
|
+
// no on-disk cwd, or fs.cp errored). Codex treats `--add-dir`
|
|
3020
|
+
// entries as writable, so Codex receives only the narrow
|
|
3021
|
+
// `${CODEX_HOME:-$HOME/.codex}/generated_images` output folder
|
|
3022
|
+
// for allowlisted gpt-image image projects.
|
|
3023
|
+
// 3. PROJECT_ROOT cwd. When `cwd` is null, the agent runs with
|
|
3024
|
+
// `cwd: PROJECT_ROOT` — there the absolute path is already an
|
|
3025
|
+
// in-cwd path, so neither (1) nor (2) is required for it to
|
|
3026
|
+
// resolve.
|
|
3027
|
+
//
|
|
3028
|
+
// Design systems are *not* staged here. Their bodies are read by the
|
|
3029
|
+
// daemon and folded into the system prompt directly (see
|
|
3030
|
+
// `readDesignSystem`), so an agent never has to open them via the
|
|
3031
|
+
// filesystem.
|
|
3032
|
+
if (cwd && activeSkillDir) {
|
|
3033
|
+
const result = await stageActiveSkill(cwd, path.basename(activeSkillDir), activeSkillDir, (msg) => console.warn(msg));
|
|
3034
|
+
if (!result.staged) {
|
|
3035
|
+
console.warn(`[od] skill-stage skipped: ${result.reason ?? 'unknown reason'}; falling back to absolute paths`);
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
// Resolve the agent's effective working directory once and use it
|
|
3039
|
+
// everywhere the agent could read it (buildArgs runtimeContext, spawn
|
|
3040
|
+
// cwd, ACP session new). Falling back to PROJECT_ROOT — rather than
|
|
3041
|
+
// letting `spawn` inherit the daemon process cwd — is what makes the
|
|
3042
|
+
// absolute-path fallback in the skill preamble actually in-cwd for
|
|
3043
|
+
// no-project runs (packaged daemons / service launches do not start
|
|
3044
|
+
// their working directory from the workspace root).
|
|
3045
|
+
const effectiveCwd = cwd ?? PROJECT_ROOT;
|
|
3046
|
+
let codexGeneratedImagesDir = resolveCodexGeneratedImagesDir(agentId, projectRecord?.metadata);
|
|
3047
|
+
if (codexGeneratedImagesDir) {
|
|
3048
|
+
codexGeneratedImagesDir = validateCodexGeneratedImagesDir(codexGeneratedImagesDir, {
|
|
3049
|
+
protectedDirs: [SKILLS_DIR, DESIGN_SYSTEMS_DIR, ...linkedDirs],
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
const extraAllowedDirs = resolveChatExtraAllowedDirs({
|
|
3053
|
+
agentId,
|
|
3054
|
+
skillsDir: SKILLS_DIR,
|
|
3055
|
+
designSystemsDir: DESIGN_SYSTEMS_DIR,
|
|
3056
|
+
linkedDirs,
|
|
3057
|
+
codexGeneratedImagesDir,
|
|
3058
|
+
});
|
|
3059
|
+
const codexImagegenOverride = resolveGrantedCodexImagegenOverride({
|
|
3060
|
+
agentId,
|
|
3061
|
+
metadata: projectRecord?.metadata,
|
|
3062
|
+
codexGeneratedImagesDir,
|
|
3063
|
+
extraAllowedDirs,
|
|
3064
|
+
});
|
|
3065
|
+
const researchCommandContract = resolveResearchCommandContract(research, message);
|
|
3066
|
+
const clientInstructionPrompt = [researchCommandContract, systemPrompt]
|
|
3067
|
+
.map((part) => (typeof part === 'string' ? part.trim() : ''))
|
|
3068
|
+
.filter(Boolean)
|
|
3069
|
+
.join('\n\n---\n\n');
|
|
3070
|
+
const instructionPrompt = composeLiveInstructionPrompt({
|
|
3071
|
+
daemonSystemPrompt,
|
|
3072
|
+
runtimeToolPrompt,
|
|
3073
|
+
clientSystemPrompt: clientInstructionPrompt,
|
|
3074
|
+
finalPromptOverride: codexImagegenOverride,
|
|
3075
|
+
});
|
|
3076
|
+
const composed = [
|
|
3077
|
+
instructionPrompt
|
|
3078
|
+
? `# Instructions (read first)\n\n${instructionPrompt}${cwdHint}${linkedDirsHint}\n\n---\n`
|
|
3079
|
+
: cwdHint
|
|
3080
|
+
? `# Instructions${cwdHint}${linkedDirsHint}\n\n---\n`
|
|
3081
|
+
: linkedDirsHint
|
|
3082
|
+
? `# Instructions${linkedDirsHint}\n\n---\n`
|
|
3083
|
+
: '',
|
|
3084
|
+
`# User request\n\n${message || '(No extra typed instruction.)'}${attachmentHint}${commentHint}`,
|
|
3085
|
+
safeImages.length
|
|
3086
|
+
? `\n\n${safeImages.map((p) => `@${p}`).join(' ')}`
|
|
3087
|
+
: '',
|
|
3088
|
+
].join('');
|
|
3089
|
+
// Per-agent model + reasoning the user picked in the model menu.
|
|
3090
|
+
// Trust the value when it matches the most recent /api/agents listing
|
|
3091
|
+
// (live or fallback). Otherwise allow it through if it passes a
|
|
3092
|
+
// permissive sanitizer — that's the path for user-typed custom model
|
|
3093
|
+
// ids the CLI's listing didn't surface yet.
|
|
3094
|
+
const safeModel = typeof model === 'string'
|
|
3095
|
+
? isKnownModel(def, model)
|
|
3096
|
+
? model
|
|
3097
|
+
: sanitizeCustomModel(model)
|
|
3098
|
+
: null;
|
|
3099
|
+
const safeReasoning = typeof reasoning === 'string' && Array.isArray(def.reasoningOptions)
|
|
3100
|
+
? (def.reasoningOptions.find((r) => r.id === reasoning)?.id ?? null)
|
|
3101
|
+
: null;
|
|
3102
|
+
const agentOptions = { model: safeModel, reasoning: safeReasoning };
|
|
3103
|
+
const mcpServers = buildLiveArtifactsMcpServersForAgent(def, {
|
|
3104
|
+
enabled: Boolean(toolTokenGrant?.token),
|
|
3105
|
+
command: process.execPath,
|
|
3106
|
+
argsPrefix: [OD_BIN],
|
|
3107
|
+
});
|
|
3108
|
+
// External MCP servers configured by the user in Settings → External MCP.
|
|
3109
|
+
// Open Design relays them to the agent so the model can call those tools.
|
|
3110
|
+
// Two delivery shapes today:
|
|
3111
|
+
// - Claude Code: write a `.mcp.json` into the project cwd. Claude Code
|
|
3112
|
+
// auto-loads that file at spawn (same format the CLI accepts via
|
|
3113
|
+
// `claude mcp add` + Claude Desktop's config). Fire-and-forget; we
|
|
3114
|
+
// deliberately do NOT block spawn on a write failure since the agent
|
|
3115
|
+
// can still run without external tools — log a warning and continue.
|
|
3116
|
+
// - ACP agents (Hermes/Kimi): merge stdio entries into the existing
|
|
3117
|
+
// `mcpServers` array; SSE/HTTP entries are skipped because ACP's
|
|
3118
|
+
// stdio-only descriptor can't represent them yet.
|
|
3119
|
+
// Other agents (Codex, Gemini, OpenCode, Cursor, Qwen, Qoder, Copilot,
|
|
3120
|
+
// Pi, DeepSeek) inherit the user's per-CLI MCP config from their own
|
|
3121
|
+
// home dir for now — a future change can grow this list.
|
|
3122
|
+
//
|
|
3123
|
+
// The MCP config + OAuth tokens were resolved earlier (above
|
|
3124
|
+
// composeDaemonSystemPrompt) so the system prompt could mention any
|
|
3125
|
+
// already-authenticated servers; we reuse `enabledExternalMcp` and
|
|
3126
|
+
// `oauthTokensForSpawn` here for the Claude `.mcp.json` write +
|
|
3127
|
+
// ACP merge so we don't pay for a second filesystem read.
|
|
3128
|
+
//
|
|
3129
|
+
// Claude Code: write `.mcp.json` to the daemon-managed project cwd before
|
|
3130
|
+
// spawn so Claude Code auto-loads the user's external MCP servers. Strict
|
|
3131
|
+
// gating is essential here:
|
|
3132
|
+
// - cwd must be set (no project → no `.mcp.json` write).
|
|
3133
|
+
// - cwd must live UNDER PROJECTS_DIR. We never write to a git-linked
|
|
3134
|
+
// baseDir (= the user's own repo), since that would silently overwrite
|
|
3135
|
+
// a hand-crafted .mcp.json the user already keeps in their source tree.
|
|
3136
|
+
// We also unlink a stale `.mcp.json` we previously wrote when the user has
|
|
3137
|
+
// since disabled all servers, so removing a server actually takes effect
|
|
3138
|
+
// on the next run.
|
|
3139
|
+
if (def.id === 'claude' && isManagedProjectCwd(cwd, PROJECTS_DIR)) {
|
|
3140
|
+
{
|
|
3141
|
+
const target = path.join(cwd, '.mcp.json');
|
|
3142
|
+
if (enabledExternalMcp.length > 0) {
|
|
3143
|
+
try {
|
|
3144
|
+
const claudeMcp = buildClaudeMcpJson(enabledExternalMcp, oauthTokensForSpawn);
|
|
3145
|
+
if (claudeMcp) {
|
|
3146
|
+
await fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
3147
|
+
await fs.promises.writeFile(target, JSON.stringify(claudeMcp, null, 2), 'utf8');
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
catch (err) {
|
|
3151
|
+
console.warn('[mcp-config] failed to write project .mcp.json:', err && err.message ? err.message : err);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
else {
|
|
3155
|
+
try {
|
|
3156
|
+
await fs.promises.unlink(target);
|
|
3157
|
+
}
|
|
3158
|
+
catch (err) {
|
|
3159
|
+
if ((err && err.code) !== 'ENOENT') {
|
|
3160
|
+
console.warn('[mcp-config] failed to remove stale .mcp.json:', err && err.message ? err.message : err);
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
if (enabledExternalMcp.length > 0 && def.streamFormat === 'acp-json-rpc') {
|
|
3167
|
+
const acpExternal = buildAcpMcpServers(enabledExternalMcp);
|
|
3168
|
+
mcpServers.push(...acpExternal);
|
|
3169
|
+
}
|
|
3170
|
+
// Pre-flight the composed prompt against any argv-byte budget the
|
|
3171
|
+
// adapter declared (only DeepSeek TUI today — its CLI doesn't accept
|
|
3172
|
+
// a `-` stdin sentinel, so the prompt has to ride argv). Doing this
|
|
3173
|
+
// before bin resolution means the test harness pins the guard
|
|
3174
|
+
// independently of whether the adapter binary happens to be on PATH
|
|
3175
|
+
// in the CI environment, and the user gets the actionable
|
|
3176
|
+
// adapter-named error even if /api/agents hadn't refreshed yet.
|
|
3177
|
+
const promptBudgetError = checkPromptArgvBudget(def, composed);
|
|
3178
|
+
if (promptBudgetError) {
|
|
3179
|
+
design.runs.emit(run, 'error', createSseErrorPayload(promptBudgetError.code, promptBudgetError.message, { retryable: false }));
|
|
3180
|
+
return design.runs.finish(run, 'failed', 1, null);
|
|
3181
|
+
}
|
|
3182
|
+
let configuredAgentEnv = {};
|
|
3183
|
+
try {
|
|
3184
|
+
const appConfig = await readAppConfig(RUNTIME_DATA_DIR);
|
|
3185
|
+
configuredAgentEnv = agentCliEnvForAgent(appConfig.agentCliEnv, def.id);
|
|
3186
|
+
}
|
|
3187
|
+
catch {
|
|
3188
|
+
configuredAgentEnv = {};
|
|
3189
|
+
}
|
|
3190
|
+
const agentLaunch = resolveAgentLaunch(def, configuredAgentEnv);
|
|
3191
|
+
const resolvedBin = agentLaunch.selectedPath;
|
|
3192
|
+
const args = def.buildArgs(composed, safeImages, extraAllowedDirs, agentOptions, { cwd: effectiveCwd });
|
|
3193
|
+
// Second-pass budget check that knows about the Windows `.cmd` shim
|
|
3194
|
+
// wrap. The pre-buildArgs `checkPromptArgvBudget` only looks at the
|
|
3195
|
+
// raw composed prompt; on Windows an npm-installed adapter resolves
|
|
3196
|
+
// to e.g. `deepseek.cmd`, the spawn path goes through `cmd.exe /d /s
|
|
3197
|
+
// /c "<inner>"`, and `quoteForWindowsCmdShim` doubles every embedded
|
|
3198
|
+
// `"` plus wraps any whitespace/special-char arg in outer quotes —
|
|
3199
|
+
// so a quote-heavy prompt that fit under `maxPromptArgBytes` can
|
|
3200
|
+
// still expand past CreateProcess's 32_767-char cap. Fail fast with
|
|
3201
|
+
// the same `AGENT_PROMPT_TOO_LARGE` shape so the SSE error path
|
|
3202
|
+
// doesn't have to special-case it.
|
|
3203
|
+
const cmdShimBudgetError = checkWindowsCmdShimCommandLineBudget(def, agentLaunch.launchPath ?? resolvedBin, args);
|
|
3204
|
+
if (cmdShimBudgetError) {
|
|
3205
|
+
design.runs.emit(run, 'error', createSseErrorPayload(cmdShimBudgetError.code, cmdShimBudgetError.message, { retryable: false }));
|
|
3206
|
+
return design.runs.finish(run, 'failed', 1, null);
|
|
3207
|
+
}
|
|
3208
|
+
// Companion guard for non-shim Windows installs (e.g. a cargo-built
|
|
3209
|
+
// `deepseek.exe` rather than the npm `.cmd` shim). Direct `.exe`
|
|
3210
|
+
// spawns skip the cmd.exe wrap above, but Node/libuv still composes
|
|
3211
|
+
// a CreateProcess `lpCommandLine` by walking each argv element
|
|
3212
|
+
// through `quote_cmd_arg`, which escapes every embedded `"` as `\"`
|
|
3213
|
+
// and doubles backslashes adjacent to quotes. A quote-heavy prompt
|
|
3214
|
+
// under `maxPromptArgBytes` can expand past the 32_767-char kernel
|
|
3215
|
+
// cap there too, so the cmd-shim early-return alone would let those
|
|
3216
|
+
// users hit a generic `spawn ENAMETOOLONG`.
|
|
3217
|
+
const directExeBudgetError = checkWindowsDirectExeCommandLineBudget(def, agentLaunch.launchPath ?? resolvedBin, args);
|
|
3218
|
+
if (directExeBudgetError) {
|
|
3219
|
+
design.runs.emit(run, 'error', createSseErrorPayload(directExeBudgetError.code, directExeBudgetError.message, { retryable: false }));
|
|
3220
|
+
return design.runs.finish(run, 'failed', 1, null);
|
|
3221
|
+
}
|
|
3222
|
+
const send = (event, data) => design.runs.emit(run, event, data);
|
|
3223
|
+
const inactivityTimeoutMs = resolveChatRunInactivityTimeoutMs();
|
|
3224
|
+
const inactivityKillGraceMs = 3_000;
|
|
3225
|
+
let inactivityTimer = null;
|
|
3226
|
+
let childStdoutSeen = false;
|
|
3227
|
+
let lastAgentEventPhase = 'spawn pending';
|
|
3228
|
+
let lastToolResultChars = 0;
|
|
3229
|
+
const summarizeAgentEventForInactivity = (payload) => {
|
|
3230
|
+
const type = payload?.type ? String(payload.type) : 'unknown';
|
|
3231
|
+
if (type === 'tool_result') {
|
|
3232
|
+
const content = typeof payload.content === 'string' ? payload.content : '';
|
|
3233
|
+
lastToolResultChars = Math.max(lastToolResultChars, content.length);
|
|
3234
|
+
return `tool_result:${content.length} chars`;
|
|
3235
|
+
}
|
|
3236
|
+
if (type === 'tool_use') {
|
|
3237
|
+
const name = payload?.name ? String(payload.name) : 'unknown';
|
|
3238
|
+
return `tool_use:${name}`;
|
|
3239
|
+
}
|
|
3240
|
+
if (type === 'text_delta' || type === 'thinking_delta') {
|
|
3241
|
+
const text = typeof payload.text === 'string' ? payload.text : '';
|
|
3242
|
+
return `${type}:${text.length} chars`;
|
|
3243
|
+
}
|
|
3244
|
+
return type;
|
|
3245
|
+
};
|
|
3246
|
+
const clearInactivityWatchdog = () => {
|
|
3247
|
+
if (inactivityTimer) {
|
|
3248
|
+
clearTimeout(inactivityTimer);
|
|
3249
|
+
inactivityTimer = null;
|
|
3250
|
+
}
|
|
3251
|
+
};
|
|
3252
|
+
const scheduleForcedChildShutdown = () => {
|
|
3253
|
+
if (!child)
|
|
3254
|
+
return;
|
|
3255
|
+
setTimeout(() => {
|
|
3256
|
+
if (child && !child.killed)
|
|
3257
|
+
child.kill('SIGTERM');
|
|
3258
|
+
}, inactivityKillGraceMs).unref?.();
|
|
3259
|
+
setTimeout(() => {
|
|
3260
|
+
if (child && !child.killed)
|
|
3261
|
+
child.kill('SIGKILL');
|
|
3262
|
+
}, inactivityKillGraceMs * 2).unref?.();
|
|
3263
|
+
};
|
|
3264
|
+
const failForInactivity = () => {
|
|
3265
|
+
if (run.cancelRequested || design.runs.isTerminal(run.status))
|
|
3266
|
+
return;
|
|
3267
|
+
const message = `Agent stalled without emitting any new output for ${Math.round(inactivityTimeoutMs / 1000)}s. ` +
|
|
3268
|
+
'The model or CLI likely hung while generating. ' +
|
|
3269
|
+
`Phase details: spawned agent binary ${resolvedBin}; stdout arrived: ${childStdoutSeen ? 'yes' : 'no'}; ` +
|
|
3270
|
+
`last agent event: ${lastAgentEventPhase}; largest tool result observed: ${lastToolResultChars} chars. ` +
|
|
3271
|
+
'Retry the turn, pick a different model, or start a new conversation if the prior context is very large.';
|
|
3272
|
+
clearInactivityWatchdog();
|
|
3273
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', message, { retryable: true }));
|
|
3274
|
+
design.runs.finish(run, 'failed', 1, null);
|
|
3275
|
+
if (acpSession?.abort) {
|
|
3276
|
+
acpSession.abort();
|
|
3277
|
+
}
|
|
3278
|
+
if (child && !child.killed)
|
|
3279
|
+
child.kill('SIGTERM');
|
|
3280
|
+
scheduleForcedChildShutdown();
|
|
3281
|
+
};
|
|
3282
|
+
const noteAgentActivity = () => {
|
|
3283
|
+
if (inactivityTimeoutMs <= 0)
|
|
3284
|
+
return;
|
|
3285
|
+
clearInactivityWatchdog();
|
|
3286
|
+
inactivityTimer = setTimeout(failForInactivity, inactivityTimeoutMs);
|
|
3287
|
+
inactivityTimer.unref?.();
|
|
3288
|
+
};
|
|
3289
|
+
const unregisterChatAgentEventSink = () => {
|
|
3290
|
+
activeChatAgentEventSinks.delete(toolTokenGrant?.runId ?? runId);
|
|
3291
|
+
};
|
|
3292
|
+
if (toolTokenGrant?.runId) {
|
|
3293
|
+
activeChatAgentEventSinks.set(toolTokenGrant.runId, (payload) => {
|
|
3294
|
+
lastAgentEventPhase = summarizeAgentEventForInactivity(payload);
|
|
3295
|
+
noteAgentActivity();
|
|
3296
|
+
send('agent', payload);
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3299
|
+
// If detection can't find the binary, surface a friendly SSE error
|
|
3300
|
+
// pointing at /api/agents instead of silently falling back to
|
|
3301
|
+
// spawn(def.bin) — that fallback re-introduces the exact ENOENT symptom
|
|
3302
|
+
// from issue #10.
|
|
3303
|
+
if (!resolvedBin || !agentLaunch.launchPath) {
|
|
3304
|
+
revokeToolToken('child_exit');
|
|
3305
|
+
unregisterChatAgentEventSink();
|
|
3306
|
+
send('error', createSseErrorPayload('AGENT_UNAVAILABLE', `Agent "${def.name}" (\`${def.bin}\`) is not installed or not on PATH. ` +
|
|
3307
|
+
'Install it and refresh the agent list (GET /api/agents) before retrying.', { retryable: true }));
|
|
3308
|
+
return design.runs.finish(run, 'failed', 1, null);
|
|
3309
|
+
}
|
|
3310
|
+
const odMediaEnv = {
|
|
3311
|
+
OD_BIN,
|
|
3312
|
+
OD_NODE_BIN,
|
|
3313
|
+
OD_DAEMON_URL: daemonUrl,
|
|
3314
|
+
...(typeof projectId === 'string' && projectId && cwd
|
|
3315
|
+
? {
|
|
3316
|
+
OD_PROJECT_ID: projectId,
|
|
3317
|
+
OD_PROJECT_DIR: cwd,
|
|
3318
|
+
}
|
|
3319
|
+
: {}),
|
|
3320
|
+
};
|
|
3321
|
+
if (run.cancelRequested || design.runs.isTerminal(run.status)) {
|
|
3322
|
+
revokeToolToken('child_exit');
|
|
3323
|
+
unregisterChatAgentEventSink();
|
|
3324
|
+
return;
|
|
3325
|
+
}
|
|
3326
|
+
run.status = 'running';
|
|
3327
|
+
run.updatedAt = Date.now();
|
|
3328
|
+
send('start', {
|
|
3329
|
+
runId,
|
|
3330
|
+
agentId,
|
|
3331
|
+
bin: resolvedBin,
|
|
3332
|
+
streamFormat: def.streamFormat ?? 'plain',
|
|
3333
|
+
projectId: typeof projectId === 'string' ? projectId : null,
|
|
3334
|
+
cwd,
|
|
3335
|
+
model: safeModel,
|
|
3336
|
+
reasoning: safeReasoning,
|
|
3337
|
+
toolTokenExpiresAt: toolTokenGrant?.expiresAt ?? null,
|
|
3338
|
+
});
|
|
3339
|
+
noteAgentActivity();
|
|
3340
|
+
let child;
|
|
3341
|
+
let acpSession = null;
|
|
3342
|
+
let writePromptToChildStdin = false;
|
|
3343
|
+
let spawnedAgentEnv = null;
|
|
3344
|
+
let agentStdoutTail = '';
|
|
3345
|
+
let agentStderrTail = '';
|
|
3346
|
+
try {
|
|
3347
|
+
// Prompt delivery via stdin is now the universal default. This bypasses
|
|
3348
|
+
// both the cmd.exe 8KB limit and the CreateProcess 32KB limit.
|
|
3349
|
+
const stdinMode = def.promptViaStdin || def.streamFormat === 'acp-json-rpc'
|
|
3350
|
+
? 'pipe'
|
|
3351
|
+
: 'ignore';
|
|
3352
|
+
const env = applyAgentLaunchEnv({
|
|
3353
|
+
...spawnEnvForAgent(def.id, {
|
|
3354
|
+
...createAgentRuntimeEnv(process.env, daemonUrl, toolTokenGrant),
|
|
3355
|
+
...(def.env || {}),
|
|
3356
|
+
}, configuredAgentEnv),
|
|
3357
|
+
...odMediaEnv,
|
|
3358
|
+
}, agentLaunch);
|
|
3359
|
+
spawnedAgentEnv = env;
|
|
3360
|
+
const invocation = createCommandInvocation({
|
|
3361
|
+
command: agentLaunch.launchPath,
|
|
3362
|
+
args,
|
|
3363
|
+
env,
|
|
3364
|
+
});
|
|
3365
|
+
child = spawn(invocation.command, invocation.args, {
|
|
3366
|
+
env,
|
|
3367
|
+
stdio: [stdinMode, 'pipe', 'pipe'],
|
|
3368
|
+
cwd: effectiveCwd,
|
|
3369
|
+
shell: false,
|
|
3370
|
+
// Required when invocation wraps a Windows .cmd/.bat shim through
|
|
3371
|
+
// cmd.exe; without this, Node re-escapes the inner command line and
|
|
3372
|
+
// breaks paths containing spaces (issue #315).
|
|
3373
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
3374
|
+
});
|
|
3375
|
+
run.child = child;
|
|
3376
|
+
if (def.promptViaStdin && child.stdin && def.streamFormat !== 'pi-rpc') {
|
|
3377
|
+
// EPIPE from a fast-exiting CLI (bad auth, missing model, exit on
|
|
3378
|
+
// launch) would otherwise surface as an unhandled stream error and
|
|
3379
|
+
// crash the daemon. Swallow it — the regular exit/close handlers
|
|
3380
|
+
// below already route the underlying failure to SSE via stderr.
|
|
3381
|
+
child.stdin.on('error', (err) => {
|
|
3382
|
+
if (err.code !== 'EPIPE') {
|
|
3383
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', `stdin: ${err.message}`));
|
|
3384
|
+
}
|
|
3385
|
+
});
|
|
3386
|
+
writePromptToChildStdin = true;
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
catch (err) {
|
|
3390
|
+
revokeToolToken('child_exit');
|
|
3391
|
+
unregisterChatAgentEventSink();
|
|
3392
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', `spawn failed: ${err.message}`));
|
|
3393
|
+
design.runs.finish(run, 'failed', 1, null);
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
child.stdout.setEncoding('utf8');
|
|
3397
|
+
child.stderr.setEncoding('utf8');
|
|
3398
|
+
// Reset the inactivity watchdog on every raw stdout byte so that
|
|
3399
|
+
// structured adapters that buffer partial lines (Codex item.completed,
|
|
3400
|
+
// pi-rpc session/prompt, ACP agent messages) and models that spend a
|
|
3401
|
+
// long time in non-streamed reasoning still keep the run alive.
|
|
3402
|
+
child.stdout.on('data', (chunk) => {
|
|
3403
|
+
childStdoutSeen = true;
|
|
3404
|
+
noteAgentActivity();
|
|
3405
|
+
agentStdoutTail = `${agentStdoutTail}${chunk}`.slice(-2000);
|
|
3406
|
+
});
|
|
3407
|
+
// ---- Memory: assistant-reply buffer for LLM extraction --------------
|
|
3408
|
+
// Capture up to 32 KiB of raw stdout. The LLM extractor (fired in the
|
|
3409
|
+
// close handler) trims further; we only need enough to ground the
|
|
3410
|
+
// model. Multiple `on('data')` listeners coexist — the wrapper-stream
|
|
3411
|
+
// handlers below also subscribe and that's fine.
|
|
3412
|
+
const MEMORY_BUFFER_CAP = 32 * 1024;
|
|
3413
|
+
let memoryAssistantBuffer = '';
|
|
3414
|
+
child.stdout.on('data', (chunk) => {
|
|
3415
|
+
if (memoryAssistantBuffer.length >= MEMORY_BUFFER_CAP)
|
|
3416
|
+
return;
|
|
3417
|
+
memoryAssistantBuffer += String(chunk);
|
|
3418
|
+
if (memoryAssistantBuffer.length > MEMORY_BUFFER_CAP) {
|
|
3419
|
+
memoryAssistantBuffer = memoryAssistantBuffer.slice(0, MEMORY_BUFFER_CAP);
|
|
3420
|
+
}
|
|
3421
|
+
});
|
|
3422
|
+
child.on('close', () => {
|
|
3423
|
+
const captured = memoryAssistantBuffer;
|
|
3424
|
+
const userMsg = typeof message === 'string' ? message : '';
|
|
3425
|
+
// Forward the chat agent id so memory-llm.pickProvider can
|
|
3426
|
+
// constrain its auto-pick to the chat protocol's family — keeps
|
|
3427
|
+
// a Claude Code (anthropic) chat from triggering OpenAI/gpt-4o-
|
|
3428
|
+
// mini extraction in the background just because the user has
|
|
3429
|
+
// an OpenAI key parked in media-config.
|
|
3430
|
+
void import('./memory-llm.js')
|
|
3431
|
+
.then(({ extractWithLLM }) => extractWithLLM(RUNTIME_DATA_DIR, {
|
|
3432
|
+
userMessage: userMsg,
|
|
3433
|
+
assistantMessage: captured,
|
|
3434
|
+
}, {
|
|
3435
|
+
projectRoot: PROJECT_ROOT,
|
|
3436
|
+
chatAgentId: typeof agentId === 'string' ? agentId : null,
|
|
3437
|
+
}))
|
|
3438
|
+
.catch((err) => console.warn('[memory-llm] background failed', err));
|
|
3439
|
+
});
|
|
3440
|
+
// Critique Theater branch (M0 dark launch, default disabled).
|
|
3441
|
+
// Only plain-stream adapters are routed through runOrchestrator in v1.
|
|
3442
|
+
// Adapters that emit structured wrappers (claude-stream-json,
|
|
3443
|
+
// qoder-stream-json, copilot-stream-json, json-event-stream,
|
|
3444
|
+
// acp-json-rpc, pi-rpc) fall
|
|
3445
|
+
// through to the legacy single-pass code path below with a one-time
|
|
3446
|
+
// stderr warning so the parser never sees wrapper bytes. Per-format
|
|
3447
|
+
// decoding into the orchestrator is a v2 concern.
|
|
3448
|
+
//
|
|
3449
|
+
// Use critiqueShouldRun (computed in the prompt builder) instead of
|
|
3450
|
+
// just the env var or the rollout resolver so the orchestrator gate
|
|
3451
|
+
// is in lockstep with the panel addendum. Media surfaces and runs
|
|
3452
|
+
// missing brand/skill context never get the panel prompt, so they
|
|
3453
|
+
// must also skip the orchestrator and fall through to legacy
|
|
3454
|
+
// generation; otherwise the parser waits for <CRITIQUE_RUN> tags
|
|
3455
|
+
// the model was never told to emit.
|
|
3456
|
+
if (critiqueShouldRun) {
|
|
3457
|
+
const adapterStreamFormat = def.streamFormat ?? 'plain';
|
|
3458
|
+
if (adapterStreamFormat !== 'plain') {
|
|
3459
|
+
if (!critiqueWarnedAdapters.has(adapterStreamFormat)) {
|
|
3460
|
+
critiqueWarnedAdapters.add(adapterStreamFormat);
|
|
3461
|
+
console.warn(`[critique] adapter format=${adapterStreamFormat} is not plain-stream; skipping orchestrator and falling through to legacy generation`);
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
else {
|
|
3465
|
+
const critiqueRunId = run.id;
|
|
3466
|
+
// Per-run artifact directory keeps concurrent or sequential runs in the
|
|
3467
|
+
// same project from overwriting each other's transcript or final HTML.
|
|
3468
|
+
// Spec: artifacts/<projectId>/<runId>/transcript.ndjson(.gz).
|
|
3469
|
+
const critiqueProjectKey = typeof projectId === 'string' && projectId ? projectId : critiqueRunId;
|
|
3470
|
+
const critiqueArtifactDir = path.join(ARTIFACTS_DIR, critiqueProjectKey, critiqueRunId);
|
|
3471
|
+
const stdoutIterable = (async function* () {
|
|
3472
|
+
for await (const chunk of child.stdout)
|
|
3473
|
+
yield String(chunk);
|
|
3474
|
+
})();
|
|
3475
|
+
// Forward each CritiqueSseEvent on its own contract-defined channel
|
|
3476
|
+
// (critique.run_started, critique.ship, critique.failed, ...) rather
|
|
3477
|
+
// than wrapping the frame inside the legacy 'agent' channel. Clients
|
|
3478
|
+
// that subscribe to the new event names see them directly with the
|
|
3479
|
+
// contract payload as event.data.
|
|
3480
|
+
//
|
|
3481
|
+
// Critique events go to TWO sinks (codex P1 on PR #1338):
|
|
3482
|
+
//
|
|
3483
|
+
// 1. `design.runs.emit(...)` via `send(...)`, which fans out on
|
|
3484
|
+
// `/api/runs/:runId/events`. Existing transport, unchanged.
|
|
3485
|
+
// 2. The per-project event-sinks map, which fans out on
|
|
3486
|
+
// `/api/projects/:projectId/events`. This is the transport the
|
|
3487
|
+
// web `CritiqueTheaterMount` actually subscribes to (the mount
|
|
3488
|
+
// is project-scoped, not run-scoped, because it lives at the
|
|
3489
|
+
// project workspace level and follows the user across runs).
|
|
3490
|
+
// Without this second sink the mount sees no frames in
|
|
3491
|
+
// production and only the e2e tests' stubbed routes deliver
|
|
3492
|
+
// anything to the reducer.
|
|
3493
|
+
//
|
|
3494
|
+
// The project-events route emits via `sse.send(payload.type,
|
|
3495
|
+
// payload)`, so we pack the SSE channel name onto `payload.type`
|
|
3496
|
+
// and let the sink push the right channel name. The web's
|
|
3497
|
+
// `sseToPanelEvent` overwrites `type` from the channel name on the
|
|
3498
|
+
// way back into a PanelEvent, so this round-trip stays correct.
|
|
3499
|
+
const critiqueProjectIdForBus = typeof projectId === 'string' && projectId ? projectId : null;
|
|
3500
|
+
const critiqueBus = {
|
|
3501
|
+
emit: (e) => {
|
|
3502
|
+
// Two transports for every critique event: the run-scoped
|
|
3503
|
+
// SSE send back to the originating chat run, plus the
|
|
3504
|
+
// project-scoped fan-out so the Theater mount (subscribed
|
|
3505
|
+
// to /api/projects/:id/events) sees it too. Route the
|
|
3506
|
+
// project fan-out through emitProjectEvent so empty-sink
|
|
3507
|
+
// cleanup and any future broadcast policy (rate limiting,
|
|
3508
|
+
// schema validation, telemetry) apply uniformly across
|
|
3509
|
+
// every project emitter (PerishCode P3 on PR #1338).
|
|
3510
|
+
send(e.event, e.data);
|
|
3511
|
+
if (critiqueProjectIdForBus) {
|
|
3512
|
+
emitProjectEvent(critiqueProjectIdForBus, { ...e.data, type: e.event });
|
|
3513
|
+
}
|
|
3514
|
+
},
|
|
3515
|
+
};
|
|
3516
|
+
// Register this run with the in-process registry so the interrupt
|
|
3517
|
+
// endpoint can cascade an AbortController to the orchestrator. The
|
|
3518
|
+
// register call must run BEFORE runOrchestrator is invoked, so a
|
|
3519
|
+
// request that arrives between spawn and orchestrator-start cannot
|
|
3520
|
+
// miss a runId that already has a live child process.
|
|
3521
|
+
const critiqueAbort = new AbortController();
|
|
3522
|
+
critiqueRunRegistry.register({
|
|
3523
|
+
runId: critiqueRunId,
|
|
3524
|
+
projectId: critiqueProjectKey,
|
|
3525
|
+
abort: critiqueAbort,
|
|
3526
|
+
startedAt: Date.now(),
|
|
3527
|
+
});
|
|
3528
|
+
// Stderr forwarding and child.on('error') must be wired BEFORE the
|
|
3529
|
+
// orchestrator awaits stdout. Otherwise a CLI that floods stderr can
|
|
3530
|
+
// fill the OS pipe and deadlock the run until the total timeout, and
|
|
3531
|
+
// an early child error fired before the orchestrator returns has no
|
|
3532
|
+
// listener. Both registrations are idempotent and the run lifecycle
|
|
3533
|
+
// is owned solely by the orchestrator's awaited result below.
|
|
3534
|
+
child.stderr.on('data', (chunk) => {
|
|
3535
|
+
noteAgentActivity();
|
|
3536
|
+
send('stderr', { chunk });
|
|
3537
|
+
});
|
|
3538
|
+
child.on('error', (err) => {
|
|
3539
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', err.message));
|
|
3540
|
+
});
|
|
3541
|
+
// Wrap the child's close event so the orchestrator can race child
|
|
3542
|
+
// exit against parser completion, abort, and timeouts in one awaited
|
|
3543
|
+
// flow. Without this the orchestrator can't tell a non-zero exit
|
|
3544
|
+
// apart from a clean ship and may misclassify failures.
|
|
3545
|
+
const childExitPromise = new Promise((resolve) => {
|
|
3546
|
+
child.once('close', (code, signal) => resolve({ code, signal }));
|
|
3547
|
+
});
|
|
3548
|
+
try {
|
|
3549
|
+
const orchestratorResult = await runOrchestrator({
|
|
3550
|
+
runId: critiqueRunId,
|
|
3551
|
+
projectId: typeof projectId === 'string' ? projectId : '',
|
|
3552
|
+
conversationId: typeof conversationId === 'string' ? conversationId : null,
|
|
3553
|
+
artifactId: critiqueRunId,
|
|
3554
|
+
artifactDir: critiqueArtifactDir,
|
|
3555
|
+
adapter: typeof agentId === 'string' ? agentId : 'unknown',
|
|
3556
|
+
// Codex P2 on PR #1485: thread the resolved skill id into the
|
|
3557
|
+
// orchestrator so the Phase 12 metrics carry the real label
|
|
3558
|
+
// instead of falling through to 'unknown' for every live run.
|
|
3559
|
+
// `effectiveSkillId` was already computed above (line ~2951) as
|
|
3560
|
+
// the request skillId with a project-row fallback; pass it
|
|
3561
|
+
// through verbatim, and leave the orchestrator's own default
|
|
3562
|
+
// of 'unknown' for runs that genuinely have no skill assigned.
|
|
3563
|
+
skill: typeof effectiveSkillId === 'string' && effectiveSkillId
|
|
3564
|
+
? effectiveSkillId
|
|
3565
|
+
: undefined,
|
|
3566
|
+
cfg: critiqueCfg,
|
|
3567
|
+
db,
|
|
3568
|
+
bus: critiqueBus,
|
|
3569
|
+
stdout: stdoutIterable,
|
|
3570
|
+
child,
|
|
3571
|
+
childExitPromise,
|
|
3572
|
+
signal: critiqueAbort.signal,
|
|
3573
|
+
});
|
|
3574
|
+
// Map the critique terminal status to the chat run lifecycle.
|
|
3575
|
+
// 'shipped' and 'below_threshold' both ran to a ship decision and
|
|
3576
|
+
// finalize as 'succeeded'; every other status (timed_out,
|
|
3577
|
+
// interrupted, degraded, failed, legacy) is a failure path so the
|
|
3578
|
+
// run reflects the real outcome instead of a misleading success.
|
|
3579
|
+
const succeeded = orchestratorResult.status === 'shipped'
|
|
3580
|
+
|| orchestratorResult.status === 'below_threshold';
|
|
3581
|
+
if (run.cancelRequested) {
|
|
3582
|
+
design.runs.finish(run, 'canceled', 1, null);
|
|
3583
|
+
}
|
|
3584
|
+
else if (succeeded) {
|
|
3585
|
+
design.runs.finish(run, 'succeeded', 0, null);
|
|
3586
|
+
}
|
|
3587
|
+
else {
|
|
3588
|
+
design.runs.finish(run, 'failed', 1, null);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
catch (err) {
|
|
3592
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', err instanceof Error ? err.message : String(err)));
|
|
3593
|
+
design.runs.finish(run, 'failed', 1, null);
|
|
3594
|
+
}
|
|
3595
|
+
finally {
|
|
3596
|
+
critiqueRunRegistry.unregister(critiqueProjectKey, critiqueRunId);
|
|
3597
|
+
}
|
|
3598
|
+
return;
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
// Structured streams (Claude Code) go through a line-delimited JSON
|
|
3602
|
+
// parser that turns stream_event objects into UI-friendly events. For
|
|
3603
|
+
// plain streams (most other CLIs) we forward raw chunks unchanged so
|
|
3604
|
+
// the browser can append them to the assistant's text buffer.
|
|
3605
|
+
let agentStreamError = null;
|
|
3606
|
+
// Tracks whether any stream the run is using actually emitted user-
|
|
3607
|
+
// visible content. Only the streams routed through `sendAgentEvent`
|
|
3608
|
+
// contribute to this flag; ACP sessions and plain stdout streams are
|
|
3609
|
+
// covered by their own success/failure paths and the empty-output
|
|
3610
|
+
// guard below skips them via `trackingSubstantiveOutput`.
|
|
3611
|
+
let agentProducedOutput = false;
|
|
3612
|
+
let trackingSubstantiveOutput = false;
|
|
3613
|
+
// Event types that count as "the agent actually produced something the
|
|
3614
|
+
// user can see." Lifecycle markers (`status`) and meter readings
|
|
3615
|
+
// (`usage`) deliberately do NOT count — a model can emit token-usage
|
|
3616
|
+
// numbers for an empty completion (issue #691), and a `status:running`
|
|
3617
|
+
// banner without any follow-up is exactly the silent-failure shape we
|
|
3618
|
+
// want to surface as failed instead of succeeded.
|
|
3619
|
+
const SUBSTANTIVE_AGENT_EVENT_TYPES = new Set([
|
|
3620
|
+
'text_delta',
|
|
3621
|
+
'thinking_delta',
|
|
3622
|
+
'tool_use',
|
|
3623
|
+
'tool_result',
|
|
3624
|
+
'artifact',
|
|
3625
|
+
]);
|
|
3626
|
+
const sendAgentEvent = (ev) => {
|
|
3627
|
+
if (ev?.type === 'error') {
|
|
3628
|
+
if (agentStreamError)
|
|
3629
|
+
return;
|
|
3630
|
+
agentStreamError = String(ev.message || 'Agent stream error');
|
|
3631
|
+
clearInactivityWatchdog();
|
|
3632
|
+
const authFailure = classifyAgentAuthFailure(agentId, [
|
|
3633
|
+
agentStreamError,
|
|
3634
|
+
typeof ev.raw === 'string' ? ev.raw : '',
|
|
3635
|
+
agentStdoutTail,
|
|
3636
|
+
agentStderrTail,
|
|
3637
|
+
].join('\n'));
|
|
3638
|
+
if (authFailure?.status === 'missing') {
|
|
3639
|
+
send('error', createSseErrorPayload('AGENT_AUTH_REQUIRED', cursorAuthGuidance(), { retryable: true }));
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', agentStreamError, {
|
|
3643
|
+
details: ev.raw ? { raw: ev.raw } : undefined,
|
|
3644
|
+
retryable: false,
|
|
3645
|
+
}));
|
|
3646
|
+
return;
|
|
3647
|
+
}
|
|
3648
|
+
lastAgentEventPhase = summarizeAgentEventForInactivity(ev);
|
|
3649
|
+
noteAgentActivity();
|
|
3650
|
+
if (ev?.type && SUBSTANTIVE_AGENT_EVENT_TYPES.has(ev.type)) {
|
|
3651
|
+
agentProducedOutput = true;
|
|
3652
|
+
}
|
|
3653
|
+
send('agent', ev);
|
|
3654
|
+
};
|
|
3655
|
+
if (def.streamFormat === 'claude-stream-json') {
|
|
3656
|
+
const claude = createClaudeStreamHandler((ev) => {
|
|
3657
|
+
lastAgentEventPhase = summarizeAgentEventForInactivity(ev);
|
|
3658
|
+
noteAgentActivity();
|
|
3659
|
+
send('agent', ev);
|
|
3660
|
+
// Stream-json input mode keeps the child's stdin open across the
|
|
3661
|
+
// turn so we can answer interactive tools like `AskUserQuestion`
|
|
3662
|
+
// with a real `tool_result`. The child has no other way to know
|
|
3663
|
+
// the conversation is over, though — without an EOF it sits idle
|
|
3664
|
+
// until the inactivity watchdog kills it. Bookkeeping here:
|
|
3665
|
+
// - tool_use(AskUserQuestion): record the id so we know we owe
|
|
3666
|
+
// the model a tool_result before the turn can end.
|
|
3667
|
+
// - turn_end (per-turn synthesized from `stop_reason`): fire on
|
|
3668
|
+
// `end_turn` etc. but NOT on `tool_use` — that stop reason
|
|
3669
|
+
// means the model paused mid-tool, not "turn complete".
|
|
3670
|
+
// - usage (session result at EOF in single-shot mode).
|
|
3671
|
+
try {
|
|
3672
|
+
if (run.stdinOpen) {
|
|
3673
|
+
if (ev &&
|
|
3674
|
+
typeof ev === 'object' &&
|
|
3675
|
+
ev.type === 'tool_use' &&
|
|
3676
|
+
(ev.name === 'AskUserQuestion' || ev.name === 'ask_user_question') &&
|
|
3677
|
+
typeof ev.id === 'string') {
|
|
3678
|
+
if (!run.pendingHostAnswers)
|
|
3679
|
+
run.pendingHostAnswers = new Set();
|
|
3680
|
+
run.pendingHostAnswers.add(ev.id);
|
|
3681
|
+
}
|
|
3682
|
+
else if (ev &&
|
|
3683
|
+
typeof ev === 'object' &&
|
|
3684
|
+
((ev.type === 'turn_end' &&
|
|
3685
|
+
// `stop_reason: tool_use` means the model paused to wait
|
|
3686
|
+
// for tool execution (claude-code is about to run an
|
|
3687
|
+
// internal tool, or we owe a host tool_result). Either
|
|
3688
|
+
// way the conversation is still in flight — do not close.
|
|
3689
|
+
ev.stopReason !== 'tool_use') ||
|
|
3690
|
+
ev.type === 'usage') &&
|
|
3691
|
+
(!run.pendingHostAnswers || run.pendingHostAnswers.size === 0)) {
|
|
3692
|
+
// Per-turn `turn_end` (synthesized from
|
|
3693
|
+
// `assistant.message.stop_reason` in `claude-stream`) is the
|
|
3694
|
+
// primary close signal; `usage` is the session-level result
|
|
3695
|
+
// that fires at EOF in single-shot mode. Either is a valid
|
|
3696
|
+
// "this turn is done" cue, but only when there's no host
|
|
3697
|
+
// answer outstanding AND the model isn't paused mid-tool.
|
|
3698
|
+
if (run.child && run.child.stdin && !run.child.stdin.destroyed) {
|
|
3699
|
+
try {
|
|
3700
|
+
run.child.stdin.end();
|
|
3701
|
+
}
|
|
3702
|
+
catch { }
|
|
3703
|
+
}
|
|
3704
|
+
run.stdinOpen = false;
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
catch { }
|
|
3709
|
+
});
|
|
3710
|
+
child.stdout.on('data', (chunk) => claude.feed(chunk));
|
|
3711
|
+
child.on('close', () => claude.flush());
|
|
3712
|
+
}
|
|
3713
|
+
else if (def.streamFormat === 'qoder-stream-json') {
|
|
3714
|
+
trackingSubstantiveOutput = true;
|
|
3715
|
+
const qoder = createQoderStreamHandler(sendAgentEvent);
|
|
3716
|
+
child.stdout.on('data', (chunk) => qoder.feed(chunk));
|
|
3717
|
+
child.on('close', () => qoder.flush());
|
|
3718
|
+
}
|
|
3719
|
+
else if (def.streamFormat === 'copilot-stream-json') {
|
|
3720
|
+
const copilot = createCopilotStreamHandler((ev) => {
|
|
3721
|
+
lastAgentEventPhase = summarizeAgentEventForInactivity(ev);
|
|
3722
|
+
noteAgentActivity();
|
|
3723
|
+
send('agent', ev);
|
|
3724
|
+
});
|
|
3725
|
+
child.stdout.on('data', (chunk) => copilot.feed(chunk));
|
|
3726
|
+
child.on('close', () => copilot.flush());
|
|
3727
|
+
}
|
|
3728
|
+
else if (def.streamFormat === 'pi-rpc') {
|
|
3729
|
+
// Route through sendAgentEvent so that pi-rpc's error events
|
|
3730
|
+
// (extension_error, auto_retry_end with success=false, and the
|
|
3731
|
+
// message_update error delta) set agentStreamError and flip the
|
|
3732
|
+
// run to `failed` on close — same path as qoder-stream-json and
|
|
3733
|
+
// json-event-stream after issue #691. Also enables the
|
|
3734
|
+
// substantive-output guard (agentProducedOutput) so a pi run
|
|
3735
|
+
// that exits 0 without producing visible content is caught.
|
|
3736
|
+
//
|
|
3737
|
+
// attachPiRpcSession invokes its send callback with the two-arg
|
|
3738
|
+
// channel/payload shape: send('agent', payload) for normal events
|
|
3739
|
+
// and send('error', {message}) from fail(). sendAgentEvent
|
|
3740
|
+
// expects a single event object, so we adapt at the call site:
|
|
3741
|
+
// - 'agent' channel → relay payload through sendAgentEvent
|
|
3742
|
+
// - 'error' channel → route through the daemon's error path
|
|
3743
|
+
// (createSseErrorPayload + send SSE + set agentStreamError)
|
|
3744
|
+
trackingSubstantiveOutput = true;
|
|
3745
|
+
acpSession = attachPiRpcSession({
|
|
3746
|
+
child,
|
|
3747
|
+
prompt: composed,
|
|
3748
|
+
cwd: effectiveCwd,
|
|
3749
|
+
model: safeModel,
|
|
3750
|
+
send: (channel, payload) => {
|
|
3751
|
+
if (channel === 'agent') {
|
|
3752
|
+
sendAgentEvent(payload);
|
|
3753
|
+
}
|
|
3754
|
+
else if (channel === 'error') {
|
|
3755
|
+
if (agentStreamError)
|
|
3756
|
+
return;
|
|
3757
|
+
agentStreamError = String(payload?.message || 'Pi session error');
|
|
3758
|
+
clearInactivityWatchdog();
|
|
3759
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', agentStreamError, { retryable: false }));
|
|
3760
|
+
}
|
|
3761
|
+
else {
|
|
3762
|
+
noteAgentActivity();
|
|
3763
|
+
send(channel, payload);
|
|
3764
|
+
}
|
|
3765
|
+
},
|
|
3766
|
+
imagePaths: def.supportsImagePaths ? safeImages : [],
|
|
3767
|
+
uploadRoot: UPLOAD_DIR,
|
|
3768
|
+
});
|
|
3769
|
+
}
|
|
3770
|
+
else if (def.streamFormat === 'acp-json-rpc') {
|
|
3771
|
+
const acpStageTimeoutMs = resolveAcpStageTimeoutMs();
|
|
3772
|
+
acpSession = attachAcpSession({
|
|
3773
|
+
child,
|
|
3774
|
+
prompt: composed,
|
|
3775
|
+
cwd: effectiveCwd,
|
|
3776
|
+
model: safeModel,
|
|
3777
|
+
mcpServers,
|
|
3778
|
+
send: (event, data) => {
|
|
3779
|
+
noteAgentActivity();
|
|
3780
|
+
send(event, data);
|
|
3781
|
+
},
|
|
3782
|
+
...(acpStageTimeoutMs !== undefined ? { stageTimeoutMs: acpStageTimeoutMs } : {}),
|
|
3783
|
+
});
|
|
3784
|
+
}
|
|
3785
|
+
else if (def.streamFormat === 'json-event-stream') {
|
|
3786
|
+
// Pipe through sendAgentEvent so the OpenCode `type:'error'` frame
|
|
3787
|
+
// (now emitted as a real error event by json-event-stream.ts after
|
|
3788
|
+
// #691) actually triggers `agentStreamError` instead of being
|
|
3789
|
+
// forwarded as a no-op `agent` SSE event. This also wires the
|
|
3790
|
+
// substantive-output tracking the close handler reads below.
|
|
3791
|
+
trackingSubstantiveOutput = true;
|
|
3792
|
+
const handler = createJsonEventStreamHandler(def.eventParser || def.id, sendAgentEvent);
|
|
3793
|
+
child.stdout.on('data', (chunk) => handler.feed(chunk));
|
|
3794
|
+
child.on('close', () => handler.flush());
|
|
3795
|
+
}
|
|
3796
|
+
else {
|
|
3797
|
+
child.stdout.on('data', (chunk) => {
|
|
3798
|
+
noteAgentActivity();
|
|
3799
|
+
send('stdout', { chunk });
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3802
|
+
// Wire the acpSession onto the run so cancel() can call abort()
|
|
3803
|
+
// instead of raw SIGTERM (applies to pi-rpc and acp-json-rpc).
|
|
3804
|
+
run.acpSession = acpSession;
|
|
3805
|
+
child.stderr.on('data', (chunk) => {
|
|
3806
|
+
noteAgentActivity();
|
|
3807
|
+
agentStderrTail = `${agentStderrTail}${chunk}`.slice(-2000);
|
|
3808
|
+
send('stderr', { chunk });
|
|
3809
|
+
});
|
|
3810
|
+
child.on('error', (err) => {
|
|
3811
|
+
clearInactivityWatchdog();
|
|
3812
|
+
revokeToolToken('child_exit');
|
|
3813
|
+
unregisterChatAgentEventSink();
|
|
3814
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', err.message));
|
|
3815
|
+
design.runs.finish(run, 'failed', 1, null);
|
|
3816
|
+
});
|
|
3817
|
+
child.on('close', (code, signal) => {
|
|
3818
|
+
clearInactivityWatchdog();
|
|
3819
|
+
revokeToolToken('child_exit');
|
|
3820
|
+
unregisterChatAgentEventSink();
|
|
3821
|
+
if (acpSession?.hasFatalError()) {
|
|
3822
|
+
return design.runs.finish(run, 'failed', code ?? 1, signal ?? null);
|
|
3823
|
+
}
|
|
3824
|
+
if (agentStreamError) {
|
|
3825
|
+
return design.runs.finish(run, 'failed', code ?? 1, signal ?? null);
|
|
3826
|
+
}
|
|
3827
|
+
if (code !== 0 &&
|
|
3828
|
+
!run.cancelRequested &&
|
|
3829
|
+
classifyAgentAuthFailure(agentId, `${agentStderrTail}\n${agentStdoutTail}`)?.status === 'missing') {
|
|
3830
|
+
send('error', createSseErrorPayload('AGENT_AUTH_REQUIRED', cursorAuthGuidance(), { retryable: true }));
|
|
3831
|
+
return design.runs.finish(run, 'failed', code ?? 1, signal ?? null);
|
|
3832
|
+
}
|
|
3833
|
+
// Empty-output guard: a clean `code === 0` exit on a stream we are
|
|
3834
|
+
// tracking, with no error frame and no substantive event, means the
|
|
3835
|
+
// run silently finished without producing anything visible. That used
|
|
3836
|
+
// to be marked `succeeded` and rendered as an empty assistant turn —
|
|
3837
|
+
// see issue #691, where OpenCode runs were ending in ~3s with no
|
|
3838
|
+
// chat content and no error banner. Surface an explicit failure
|
|
3839
|
+
// instead so the chat shows a clear reason. ACP sessions and plain
|
|
3840
|
+
// stdout streams are gated out via `trackingSubstantiveOutput`;
|
|
3841
|
+
// their success/failure determination lives elsewhere.
|
|
3842
|
+
if (code === 0 &&
|
|
3843
|
+
!run.cancelRequested &&
|
|
3844
|
+
trackingSubstantiveOutput &&
|
|
3845
|
+
!agentProducedOutput) {
|
|
3846
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', 'Agent completed without producing any output. The model or provider may have returned an empty response — check the agent logs for upstream errors.', { retryable: true }));
|
|
3847
|
+
return design.runs.finish(run, 'failed', code, signal);
|
|
3848
|
+
}
|
|
3849
|
+
// ACP agents that don't shut down on stdin.end() (e.g. Devin for
|
|
3850
|
+
// Terminal) are forced to exit via SIGTERM from attachAcpSession after
|
|
3851
|
+
// a clean prompt completion. Without an override, the chat run would
|
|
3852
|
+
// be marked `failed` because `code === 0` fails (code is null on a
|
|
3853
|
+
// signal exit). `completedSuccessfully()` reports whether the ACP
|
|
3854
|
+
// session resolved without a fatal error or abort.
|
|
3855
|
+
//
|
|
3856
|
+
// Scope the override narrowly to the exact forced-shutdown shape this
|
|
3857
|
+
// PR introduces: code is null AND signal is SIGTERM AND the ACP
|
|
3858
|
+
// session reported clean completion. Any other post-response failure
|
|
3859
|
+
// (non-zero exit code, SIGKILL, SIGSEGV, etc.) still propagates as
|
|
3860
|
+
// `failed`, preserving the existing close-status behavior for genuine
|
|
3861
|
+
// post-response process problems.
|
|
3862
|
+
const acpCleanCompletion = typeof acpSession?.completedSuccessfully === 'function' &&
|
|
3863
|
+
acpSession.completedSuccessfully();
|
|
3864
|
+
const acpForcedShutdown = code === null && signal === 'SIGTERM' && acpCleanCompletion;
|
|
3865
|
+
const status = run.cancelRequested
|
|
3866
|
+
? 'canceled'
|
|
3867
|
+
: code === 0 || acpForcedShutdown
|
|
3868
|
+
? 'succeeded'
|
|
3869
|
+
: 'failed';
|
|
3870
|
+
if (status === 'failed') {
|
|
3871
|
+
const diagnostic = diagnoseClaudeCliFailure({
|
|
3872
|
+
agentId: def.id,
|
|
3873
|
+
exitCode: code,
|
|
3874
|
+
signal,
|
|
3875
|
+
stderrTail: agentStderrTail,
|
|
3876
|
+
stdoutTail: agentStdoutTail,
|
|
3877
|
+
env: spawnedAgentEnv,
|
|
3878
|
+
});
|
|
3879
|
+
if (diagnostic) {
|
|
3880
|
+
send('error', createSseErrorPayload('AGENT_EXECUTION_FAILED', diagnostic.message, { retryable: diagnostic.retryable, details: { detail: diagnostic.detail } }));
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
design.runs.finish(run, status, code, signal);
|
|
3884
|
+
});
|
|
3885
|
+
if (writePromptToChildStdin && child.stdin) {
|
|
3886
|
+
const promptInputFormat = def.promptInputFormat ?? 'text';
|
|
3887
|
+
if (promptInputFormat === 'stream-json') {
|
|
3888
|
+
// Wrap the prompt as an Anthropic user message and write it as one
|
|
3889
|
+
// JSONL line. Do NOT close stdin: claude-code keeps reading further
|
|
3890
|
+
// messages until EOF, which is what lets us inject a `tool_result`
|
|
3891
|
+
// block later when the user answers an `AskUserQuestion` card. The
|
|
3892
|
+
// stdin is closed implicitly when the child exits (run terminates,
|
|
3893
|
+
// user cancels, or the model finishes without an outstanding tool
|
|
3894
|
+
// call).
|
|
3895
|
+
const userMessage = JSON.stringify({
|
|
3896
|
+
type: 'user',
|
|
3897
|
+
message: {
|
|
3898
|
+
role: 'user',
|
|
3899
|
+
content: [{ type: 'text', text: composed }],
|
|
3900
|
+
},
|
|
3901
|
+
});
|
|
3902
|
+
try {
|
|
3903
|
+
child.stdin.write(`${userMessage}\n`, 'utf8');
|
|
3904
|
+
}
|
|
3905
|
+
catch (err) {
|
|
3906
|
+
// Swallow EPIPE here for the same reason as the listener above —
|
|
3907
|
+
// a fast-exiting child has already routed its failure through
|
|
3908
|
+
// stderr / exit handlers.
|
|
3909
|
+
if (err && err.code !== 'EPIPE')
|
|
3910
|
+
throw err;
|
|
3911
|
+
}
|
|
3912
|
+
run.stdinOpen = true;
|
|
3913
|
+
}
|
|
3914
|
+
else {
|
|
3915
|
+
child.stdin.end(composed, 'utf8');
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
};
|
|
3919
|
+
// Send a `tool_result` content block into a still-running stream-json
|
|
3920
|
+
// child. Used for interactive tools that the host answers (currently:
|
|
3921
|
+
// Claude's `AskUserQuestion`). The run must still be active and its
|
|
3922
|
+
// stdin must still be open — we never re-spawn a closed child.
|
|
3923
|
+
const submitToolResultToRun = (runId, toolUseId, content, isError = false) => {
|
|
3924
|
+
const run = design.runs.get(runId);
|
|
3925
|
+
if (!run)
|
|
3926
|
+
return { ok: false, reason: 'not_found' };
|
|
3927
|
+
if (design.runs.isTerminal(run.status)) {
|
|
3928
|
+
return { ok: false, reason: 'run_terminal' };
|
|
3929
|
+
}
|
|
3930
|
+
if (!run.child || !run.child.stdin || run.child.stdin.destroyed) {
|
|
3931
|
+
return { ok: false, reason: 'stdin_closed' };
|
|
3932
|
+
}
|
|
3933
|
+
if (!run.stdinOpen) {
|
|
3934
|
+
return { ok: false, reason: 'stdin_text_mode' };
|
|
3935
|
+
}
|
|
3936
|
+
if (typeof toolUseId !== 'string' || !toolUseId) {
|
|
3937
|
+
return { ok: false, reason: 'bad_tool_use_id' };
|
|
3938
|
+
}
|
|
3939
|
+
const safeContent = typeof content === 'string' ? content : String(content ?? '');
|
|
3940
|
+
const userMessage = JSON.stringify({
|
|
3941
|
+
type: 'user',
|
|
3942
|
+
message: {
|
|
3943
|
+
role: 'user',
|
|
3944
|
+
content: [
|
|
3945
|
+
{
|
|
3946
|
+
type: 'tool_result',
|
|
3947
|
+
tool_use_id: toolUseId,
|
|
3948
|
+
content: safeContent,
|
|
3949
|
+
is_error: !!isError,
|
|
3950
|
+
},
|
|
3951
|
+
],
|
|
3952
|
+
},
|
|
3953
|
+
});
|
|
3954
|
+
try {
|
|
3955
|
+
run.child.stdin.write(`${userMessage}\n`, 'utf8');
|
|
3956
|
+
}
|
|
3957
|
+
catch (err) {
|
|
3958
|
+
return { ok: false, reason: 'write_failed', error: err && err.message };
|
|
3959
|
+
}
|
|
3960
|
+
if (run.pendingHostAnswers) {
|
|
3961
|
+
run.pendingHostAnswers.delete(toolUseId);
|
|
3962
|
+
if (run.pendingHostAnswers.size === 0 && run.stdinOpen) {
|
|
3963
|
+
if (run.child && run.child.stdin && !run.child.stdin.destroyed) {
|
|
3964
|
+
try {
|
|
3965
|
+
run.child.stdin.end();
|
|
3966
|
+
}
|
|
3967
|
+
catch { }
|
|
3968
|
+
}
|
|
3969
|
+
run.stdinOpen = false;
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
return { ok: true };
|
|
3973
|
+
};
|
|
3974
|
+
orbitService.setRunHandler(async ({ trigger, startedAt, prompt, systemPrompt, template, }) => {
|
|
3975
|
+
// Each Orbit run gets its own project so the conversation, messages, and
|
|
3976
|
+
// live artifact are isolated. The handler does the synchronous prep here
|
|
3977
|
+
// (insert project/conversation/run rows, kick off the chat run) and
|
|
3978
|
+
// returns immediately with the new project id; the daemon endpoint
|
|
3979
|
+
// resolves the HTTP request with that id so the client can navigate to
|
|
3980
|
+
// the new project before the agent has finished. Anything that depends
|
|
3981
|
+
// on the agent's final status (live artifact discovery, lastRun summary
|
|
3982
|
+
// metadata) lives inside the `completion` promise.
|
|
3983
|
+
const appConfig = await readAppConfig(RUNTIME_DATA_DIR);
|
|
3984
|
+
let agentId = typeof appConfig.agentId === 'string' && appConfig.agentId
|
|
3985
|
+
? appConfig.agentId
|
|
3986
|
+
: null;
|
|
3987
|
+
if (!agentId) {
|
|
3988
|
+
const agents = await detectAgents(appConfig.agentCliEnv ?? {}).catch(() => []);
|
|
3989
|
+
agentId = agents.find((agent) => agent.available)?.id ?? null;
|
|
3990
|
+
}
|
|
3991
|
+
if (!agentId)
|
|
3992
|
+
throw new Error('No available agent is configured for Orbit. Choose an agent in Settings first.');
|
|
3993
|
+
const now = Date.now();
|
|
3994
|
+
const projectId = `orbit-${randomUUID()}`;
|
|
3995
|
+
const conversationId = `orbit-conv-${randomUUID()}`;
|
|
3996
|
+
const assistantMessageId = `orbit-assistant-${randomUUID()}`;
|
|
3997
|
+
const projectName = `Orbit · ${formatLocalProjectTimestamp(startedAt)}`;
|
|
3998
|
+
const orbitDesignSystemId = template?.designSystemRequired === false
|
|
3999
|
+
? null
|
|
4000
|
+
: appConfig.designSystemId ?? null;
|
|
4001
|
+
insertProject(db, {
|
|
4002
|
+
id: projectId,
|
|
4003
|
+
name: projectName,
|
|
4004
|
+
skillId: 'live-artifact',
|
|
4005
|
+
designSystemId: orbitDesignSystemId,
|
|
4006
|
+
pendingPrompt: null,
|
|
4007
|
+
metadata: { kind: 'orbit', trigger },
|
|
4008
|
+
createdAt: now,
|
|
4009
|
+
updatedAt: now,
|
|
4010
|
+
});
|
|
4011
|
+
insertConversation(db, {
|
|
4012
|
+
id: conversationId,
|
|
4013
|
+
projectId,
|
|
4014
|
+
title: projectName,
|
|
4015
|
+
createdAt: now,
|
|
4016
|
+
updatedAt: now,
|
|
4017
|
+
});
|
|
4018
|
+
const run = design.runs.create({
|
|
4019
|
+
projectId,
|
|
4020
|
+
conversationId,
|
|
4021
|
+
assistantMessageId,
|
|
4022
|
+
clientRequestId: `orbit-${trigger}-${randomUUID()}`,
|
|
4023
|
+
agentId,
|
|
4024
|
+
});
|
|
4025
|
+
upsertMessage(db, conversationId, {
|
|
4026
|
+
id: `orbit-user-${run.id}`,
|
|
4027
|
+
role: 'user',
|
|
4028
|
+
content: prompt,
|
|
4029
|
+
});
|
|
4030
|
+
upsertMessage(db, conversationId, {
|
|
4031
|
+
id: assistantMessageId,
|
|
4032
|
+
role: 'assistant',
|
|
4033
|
+
content: '',
|
|
4034
|
+
agentId,
|
|
4035
|
+
agentName: getAgentDef(agentId)?.name ?? agentId,
|
|
4036
|
+
runId: run.id,
|
|
4037
|
+
runStatus: 'queued',
|
|
4038
|
+
startedAt: now,
|
|
4039
|
+
});
|
|
4040
|
+
if (template?.dir) {
|
|
4041
|
+
const cwd = await ensureProject(PROJECTS_DIR, projectId);
|
|
4042
|
+
const result = await stageActiveSkill(cwd, path.basename(template.dir), template.dir, (msg) => console.warn(msg));
|
|
4043
|
+
if (!result.staged) {
|
|
4044
|
+
console.warn(`[od] orbit template skill-stage skipped: ${result.reason ?? 'unknown reason'}; falling back to prompt-embedded instructions`);
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
const modelPrefs = appConfig.agentModels?.[agentId] ?? {};
|
|
4048
|
+
design.runs.start(run, () => startChatRun({
|
|
4049
|
+
agentId,
|
|
4050
|
+
projectId,
|
|
4051
|
+
conversationId: run.conversationId,
|
|
4052
|
+
assistantMessageId: run.assistantMessageId,
|
|
4053
|
+
clientRequestId: run.clientRequestId,
|
|
4054
|
+
skillId: 'live-artifact',
|
|
4055
|
+
designSystemId: orbitDesignSystemId,
|
|
4056
|
+
model: modelPrefs.model ?? null,
|
|
4057
|
+
reasoning: modelPrefs.reasoning ?? null,
|
|
4058
|
+
message: prompt,
|
|
4059
|
+
systemPrompt: [
|
|
4060
|
+
renderOrbitTemplateSystemPrompt(template),
|
|
4061
|
+
systemPrompt,
|
|
4062
|
+
'You are Orbit, an autonomous activity-summary agent inside Open Design.',
|
|
4063
|
+
'You must discover connectors and connector tools yourself through the OD CLI; the daemon has not chosen tools for you.',
|
|
4064
|
+
'You must create and register a Live Artifact as the final deliverable. Do not merely describe what you would do.',
|
|
4065
|
+
'Do not ask follow-up questions, do not emit <question-form>, and do not wait for user input. This run is unattended; pick reasonable defaults and complete the artifact.',
|
|
4066
|
+
'Keep connector credentials and OD_TOOL_TOKEN private; never print or persist secrets.',
|
|
4067
|
+
].join('\n'),
|
|
4068
|
+
}, run));
|
|
4069
|
+
const completion = (async () => {
|
|
4070
|
+
const finalStatus = await design.runs.wait(run);
|
|
4071
|
+
db.prepare(`UPDATE messages SET run_status = ?, ended_at = ? WHERE id = ?`).run(finalStatus.status, Date.now(), assistantMessageId);
|
|
4072
|
+
const artifacts = await listLiveArtifacts({ projectsRoot: PROJECTS_DIR, projectId });
|
|
4073
|
+
const artifact = artifacts.find((candidate) => candidate.createdByRunId === run.id);
|
|
4074
|
+
const status = finalStatus.status === 'succeeded' && !artifact ? 'failed' : finalStatus.status;
|
|
4075
|
+
return {
|
|
4076
|
+
agentRunId: run.id,
|
|
4077
|
+
status,
|
|
4078
|
+
...(artifact?.id ? { artifactId: artifact.id, artifactProjectId: projectId } : {}),
|
|
4079
|
+
summary: artifact?.id
|
|
4080
|
+
? `Agent ${finalStatus.status} and registered live artifact ${artifact.title}.`
|
|
4081
|
+
: finalStatus.status === 'succeeded'
|
|
4082
|
+
? buildOrbitNoLiveArtifactSummary(run.events)
|
|
4083
|
+
: `Agent ${finalStatus.status} but did not register a live artifact for this Orbit run.`,
|
|
4084
|
+
};
|
|
4085
|
+
})();
|
|
4086
|
+
return { projectId, agentRunId: run.id, completion };
|
|
4087
|
+
});
|
|
4088
|
+
orbitService.setTemplateResolver(async (skillId) => {
|
|
4089
|
+
// Orbit templates (live-artifact, etc.) live under design-templates after
|
|
4090
|
+
// the split, but earlier projects may still point at functional-skill
|
|
4091
|
+
// ids for the same purpose — search both roots so a stored project id
|
|
4092
|
+
// keeps resolving through one or the other.
|
|
4093
|
+
const skills = await listAllSkillLikeEntries();
|
|
4094
|
+
const skill = findSkillById(skills, skillId);
|
|
4095
|
+
if (!skill || skill.scenario !== 'orbit')
|
|
4096
|
+
return null;
|
|
4097
|
+
return {
|
|
4098
|
+
id: skill.id,
|
|
4099
|
+
name: skill.name,
|
|
4100
|
+
examplePrompt: skill.examplePrompt,
|
|
4101
|
+
dir: skill.dir,
|
|
4102
|
+
body: skill.body,
|
|
4103
|
+
designSystemRequired: skill.designSystemRequired !== false,
|
|
4104
|
+
};
|
|
4105
|
+
});
|
|
4106
|
+
// Each routine fire resolves an agent, prepares project/conversation state,
|
|
4107
|
+
// and dispatches into the same chat runner used by manual runs.
|
|
4108
|
+
routineService.setRunHandler(async ({ routine, trigger, startedAt }) => {
|
|
4109
|
+
const appConfig = await readAppConfig(RUNTIME_DATA_DIR);
|
|
4110
|
+
let agentId = routine.agentId
|
|
4111
|
+
|| (typeof appConfig.agentId === 'string' && appConfig.agentId ? appConfig.agentId : null);
|
|
4112
|
+
if (!agentId) {
|
|
4113
|
+
const agents = await detectAgents(appConfig.agentCliEnv ?? {}).catch(() => []);
|
|
4114
|
+
agentId = agents.find((agent) => agent.available)?.id ?? null;
|
|
4115
|
+
}
|
|
4116
|
+
if (!agentId) {
|
|
4117
|
+
throw new Error('No available agent is configured. Choose an agent in Settings first.');
|
|
4118
|
+
}
|
|
4119
|
+
const now = startedAt;
|
|
4120
|
+
const stamp = formatLocalProjectTimestamp(new Date(now).toISOString());
|
|
4121
|
+
let projectId;
|
|
4122
|
+
let projectName;
|
|
4123
|
+
if (routine.target.mode === 'reuse') {
|
|
4124
|
+
const project = getProject(db, routine.target.projectId);
|
|
4125
|
+
if (!project)
|
|
4126
|
+
throw new Error(`Routine target project ${routine.target.projectId} not found`);
|
|
4127
|
+
projectId = project.id;
|
|
4128
|
+
projectName = project.name;
|
|
4129
|
+
}
|
|
4130
|
+
else {
|
|
4131
|
+
projectId = `routine-${randomUUID()}`;
|
|
4132
|
+
projectName = `${routine.name} · ${stamp}`;
|
|
4133
|
+
insertProject(db, {
|
|
4134
|
+
id: projectId,
|
|
4135
|
+
name: projectName,
|
|
4136
|
+
skillId: routine.skillId ?? null,
|
|
4137
|
+
designSystemId: appConfig.designSystemId ?? null,
|
|
4138
|
+
pendingPrompt: null,
|
|
4139
|
+
metadata: { kind: 'other', intent: 'routine', routineId: routine.id, trigger },
|
|
4140
|
+
createdAt: now,
|
|
4141
|
+
updatedAt: now,
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
const conversationId = `routine-conv-${randomUUID()}`;
|
|
4145
|
+
const conversationTitle = routine.target.mode === 'reuse'
|
|
4146
|
+
? `${routine.name} · ${stamp}`
|
|
4147
|
+
: projectName;
|
|
4148
|
+
insertConversation(db, {
|
|
4149
|
+
id: conversationId,
|
|
4150
|
+
projectId,
|
|
4151
|
+
title: conversationTitle,
|
|
4152
|
+
createdAt: now,
|
|
4153
|
+
updatedAt: now,
|
|
4154
|
+
});
|
|
4155
|
+
// Notify any open `ProjectView` watching this project so its
|
|
4156
|
+
// conversation list picks up the new routine conversation without
|
|
4157
|
+
// requiring the user to leave and re-enter the project (#1361).
|
|
4158
|
+
// For reuse-an-existing-project mode this is the only path the
|
|
4159
|
+
// open view has to learn the conversation exists; for new-project
|
|
4160
|
+
// mode this is harmless (no subscribers for a project that was
|
|
4161
|
+
// just created milliseconds ago). The payload shape is the shared
|
|
4162
|
+
// `ProjectConversationCreatedSsePayload` from `@open-design/contracts`
|
|
4163
|
+
// so the daemon producer and the web consumer cannot drift.
|
|
4164
|
+
/** @type {ProjectConversationCreatedSsePayload} */
|
|
4165
|
+
const conversationCreatedEvent = {
|
|
4166
|
+
type: 'conversation-created',
|
|
4167
|
+
projectId,
|
|
4168
|
+
conversationId,
|
|
4169
|
+
title: conversationTitle,
|
|
4170
|
+
createdAt: now,
|
|
4171
|
+
};
|
|
4172
|
+
emitProjectEvent(projectId, conversationCreatedEvent);
|
|
4173
|
+
const assistantMessageId = `routine-assistant-${randomUUID()}`;
|
|
4174
|
+
const run = design.runs.create({
|
|
4175
|
+
projectId,
|
|
4176
|
+
conversationId,
|
|
4177
|
+
assistantMessageId,
|
|
4178
|
+
clientRequestId: `routine-${trigger}-${randomUUID()}`,
|
|
4179
|
+
agentId,
|
|
4180
|
+
});
|
|
4181
|
+
upsertMessage(db, conversationId, {
|
|
4182
|
+
id: `routine-user-${run.id}`,
|
|
4183
|
+
role: 'user',
|
|
4184
|
+
content: routine.prompt,
|
|
4185
|
+
});
|
|
4186
|
+
upsertMessage(db, conversationId, {
|
|
4187
|
+
id: assistantMessageId,
|
|
4188
|
+
role: 'assistant',
|
|
4189
|
+
content: '',
|
|
4190
|
+
agentId,
|
|
4191
|
+
agentName: getAgentDef(agentId)?.name ?? agentId,
|
|
4192
|
+
runId: run.id,
|
|
4193
|
+
runStatus: 'queued',
|
|
4194
|
+
startedAt: now,
|
|
4195
|
+
});
|
|
4196
|
+
const modelPrefs = appConfig.agentModels?.[agentId] ?? {};
|
|
4197
|
+
design.runs.start(run, () => startChatRun({
|
|
4198
|
+
agentId,
|
|
4199
|
+
projectId,
|
|
4200
|
+
conversationId: run.conversationId,
|
|
4201
|
+
assistantMessageId: run.assistantMessageId,
|
|
4202
|
+
clientRequestId: run.clientRequestId,
|
|
4203
|
+
skillId: routine.skillId ?? null,
|
|
4204
|
+
designSystemId: appConfig.designSystemId ?? null,
|
|
4205
|
+
model: modelPrefs.model ?? null,
|
|
4206
|
+
reasoning: modelPrefs.reasoning ?? null,
|
|
4207
|
+
message: routine.prompt,
|
|
4208
|
+
systemPrompt: [
|
|
4209
|
+
`You are running an unattended scheduled routine named "${routine.name}".`,
|
|
4210
|
+
'Do not ask follow-up questions, do not emit <question-form>, and do not wait for user input. Pick reasonable defaults and finish the task.',
|
|
4211
|
+
].join('\n'),
|
|
4212
|
+
}, run));
|
|
4213
|
+
const completion = (async () => {
|
|
4214
|
+
const finalStatus = await design.runs.wait(run);
|
|
4215
|
+
db.prepare(`UPDATE messages SET run_status = ?, ended_at = ? WHERE id = ?`)
|
|
4216
|
+
.run(finalStatus.status, Date.now(), assistantMessageId);
|
|
4217
|
+
return {
|
|
4218
|
+
status: finalStatus.status,
|
|
4219
|
+
summary: `Routine "${routine.name}" ${finalStatus.status}.`,
|
|
4220
|
+
};
|
|
4221
|
+
})();
|
|
4222
|
+
return { projectId, conversationId, agentRunId: run.id, completion };
|
|
4223
|
+
});
|
|
4224
|
+
routineService.start();
|
|
4225
|
+
assertServerContextSatisfiesRoutes({
|
|
4226
|
+
db,
|
|
4227
|
+
design,
|
|
4228
|
+
http: httpDeps,
|
|
4229
|
+
paths: pathDeps,
|
|
4230
|
+
ids: idDeps,
|
|
4231
|
+
uploads: uploadDeps,
|
|
4232
|
+
node: nodeDeps,
|
|
4233
|
+
projectStore: projectStoreDeps,
|
|
4234
|
+
projectFiles: projectFileDeps,
|
|
4235
|
+
conversations: conversationDeps,
|
|
4236
|
+
templates: templateDeps,
|
|
4237
|
+
status: projectStatusDeps,
|
|
4238
|
+
events: projectEventDeps,
|
|
4239
|
+
imports: importDeps,
|
|
4240
|
+
exports: projectExportDeps,
|
|
4241
|
+
artifacts: artifactDeps,
|
|
4242
|
+
documents: { buildDocumentPreview },
|
|
4243
|
+
auth: authDeps,
|
|
4244
|
+
liveArtifacts: liveArtifactDeps,
|
|
4245
|
+
deploy: deployDeps,
|
|
4246
|
+
media: mediaDeps,
|
|
4247
|
+
appConfig: appConfigDeps,
|
|
4248
|
+
orbit: orbitDeps,
|
|
4249
|
+
nativeDialogs: nativeDialogDeps,
|
|
4250
|
+
research: researchDeps,
|
|
4251
|
+
mcp: { pendingAuth: mcpPendingAuth, daemonUrlRef },
|
|
4252
|
+
resources: {
|
|
4253
|
+
listAllSkills,
|
|
4254
|
+
listAllDesignTemplates,
|
|
4255
|
+
listAllSkillLikeEntries,
|
|
4256
|
+
listAllDesignSystems,
|
|
4257
|
+
mimeFor,
|
|
4258
|
+
},
|
|
4259
|
+
routines: { routineService },
|
|
4260
|
+
validation: validationDeps,
|
|
4261
|
+
finalize: finalizeDeps,
|
|
4262
|
+
chat: { startChatRun, submitToolResultToRun },
|
|
4263
|
+
agents: agentDeps,
|
|
4264
|
+
critique: critiqueDeps,
|
|
4265
|
+
lifecycle: { isDaemonShuttingDown: () => daemonShuttingDown },
|
|
4266
|
+
});
|
|
4267
|
+
registerRoutineRoutes(app, {
|
|
4268
|
+
db,
|
|
4269
|
+
routines: { routineService },
|
|
4270
|
+
});
|
|
4271
|
+
registerChatRoutes(app, {
|
|
4272
|
+
db,
|
|
4273
|
+
design,
|
|
4274
|
+
http: httpDeps,
|
|
4275
|
+
chat: { startChatRun, submitToolResultToRun },
|
|
4276
|
+
agents: agentDeps,
|
|
4277
|
+
critique: critiqueDeps,
|
|
4278
|
+
validation: validationDeps,
|
|
4279
|
+
lifecycle: { isDaemonShuttingDown: () => daemonShuttingDown },
|
|
4280
|
+
});
|
|
4281
|
+
// Wait for `listen` to bind so callers always see the resolved URL —
|
|
4282
|
+
// critical when port=0 (ephemeral port) and when the embedding sidecar
|
|
4283
|
+
// needs to advertise the port to a parent process before any request
|
|
4284
|
+
// can flow. Three callers depend on this contract:
|
|
4285
|
+
// - `apps/daemon/src/cli.ts` → expects `{ url, server, shutdown }`
|
|
4286
|
+
// - `apps/daemon/sidecar/server.ts` → expects `{ url, server }`
|
|
4287
|
+
// - `apps/daemon/tests/version-route.test.ts` → expects `{ url, server }`
|
|
4288
|
+
return await new Promise((resolve, reject) => {
|
|
4289
|
+
let daemonShutdownStarted = false;
|
|
4290
|
+
const cleanupDaemonBackgroundWork = () => {
|
|
4291
|
+
composioConnectorProvider.stopCatalogRefreshLoop();
|
|
4292
|
+
orbitService.stop();
|
|
4293
|
+
routineService?.stop();
|
|
4294
|
+
};
|
|
4295
|
+
const shutdownDaemonRuns = async () => {
|
|
4296
|
+
if (daemonShutdownStarted)
|
|
4297
|
+
return;
|
|
4298
|
+
daemonShutdownStarted = true;
|
|
4299
|
+
daemonShuttingDown = true;
|
|
4300
|
+
await design.runs.shutdownActive({ graceMs: resolveChatRunShutdownGraceMs() });
|
|
4301
|
+
await design.analytics.shutdown();
|
|
4302
|
+
};
|
|
4303
|
+
let server;
|
|
4304
|
+
try {
|
|
4305
|
+
server = app.listen(port, host, () => {
|
|
4306
|
+
const address = server.address();
|
|
4307
|
+
// `address()` can in theory return `string | AddressInfo | null`. For
|
|
4308
|
+
// a TCP listener it's always `AddressInfo` with a `.port` — the guard
|
|
4309
|
+
// is belt-and-braces so an unexpected null never silently produces a
|
|
4310
|
+
// `http://127.0.0.1:0` URL that callers would then try to fetch.
|
|
4311
|
+
const boundPort = address && typeof address === 'object' ? address.port : null;
|
|
4312
|
+
if (!boundPort) {
|
|
4313
|
+
reject(new Error(`[od] daemon failed to resolve listening port (address=${JSON.stringify(address)})`));
|
|
4314
|
+
return;
|
|
4315
|
+
}
|
|
4316
|
+
resolvedPort = boundPort;
|
|
4317
|
+
// When binding to all interfaces report localhost for local callers;
|
|
4318
|
+
// when binding to a specific address (e.g. a Tailscale IP) report that
|
|
4319
|
+
// address so remote callers and the sidecar use the correct URL.
|
|
4320
|
+
const reportHost = host === '0.0.0.0' || host === '::' ? '127.0.0.1' : host;
|
|
4321
|
+
const url = `http://${reportHost}:${resolvedPort}`;
|
|
4322
|
+
if (!returnServer) {
|
|
4323
|
+
console.log(`[od] daemon listening on ${url}`);
|
|
4324
|
+
}
|
|
4325
|
+
daemonUrl = url;
|
|
4326
|
+
resolve(returnServer ? { url, server, shutdown: shutdownDaemonRuns } : url);
|
|
4327
|
+
});
|
|
4328
|
+
}
|
|
4329
|
+
catch (error) {
|
|
4330
|
+
cleanupDaemonBackgroundWork();
|
|
4331
|
+
reject(error);
|
|
4332
|
+
return;
|
|
4333
|
+
}
|
|
4334
|
+
server.once('close', () => {
|
|
4335
|
+
void shutdownDaemonRuns().finally(cleanupDaemonBackgroundWork);
|
|
4336
|
+
});
|
|
4337
|
+
// `app.listen` throws synchronously when the port is already in use on
|
|
4338
|
+
// some Node versions, but emits an `error` event on others (and for
|
|
4339
|
+
// EACCES / EADDRNOTAVAIL even on the same Node). Wire the event so the
|
|
4340
|
+
// returned Promise always settles instead of hanging forever.
|
|
4341
|
+
server.on('error', (error) => {
|
|
4342
|
+
cleanupDaemonBackgroundWork();
|
|
4343
|
+
reject(error);
|
|
4344
|
+
});
|
|
4345
|
+
});
|
|
4346
|
+
}
|
|
4347
|
+
function randomId() {
|
|
4348
|
+
return randomUUID();
|
|
4349
|
+
}
|
|
4350
|
+
function sanitizeSlug(text) {
|
|
4351
|
+
return String(text)
|
|
4352
|
+
.toLowerCase()
|
|
4353
|
+
.replace(/[^\w\s-]/g, '')
|
|
4354
|
+
.replace(/[\s_]+/g, '-')
|
|
4355
|
+
.replace(/^-+|-+$/g, '')
|
|
4356
|
+
.slice(0, 64);
|
|
4357
|
+
}
|
|
4358
|
+
function assembleExample(templateHtml, slidesHtml, title) {
|
|
4359
|
+
return templateHtml
|
|
4360
|
+
.replace('<!-- SLIDES_HERE -->', slidesHtml)
|
|
4361
|
+
.replace(/<title>.*?<\/title>/, `<title>${title} | Open Design Example</title>`);
|
|
4362
|
+
}
|
|
4363
|
+
// Skill example HTML often references shipped images via relative paths
|
|
4364
|
+
// like `./assets/hero.png`. Those resolve correctly when the file is
|
|
4365
|
+
// opened from disk, but the web app loads the example into a sandboxed
|
|
4366
|
+
// iframe via `srcdoc`, where the document URL is `about:srcdoc` and
|
|
4367
|
+
// relative URLs cannot find the assets. Rewriting them to an absolute
|
|
4368
|
+
// `/api/skills/<id>/assets/...` URL lets the same HTML render in both
|
|
4369
|
+
// places — the disk preview keeps working, and the in-app preview now
|
|
4370
|
+
// fetches assets through the matching route below.
|
|
4371
|
+
export function rewriteSkillAssetUrls(html, skillId) {
|
|
4372
|
+
if (typeof html !== 'string' || html.length === 0)
|
|
4373
|
+
return html;
|
|
4374
|
+
// Match src/href attributes whose values point at the current skill's
|
|
4375
|
+
// assets (`./assets/...` or `assets/...`) or a sibling skill's assets
|
|
4376
|
+
// (`../other-skill/assets/...`). Quote style is preserved so we do not
|
|
4377
|
+
// disturb the surrounding markup.
|
|
4378
|
+
return html.replace(/(\s(?:src|href)\s*=\s*)(['"])((?:\.\.\/([^/'"#?]+)\/)?(?:\.\/)?assets\/([^'"#?]+))(\2)/gi, (_match, attr, openQuote, _fullPath, siblingSkillId, relPath, closeQuote) => {
|
|
4379
|
+
const resolvedSkillId = siblingSkillId || skillId;
|
|
4380
|
+
const prefix = `/api/skills/${encodeURIComponent(resolvedSkillId)}/assets/`;
|
|
4381
|
+
return `${attr}${openQuote}${prefix}${relPath}${closeQuote}`;
|
|
4382
|
+
});
|
|
4383
|
+
}
|
|
4384
|
+
//# sourceMappingURL=server.js.map
|