citadel_cli 1.1.4 → 1.1.6

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.
@@ -1,9 +1,9 @@
1
- (function(w,i){typeof exports=="object"&&typeof module<"u"?i(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"],i):(w=typeof globalThis<"u"?globalThis:w||self,i(w.Citadel={},w.jsxRuntime,w.React,w.client))})(this,function(w,i,s,me){"use strict";var je=Object.defineProperty;var Me=(w,i,s)=>i in w?je(w,i,{enumerable:!0,configurable:!0,writable:!0,value:s}):w[i]=s;var y=(w,i,s)=>Me(w,typeof i!="symbol"?i+"":i,s);const ue=({onOpen:r,onClose:e,isVisible:n,showCitadelKey:t})=>{s.useEffect(()=>{const o=a=>{var c,m;!n&&a.key===t&&!["input","textarea"].includes(((m=(c=a.target)==null?void 0:c.tagName)==null?void 0:m.toLowerCase())||"")&&(a.preventDefault(),r()),n&&a.key==="Escape"&&(a.preventDefault(),e())};return document.addEventListener("keydown",o),()=>document.removeEventListener("keydown",o)},[r,e,n,t])},Y={container:"_container_141sr_3",innerContainer:"_innerContainer_141sr_19",inputSection:"_inputSection_141sr_28",resizeHandle:"_resizeHandle_141sr_35",citadel_slideUp:"_citadel_slideUp_141sr_64",citadel_slideDown:"_citadel_slideDown_141sr_68"},pe=r=>{const{isVisible:e,isClosing:n,onAnimationComplete:t}=r,o=s.useMemo(()=>e?n?Y.slideDown:Y.slideUp:"",[e,n]);return s.useEffect(()=>{if(t){const c=setTimeout(()=>{t()},200);return()=>clearTimeout(c)}},[n,t]),{style:s.useMemo(()=>({opacity:e?1:0,transform:e?"translateY(0)":n?"translateY(100%)":"translateY(-100%)",transition:"opacity 200ms ease-in-out, transform 200ms ease-in-out"}),[e,n]),animationClass:o}};var T=(r=>(r.Pending="pending",r.Success="success",r.Failure="failure",r.Timeout="timeout",r))(T||{});class H{constructor(e=Date.now()){y(this,"_status","pending");this.timestamp=e}get status(){return this._status}markSuccess(){this._status="success"}markFailure(){this._status="failure"}markTimeout(){this._status="timeout"}}class ge extends H{constructor(e,n){super(n),this.data=e}render(){return i.jsx("pre",{className:"text-gray-200",children:JSON.stringify(this.data,null,2)})}}class V extends H{constructor(e,n){super(n),this.text=e}render(){return i.jsx("div",{className:"text-gray-200 whitespace-pre font-mono",children:this.text})}}class B extends H{constructor(e,n){super(n),this.error=e,this.markFailure()}render(){return i.jsx("div",{className:"mt-1 text-red-400",children:this.error})}}class G extends H{render(){return i.jsx("div",{className:"text-gray-400",children:"..."})}}class he extends H{constructor(e,n="",t){super(t),this.imageUrl=e,this.altText=n}render(){return i.jsx("div",{className:"my-2",children:i.jsx("img",{src:this.imageUrl,alt:this.altText,className:"max-w-[400px] max-h-[300px] h-auto rounded-lg object-contain"})})}}const fe=r=>async function(){const e=r.commands.filter(n=>n.fullPath[0]!=="help").map(n=>`${n.segments.map(o=>o.type==="argument"?`<${o.name}>`:o.name).join(" ")} - ${n.description}`).sort();return e.push("help - Show available commands"),new V(e.length>0?`Available Commands:
1
+ (function(w,a){typeof exports=="object"&&typeof module<"u"?a(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"],a):(w=typeof globalThis<"u"?globalThis:w||self,a(w.Citadel={},w.jsxRuntime,w.React,w.client))})(this,function(w,a,s,pe){"use strict";var $e=Object.defineProperty;var Ke=(w,a,s)=>a in w?$e(w,a,{enumerable:!0,configurable:!0,writable:!0,value:s}):w[a]=s;var x=(w,a,s)=>Ke(w,typeof a!="symbol"?a+"":a,s);var D=(r=>(r.Pending="pending",r.Success="success",r.Failure="failure",r.Timeout="timeout",r))(D||{});class P{constructor(e=Date.now()){x(this,"_status","pending");this.timestamp=e}get status(){return this._status}markSuccess(){this._status="success"}markFailure(){this._status="failure"}markTimeout(){this._status="timeout"}}class he extends P{constructor(e,n){super(n),this.data=e}render(){return a.jsx("pre",{className:"text-gray-200",children:JSON.stringify(this.data,null,2)})}}class V extends P{constructor(e,n){super(n),this.text=e}render(){return a.jsx("div",{className:"text-gray-200 whitespace-pre font-mono",children:this.text})}}class G extends P{constructor(e,n){super(n),this.error=e,this.markFailure()}render(){return a.jsx("div",{className:"mt-1 text-red-400",children:this.error})}}class J extends P{render(){return a.jsx("div",{className:"text-gray-400",children:"..."})}}class ge extends P{constructor(e,n="",t){super(t),this.imageUrl=e,this.altText=n}render(){return a.jsx("div",{className:"my-2",children:a.jsx("img",{src:this.imageUrl,alt:this.altText,className:"max-w-[400px] max-h-[300px] h-auto rounded-lg object-contain"})})}}const fe=r=>async function(){const e=r.commands.filter(n=>n.fullPath[0]!=="help").map(n=>`${n.segments.map(o=>o.type==="argument"?`<${o.name}>`:o.name).join(" ")} - ${n.description}`).sort();return e.push("help - Show available commands"),new V(e.length>0?`Available Commands:
2
2
  `+e.join(`
3
- `):"No commands available yet. Add some commands to get started!")};var $=(r=>(r[r.NONE=0]="NONE",r[r.ERROR=1]="ERROR",r[r.WARN=2]="WARN",r[r.INFO=3]="INFO",r[r.DEBUG=4]="DEBUG",r[r.TRACE=5]="TRACE",r))($||{});class S{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&process.env.NODE_ENV!=="production"&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&process.env.NODE_ENV!=="production"&&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)}}y(S,"level",0),y(S,"prefix","");const N={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,initialHeight:"40vh",logLevel:process.env.NODE_ENV==="production"?$.ERROR:$.DEBUG,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,showCitadelKey:".",storage:{type:"localStorage",maxCommands:100}};class J{constructor(e){y(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 we extends J{constructor(n){super(n);y(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const n=window.localStorage.getItem(this.storageKey);return n?JSON.parse(n).map(o=>({commandSegments:o.commandSegments||[],timestamp:o.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 t=n.map(o=>({commandSegments:Array.isArray(o.commandSegments)?[...o.commandSegments]:[],timestamp:o.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(t))}catch(t){throw console.warn("Failed to save commands to localStorage:",t),t}}}class be extends J{constructor(n){super(n);y(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?[...n.commandSegments]:[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(t=>({commandSegments:Array.isArray(t.commandSegments)?[...t.commandSegments]:[],timestamp:t.timestamp}))}}const D=class D{constructor(){y(this,"currentStorage")}static getInstance(){return D.instance||(D.instance=new D),D.instance}initializeStorage(e){if(!this.currentStorage)try{this.currentStorage=new we(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new be(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};y(D,"instance");let K=D;const Q=async()=>new V("");class W{constructor(e,n,t){this.type=e,this.name=n,this.description=t}toString(){return this.name}}class X extends W{constructor(){super("null",">null<","Empty segment")}}class ye extends W{constructor(e,n){super("word",e,n)}}class xe extends W{constructor(e,n,t,o){super("argument",e,n),this.value=t,this.valid=o}}class Ce{constructor(e,n,t=Q){y(this,"_segments");y(this,"_description");y(this,"_handler");this._segments=e,this._description=n,this._handler=t}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 L{constructor(){y(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,t=Q){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const o=new Ce(e,n,t),a=this._commands.find(c=>{const m=c.segments.map(d=>d.type==="argument"?"*":d.name).join(" "),u=e.map(d=>d.type==="argument"?"*":d.name).join(" ");return m===u});if(a)throw new Error(`Duplicate commands: '${a.fullPath_s}' and '${o.fullPath_s}'`);this._commands.push(o)}getCommand(e){return this._commands.find(n=>{const t=n.fullPath.join(" "),o=e.join(" ");if(t===o)return!0;const c=n.segments.filter(m=>m.type==="word").map(m=>m.name);return c.length===e.length&&c.join(" ")===o})}commandExistsForPath(e){const n=this._commands.map(o=>o.segments.map(a=>a.type==="argument"?"*":a.name).join(" ")),t=e.map((o,a)=>this._commands.some(m=>{var u;return((u=m.segments[a])==null?void 0:u.type)==="argument"})?"*":o).join(" ");return n.includes(t)}getCompletions_s(e){return this.getCompletions(e).map(n=>n.name)}getCompletions(e){if(S.debug("[getCompletions] path: ",e),!e.length){const a=this._commands.map(u=>u.segments[0]),c=(u,d)=>u.type===d.type&&u.name===d.name;return a.filter((u,d,p)=>d===p.findIndex(g=>c(g,u)))}const n=e.length;return this._commands.filter(a=>{const c=a.segments;if(c.length<=n-1)return!1;for(let m=0;m<n;m++){const u=e[m],d=c[m];if(!(u==="*"&&d.type==="argument")&&u!==d.name)return!1}return!0}).filter(a=>a.segments.length>n).map(a=>{const c=a.segments[n],m=c.type==="argument"?xe:ye;return new m(c.name,c.description)}).filter((a,c,m)=>c===m.findIndex(u=>u.type===a.type&&u.name===a.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class Z{constructor(){y(this,"segments",[]);y(this,"nullSegment",new X);y(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 ve={config:N,commands:new L,segmentStack:new Z},U=s.createContext(ve),Se=({config:r=N,commandRegistry:e,children:n})=>{const[t,o]=s.useState(),a={...N,...r,storage:{...N.storage,...r.storage},cursorType:r.cursorType??N.cursorType,cursorColor:r.cursorColor??N.cursorColor,cursorSpeed:r.cursorSpeed??N.cursorSpeed,showCitadelKey:r.showCitadelKey||"."};s.useEffect(()=>{K.getInstance().initializeStorage(a.storage??N.storage),o(K.getInstance().getStorage())},[]),s.useEffect(()=>{if(e&&a.includeHelpCommand&&!e.commandExistsForPath(["help"])){const m=fe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",m)}},[e,a.includeHelpCommand]);const c={config:a,commands:e||new L,storage:t,segmentStack:new Z};return i.jsx(U.Provider,{value:c,children:n})},F=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return r.config},q=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return r.commands},R=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return r.storage},j=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return r.segmentStack};class ee{constructor(e,n){y(this,"timestamp");y(this,"command");y(this,"result");this.command=e.toArray().map(t=>t.type==="argument"?t.value||"":t.name),this.timestamp=Date.now(),this.result=n??new G}}function ke(r){return{commandSegments:r,timestamp:Date.now()}}function ne(){const r=R(),[e,n]=s.useState({storedCommands:[],position:null}),t=s.useCallback(async m=>{if(r)try{const u=ke(m);await r.addStoredCommand(u),n(d=>({...d,storedCommands:[...d.storedCommands,u],position:null}))}catch(u){console.warn("Failed to save command to history:",u)}},[r]),o=s.useCallback(async()=>r?await r.getStoredCommands():[],[r]);s.useEffect(()=>{if(!r)return;(async()=>{try{const u=await r.getStoredCommands();return n(d=>({...d,storedCommands:u})),u}catch(u){console.warn("Failed to load command history:",u)}})()},[r]);const a=s.useCallback(async m=>{if((await o()).length===0)return{segments:null,position:null};let d=null;return m==="up"?e.position===null?d=e.storedCommands.length-1:e.position>0?d=e.position-1:d=0:e.position===null||e.position>=e.storedCommands.length-1?d=null:d=e.position+1,n(g=>({...g,position:d})),d===null?{segments:[],position:null}:{segments:d!==null?e.storedCommands[d].commandSegments:null,position:d}},[e,o]),c=s.useCallback(async()=>{try{if(!r)return;await r.clear(),n({storedCommands:[],position:null})}catch(m){console.warn("Failed to clear command history:",m)}},[r]);return{history:e,addStoredCommand:t,getStoredCommands:o,navigateHistory:a,clear:c}}const te=()=>{const r=F(),e=q(),n=ne(),t=j(),o=R(),[a,c]=s.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:o}});s.useEffect(()=>{},[o]),s.useEffect(()=>{c(p=>({...p,history:{commands:n.history.storedCommands,position:n.history.position,storage:o}}))},[n.history,o]);const m={setCurrentInput:s.useCallback(p=>{S.debug("[CitadelActions] setCurrentInput: ",p),c(g=>({...g,currentInput:p}))},[]),setIsEnteringArg:s.useCallback(p=>{S.debug("[CitadelActions] setIsEnteringArg: ",p),c(g=>({...g,isEnteringArg:p}))},[]),addOutput:s.useCallback(p=>{S.debug("[CitadelActions]addOutput: ",p),c(g=>({...g,output:[...g.output,p]}))},[]),executeCommand:s.useCallback(async()=>{const p=t.path(),g=e.getCommand(p);if(!g){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",p);return}const k=new ee(t);c(x=>({...x,output:[...x.output,k]}));try{const x=new Promise((l,h)=>{setTimeout(()=>{h(new Error("Request timed out"))},r.commandTimeoutMs)}),A=t.arguments.map(l=>l.value||""),_=await Promise.race([g.handler(A),x]);if(!(_ instanceof H))throw new Error(`The ${p.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
3
+ `):"No commands available yet. Add some commands to get started!")};var F=(r=>(r[r.NONE=0]="NONE",r[r.ERROR=1]="ERROR",r[r.WARN=2]="WARN",r[r.INFO=3]="INFO",r[r.DEBUG=4]="DEBUG",r[r.TRACE=5]="TRACE",r))(F||{});class E{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&process.env.NODE_ENV!=="production"&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&process.env.NODE_ENV!=="production"&&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)}}x(E,"level",0),x(E,"prefix","");const A={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,initialHeight:"40vh",logLevel:process.env.NODE_ENV==="production"?F.ERROR:F.DEBUG,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,showCitadelKey:".",displayMode:"panel",storage:{type:"localStorage",maxCommands:100}};class Q{constructor(e){x(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 we extends Q{constructor(n){super(n);x(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const n=window.localStorage.getItem(this.storageKey);return n?JSON.parse(n).map(o=>({commandSegments:o.commandSegments||[],timestamp:o.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 t=n.map(o=>({commandSegments:Array.isArray(o.commandSegments)?[...o.commandSegments]:[],timestamp:o.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(t))}catch(t){throw console.warn("Failed to save commands to localStorage:",t),t}}}class be extends Q{constructor(n){super(n);x(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?[...n.commandSegments]:[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(t=>({commandSegments:Array.isArray(t.commandSegments)?[...t.commandSegments]:[],timestamp:t.timestamp}))}}const H=class H{constructor(){x(this,"currentStorage")}static getInstance(){return H.instance||(H.instance=new H),H.instance}initializeStorage(e){if(!this.currentStorage)try{this.currentStorage=new we(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new be(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};x(H,"instance");let O=H;const X=async()=>new V("");class W{constructor(e,n,t){this.type=e,this.name=n,this.description=t}toString(){return this.name}}class Z extends W{constructor(){super("null",">null<","Empty segment")}}class ye extends W{constructor(e,n){super("word",e,n)}}class xe extends W{constructor(e,n,t,o){super("argument",e,n),this.value=t,this.valid=o}}class Ce{constructor(e,n,t=X){x(this,"_segments");x(this,"_description");x(this,"_handler");this._segments=e,this._description=n,this._handler=t}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 L{constructor(){x(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,t=X){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const o=new Ce(e,n,t),i=this._commands.find(l=>{const m=l.segments.map(d=>d.type==="argument"?"*":d.name).join(" "),u=e.map(d=>d.type==="argument"?"*":d.name).join(" ");return m===u});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${o.fullPath_s}'`);this._commands.push(o)}removeCommand(e){const n=e.join(" "),t=this._commands.findIndex(o=>o.fullPath.join(" ")===n);return t===-1?!1:(this._commands.splice(t,1),!0)}getCommand(e){return this._commands.find(n=>{const t=n.fullPath.join(" "),o=e.join(" ");if(t===o)return!0;const l=n.segments.filter(m=>m.type==="word").map(m=>m.name);return l.length===e.length&&l.join(" ")===o})}commandExistsForPath(e){const n=this._commands.map(o=>o.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),t=e.map((o,i)=>this._commands.some(m=>{var u;return((u=m.segments[i])==null?void 0:u.type)==="argument"})?"*":o).join(" ");return n.includes(t)}getCompletions_s(e){return this.getCompletions(e).map(n=>n.name)}getCompletions(e){if(E.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(u=>u.segments[0]),l=(u,d)=>u.type===d.type&&u.name===d.name;return i.filter((u,d,p)=>d===p.findIndex(g=>l(g,u)))}const n=e.length;return this._commands.filter(i=>{const l=i.segments;if(l.length<=n-1)return!1;for(let m=0;m<n;m++){const u=e[m],d=l[m];if(!(u==="*"&&d.type==="argument")&&u!==d.name)return!1}return!0}).filter(i=>i.segments.length>n).map(i=>{const l=i.segments[n],m=l.type==="argument"?xe:ye;return new m(l.name,l.description)}).filter((i,l,m)=>l===m.findIndex(u=>u.type===i.type&&u.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class R{constructor(){x(this,"segments",[]);x(this,"nullSegment",new Z);x(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 ve={config:A,commands:new L,segmentStack:new R},U=s.createContext(ve),Se=({config:r=A,commandRegistry:e,children:n})=>{const[t,o]=s.useState(),i={...A,...r,storage:{...A.storage,...r.storage},cursorType:r.cursorType??A.cursorType,cursorColor:r.cursorColor??A.cursorColor,cursorSpeed:r.cursorSpeed??A.cursorSpeed,showCitadelKey:r.showCitadelKey||"."};s.useEffect(()=>{O.getInstance().initializeStorage(i.storage??A.storage),o(O.getInstance().getStorage())},[]),s.useEffect(()=>{if(e){if(i.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const m=fe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",m)}return}e.removeCommand(["help"])}},[e,i.includeHelpCommand]);const l={config:i,commands:e||new L,storage:t,segmentStack:new R};return a.jsx(U.Provider,{value:l,children:n})},M=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return r.config},$=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return r.commands},ee=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return r.storage},j=()=>{const r=s.useContext(U);if(r===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return r.segmentStack};class ne{constructor(e,n){x(this,"timestamp");x(this,"command");x(this,"result");this.command=e.toArray().map(t=>t.type==="argument"?t.value||"":t.name),this.timestamp=Date.now(),this.result=n??new J}}function ke(r){return{commandSegments:r,timestamp:Date.now()}}function te(){const r=ee(),[e,n]=s.useState({storedCommands:[],position:null}),t=s.useCallback(async m=>{if(r)try{const u=ke(m);await r.addStoredCommand(u),n(d=>({...d,storedCommands:[...d.storedCommands,u],position:null}))}catch(u){console.warn("Failed to save command to history:",u)}},[r]),o=s.useCallback(async()=>r?await r.getStoredCommands():[],[r]);s.useEffect(()=>{if(!r)return;(async()=>{try{const u=await r.getStoredCommands();return n(d=>({...d,storedCommands:u})),u}catch(u){console.warn("Failed to load command history:",u)}})()},[r]);const i=s.useCallback(async m=>{if((await o()).length===0)return{segments:null,position:null};let d=null;return m==="up"?e.position===null?d=e.storedCommands.length-1:e.position>0?d=e.position-1:d=0:e.position===null||e.position>=e.storedCommands.length-1?d=null:d=e.position+1,n(g=>({...g,position:d})),d===null?{segments:[],position:null}:{segments:d!==null?e.storedCommands[d].commandSegments:null,position:d}},[e,o]),l=s.useCallback(async()=>{try{if(!r)return;await r.clear(),n({storedCommands:[],position:null})}catch(m){console.warn("Failed to clear command history:",m)}},[r]);return{history:e,addStoredCommand:t,getStoredCommands:o,navigateHistory:i,clear:l}}const Y=()=>{const r=M(),e=$(),n=te(),t=j(),o=ee(),[i,l]=s.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:o}});s.useEffect(()=>{},[o]),s.useEffect(()=>{l(p=>({...p,history:{commands:n.history.storedCommands,position:n.history.position,storage:o}}))},[n.history,o]);const m={setCurrentInput:s.useCallback(p=>{E.debug("[CitadelActions] setCurrentInput: ",p),l(g=>({...g,currentInput:p}))},[]),setIsEnteringArg:s.useCallback(p=>{E.debug("[CitadelActions] setIsEnteringArg: ",p),l(g=>({...g,isEnteringArg:p}))},[]),addOutput:s.useCallback(p=>{E.debug("[CitadelActions]addOutput: ",p),l(g=>({...g,output:[...g.output,p]}))},[]),executeCommand:s.useCallback(async()=>{const p=t.path(),g=e.getCommand(p);if(!g){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",p);return}const S=new ne(t);l(b=>({...b,output:[...b.output,S]}));try{const b=new Promise((c,h)=>{setTimeout(()=>{h(new Error("Request timed out"))},r.commandTimeoutMs)}),C=t.arguments.map(c=>c.value||""),_=await Promise.race([g.handler(C),b]);if(!(_ instanceof P))throw new Error(`The ${p.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 ${p.join(".")} command and update the return type for its handler.`);_.markSuccess(),c(l=>({...l,output:l.output.map(h=>h.timestamp===k.timestamp?{...h,result:_}:h)}))}catch(x){const A=new B(x instanceof Error?x.message:"Unknown error");A.markFailure(),c(_=>({..._,output:_.output.map(l=>l.timestamp===k.timestamp?{...l,result:A}:l)}))}},[e,r.commandTimeoutMs,t]),clearHistory:s.useCallback(async()=>{try{await n.clear()}catch(p){console.warn("Failed to clear history:",p)}},[n])},u=s.useCallback(()=>e.getCompletions_s(t.path()),[t,e]),d=s.useCallback(()=>e.getCompletions(t.path()),[t,e]);return{state:a,actions:m,getAvailableCommands_s:u,getAvailableCommandSegments:d}},re={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},oe=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],se=["|","/","-","\\"],Ee=({style:r={type:"blink"},isValid:e=!0,errorMessage:n})=>{const t=s.useMemo(()=>({...re[r.type],...r}),[r]),[o,a]=s.useState(!0),[c,m]=s.useState(0);s.useEffect(()=>{if(t.speed===0)return;const p=setInterval(()=>{t.type==="blink"?a(g=>!g):["spin","bbs"].includes(t.type)&&m(g=>(g+1)%(t.type==="bbs"?se.length:oe.length))},t.speed);return()=>clearInterval(p)},[t.type,t.speed]);const u=s.useMemo(()=>({color:e?t.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,t.color]),d=()=>!e&&n?"✗":["spin","bbs"].includes(t.type)?(t.type==="bbs"?se:oe)[c]:t.type==="solid"||o?t.character:" ";return i.jsx("div",{className:"relative inline-block",children:i.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:u,title:n,children:d()})})};function _e(r,e){switch(e.type){case"set":return S.debug(`[inputStateReducer] InputState changing from ${r} to ${e.state}`),e.state;default:return r}}const Ne=()=>{const{state:r}=te(),e=q(),n=ne(),t=j(),[o,a]=s.useReducer(_e,"idle"),c=l=>{a({type:"set",state:l})},m=s.useCallback(()=>{const h=e.getCompletions(t.path())[0]||t.nullSegment;return S.debug("[getNextExpectedSegment] ",h),h},[e,t]),u=s.useCallback(()=>e.getCompletions_s(t.path()).map(h=>e.getCommand([...t.path(),h])).filter(h=>h!==void 0),[e,t]),d=s.useCallback((l,h)=>{if(!l)return h;const f=h.reduce((b,C)=>{const v=m();return(v==null?void 0:v.type)==="word"&&b.set(v.name,C),b},new Map);return Array.from(f.values()).filter(()=>{const b=m();return b.type!=="word"?!1:b.name.toLowerCase().startsWith(l.toLowerCase())})},[m]),p=s.useCallback(l=>{const f=e.getCompletions(t.path()).filter(E=>E.type==="word").filter(E=>E.name.toLowerCase().startsWith(l.toLowerCase()));return f.length===1?f[0]:t.nullSegment},[e,t]),g=s.useCallback(l=>{const h=t.path(),f=e.getCompletions(h);return f.length===0&&l?!1:f.some(b=>b.type==="argument")?!0:f.some(b=>b.type==="word"&&b.name.toLowerCase().startsWith(l.toLowerCase()))},[e,t]),k=s.useCallback(l=>{S.debug("[tryAutoComplete] input: ",l);const h=p(l);return!h||h.name===l?new X:(S.debug("[tryAutoComplete] result: ",h),h)},[p]),x=s.useCallback((l,h)=>{if(r.history.position===null){if(h.setCurrentInput(l),S.debug("[useCommandParser][handleInputChange] newValue: ",l),o==="entering_argument"){const f=ae(l);if(f.isQuoted)if(f.isComplete){const E=m();if(E.type==="argument"){const b=E;b.value=l.trim()||"",S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",b),t.push(b),h.setCurrentInput(""),c("idle");return}}else return;else if(f.isComplete){const E=m();E.value=l.trim()||"",S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",E),t.push(E),h.setCurrentInput(""),c("idle");return}else return}if(o=="entering_command"){const f=k(l);if(f.type==="word"){S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",f),t.push(f),h.setCurrentInput(""),c("idle");return}}}},[k,r,m,o,t]),A=s.useCallback(l=>{l.setCurrentInput(""),l.setIsEnteringArg(!1),t.clear(),c("idle")},[t]),_=s.useCallback((l,h,f)=>{if(!(l.key==="Backspace"||l.key==="Enter"||l.key==="ArrowUp"||l.key==="ArrowDown"||l.key==="ArrowLeft"||l.key==="ArrowRight"||l.key==="Escape"||l.key==="Delete"||l.key==="Home"||l.key==="End"||l.key.length===1))return!0;const{currentInput:b,isEnteringArg:C}=h,v=ae(b);switch(l.key){case"Backspace":return b===""&&(l.preventDefault(),t.size()>0&&t.pop(),c("idle")),!0;case"Enter":{if(l.preventDefault(),v.isQuoted&&!v.isComplete)return!0;if(o==="entering_argument"||C&&b.trim()){const P=m();P.value=b,S.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",P),t.push(P)}const z=t.path(),I=e.getCommand(z);if(I){const M=I.segments.filter(O=>O.type==="argument"),P=t.arguments;if(M.length>P.length)return!1}return S.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",t),f.executeCommand(),n.addStoredCommand(t.toArray()),A(f),!0}case"ArrowUp":return l.preventDefault(),(async()=>{const z=await n.navigateHistory("up",t.toArray());return z.segments&&(t.clear(),t.pushAll(z.segments),f.setCurrentInput("")),!0})();case"ArrowDown":return l.preventDefault(),(async()=>{const z=await n.navigateHistory("down",t.toArray());return z.segments&&(t.clear(),t.pushAll(z.segments),f.setCurrentInput("")),!0})();default:{if(!C&&l.key.length===1){const z=b+l.key;if(!g(z))return l.preventDefault(),!1}return!0}}},[o,g,m,n,A,t]);return{handleInputChange:x,handleKeyDown:_,inputState:o,setInputStateWithLogging:c,findMatchingCommands:d,getAutocompleteSuggestion:p,getAvailableNodes:u,getNextExpectedSegment:m,isValidCommandInput:g}};function ae(r){const e=[];let n="",t=!1,o;for(let a=0;a<r.length;a++){const c=r[a];(c==='"'||c==="'")&&(!t||c===o)?t?(e.push(n),n="",t=!1,o=void 0):(n&&(e.push(n),n=""),t=!0,o=c):!t&&c===" "?n&&(e.push(n),n=""):n+=c}return{words:e,currentWord:n,isQuoted:t,quoteChar:o,isComplete:!t&&!n}}const Ae=()=>{const r=j(),[e,n]=s.useState(0);return s.useEffect(()=>{const t={update:()=>{n(o=>o+1)}};return r.subscribe(t),()=>{r.unsubscribe(t)}},[r]),e},ze=({state:r,actions:e})=>{const n=s.useRef(null),t=q(),o=j(),{handleKeyDown:a,handleInputChange:c,inputState:m,setInputStateWithLogging:u,getNextExpectedSegment:d}=Ne(),[p,g]=s.useState(!1),k=F(),x=Ae(),A=async C=>{const v=a(C,r,e);await Promise.resolve(v)===!1&&(g(!0),setTimeout(()=>g(!1),500))},_=C=>{c(C.target.value,e)},l=C=>{C.preventDefault();const v=C.clipboardData.getData("text");c(v,e)};s.useEffect(()=>{n.current&&n.current.focus(),m!=="entering_command"&&u("entering_command")},[m,u]),s.useEffect(()=>{if(m!=="idle")return;const C=d();let v="idle";switch(C.type){case"word":v="entering_command",e.setIsEnteringArg(!1);break;case"argument":v="entering_argument",e.setIsEnteringArg(!0);break}u(v)},[x,m,d,u,e]);const[h,f]=s.useState([]);s.useEffect(()=>{const C=[],v=o.toArray().map((I,M)=>{C.push(I.name);const P=t.hasNextSegment(C);if(I.type==="argument"){const O=I;return i.jsxs(s.Fragment,{children:[i.jsx("span",{className:"text-gray-200 whitespace-pre",children:O.value}),M<o.size()&&P&&i.jsx("span",{className:"text-gray-200 whitespace-pre",children:" "})]},"arg-"+O.name+O.value)}return i.jsxs(s.Fragment,{children:[i.jsx("span",{className:"text-blue-400 whitespace-pre",children:I.name}),M<o.size()&&P&&i.jsx("span",{className:"text-blue-400 whitespace-pre",children:" "})]},"word-"+I.name)});f([i.jsx("div",{className:"flex items-center gap-1","data-testid":"user-input-area",children:v},"{segmentStackVersion}")])},[x,t,o]);const[E,b]=s.useState("");return s.useEffect(()=>{const C=d();C.type==="argument"?b(C.name):b("")},[x,d]),i.jsxs("div",{className:"flex flex-col w-full bg-gray-900 rounded-lg p-4",children:[i.jsx("style",{children:`
6
+ Check the definition of the ${p.join(".")} command and update the return type for its handler.`);_.markSuccess(),l(c=>({...c,output:c.output.map(h=>h.timestamp===S.timestamp?{...h,result:_}:h)}))}catch(b){const C=new G(b instanceof Error?b.message:"Unknown error");C.markFailure(),l(_=>({..._,output:_.output.map(c=>c.timestamp===S.timestamp?{...c,result:C}:c)}))}},[e,r.commandTimeoutMs,t]),clearHistory:s.useCallback(async()=>{try{await n.clear()}catch(p){console.warn("Failed to clear history:",p)}},[n])},u=s.useCallback(()=>e.getCompletions_s(t.path()),[t,e]),d=s.useCallback(()=>e.getCompletions(t.path()),[t,e]);return{state:i,actions:m,getAvailableCommands_s:u,getAvailableCommandSegments:d}},Ee=({onOpen:r,onClose:e,isVisible:n,showCitadelKey:t})=>{s.useEffect(()=>{const o=i=>{var l,m;!n&&i.key===t&&!["input","textarea"].includes(((m=(l=i.target)==null?void 0:l.tagName)==null?void 0:m.toLowerCase())||"")&&(i.preventDefault(),r()),n&&i.key==="Escape"&&(i.preventDefault(),e())};return document.addEventListener("keydown",o),()=>document.removeEventListener("keydown",o)},[r,e,n,t])},re={panelContainer:"_panelContainer_1pav9_3",innerContainer:"_innerContainer_1pav9_19",inputSection:"_inputSection_1pav9_29",resizeHandle:"_resizeHandle_1pav9_36",citadel_slideUp:"_citadel_slideUp_1pav9_65",citadel_slideDown:"_citadel_slideDown_1pav9_69",inlineContainer:"_inlineContainer_1pav9_73"},_e=r=>{const{isVisible:e,isClosing:n,onAnimationComplete:t}=r,o=s.useMemo(()=>e?n?re.slideDown:re.slideUp:"",[e,n]);return s.useEffect(()=>{if(t){const l=setTimeout(()=>{t()},200);return()=>clearTimeout(l)}},[n,t]),{style:s.useMemo(()=>({opacity:e?1:0,transform:e?"translateY(0)":n?"translateY(100%)":"translateY(-100%)",transition:"opacity 200ms ease-in-out, transform 200ms ease-in-out"}),[e,n]),animationClass:o}},Ne=()=>a.jsx("div",{"data-testid":"spinner",className:"animate-spin rounded-full h-4 w-4 border-2 border-gray-300 border-t-gray-600"}),Ae=({command:r,timestamp:e,status:n})=>a.jsxs("div",{className:"flex items-center gap-2 font-mono text-sm",children:[a.jsxs("span",{className:"text-gray-200",children:["> ",r.split(" ").map((t,o)=>{const i=t.startsWith("<")&&t.endsWith(">");return a.jsxs("span",{className:i?"text-green-400":"text-gray-200",children:[o>0?" ":"",t]},o)})]}),a.jsx("span",{className:"text-gray-400",children:"·"}),a.jsx("span",{className:"text-gray-500",children:e}),n===D.Pending&&a.jsx(Ne,{}),n===D.Success&&a.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-green-500"}),(n===D.Timeout||n===D.Failure)&&a.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-red-500"})]}),ze=({output:r,outputRef:e})=>{const n=M(),t=s.useCallback(()=>{if(e.current){const o=e.current;requestAnimationFrame(()=>{o.scrollTop=o.scrollHeight})}},[e]);return s.useEffect(()=>{if(t(),e.current){const o=e.current.getElementsByTagName("img"),i=o[o.length-1];if(i&&!i.complete)return i.addEventListener("load",t),()=>i.removeEventListener("load",t)}},[r,t,e]),a.jsx("div",{ref:e,className:"h-full overflow-y-auto border border-gray-700 rounded-lg p-3 text-left","data-testid":"citadel-command-output",children:r.map((o,i)=>a.jsxs("div",{className:"mb-4 last:mb-0",children:[a.jsx(Ae,{command:o.command.join(" "),timestamp:new Date(o.timestamp).toLocaleTimeString(),status:o.result.status}),a.jsx("pre",{className:`text-gray-200 whitespace-pre font-mono ${n.outputFontSize}`,children:o.result.render()})]},i))})},oe={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},se=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],ae=["|","/","-","\\"],Ie=({style:r={type:"blink"},isValid:e=!0,errorMessage:n})=>{const t=s.useMemo(()=>({...oe[r.type],...r}),[r]),[o,i]=s.useState(!0),[l,m]=s.useState(0);s.useEffect(()=>{if(t.speed===0)return;const p=setInterval(()=>{t.type==="blink"?i(g=>!g):["spin","bbs"].includes(t.type)&&m(g=>(g+1)%(t.type==="bbs"?ae.length:se.length))},t.speed);return()=>clearInterval(p)},[t.type,t.speed]);const u=s.useMemo(()=>({color:e?t.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,t.color]),d=()=>!e&&n?"✗":["spin","bbs"].includes(t.type)?(t.type==="bbs"?ae:se)[l]:t.type==="solid"||o?t.character:" ";return a.jsx("div",{className:"relative inline-block",children:a.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:u,title:n,children:d()})})};function Pe(r,e){switch(e.type){case"set":return E.debug(`[inputStateReducer] InputState changing from ${r} to ${e.state}`),e.state;default:return r}}const He=()=>{const{state:r}=Y(),e=$(),n=te(),t=j(),[o,i]=s.useReducer(Pe,"idle"),l=c=>{i({type:"set",state:c})},m=s.useCallback(()=>{const h=e.getCompletions(t.path())[0]||t.nullSegment;return E.debug("[getNextExpectedSegment] ",h),h},[e,t]),u=s.useCallback(()=>e.getCompletions_s(t.path()).map(h=>e.getCommand([...t.path(),h])).filter(h=>h!==void 0),[e,t]),d=s.useCallback((c,h)=>{if(!c)return h;const f=h.reduce((y,v)=>{const k=m();return(k==null?void 0:k.type)==="word"&&y.set(k.name,v),y},new Map);return Array.from(f.values()).filter(()=>{const y=m();return y.type!=="word"?!1:y.name.toLowerCase().startsWith(c.toLowerCase())})},[m]),p=s.useCallback(c=>{const f=e.getCompletions(t.path()).filter(N=>N.type==="word").filter(N=>N.name.toLowerCase().startsWith(c.toLowerCase()));return f.length===1?f[0]:t.nullSegment},[e,t]),g=s.useCallback(c=>{const h=t.path(),f=e.getCompletions(h);return f.length===0&&c?!1:f.some(y=>y.type==="argument")?!0:f.some(y=>y.type==="word"&&y.name.toLowerCase().startsWith(c.toLowerCase()))},[e,t]),S=s.useCallback(c=>{E.debug("[tryAutoComplete] input: ",c);const h=p(c);return!h||h.name===c?new Z:(E.debug("[tryAutoComplete] result: ",h),h)},[p]),b=s.useCallback((c,h)=>{if(r.history.position===null){if(h.setCurrentInput(c),E.debug("[useCommandParser][handleInputChange] newValue: ",c),o==="entering_argument"){const f=ie(c);if(f.isQuoted)if(f.isComplete){const N=m();if(N.type==="argument"){const y=N;y.value=c.trim()||"",E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",y),t.push(y),h.setCurrentInput(""),l("idle");return}}else return;else if(f.isComplete){const N=m();N.value=c.trim()||"",E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",N),t.push(N),h.setCurrentInput(""),l("idle");return}else return}if(o=="entering_command"){const f=S(c);if(f.type==="word"){E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",f),t.push(f),h.setCurrentInput(""),l("idle");return}}}},[S,r,m,o,t]),C=s.useCallback(c=>{c.setCurrentInput(""),c.setIsEnteringArg(!1),t.clear(),l("idle")},[t]),_=s.useCallback((c,h,f)=>{if(!(c.key==="Backspace"||c.key==="Enter"||c.key==="ArrowUp"||c.key==="ArrowDown"||c.key==="ArrowLeft"||c.key==="ArrowRight"||c.key==="Escape"||c.key==="Delete"||c.key==="Home"||c.key==="End"||c.key.length===1))return!0;const{currentInput:y,isEnteringArg:v}=h,k=ie(y);switch(c.key){case"Backspace":return y===""&&(c.preventDefault(),t.size()>0&&t.pop(),l("idle")),!0;case"Enter":{if(c.preventDefault(),k.isQuoted&&!k.isComplete)return!0;if(o==="entering_argument"||v&&y.trim()){const B=m();B.value=y,E.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",B),t.push(B)}const z=t.path(),I=e.getCommand(z);if(!I)return!1;const K=I.segments.filter(T=>T.type==="argument"),q=t.arguments;return K.length>q.length?!1:(E.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",t),f.executeCommand(),n.addStoredCommand(t.toArray()),C(f),!0)}case"ArrowUp":return c.preventDefault(),(async()=>{const z=await n.navigateHistory("up",t.toArray());return z.segments&&(t.clear(),t.pushAll(z.segments),f.setCurrentInput("")),!0})();case"ArrowDown":return c.preventDefault(),(async()=>{const z=await n.navigateHistory("down",t.toArray());return z.segments&&(t.clear(),t.pushAll(z.segments),f.setCurrentInput("")),!0})();default:{if(!v&&c.key.length===1){const z=y+c.key;if(!g(z))return c.preventDefault(),!1}return!0}}},[o,g,m,n,C,e,t]);return{handleInputChange:b,handleKeyDown:_,inputState:o,setInputStateWithLogging:l,findMatchingCommands:d,getAutocompleteSuggestion:p,getAvailableNodes:u,getNextExpectedSegment:m,isValidCommandInput:g}};function ie(r){const e=[];let n="",t=!1,o;for(let i=0;i<r.length;i++){const l=r[i];(l==='"'||l==="'")&&(!t||l===o)?t?(e.push(n),n="",t=!1,o=void 0):(n&&(e.push(n),n=""),t=!0,o=l):!t&&l===" "?n&&(e.push(n),n=""):n+=l}return{words:e,currentWord:n,isQuoted:t,quoteChar:o,isComplete:!t&&!n}}const De=()=>{const r=j(),[e,n]=s.useState(0);return s.useEffect(()=>{const t={update:()=>{n(o=>o+1)}};return r.subscribe(t),()=>{r.unsubscribe(t)}},[r]),e},Me=({state:r,actions:e})=>{const n=s.useRef(null),t=$(),o=j(),{handleKeyDown:i,handleInputChange:l,inputState:m,setInputStateWithLogging:u,getNextExpectedSegment:d}=He(),[p,g]=s.useState(!1),S=M(),b=De(),C=async v=>{const k=i(v,r,e);await Promise.resolve(k)===!1&&(g(!0),setTimeout(()=>g(!1),500))},_=v=>{l(v.target.value,e)},c=v=>{v.preventDefault();const k=v.clipboardData.getData("text");l(k,e)};s.useEffect(()=>{n.current&&n.current.focus(),m!=="entering_command"&&u("entering_command")},[m,u]),s.useEffect(()=>{if(m!=="idle")return;const v=d();let k="idle";switch(v.type){case"word":k="entering_command",e.setIsEnteringArg(!1);break;case"argument":k="entering_argument",e.setIsEnteringArg(!0);break}u(k)},[b,m,d,u,e]);const[h,f]=s.useState([]);s.useEffect(()=>{const v=[],k=o.toArray().map((I,K)=>{v.push(I.name);const q=t.hasNextSegment(v);if(I.type==="argument"){const T=I;return a.jsxs(s.Fragment,{children:[a.jsx("span",{className:"text-gray-200 whitespace-pre",children:T.value}),K<o.size()&&q&&a.jsx("span",{className:"text-gray-200 whitespace-pre",children:" "})]},"arg-"+T.name+T.value)}return a.jsxs(s.Fragment,{children:[a.jsx("span",{className:"text-blue-400 whitespace-pre",children:I.name}),K<o.size()&&q&&a.jsx("span",{className:"text-blue-400 whitespace-pre",children:" "})]},"word-"+I.name)});f([a.jsx("div",{className:"flex items-center gap-1","data-testid":"user-input-area",children:k},"{segmentStackVersion}")])},[b,t,o]);const[N,y]=s.useState("");return s.useEffect(()=>{const v=d();v.type==="argument"?y(v.name):y("")},[b,d]),a.jsxs("div",{className:"flex flex-col w-full bg-gray-900 rounded-lg p-4",children:[a.jsx("style",{children:`
7
7
  @keyframes subtleGlow {
8
8
  0%, 100% { box-shadow: 0 0 0 rgba(239, 68, 68, 0); }
9
9
  50% { box-shadow: 0 0 8px rgba(239, 68, 68, 0.6); }
@@ -11,7 +11,7 @@ Check the definition of the ${p.join(".")} command and update the return type fo
11
11
  .invalid-input-animation {
12
12
  animation: subtleGlow 0.4s ease-in-out;
13
13
  }
14
- `}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:"text-gray-400 font-mono",children:">"}),i.jsxs("div",{className:"flex-1 font-mono flex items-center",children:[h,i.jsxs("div",{className:"relative flex-1",children:[i.jsx("input",{ref:n,type:"text",role:"textbox",value:r.currentInput,onChange:_,onKeyDown:A,onPaste:l,"data-testid":"citadel-command-input",className:`w-full bg-transparent outline-none text-gray-200 caret-transparent ${p?"invalid-input-animation":""}`,spellCheck:!1,autoComplete:"off",placeholder:E}),i.jsx("div",{className:"absolute top-0 pointer-events-none",style:{left:`${r.currentInput.length}ch`,transition:"left 0.05s ease-out"},children:i.jsx(Ee,{style:{type:k.cursorType??N.cursorType,color:k.cursorColor||N.cursorColor,speed:k.cursorSpeed||N.cursorSpeed}})})]})]})]})]})},Ie=()=>i.jsx("div",{"data-testid":"spinner",className:"animate-spin rounded-full h-4 w-4 border-2 border-gray-300 border-t-gray-600"}),Pe=({command:r,timestamp:e,status:n})=>i.jsxs("div",{className:"flex items-center gap-2 font-mono text-sm",children:[i.jsxs("span",{className:"text-gray-200",children:["> ",r.split(" ").map((t,o)=>{const a=t.startsWith("<")&&t.endsWith(">");return i.jsxs("span",{className:a?"text-green-400":"text-gray-200",children:[o>0?" ":"",t]},o)})]}),i.jsx("span",{className:"text-gray-400",children:"·"}),i.jsx("span",{className:"text-gray-500",children:e}),n===T.Pending&&i.jsx(Ie,{}),n===T.Success&&i.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-green-500"}),(n===T.Timeout||n===T.Failure)&&i.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-red-500"})]}),He=({output:r,outputRef:e})=>{const n=F(),t=s.useCallback(()=>{if(e.current){const o=e.current;requestAnimationFrame(()=>{o.scrollTop=o.scrollHeight})}},[e]);return s.useEffect(()=>{if(t(),e.current){const o=e.current.getElementsByTagName("img"),a=o[o.length-1];if(a&&!a.complete)return a.addEventListener("load",t),()=>a.removeEventListener("load",t)}},[r,t,e]),i.jsx("div",{ref:e,className:"h-full overflow-y-auto border border-gray-700 rounded-lg p-3 text-left",children:r.map((o,a)=>i.jsxs("div",{className:"mb-4 last:mb-0",children:[i.jsx(Pe,{command:o.command.join(" "),timestamp:new Date(o.timestamp).toLocaleTimeString(),status:o.result.status}),i.jsx("pre",{className:`text-gray-200 whitespace-pre font-mono ${n.outputFontSize}`,children:o.result.render()})]},a))})},De=()=>{const r=q(),e=F(),n=j(),t="h-12 mt-2 border-t border-gray-700 px-4",o="text-gray-300 pt-2",a=r.getCompletions(n.path());S.debug("[AvailableCommands] nextCommandSegments: ",a);const c=s.useMemo(()=>{if(e.includeHelpCommand){const d=a.filter(g=>g.name!=="help"),p=a.find(g=>g.name==="help");return[...d,...p?[p]:[]]}return a},[a,e.includeHelpCommand]),m=a.some(d=>d.type==="argument"),u=a[0];return i.jsx("div",{className:t,"data-testid":"available-commands",children:i.jsx("div",{className:o,children:m?a.length>0?i.jsxs(i.Fragment,{children:[i.jsx("span",{className:"text-blue-400",children:u.name}),u.description&&i.jsxs("span",{className:"text-gray-400 ml-2",children:["- ",u.description]})]}):null:i.jsx("div",{className:"flex flex-wrap gap-2",children:c==null?void 0:c.map(d=>{const p=c==null?void 0:c.reduce((g,k)=>{if(k===d)return g;let x=0;for(;x<d.name.length&&x<k.name.length&&d.name[x].toLowerCase()===k.name[x].toLowerCase();)x++;return Math.max(g,x+1)},1);return i.jsx("div",{className:"px-2 py-1 rounded bg-gray-800 mr-2 last:mr-0",children:i.jsxs("span",{className:"font-mono text-white",children:[i.jsx("strong",{className:"underline",children:d.name.slice(0,p)}),d.name.slice(p)]})},d.name)})})})})},ie=`:host {
14
+ `}),a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("div",{className:"text-gray-400 font-mono",children:">"}),a.jsxs("div",{className:"flex-1 font-mono flex items-center",children:[h,a.jsxs("div",{className:"relative flex-1",children:[a.jsx("input",{ref:n,type:"text",role:"textbox",value:r.currentInput,onChange:_,onKeyDown:C,onPaste:c,"data-testid":"citadel-command-input",className:`w-full bg-transparent outline-none text-gray-200 caret-transparent ${p?"invalid-input-animation":""}`,spellCheck:!1,autoComplete:"off",placeholder:N}),a.jsx("div",{className:"absolute top-0 pointer-events-none",style:{left:`${r.currentInput.length}ch`,transition:"left 0.05s ease-out"},children:a.jsx(Ie,{style:{type:S.cursorType??A.cursorType,color:S.cursorColor||A.cursorColor,speed:S.cursorSpeed||A.cursorSpeed}})})]})]})]})]})},Te=()=>{const r=$(),e=M(),n=j(),t="mt-2 border-t border-gray-700 px-4 py-2",o="text-gray-300",i=r.getCompletions(n.path());E.debug("[AvailableCommands] nextCommandSegments: ",i);const l=s.useMemo(()=>{const d=[...i],p=C=>C.name.toLowerCase()==="help",S=d.filter(C=>!p(C)).sort((C,_)=>C.name.localeCompare(_.name,void 0,{sensitivity:"base"}));if(!e.includeHelpCommand)return S;const b=d.find(p);return b?[...S,b]:S},[i,e.includeHelpCommand]),m=i.some(d=>d.type==="argument"),u=i[0];return a.jsx("div",{className:t,"data-testid":"available-commands",children:a.jsx("div",{className:o,children:m?i.length>0?a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"text-blue-400",children:u.name}),u.description&&a.jsxs("span",{className:"text-gray-400 ml-2",children:["- ",u.description]})]}):null:a.jsx("div",{className:"flex flex-wrap gap-2",children:l==null?void 0:l.map(d=>{const p=l==null?void 0:l.reduce((g,S)=>{if(S===d)return g;let b=0;for(;b<d.name.length&&b<S.name.length&&d.name[b].toLowerCase()===S.name[b].toLowerCase();)b++;return Math.max(g,b+1)},1);return a.jsx("div",{className:"px-2 py-1 rounded bg-gray-800 mr-2 last:mr-0",children:a.jsxs("span",{className:"font-mono text-white",children:[a.jsx("strong",{className:"underline",children:d.name.slice(0,p)}),d.name.slice(p)]})},d.name)})})})})},le=({state:r,actions:e,outputRef:n})=>a.jsxs("div",{className:"innerContainer",children:[a.jsx("div",{className:"flex-1 min-h-0 pt-3 px-4",children:a.jsx(ze,{output:r.output,outputRef:n})}),a.jsxs("div",{children:[a.jsx(Me,{state:r,actions:e}),a.jsx(Te,{})]})]}),Ue=()=>{const[r,e]=s.useState(!1),[n,t]=s.useState(!1),o=M(),[i,l]=s.useState(()=>o.initialHeight||null),m=s.useRef(null),u=s.useRef(null),d=s.useRef(!1),p=s.useRef(0),g=s.useRef(0),{state:S,actions:b}=Y();Ee({onOpen:()=>e(!0),onClose:()=>t(!0),isVisible:r,showCitadelKey:o.showCitadelKey||"."});const C=s.useCallback(f=>{var k;if(!d.current)return;const N=f.clientY-p.current,y=(k=o.maxHeight)!=null&&k.endsWith("vh")?window.innerHeight*parseInt(o.maxHeight,10)/100:parseInt(o.maxHeight||"80vh",10),v=Math.min(Math.max(g.current-N,parseInt(o.minHeight||"200",10)),y);u.current&&(u.current.style.height=`${v}px`,u.current.style.bottom="0",l(`${v}px`))},[o.maxHeight,o.minHeight]),_=s.useCallback(()=>{d.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",C),document.removeEventListener("mouseup",_)},[C]),c=s.useCallback(f=>{u.current&&(d.current=!0,p.current=f.clientY,g.current=u.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",C),document.addEventListener("mouseup",_))},[C,_]);s.useEffect(()=>()=>{document.removeEventListener("mousemove",C),document.removeEventListener("mouseup",_)},[C,_]);const h=s.useCallback(()=>{n&&(e(!1),t(!1))},[n]);return _e({isVisible:r,isClosing:n,onAnimationComplete:h}),r?a.jsxs("div",{ref:u,className:`panelContainer ${r?"citadel_slideUp":""} ${n?"citadel_slideDown":""}`,style:{...i?{height:i}:void 0,maxHeight:o.maxHeight},children:[a.jsx("div",{className:"resizeHandle",onMouseDown:c}),a.jsx(le,{state:S,actions:b,outputRef:m})]}):null},je=()=>{const{state:r,actions:e}=Y(),n=s.useRef(null);return a.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",children:a.jsx(le,{state:r,actions:e,outputRef:n})})},ce=`:host {
15
15
  --citadel-bg: rgb(17, 24, 39);
16
16
  --citadel-text: rgba(255, 255, 255, 0.87);
17
17
  --citadel-border: rgb(55, 65, 81);
@@ -22,23 +22,38 @@ Check the definition of the ${p.join(".")} command and update the return type fo
22
22
  --citadel-default-height: 35vh;
23
23
  --citadel-error: rgb(239, 68, 68);
24
24
 
25
- height: var(--citadel-default-height);
26
- max-height: var(--citadel-max-height);
27
- min-height: var(--citadel-min-height);
28
- width: 100%;
25
+ display: block;
26
+ pointer-events: auto;
27
+ font-synthesis: none;
28
+ text-rendering: optimizeLegibility;
29
+ -webkit-font-smoothing: antialiased;
30
+ -moz-osx-font-smoothing: grayscale;
31
+ }
29
32
 
33
+ :host([data-display-mode="panel"]) {
30
34
  position: fixed;
31
35
  bottom: 0;
32
36
  left: 0;
33
37
  right: 0;
38
+ width: 100%;
39
+ height: var(--citadel-default-height);
40
+ max-height: var(--citadel-max-height);
41
+ min-height: var(--citadel-min-height);
34
42
  z-index: 2147483647; /* Maximum z-index value */
35
43
  overflow: hidden;
44
+ }
36
45
 
37
- pointer-events: auto;
38
- font-synthesis: none;
39
- text-rendering: optimizeLegibility;
40
- -webkit-font-smoothing: antialiased;
41
- -moz-osx-font-smoothing: grayscale;
46
+ :host([data-display-mode="inline"]) {
47
+ position: relative;
48
+ bottom: auto;
49
+ left: auto;
50
+ right: auto;
51
+ z-index: auto;
52
+ width: 100%;
53
+ height: 100%;
54
+ max-height: none;
55
+ min-height: 0;
56
+ overflow: hidden;
42
57
  }
43
58
 
44
59
  button {
@@ -100,10 +115,9 @@ a:hover {
100
115
  .text-left {
101
116
  text-align: left;
102
117
  }
118
+ `,de=`/* Keep only component-specific styles here */
103
119
 
104
- `,le=`/* Keep only component-specific styles here */
105
-
106
- .container {
120
+ .panelContainer {
107
121
  position: fixed;
108
122
  height: var(--citadel-default-height);
109
123
  min-height: var(--citadel-min-height);
@@ -121,6 +135,7 @@ a:hover {
121
135
 
122
136
  .innerContainer {
123
137
  height: 100%;
138
+ flex: 1;
124
139
  width: 100%;
125
140
  display: flex;
126
141
  flex-direction: column;
@@ -171,10 +186,21 @@ a:hover {
171
186
  .citadel_slideDown {
172
187
  animation: citadel_slideDown 0.2s ease-out forwards;
173
188
  }
174
- `,ce=`@tailwind base;
189
+
190
+ .inlineContainer {
191
+ position: relative;
192
+ width: 100%;
193
+ height: 100%;
194
+ display: flex;
195
+ flex-direction: column;
196
+ background-color: var(--citadel-bg);
197
+ overflow: hidden;
198
+ box-sizing: border-box;
199
+ }
200
+ `,me=`@tailwind base;
175
201
  @tailwind components;
176
202
  @tailwind utilities;
177
- `,Te=`*, ::before, ::after {
203
+ `,Fe=`*, ::before, ::after {
178
204
  --tw-border-spacing-x: 0;
179
205
  --tw-border-spacing-y: 0;
180
206
  --tw-translate-x: 0;
@@ -991,5 +1017,5 @@ video {
991
1017
  .last\\:mr-0:last-child {
992
1018
  margin-right: 0px;
993
1019
  }
994
- `,Ue=({config:r=N,commandRegistry:e=new L,containerId:n=null})=>(s.useEffect(()=>{S.configure({level:r.logLevel||N.logLevel||$.ERROR,prefix:"[Citadel]"});const t=new de(e,r),o=n?document.getElementById(n):document.body;return o?o.appendChild(t):(console.warn(`Container with id "${n}" not found, falling back to body`),document.body.appendChild(t)),()=>{var a;(a=t.parentElement)==null||a.removeChild(t)}},[e,n,r]),null);class de extends HTMLElement{constructor(n,t){super();y(this,"shadow");y(this,"root",null);y(this,"commandRegistry");y(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=n,this.config=t}connectedCallback(){try{const t=[ie,le,ce,Te].map(o=>{const a=new CSSStyleSheet;return a.replaceSync(o),a});this.shadow.adoptedStyleSheets=[...t]}catch{const t=[ie,le,ce].join(`
995
- `),o=document.createElement("style");o.textContent=t,this.shadow.appendChild(o)}const n=document.createElement("div");n.id="citadel-root",this.shadow.appendChild(n),this.root=me.createRoot(n),this.root.render(i.jsx(Se,{config:this.config||N,commandRegistry:this.commandRegistry,children:i.jsx(Fe,{})}))}}customElements.define("citadel-element",de);const Fe=()=>{const[r,e]=s.useState(!1),[n,t]=s.useState(!1),o=F(),[a,c]=s.useState(()=>o.initialHeight||null),m=s.useRef(null),u=s.useRef(null),d=s.useRef(!1),p=s.useRef(0),g=s.useRef(0),{state:k,actions:x}=te();ue({onOpen:()=>e(!0),onClose:()=>t(!0),isVisible:r,showCitadelKey:o.showCitadelKey||"."});const A=s.useCallback(f=>{u.current&&(d.current=!0,p.current=f.clientY,g.current=u.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",_),document.addEventListener("mouseup",l))},[]),_=s.useCallback(f=>{var v;if(!d.current)return;const E=f.clientY-p.current,b=(v=o.maxHeight)!=null&&v.endsWith("vh")?window.innerHeight*parseInt(o.maxHeight,10)/100:parseInt(o.maxHeight||"80vh",10),C=Math.min(Math.max(g.current-E,parseInt(o.minHeight||"200",10)),b);u.current&&(u.current.style.height=`${C}px`,u.current.style.bottom="0",c(`${C}px`))},[o.maxHeight,o.minHeight]),l=s.useCallback(()=>{d.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",_),document.removeEventListener("mouseup",l)},[_]);s.useEffect(()=>()=>{document.removeEventListener("mousemove",_),document.removeEventListener("mouseup",l)},[_,l]);const h=s.useCallback(()=>{n&&(e(!1),t(!1))},[n]);return pe({isVisible:r,isClosing:n,onAnimationComplete:h}),r?i.jsxs("div",{ref:u,className:`container ${r?"citadel_slideUp":""} ${n?"citadel_slideDown":""}`,style:{...a?{height:a}:void 0,maxHeight:o.maxHeight},children:[i.jsx("div",{className:"resizeHandle",onMouseDown:A}),i.jsxs("div",{className:"innerContainer",children:[i.jsx("div",{className:"flex-1 min-h-0 pt-3 px-4",children:i.jsx(He,{output:k.output,outputRef:m})}),i.jsxs("div",{children:[i.jsx(ze,{state:k,actions:x}),i.jsx(De,{})]})]})]}):null};w.Citadel=Ue,w.CommandRegistry=L,w.CommandResult=H,w.CommandStatus=T,w.DEFAULT_CURSOR_CONFIGS=re,w.ErrorCommandResult=B,w.ImageCommandResult=he,w.JsonCommandResult=ge,w.OutputItem=ee,w.PendingCommandResult=G,w.TextCommandResult=V,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
1020
+ `,Oe=({config:r=A,commandRegistry:e=new L,containerId:n=null})=>{const t=s.useRef(null),o=r.displayMode??A.displayMode??"panel";return s.useEffect(()=>{E.configure({level:r.logLevel||A.logLevel||F.ERROR,prefix:"[Citadel]"});const i=new ue(e,r),l=o==="inline"&&!n,m=l?t.current:n?document.getElementById(n):document.body;if(m)m.appendChild(i);else{if(l){console.warn("[Citadel] No host available for inline mode; skipping mount.");return}console.warn(`Container with id "${n}" not found, falling back to body`),document.body.appendChild(i)}return()=>{var u;(u=i.parentElement)==null||u.removeChild(i)}},[e,n,r,o]),o==="inline"&&!n?a.jsx("div",{ref:t,style:{width:"100%",height:"100%"}}):null};class ue extends HTMLElement{constructor(n,t){var i;super();x(this,"shadow");x(this,"root",null);x(this,"commandRegistry");x(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=n,this.config=t;const o=((i=this.config)==null?void 0:i.displayMode)??"panel";this.setAttribute("data-display-mode",o)}connectedCallback(){try{const t=[ce,de,me,Fe].map(o=>{const i=new CSSStyleSheet;return i.replaceSync(o),i});this.shadow.adoptedStyleSheets=[...t]}catch{const t=[ce,de,me].join(`
1021
+ `),o=document.createElement("style");o.textContent=t,this.shadow.appendChild(o)}const n=document.createElement("div");n.id="citadel-root",n.style.width="100%",n.style.height="100%",this.shadow.appendChild(n),this.root=pe.createRoot(n),this.root.render(a.jsx(Se,{config:this.config||A,commandRegistry:this.commandRegistry,children:a.jsx(Le,{})}))}}customElements.define("citadel-element",ue);const Le=()=>(M().displayMode??"panel")==="inline"?a.jsx(je,{}):a.jsx(Ue,{});w.Citadel=Oe,w.CommandRegistry=L,w.CommandResult=P,w.CommandStatus=D,w.DEFAULT_CURSOR_CONFIGS=oe,w.ErrorCommandResult=G,w.ImageCommandResult=ge,w.JsonCommandResult=he,w.OutputItem=ne,w.PendingCommandResult=J,w.TextCommandResult=V,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
@@ -1,10 +1,22 @@
1
+ import { default as React } from 'react';
1
2
  import { CitadelConfig } from './config/types';
2
3
  import { CommandRegistry } from './types/command-registry';
3
- export declare const Citadel: ({ config, commandRegistry, containerId }: {
4
- config?: CitadelConfig | undefined;
5
- commandRegistry?: CommandRegistry | undefined;
6
- containerId?: null | undefined;
7
- }) => null;
4
+ interface CitadelProps {
5
+ config?: CitadelConfig;
6
+ commandRegistry?: CommandRegistry;
7
+ containerId?: string | null;
8
+ }
9
+ /**
10
+ * Top-level entry point for embedding Citadel.
11
+ *
12
+ * @param config Optional `CitadelConfig` describing runtime behaviour (keyboard shortcuts, logging, sizing)
13
+ * with `defaultConfig` used when omitted.
14
+ * @param commandRegistry Optional pre-populated registry. A fresh instance is created by default so consumers
15
+ * can register commands before mounting.
16
+ * @param containerId Optional DOM id where the custom element should be appended. When not supplied the
17
+ * component appends to `document.body` in panel mode and to an internal host in inline mode.
18
+ */
19
+ export declare const Citadel: React.FC<CitadelProps>;
8
20
  export declare class CitadelElement extends HTMLElement {
9
21
  private shadow;
10
22
  private root;
@@ -13,3 +25,4 @@ export declare class CitadelElement extends HTMLElement {
13
25
  constructor(commandRegistry: CommandRegistry, config?: CitadelConfig);
14
26
  connectedCallback(): void;
15
27
  }
28
+ export {};
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ import { CitadelState, CitadelActions } from '../types/state';
3
+ interface CitadelTtyProps {
4
+ state: CitadelState;
5
+ actions: CitadelActions;
6
+ outputRef: React.RefObject<HTMLDivElement>;
7
+ }
8
+ export declare const CitadelTty: React.FC<CitadelTtyProps>;
9
+ export {};
@@ -61,6 +61,12 @@ export interface CitadelConfig {
61
61
  * The keyboard key that shows the command interface.
62
62
  */
63
63
  showCitadelKey?: string;
64
+ /**
65
+ * Presentation mode for rendering the Citadel interface.
66
+ * - 'panel': Renders as an overlay panel anchored to the viewport bottom and toggled via keyboard shortcuts.
67
+ * - 'inline': Renders directly within the host container and remains visible at all times.
68
+ */
69
+ displayMode?: 'panel' | 'inline';
64
70
  /**
65
71
  * Configuration for command history storage
66
72
  */
@@ -0,0 +1,2 @@
1
+ import { default as React } from 'react';
2
+ export declare const InlineController: React.FC;
@@ -0,0 +1,2 @@
1
+ import { default as React } from 'react';
2
+ export declare const PanelController: React.FC;
@@ -55,13 +55,24 @@ export declare class CommandRegistry {
55
55
  private _commands;
56
56
  get commands(): CommandNode[];
57
57
  /**
58
- * Registers a new command
58
+ * Registers a new command composed of ordered segments.
59
59
  *
60
- * @param newCommandNode The new command to add
61
- * @throws {Error} If attempting to add a duplicate leaf command or a subcommand to a leaf
60
+ * Each segment describes either a literal word or an argument placeholder. The resulting
61
+ * path must be unique across the registry once argument placeholders are normalized.
62
62
  *
63
+ * @param segments Ordered command path definition.
64
+ * @param description Human-readable summary surfaced by help and search results.
65
+ * @param handler Async handler executed when the command is submitted; defaults to `NoopHandler`.
66
+ * @throws {Error} If the segment list is empty or the path collides with an existing command.
63
67
  */
64
68
  addCommand(segments: CommandSegment[], description: string, handler?: CommandHandler): void;
69
+ /**
70
+ * Removes a command that exactly matches the provided path.
71
+ *
72
+ * @param path The command path to remove.
73
+ * @returns True if a command was removed; otherwise false.
74
+ */
75
+ removeCommand(path: string[]): boolean;
65
76
  /**
66
77
  * Retrieves a command from the registry for the given path.
67
78
  *
@@ -0,0 +1,6 @@
1
+ import { CommandRegistry } from '../components/Citadel/types/command-registry';
2
+ /**
3
+ * Build a fresh registry populated with the basic sample commands.
4
+ * Used by the demo app and example bundles.
5
+ */
6
+ export declare function createBasicCommandRegistry(): CommandRegistry;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/jchilders/citadel_cli.git"
19
19
  },
20
- "version": "1.1.4",
20
+ "version": "1.1.6",
21
21
  "type": "module",
22
22
  "scripts": {
23
23
  "build": "tsc && vite build",
@@ -27,7 +27,10 @@
27
27
  "preview": "vite preview",
28
28
  "push": "NODE_ENV=production && npm run build && npm push",
29
29
  "test": "vitest --run",
30
- "coverage": "vitest run --coverage"
30
+ "test:e2e": "playwright test",
31
+ "test:e2e:ui": "playwright test --ui",
32
+ "coverage": "vitest run --coverage",
33
+ "postinstall": "playwright install"
31
34
  },
32
35
  "exports": {
33
36
  ".": {
@@ -54,6 +57,7 @@
54
57
  },
55
58
  "devDependencies": {
56
59
  "@eslint/js": "^9.13.0",
60
+ "@playwright/test": "^1.56.0",
57
61
  "@testing-library/jest-dom": "^6.6.3",
58
62
  "@testing-library/react": "^16.1.0",
59
63
  "@testing-library/user-event": "^14.5.2",