eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
7 lines • 12.4 kB
JavaScript
import{maskLine,visibleLine}from"./line-editor.js";import{clipVisible,renderInputText,renderInputWithBlockCursor,visibleLength,wrapVisibleLine}from"#cli/ui/terminal-text.js";import{renderCursorRow,renderOptionRow,resolveOptionRowState}from"#setup/cli/option-row.js";import{filterOptions,submitRowIndex}from"#setup/cli/select-state.js";function clip(e,t){return clipVisible(e,t)}function questionFooter(e,t,n){let r=t.colors,i=e.join(` ${t.glyph.dot} `);return[``,...(n===void 0?[i]:wrapVisibleLine(i,Math.max(1,n-3))).map(e=>` ${r.dim(e)}`)]}function solidWithinDim(e,t){return t.color?`[22m${e}[2m`:e}function toneGlyph(e,t){let n=t.colors;switch(e){case`success`:return n.green(t.glyph.success);case`warning`:return n.yellow(t.glyph.warning);case`error`:return n.red(t.glyph.error);case`info`:return n.dim(t.glyph.dot)}}function renderIndicator(e,t){return e.color===`green`?t.colors.green(e.glyph):t.colors.yellow(e.glyph)}function renderStatusText(e,t){if(e.kind===`progress`)return t.colors.dim(e.text);let n=e.text.indexOf(e.emphasis);if(n===-1)return t.colors.dim(e.text);let r=n+e.emphasis.length;return`${t.colors.dim(e.text.slice(0,n))}${t.colors.yellow(e.text.slice(n,r))}${t.colors.dim(e.text.slice(r))}`}function renderFlowPanelStatus(e,t){return`${renderIndicator(e.indicator,t)} ${renderStatusText(e,t)}`}function flowMessageRows(e,t){let n=t.colors,r=[],i=e.slice(-6);for(let e of i){let i=e.text.split(`
`);for(let[a,o]of i.entries()){let i=e.tone===`info`?n.dim(o):o,s=a===0?`${toneGlyph(e.tone,t)} `:` `;r.push(` ${s}${i}`)}}return i.length>0&&r.push(``),r}function renderFlowPanel(e,t,n){let r=t.colors,i=[],a=e.content.kind===`question`?e.content.title??e.title:e.title;if(a.length>0){for(let e of a.split(`
`)){if(e.length===0){i.push(``);continue}for(let t of wrapVisibleLine(e,Math.max(1,n-3)))i.push(` ${r.bold(t)}`)}i.push(``)}switch(e.navigation?.kind===`planner`&&i.push(...plannerStepRows(e.navigation,void 0,t)),i.push(...flowMessageRows(e.lines,t)),e.content.kind){case`question`:e.content.status!==void 0&&i.push(` ${renderFlowPanelStatus(e.content.status,t)}`,``),i.push(...e.content.rows);break;case`status`:if(i.push(` ${renderFlowPanelStatus(e.content.status,t)}`),e.content.preview!==void 0)for(let t of e.content.preview.split(`
`))i.push(` ${r.dim(t)}`);break;case`preview`:{let[n,...a]=e.content.text.split(`
`);i.push(` ${renderIndicator(e.content.indicator,t)} ${r.dim(n??``)}`);for(let e of a)i.push(` ${r.dim(e)}`);break}case`idle`:i.push(` ${renderIndicator(e.content.indicator,t)} ${r.dim(`Working…`)}`)}return i.map(e=>e.length===0?clip(e,n):clip(` ${e}`,n))}function optionRow(e){let{option:t,theme:n}=e,r=e.railed===!0;return renderOptionRow({colors:n.colors,glyphs:{pointer:n.glyph.pointer,selectedPointer:n.glyph.selectedPointer,success:n.glyph.success,placeholder:n.glyph.option,dot:r?``:n.glyph.dot,warning:n.glyph.warning},label:t.label,hint:t.hint,focusHint:t.focusHint,accent:t.accent,isCursor:e.isCursor,state:resolveOptionRowState(t,e.isChecked),placeholder:e.placeholder,hintPadding:e.hintPadding})}function selectPresentation(e){switch(e.kind){case`single`:return{selection:`single`,filter:void 0,layout:`plain`,edit:void 0};case`search`:return{selection:`single`,filter:{placeholder:e.placeholder},layout:e.layout??`plain`,edit:void 0};case`multi`:return{selection:`multiple`,filter:void 0,layout:`plain`,edit:void 0};case`searchable-multi`:return{selection:`multiple`,filter:{placeholder:e.placeholder},layout:e.layout??`plain`,edit:void 0};case`stacked`:return{selection:`single`,filter:void 0,layout:`stacked`,edit:void 0};case`task-list`:return{selection:`single`,filter:void 0,layout:`task-list`,edit:void 0};case`inline-edit`:return{selection:`single`,filter:void 0,layout:e.layout,edit:e.edit}}}function canNavigateBack(e){return e.activeStep>(e.firstNavigableStep??0)}function canNavigateForward(e){return e.activeStep>=(e.firstNavigableStep??0)&&e.activeStep<e.steps.length-1}function plannerStepRows(e,t,n){let r=e.steps.map((r,i)=>{let a=i===e.activeStep?t:r.count,o=a===void 0||a===0?``:` (${a})`,s=`${r.complete===!0?`${n.glyph.success} `:``}${r.label}${o}`;return i===e.activeStep?n.colors.bold(` ${s}`):r.complete===!0?n.colors.green(s):n.colors.dim(s)});return[` ${r.flatMap((t,i)=>{if(i===r.length-1)return[t];let a=e.activeStep===i&&canNavigateForward(e)?` → `:e.activeStep===i+1&&canNavigateBack(e)?` ← `:` · `;return[t,n.colors.dim(a)]}).join(``)}`,``]}function selectMessageRows(e,t,n,r){if(e===``)return[];let i=e.split(`
`).flatMap((e,i)=>{let a=t===`stacked`||i>0;return wrapVisibleLine(e,Math.max(1,r-4)).map(e=>` ${a?n.colors.bold(e):e}`)});return i.push(``),i}function searchFilter(e,t,n,r,i){let a=r.colors.dim(r.glyph.caret),o=a;return i?o=e.length>0?e+a:r.colors.dim(t??`type to filter`):e.length>0?o=e+a:t!==void 0&&(o=r.colors.dim(`> ${t}`)),n===void 0?o:`${o} ${r.colors.yellow(n)}`}function isRailedSearch(e){return e.filter!==void 0&&e.layout===`plain`&&e.selection===`single`&&e.edit===void 0}function selectViewSize(e){return e.search?e.railed?5:e.stacked?Math.min(e.optionCount,8):8:e.optionCount}function noticeBody(e,t,n){return e.tone===`info`?n.colors.dim(e.text):e.tone===`success`&&t===`task-list`?n.colors.bold(e.text):e.text}function renameHint(e,t,n,r){let i={text:n.editor.text||n.defaultValue,cursor:n.editor.cursor},a=renderInputWithBlockCursor({...visibleLine(i,1/0),visible:t,inverse:r.colors.inverse});return n.editor.text.length>0&&(a=solidWithinDim(a,r)),{...e,hint:n.formatHint(a)}}function keyHint(e,t,n,r,i){let a=n.phase;if(a.kind===`inactive`)return e;let o=r.colors,s=maskLine(a.editor),c=a.kind!==`validating`&&a.kind!==`invalid`,l=``;a.kind===`editing`?l=` ${enterBadge(r,`validate`)}`:a.kind===`validating`?l=` ${o.yellow(r.glyph.validating)} ${o.dim(`validating`)}`:a.kind===`invalid`&&(l=` ${o.red(`${r.glyph.error} API key is not valid`)}`);let u=`${r.glyph.elbow} `,d=a.editor.text.length===0?`type your key`:void 0,f=d===void 0?s:{text:d,cursor:0},p=Math.max(1,i-visibleLength(`${u}${l}`)),m=visibleLine(f,p,r.glyph.ellipsis),h=c?renderInputWithBlockCursor({...m,visible:t,inverse:r.colors.inverse}):renderInputText(`${m.before}${m.under}${m.after}`);return{...e,hint:`${u}${h}${l}`}}function inlineEditOption(e,t,n,r,i){if(!t||n===void 0||e.value!==n.optionValue)return e;switch(n.editor.kind){case`rename`:return renameHint(e,n.caretVisible,n.editor,r);case`key`:return keyHint(e,n.caretVisible,n.editor,r,i)}}function optionUsesPlaceholder(e,t){let n=e.filter!==void 0&&e.layout!==`task-list`,r=e.selection===`multiple`,i=e.layout!==`plain`;return!n&&!t&&(r||i)}function appendSelectOptionRows(e){let{rows:t,state:n,presentation:r,visible:i,start:a,end:o,cursor:s,visibleLabelWidth:c,width:l,theme:u}=e,d=!1;for(let e=a;e<o;e+=1){let o=i[e],f=e===s,p=r.layout===`task-list`&&o.trailingAction===!0;p&&(appendSelectNotices(t,n.notices,r.layout,u,l),d=!0),p&&(e>a||(n.notices?.length??0)>0)&&t.push(``);let m=r.layout===`stacked`?Math.max(1,l-6):Math.max(1,l-Math.max(c,o.label.length)-9),h=inlineEditOption(o,f,r.edit,u,m),g=r.edit?.editor.kind===`key`&&f,_={...h,hint:(h.hint??(f||o.disabled?o.description:void 0))?.replace(/\s*\n\s*/gu,` `)};g&&(_.hint=void 0);let v=isRailedSearch(r),y=n.cursorBadge,b=f&&y!==void 0?` ${y}`:``;t.push(` ${optionRow({option:_,isCursor:f,isChecked:r.selection===`multiple`?n.select.selected.has(o.value):o.checked===!0,placeholder:v||optionUsesPlaceholder(r,p),railed:v,hintPadding:Math.max(0,c-_.label.length),theme:u})}${b}`),g&&h.hint&&t.push(` ${h.hint}`)}return d}function appendSubmitRow(e,t,n,r){if(n<0)return;let i=t===n,a=i?`${r.glyph.selectedPointer} ${r.colors.bold(`Submit`)}`:` Submit`;e.push(``,` ${renderCursorRow(a,i,r.colors)}`)}function appendSelectNotices(e,t,n,r,i){if(t!==void 0&&t.length!==0){e.push(``);for(let a of t){let t=toneGlyph(a.tone,r),o=` `.repeat(visibleLength(t)+1),s=Math.max(1,i-2-visibleLength(t)-1),c=wrapVisibleLine(a.text,s);for(let[i,s]of c.entries()){let c=noticeBody({...a,text:s},n,r);e.push(i===0?` ${t} ${c}`:` ${o}${c}`)}}}}function selectFooterHints(e,t,n,r){let i=[],a=`esc to cancel`,o=e.edit;if(o!==void 0&&t[n]?.value===o.optionValue){if(o.editor.kind===`key`){let e=o.editor.phase;if(e.kind!==`inactive`&&e.editor.text.length>0&&(a=`esc to clear`),e.kind===`validating`)return[a];i.push(`type your key`)}else i.push(`type to rename`)}if(e.filter!==void 0&&i.push(`type to filter`),i.push(`↑/↓ move`),r!==void 0){let t=canNavigateBack(r),n=canNavigateForward(r);return i.push(e.selection===`multiple`?`space/enter toggle`:`enter to select`),t&&n?i.push(`←/→ steps`):t?i.push(`← back`):n&&i.push(`→ next`),i.push(a),i}return i.push(e.selection===`multiple`?`space to toggle`:`enter to select`),e.selection===`multiple`&&i.push(`enter on Submit to confirm`),i.push(a),i}function renderActionQuestion(e,t,n){let r=[` ${t.colors.dim(`${t.glyph.dot} ${e.context}`)}`,``];for(let[n,i]of e.actions.entries())r.push(` ${optionRow({option:i,isCursor:n===e.cursor,isChecked:!1,placeholder:!0,hintPadding:0,theme:t})}`);return r.push(...questionFooter([`↑/↓ move`,`enter to select`,`esc to cancel`],t)),r.map(e=>clip(e,n))}function renderSelectQuestion(e,t,n){if(e.kind===`actions`)return renderActionQuestion(e,t,n);let r=t.colors,i=selectPresentation(e),a=i.filter?filterOptions(e.options,e.select.filter,e.searchAction):e.options,o=e.navigation?.kind===`planner`?e.navigation:void 0,s=i.selection===`multiple`&&o===void 0?submitRowIndex(a):-1,c=e.select.cursor,l=isRailedSearch(i),u=[...e.navigation?.kind===`planner`?plannerStepRows(e.navigation,i.selection===`multiple`?e.select.selected.size:void 0,t):[],...selectMessageRows(e.message,i.layout,t,n)];if(e.description!==void 0||e.metadata!==void 0){if(u.at(-1)===``&&u.pop(),e.description!==void 0)for(let t of wrapVisibleLine(e.description,Math.max(1,n-4)))u.push(` ${r.dim(t)}`);for(let{label:t,value:i}of e.metadata??[]){let e=`${t}: `,a=wrapVisibleLine(i,Math.max(1,n-4-e.length));u.push(` ${r.dim(`${e}${a[0]??``}`)}`);for(let t of a.slice(1))u.push(` ${r.dim(`${` `.repeat(e.length)}${t}`)}`)}u.push(``)}i.filter!==void 0&&u.push(` ${l?` `:``}${searchFilter(e.select.filter,i.filter.placeholder,e.loadingFrame,t,l)}`);let d=selectViewSize({search:i.filter!==void 0,filter:e.select.filter,optionCount:a.length,railed:l,stacked:i.layout===`stacked`}),f=Math.max(0,Math.min(c-Math.floor(d/2),Math.max(0,a.length-d))),p=Math.min(f+d,a.length),m=a.slice(f,p).filter(e=>e.hint!==void 0||e.focusHint!==void 0).reduce((e,t)=>Math.max(e,t.label.length),0);a.length===0&&u.push(` ${r.dim(`(no matches)`)}`);let h=appendSelectOptionRows({rows:u,state:e,presentation:i,visible:a,start:f,end:p,cursor:c,visibleLabelWidth:m,width:n,theme:t});if(appendSubmitRow(u,c,s,t),o!==void 0&&i.selection===`multiple`){let t=e.select.selected.size;u.push(``,` ${r.dim(`${t} selected`)}`)}return!l&&a.length>p-f&&u.push(` ${r.dim(`↑↓ ${a.length} options, showing ${f+1}–${p}`)}`),h||appendSelectNotices(u,e.notices,i.layout,t,n),e.error!==void 0&&u.push(``,` ${r.red(e.error)}`),u.push(...questionFooter(e.footerHints??(l?[`Enter select`,`Esc back`]:selectFooterHints(i,a,c,o)),t,n)),u.map(e=>clip(e,n))}function enterBadge(e,t){return e.colors.dim(t===void 0?e.glyph.enter:`${e.glyph.enter} ${t}`)}function renderTextQuestion(e,t,n,r){let i=t.colors,a=[];for(let n of e.notices??[]){let e=n.tone===`info`?i.dim(n.text):n.text;a.push(`${toneGlyph(n.tone,t)} ${e}`)}e.message!==``&&a.push(...e.message.split(`
`).map(e=>` ${i.bold(e)}`));let o=Math.max(4,n-4),s=e.mask?maskLine(e.editor):e.editor,c=e.editor.text.length===0?e.placeholder:void 0,l=renderInputWithBlockCursor({...visibleLine(c===void 0?s:{text:c,cursor:0},o,t.glyph.ellipsis),visible:r,inverse:i.inverse,render:c===void 0?renderInputText:e=>i.dim(renderInputText(e))});return a.push(` ${l}`),e.error!==void 0&&a.push(``,` ${i.red(e.error)}`),a.push(...questionFooter([`enter to submit`,`esc to cancel`],t)),a.map(e=>clip(e,n))}function renderAcknowledgeQuestion(e,t,n){let r=t.colors,i=e.message===``?[]:[` ${r.bold(e.message)}`];if(e.lines.length>0){i.push(``);for(let t of e.lines)i.push(` ${r.dim(t)}`)}return i.push(...questionFooter([`enter to continue`],t)),i.map(e=>clip(e,n))}export{enterBadge,flowMessageRows,renderAcknowledgeQuestion,renderFlowPanel,renderSelectQuestion,renderTextQuestion};