agent-state-machine 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/bin/cli.js +33 -5
  2. package/lib/file-tree.js +1 -1
  3. package/lib/runtime/agent.js +6 -2
  4. package/lib/runtime/interaction.js +2 -1
  5. package/lib/runtime/prompt.js +37 -1
  6. package/lib/runtime/runtime.js +67 -5
  7. package/lib/setup.js +4 -4
  8. package/package.json +1 -1
  9. package/templates/project-builder/agents/code-fixer.md +50 -0
  10. package/templates/project-builder/agents/code-writer.md +3 -0
  11. package/templates/project-builder/agents/sanity-checker.md +6 -0
  12. package/templates/project-builder/agents/test-planner.md +3 -1
  13. package/templates/project-builder/config.js +4 -4
  14. package/templates/project-builder/scripts/workflow-helpers.js +104 -2
  15. package/templates/project-builder/workflow.js +151 -14
  16. package/templates/starter/config.js +1 -1
  17. package/vercel-server/api/submit/[token].js +0 -11
  18. package/vercel-server/local-server.js +0 -19
  19. package/vercel-server/public/remote/assets/index-BTLc1QSv.js +168 -0
  20. package/vercel-server/public/remote/assets/index-DLa4X08t.css +1 -0
  21. package/vercel-server/public/remote/index.html +2 -2
  22. package/vercel-server/ui/src/App.jsx +53 -18
  23. package/vercel-server/ui/src/components/ChoiceInteraction.jsx +69 -18
  24. package/vercel-server/ui/src/components/ConfirmInteraction.jsx +7 -7
  25. package/vercel-server/ui/src/components/ContentCard.jsx +607 -103
  26. package/vercel-server/ui/src/components/EventsLog.jsx +20 -13
  27. package/vercel-server/ui/src/components/Footer.jsx +9 -4
  28. package/vercel-server/ui/src/components/Header.jsx +12 -3
  29. package/vercel-server/ui/src/components/SendingCard.jsx +33 -0
  30. package/vercel-server/ui/src/components/TextInteraction.jsx +8 -8
  31. package/vercel-server/ui/src/index.css +82 -10
  32. package/vercel-server/public/remote/assets/index-CbgeVnKw.js +0 -148
  33. package/vercel-server/public/remote/assets/index-DHL_iHQW.css +0 -1
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-4{top:-1rem;right:-1rem;bottom:-1rem;left:-1rem}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.bottom-6{bottom:1.5rem}.left-2{left:.5rem}.left-4{left:1rem}.right-3{right:.75rem}.top-0{top:0}.top-1\/2{top:50%}.z-40{z-index:40}.z-50{z-index:50}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[100dvh\]{height:100dvh}.h-\[40vh\]{height:40vh}.h-full{height:100%}.max-h-\[60vh\]{max-height:60vh}.min-h-\[50vh\]{min-height:50vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-\[300px\]{max-width:300px}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-balance{text-wrap:balance}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[24px\]{border-radius:24px}.rounded-\[28px\]{border-radius:28px}.rounded-\[32px\]{border-radius:32px}.rounded-\[36px\]{border-radius:36px}.rounded-full{border-radius:9999px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-black{--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1))}.border-black\/10{border-color:#0000001a}.border-black\/20{border-color:#0003}.border-black\/30{border-color:#0000004d}.border-transparent{border-color:transparent}.bg-bg{background-color:var(--bg)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/10{background-color:#0000001a}.bg-black\/5{background-color:#0000000d}.bg-black\/\[0\.02\]{background-color:#00000005}.bg-black\/\[0\.03\]{background-color:#00000008}.bg-fg{background-color:var(--fg)}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/20{background-color:#fff3}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-bg{--tw-gradient-from: var(--bg) var(--tw-gradient-from-position);--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-bg{--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--bg) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-transparent{--tw-gradient-to: transparent var(--tw-gradient-to-position)}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-6{padding-bottom:1.5rem}.pl-11{padding-left:2.75rem}.pr-10{padding-right:2.5rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-\[0\.16em\]{letter-spacing:.16em}.tracking-\[0\.24em\]{letter-spacing:.24em}.tracking-\[0\.28em\]{letter-spacing:.28em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-\[0\.32em\]{letter-spacing:.32em}.tracking-\[0\.35em\]{letter-spacing:.35em}.tracking-\[0\.4em\]{letter-spacing:.4em}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-widest{letter-spacing:.1em}.text-bg{color:var(--bg)}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-black\/40{color:#0006}.text-black\/50{color:#00000080}.text-black\/60{color:#0009}.text-black\/70{color:#000000b3}.text-black\/80{color:#000c}.text-black\/85{color:#000000d9}.text-black\/90{color:#000000e6}.text-fg{color:var(--fg)}.text-subtle{color:var(--subtle)}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\/70{color:#ffffffb3}.text-white\/90{color:#ffffffe6}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-20{opacity:.2}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_10px_30px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow: 0 10px 30px rgba(0,0,0,.2);--tw-shadow-colored: 0 10px 30px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-black\/20{--tw-shadow-color: rgb(0 0 0 / .2);--tw-shadow: var(--tw-shadow-colored)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-2xl{--tw-blur: blur(40px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-3xl{--tw-backdrop-blur: blur(64px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}:root{--bg: #ffffff;--fg: #000000;--subtle: rgba(0, 0, 0, .45);--border: rgba(0, 0, 0, .12);--accent: #000000}.dark{--bg: #000000;--fg: #ffffff;--subtle: rgba(255, 255, 255, .45);--border: rgba(255, 255, 255, .18);--accent: #ffffff}body{background-color:var(--bg);color:var(--fg);font-family:Inter,sans-serif;transition:background-color .4s ease,color .4s ease;overflow:hidden;margin:0;height:100vh;height:100dvh;width:100vw}.custom-scroll::-webkit-scrollbar{width:4px}.custom-scroll::-webkit-scrollbar-track{background:transparent}.custom-scroll::-webkit-scrollbar-thumb{background:var(--subtle);border-radius:4px;opacity:.2}.markdown-body pre{background:#0000000d;padding:1.5rem;border-radius:12px;overflow-x:auto;font-size:.85rem;line-height:1.6}.dark .markdown-body pre{background:#ffffff14}.content-width{width:100%;max-width:900px;margin:0 auto}.main-container{height:100vh;width:100vw;display:flex;flex-direction:column}.main-stage{flex:1;position:relative;z-index:10;padding-top:calc(80px + env(safe-area-inset-top))}.jumper-input{background:transparent;border:none;color:inherit;font-family:inherit;font-weight:700;text-align:center;width:2.2rem;outline:none;padding:0;margin:0;font-size:inherit}.jumper-input::-webkit-inner-spin-button,.jumper-input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.nav-footer{height:80px;display:flex;align-items:center;justify-content:center;z-index:50}.footer-control{display:flex;align-items:center;gap:1.5rem;padding:.5rem 1.2rem;background:#0000000a;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);border-radius:99px;border:1px solid var(--border)}.dark .footer-control{background:#ffffff14}.tooltip{position:relative}.tooltip:after{content:attr(data-tooltip);position:absolute;bottom:-2.2rem;left:50%;transform:translate(-50%) translateY(4px);background:var(--fg);color:var(--bg);padding:.35rem .55rem;border-radius:999px;font-size:10px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .12s ease,transform .12s ease;box-shadow:0 12px 30px #00000026;z-index:40}.tooltip:hover:after,.tooltip:focus-visible:after{opacity:1;transform:translate(-50%) translateY(0)}.raw-json-block{margin:0;padding:1.5rem;border-radius:24px;border:1px solid var(--border);background:#0000000a;color:#000000d9;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"monospace";font-size:.85rem;line-height:1.6;white-space:pre-wrap;word-break:break-word;overflow:auto;max-height:70vh}.raw-json-block--full{max-height:none;overflow:visible}.dark .raw-json-block{background:#ffffff14;color:#ffffffe6}.json-token-key{color:#000000bf;font-weight:600}.json-token-string{color:#0009}.json-token-number,.json-token-boolean{color:#000000d9}.json-token-null{color:#00000073}.dark .json-token-key{color:#fffc}.dark .json-token-string{color:#ffffffa6}.dark .json-token-number,.dark .json-token-boolean{color:#ffffffe6}.dark .json-token-null{color:#ffffff8c}.placeholder\:text-black\/40::-moz-placeholder{color:#0006}.placeholder\:text-black\/40::placeholder{color:#0006}.placeholder\:opacity-20::-moz-placeholder{opacity:.2}.placeholder\:opacity-20::placeholder{opacity:.2}.hover\:scale-105:hover{--tw-scale-x: 1.05;--tw-scale-y: 1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-\[1\.02\]:hover{--tw-scale-x: 1.02;--tw-scale-y: 1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-black\/30:hover{border-color:#0000004d}.hover\:border-black\/40:hover{border-color:#0006}.hover\:bg-black\/5:hover{background-color:#0000000d}.hover\:bg-black\/\[0\.03\]:hover{background-color:#00000008}.hover\:text-black:hover{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.hover\:opacity-100:hover{opacity:1}.focus\:border-black:focus{--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-black\/30:focus{--tw-ring-color: rgb(0 0 0 / .3)}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:opacity-0:disabled{opacity:0}.disabled\:opacity-30:disabled{opacity:.3}.group[open] .group-open\:rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:opacity-60{opacity:.6}.group:hover .group-hover\:opacity-70{opacity:.7}.dark\:border-white:is(.dark *){--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.dark\:border-white\/10:is(.dark *){border-color:#ffffff1a}.dark\:border-white\/15:is(.dark *){border-color:#ffffff26}.dark\:border-white\/20:is(.dark *){border-color:#fff3}.dark\:border-white\/30:is(.dark *){border-color:#ffffff4d}.dark\:bg-black:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.dark\:bg-black\/20:is(.dark *){background-color:#0003}.dark\:bg-white:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.dark\:bg-white\/10:is(.dark *){background-color:#ffffff1a}.dark\:bg-white\/20:is(.dark *){background-color:#fff3}.dark\:bg-white\/5:is(.dark *){background-color:#ffffff0d}.dark\:bg-white\/\[0\.03\]:is(.dark *){background-color:#ffffff08}.dark\:bg-white\/\[0\.04\]:is(.dark *){background-color:#ffffff0a}.dark\:text-black:is(.dark *){--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.dark\:text-black\/70:is(.dark *){color:#000000b3}.dark\:text-black\/90:is(.dark *){color:#000000e6}.dark\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.dark\:text-white\/40:is(.dark *){color:#fff6}.dark\:text-white\/50:is(.dark *){color:#ffffff80}.dark\:text-white\/60:is(.dark *){color:#fff9}.dark\:text-white\/70:is(.dark *){color:#ffffffb3}.dark\:text-white\/80:is(.dark *){color:#fffc}.dark\:text-white\/85:is(.dark *){color:#ffffffd9}.dark\:text-white\/90:is(.dark *){color:#ffffffe6}.dark\:shadow-\[0_10px_30px_rgba\(255\,255\,255\,0\.1\)\]:is(.dark *){--tw-shadow: 0 10px 30px rgba(255,255,255,.1);--tw-shadow-colored: 0 10px 30px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.dark\:shadow-white\/10:is(.dark *){--tw-shadow-color: rgb(255 255 255 / .1);--tw-shadow: var(--tw-shadow-colored)}.dark\:placeholder\:text-white\/40:is(.dark *)::-moz-placeholder{color:#fff6}.dark\:placeholder\:text-white\/40:is(.dark *)::placeholder{color:#fff6}.dark\:hover\:border-white\/30:hover:is(.dark *){border-color:#ffffff4d}.dark\:hover\:border-white\/40:hover:is(.dark *){border-color:#fff6}.dark\:hover\:bg-white\/10:hover:is(.dark *){background-color:#ffffff1a}.dark\:hover\:bg-white\/\[0\.04\]:hover:is(.dark *){background-color:#ffffff0a}.dark\:hover\:text-white:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.dark\:focus\:border-white:focus:is(.dark *){--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.dark\:focus\:ring-white\/40:focus:is(.dark *){--tw-ring-color: rgb(255 255 255 / .4)}.group:hover .dark\:group-hover\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.sm\:left-4{left:1rem}.sm\:grid-cols-\[160px_1fr\]{grid-template-columns:160px 1fr}.sm\:items-start{align-items:flex-start}.sm\:p-8{padding:2rem}.sm\:px-10{padding-left:2.5rem;padding-right:2.5rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}.sm\:py-14{padding-top:3.5rem;padding-bottom:3.5rem}.sm\:pt-10{padding-top:2.5rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-xl{font-size:1.25rem;line-height:1.75rem}}@media (min-width: 768px){.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-7xl{font-size:4.5rem;line-height:1}}@media (min-width: 1024px){.lg\:px-10{padding-left:2.5rem;padding-right:2.5rem}.lg\:px-12{padding-left:3rem;padding-right:3rem}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2) format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-greek-wght-normal-CkhJZR-_.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/remote/assets/inter-latin-wght-normal-Dx4kXJAl.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,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) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/remote/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/remote/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/remote/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/remote/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/remote/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
6
  <title>{{WORKFLOW_NAME}}</title>
7
- <script type="module" crossorigin src="/remote/assets/index-CbgeVnKw.js"></script>
8
- <link rel="stylesheet" crossorigin href="/remote/assets/index-DHL_iHQW.css">
7
+ <script type="module" crossorigin src="/remote/assets/index-BTLc1QSv.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/remote/assets/index-DLa4X08t.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -5,6 +5,7 @@ import EventsLog from "./components/EventsLog.jsx";
5
5
  import Footer from "./components/Footer.jsx";
6
6
  import Header from "./components/Header.jsx";
7
7
  import InteractionForm from "./components/InteractionForm.jsx";
8
+ import SendingCard from "./components/SendingCard.jsx";
8
9
 
9
10
  export default function App() {
10
11
  const [history, setHistory] = useState([]);
@@ -15,6 +16,7 @@ export default function App() {
15
16
  const [viewMode, setViewMode] = useState("present");
16
17
  const [pendingInteraction, setPendingInteraction] = useState(null);
17
18
  const [hasNew, setHasNew] = useState(false);
19
+ const [sendingState, setSendingState] = useState(null);
18
20
 
19
21
  useEffect(() => {
20
22
  const savedTheme = localStorage.getItem("rf_theme") || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
@@ -76,6 +78,32 @@ export default function App() {
76
78
  prevLen.current = history.length;
77
79
  }, [history.length, pageIndex]);
78
80
 
81
+ useEffect(() => {
82
+ if (!sendingState || history.length === 0) return;
83
+ const latest = history[history.length - 1];
84
+ const hasNewEvent =
85
+ history.length !== sendingState.historyLength ||
86
+ (latest?.timestamp && latest.timestamp !== sendingState.lastEventTimestamp);
87
+
88
+ if (!hasNewEvent) return;
89
+
90
+ if (latest?.event === "INTERACTION_SUBMITTED") {
91
+ setSendingState((prev) =>
92
+ prev
93
+ ? {
94
+ ...prev,
95
+ historyLength: history.length,
96
+ lastEventTimestamp: latest?.timestamp || prev.lastEventTimestamp,
97
+ }
98
+ : prev
99
+ );
100
+ return;
101
+ }
102
+
103
+ setSendingState(null);
104
+ setPageIndex(history.length - 1);
105
+ }, [history, sendingState]);
106
+
79
107
  useEffect(() => {
80
108
  if (pageIndex === history.length - 1) {
81
109
  setHasNew(false);
@@ -112,6 +140,7 @@ export default function App() {
112
140
  const currentItem = history[pageIndex];
113
141
  const isRequestEvent = currentItem && (currentItem.event === "INTERACTION_REQUESTED" || currentItem.event === "PROMPT_REQUESTED");
114
142
  const isRequest = pendingInteraction && isRequestEvent && currentItem.slug === pendingInteraction.slug;
143
+ const isSending = Boolean(sendingState);
115
144
 
116
145
  return (
117
146
  <div className="w-full h-[100dvh] flex flex-col relative overflow-hidden bg-bg">
@@ -144,30 +173,36 @@ export default function App() {
144
173
  transition={{ duration: 0.3, ease: [0.16, 1, 0.3, 1] }}
145
174
  className="w-full h-full"
146
175
  >
147
- {isRequest ? (
176
+ {isSending ? (
177
+ <SendingCard submission={sendingState} />
178
+ ) : isRequest ? (
148
179
  <div className="content-width h-full">
149
180
  <InteractionForm
150
181
  interaction={pendingInteraction}
151
182
  onSubmit={async (slug, targetKey, response) => {
152
- const responsePreview = typeof response === "string" ? response : JSON.stringify(response);
153
- setHistory((prev) => [
154
- ...prev,
155
- {
156
- timestamp: new Date().toISOString(),
157
- event: "INTERACTION_SUBMITTED",
158
- answer: responsePreview,
159
- response
160
- }
161
- ]);
162
- setPageIndex((prev) => prev + 1);
163
- await fetch(submitUrl, {
164
- method: "POST",
165
- headers: { "Content-Type": "application/json" },
166
- body: JSON.stringify({ slug, targetKey, response })
183
+ const lastEvent = history[history.length - 1];
184
+ setSendingState({
185
+ slug,
186
+ targetKey,
187
+ historyLength: history.length,
188
+ lastEventTimestamp: lastEvent?.timestamp || null,
167
189
  });
168
- setTimeout(fetchData, 1000);
190
+ try {
191
+ const res = await fetch(submitUrl, {
192
+ method: "POST",
193
+ headers: { "Content-Type": "application/json" },
194
+ body: JSON.stringify({ slug, targetKey, response })
195
+ });
196
+ if (!res.ok) {
197
+ throw new Error(`Submit failed with ${res.status}`);
198
+ }
199
+ } catch (error) {
200
+ setSendingState(null);
201
+ } finally {
202
+ setTimeout(fetchData, 1000);
203
+ }
169
204
  }}
170
- disabled={status === "disconnected"}
205
+ disabled={status === "disconnected" || isSending}
171
206
  />
172
207
  </div>
173
208
  ) : (
@@ -1,15 +1,31 @@
1
- import { useMemo, useState } from "react";
1
+ import { useEffect, useMemo, useState } from "react";
2
2
  import { Bot, Check } from "lucide-react";
3
3
 
4
4
  export default function ChoiceInteraction({ interaction, onSubmit, disabled }) {
5
- const { prompt, question, options = [], multiSelect, allowCustom } = interaction;
5
+ const { prompt, question, options = [], multiSelect, allowCustom, fullAuto, autoSelectDelay = 20, timestamp } = interaction;
6
6
  const [selected, setSelected] = useState(multiSelect ? [] : null);
7
7
  const [customText, setCustomText] = useState("");
8
8
  const [showCustom, setShowCustom] = useState(false);
9
+ const [tick, setTick] = useState(0);
9
10
 
10
11
  const list = useMemo(() => options || [], [options]);
11
12
  const title = prompt || question || "Choose an option.";
12
13
 
14
+ // Calculate countdown based on event timestamp
15
+ const countdown = useMemo(() => {
16
+ if (!fullAuto || !timestamp) return null;
17
+ const eventTime = new Date(timestamp).getTime();
18
+ const elapsed = Math.floor((Date.now() - eventTime) / 1000);
19
+ return autoSelectDelay - elapsed;
20
+ }, [fullAuto, timestamp, autoSelectDelay, tick]);
21
+
22
+ // Tick every second to update countdown
23
+ useEffect(() => {
24
+ if (!fullAuto) return;
25
+ const timer = setInterval(() => setTick(t => t + 1), 1000);
26
+ return () => clearInterval(timer);
27
+ }, [fullAuto]);
28
+
13
29
  const handleSelect = (key) => {
14
30
  if (multiSelect) {
15
31
  setSelected((prev) => (
@@ -44,19 +60,43 @@ export default function ChoiceInteraction({ interaction, onSubmit, disabled }) {
44
60
  <div className="w-full h-full flex flex-col items-stretch overflow-hidden">
45
61
  <div className="flex-1 overflow-y-auto custom-scroll px-6 py-12 space-y-8 flex flex-col items-center">
46
62
  <div className="space-y-4 shrink-0">
47
- <div className="w-16 h-16 rounded-3xl bg-accent text-white flex items-center justify-center mx-auto shadow-2xl shadow-accent/40">
63
+ <div className="w-16 h-16 rounded-3xl bg-black text-white dark:bg-white dark:text-black flex items-center justify-center mx-auto shadow-2xl shadow-black/20 dark:shadow-white/10">
48
64
  <Bot className="w-8 h-8" />
49
65
  </div>
50
- <h3 className="text-4xl font-extrabold tracking-tight text-fg pt-4 text-center">Choose an option.</h3>
66
+ <h3 className="text-3xl sm:text-4xl font-extrabold tracking-tight text-fg pt-4 text-center">Choose an option.</h3>
51
67
  </div>
52
68
 
53
- <div className="text-xl font-medium text-fg/70 text-center max-w-2xl whitespace-pre-wrap">
69
+ <div className="text-lg sm:text-xl font-medium text-fg/70 text-center max-w-2xl whitespace-pre-wrap break-words">
54
70
  {title}
55
71
  </div>
56
72
 
73
+ {fullAuto && countdown !== null && (
74
+ <div className="text-center">
75
+ <div className={`inline-flex items-center gap-2 px-4 py-2 rounded-full ${
76
+ countdown > 0
77
+ ? "bg-yellow-500 text-black animate-pulse"
78
+ : "bg-black text-white dark:bg-white dark:text-black"
79
+ }`}>
80
+ <span className="text-xl">⚡</span>
81
+ <span className="text-sm font-bold">
82
+ {countdown > 0
83
+ ? `Agent deciding in ${countdown}s...`
84
+ : "Auto-selecting recommended option..."}
85
+ </span>
86
+ </div>
87
+ </div>
88
+ )}
89
+
57
90
  <div className="w-full max-w-2xl space-y-3">
58
- {list.map((opt) => {
91
+ {list.map((opt, index) => {
59
92
  const isSelected = multiSelect ? selected.includes(opt.key) : selected === opt.key;
93
+ const labelClass = isSelected
94
+ ? "text-white dark:text-black"
95
+ : "text-black dark:text-white";
96
+ const descriptionClass = isSelected
97
+ ? "text-white/70 dark:text-black/70"
98
+ : "text-black/50 dark:text-white/50";
99
+
60
100
  return (
61
101
  <button
62
102
  key={opt.key}
@@ -65,21 +105,32 @@ export default function ChoiceInteraction({ interaction, onSubmit, disabled }) {
65
105
  type="button"
66
106
  className={`w-full p-6 rounded-2xl border-2 transition-all text-left ${
67
107
  isSelected
68
- ? "border-accent bg-accent/10"
69
- : "border-white/10 hover:border-white/20 bg-black/[0.03] dark:bg-white/[0.03]"
108
+ ? "border-black bg-black text-white dark:border-white dark:bg-white dark:text-black"
109
+ : "border-black/10 dark:border-white/10 hover:border-black/30 dark:hover:border-white/30 bg-black/[0.02] dark:bg-white/[0.03]"
70
110
  }`}
71
111
  >
72
112
  <div className="flex items-center gap-4">
73
113
  <div className={`w-6 h-6 rounded-full border-2 flex items-center justify-center ${
74
114
  isSelected
75
- ? "border-accent bg-accent text-white"
76
- : "border-white/20"
115
+ ? "border-black bg-black text-white dark:border-white dark:bg-white dark:text-black"
116
+ : "border-black/30 dark:border-white/30"
77
117
  }`}>
78
118
  {isSelected && <Check className="w-4 h-4" />}
79
119
  </div>
80
120
  <div className="flex-1">
81
- <div className="font-bold text-lg">{opt.label || opt.key}</div>
82
- {opt.description && <div className="text-sm text-fg/50 mt-1">{opt.description}</div>}
121
+ <div className={`font-bold text-lg break-words flex flex-wrap items-center gap-2 ${labelClass}`}>
122
+ <span className="break-words">{opt.label || opt.key}</span>
123
+ {index === 0 && (
124
+ <span className={`ml-2 text-xs font-medium px-2 py-0.5 rounded-full ${
125
+ isSelected
126
+ ? 'bg-white/20 dark:bg-black/20'
127
+ : 'bg-black/10 dark:bg-white/10'
128
+ }`}>
129
+ Recommended
130
+ </span>
131
+ )}
132
+ </div>
133
+ {opt.description && <div className={`text-sm mt-1 break-words ${descriptionClass}`}>{opt.description}</div>}
83
134
  </div>
84
135
  </div>
85
136
  </button>
@@ -93,12 +144,12 @@ export default function ChoiceInteraction({ interaction, onSubmit, disabled }) {
93
144
  type="button"
94
145
  className={`w-full p-6 rounded-2xl border-2 transition-all text-left ${
95
146
  showCustom
96
- ? "border-accent bg-accent/10"
97
- : "border-white/10 hover:border-white/20 bg-black/[0.03] dark:bg-white/[0.03]"
147
+ ? "border-black bg-black text-white dark:border-white dark:bg-white dark:text-black"
148
+ : "border-black/10 dark:border-white/10 hover:border-black/30 dark:hover:border-white/30 bg-black/[0.02] dark:bg-white/[0.03]"
98
149
  }`}
99
150
  >
100
- <div className="font-bold text-lg">Other</div>
101
- <div className="text-sm text-fg/50 mt-1">Provide a custom response</div>
151
+ <div className={`font-bold text-lg break-words ${showCustom ? "text-white dark:text-black" : "text-black dark:text-white"}`}>Other</div>
152
+ <div className={`text-sm mt-1 break-words ${showCustom ? "text-white/70 dark:text-black/70" : "text-black/50 dark:text-white/50"}`}>Provide a custom response</div>
102
153
  </button>
103
154
  )}
104
155
 
@@ -107,13 +158,13 @@ export default function ChoiceInteraction({ interaction, onSubmit, disabled }) {
107
158
  value={customText}
108
159
  onChange={(event) => setCustomText(event.target.value)}
109
160
  placeholder="Type your response..."
110
- className="w-full h-32 p-6 rounded-2xl bg-black/[0.03] dark:bg-white/[0.03] border-2 border-accent/30 focus:border-accent focus:outline-none text-lg"
161
+ className="w-full h-32 p-6 rounded-2xl bg-black/[0.02] dark:bg-white/[0.03] border-2 border-black/20 dark:border-white/20 focus:border-black dark:focus:border-white focus:outline-none text-lg"
111
162
  />
112
163
  )}
113
164
  </div>
114
165
  </div>
115
166
 
116
- <div className="p-4 flex justify-center bg-gradient-to-t from-bg via-bg to-transparent shrink-0 border-t border-white/5">
167
+ <div className="p-4 flex justify-center bg-gradient-to-t from-bg via-bg to-transparent shrink-0 border-t border-black/10 dark:border-white/10">
117
168
  <button
118
169
  onClick={handleSubmit}
119
170
  disabled={disabled || !isValid}
@@ -13,35 +13,35 @@ export default function ConfirmInteraction({ interaction, onSubmit, disabled })
13
13
  <div className="w-full h-full flex flex-col items-stretch overflow-hidden">
14
14
  <div className="flex-1 overflow-y-auto custom-scroll px-6 py-12 space-y-8 flex flex-col items-center justify-center">
15
15
  <div className="space-y-4">
16
- <div className="w-16 h-16 rounded-3xl bg-accent text-white flex items-center justify-center mx-auto shadow-2xl shadow-accent/40">
16
+ <div className="w-16 h-16 rounded-3xl bg-black text-white dark:bg-white dark:text-black flex items-center justify-center mx-auto shadow-2xl shadow-black/20 dark:shadow-white/10">
17
17
  <Bot className="w-8 h-8" />
18
18
  </div>
19
- <h3 className="text-4xl font-extrabold tracking-tight text-fg pt-4 text-center">Confirm action.</h3>
19
+ <h3 className="text-3xl sm:text-4xl font-extrabold tracking-tight text-fg pt-4 text-center">Confirm action.</h3>
20
20
  </div>
21
21
 
22
- <div className="text-xl font-medium text-fg/70 text-center max-w-2xl whitespace-pre-wrap">
22
+ <div className="text-lg sm:text-xl font-medium text-fg/70 text-center max-w-2xl whitespace-pre-wrap break-words">
23
23
  {prompt || question || "Please confirm."}
24
24
  </div>
25
25
 
26
26
  {context?.documentPath && (
27
27
  <div className="text-sm text-fg/40 text-center">
28
- Review: <code className="bg-white/10 px-2 py-1 rounded">{context.documentPath}</code>
28
+ Review: <code className="bg-black/10 dark:bg-white/10 px-2 py-1 rounded">{context.documentPath}</code>
29
29
  </div>
30
30
  )}
31
31
  </div>
32
32
 
33
- <div className="p-4 flex justify-center gap-4 bg-gradient-to-t from-bg via-bg to-transparent shrink-0 border-t border-white/5">
33
+ <div className="p-4 flex justify-center gap-4 bg-gradient-to-t from-bg via-bg to-transparent shrink-0 border-t border-black/10 dark:border-white/10">
34
34
  <button
35
35
  onClick={() => onSubmit({ confirmed: false, raw: cancelLabel })}
36
36
  disabled={disabled}
37
- className="px-12 py-6 bg-white/10 text-fg rounded-full font-bold text-xl hover:bg-white/20 transition-all disabled:opacity-30"
37
+ className="px-12 py-6 border border-black/20 dark:border-white/20 text-fg rounded-full font-bold text-xl hover:bg-black/5 dark:hover:bg-white/10 transition-all disabled:opacity-30"
38
38
  >
39
39
  {cancelLabel}
40
40
  </button>
41
41
  <button
42
42
  onClick={() => onSubmit({ confirmed: true, raw: confirmLabel })}
43
43
  disabled={disabled}
44
- className="px-12 py-6 bg-fg text-bg rounded-full font-bold text-xl hover:scale-105 active:scale-95 transition-all disabled:opacity-30 shadow-2xl"
44
+ className="px-12 py-6 bg-fg text-bg rounded-full font-bold text-xl hover:scale-105 active:scale-95 transition-all disabled:opacity-30 shadow-2xl shadow-black/20 dark:shadow-white/10"
45
45
  >
46
46
  {confirmLabel}
47
47
  </button>