citadel_cli 1.4.1 → 1.4.2
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/README.md +1 -0
- package/dist/citadel.es.js +744 -717
- package/dist/citadel.umd.cjs +6 -6
- package/dist/citadel.umd.js +6 -6
- package/dist/components/Citadel/config/defaults.d.ts +2 -0
- package/dist/components/Citadel/config/types.d.ts +6 -0
- package/dist/examples/runtimeConfigCommands.d.ts +1 -0
- package/package.json +1 -1
package/dist/citadel.umd.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function(g,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom/client"],c):(g=typeof globalThis<"u"?globalThis:g||self,c(g.Citadel={},g.jsxRuntime,g.React,g.client))})(this,function(g,c,
|
|
2
|
-
`+
|
|
3
|
-
`)))};var R=(t=>(t[t.NONE=0]="NONE",t[t.ERROR=1]="ERROR",t[t.WARN=2]="WARN",t[t.INFO=3]="INFO",t[t.DEBUG=4]="DEBUG",t[t.TRACE=5]="TRACE",t))(R||{});const de=!0;class x{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!de&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!de&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(x,"level",0),C(x,"prefix","");const k={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:R.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,closeOnEscape:!0,showCitadelKey:".",showOnLoad:!1,displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},me=async()=>new q("");class ee{constructor(e,n,s){this.type=e,this.name=n,this.description=s}toString(){return this.name}}class te extends ee{constructor(){super("null",">null<","Empty segment")}}class ue extends ee{constructor(e,n){super("word",e,n)}}class U extends ee{constructor(e,n,s,r){super("argument",e,n),this.value=s,this.valid=r}}const He=t=>{if(t.type==="word")return new ue(t.name,t.description);if(t.type==="argument"){const e=t;return new U(e.name,e.description,e.value,e.valid)}return new te},H=t=>t.map(e=>He(e));class _e{constructor(e,n,s=me){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=n,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class K{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,s=me){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new _e(e,n,s),i=this._commands.find(o=>{const d=o.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const n=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===n);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(n=>{const s=n.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const o=n.segments.filter(d=>d.type==="word").map(d=>d.name);return o.length===e.length&&o.join(" ")===r})}commandExistsForPath(e){const n=this._commands.map(r=>r.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),s=e.map((r,i)=>this._commands.some(d=>{var l;return((l=d.segments[i])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return n.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(n=>n.name)}getMatchingCompletions(e,n){const s=n.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(i=>i.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,n){const s=this.getMatchingCompletions(e,n);if(s.length===1)return s[0]}getCompletions(e){if(x.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(l=>l.segments[0]),o=(l,u)=>l.type===u.type&&l.name===u.name;return i.filter((l,u,y)=>u===y.findIndex(p=>o(p,l)))}const n=e.length;return this._commands.filter(i=>{const o=i.segments;if(o.length<=n-1)return!1;for(let d=0;d<n;d++){const l=e[d],u=o[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(i=>i.segments.length>n).map(i=>{const o=i.segments[n],d=o.type==="argument"?U:ue;return new d(o.name,o.description)}).filter((i,o,d)=>o===d.findIndex(l=>l.type===i.type&&l.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class pe{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const n=await this.getStoredCommands();for(n.push(e);n.length>this.config.maxCommands;)n.shift();await this.saveCommands(n)}}class Te extends pe{constructor(n){super(n);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const n=window.localStorage.getItem(this.storageKey);return n?JSON.parse(n).map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(n){return console.warn("Failed to load commands from localStorage:",n),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(n){console.warn("Failed to clear localStorage:",n)}}async saveCommands(n){try{const s=n.map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments).map(i=>({type:i.type,name:i.name,description:i.description,...i instanceof U?{value:i.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class he extends pe{constructor(n){super(n);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?H(n.commandSegments):[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(s=>({commandSegments:Array.isArray(s.commandSegments)?H(s.commandSegments):[],timestamp:s.timestamp}))}}const z=class z{constructor(){C(this,"currentStorage")}static reset(){z.instance=void 0}static getInstance(){return z.instance||(z.instance=new z),z.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new he(e):this.currentStorage=new Te(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new he(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(z,"instance");let Y=z;class ge{constructor(){C(this,"segments",[]);C(this,"nullSegment",new te);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(n=>n!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(n=>this.push(n))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const ze={config:k,commands:new K,segmentStack:new ge},W=a.createContext(ze),De=({config:t=k,commandRegistry:e,children:n})=>{const[s,r]=a.useState(),[i]=a.useState(()=>new ge),o=a.useMemo(()=>({...k,...t,storage:{...k.storage,...t.storage},cursorType:t.cursorType??k.cursorType,cursorColor:t.cursorColor??k.cursorColor,cursorSpeed:t.cursorSpeed??k.cursorSpeed,closeOnEscape:t.closeOnEscape??k.closeOnEscape,showCitadelKey:t.showCitadelKey??k.showCitadelKey,showOnLoad:t.showOnLoad??k.showOnLoad}),[t]);a.useEffect(()=>{Y.getInstance().initializeStorage(o.storage??k.storage),r(Y.getInstance().getStorage())},[o.storage]),a.useEffect(()=>{if(e){if(o.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=Pe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,o.includeHelpCommand]);const d=a.useMemo(()=>({config:o,commands:e||new K,storage:s,segmentStack:i}),[o,e,s,i]);return c.jsx(W.Provider,{value:d,children:n})},T=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return t.config},J=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return t.commands},fe=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return t.storage},B=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return t.segmentStack},X=class X{constructor(e,n){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${X.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=n??new le}};C(X,"idCounter",0);let G=X;function Oe(t){return{commandSegments:H(t),timestamp:Date.now()}}function ye(){const t=fe(),[e,n]=a.useState({storedCommands:[],position:null}),s=a.useCallback(async d=>{if(t)try{const l=Oe(d);await t.addStoredCommand(l),n(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:H(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[t]),r=a.useCallback(async()=>t?(await t.getStoredCommands()).map(l=>({...l,commandSegments:H(l.commandSegments)})):[],[t]);a.useEffect(()=>{if(!t)return;(async()=>{try{const u=(await t.getStoredCommands()).map(y=>({...y,commandSegments:H(y.commandSegments)}));return n(y=>({...y,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[t]);const i=a.useCallback(async d=>{const l=await r();if(l.length===0)return n(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,n(p=>({...p,storedCommands:l.map(f=>({...f,commandSegments:H(f.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const y=l[u];return y?{segments:H(y.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),o=a.useCallback(async()=>{try{if(!t)return;await t.clear(),n({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[t]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:i,clear:o}}const ne=()=>{const t=T(),e=J(),n=ye(),s=B(),r=fe(),[i,o]=a.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});a.useEffect(()=>{},[r]),a.useEffect(()=>{o(l=>({...l,history:{commands:n.history.storedCommands,position:n.history.position,storage:r}}))},[n.history,r]);const d={setCurrentInput:a.useCallback(l=>{x.debug("[CitadelActions] setCurrentInput: ",l),o(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:a.useCallback(l=>{x.debug("[CitadelActions] setIsEnteringArg: ",l),o(u=>({...u,isEnteringArg:l}))},[]),addOutput:a.useCallback(l=>{x.debug("[CitadelActions]addOutput: ",l),o(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:a.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const y=new G(s);o(p=>({...p,output:[...p.output,y]}));try{const p=new Promise((v,E)=>{setTimeout(()=>{E(new Error("Request timed out"))},t.commandTimeoutMs)}),f=s.arguments.map(v=>v.value||""),b=await Promise.race([u.handler(f),p]);if(!(b instanceof _))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
1
|
+
(function(g,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom/client"],c):(g=typeof globalThis<"u"?globalThis:g||self,c(g.Citadel={},g.jsxRuntime,g.React,g.client))})(this,function(g,c,o,Oe){"use strict";var wt=Object.defineProperty;var vt=(g,c,o)=>c in g?wt(g,c,{enumerable:!0,configurable:!0,writable:!0,value:o}):g[c]=o;var C=(g,c,o)=>vt(g,typeof c!="symbol"?c+"":c,o);var $=(n=>(n.Pending="pending",n.Success="success",n.Failure="failure",n.Timeout="timeout",n))($||{});class F{constructor(e=Date.now()){C(this,"_status","pending");this.timestamp=e}get status(){return this._status}markSuccess(){this._status="success"}markFailure(){this._status="failure"}markTimeout(){this._status="timeout"}}class de extends F{constructor(e,t){super(t),this.data=e}render(){return c.jsx("pre",{className:"citadel-result-json",children:JSON.stringify(this.data,null,2)})}}class q extends F{constructor(e,t){super(t),this.text=e}render(){return c.jsx("div",{className:"citadel-result-text",children:this.text})}}class me extends F{constructor(e,t="true",s="false",r){super(r),this.value=e,this.trueText=t,this.falseText=s}render(){return c.jsx("div",{className:"citadel-result-text citadel-result-boolean",children:this.value?this.trueText:this.falseText})}}class ne extends F{constructor(e,t){super(t),this.error=e,this.markFailure()}render(){return c.jsx("div",{className:"citadel-result-error",children:this.error})}}class ue extends F{render(){return c.jsx("div",{className:"citadel-result-pending",children:"..."})}}class pe extends F{constructor(e,t="",s){super(s),this.imageUrl=e,this.altText=t}render(){return c.jsx("div",{className:"citadel-result-image-wrap",children:c.jsx("img",{src:this.imageUrl,alt:this.altText,className:"citadel-result-image"})})}}const De=n=>async function(){const t=n.commands.filter(s=>s.fullPath[0]!=="help").map(s=>{const i=`${s.segments.map(d=>d.type==="argument"?`<${d.name}>`:d.name).join(" ")} - ${s.description}`,a=s.segments.filter(d=>d.type==="argument"&&d.description).map(d=>` <${d.name}>: ${d.description}`);return{commandLine:i,argumentLines:a}}).sort((s,r)=>s.commandLine.localeCompare(r.commandLine)).flatMap(s=>[s.commandLine,...s.argumentLines]);return t.length===0?new q("No commands available yet. Add some commands to get started!"):(t.push("help - Show available commands"),new q(`Available Commands:
|
|
2
|
+
`+t.join(`
|
|
3
|
+
`)))};var se=(n=>(n[n.NONE=0]="NONE",n[n.ERROR=1]="ERROR",n[n.WARN=2]="WARN",n[n.INFO=3]="INFO",n[n.DEBUG=4]="DEBUG",n[n.TRACE=5]="TRACE",n))(se||{});const he=!0;class k{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!he&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!he&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(k,"level",0),C(k,"prefix","");const E={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:se.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",showOutputPane:!0,resetStateOnHide:!1,closeOnEscape:!0,showCitadelKey:".",showOnLoad:!1,displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},ge=async()=>new q("");class re{constructor(e,t,s){this.type=e,this.name=t,this.description=s}toString(){return this.name}}class oe extends re{constructor(){super("null",">null<","Empty segment")}}class fe extends re{constructor(e,t){super("word",e,t)}}class j extends re{constructor(e,t,s,r){super("argument",e,t),this.value=s,this.valid=r}}const ze=n=>{if(n.type==="word")return new fe(n.name,n.description);if(n.type==="argument"){const e=n;return new j(e.name,e.description,e.value,e.valid)}return new oe},_=n=>n.map(e=>ze(e));class Fe{constructor(e,t,s=ge){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=t,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class K{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,t,s=ge){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new Fe(e,t,s),i=this._commands.find(a=>{const d=a.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const t=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===t);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(t=>{const s=t.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const a=t.segments.filter(d=>d.type==="word").map(d=>d.name);return a.length===e.length&&a.join(" ")===r})}commandExistsForPath(e){const t=this._commands.map(r=>r.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),s=e.map((r,i)=>this._commands.some(d=>{var l;return((l=d.segments[i])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return t.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(t=>t.name)}getMatchingCompletions(e,t){const s=t.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(i=>i.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,t){const s=this.getMatchingCompletions(e,t);if(s.length===1)return s[0]}getCompletions(e){if(k.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(l=>l.segments[0]),a=(l,u)=>l.type===u.type&&l.name===u.name;return i.filter((l,u,f)=>u===f.findIndex(p=>a(p,l)))}const t=e.length;return this._commands.filter(i=>{const a=i.segments;if(a.length<=t-1)return!1;for(let d=0;d<t;d++){const l=e[d],u=a[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(i=>i.segments.length>t).map(i=>{const a=i.segments[t],d=a.type==="argument"?j:fe;return new d(a.name,a.description)}).filter((i,a,d)=>a===d.findIndex(l=>l.type===i.type&&l.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class ye{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const t=await this.getStoredCommands();for(t.push(e);t.length>this.config.maxCommands;)t.shift();await this.saveCommands(t)}}class Le extends ye{constructor(t){super(t);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const t=window.localStorage.getItem(this.storageKey);return t?JSON.parse(t).map(r=>({commandSegments:Array.isArray(r.commandSegments)?_(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(t){return console.warn("Failed to load commands from localStorage:",t),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(t){console.warn("Failed to clear localStorage:",t)}}async saveCommands(t){try{const s=t.map(r=>({commandSegments:Array.isArray(r.commandSegments)?_(r.commandSegments).map(i=>({type:i.type,name:i.name,description:i.description,...i instanceof j?{value:i.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class Ce extends ye{constructor(t){super(t);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(t=>({commandSegments:Array.isArray(t.commandSegments)?_(t.commandSegments):[],timestamp:t.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(t){this.storedCommands=t.map(s=>({commandSegments:Array.isArray(s.commandSegments)?_(s.commandSegments):[],timestamp:s.timestamp}))}}const U=class U{constructor(){C(this,"currentStorage")}static reset(){U.instance=void 0}static getInstance(){return U.instance||(U.instance=new U),U.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new Ce(e):this.currentStorage=new Le(e)}catch(t){console.warn("Failed to create storage, falling back to memory storage:",t),this.currentStorage=new Ce(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(U,"instance");let J=U;class we{constructor(){C(this,"segments",[]);C(this,"nullSegment",new oe);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(t=>t!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(t=>this.push(t))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const Ue={config:E,commands:new K,segmentStack:new we},W=o.createContext(Ue),$e=({config:n=E,commandRegistry:e,children:t})=>{const[s,r]=o.useState(),[i]=o.useState(()=>new we),a=o.useMemo(()=>({...E,...n,storage:{...E.storage,...n.storage},cursorType:n.cursorType??E.cursorType,cursorColor:n.cursorColor??E.cursorColor,cursorSpeed:n.cursorSpeed??E.cursorSpeed,closeOnEscape:n.closeOnEscape??E.closeOnEscape,showCitadelKey:n.showCitadelKey??E.showCitadelKey,showOnLoad:n.showOnLoad??E.showOnLoad}),[n]);o.useEffect(()=>{J.getInstance().initializeStorage(a.storage??E.storage),r(J.getInstance().getStorage())},[a.storage]),o.useEffect(()=>{if(e){if(a.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=De(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,a.includeHelpCommand]);const d=o.useMemo(()=>({config:a,commands:e||new K,storage:s,segmentStack:i}),[a,e,s,i]);return c.jsx(W.Provider,{value:d,children:t})},L=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return n.config},X=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return n.commands},ve=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return n.storage},B=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return n.segmentStack},ee=class ee{constructor(e,t){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${ee.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=t??new ue}};C(ee,"idCounter",0);let Q=ee;function je(n){return{commandSegments:_(n),timestamp:Date.now()}}function Se(){const n=ve(),[e,t]=o.useState({storedCommands:[],position:null}),s=o.useCallback(async d=>{if(n)try{const l=je(d);await n.addStoredCommand(l),t(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:_(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[n]),r=o.useCallback(async()=>n?(await n.getStoredCommands()).map(l=>({...l,commandSegments:_(l.commandSegments)})):[],[n]);o.useEffect(()=>{if(!n)return;(async()=>{try{const u=(await n.getStoredCommands()).map(f=>({...f,commandSegments:_(f.commandSegments)}));return t(f=>({...f,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[n]);const i=o.useCallback(async d=>{const l=await r();if(l.length===0)return t(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,t(p=>({...p,storedCommands:l.map(y=>({...y,commandSegments:_(y.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const f=l[u];return f?{segments:_(f.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),a=o.useCallback(async()=>{try{if(!n)return;await n.clear(),t({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[n]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:i,clear:a}}const ae=()=>{const n=L(),e=X(),t=Se(),s=B(),r=ve(),[i,a]=o.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});o.useEffect(()=>{},[r]),o.useEffect(()=>{a(l=>({...l,history:{commands:t.history.storedCommands,position:t.history.position,storage:r}}))},[t.history,r]);const d={setCurrentInput:o.useCallback(l=>{k.debug("[CitadelActions] setCurrentInput: ",l),a(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:o.useCallback(l=>{k.debug("[CitadelActions] setIsEnteringArg: ",l),a(u=>({...u,isEnteringArg:l}))},[]),addOutput:o.useCallback(l=>{k.debug("[CitadelActions]addOutput: ",l),a(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:o.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const f=new Q(s);a(p=>({...p,output:[...p.output,f]}));try{const p=new Promise((S,N)=>{setTimeout(()=>{N(new Error("Request timed out"))},n.commandTimeoutMs)}),y=s.arguments.map(S=>S.value||""),w=await Promise.race([u.handler(y),p]);if(!(w instanceof F))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
4
4
|
For example:
|
|
5
5
|
return new JsonCommandResult({ text: "Hello World" });
|
|
6
|
-
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);b.markSuccess(),o(v=>({...v,output:v.output.map(E=>E.id===y.id?{...E,result:b}:E)}))}catch(p){const f=new Z(p instanceof Error?p.message:"Unknown error");f.markFailure(),o(b=>({...b,output:b.output.map(v=>v.id===y.id?{...v,result:f}:v)}))}},[e,t.commandTimeoutMs,s]),clearHistory:a.useCallback(async()=>{try{await n.clear()}catch(l){console.warn("Failed to clear history:",l)}},[n])};return{state:i,actions:d}},Fe=({onOpen:t,onClose:e,isVisible:n,showCitadelKey:s,closeOnEscape:r})=>{a.useEffect(()=>{const i=o=>{var d,l;!n&&o.key===s&&!["input","textarea"].includes(((l=(d=o.target)==null?void 0:d.tagName)==null?void 0:l.toLowerCase())||"")&&(o.preventDefault(),t()),r&&n&&o.key==="Escape"&&(o.preventDefault(),e())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[t,e,n,s,r])},Le=200,je=t=>{const{isVisible:e,isClosing:n,onAnimationComplete:s}=t,r=a.useMemo(()=>e?n?"citadel_slideDown":"citadel_slideUp":"",[e,n]);return a.useEffect(()=>{if(!n||!s)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){s();return}const o=setTimeout(()=>{s()},Le);return()=>clearTimeout(o)},[n,s]),{animationClass:r}},Ue=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),Ce=t=>{const e=t==null?void 0:t.trim();return e||void 0},$e=t=>{const e=Ce(t);return e?{style:{fontSize:e}}:{}},Q=(t,e)=>{const n=Ce(t),r={...$e(e).style};return n&&(r.fontFamily=n),{style:Object.keys(r).length>0?r:void 0}},qe=({command:t,timestamp:e,status:n,fontFamily:s,fontSize:r})=>{const i=a.useMemo(()=>Q(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:i.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",t.split(" ").map((o,d)=>{const l=o.startsWith("<")&&o.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",o]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),n===j.Pending&&c.jsx(Ue,{}),n===j.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(n===j.Timeout||n===j.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},Ke=({output:t,outputRef:e})=>{const n=T(),s=a.useMemo(()=>Q(n.fontFamily,n.outputFontSize??n.fontSize),[n.fontFamily,n.fontSize,n.outputFontSize]),r=a.useCallback(()=>{if(e.current){const i=e.current;requestAnimationFrame(()=>{i.scrollTop=i.scrollHeight})}},[e]);return a.useEffect(()=>{if(r(),e.current){const i=e.current.getElementsByTagName("img"),o=i[i.length-1];if(o&&!o.complete)return o.addEventListener("load",r),()=>o.removeEventListener("load",r)}},[t,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:t.map(i=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(qe,{command:i.command.join(" "),timestamp:new Date(i.timestamp).toLocaleTimeString(),status:i.result.status,fontFamily:n.fontFamily,fontSize:n.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:i.result.render()})]},i.id))})},we={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ve=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],Se=["|","/","-","\\"],We=({style:t={type:"blink"},isValid:e=!0,errorMessage:n})=>{const s=a.useMemo(()=>({...we[t.type],...t}),[t]),[r,i]=a.useState(!0),[o,d]=a.useState(0);a.useEffect(()=>{if(s.speed===0)return;const y=setInterval(()=>{s.type==="blink"?i(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?Se.length:ve.length))},s.speed);return()=>clearInterval(y)},[s.type,s.speed]);const l=a.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&n?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?Se:ve)[o]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:n,children:u()})})};function Be(t,e){switch(e.type){case"set":return x.debug(`[inputStateReducer] InputState changing from ${t} to ${e.state}`),e.state;default:return t}}const Ve=()=>{const{state:t}=ne(),e=J(),n=ye(),s=B(),[r,i]=a.useReducer(Be,"idle"),o=m=>{i({type:"set",state:m})},d=a.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return x.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=a.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=a.useCallback((m,h)=>{if(!m)return h;const w=s.path().length;return h.filter(D=>{const S=D.segments[w];return!S||S.type!=="word"?!1:S.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),y=a.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=a.useCallback(m=>{const h=s.path(),w=e.getCompletions(h);return w.length===0&&m?!1:w.some(S=>S.type==="argument")?!0:e.getMatchingCompletions(h,m).some(S=>S.type==="word")},[e,s]),f=a.useCallback(m=>{x.debug("[tryAutoComplete] input: ",m);const h=y(m);return!h||h.type==="null"?new te:(x.debug("[tryAutoComplete] result: ",h),h)},[y]),b=a.useCallback((m,h)=>{if(t.history.position!==null)return;h.setCurrentInput(m),x.debug("[useCommandParser][handleInputChange] newValue: ",m);const w=d();if(w.type==="argument"||r==="entering_argument"){const A=be(m);if(A.isQuoted)if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return;else if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return}if(m.endsWith(" ")){const A=m.trim().toLowerCase(),P=e.getCompletions(s.path()).filter(N=>N.type==="word"&&N.name.toLowerCase()===A);if(P.length===1){s.push(P[0]),h.setCurrentInput(""),o("idle");return}}const S=f(m);if(S.type==="word"){x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",S),s.push(S),h.setCurrentInput(""),o("idle");return}},[f,t,d,r,s,e]),v=a.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),o("idle")},[s]),E=a.useCallback((m,h,w)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:S,isEnteringArg:A}=h,P=be(S);switch(m.key){case"Backspace":return S===""&&(m.preventDefault(),s.size()>0&&s.pop(),o("idle")),!0;case"Enter":{if(m.preventDefault(),P.isQuoted&&!P.isComplete)return!0;if(r==="entering_argument"||A&&S.trim()){const F=d();F instanceof U&&(F.value=S,x.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",F),s.push(F))}const N=s.path(),V=e.getCommand(N);if(!V)return!1;const O=V.segments.filter(F=>F.type==="argument"),$=s.arguments;return O.length>$.length?!1:(x.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),w.executeCommand(),n.addStoredCommand(s.toArray()),v(w),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("up");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("down");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();default:{if(!A&&m.key.length===1){const N=S+m.key;if(!p(N))return m.preventDefault(),!1}return!0}}},[r,p,d,n,v,e,s]);return{handleInputChange:b,handleKeyDown:E,inputState:r,setInputStateWithLogging:o,findMatchingCommands:u,getAutocompleteSuggestion:y,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function be(t){const e=[];let n="",s=!1,r;for(let i=0;i<t.length;i++){const o=t[i];(o==='"'||o==="'")&&(!s||o===r)?s?(e.push(n),n="",s=!1,r=void 0):(n&&(e.push(n),n=""),s=!0,r=o):!s&&o===" "?n&&(e.push(n),n=""):n+=o}return{words:e,currentWord:n,isQuoted:s,quoteChar:r,isComplete:!s&&!n}}const Ye=()=>{const t=B(),[e,n]=a.useState(0);return a.useEffect(()=>{const s={update:()=>{n(r=>r+1)}};return t.subscribe(s),()=>{t.unsubscribe(s)}},[t]),e},Je=({state:t,actions:e})=>{const n=a.useRef(null),s=J(),r=B(),{handleKeyDown:i,handleInputChange:o,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Ve(),[y,p]=a.useState(!1),f=T(),b=Ye(),v=a.useRef(null),[E,m]=a.useState(0),h=a.useMemo(()=>Q(f.fontFamily,f.fontSize),[f.fontFamily,f.fontSize]),w=a.useCallback(async I=>{const M=i(I,t,e);await Promise.resolve(M)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,i,t]),D=a.useCallback(I=>{o(I.target.value,e)},[e,o]),S=a.useCallback(I=>{I.preventDefault();const M=I.clipboardData.getData("text");o(M,e)},[e,o]);a.useEffect(()=>{n.current&&n.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),a.useEffect(()=>{if(d!=="idle")return;const I=u();let M="idle";switch(I.type){case"word":M="entering_command",e.setIsEnteringArg(!1);break;case"argument":M="entering_argument",e.setIsEnteringArg(!0);break}l(M)},[b,d,u,l,e]);const A=a.useMemo(()=>{const I=[],M=r.toArray().map((L,re)=>{I.push(L.name);const Ae=s.hasNextSegment(I);if(L.type==="argument"){const ae=L;return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:ae.value}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+ae.name+ae.value)}return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:L.name}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+L.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:M},b)]},[b,s,r]),[P,N]=a.useState("");a.useEffect(()=>{const I=u();I.type==="argument"?N(I.name):N("")},[b,u]);const O=!t.isEnteringArg?"is-command-mode":"is-argument-mode",$=a.useMemo(()=>({left:`${E}px`,transition:"left 0.05s ease-out"}),[E]),F=a.useMemo(()=>({type:f.cursorType??k.cursorType,color:f.cursorColor||k.cursorColor,speed:f.cursorSpeed||k.cursorSpeed}),[f.cursorColor,f.cursorSpeed,f.cursorType]);return a.useLayoutEffect(()=>{const I=v.current,M=n.current;if(!I||!M){m(0);return}const L=I.getBoundingClientRect().width;m(Math.max(0,L-M.scrollLeft))},[t.currentInput,O,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[A,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:v,className:`citadel-input-measure ${O}`.trim(),"aria-hidden":"true",children:t.currentInput}),c.jsx("input",{ref:n,type:"text",role:"textbox",value:t.currentInput,onChange:D,onKeyDown:w,onPaste:S,"data-testid":"citadel-command-input",className:`citadel-input-field ${O} ${y?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:P}),c.jsx("div",{className:"citadel-input-cursor",style:$,children:c.jsx(We,{style:F})})]})]})]})})},Ge=({currentInput:t=""})=>{const e=J(),n=T(),s=B(),r=a.useMemo(()=>Q(n.fontFamily,n.fontSize),[n.fontFamily,n.fontSize]),i=t.trim().toLowerCase(),o=e.getMatchingCompletions(s.path(),i);x.debug("[AvailableCommands] nextCommandSegments: ",o);const d=a.useMemo(()=>{const p=[...o],f=m=>m.name.toLowerCase()==="help",b=p.filter(f);return[...p.filter(m=>!f(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...b]},[o]),l=a.useMemo(()=>{const p=new Map;for(const f of d){const b=d.reduce((v,E)=>{if(E===f)return v;let m=0;for(;m<f.name.length&&m<E.name.length&&f.name[m].toLowerCase()===E.name[m].toLowerCase();)m++;return Math.max(v,m+1)},1);p.set(f.name,b)}return p},[d]),u=o.some(p=>p.type==="argument"),y=o[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?o.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:y.name}),y.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",y.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const f=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,f)}),p.name.slice(f)]})},p.name)})})})})},xe=({state:t,actions:e,outputRef:n})=>{const r=T().displayMode==="inline",i=a.useMemo(()=>r?{overflow:"hidden"}:void 0,[r]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:i,children:c.jsx(Ke,{output:t.output,outputRef:n})}),c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Je,{state:t,actions:e}),c.jsx(Ge,{currentInput:t.isEnteringArg?"":t.currentInput})]})]})},Qe=()=>{const t=T(),[e,n]=a.useState(()=>t.showOnLoad??!1),[s,r]=a.useState(!1),[i,o]=a.useState(()=>t.initialHeight||null),d=a.useRef(null),l=a.useRef(null),u=a.useRef(!1),y=a.useRef(0),p=a.useRef(0),{state:f,actions:b}=ne(),v=a.useCallback(()=>{r(!1),n(!0)},[]),E=a.useCallback(()=>{r(!0)},[]);Fe({onOpen:v,onClose:E,isVisible:e&&!s,showCitadelKey:t.showCitadelKey||".",closeOnEscape:t.closeOnEscape??!0});const m=a.useCallback(P=>{var $;if(!u.current)return;const N=P.clientY-y.current,V=($=t.maxHeight)!=null&&$.endsWith("vh")?window.innerHeight*parseInt(t.maxHeight,10)/100:parseInt(t.maxHeight||"80vh",10),O=Math.min(Math.max(p.current-N,parseInt(t.minHeight||"200",10)),V);l.current&&(l.current.style.height=`${O}px`,l.current.style.bottom="0",o(`${O}px`))},[t.maxHeight,t.minHeight]),h=a.useCallback(()=>{u.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m]),w=a.useCallback(P=>{l.current&&(u.current=!0,y.current=P.clientY,p.current=l.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",m),document.addEventListener("mouseup",h))},[m,h]);a.useEffect(()=>()=>{document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m,h]);const D=a.useCallback(()=>{s&&(n(!1),r(!1))},[s]),{animationClass:S}=je({isVisible:e,isClosing:s,onAnimationComplete:D}),A=a.useMemo(()=>({...i?{height:i}:{},maxHeight:t.maxHeight}),[t.maxHeight,i]);return e?c.jsxs("div",{ref:l,className:`panelContainer ${S}`.trim(),style:A,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:w}),c.jsx(xe,{state:f,actions:b,outputRef:d})]}):null},se=t=>{if(!t)return;const e=t.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Xe=()=>{const{state:t,actions:e}=ne(),n=T(),s=a.useRef(null),r=a.useMemo(()=>({height:se(n.initialHeight),maxHeight:se(n.maxHeight),minHeight:se(n.minHeight)}),[n.initialHeight,n.maxHeight,n.minHeight]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:r,children:c.jsx(xe,{state:t,actions:e,outputRef:s})})},ke=`:host {
|
|
6
|
+
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);w.markSuccess(),a(S=>({...S,output:S.output.map(N=>N.id===f.id?{...N,result:w}:N)}))}catch(p){const y=new ne(p instanceof Error?p.message:"Unknown error");y.markFailure(),a(w=>({...w,output:w.output.map(S=>S.id===f.id?{...S,result:y}:S)}))}},[e,n.commandTimeoutMs,s]),clearHistory:o.useCallback(async()=>{try{await t.clear()}catch(l){console.warn("Failed to clear history:",l)}},[t])};return{state:i,actions:d}},qe=({onOpen:n,onClose:e,isVisible:t,showCitadelKey:s,closeOnEscape:r})=>{o.useEffect(()=>{const i=a=>{var d,l;!t&&a.key===s&&!["input","textarea"].includes(((l=(d=a.target)==null?void 0:d.tagName)==null?void 0:l.toLowerCase())||"")&&(a.preventDefault(),n()),r&&t&&a.key==="Escape"&&(a.preventDefault(),e())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[n,e,t,s,r])},Ke=200,We=n=>{const{isVisible:e,isClosing:t,onAnimationComplete:s}=n,r=o.useMemo(()=>e?t?"citadel_slideDown":"citadel_slideUp":"",[e,t]);return o.useEffect(()=>{if(!t||!s)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){s();return}const a=setTimeout(()=>{s()},Ke);return()=>clearTimeout(a)},[t,s]),{animationClass:r}},Be=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),be=n=>{const e=n==null?void 0:n.trim();return e||void 0},Ve=n=>{const e=be(n);return e?{style:{fontSize:e}}:{}},Z=(n,e)=>{const t=be(n),r={...Ve(e).style};return t&&(r.fontFamily=t),{style:Object.keys(r).length>0?r:void 0}},Ge=({command:n,timestamp:e,status:t,fontFamily:s,fontSize:r})=>{const i=o.useMemo(()=>Z(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:i.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",n.split(" ").map((a,d)=>{const l=a.startsWith("<")&&a.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",a]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),t===$.Pending&&c.jsx(Be,{}),t===$.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(t===$.Timeout||t===$.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},Ye=({output:n,outputRef:e})=>{const t=L(),s=o.useMemo(()=>Z(t.fontFamily,t.outputFontSize??t.fontSize),[t.fontFamily,t.fontSize,t.outputFontSize]),r=o.useCallback(()=>{if(e.current){const i=e.current;requestAnimationFrame(()=>{i.scrollTop=i.scrollHeight})}},[e]);return o.useEffect(()=>{if(r(),e.current){const i=e.current.getElementsByTagName("img"),a=i[i.length-1];if(a&&!a.complete)return a.addEventListener("load",r),()=>a.removeEventListener("load",r)}},[n,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:n.map(i=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(Ge,{command:i.command.join(" "),timestamp:new Date(i.timestamp).toLocaleTimeString(),status:i.result.status,fontFamily:t.fontFamily,fontSize:t.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:i.result.render()})]},i.id))})},xe={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ke=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],Ee=["|","/","-","\\"],Je=({style:n={type:"blink"},isValid:e=!0,errorMessage:t})=>{const s=o.useMemo(()=>({...xe[n.type],...n}),[n]),[r,i]=o.useState(!0),[a,d]=o.useState(0);o.useEffect(()=>{if(s.speed===0)return;const f=setInterval(()=>{s.type==="blink"?i(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?Ee.length:ke.length))},s.speed);return()=>clearInterval(f)},[s.type,s.speed]);const l=o.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&t?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?Ee:ke)[a]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:t,children:u()})})};function Xe(n,e){switch(e.type){case"set":return k.debug(`[inputStateReducer] InputState changing from ${n} to ${e.state}`),e.state;default:return n}}const Qe=()=>{const{state:n}=ae(),e=X(),t=Se(),s=B(),[r,i]=o.useReducer(Xe,"idle"),a=m=>{i({type:"set",state:m})},d=o.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return k.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=o.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=o.useCallback((m,h)=>{if(!m)return h;const v=s.path().length;return h.filter(T=>{const b=T.segments[v];return!b||b.type!=="word"?!1:b.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),f=o.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=o.useCallback(m=>{const h=s.path(),v=e.getCompletions(h);return v.length===0&&m?!1:v.some(b=>b.type==="argument")?!0:e.getMatchingCompletions(h,m).some(b=>b.type==="word")},[e,s]),y=o.useCallback(m=>{k.debug("[tryAutoComplete] input: ",m);const h=f(m);return!h||h.type==="null"?new oe:(k.debug("[tryAutoComplete] result: ",h),h)},[f]),w=o.useCallback((m,h)=>{if(n.history.position!==null)return;h.setCurrentInput(m),k.debug("[useCommandParser][handleInputChange] newValue: ",m);const v=d();if(v.type==="argument"||r==="entering_argument"){const H=Ne(m);if(H.isQuoted)if(H.isComplete){if(!(v instanceof j))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),a("idle");return}else return;else if(H.isComplete){if(!(v instanceof j))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),a("idle");return}else return}if(m.endsWith(" ")){const H=m.trim().toLowerCase(),z=e.getCompletions(s.path()).filter(I=>I.type==="word"&&I.name.toLowerCase()===H);if(z.length===1){s.push(z[0]),h.setCurrentInput(""),a("idle");return}}const b=y(m);if(b.type==="word"){k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",b),s.push(b),h.setCurrentInput(""),a("idle");return}},[y,n,d,r,s,e]),S=o.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),a("idle")},[s]),N=o.useCallback((m,h,v)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:b,isEnteringArg:H}=h,z=Ne(b);switch(m.key){case"Backspace":return b===""&&(m.preventDefault(),s.size()>0&&s.pop(),a("idle")),!0;case"Enter":{if(m.preventDefault(),z.isQuoted&&!z.isComplete)return!0;if(r==="entering_argument"||H&&b.trim()){const D=d();D instanceof j&&(D.value=b,k.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",D),s.push(D))}const I=s.path(),O=e.getCommand(I);if(!O)return!1;const M=O.segments.filter(D=>D.type==="argument"),V=s.arguments;return M.length>V.length?!1:(k.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),v.executeCommand(),t.addStoredCommand(s.toArray()),S(v),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const I=await t.navigateHistory("up");return I.segments&&(s.clear(),s.pushAll(I.segments),v.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const I=await t.navigateHistory("down");return I.segments&&(s.clear(),s.pushAll(I.segments),v.setCurrentInput("")),!0})();default:{if(!H&&m.key.length===1){const I=b+m.key;if(!p(I))return m.preventDefault(),!1}return!0}}},[r,p,d,t,S,e,s]);return{handleInputChange:w,handleKeyDown:N,inputState:r,setInputStateWithLogging:a,findMatchingCommands:u,getAutocompleteSuggestion:f,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function Ne(n){const e=[];let t="",s=!1,r;for(let i=0;i<n.length;i++){const a=n[i];(a==='"'||a==="'")&&(!s||a===r)?s?(e.push(t),t="",s=!1,r=void 0):(t&&(e.push(t),t=""),s=!0,r=a):!s&&a===" "?t&&(e.push(t),t=""):t+=a}return{words:e,currentWord:t,isQuoted:s,quoteChar:r,isComplete:!s&&!t}}const Ze=()=>{const n=B(),[e,t]=o.useState(0);return o.useEffect(()=>{const s={update:()=>{t(r=>r+1)}};return n.subscribe(s),()=>{n.unsubscribe(s)}},[n]),e},Re=({state:n,actions:e})=>{const t=o.useRef(null),s=X(),r=B(),{handleKeyDown:i,handleInputChange:a,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Qe(),[f,p]=o.useState(!1),y=L(),w=Ze(),S=o.useRef(null),[N,m]=o.useState(0),h=o.useMemo(()=>Z(y.fontFamily,y.fontSize),[y.fontFamily,y.fontSize]),v=o.useCallback(async x=>{const A=i(x,n,e);await Promise.resolve(A)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,i,n]),T=o.useCallback(x=>{a(x.target.value,e)},[e,a]),b=o.useCallback(x=>{x.preventDefault();const A=x.clipboardData.getData("text");a(A,e)},[e,a]);o.useEffect(()=>{t.current&&t.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),o.useEffect(()=>{if(d!=="idle")return;const x=u();let A="idle";switch(x.type){case"word":A="entering_command",e.setIsEnteringArg(!1);break;case"argument":A="entering_argument",e.setIsEnteringArg(!0);break}l(A)},[w,d,u,l,e]);const H=o.useMemo(()=>{const x=[],A=r.toArray().map((P,G)=>{x.push(P.name);const te=s.hasNextSegment(x);if(P.type==="argument"){const Y=P;return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:Y.value}),G<r.size()&&te&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+Y.name+Y.value)}return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:P.name}),G<r.size()&&te&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+P.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:A},w)]},[w,s,r]),[z,I]=o.useState("");o.useEffect(()=>{const x=u();x.type==="argument"?I(x.name):I("")},[w,u]);const M=!n.isEnteringArg?"is-command-mode":"is-argument-mode",V=o.useMemo(()=>({left:`${N}px`,transition:"left 0.05s ease-out"}),[N]),D=o.useMemo(()=>({type:y.cursorType??E.cursorType,color:y.cursorColor||E.cursorColor,speed:y.cursorSpeed||E.cursorSpeed}),[y.cursorColor,y.cursorSpeed,y.cursorType]);return o.useLayoutEffect(()=>{const x=S.current,A=t.current;if(!x||!A){m(0);return}const P=x.getBoundingClientRect().width;m(Math.max(0,P-A.scrollLeft))},[n.currentInput,M,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[H,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:S,className:`citadel-input-measure ${M}`.trim(),"aria-hidden":"true",children:n.currentInput}),c.jsx("input",{ref:t,type:"text",role:"textbox",value:n.currentInput,onChange:T,onKeyDown:v,onPaste:b,"data-testid":"citadel-command-input",className:`citadel-input-field ${M} ${f?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:z}),c.jsx("div",{className:"citadel-input-cursor",style:V,children:c.jsx(Je,{style:D})})]})]})]})})},et=({currentInput:n=""})=>{const e=X(),t=L(),s=B(),r=o.useMemo(()=>Z(t.fontFamily,t.fontSize),[t.fontFamily,t.fontSize]),i=n.trim().toLowerCase(),a=e.getMatchingCompletions(s.path(),i);k.debug("[AvailableCommands] nextCommandSegments: ",a);const d=o.useMemo(()=>{const p=[...a],y=m=>m.name.toLowerCase()==="help",w=p.filter(y);return[...p.filter(m=>!y(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...w]},[a]),l=o.useMemo(()=>{const p=new Map;for(const y of d){const w=d.reduce((S,N)=>{if(N===y)return S;let m=0;for(;m<y.name.length&&m<N.name.length&&y.name[m].toLowerCase()===N.name[m].toLowerCase();)m++;return Math.max(S,m+1)},1);p.set(y.name,w)}return p},[d]),u=a.some(p=>p.type==="argument"),f=a[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?a.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:f.name}),f.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",f.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const y=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,y)}),p.name.slice(y)]})},p.name)})})})})},Ie=({state:n,actions:e,outputRef:t})=>{const s=L(),r=s.displayMode==="inline",i=s.showOutputPane??!0,a=o.useMemo(()=>i&&r?{overflow:"hidden"}:void 0,[r,i]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[i?c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:a,children:c.jsx(Ye,{output:n.output,outputRef:t})}):null,c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Re,{state:n,actions:e}),c.jsx(et,{currentInput:n.isEnteringArg?"":n.currentInput})]})]})},R="128px",tt="200px",nt="80vh",ie=n=>{if(!n)return;const e=n.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Ae=(n,e)=>{if(!n)return e;const t=n.trim();if(!t)return e;if(t.endsWith("vh")){const r=Number.parseFloat(t);return Number.isFinite(r)?window.innerHeight*r/100:e}const s=Number.parseFloat(t);return Number.isFinite(s)?s:e},st=()=>{const n=L(),e=n.showOutputPane??!0,t=ie(n.minHeight)??tt,s=ie(n.maxHeight)??nt,r=e?t:R,i=Number.parseFloat(R),[a,d]=o.useState(()=>{const P=ie(n.initialHeight);return e?P??null:R}),[l,u]=o.useState(()=>n.showOnLoad??!1),[f,p]=o.useState(!1),y=o.useRef(null),w=o.useRef(null),S=o.useRef(!1),N=o.useRef(0),m=o.useRef(0),h=o.useRef(null),v=o.useRef(a),T=o.useRef(e),{state:b,actions:H}=ae(),z=o.useCallback(()=>{p(!1),u(!0)},[]),I=o.useCallback(()=>{p(!0)},[]);qe({onOpen:z,onClose:I,isVisible:l&&!f,showCitadelKey:n.showCitadelKey||".",closeOnEscape:n.closeOnEscape??!0});const O=o.useCallback(P=>{if(!S.current)return;const G=P.clientY-N.current,te=Ae(s,window.innerHeight*80/100),Y=Ae(r,i),Te=Math.min(Math.max(m.current-G,Y),te);w.current&&(w.current.style.height=`${Te}px`,w.current.style.bottom="0",d(`${Te}px`))},[i,r,s]),M=o.useCallback(()=>{S.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",O),document.removeEventListener("mouseup",M)},[O]),V=o.useCallback(P=>{w.current&&(S.current=!0,N.current=P.clientY,m.current=w.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",O),document.addEventListener("mouseup",M))},[O,M]);o.useEffect(()=>()=>{document.removeEventListener("mousemove",O),document.removeEventListener("mouseup",M)},[O,M]),o.useEffect(()=>{v.current=a},[a]),o.useEffect(()=>{if(!e){T.current&&(h.current=v.current??(w.current?`${w.current.offsetHeight}px`:null)),T.current=!1,d(R);return}T.current=!0,h.current&&(d(h.current),h.current=null)},[e]);const D=o.useCallback(()=>{f&&(u(!1),p(!1))},[f]),{animationClass:x}=We({isVisible:l,isClosing:f,onAnimationComplete:D}),A=o.useMemo(()=>({...a?{height:a}:{},minHeight:r,maxHeight:s}),[r,a,s]);return l?c.jsxs("div",{ref:w,className:`panelContainer ${x}`.trim(),style:A,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:V}),c.jsx(Ie,{state:b,actions:H,outputRef:y})]}):null},le="128px",ce=n=>{if(!n)return;const e=n.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},rt=()=>{const{state:n,actions:e}=ae(),t=L(),s=t.showOutputPane??!0,r=o.useRef(null),i=o.useMemo(()=>({height:s?ce(t.initialHeight):le,maxHeight:s?ce(t.maxHeight):le,minHeight:s?ce(t.minHeight):le}),[t.initialHeight,t.maxHeight,t.minHeight,s]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:i,children:c.jsx(Ie,{state:n,actions:e,outputRef:r})})},Pe=`:host {
|
|
7
7
|
--citadel-bg: oklch(20.8% 0.042 265.8);
|
|
8
8
|
--citadel-surface: oklch(27.9% 0.041 260);
|
|
9
9
|
--citadel-border: oklch(37.2% 0.044 257.3);
|
|
@@ -475,5 +475,5 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
475
475
|
object-fit: contain;
|
|
476
476
|
border-radius: 0.5rem;
|
|
477
477
|
}
|
|
478
|
-
`,
|
|
479
|
-
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const
|
|
478
|
+
`,ot=({config:n=E,commandRegistry:e,containerId:t=null})=>{const s=o.useRef(new K),r=e??s.current,i=o.useRef(null),a=o.useMemo(()=>({width:"100%",height:"100%"}),[]),d=n.displayMode??E.displayMode??"panel";return o.useEffect(()=>{k.configure({level:n.logLevel||E.logLevel||se.ERROR,prefix:"[Citadel]"});const l=new He(r,n),u=d==="inline"&&!t,f=u?i.current:t?document.getElementById(t):document.body;if(f)f.appendChild(l);else{if(u){console.warn("[Citadel] No host available for inline mode; skipping mount.");return}console.warn(`Container with id "${t}" not found, falling back to body`),document.body.appendChild(l)}return()=>{var p;(p=l.parentElement)==null||p.removeChild(l)}},[r,t,n,d]),d==="inline"&&!t?c.jsx("div",{ref:i,style:a}):null};class He extends HTMLElement{constructor(t,s){var i;super();C(this,"shadow");C(this,"root",null);C(this,"commandRegistry");C(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=t,this.config=s;const r=((i=this.config)==null?void 0:i.displayMode)??"panel";this.setAttribute("data-display-mode",r)}connectedCallback(){try{const s=[Pe].map(r=>{const i=new CSSStyleSheet;return i.replaceSync(r),i});this.shadow.adoptedStyleSheets=[...s]}catch{const s=[Pe].join(`
|
|
479
|
+
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const t=document.createElement("div");t.id="citadel-root",t.style.width="100%",t.style.height="100%",this.shadow.appendChild(t),this.root=Oe.createRoot(t),this.root.render(c.jsx($e,{config:this.config||E,commandRegistry:this.commandRegistry,children:c.jsx(at,{})}))}disconnectedCallback(){const t=this.root;if(this.root=null,!t){this.shadow.replaceChildren();return}queueMicrotask(()=>{t.unmount(),this.shadow.replaceChildren()})}}typeof window<"u"&&window.customElements&&!window.customElements.get("citadel-element")&&window.customElements.define("citadel-element",He);const at=()=>(L().displayMode??"panel")==="inline"?c.jsx(rt,{}):c.jsx(st,{});class it{constructor(){C(this,"_description")}describe(e){return this._description=e,this}get description(){return this._description}}class lt{constructor(e){C(this,"state");this.state={path:e,description:"",segments:ct(e)}}describe(e){return this.state.description=e,this}details(e){return this.state.details=e,this}arg(e,t){const s=new it;return t==null||t(s),this.state.segments.push({type:"argument",name:e,description:s.description}),this}handle(e){return{path:this.state.path,description:this.state.description,details:this.state.details,segments:[...this.state.segments],handler:e}}}function ct(n){const e=n.trim();if(!e)throw new Error("Command path cannot be empty");const t=e.split(".");if(t.some(s=>s.trim()===""))throw new Error(`Invalid command path "${n}". Empty segments are not allowed.`);if(t.some(s=>s.includes(" ")))throw new Error(`Invalid command path "${n}". Use dot-delimited words (e.g. "user.show").`);return t.map(s=>({type:"word",name:s}))}function dt(n){return n.flatMap(e=>e.type==="argument"?[e.name]:[])}function mt(n){const e=dt(n.segments);return async t=>{const s=e.reduce((r,i,a)=>(r[i]=t[a],r),{});return Promise.resolve(n.handler({rawArgs:t,namedArgs:s,commandPath:n.path}))}}function ut(n){return new lt(n)}function Me(n,e){n.addCommand(e.segments,e.description,mt(e))}function _e(n,e){return e.forEach(t=>Me(n,t)),n}function pt(n){const e=new K;return _e(e,n)}function ht(n){return new q(n)}function gt(n,e="true",t="false"){return new me(n,e,t)}function ft(n){return new de(n)}function yt(n,e=""){return new pe(n,e)}function Ct(n){return new ne(n)}g.BooleanCommandResult=me,g.Citadel=ot,g.CommandRegistry=K,g.CommandResult=F,g.CommandStatus=$,g.DEFAULT_CURSOR_CONFIGS=xe,g.ErrorCommandResult=ne,g.ImageCommandResult=pe,g.JsonCommandResult=de,g.OutputItem=Q,g.PendingCommandResult=ue,g.TextCommandResult=q,g.bool=gt,g.command=ut,g.createCommandRegistry=pt,g.error=Ct,g.image=yt,g.json=ft,g.registerCommand=Me,g.registerCommands=_e,g.text=ht,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
|
package/dist/citadel.umd.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function(g,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom/client"],c):(g=typeof globalThis<"u"?globalThis:g||self,c(g.Citadel={},g.jsxRuntime,g.React,g.client))})(this,function(g,c,
|
|
2
|
-
`+
|
|
3
|
-
`)))};var R=(t=>(t[t.NONE=0]="NONE",t[t.ERROR=1]="ERROR",t[t.WARN=2]="WARN",t[t.INFO=3]="INFO",t[t.DEBUG=4]="DEBUG",t[t.TRACE=5]="TRACE",t))(R||{});const de=!0;class x{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!de&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!de&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(x,"level",0),C(x,"prefix","");const k={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:R.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,closeOnEscape:!0,showCitadelKey:".",showOnLoad:!1,displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},me=async()=>new q("");class ee{constructor(e,n,s){this.type=e,this.name=n,this.description=s}toString(){return this.name}}class te extends ee{constructor(){super("null",">null<","Empty segment")}}class ue extends ee{constructor(e,n){super("word",e,n)}}class U extends ee{constructor(e,n,s,r){super("argument",e,n),this.value=s,this.valid=r}}const He=t=>{if(t.type==="word")return new ue(t.name,t.description);if(t.type==="argument"){const e=t;return new U(e.name,e.description,e.value,e.valid)}return new te},H=t=>t.map(e=>He(e));class _e{constructor(e,n,s=me){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=n,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class K{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,s=me){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new _e(e,n,s),i=this._commands.find(o=>{const d=o.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const n=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===n);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(n=>{const s=n.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const o=n.segments.filter(d=>d.type==="word").map(d=>d.name);return o.length===e.length&&o.join(" ")===r})}commandExistsForPath(e){const n=this._commands.map(r=>r.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),s=e.map((r,i)=>this._commands.some(d=>{var l;return((l=d.segments[i])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return n.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(n=>n.name)}getMatchingCompletions(e,n){const s=n.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(i=>i.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,n){const s=this.getMatchingCompletions(e,n);if(s.length===1)return s[0]}getCompletions(e){if(x.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(l=>l.segments[0]),o=(l,u)=>l.type===u.type&&l.name===u.name;return i.filter((l,u,y)=>u===y.findIndex(p=>o(p,l)))}const n=e.length;return this._commands.filter(i=>{const o=i.segments;if(o.length<=n-1)return!1;for(let d=0;d<n;d++){const l=e[d],u=o[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(i=>i.segments.length>n).map(i=>{const o=i.segments[n],d=o.type==="argument"?U:ue;return new d(o.name,o.description)}).filter((i,o,d)=>o===d.findIndex(l=>l.type===i.type&&l.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class pe{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const n=await this.getStoredCommands();for(n.push(e);n.length>this.config.maxCommands;)n.shift();await this.saveCommands(n)}}class Te extends pe{constructor(n){super(n);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const n=window.localStorage.getItem(this.storageKey);return n?JSON.parse(n).map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(n){return console.warn("Failed to load commands from localStorage:",n),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(n){console.warn("Failed to clear localStorage:",n)}}async saveCommands(n){try{const s=n.map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments).map(i=>({type:i.type,name:i.name,description:i.description,...i instanceof U?{value:i.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class he extends pe{constructor(n){super(n);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?H(n.commandSegments):[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(s=>({commandSegments:Array.isArray(s.commandSegments)?H(s.commandSegments):[],timestamp:s.timestamp}))}}const z=class z{constructor(){C(this,"currentStorage")}static reset(){z.instance=void 0}static getInstance(){return z.instance||(z.instance=new z),z.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new he(e):this.currentStorage=new Te(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new he(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(z,"instance");let Y=z;class ge{constructor(){C(this,"segments",[]);C(this,"nullSegment",new te);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(n=>n!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(n=>this.push(n))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const ze={config:k,commands:new K,segmentStack:new ge},W=a.createContext(ze),De=({config:t=k,commandRegistry:e,children:n})=>{const[s,r]=a.useState(),[i]=a.useState(()=>new ge),o=a.useMemo(()=>({...k,...t,storage:{...k.storage,...t.storage},cursorType:t.cursorType??k.cursorType,cursorColor:t.cursorColor??k.cursorColor,cursorSpeed:t.cursorSpeed??k.cursorSpeed,closeOnEscape:t.closeOnEscape??k.closeOnEscape,showCitadelKey:t.showCitadelKey??k.showCitadelKey,showOnLoad:t.showOnLoad??k.showOnLoad}),[t]);a.useEffect(()=>{Y.getInstance().initializeStorage(o.storage??k.storage),r(Y.getInstance().getStorage())},[o.storage]),a.useEffect(()=>{if(e){if(o.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=Pe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,o.includeHelpCommand]);const d=a.useMemo(()=>({config:o,commands:e||new K,storage:s,segmentStack:i}),[o,e,s,i]);return c.jsx(W.Provider,{value:d,children:n})},T=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return t.config},J=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return t.commands},fe=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return t.storage},B=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return t.segmentStack},X=class X{constructor(e,n){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${X.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=n??new le}};C(X,"idCounter",0);let G=X;function Oe(t){return{commandSegments:H(t),timestamp:Date.now()}}function ye(){const t=fe(),[e,n]=a.useState({storedCommands:[],position:null}),s=a.useCallback(async d=>{if(t)try{const l=Oe(d);await t.addStoredCommand(l),n(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:H(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[t]),r=a.useCallback(async()=>t?(await t.getStoredCommands()).map(l=>({...l,commandSegments:H(l.commandSegments)})):[],[t]);a.useEffect(()=>{if(!t)return;(async()=>{try{const u=(await t.getStoredCommands()).map(y=>({...y,commandSegments:H(y.commandSegments)}));return n(y=>({...y,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[t]);const i=a.useCallback(async d=>{const l=await r();if(l.length===0)return n(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,n(p=>({...p,storedCommands:l.map(f=>({...f,commandSegments:H(f.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const y=l[u];return y?{segments:H(y.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),o=a.useCallback(async()=>{try{if(!t)return;await t.clear(),n({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[t]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:i,clear:o}}const ne=()=>{const t=T(),e=J(),n=ye(),s=B(),r=fe(),[i,o]=a.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});a.useEffect(()=>{},[r]),a.useEffect(()=>{o(l=>({...l,history:{commands:n.history.storedCommands,position:n.history.position,storage:r}}))},[n.history,r]);const d={setCurrentInput:a.useCallback(l=>{x.debug("[CitadelActions] setCurrentInput: ",l),o(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:a.useCallback(l=>{x.debug("[CitadelActions] setIsEnteringArg: ",l),o(u=>({...u,isEnteringArg:l}))},[]),addOutput:a.useCallback(l=>{x.debug("[CitadelActions]addOutput: ",l),o(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:a.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const y=new G(s);o(p=>({...p,output:[...p.output,y]}));try{const p=new Promise((v,E)=>{setTimeout(()=>{E(new Error("Request timed out"))},t.commandTimeoutMs)}),f=s.arguments.map(v=>v.value||""),b=await Promise.race([u.handler(f),p]);if(!(b instanceof _))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
1
|
+
(function(g,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom/client"],c):(g=typeof globalThis<"u"?globalThis:g||self,c(g.Citadel={},g.jsxRuntime,g.React,g.client))})(this,function(g,c,o,Oe){"use strict";var wt=Object.defineProperty;var vt=(g,c,o)=>c in g?wt(g,c,{enumerable:!0,configurable:!0,writable:!0,value:o}):g[c]=o;var C=(g,c,o)=>vt(g,typeof c!="symbol"?c+"":c,o);var $=(n=>(n.Pending="pending",n.Success="success",n.Failure="failure",n.Timeout="timeout",n))($||{});class F{constructor(e=Date.now()){C(this,"_status","pending");this.timestamp=e}get status(){return this._status}markSuccess(){this._status="success"}markFailure(){this._status="failure"}markTimeout(){this._status="timeout"}}class de extends F{constructor(e,t){super(t),this.data=e}render(){return c.jsx("pre",{className:"citadel-result-json",children:JSON.stringify(this.data,null,2)})}}class q extends F{constructor(e,t){super(t),this.text=e}render(){return c.jsx("div",{className:"citadel-result-text",children:this.text})}}class me extends F{constructor(e,t="true",s="false",r){super(r),this.value=e,this.trueText=t,this.falseText=s}render(){return c.jsx("div",{className:"citadel-result-text citadel-result-boolean",children:this.value?this.trueText:this.falseText})}}class ne extends F{constructor(e,t){super(t),this.error=e,this.markFailure()}render(){return c.jsx("div",{className:"citadel-result-error",children:this.error})}}class ue extends F{render(){return c.jsx("div",{className:"citadel-result-pending",children:"..."})}}class pe extends F{constructor(e,t="",s){super(s),this.imageUrl=e,this.altText=t}render(){return c.jsx("div",{className:"citadel-result-image-wrap",children:c.jsx("img",{src:this.imageUrl,alt:this.altText,className:"citadel-result-image"})})}}const De=n=>async function(){const t=n.commands.filter(s=>s.fullPath[0]!=="help").map(s=>{const i=`${s.segments.map(d=>d.type==="argument"?`<${d.name}>`:d.name).join(" ")} - ${s.description}`,a=s.segments.filter(d=>d.type==="argument"&&d.description).map(d=>` <${d.name}>: ${d.description}`);return{commandLine:i,argumentLines:a}}).sort((s,r)=>s.commandLine.localeCompare(r.commandLine)).flatMap(s=>[s.commandLine,...s.argumentLines]);return t.length===0?new q("No commands available yet. Add some commands to get started!"):(t.push("help - Show available commands"),new q(`Available Commands:
|
|
2
|
+
`+t.join(`
|
|
3
|
+
`)))};var se=(n=>(n[n.NONE=0]="NONE",n[n.ERROR=1]="ERROR",n[n.WARN=2]="WARN",n[n.INFO=3]="INFO",n[n.DEBUG=4]="DEBUG",n[n.TRACE=5]="TRACE",n))(se||{});const he=!0;class k{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!he&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!he&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(k,"level",0),C(k,"prefix","");const E={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:se.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",showOutputPane:!0,resetStateOnHide:!1,closeOnEscape:!0,showCitadelKey:".",showOnLoad:!1,displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},ge=async()=>new q("");class re{constructor(e,t,s){this.type=e,this.name=t,this.description=s}toString(){return this.name}}class oe extends re{constructor(){super("null",">null<","Empty segment")}}class fe extends re{constructor(e,t){super("word",e,t)}}class j extends re{constructor(e,t,s,r){super("argument",e,t),this.value=s,this.valid=r}}const ze=n=>{if(n.type==="word")return new fe(n.name,n.description);if(n.type==="argument"){const e=n;return new j(e.name,e.description,e.value,e.valid)}return new oe},_=n=>n.map(e=>ze(e));class Fe{constructor(e,t,s=ge){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=t,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class K{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,t,s=ge){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new Fe(e,t,s),i=this._commands.find(a=>{const d=a.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const t=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===t);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(t=>{const s=t.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const a=t.segments.filter(d=>d.type==="word").map(d=>d.name);return a.length===e.length&&a.join(" ")===r})}commandExistsForPath(e){const t=this._commands.map(r=>r.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),s=e.map((r,i)=>this._commands.some(d=>{var l;return((l=d.segments[i])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return t.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(t=>t.name)}getMatchingCompletions(e,t){const s=t.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(i=>i.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,t){const s=this.getMatchingCompletions(e,t);if(s.length===1)return s[0]}getCompletions(e){if(k.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(l=>l.segments[0]),a=(l,u)=>l.type===u.type&&l.name===u.name;return i.filter((l,u,f)=>u===f.findIndex(p=>a(p,l)))}const t=e.length;return this._commands.filter(i=>{const a=i.segments;if(a.length<=t-1)return!1;for(let d=0;d<t;d++){const l=e[d],u=a[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(i=>i.segments.length>t).map(i=>{const a=i.segments[t],d=a.type==="argument"?j:fe;return new d(a.name,a.description)}).filter((i,a,d)=>a===d.findIndex(l=>l.type===i.type&&l.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class ye{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const t=await this.getStoredCommands();for(t.push(e);t.length>this.config.maxCommands;)t.shift();await this.saveCommands(t)}}class Le extends ye{constructor(t){super(t);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const t=window.localStorage.getItem(this.storageKey);return t?JSON.parse(t).map(r=>({commandSegments:Array.isArray(r.commandSegments)?_(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(t){return console.warn("Failed to load commands from localStorage:",t),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(t){console.warn("Failed to clear localStorage:",t)}}async saveCommands(t){try{const s=t.map(r=>({commandSegments:Array.isArray(r.commandSegments)?_(r.commandSegments).map(i=>({type:i.type,name:i.name,description:i.description,...i instanceof j?{value:i.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class Ce extends ye{constructor(t){super(t);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(t=>({commandSegments:Array.isArray(t.commandSegments)?_(t.commandSegments):[],timestamp:t.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(t){this.storedCommands=t.map(s=>({commandSegments:Array.isArray(s.commandSegments)?_(s.commandSegments):[],timestamp:s.timestamp}))}}const U=class U{constructor(){C(this,"currentStorage")}static reset(){U.instance=void 0}static getInstance(){return U.instance||(U.instance=new U),U.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new Ce(e):this.currentStorage=new Le(e)}catch(t){console.warn("Failed to create storage, falling back to memory storage:",t),this.currentStorage=new Ce(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(U,"instance");let J=U;class we{constructor(){C(this,"segments",[]);C(this,"nullSegment",new oe);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(t=>t!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(t=>this.push(t))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const Ue={config:E,commands:new K,segmentStack:new we},W=o.createContext(Ue),$e=({config:n=E,commandRegistry:e,children:t})=>{const[s,r]=o.useState(),[i]=o.useState(()=>new we),a=o.useMemo(()=>({...E,...n,storage:{...E.storage,...n.storage},cursorType:n.cursorType??E.cursorType,cursorColor:n.cursorColor??E.cursorColor,cursorSpeed:n.cursorSpeed??E.cursorSpeed,closeOnEscape:n.closeOnEscape??E.closeOnEscape,showCitadelKey:n.showCitadelKey??E.showCitadelKey,showOnLoad:n.showOnLoad??E.showOnLoad}),[n]);o.useEffect(()=>{J.getInstance().initializeStorage(a.storage??E.storage),r(J.getInstance().getStorage())},[a.storage]),o.useEffect(()=>{if(e){if(a.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=De(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,a.includeHelpCommand]);const d=o.useMemo(()=>({config:a,commands:e||new K,storage:s,segmentStack:i}),[a,e,s,i]);return c.jsx(W.Provider,{value:d,children:t})},L=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return n.config},X=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return n.commands},ve=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return n.storage},B=()=>{const n=o.useContext(W);if(n===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return n.segmentStack},ee=class ee{constructor(e,t){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${ee.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=t??new ue}};C(ee,"idCounter",0);let Q=ee;function je(n){return{commandSegments:_(n),timestamp:Date.now()}}function Se(){const n=ve(),[e,t]=o.useState({storedCommands:[],position:null}),s=o.useCallback(async d=>{if(n)try{const l=je(d);await n.addStoredCommand(l),t(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:_(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[n]),r=o.useCallback(async()=>n?(await n.getStoredCommands()).map(l=>({...l,commandSegments:_(l.commandSegments)})):[],[n]);o.useEffect(()=>{if(!n)return;(async()=>{try{const u=(await n.getStoredCommands()).map(f=>({...f,commandSegments:_(f.commandSegments)}));return t(f=>({...f,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[n]);const i=o.useCallback(async d=>{const l=await r();if(l.length===0)return t(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,t(p=>({...p,storedCommands:l.map(y=>({...y,commandSegments:_(y.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const f=l[u];return f?{segments:_(f.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),a=o.useCallback(async()=>{try{if(!n)return;await n.clear(),t({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[n]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:i,clear:a}}const ae=()=>{const n=L(),e=X(),t=Se(),s=B(),r=ve(),[i,a]=o.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});o.useEffect(()=>{},[r]),o.useEffect(()=>{a(l=>({...l,history:{commands:t.history.storedCommands,position:t.history.position,storage:r}}))},[t.history,r]);const d={setCurrentInput:o.useCallback(l=>{k.debug("[CitadelActions] setCurrentInput: ",l),a(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:o.useCallback(l=>{k.debug("[CitadelActions] setIsEnteringArg: ",l),a(u=>({...u,isEnteringArg:l}))},[]),addOutput:o.useCallback(l=>{k.debug("[CitadelActions]addOutput: ",l),a(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:o.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const f=new Q(s);a(p=>({...p,output:[...p.output,f]}));try{const p=new Promise((S,N)=>{setTimeout(()=>{N(new Error("Request timed out"))},n.commandTimeoutMs)}),y=s.arguments.map(S=>S.value||""),w=await Promise.race([u.handler(y),p]);if(!(w instanceof F))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
4
4
|
For example:
|
|
5
5
|
return new JsonCommandResult({ text: "Hello World" });
|
|
6
|
-
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);b.markSuccess(),o(v=>({...v,output:v.output.map(E=>E.id===y.id?{...E,result:b}:E)}))}catch(p){const f=new Z(p instanceof Error?p.message:"Unknown error");f.markFailure(),o(b=>({...b,output:b.output.map(v=>v.id===y.id?{...v,result:f}:v)}))}},[e,t.commandTimeoutMs,s]),clearHistory:a.useCallback(async()=>{try{await n.clear()}catch(l){console.warn("Failed to clear history:",l)}},[n])};return{state:i,actions:d}},Fe=({onOpen:t,onClose:e,isVisible:n,showCitadelKey:s,closeOnEscape:r})=>{a.useEffect(()=>{const i=o=>{var d,l;!n&&o.key===s&&!["input","textarea"].includes(((l=(d=o.target)==null?void 0:d.tagName)==null?void 0:l.toLowerCase())||"")&&(o.preventDefault(),t()),r&&n&&o.key==="Escape"&&(o.preventDefault(),e())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[t,e,n,s,r])},Le=200,je=t=>{const{isVisible:e,isClosing:n,onAnimationComplete:s}=t,r=a.useMemo(()=>e?n?"citadel_slideDown":"citadel_slideUp":"",[e,n]);return a.useEffect(()=>{if(!n||!s)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){s();return}const o=setTimeout(()=>{s()},Le);return()=>clearTimeout(o)},[n,s]),{animationClass:r}},Ue=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),Ce=t=>{const e=t==null?void 0:t.trim();return e||void 0},$e=t=>{const e=Ce(t);return e?{style:{fontSize:e}}:{}},Q=(t,e)=>{const n=Ce(t),r={...$e(e).style};return n&&(r.fontFamily=n),{style:Object.keys(r).length>0?r:void 0}},qe=({command:t,timestamp:e,status:n,fontFamily:s,fontSize:r})=>{const i=a.useMemo(()=>Q(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:i.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",t.split(" ").map((o,d)=>{const l=o.startsWith("<")&&o.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",o]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),n===j.Pending&&c.jsx(Ue,{}),n===j.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(n===j.Timeout||n===j.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},Ke=({output:t,outputRef:e})=>{const n=T(),s=a.useMemo(()=>Q(n.fontFamily,n.outputFontSize??n.fontSize),[n.fontFamily,n.fontSize,n.outputFontSize]),r=a.useCallback(()=>{if(e.current){const i=e.current;requestAnimationFrame(()=>{i.scrollTop=i.scrollHeight})}},[e]);return a.useEffect(()=>{if(r(),e.current){const i=e.current.getElementsByTagName("img"),o=i[i.length-1];if(o&&!o.complete)return o.addEventListener("load",r),()=>o.removeEventListener("load",r)}},[t,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:t.map(i=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(qe,{command:i.command.join(" "),timestamp:new Date(i.timestamp).toLocaleTimeString(),status:i.result.status,fontFamily:n.fontFamily,fontSize:n.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:i.result.render()})]},i.id))})},we={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ve=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],Se=["|","/","-","\\"],We=({style:t={type:"blink"},isValid:e=!0,errorMessage:n})=>{const s=a.useMemo(()=>({...we[t.type],...t}),[t]),[r,i]=a.useState(!0),[o,d]=a.useState(0);a.useEffect(()=>{if(s.speed===0)return;const y=setInterval(()=>{s.type==="blink"?i(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?Se.length:ve.length))},s.speed);return()=>clearInterval(y)},[s.type,s.speed]);const l=a.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&n?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?Se:ve)[o]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:n,children:u()})})};function Be(t,e){switch(e.type){case"set":return x.debug(`[inputStateReducer] InputState changing from ${t} to ${e.state}`),e.state;default:return t}}const Ve=()=>{const{state:t}=ne(),e=J(),n=ye(),s=B(),[r,i]=a.useReducer(Be,"idle"),o=m=>{i({type:"set",state:m})},d=a.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return x.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=a.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=a.useCallback((m,h)=>{if(!m)return h;const w=s.path().length;return h.filter(D=>{const S=D.segments[w];return!S||S.type!=="word"?!1:S.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),y=a.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=a.useCallback(m=>{const h=s.path(),w=e.getCompletions(h);return w.length===0&&m?!1:w.some(S=>S.type==="argument")?!0:e.getMatchingCompletions(h,m).some(S=>S.type==="word")},[e,s]),f=a.useCallback(m=>{x.debug("[tryAutoComplete] input: ",m);const h=y(m);return!h||h.type==="null"?new te:(x.debug("[tryAutoComplete] result: ",h),h)},[y]),b=a.useCallback((m,h)=>{if(t.history.position!==null)return;h.setCurrentInput(m),x.debug("[useCommandParser][handleInputChange] newValue: ",m);const w=d();if(w.type==="argument"||r==="entering_argument"){const A=be(m);if(A.isQuoted)if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return;else if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return}if(m.endsWith(" ")){const A=m.trim().toLowerCase(),P=e.getCompletions(s.path()).filter(N=>N.type==="word"&&N.name.toLowerCase()===A);if(P.length===1){s.push(P[0]),h.setCurrentInput(""),o("idle");return}}const S=f(m);if(S.type==="word"){x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",S),s.push(S),h.setCurrentInput(""),o("idle");return}},[f,t,d,r,s,e]),v=a.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),o("idle")},[s]),E=a.useCallback((m,h,w)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:S,isEnteringArg:A}=h,P=be(S);switch(m.key){case"Backspace":return S===""&&(m.preventDefault(),s.size()>0&&s.pop(),o("idle")),!0;case"Enter":{if(m.preventDefault(),P.isQuoted&&!P.isComplete)return!0;if(r==="entering_argument"||A&&S.trim()){const F=d();F instanceof U&&(F.value=S,x.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",F),s.push(F))}const N=s.path(),V=e.getCommand(N);if(!V)return!1;const O=V.segments.filter(F=>F.type==="argument"),$=s.arguments;return O.length>$.length?!1:(x.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),w.executeCommand(),n.addStoredCommand(s.toArray()),v(w),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("up");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("down");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();default:{if(!A&&m.key.length===1){const N=S+m.key;if(!p(N))return m.preventDefault(),!1}return!0}}},[r,p,d,n,v,e,s]);return{handleInputChange:b,handleKeyDown:E,inputState:r,setInputStateWithLogging:o,findMatchingCommands:u,getAutocompleteSuggestion:y,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function be(t){const e=[];let n="",s=!1,r;for(let i=0;i<t.length;i++){const o=t[i];(o==='"'||o==="'")&&(!s||o===r)?s?(e.push(n),n="",s=!1,r=void 0):(n&&(e.push(n),n=""),s=!0,r=o):!s&&o===" "?n&&(e.push(n),n=""):n+=o}return{words:e,currentWord:n,isQuoted:s,quoteChar:r,isComplete:!s&&!n}}const Ye=()=>{const t=B(),[e,n]=a.useState(0);return a.useEffect(()=>{const s={update:()=>{n(r=>r+1)}};return t.subscribe(s),()=>{t.unsubscribe(s)}},[t]),e},Je=({state:t,actions:e})=>{const n=a.useRef(null),s=J(),r=B(),{handleKeyDown:i,handleInputChange:o,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Ve(),[y,p]=a.useState(!1),f=T(),b=Ye(),v=a.useRef(null),[E,m]=a.useState(0),h=a.useMemo(()=>Q(f.fontFamily,f.fontSize),[f.fontFamily,f.fontSize]),w=a.useCallback(async I=>{const M=i(I,t,e);await Promise.resolve(M)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,i,t]),D=a.useCallback(I=>{o(I.target.value,e)},[e,o]),S=a.useCallback(I=>{I.preventDefault();const M=I.clipboardData.getData("text");o(M,e)},[e,o]);a.useEffect(()=>{n.current&&n.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),a.useEffect(()=>{if(d!=="idle")return;const I=u();let M="idle";switch(I.type){case"word":M="entering_command",e.setIsEnteringArg(!1);break;case"argument":M="entering_argument",e.setIsEnteringArg(!0);break}l(M)},[b,d,u,l,e]);const A=a.useMemo(()=>{const I=[],M=r.toArray().map((L,re)=>{I.push(L.name);const Ae=s.hasNextSegment(I);if(L.type==="argument"){const ae=L;return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:ae.value}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+ae.name+ae.value)}return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:L.name}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+L.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:M},b)]},[b,s,r]),[P,N]=a.useState("");a.useEffect(()=>{const I=u();I.type==="argument"?N(I.name):N("")},[b,u]);const O=!t.isEnteringArg?"is-command-mode":"is-argument-mode",$=a.useMemo(()=>({left:`${E}px`,transition:"left 0.05s ease-out"}),[E]),F=a.useMemo(()=>({type:f.cursorType??k.cursorType,color:f.cursorColor||k.cursorColor,speed:f.cursorSpeed||k.cursorSpeed}),[f.cursorColor,f.cursorSpeed,f.cursorType]);return a.useLayoutEffect(()=>{const I=v.current,M=n.current;if(!I||!M){m(0);return}const L=I.getBoundingClientRect().width;m(Math.max(0,L-M.scrollLeft))},[t.currentInput,O,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[A,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:v,className:`citadel-input-measure ${O}`.trim(),"aria-hidden":"true",children:t.currentInput}),c.jsx("input",{ref:n,type:"text",role:"textbox",value:t.currentInput,onChange:D,onKeyDown:w,onPaste:S,"data-testid":"citadel-command-input",className:`citadel-input-field ${O} ${y?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:P}),c.jsx("div",{className:"citadel-input-cursor",style:$,children:c.jsx(We,{style:F})})]})]})]})})},Ge=({currentInput:t=""})=>{const e=J(),n=T(),s=B(),r=a.useMemo(()=>Q(n.fontFamily,n.fontSize),[n.fontFamily,n.fontSize]),i=t.trim().toLowerCase(),o=e.getMatchingCompletions(s.path(),i);x.debug("[AvailableCommands] nextCommandSegments: ",o);const d=a.useMemo(()=>{const p=[...o],f=m=>m.name.toLowerCase()==="help",b=p.filter(f);return[...p.filter(m=>!f(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...b]},[o]),l=a.useMemo(()=>{const p=new Map;for(const f of d){const b=d.reduce((v,E)=>{if(E===f)return v;let m=0;for(;m<f.name.length&&m<E.name.length&&f.name[m].toLowerCase()===E.name[m].toLowerCase();)m++;return Math.max(v,m+1)},1);p.set(f.name,b)}return p},[d]),u=o.some(p=>p.type==="argument"),y=o[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?o.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:y.name}),y.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",y.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const f=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,f)}),p.name.slice(f)]})},p.name)})})})})},xe=({state:t,actions:e,outputRef:n})=>{const r=T().displayMode==="inline",i=a.useMemo(()=>r?{overflow:"hidden"}:void 0,[r]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:i,children:c.jsx(Ke,{output:t.output,outputRef:n})}),c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Je,{state:t,actions:e}),c.jsx(Ge,{currentInput:t.isEnteringArg?"":t.currentInput})]})]})},Qe=()=>{const t=T(),[e,n]=a.useState(()=>t.showOnLoad??!1),[s,r]=a.useState(!1),[i,o]=a.useState(()=>t.initialHeight||null),d=a.useRef(null),l=a.useRef(null),u=a.useRef(!1),y=a.useRef(0),p=a.useRef(0),{state:f,actions:b}=ne(),v=a.useCallback(()=>{r(!1),n(!0)},[]),E=a.useCallback(()=>{r(!0)},[]);Fe({onOpen:v,onClose:E,isVisible:e&&!s,showCitadelKey:t.showCitadelKey||".",closeOnEscape:t.closeOnEscape??!0});const m=a.useCallback(P=>{var $;if(!u.current)return;const N=P.clientY-y.current,V=($=t.maxHeight)!=null&&$.endsWith("vh")?window.innerHeight*parseInt(t.maxHeight,10)/100:parseInt(t.maxHeight||"80vh",10),O=Math.min(Math.max(p.current-N,parseInt(t.minHeight||"200",10)),V);l.current&&(l.current.style.height=`${O}px`,l.current.style.bottom="0",o(`${O}px`))},[t.maxHeight,t.minHeight]),h=a.useCallback(()=>{u.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m]),w=a.useCallback(P=>{l.current&&(u.current=!0,y.current=P.clientY,p.current=l.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",m),document.addEventListener("mouseup",h))},[m,h]);a.useEffect(()=>()=>{document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m,h]);const D=a.useCallback(()=>{s&&(n(!1),r(!1))},[s]),{animationClass:S}=je({isVisible:e,isClosing:s,onAnimationComplete:D}),A=a.useMemo(()=>({...i?{height:i}:{},maxHeight:t.maxHeight}),[t.maxHeight,i]);return e?c.jsxs("div",{ref:l,className:`panelContainer ${S}`.trim(),style:A,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:w}),c.jsx(xe,{state:f,actions:b,outputRef:d})]}):null},se=t=>{if(!t)return;const e=t.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Xe=()=>{const{state:t,actions:e}=ne(),n=T(),s=a.useRef(null),r=a.useMemo(()=>({height:se(n.initialHeight),maxHeight:se(n.maxHeight),minHeight:se(n.minHeight)}),[n.initialHeight,n.maxHeight,n.minHeight]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:r,children:c.jsx(xe,{state:t,actions:e,outputRef:s})})},ke=`:host {
|
|
6
|
+
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);w.markSuccess(),a(S=>({...S,output:S.output.map(N=>N.id===f.id?{...N,result:w}:N)}))}catch(p){const y=new ne(p instanceof Error?p.message:"Unknown error");y.markFailure(),a(w=>({...w,output:w.output.map(S=>S.id===f.id?{...S,result:y}:S)}))}},[e,n.commandTimeoutMs,s]),clearHistory:o.useCallback(async()=>{try{await t.clear()}catch(l){console.warn("Failed to clear history:",l)}},[t])};return{state:i,actions:d}},qe=({onOpen:n,onClose:e,isVisible:t,showCitadelKey:s,closeOnEscape:r})=>{o.useEffect(()=>{const i=a=>{var d,l;!t&&a.key===s&&!["input","textarea"].includes(((l=(d=a.target)==null?void 0:d.tagName)==null?void 0:l.toLowerCase())||"")&&(a.preventDefault(),n()),r&&t&&a.key==="Escape"&&(a.preventDefault(),e())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[n,e,t,s,r])},Ke=200,We=n=>{const{isVisible:e,isClosing:t,onAnimationComplete:s}=n,r=o.useMemo(()=>e?t?"citadel_slideDown":"citadel_slideUp":"",[e,t]);return o.useEffect(()=>{if(!t||!s)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){s();return}const a=setTimeout(()=>{s()},Ke);return()=>clearTimeout(a)},[t,s]),{animationClass:r}},Be=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),be=n=>{const e=n==null?void 0:n.trim();return e||void 0},Ve=n=>{const e=be(n);return e?{style:{fontSize:e}}:{}},Z=(n,e)=>{const t=be(n),r={...Ve(e).style};return t&&(r.fontFamily=t),{style:Object.keys(r).length>0?r:void 0}},Ge=({command:n,timestamp:e,status:t,fontFamily:s,fontSize:r})=>{const i=o.useMemo(()=>Z(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:i.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",n.split(" ").map((a,d)=>{const l=a.startsWith("<")&&a.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",a]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),t===$.Pending&&c.jsx(Be,{}),t===$.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(t===$.Timeout||t===$.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},Ye=({output:n,outputRef:e})=>{const t=L(),s=o.useMemo(()=>Z(t.fontFamily,t.outputFontSize??t.fontSize),[t.fontFamily,t.fontSize,t.outputFontSize]),r=o.useCallback(()=>{if(e.current){const i=e.current;requestAnimationFrame(()=>{i.scrollTop=i.scrollHeight})}},[e]);return o.useEffect(()=>{if(r(),e.current){const i=e.current.getElementsByTagName("img"),a=i[i.length-1];if(a&&!a.complete)return a.addEventListener("load",r),()=>a.removeEventListener("load",r)}},[n,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:n.map(i=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(Ge,{command:i.command.join(" "),timestamp:new Date(i.timestamp).toLocaleTimeString(),status:i.result.status,fontFamily:t.fontFamily,fontSize:t.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:i.result.render()})]},i.id))})},xe={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ke=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],Ee=["|","/","-","\\"],Je=({style:n={type:"blink"},isValid:e=!0,errorMessage:t})=>{const s=o.useMemo(()=>({...xe[n.type],...n}),[n]),[r,i]=o.useState(!0),[a,d]=o.useState(0);o.useEffect(()=>{if(s.speed===0)return;const f=setInterval(()=>{s.type==="blink"?i(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?Ee.length:ke.length))},s.speed);return()=>clearInterval(f)},[s.type,s.speed]);const l=o.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&t?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?Ee:ke)[a]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:t,children:u()})})};function Xe(n,e){switch(e.type){case"set":return k.debug(`[inputStateReducer] InputState changing from ${n} to ${e.state}`),e.state;default:return n}}const Qe=()=>{const{state:n}=ae(),e=X(),t=Se(),s=B(),[r,i]=o.useReducer(Xe,"idle"),a=m=>{i({type:"set",state:m})},d=o.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return k.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=o.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=o.useCallback((m,h)=>{if(!m)return h;const v=s.path().length;return h.filter(T=>{const b=T.segments[v];return!b||b.type!=="word"?!1:b.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),f=o.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=o.useCallback(m=>{const h=s.path(),v=e.getCompletions(h);return v.length===0&&m?!1:v.some(b=>b.type==="argument")?!0:e.getMatchingCompletions(h,m).some(b=>b.type==="word")},[e,s]),y=o.useCallback(m=>{k.debug("[tryAutoComplete] input: ",m);const h=f(m);return!h||h.type==="null"?new oe:(k.debug("[tryAutoComplete] result: ",h),h)},[f]),w=o.useCallback((m,h)=>{if(n.history.position!==null)return;h.setCurrentInput(m),k.debug("[useCommandParser][handleInputChange] newValue: ",m);const v=d();if(v.type==="argument"||r==="entering_argument"){const H=Ne(m);if(H.isQuoted)if(H.isComplete){if(!(v instanceof j))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),a("idle");return}else return;else if(H.isComplete){if(!(v instanceof j))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),a("idle");return}else return}if(m.endsWith(" ")){const H=m.trim().toLowerCase(),z=e.getCompletions(s.path()).filter(I=>I.type==="word"&&I.name.toLowerCase()===H);if(z.length===1){s.push(z[0]),h.setCurrentInput(""),a("idle");return}}const b=y(m);if(b.type==="word"){k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",b),s.push(b),h.setCurrentInput(""),a("idle");return}},[y,n,d,r,s,e]),S=o.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),a("idle")},[s]),N=o.useCallback((m,h,v)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:b,isEnteringArg:H}=h,z=Ne(b);switch(m.key){case"Backspace":return b===""&&(m.preventDefault(),s.size()>0&&s.pop(),a("idle")),!0;case"Enter":{if(m.preventDefault(),z.isQuoted&&!z.isComplete)return!0;if(r==="entering_argument"||H&&b.trim()){const D=d();D instanceof j&&(D.value=b,k.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",D),s.push(D))}const I=s.path(),O=e.getCommand(I);if(!O)return!1;const M=O.segments.filter(D=>D.type==="argument"),V=s.arguments;return M.length>V.length?!1:(k.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),v.executeCommand(),t.addStoredCommand(s.toArray()),S(v),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const I=await t.navigateHistory("up");return I.segments&&(s.clear(),s.pushAll(I.segments),v.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const I=await t.navigateHistory("down");return I.segments&&(s.clear(),s.pushAll(I.segments),v.setCurrentInput("")),!0})();default:{if(!H&&m.key.length===1){const I=b+m.key;if(!p(I))return m.preventDefault(),!1}return!0}}},[r,p,d,t,S,e,s]);return{handleInputChange:w,handleKeyDown:N,inputState:r,setInputStateWithLogging:a,findMatchingCommands:u,getAutocompleteSuggestion:f,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function Ne(n){const e=[];let t="",s=!1,r;for(let i=0;i<n.length;i++){const a=n[i];(a==='"'||a==="'")&&(!s||a===r)?s?(e.push(t),t="",s=!1,r=void 0):(t&&(e.push(t),t=""),s=!0,r=a):!s&&a===" "?t&&(e.push(t),t=""):t+=a}return{words:e,currentWord:t,isQuoted:s,quoteChar:r,isComplete:!s&&!t}}const Ze=()=>{const n=B(),[e,t]=o.useState(0);return o.useEffect(()=>{const s={update:()=>{t(r=>r+1)}};return n.subscribe(s),()=>{n.unsubscribe(s)}},[n]),e},Re=({state:n,actions:e})=>{const t=o.useRef(null),s=X(),r=B(),{handleKeyDown:i,handleInputChange:a,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Qe(),[f,p]=o.useState(!1),y=L(),w=Ze(),S=o.useRef(null),[N,m]=o.useState(0),h=o.useMemo(()=>Z(y.fontFamily,y.fontSize),[y.fontFamily,y.fontSize]),v=o.useCallback(async x=>{const A=i(x,n,e);await Promise.resolve(A)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,i,n]),T=o.useCallback(x=>{a(x.target.value,e)},[e,a]),b=o.useCallback(x=>{x.preventDefault();const A=x.clipboardData.getData("text");a(A,e)},[e,a]);o.useEffect(()=>{t.current&&t.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),o.useEffect(()=>{if(d!=="idle")return;const x=u();let A="idle";switch(x.type){case"word":A="entering_command",e.setIsEnteringArg(!1);break;case"argument":A="entering_argument",e.setIsEnteringArg(!0);break}l(A)},[w,d,u,l,e]);const H=o.useMemo(()=>{const x=[],A=r.toArray().map((P,G)=>{x.push(P.name);const te=s.hasNextSegment(x);if(P.type==="argument"){const Y=P;return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:Y.value}),G<r.size()&&te&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+Y.name+Y.value)}return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:P.name}),G<r.size()&&te&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+P.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:A},w)]},[w,s,r]),[z,I]=o.useState("");o.useEffect(()=>{const x=u();x.type==="argument"?I(x.name):I("")},[w,u]);const M=!n.isEnteringArg?"is-command-mode":"is-argument-mode",V=o.useMemo(()=>({left:`${N}px`,transition:"left 0.05s ease-out"}),[N]),D=o.useMemo(()=>({type:y.cursorType??E.cursorType,color:y.cursorColor||E.cursorColor,speed:y.cursorSpeed||E.cursorSpeed}),[y.cursorColor,y.cursorSpeed,y.cursorType]);return o.useLayoutEffect(()=>{const x=S.current,A=t.current;if(!x||!A){m(0);return}const P=x.getBoundingClientRect().width;m(Math.max(0,P-A.scrollLeft))},[n.currentInput,M,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[H,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:S,className:`citadel-input-measure ${M}`.trim(),"aria-hidden":"true",children:n.currentInput}),c.jsx("input",{ref:t,type:"text",role:"textbox",value:n.currentInput,onChange:T,onKeyDown:v,onPaste:b,"data-testid":"citadel-command-input",className:`citadel-input-field ${M} ${f?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:z}),c.jsx("div",{className:"citadel-input-cursor",style:V,children:c.jsx(Je,{style:D})})]})]})]})})},et=({currentInput:n=""})=>{const e=X(),t=L(),s=B(),r=o.useMemo(()=>Z(t.fontFamily,t.fontSize),[t.fontFamily,t.fontSize]),i=n.trim().toLowerCase(),a=e.getMatchingCompletions(s.path(),i);k.debug("[AvailableCommands] nextCommandSegments: ",a);const d=o.useMemo(()=>{const p=[...a],y=m=>m.name.toLowerCase()==="help",w=p.filter(y);return[...p.filter(m=>!y(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...w]},[a]),l=o.useMemo(()=>{const p=new Map;for(const y of d){const w=d.reduce((S,N)=>{if(N===y)return S;let m=0;for(;m<y.name.length&&m<N.name.length&&y.name[m].toLowerCase()===N.name[m].toLowerCase();)m++;return Math.max(S,m+1)},1);p.set(y.name,w)}return p},[d]),u=a.some(p=>p.type==="argument"),f=a[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?a.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:f.name}),f.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",f.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const y=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,y)}),p.name.slice(y)]})},p.name)})})})})},Ie=({state:n,actions:e,outputRef:t})=>{const s=L(),r=s.displayMode==="inline",i=s.showOutputPane??!0,a=o.useMemo(()=>i&&r?{overflow:"hidden"}:void 0,[r,i]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[i?c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:a,children:c.jsx(Ye,{output:n.output,outputRef:t})}):null,c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Re,{state:n,actions:e}),c.jsx(et,{currentInput:n.isEnteringArg?"":n.currentInput})]})]})},R="128px",tt="200px",nt="80vh",ie=n=>{if(!n)return;const e=n.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Ae=(n,e)=>{if(!n)return e;const t=n.trim();if(!t)return e;if(t.endsWith("vh")){const r=Number.parseFloat(t);return Number.isFinite(r)?window.innerHeight*r/100:e}const s=Number.parseFloat(t);return Number.isFinite(s)?s:e},st=()=>{const n=L(),e=n.showOutputPane??!0,t=ie(n.minHeight)??tt,s=ie(n.maxHeight)??nt,r=e?t:R,i=Number.parseFloat(R),[a,d]=o.useState(()=>{const P=ie(n.initialHeight);return e?P??null:R}),[l,u]=o.useState(()=>n.showOnLoad??!1),[f,p]=o.useState(!1),y=o.useRef(null),w=o.useRef(null),S=o.useRef(!1),N=o.useRef(0),m=o.useRef(0),h=o.useRef(null),v=o.useRef(a),T=o.useRef(e),{state:b,actions:H}=ae(),z=o.useCallback(()=>{p(!1),u(!0)},[]),I=o.useCallback(()=>{p(!0)},[]);qe({onOpen:z,onClose:I,isVisible:l&&!f,showCitadelKey:n.showCitadelKey||".",closeOnEscape:n.closeOnEscape??!0});const O=o.useCallback(P=>{if(!S.current)return;const G=P.clientY-N.current,te=Ae(s,window.innerHeight*80/100),Y=Ae(r,i),Te=Math.min(Math.max(m.current-G,Y),te);w.current&&(w.current.style.height=`${Te}px`,w.current.style.bottom="0",d(`${Te}px`))},[i,r,s]),M=o.useCallback(()=>{S.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",O),document.removeEventListener("mouseup",M)},[O]),V=o.useCallback(P=>{w.current&&(S.current=!0,N.current=P.clientY,m.current=w.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",O),document.addEventListener("mouseup",M))},[O,M]);o.useEffect(()=>()=>{document.removeEventListener("mousemove",O),document.removeEventListener("mouseup",M)},[O,M]),o.useEffect(()=>{v.current=a},[a]),o.useEffect(()=>{if(!e){T.current&&(h.current=v.current??(w.current?`${w.current.offsetHeight}px`:null)),T.current=!1,d(R);return}T.current=!0,h.current&&(d(h.current),h.current=null)},[e]);const D=o.useCallback(()=>{f&&(u(!1),p(!1))},[f]),{animationClass:x}=We({isVisible:l,isClosing:f,onAnimationComplete:D}),A=o.useMemo(()=>({...a?{height:a}:{},minHeight:r,maxHeight:s}),[r,a,s]);return l?c.jsxs("div",{ref:w,className:`panelContainer ${x}`.trim(),style:A,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:V}),c.jsx(Ie,{state:b,actions:H,outputRef:y})]}):null},le="128px",ce=n=>{if(!n)return;const e=n.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},rt=()=>{const{state:n,actions:e}=ae(),t=L(),s=t.showOutputPane??!0,r=o.useRef(null),i=o.useMemo(()=>({height:s?ce(t.initialHeight):le,maxHeight:s?ce(t.maxHeight):le,minHeight:s?ce(t.minHeight):le}),[t.initialHeight,t.maxHeight,t.minHeight,s]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:i,children:c.jsx(Ie,{state:n,actions:e,outputRef:r})})},Pe=`:host {
|
|
7
7
|
--citadel-bg: oklch(20.8% 0.042 265.8);
|
|
8
8
|
--citadel-surface: oklch(27.9% 0.041 260);
|
|
9
9
|
--citadel-border: oklch(37.2% 0.044 257.3);
|
|
@@ -475,5 +475,5 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
475
475
|
object-fit: contain;
|
|
476
476
|
border-radius: 0.5rem;
|
|
477
477
|
}
|
|
478
|
-
`,
|
|
479
|
-
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const
|
|
478
|
+
`,ot=({config:n=E,commandRegistry:e,containerId:t=null})=>{const s=o.useRef(new K),r=e??s.current,i=o.useRef(null),a=o.useMemo(()=>({width:"100%",height:"100%"}),[]),d=n.displayMode??E.displayMode??"panel";return o.useEffect(()=>{k.configure({level:n.logLevel||E.logLevel||se.ERROR,prefix:"[Citadel]"});const l=new He(r,n),u=d==="inline"&&!t,f=u?i.current:t?document.getElementById(t):document.body;if(f)f.appendChild(l);else{if(u){console.warn("[Citadel] No host available for inline mode; skipping mount.");return}console.warn(`Container with id "${t}" not found, falling back to body`),document.body.appendChild(l)}return()=>{var p;(p=l.parentElement)==null||p.removeChild(l)}},[r,t,n,d]),d==="inline"&&!t?c.jsx("div",{ref:i,style:a}):null};class He extends HTMLElement{constructor(t,s){var i;super();C(this,"shadow");C(this,"root",null);C(this,"commandRegistry");C(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=t,this.config=s;const r=((i=this.config)==null?void 0:i.displayMode)??"panel";this.setAttribute("data-display-mode",r)}connectedCallback(){try{const s=[Pe].map(r=>{const i=new CSSStyleSheet;return i.replaceSync(r),i});this.shadow.adoptedStyleSheets=[...s]}catch{const s=[Pe].join(`
|
|
479
|
+
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const t=document.createElement("div");t.id="citadel-root",t.style.width="100%",t.style.height="100%",this.shadow.appendChild(t),this.root=Oe.createRoot(t),this.root.render(c.jsx($e,{config:this.config||E,commandRegistry:this.commandRegistry,children:c.jsx(at,{})}))}disconnectedCallback(){const t=this.root;if(this.root=null,!t){this.shadow.replaceChildren();return}queueMicrotask(()=>{t.unmount(),this.shadow.replaceChildren()})}}typeof window<"u"&&window.customElements&&!window.customElements.get("citadel-element")&&window.customElements.define("citadel-element",He);const at=()=>(L().displayMode??"panel")==="inline"?c.jsx(rt,{}):c.jsx(st,{});class it{constructor(){C(this,"_description")}describe(e){return this._description=e,this}get description(){return this._description}}class lt{constructor(e){C(this,"state");this.state={path:e,description:"",segments:ct(e)}}describe(e){return this.state.description=e,this}details(e){return this.state.details=e,this}arg(e,t){const s=new it;return t==null||t(s),this.state.segments.push({type:"argument",name:e,description:s.description}),this}handle(e){return{path:this.state.path,description:this.state.description,details:this.state.details,segments:[...this.state.segments],handler:e}}}function ct(n){const e=n.trim();if(!e)throw new Error("Command path cannot be empty");const t=e.split(".");if(t.some(s=>s.trim()===""))throw new Error(`Invalid command path "${n}". Empty segments are not allowed.`);if(t.some(s=>s.includes(" ")))throw new Error(`Invalid command path "${n}". Use dot-delimited words (e.g. "user.show").`);return t.map(s=>({type:"word",name:s}))}function dt(n){return n.flatMap(e=>e.type==="argument"?[e.name]:[])}function mt(n){const e=dt(n.segments);return async t=>{const s=e.reduce((r,i,a)=>(r[i]=t[a],r),{});return Promise.resolve(n.handler({rawArgs:t,namedArgs:s,commandPath:n.path}))}}function ut(n){return new lt(n)}function Me(n,e){n.addCommand(e.segments,e.description,mt(e))}function _e(n,e){return e.forEach(t=>Me(n,t)),n}function pt(n){const e=new K;return _e(e,n)}function ht(n){return new q(n)}function gt(n,e="true",t="false"){return new me(n,e,t)}function ft(n){return new de(n)}function yt(n,e=""){return new pe(n,e)}function Ct(n){return new ne(n)}g.BooleanCommandResult=me,g.Citadel=ot,g.CommandRegistry=K,g.CommandResult=F,g.CommandStatus=$,g.DEFAULT_CURSOR_CONFIGS=xe,g.ErrorCommandResult=ne,g.ImageCommandResult=pe,g.JsonCommandResult=de,g.OutputItem=Q,g.PendingCommandResult=ue,g.TextCommandResult=q,g.bool=gt,g.command=ut,g.createCommandRegistry=pt,g.error=Ct,g.image=yt,g.json=ft,g.registerCommand=Me,g.registerCommands=_e,g.text=ht,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -28,6 +28,8 @@ import { CitadelConfig } from './types';
|
|
|
28
28
|
*
|
|
29
29
|
* @property outputFontSize - The output font size as a CSS value. Default: '0.875rem'.
|
|
30
30
|
*
|
|
31
|
+
* @property showOutputPane - Whether to render the output pane. Default: true.
|
|
32
|
+
*
|
|
31
33
|
* @property resetStateOnHide - When true, hiding the interface (via Escape key or other means) will clear the command input.
|
|
32
34
|
* When false, the interface preserves the last input when hidden. Default: false.
|
|
33
35
|
*
|
|
@@ -65,6 +65,12 @@ export interface CitadelConfig {
|
|
|
65
65
|
* If omitted, output uses `fontSize`.
|
|
66
66
|
*/
|
|
67
67
|
outputFontSize?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Controls whether the output pane is rendered.
|
|
70
|
+
* Set to `false` when command side effects are rendered elsewhere in the host app.
|
|
71
|
+
* Defaults to `true`.
|
|
72
|
+
*/
|
|
73
|
+
showOutputPane?: boolean;
|
|
68
74
|
/**
|
|
69
75
|
* Whether to reset the state when the interface is hidden (via Escape key or other means).
|
|
70
76
|
*/
|
|
@@ -8,6 +8,7 @@ export interface RuntimeConfigControls {
|
|
|
8
8
|
setCursorColor: (color: string) => void;
|
|
9
9
|
setDisplayMode: (mode: DisplayMode) => void;
|
|
10
10
|
setIncludeHelpCommand: (enabled: boolean) => void;
|
|
11
|
+
toggleOutputPane: () => void;
|
|
11
12
|
setMaxHeight: (value: string) => void;
|
|
12
13
|
resetConfig: () => void;
|
|
13
14
|
}
|
package/package.json
CHANGED