citadel_cli 1.1.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
- (function(y,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):(y=typeof globalThis<"u"?globalThis:y||self,a(y.Citadel={},y.jsxRuntime,y.React,y.client))})(this,function(y,a,s,ge){"use strict";var Ke=Object.defineProperty;var qe=(y,a,s)=>a in y?Ke(y,a,{enumerable:!0,configurable:!0,writable:!0,value:s}):y[a]=s;var x=(y,a,s)=>qe(y,typeof a!="symbol"?a+"":a,s);var H=(r=>(r.Pending="pending",r.Success="success",r.Failure="failure",r.Timeout="timeout",r))(H||{});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 fe 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 O 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 J 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 Q extends P{render(){return a.jsx("div",{className:"text-gray-400",children:"..."})}}class we 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 be=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.length===0?new O("No commands available yet. Add some commands to get started!"):(e.push("help - Show available commands"),new O(`Available Commands:
2
- `+e.join(`
3
- `)))};var Y=(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))(Y||{});const X=!0;class S{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!X&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!X&&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(S,"level",0),x(S,"prefix","");const N={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,initialHeight:"40vh",logLevel:Y.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,showCitadelKey:".",displayMode:"panel",storage:{type:"localStorage",maxCommands:100}};class Z{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 ye extends Z{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 R extends Z{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 z=class z{constructor(){x(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 R(e):this.currentStorage=new ye(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new R(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};x(z,"instance");let L=z;const ee=async()=>new O("");class B{constructor(e,n,t){this.type=e,this.name=n,this.description=t}toString(){return this.name}}class ne extends B{constructor(){super("null",">null<","Empty segment")}}class xe extends B{constructor(e,n){super("word",e,n)}}class $ extends B{constructor(e,n,t,o){super("argument",e,n),this.value=t,this.valid=o}}class Ce{constructor(e,n,t=ee){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 K{constructor(){x(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,t=ee){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const o=new Ce(e,n,t),l=this._commands.find(d=>{const m=d.segments.map(c=>c.type==="argument"?"*":c.name).join(" "),i=e.map(c=>c.type==="argument"?"*":c.name).join(" ");return m===i});if(l)throw new Error(`Duplicate commands: '${l.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 d=n.segments.filter(m=>m.type==="word").map(m=>m.name);return d.length===e.length&&d.join(" ")===o})}commandExistsForPath(e){const n=this._commands.map(o=>o.segments.map(l=>l.type==="argument"?"*":l.name).join(" ")),t=e.map((o,l)=>this._commands.some(m=>{var i;return((i=m.segments[l])==null?void 0:i.type)==="argument"})?"*":o).join(" ");return n.includes(t)}getCompletionNames(e){return this.getCompletions(e).map(n=>n.name)}getCompletions(e){if(S.debug("[getCompletions] path: ",e),!e.length){const l=this._commands.map(i=>i.segments[0]),d=(i,c)=>i.type===c.type&&i.name===c.name;return l.filter((i,c,p)=>c===p.findIndex(g=>d(g,i)))}const n=e.length;return this._commands.filter(l=>{const d=l.segments;if(d.length<=n-1)return!1;for(let m=0;m<n;m++){const i=e[m],c=d[m];if(!(i==="*"&&c.type==="argument")&&i!==c.name)return!1}return!0}).filter(l=>l.segments.length>n).map(l=>{const d=l.segments[n],m=d.type==="argument"?$:xe;return new m(d.name,d.description)}).filter((l,d,m)=>d===m.findIndex(i=>i.type===l.type&&i.name===l.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class te{constructor(){x(this,"segments",[]);x(this,"nullSegment",new ne);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:N,commands:new K,segmentStack:new te},D=s.createContext(ve),Se=({config:r=N,commandRegistry:e,children:n})=>{const[t,o]=s.useState(),[l]=s.useState(()=>new te),d={...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(()=>{L.getInstance().initializeStorage(d.storage??N.storage),o(L.getInstance().getStorage())},[]),s.useEffect(()=>{if(e){if(d.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const i=be(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",i)}return}e.removeCommand(["help"])}},[e,d.includeHelpCommand]);const m=s.useMemo(()=>({config:d,commands:e||new K,storage:t,segmentStack:l}),[d,e,t,l]);return a.jsx(D.Provider,{value:m,children:n})},T=()=>{const r=s.useContext(D);if(r===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return r.config},q=()=>{const r=s.useContext(D);if(r===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return r.commands},re=()=>{const r=s.useContext(D);if(r===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return r.storage},U=()=>{const r=s.useContext(D);if(r===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return r.segmentStack},V=class V{constructor(e,n){x(this,"id");x(this,"timestamp");x(this,"command");x(this,"result");this.id=`output-${Date.now()}-${V.idCounter++}`,this.command=e.toArray().map(t=>t.type==="argument"?t.value||"":t.name),this.timestamp=Date.now(),this.result=n??new Q}};x(V,"idCounter",0);let W=V;function ke(r){return{commandSegments:r,timestamp:Date.now()}}function oe(){const r=re(),[e,n]=s.useState({storedCommands:[],position:null}),t=s.useCallback(async m=>{if(r)try{const i=ke(m);await r.addStoredCommand(i),n(c=>({...c,storedCommands:[...c.storedCommands,i],position:null}))}catch(i){console.warn("Failed to save command to history:",i)}},[r]),o=s.useCallback(async()=>r?await r.getStoredCommands():[],[r]);s.useEffect(()=>{if(!r)return;(async()=>{try{const i=await r.getStoredCommands();return n(c=>({...c,storedCommands:i})),i}catch(i){console.warn("Failed to load command history:",i)}})()},[r]);const l=s.useCallback(async m=>{const i=await o();if(i.length===0)return n(g=>({...g,storedCommands:[],position:null})),{segments:null,position:null};let c=null;if(m==="up"?e.position===null?c=i.length-1:e.position>0?c=e.position-1:c=0:e.position===null||e.position>=i.length-1?c=null:c=e.position+1,n(g=>({...g,storedCommands:i,position:c})),c===null)return{segments:[],position:null};const p=i[c];return p?{segments:p.commandSegments,position:c}:{segments:[],position:null}},[e.position,o]),d=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:l,clear:d}}const G=()=>{const r=T(),e=q(),n=oe(),t=U(),o=re(),[l,d]=s.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:o}});s.useEffect(()=>{},[o]),s.useEffect(()=>{d(i=>({...i,history:{commands:n.history.storedCommands,position:n.history.position,storage:o}}))},[n.history,o]);const m={setCurrentInput:s.useCallback(i=>{S.debug("[CitadelActions] setCurrentInput: ",i),d(c=>({...c,currentInput:i}))},[]),setIsEnteringArg:s.useCallback(i=>{S.debug("[CitadelActions] setIsEnteringArg: ",i),d(c=>({...c,isEnteringArg:i}))},[]),addOutput:s.useCallback(i=>{S.debug("[CitadelActions]addOutput: ",i),d(c=>({...c,output:[...c.output,i]}))},[]),executeCommand:s.useCallback(async()=>{const i=t.path(),c=e.getCommand(i);if(!c){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",i);return}const p=new W(t);d(g=>({...g,output:[...g.output,p]}));try{const g=new Promise((h,E)=>{setTimeout(()=>{E(new Error("Request timed out"))},r.commandTimeoutMs)}),k=t.arguments.map(h=>h.value||""),v=await Promise.race([c.handler(k),g]);if(!(v instanceof P))throw new Error(`The ${i.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,s,Ne){"use strict";var dn=Object.defineProperty;var mn=(g,c,s)=>c in g?dn(g,c,{enumerable:!0,configurable:!0,writable:!0,value:s}):g[c]=s;var C=(g,c,s)=>mn(g,typeof c!="symbol"?c+"":c,s);var U=(t=>(t.Pending="pending",t.Success="success",t.Failure="failure",t.Timeout="timeout",t))(U||{});class D{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 te extends D{constructor(e,n){super(n),this.data=e}render(){return c.jsx("pre",{className:"text-gray-200",children:JSON.stringify(this.data,null,2)})}}class L extends D{constructor(e,n){super(n),this.text=e}render(){return c.jsx("div",{className:"text-gray-200 whitespace-pre",children:this.text})}}class J extends D{constructor(e,n){super(n),this.error=e,this.markFailure()}render(){return c.jsx("div",{className:"mt-1 text-red-400",children:this.error})}}class re extends D{render(){return c.jsx("div",{className:"text-gray-400",children:"..."})}}class oe extends D{constructor(e,n="",r){super(r),this.imageUrl=e,this.altText=n}render(){return c.jsx("div",{className:"my-2",children:c.jsx("img",{src:this.imageUrl,alt:this.altText,className:"max-w-[400px] max-h-[300px] h-auto rounded-lg object-contain"})})}}const ze=t=>async function(){const n=t.commands.filter(r=>r.fullPath[0]!=="help").map(r=>{const a=`${r.segments.map(d=>d.type==="argument"?`<${d.name}>`:d.name).join(" ")} - ${r.description}`,l=r.segments.filter(d=>d.type==="argument"&&d.description).map(d=>` <${d.name}>: ${d.description}`);return{commandLine:a,argumentLines:l}}).sort((r,o)=>r.commandLine.localeCompare(o.commandLine)).flatMap(r=>[r.commandLine,...r.argumentLines]);return n.length===0?new L("No commands available yet. Add some commands to get started!"):(n.push("help - Show available commands"),new L(`Available Commands:
2
+ `+n.join(`
3
+ `)))};var X=(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))(X||{});const se=!0;class E{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!se&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!se&&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(E,"level",0),C(E,"prefix","");const N={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"40vh",logLevel:X.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,showCitadelKey:".",displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},ae=async()=>new L("");class Q{constructor(e,n,r){this.type=e,this.name=n,this.description=r}toString(){return this.name}}class Z extends Q{constructor(){super("null",">null<","Empty segment")}}class ie extends Q{constructor(e,n){super("word",e,n)}}class j extends Q{constructor(e,n,r,o){super("argument",e,n),this.value=r,this.valid=o}}const _e=t=>{if(t.type==="word")return new ie(t.name,t.description);if(t.type==="argument"){const e=t;return new j(e.name,e.description,e.value,e.valid)}return new Z},A=t=>t.map(e=>_e(e));class Ae{constructor(e,n,r=ae){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=n,this._handler=r}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 O{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,r=ae){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const o=new Ae(e,n,r),a=this._commands.find(l=>{const d=l.segments.map(m=>m.type==="argument"?"*":m.name).join(" "),i=e.map(m=>m.type==="argument"?"*":m.name).join(" ");return d===i});if(a)throw new Error(`Duplicate commands: '${a.fullPath_s}' and '${o.fullPath_s}'`);this._commands.push(o)}removeCommand(e){const n=e.join(" "),r=this._commands.findIndex(o=>o.fullPath.join(" ")===n);return r===-1?!1:(this._commands.splice(r,1),!0)}getCommand(e){return this._commands.find(n=>{const r=n.fullPath.join(" "),o=e.join(" ");if(r===o)return!0;const l=n.segments.filter(d=>d.type==="word").map(d=>d.name);return l.length===e.length&&l.join(" ")===o})}commandExistsForPath(e){const n=this._commands.map(o=>o.segments.map(a=>a.type==="argument"?"*":a.name).join(" ")),r=e.map((o,a)=>this._commands.some(d=>{var i;return((i=d.segments[a])==null?void 0:i.type)==="argument"})?"*":o).join(" ");return n.includes(r)}getCompletionNames(e){return this.getCompletions(e).map(n=>n.name)}getMatchingCompletions(e,n){const r=n.trim().toLowerCase(),o=this.getCompletions(e);return r?o.filter(a=>a.name.toLowerCase().startsWith(r)):o}getUniqueCompletion(e,n){const r=this.getMatchingCompletions(e,n);if(r.length===1)return r[0]}getCompletions(e){if(E.debug("[getCompletions] path: ",e),!e.length){const a=this._commands.map(i=>i.segments[0]),l=(i,m)=>i.type===m.type&&i.name===m.name;return a.filter((i,m,w)=>m===w.findIndex(b=>l(b,i)))}const n=e.length;return this._commands.filter(a=>{const l=a.segments;if(l.length<=n-1)return!1;for(let d=0;d<n;d++){const i=e[d],m=l[d];if(!(i==="*"&&m.type==="argument")&&i!==m.name)return!1}return!0}).filter(a=>a.segments.length>n).map(a=>{const l=a.segments[n],d=l.type==="argument"?j:ie;return new d(l.name,l.description)}).filter((a,l,d)=>l===d.findIndex(i=>i.type===a.type&&i.name===a.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class le{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 Ie extends le{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(o=>({commandSegments:Array.isArray(o.commandSegments)?A(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 r=n.map(o=>({commandSegments:Array.isArray(o.commandSegments)?A(o.commandSegments).map(a=>({type:a.type,name:a.name,description:a.description,...a instanceof j?{value:a.value}:{}})):[],timestamp:o.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(r))}catch(r){throw console.warn("Failed to save commands to localStorage:",r),r}}}class ce extends le{constructor(n){super(n);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?A(n.commandSegments):[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(r=>({commandSegments:Array.isArray(r.commandSegments)?A(r.commandSegments):[],timestamp:r.timestamp}))}}const T=class T{constructor(){C(this,"currentStorage")}static reset(){T.instance=void 0}static getInstance(){return T.instance||(T.instance=new T),T.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new ce(e):this.currentStorage=new Ie(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new ce(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(T,"instance");let W=T;class de{constructor(){C(this,"segments",[]);C(this,"nullSegment",new Z);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 Me={config:N,commands:new O,segmentStack:new de},$=s.createContext(Me),Pe=({config:t=N,commandRegistry:e,children:n})=>{const[r,o]=s.useState(),[a]=s.useState(()=>new de),l=s.useMemo(()=>({...N,...t,storage:{...N.storage,...t.storage},cursorType:t.cursorType??N.cursorType,cursorColor:t.cursorColor??N.cursorColor,cursorSpeed:t.cursorSpeed??N.cursorSpeed,showCitadelKey:t.showCitadelKey||"."}),[t]);s.useEffect(()=>{W.getInstance().initializeStorage(l.storage??N.storage),o(W.getInstance().getStorage())},[l.storage]),s.useEffect(()=>{if(e){if(l.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const i=ze(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",i)}return}e.removeCommand(["help"])}},[e,l.includeHelpCommand]);const d=s.useMemo(()=>({config:l,commands:e||new O,storage:r,segmentStack:a}),[l,e,r,a]);return c.jsx($.Provider,{value:d,children:n})},H=()=>{const t=s.useContext($);if(t===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return t.config},B=()=>{const t=s.useContext($);if(t===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return t.commands},me=()=>{const t=s.useContext($);if(t===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return t.storage},q=()=>{const t=s.useContext($);if(t===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return t.segmentStack},G=class G{constructor(e,n){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${G.idCounter++}`,this.command=e.toArray().map(r=>r.type==="argument"?r.value||"":r.name),this.timestamp=Date.now(),this.result=n??new re}};C(G,"idCounter",0);let Y=G;function He(t){return{commandSegments:A(t),timestamp:Date.now()}}function ue(){const t=me(),[e,n]=s.useState({storedCommands:[],position:null}),r=s.useCallback(async d=>{if(t)try{const i=He(d);await t.addStoredCommand(i),n(m=>({...m,storedCommands:[...m.storedCommands,{...i,commandSegments:A(i.commandSegments)}],position:null}))}catch(i){console.warn("Failed to save command to history:",i)}},[t]),o=s.useCallback(async()=>t?(await t.getStoredCommands()).map(i=>({...i,commandSegments:A(i.commandSegments)})):[],[t]);s.useEffect(()=>{if(!t)return;(async()=>{try{const m=(await t.getStoredCommands()).map(w=>({...w,commandSegments:A(w.commandSegments)}));return n(w=>({...w,storedCommands:m})),m}catch(i){console.warn("Failed to load command history:",i)}})()},[t]);const a=s.useCallback(async d=>{const i=await o();if(i.length===0)return n(b=>({...b,storedCommands:[],position:null})),{segments:null,position:null};let m=null;if(d==="up"?e.position===null?m=i.length-1:e.position>0?m=e.position-1:m=0:e.position===null||e.position>=i.length-1?m=null:m=e.position+1,n(b=>({...b,storedCommands:i.map(v=>({...v,commandSegments:A(v.commandSegments)})),position:m})),m===null)return{segments:[],position:null};const w=i[m];return w?{segments:A(w.commandSegments),position:m}:{segments:[],position:null}},[e.position,o]),l=s.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:r,getStoredCommands:o,navigateHistory:a,clear:l}}const R=()=>{const t=H(),e=B(),n=ue(),r=q(),o=me(),[a,l]=s.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:o}});s.useEffect(()=>{},[o]),s.useEffect(()=>{l(i=>({...i,history:{commands:n.history.storedCommands,position:n.history.position,storage:o}}))},[n.history,o]);const d={setCurrentInput:s.useCallback(i=>{E.debug("[CitadelActions] setCurrentInput: ",i),l(m=>({...m,currentInput:i}))},[]),setIsEnteringArg:s.useCallback(i=>{E.debug("[CitadelActions] setIsEnteringArg: ",i),l(m=>({...m,isEnteringArg:i}))},[]),addOutput:s.useCallback(i=>{E.debug("[CitadelActions]addOutput: ",i),l(m=>({...m,output:[...m.output,i]}))},[]),executeCommand:s.useCallback(async()=>{const i=r.path(),m=e.getCommand(i);if(!m){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",i);return}const w=new Y(r);l(b=>({...b,output:[...b.output,w]}));try{const b=new Promise((f,k)=>{setTimeout(()=>{k(new Error("Request timed out"))},t.commandTimeoutMs)}),v=r.arguments.map(f=>f.value||""),y=await Promise.race([m.handler(v),b]);if(!(y instanceof D))throw new Error(`The ${i.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 ${i.join(".")} command and update the return type for its handler.`);v.markSuccess(),d(h=>({...h,output:h.output.map(E=>E.id===p.id?{...E,result:v}:E)}))}catch(g){const k=new J(g instanceof Error?g.message:"Unknown error");k.markFailure(),d(v=>({...v,output:v.output.map(h=>h.id===p.id?{...h,result:k}:h)}))}},[e,r.commandTimeoutMs,t]),clearHistory:s.useCallback(async()=>{try{await n.clear()}catch(i){console.warn("Failed to clear history:",i)}},[n])};return{state:l,actions:m}},Ee=({onOpen:r,onClose:e,isVisible:n,showCitadelKey:t})=>{s.useEffect(()=>{const o=l=>{var d,m;!n&&l.key===t&&!["input","textarea"].includes(((m=(d=l.target)==null?void 0:d.tagName)==null?void 0:m.toLowerCase())||"")&&(l.preventDefault(),r()),n&&l.key==="Escape"&&(l.preventDefault(),e())};return document.addEventListener("keydown",o),()=>document.removeEventListener("keydown",o)},[r,e,n,t])},se={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"},Ne=r=>{const{isVisible:e,isClosing:n,onAnimationComplete:t}=r,o=s.useMemo(()=>e?n?se.slideDown:se.slideUp:"",[e,n]);return s.useEffect(()=>{if(t){const d=setTimeout(()=>{t()},200);return()=>clearTimeout(d)}},[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}},_e=()=>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 l=t.startsWith("<")&&t.endsWith(">");return a.jsxs("span",{className:l?"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===H.Pending&&a.jsx(_e,{}),n===H.Success&&a.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-green-500"}),(n===H.Timeout||n===H.Failure)&&a.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-red-500"})]}),Ie=({output:r,outputRef:e})=>{const n=T(),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"),l=o[o.length-1];if(l&&!l.complete)return l.addEventListener("load",t),()=>l.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=>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()})]},o.id))})},ae={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ie=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],le=["|","/","-","\\"],ze=({style:r={type:"blink"},isValid:e=!0,errorMessage:n})=>{const t=s.useMemo(()=>({...ae[r.type],...r}),[r]),[o,l]=s.useState(!0),[d,m]=s.useState(0);s.useEffect(()=>{if(t.speed===0)return;const p=setInterval(()=>{t.type==="blink"?l(g=>!g):["spin","bbs"].includes(t.type)&&m(g=>(g+1)%(t.type==="bbs"?le.length:ie.length))},t.speed);return()=>clearInterval(p)},[t.type,t.speed]);const i=s.useMemo(()=>({color:e?t.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,t.color]),c=()=>!e&&n?"✗":["spin","bbs"].includes(t.type)?(t.type==="bbs"?le:ie)[d]: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:i,title:n,children:c()})})};function Pe(r,e){switch(e.type){case"set":return S.debug(`[inputStateReducer] InputState changing from ${r} to ${e.state}`),e.state;default:return r}}const He=()=>{const{state:r}=G(),e=q(),n=oe(),t=U(),[o,l]=s.useReducer(Pe,"idle"),d=u=>{l({type:"set",state:u})},m=s.useCallback(()=>{const w=e.getCompletions(t.path())[0]||t.nullSegment;return S.debug("[getNextExpectedSegment] ",w),w},[e,t]),i=s.useCallback(()=>e.getCompletionNames(t.path()).map(w=>e.getCommand([...t.path(),w])).filter(w=>w!==void 0),[e,t]),c=s.useCallback((u,w)=>{if(!u)return w;const b=t.path().length;return w.filter(C=>{const f=C.segments[b];return!f||f.type!=="word"?!1:f.name.toLowerCase().startsWith(u.toLowerCase())})},[t]),p=s.useCallback(u=>{const b=e.getCompletions(t.path()).filter(C=>C.type==="word").filter(C=>C.name.toLowerCase().startsWith(u.toLowerCase()));return b.length===1?b[0]:t.nullSegment},[e,t]),g=s.useCallback(u=>{const w=t.path(),b=e.getCompletions(w);return b.length===0&&u?!1:b.some(f=>f.type==="argument")?!0:b.some(f=>f.type==="word"&&f.name.toLowerCase().startsWith(u.toLowerCase()))},[e,t]),k=s.useCallback(u=>{S.debug("[tryAutoComplete] input: ",u);const w=p(u);return!w||w.name===u?new ne:(S.debug("[tryAutoComplete] result: ",w),w)},[p]),v=s.useCallback((u,w)=>{if(r.history.position===null){if(w.setCurrentInput(u),S.debug("[useCommandParser][handleInputChange] newValue: ",u),o==="entering_argument"){const b=ce(u);if(b.isQuoted)if(b.isComplete){const C=m();if(!(C instanceof $))return;C.value=u.trim()||"",S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",C),t.push(C),w.setCurrentInput(""),d("idle");return}else return;else if(b.isComplete){const C=m();if(!(C instanceof $))return;C.value=u.trim()||"",S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",C),t.push(C),w.setCurrentInput(""),d("idle");return}else return}if(o==="entering_command"){const b=k(u);if(b.type==="word"){S.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",b),t.push(b),w.setCurrentInput(""),d("idle");return}}}},[k,r,m,o,t]),h=s.useCallback(u=>{u.setCurrentInput(""),u.setIsEnteringArg(!1),t.clear(),d("idle")},[t]),E=s.useCallback((u,w,b)=>{if(!(u.key==="Backspace"||u.key==="Enter"||u.key==="ArrowUp"||u.key==="ArrowDown"||u.key==="ArrowLeft"||u.key==="ArrowRight"||u.key==="Escape"||u.key==="Delete"||u.key==="Home"||u.key==="End"||u.key.length===1))return!0;const{currentInput:f,isEnteringArg:_}=w,I=ce(f);switch(u.key){case"Backspace":return f===""&&(u.preventDefault(),t.size()>0&&t.pop(),d("idle")),!0;case"Enter":{if(u.preventDefault(),I.isQuoted&&!I.isComplete)return!0;if(o==="entering_argument"||_&&f.trim()){const M=m();M instanceof $&&(M.value=f,S.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",M),t.push(M))}const A=t.path(),j=e.getCommand(A);if(!j)return!1;const F=j.segments.filter(M=>M.type==="argument"),$e=t.arguments;return F.length>$e.length?!1:(S.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",t),b.executeCommand(),n.addStoredCommand(t.toArray()),h(b),!0)}case"ArrowUp":return u.preventDefault(),(async()=>{const A=await n.navigateHistory("up");return A.segments&&(t.clear(),t.pushAll(A.segments),b.setCurrentInput("")),!0})();case"ArrowDown":return u.preventDefault(),(async()=>{const A=await n.navigateHistory("down");return A.segments&&(t.clear(),t.pushAll(A.segments),b.setCurrentInput("")),!0})();default:{if(!_&&u.key.length===1){const A=f+u.key;if(!g(A))return u.preventDefault(),!1}return!0}}},[o,g,m,n,h,e,t]);return{handleInputChange:v,handleKeyDown:E,inputState:o,setInputStateWithLogging:d,findMatchingCommands:c,getAutocompleteSuggestion:p,getAvailableNodes:i,getNextExpectedSegment:m,isValidCommandInput:g}};function ce(r){const e=[];let n="",t=!1,o;for(let l=0;l<r.length;l++){const d=r[l];(d==='"'||d==="'")&&(!t||d===o)?t?(e.push(n),n="",t=!1,o=void 0):(n&&(e.push(n),n=""),t=!0,o=d):!t&&d===" "?n&&(e.push(n),n=""):n+=d}return{words:e,currentWord:n,isQuoted:t,quoteChar:o,isComplete:!t&&!n}}const Me=()=>{const r=U(),[e,n]=s.useState(0);return s.useEffect(()=>{const t={update:()=>{n(o=>o+1)}};return r.subscribe(t),()=>{r.unsubscribe(t)}},[r]),e},De=({state:r,actions:e})=>{const n=s.useRef(null),t=q(),o=U(),{handleKeyDown:l,handleInputChange:d,inputState:m,setInputStateWithLogging:i,getNextExpectedSegment:c}=He(),[p,g]=s.useState(!1),k=T(),v=Me(),h=async f=>{const _=l(f,r,e);await Promise.resolve(_)===!1&&(g(!0),setTimeout(()=>g(!1),500))},E=f=>{d(f.target.value,e)},u=f=>{f.preventDefault();const _=f.clipboardData.getData("text");d(_,e)};s.useEffect(()=>{n.current&&n.current.focus(),m!=="entering_command"&&i("entering_command")},[m,i]),s.useEffect(()=>{if(m!=="idle")return;const f=c();let _="idle";switch(f.type){case"word":_="entering_command",e.setIsEnteringArg(!1);break;case"argument":_="entering_argument",e.setIsEnteringArg(!0);break}i(_)},[v,m,c,i,e]);const w=s.useMemo(()=>{const f=[],_=o.toArray().map((I,A)=>{f.push(I.name);const j=t.hasNextSegment(f);if(I.type==="argument"){const F=I;return a.jsxs(s.Fragment,{children:[a.jsx("span",{className:"text-gray-200 whitespace-pre",children:F.value}),A<o.size()&&j&&a.jsx("span",{className:"text-gray-200 whitespace-pre",children:" "})]},"arg-"+F.name+F.value)}return a.jsxs(s.Fragment,{children:[a.jsx("span",{className:"text-blue-400 whitespace-pre",children:I.name}),A<o.size()&&j&&a.jsx("span",{className:"text-blue-400 whitespace-pre",children:" "})]},"word-"+I.name)});return[a.jsx("div",{className:"flex items-center gap-1","data-testid":"user-input-area",children:_},"{segmentStackVersion}")]},[v,t,o]),[b,C]=s.useState("");return s.useEffect(()=>{const f=c();f.type==="argument"?C(f.name):C("")},[v,c]),a.jsxs("div",{className:"flex flex-col w-full bg-gray-900 rounded-lg p-4",children:[a.jsx("style",{children:`
6
+ Check the definition of the ${i.join(".")} command and update the return type for its handler.`);y.markSuccess(),l(f=>({...f,output:f.output.map(k=>k.id===w.id?{...k,result:y}:k)}))}catch(b){const v=new J(b instanceof Error?b.message:"Unknown error");v.markFailure(),l(y=>({...y,output:y.output.map(f=>f.id===w.id?{...f,result:v}:f)}))}},[e,t.commandTimeoutMs,r]),clearHistory:s.useCallback(async()=>{try{await n.clear()}catch(i){console.warn("Failed to clear history:",i)}},[n])};return{state:a,actions:d}},Te=({onOpen:t,onClose:e,isVisible:n,showCitadelKey:r})=>{s.useEffect(()=>{const o=a=>{var l,d;!n&&a.key===r&&!["input","textarea"].includes(((d=(l=a.target)==null?void 0:l.tagName)==null?void 0:d.toLowerCase())||"")&&(a.preventDefault(),t()),n&&a.key==="Escape"&&(a.preventDefault(),e())};return document.addEventListener("keydown",o),()=>document.removeEventListener("keydown",o)},[t,e,n,r])},pe={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"},Fe=t=>{const{isVisible:e,isClosing:n,onAnimationComplete:r}=t,o=s.useMemo(()=>e?n?pe.slideDown:pe.slideUp:"",[e,n]);return s.useEffect(()=>{if(r){const l=setTimeout(()=>{r()},200);return()=>clearTimeout(l)}},[n,r]),{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}},De=()=>c.jsx("div",{"data-testid":"spinner",className:"animate-spin rounded-full h-4 w-4 border-2 border-gray-300 border-t-gray-600"}),Ue=/^text-(xs|sm|base|lg|xl|[2-9]xl|\[[^\]]+\])$/,he=t=>{const e=t==null?void 0:t.trim();return e||void 0},je=t=>{const e=he(t);return e?Ue.test(e)?{className:e}:{style:{fontSize:e}}:{}},V=(t,e)=>{const n=he(t),r=je(e),o={...r.style};return n&&(o.fontFamily=n),{className:r.className,style:Object.keys(o).length>0?o:void 0}},Le=({command:t,timestamp:e,status:n,fontFamily:r,fontSize:o})=>{const a=s.useMemo(()=>V(r,o??"text-sm"),[r,o]);return c.jsxs("div",{className:`flex items-center gap-2 ${a.className??""}`.trim(),style:a.style,children:[c.jsxs("span",{className:"text-gray-200",children:["> ",t.split(" ").map((l,d)=>{const i=l.startsWith("<")&&l.endsWith(">");return c.jsxs("span",{className:i?"text-green-400":"text-gray-200",children:[d>0?" ":"",l]},d)})]}),c.jsx("span",{className:"text-gray-400",children:"·"}),c.jsx("span",{className:"text-gray-500",children:e}),n===U.Pending&&c.jsx(De,{}),n===U.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-green-500"}),(n===U.Timeout||n===U.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"w-4 h-4 rounded-full bg-red-500"})]})},Oe=({output:t,outputRef:e})=>{const n=H(),r=s.useMemo(()=>V(n.fontFamily,n.outputFontSize??n.fontSize),[n.fontFamily,n.fontSize,n.outputFontSize]),o=s.useCallback(()=>{if(e.current){const a=e.current;requestAnimationFrame(()=>{a.scrollTop=a.scrollHeight})}},[e]);return s.useEffect(()=>{if(o(),e.current){const a=e.current.getElementsByTagName("img"),l=a[a.length-1];if(l&&!l.complete)return l.addEventListener("load",o),()=>l.removeEventListener("load",o)}},[t,o,e]),c.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:t.map(a=>c.jsxs("div",{className:"mb-4 last:mb-0",children:[c.jsx(Le,{command:a.command.join(" "),timestamp:new Date(a.timestamp).toLocaleTimeString(),status:a.result.status,fontFamily:n.fontFamily,fontSize:n.fontSize}),c.jsx("pre",{className:`text-gray-200 whitespace-pre ${r.className??""}`.trim(),style:r.style,children:a.result.render()})]},a.id))})},ge={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},fe=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],we=["|","/","-","\\"],$e=({style:t={type:"blink"},isValid:e=!0,errorMessage:n})=>{const r=s.useMemo(()=>({...ge[t.type],...t}),[t]),[o,a]=s.useState(!0),[l,d]=s.useState(0);s.useEffect(()=>{if(r.speed===0)return;const w=setInterval(()=>{r.type==="blink"?a(b=>!b):["spin","bbs"].includes(r.type)&&d(b=>(b+1)%(r.type==="bbs"?we.length:fe.length))},r.speed);return()=>clearInterval(w)},[r.type,r.speed]);const i=s.useMemo(()=>({color:e?r.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,r.color]),m=()=>!e&&n?"✗":["spin","bbs"].includes(r.type)?(r.type==="bbs"?we:fe)[l]:r.type==="solid"||o?r.character:" ";return c.jsx("div",{className:"relative inline-block",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:i,title:n,children:m()})})};function qe(t,e){switch(e.type){case"set":return E.debug(`[inputStateReducer] InputState changing from ${t} to ${e.state}`),e.state;default:return t}}const Ke=()=>{const{state:t}=R(),e=B(),n=ue(),r=q(),[o,a]=s.useReducer(qe,"idle"),l=u=>{a({type:"set",state:u})},d=s.useCallback(()=>{const p=e.getCompletions(r.path())[0]||r.nullSegment;return E.debug("[getNextExpectedSegment] ",p),p},[e,r]),i=s.useCallback(()=>e.getCompletionNames(r.path()).map(p=>e.getCommand([...r.path(),p])).filter(p=>p!==void 0),[e,r]),m=s.useCallback((u,p)=>{if(!u)return p;const h=r.path().length;return p.filter(I=>{const S=I.segments[h];return!S||S.type!=="word"?!1:S.name.toLowerCase().startsWith(u.toLowerCase())})},[r]),w=s.useCallback(u=>{const p=e.getUniqueCompletion(r.path(),u);return p&&p.type==="word"?p:r.nullSegment},[e,r]),b=s.useCallback(u=>{const p=r.path(),h=e.getCompletions(p);return h.length===0&&u?!1:h.some(S=>S.type==="argument")?!0:e.getMatchingCompletions(p,u).some(S=>S.type==="word")},[e,r]),v=s.useCallback(u=>{E.debug("[tryAutoComplete] input: ",u);const p=w(u);return!p||p.type==="null"?new Z:(E.debug("[tryAutoComplete] result: ",p),p)},[w]),y=s.useCallback((u,p)=>{if(t.history.position!==null)return;p.setCurrentInput(u),E.debug("[useCommandParser][handleInputChange] newValue: ",u);const h=d();if(h.type==="argument"||o==="entering_argument"){const z=be(u);if(z.isQuoted)if(z.isComplete){if(!(h instanceof j))return;h.value=u.trim()||"",E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",h),r.push(h),p.setCurrentInput(""),l("idle");return}else return;else if(z.isComplete){if(!(h instanceof j))return;h.value=u.trim()||"",E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",h),r.push(h),p.setCurrentInput(""),l("idle");return}else return}if(u.endsWith(" ")){const z=u.trim().toLowerCase(),M=e.getCompletions(r.path()).filter(x=>x.type==="word"&&x.name.toLowerCase()===z);if(M.length===1){r.push(M[0]),p.setCurrentInput(""),l("idle");return}}const S=v(u);if(S.type==="word"){E.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",S),r.push(S),p.setCurrentInput(""),l("idle");return}},[v,t,d,o,r,e]),f=s.useCallback(u=>{u.setCurrentInput(""),u.setIsEnteringArg(!1),r.clear(),l("idle")},[r]),k=s.useCallback((u,p,h)=>{if(!(u.key==="Backspace"||u.key==="Enter"||u.key==="ArrowUp"||u.key==="ArrowDown"||u.key==="ArrowLeft"||u.key==="ArrowRight"||u.key==="Escape"||u.key==="Delete"||u.key==="Home"||u.key==="End"||u.key.length===1))return!0;const{currentInput:S,isEnteringArg:z}=p,M=be(S);switch(u.key){case"Backspace":return S===""&&(u.preventDefault(),r.size()>0&&r.pop(),l("idle")),!0;case"Enter":{if(u.preventDefault(),M.isQuoted&&!M.isComplete)return!0;if(o==="entering_argument"||z&&S.trim()){const P=d();P instanceof j&&(P.value=S,E.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",P),r.push(P))}const x=r.path(),_=e.getCommand(x);if(!_)return!1;const F=_.segments.filter(P=>P.type==="argument"),K=r.arguments;return F.length>K.length?!1:(E.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",r),h.executeCommand(),n.addStoredCommand(r.toArray()),f(h),!0)}case"ArrowUp":return u.preventDefault(),(async()=>{const x=await n.navigateHistory("up");return x.segments&&(r.clear(),r.pushAll(x.segments),h.setCurrentInput("")),!0})();case"ArrowDown":return u.preventDefault(),(async()=>{const x=await n.navigateHistory("down");return x.segments&&(r.clear(),r.pushAll(x.segments),h.setCurrentInput("")),!0})();default:{if(!z&&u.key.length===1){const x=S+u.key;if(!b(x))return u.preventDefault(),!1}return!0}}},[o,b,d,n,f,e,r]);return{handleInputChange:y,handleKeyDown:k,inputState:o,setInputStateWithLogging:l,findMatchingCommands:m,getAutocompleteSuggestion:w,getAvailableNodes:i,getNextExpectedSegment:d,isValidCommandInput:b}};function be(t){const e=[];let n="",r=!1,o;for(let a=0;a<t.length;a++){const l=t[a];(l==='"'||l==="'")&&(!r||l===o)?r?(e.push(n),n="",r=!1,o=void 0):(n&&(e.push(n),n=""),r=!0,o=l):!r&&l===" "?n&&(e.push(n),n=""):n+=l}return{words:e,currentWord:n,isQuoted:r,quoteChar:o,isComplete:!r&&!n}}const We=()=>{const t=q(),[e,n]=s.useState(0);return s.useEffect(()=>{const r={update:()=>{n(o=>o+1)}};return t.subscribe(r),()=>{t.unsubscribe(r)}},[t]),e},Be=({state:t,actions:e})=>{const n=s.useRef(null),r=B(),o=q(),{handleKeyDown:a,handleInputChange:l,inputState:d,setInputStateWithLogging:i,getNextExpectedSegment:m}=Ke(),[w,b]=s.useState(!1),v=H(),y=We(),f=s.useMemo(()=>V(v.fontFamily,v.fontSize),[v.fontFamily,v.fontSize]),k=async x=>{const _=a(x,t,e);await Promise.resolve(_)===!1&&(b(!0),setTimeout(()=>b(!1),500))},u=x=>{l(x.target.value,e)},p=x=>{x.preventDefault();const _=x.clipboardData.getData("text");l(_,e)};s.useEffect(()=>{n.current&&n.current.focus(),d!=="entering_command"&&i("entering_command")},[d,i]),s.useEffect(()=>{if(d!=="idle")return;const x=m();let _="idle";switch(x.type){case"word":_="entering_command",e.setIsEnteringArg(!1);break;case"argument":_="entering_argument",e.setIsEnteringArg(!0);break}i(_)},[y,d,m,i,e]);const h=s.useMemo(()=>{const x=[],_=o.toArray().map((F,K)=>{x.push(F.name);const P=r.hasNextSegment(x);if(F.type==="argument"){const ne=F;return c.jsxs(s.Fragment,{children:[c.jsx("span",{className:"text-gray-200 whitespace-pre",children:ne.value}),K<o.size()&&P&&c.jsx("span",{className:"text-gray-200 whitespace-pre",children:" "})]},"arg-"+ne.name+ne.value)}return c.jsxs(s.Fragment,{children:[c.jsx("span",{className:"text-blue-400 whitespace-pre",children:F.name}),K<o.size()&&P&&c.jsx("span",{className:"text-blue-400 whitespace-pre",children:" "})]},"word-"+F.name)});return[c.jsx("div",{className:"flex items-center gap-1","data-testid":"user-input-area",children:_},y)]},[y,r,o]),[I,S]=s.useState("");s.useEffect(()=>{const x=m();x.type==="argument"?S(x.name):S("")},[y,m]);const z=!t.isEnteringArg,M=t.currentInput.length;return c.jsxs("div",{className:"flex flex-col w-full bg-gray-900 rounded-lg p-4",children:[c.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 ${i.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
- `}),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:[w,a.jsxs("div",{className:"relative flex-1",children:[a.jsx("input",{ref:n,type:"text",role:"textbox",value:r.currentInput,onChange:E,onKeyDown:h,onPaste:u,"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:b}),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(ze,{style:{type:k.cursorType??N.cursorType,color:k.cursorColor||N.cursorColor,speed:k.cursorSpeed||N.cursorSpeed}})})]})]})]})]})},Te=()=>{const r=q(),e=U(),n="mt-2 border-t border-gray-700 px-4 py-2",t="text-gray-300",o=r.getCompletions(e.path());S.debug("[AvailableCommands] nextCommandSegments: ",o);const l=s.useMemo(()=>{const c=[...o],p=h=>h.name.toLowerCase()==="help",g=c.filter(p);return[...c.filter(h=>!p(h)).sort((h,E)=>h.name.localeCompare(E.name,void 0,{sensitivity:"base"})),...g]},[o]),d=s.useMemo(()=>{const c=new Map;for(const p of l){const g=l.reduce((k,v)=>{if(v===p)return k;let h=0;for(;h<p.name.length&&h<v.name.length&&p.name[h].toLowerCase()===v.name[h].toLowerCase();)h++;return Math.max(k,h+1)},1);c.set(p.name,g)}return c},[l]),m=o.some(c=>c.type==="argument"),i=o[0];return a.jsx("div",{className:n,"data-testid":"available-commands",children:a.jsx("div",{className:t,children:m?o.length>0?a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"text-blue-400",children:i.name}),i.description&&a.jsxs("span",{className:"text-gray-400 ml-2",children:["- ",i.description]})]}):null:a.jsx("div",{className:"flex flex-wrap gap-2",children:l==null?void 0:l.map(c=>{const p=d.get(c.name)??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:c.name.slice(0,p)}),c.name.slice(p)]})},c.name)})})})})},de=({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(Ie,{output:r.output,outputRef:n})}),a.jsxs("div",{children:[a.jsx(De,{state:r,actions:e}),a.jsx(Te,{})]})]}),Ue=()=>{const[r,e]=s.useState(!1),[n,t]=s.useState(!1),o=T(),[l,d]=s.useState(()=>o.initialHeight||null),m=s.useRef(null),i=s.useRef(null),c=s.useRef(!1),p=s.useRef(0),g=s.useRef(0),{state:k,actions:v}=G();Ee({onOpen:()=>e(!0),onClose:()=>t(!0),isVisible:r,showCitadelKey:o.showCitadelKey||"."});const h=s.useCallback(b=>{var I;if(!c.current)return;const C=b.clientY-p.current,f=(I=o.maxHeight)!=null&&I.endsWith("vh")?window.innerHeight*parseInt(o.maxHeight,10)/100:parseInt(o.maxHeight||"80vh",10),_=Math.min(Math.max(g.current-C,parseInt(o.minHeight||"200",10)),f);i.current&&(i.current.style.height=`${_}px`,i.current.style.bottom="0",d(`${_}px`))},[o.maxHeight,o.minHeight]),E=s.useCallback(()=>{c.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",E)},[h]),u=s.useCallback(b=>{i.current&&(c.current=!0,p.current=b.clientY,g.current=i.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",h),document.addEventListener("mouseup",E))},[h,E]);s.useEffect(()=>()=>{document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",E)},[h,E]);const w=s.useCallback(()=>{n&&(e(!1),t(!1))},[n]);return Ne({isVisible:r,isClosing:n,onAnimationComplete:w}),r?a.jsxs("div",{ref:i,className:`panelContainer ${r?"citadel_slideUp":""} ${n?"citadel_slideDown":""}`,style:{...l?{height:l}:void 0,maxHeight:o.maxHeight},children:[a.jsx("div",{className:"resizeHandle",onMouseDown:u}),a.jsx(de,{state:k,actions:v,outputRef:m})]}):null},je=()=>{const{state:r,actions:e}=G(),n=s.useRef(null);return a.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",children:a.jsx(de,{state:r,actions:e,outputRef:n})})},me=`:host {
14
+ `}),c.jsxs("div",{className:`flex items-center gap-2 ${f.className??""}`.trim(),style:f.style,children:[c.jsx("div",{className:"text-gray-400",children:">"}),c.jsxs("div",{className:"flex-1 flex items-center",children:[h,c.jsxs("div",{className:"relative flex-1",children:[c.jsx("input",{ref:n,type:"text",role:"textbox",value:t.currentInput,onChange:u,onKeyDown:k,onPaste:p,"data-testid":"citadel-command-input",className:`w-full bg-transparent outline-none caret-transparent ${z?"text-blue-400":"text-gray-200"} ${w?"invalid-input-animation":""}`,spellCheck:!1,autoComplete:"off",placeholder:I}),c.jsx("div",{className:"absolute top-0 pointer-events-none",style:{left:`${M}ch`,transition:"left 0.05s ease-out"},children:c.jsx($e,{style:{type:v.cursorType??N.cursorType,color:v.cursorColor||N.cursorColor,speed:v.cursorSpeed||N.cursorSpeed}})})]})]})]})]})},Ye=({currentInput:t=""})=>{const e=B(),n=H(),r=q(),o=s.useMemo(()=>V(n.fontFamily,n.fontSize),[n.fontFamily,n.fontSize]),a="mt-2 border-t border-gray-700 px-4 py-2",l=`text-gray-300 ${o.className??""}`.trim(),d=t.trim().toLowerCase(),i=e.getMatchingCompletions(r.path(),d);E.debug("[AvailableCommands] nextCommandSegments: ",i);const m=s.useMemo(()=>{const y=[...i],f=h=>h.name.toLowerCase()==="help",k=y.filter(f);return[...y.filter(h=>!f(h)).sort((h,I)=>h.name.localeCompare(I.name,void 0,{sensitivity:"base"})),...k]},[i]),w=s.useMemo(()=>{const y=new Map;for(const f of m){const k=m.reduce((u,p)=>{if(p===f)return u;let h=0;for(;h<f.name.length&&h<p.name.length&&f.name[h].toLowerCase()===p.name[h].toLowerCase();)h++;return Math.max(u,h+1)},1);y.set(f.name,k)}return y},[m]),b=i.some(y=>y.type==="argument"),v=i[0];return c.jsx("div",{className:a,"data-testid":"available-commands",children:c.jsx("div",{className:l,style:o.style,children:b?i.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"text-blue-400",children:v.name}),v.description&&c.jsxs("span",{className:"text-gray-400 ml-2",children:["- ",v.description]})]}):null:c.jsx("div",{className:"flex flex-wrap gap-2",children:m==null?void 0:m.map(y=>{const f=w.get(y.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"px-2 py-1 rounded bg-gray-800 mr-2 last:mr-0",children:c.jsxs("span",{className:"text-white",children:[c.jsx("strong",{className:"underline",children:y.name.slice(0,f)}),y.name.slice(f)]})},y.name)})})})})},ye=({state:t,actions:e,outputRef:n})=>{const o=H().displayMode==="inline";return c.jsxs("div",{className:"innerContainer",children:[c.jsx("div",{className:"flex-1 min-h-0 pt-3 px-4","data-testid":"citadel-output-pane",style:o?{overflow:"hidden"}:void 0,children:c.jsx(Oe,{output:t.output,outputRef:n})}),c.jsxs("div",{className:"shrink-0",children:[c.jsx(Be,{state:t,actions:e}),c.jsx(Ye,{currentInput:t.isEnteringArg?"":t.currentInput})]})]})},Ve=()=>{const[t,e]=s.useState(!1),[n,r]=s.useState(!1),o=H(),[a,l]=s.useState(()=>o.initialHeight||null),d=s.useRef(null),i=s.useRef(null),m=s.useRef(!1),w=s.useRef(0),b=s.useRef(0),{state:v,actions:y}=R();Te({onOpen:()=>e(!0),onClose:()=>r(!0),isVisible:t,showCitadelKey:o.showCitadelKey||"."});const f=s.useCallback(h=>{var M;if(!m.current)return;const I=h.clientY-w.current,S=(M=o.maxHeight)!=null&&M.endsWith("vh")?window.innerHeight*parseInt(o.maxHeight,10)/100:parseInt(o.maxHeight||"80vh",10),z=Math.min(Math.max(b.current-I,parseInt(o.minHeight||"200",10)),S);i.current&&(i.current.style.height=`${z}px`,i.current.style.bottom="0",l(`${z}px`))},[o.maxHeight,o.minHeight]),k=s.useCallback(()=>{m.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",f),document.removeEventListener("mouseup",k)},[f]),u=s.useCallback(h=>{i.current&&(m.current=!0,w.current=h.clientY,b.current=i.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",f),document.addEventListener("mouseup",k))},[f,k]);s.useEffect(()=>()=>{document.removeEventListener("mousemove",f),document.removeEventListener("mouseup",k)},[f,k]);const p=s.useCallback(()=>{n&&(e(!1),r(!1))},[n]);return Fe({isVisible:t,isClosing:n,onAnimationComplete:p}),t?c.jsxs("div",{ref:i,className:`panelContainer ${t?"citadel_slideUp":""} ${n?"citadel_slideDown":""}`,style:{...a?{height:a}:void 0,maxHeight:o.maxHeight},children:[c.jsx("div",{className:"resizeHandle",onMouseDown:u}),c.jsx(ye,{state:v,actions:y,outputRef:d})]}):null},ee=t=>{if(!t)return;const e=t.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Ge=()=>{const{state:t,actions:e}=R(),n=H(),r=s.useRef(null);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:{height:ee(n.initialHeight),maxHeight:ee(n.maxHeight),minHeight:ee(n.minHeight)},children:c.jsx(ye,{state:t,actions:e,outputRef:r})})},xe=`: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);
@@ -115,7 +115,7 @@ a:hover {
115
115
  .text-left {
116
116
  text-align: left;
117
117
  }
118
- `,ue=`/* Keep only component-specific styles here */
118
+ `,Ce=`/* Keep only component-specific styles here */
119
119
 
120
120
  .panelContainer {
121
121
  position: fixed;
@@ -197,10 +197,10 @@ a:hover {
197
197
  overflow: hidden;
198
198
  box-sizing: border-box;
199
199
  }
200
- `,he=`@tailwind base;
200
+ `,ve=`@tailwind base;
201
201
  @tailwind components;
202
202
  @tailwind utilities;
203
- `,Fe=`*, ::before, ::after {
203
+ `,Je=`*, ::before, ::after {
204
204
  --tw-border-spacing-x: 0;
205
205
  --tw-border-spacing-y: 0;
206
206
  --tw-translate-x: 0;
@@ -1017,5 +1017,5 @@ video {
1017
1017
  .last\\:mr-0:last-child {
1018
1018
  margin-right: 0px;
1019
1019
  }
1020
- `,Oe=({config:r=N,commandRegistry:e=new K,containerId:n=null})=>{const t=s.useRef(null),o=r.displayMode??N.displayMode??"panel";return s.useEffect(()=>{S.configure({level:r.logLevel||N.logLevel||Y.ERROR,prefix:"[Citadel]"});const l=new pe(e,r),d=o==="inline"&&!n,m=d?t.current:n?document.getElementById(n):document.body;if(m)m.appendChild(l);else{if(d){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(l)}return()=>{var i;(i=l.parentElement)==null||i.removeChild(l)}},[e,n,r,o]),o==="inline"&&!n?a.jsx("div",{ref:t,style:{width:"100%",height:"100%"}}):null};class pe extends HTMLElement{constructor(n,t){var l;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=((l=this.config)==null?void 0:l.displayMode)??"panel";this.setAttribute("data-display-mode",o)}connectedCallback(){try{const t=[me,ue,he,Fe].map(o=>{const l=new CSSStyleSheet;return l.replaceSync(o),l});this.shadow.adoptedStyleSheets=[...t]}catch{const t=[me,ue,he].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=ge.createRoot(n),this.root.render(a.jsx(Se,{config:this.config||N,commandRegistry:this.commandRegistry,children:a.jsx(Le,{})}))}disconnectedCallback(){const n=this.root;if(this.root=null,!n){this.shadow.replaceChildren();return}queueMicrotask(()=>{n.unmount(),this.shadow.replaceChildren()})}}typeof window<"u"&&window.customElements&&!window.customElements.get("citadel-element")&&window.customElements.define("citadel-element",pe);const Le=()=>(T().displayMode??"panel")==="inline"?a.jsx(je,{}):a.jsx(Ue,{});y.Citadel=Oe,y.CommandRegistry=K,y.CommandResult=P,y.CommandStatus=H,y.DEFAULT_CURSOR_CONFIGS=ae,y.ErrorCommandResult=J,y.ImageCommandResult=we,y.JsonCommandResult=fe,y.OutputItem=W,y.PendingCommandResult=Q,y.TextCommandResult=O,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
1020
+ `,Xe=({config:t=N,commandRegistry:e,containerId:n=null})=>{const r=s.useRef(new O),o=e??r.current,a=s.useRef(null),l=t.displayMode??N.displayMode??"panel";return s.useEffect(()=>{E.configure({level:t.logLevel||N.logLevel||X.ERROR,prefix:"[Citadel]"});const d=new Se(o,t),i=l==="inline"&&!n,m=i?a.current:n?document.getElementById(n):document.body;if(m)m.appendChild(d);else{if(i){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(d)}return()=>{var w;(w=d.parentElement)==null||w.removeChild(d)}},[o,n,t,l]),l==="inline"&&!n?c.jsx("div",{ref:a,style:{width:"100%",height:"100%"}}):null};class Se extends HTMLElement{constructor(n,r){var a;super();C(this,"shadow");C(this,"root",null);C(this,"commandRegistry");C(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=n,this.config=r;const o=((a=this.config)==null?void 0:a.displayMode)??"panel";this.setAttribute("data-display-mode",o)}connectedCallback(){try{const r=[xe,Ce,ve,Je].map(o=>{const a=new CSSStyleSheet;return a.replaceSync(o),a});this.shadow.adoptedStyleSheets=[...r]}catch{const r=[xe,Ce,ve].join(`
1021
+ `),o=document.createElement("style");o.textContent=r,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=Ne.createRoot(n),this.root.render(c.jsx(Pe,{config:this.config||N,commandRegistry:this.commandRegistry,children:c.jsx(Qe,{})}))}disconnectedCallback(){const n=this.root;if(this.root=null,!n){this.shadow.replaceChildren();return}queueMicrotask(()=>{n.unmount(),this.shadow.replaceChildren()})}}typeof window<"u"&&window.customElements&&!window.customElements.get("citadel-element")&&window.customElements.define("citadel-element",Se);const Qe=()=>(H().displayMode??"panel")==="inline"?c.jsx(Ge,{}):c.jsx(Ve,{});class Ze{constructor(){C(this,"_description")}describe(e){return this._description=e,this}get description(){return this._description}}class Re{constructor(e){C(this,"state");this.state={path:e,description:"",segments:en(e)}}describe(e){return this.state.description=e,this}details(e){return this.state.details=e,this}arg(e,n){const r=new Ze;return n==null||n(r),this.state.segments.push({type:"argument",name:e,description:r.description}),this}handle(e){return{path:this.state.path,description:this.state.description,details:this.state.details,segments:[...this.state.segments],handler:e}}}function en(t){const e=t.trim();if(!e)throw new Error("Command path cannot be empty");const n=e.split(".");if(n.some(r=>r.trim()===""))throw new Error(`Invalid command path "${t}". Empty segments are not allowed.`);if(n.some(r=>r.includes(" ")))throw new Error(`Invalid command path "${t}". Use dot-delimited words (e.g. "user.show").`);return n.map(r=>({type:"word",name:r}))}function nn(t){return t.flatMap(e=>e.type==="argument"?[e.name]:[])}function tn(t){const e=nn(t.segments);return async n=>{const r=e.reduce((o,a,l)=>(o[a]=n[l],o),{});return Promise.resolve(t.handler({rawArgs:n,namedArgs:r,commandPath:t.path}))}}function rn(t){return new Re(t)}function ke(t,e){t.addCommand(e.segments,e.description,tn(e))}function Ee(t,e){return e.forEach(n=>ke(t,n)),t}function on(t){const e=new O;return Ee(e,t)}function sn(t){return new L(t)}function an(t){return new te(t)}function ln(t,e=""){return new oe(t,e)}function cn(t){return new J(t)}g.Citadel=Xe,g.CommandRegistry=O,g.CommandResult=D,g.CommandStatus=U,g.DEFAULT_CURSOR_CONFIGS=ge,g.ErrorCommandResult=J,g.ImageCommandResult=oe,g.JsonCommandResult=te,g.OutputItem=Y,g.PendingCommandResult=re,g.TextCommandResult=L,g.command=rn,g.createCommandRegistry=on,g.error=cn,g.image=ln,g.json=an,g.registerCommand=ke,g.registerCommands=Ee,g.text=sn,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
@@ -1,2 +1,6 @@
1
1
  import { default as React } from 'react';
2
- export declare const AvailableCommands: React.FC;
2
+ interface AvailableCommandsProps {
3
+ currentInput?: string;
4
+ }
5
+ export declare const AvailableCommands: React.FC<AvailableCommandsProps>;
6
+ export {};
@@ -4,6 +4,8 @@ interface CommandOutputLineProps {
4
4
  command: string;
5
5
  timestamp: string;
6
6
  status: CommandStatus;
7
+ fontFamily?: string;
8
+ fontSize?: string;
7
9
  }
8
10
  export declare const CommandOutputLine: React.FC<CommandOutputLineProps>;
9
11
  export {};
@@ -14,6 +14,10 @@ import { CitadelConfig } from './types';
14
14
  * @property includeHelpCommand - When true, automatically adds a 'help' command that displays all available commands.
15
15
  * When false, no help command will be shown. Default: true.
16
16
  *
17
+ * @property fontFamily - The font family used by the interface. Default: 'monospace'.
18
+ *
19
+ * @property fontSize - The default font size used by the interface. Default: '0.875rem'.
20
+ *
17
21
  * @property initialHeight - The initial CSS height of the interface. Default: '40vh'.
18
22
  *
19
23
  * @property logLevel - The logging level for the Citadel interface. Default: DEBUG in development, ERROR in production.
@@ -22,7 +26,7 @@ import { CitadelConfig } from './types';
22
26
  *
23
27
  * @property minHeight - The minimum CSS height of the interface. Default: '200'.
24
28
  *
25
- * @property outputFontSize - The TailwindCSS class for the font size of the output text. Default: 'text-sm'.
29
+ * @property outputFontSize - The output font size as CSS value or Tailwind text size class. Default: '0.875rem'.
26
30
  *
27
31
  * @property resetStateOnHide - When true, hiding the interface (via Escape key or other means) will clear the command input.
28
32
  * When false, the interface preserves the last input when hidden. Default: false.
@@ -26,6 +26,18 @@ export interface CitadelConfig {
26
26
  * Whether to include the default help command in the command registry.
27
27
  */
28
28
  includeHelpCommand?: boolean;
29
+ /**
30
+ * The font family used by the interface.
31
+ * Accepts any valid CSS `font-family` value.
32
+ * Example: '"JetBrains Mono", monospace'
33
+ */
34
+ fontFamily?: string;
35
+ /**
36
+ * The default font size used by the interface.
37
+ * Accepts either a CSS font-size value (e.g. '14px', '0.875rem')
38
+ * or a Tailwind text size class (e.g. 'text-sm').
39
+ */
40
+ fontSize?: string;
29
41
  /**
30
42
  * The initial height of the command interface.
31
43
  * Accepts any valid CSS height value.
@@ -49,8 +61,10 @@ export interface CitadelConfig {
49
61
  maxHeight?: string;
50
62
  minHeight?: string;
51
63
  /**
52
- * The font size for the command output text.
53
- * Accepts Tailwind text size classes: 'text-xs', 'text-sm', 'text-base', 'text-lg', etc.
64
+ * The font size for command output text.
65
+ * Accepts either a CSS font-size value (e.g. '14px', '0.875rem')
66
+ * or a Tailwind text size class (e.g. 'text-sm').
67
+ * If omitted, output uses `fontSize`.
54
68
  */
55
69
  outputFontSize?: string;
56
70
  /**
@@ -0,0 +1,32 @@
1
+ import { CommandRegistry, CommandSegment } from './command-registry';
2
+ import { CommandResult, ErrorCommandResult, ImageCommandResult, JsonCommandResult, TextCommandResult } from './command-results';
3
+ export interface CommandExecutionContext<ArgName extends string = string> {
4
+ rawArgs: string[];
5
+ namedArgs: Record<ArgName, string | undefined>;
6
+ commandPath: string;
7
+ }
8
+ export type DslCommandHandler<ArgName extends string = string> = (context: CommandExecutionContext<ArgName>) => CommandResult | Promise<CommandResult>;
9
+ export interface CommandDefinition<ArgName extends string = string> {
10
+ path: string;
11
+ description: string;
12
+ details?: string;
13
+ segments: CommandSegment[];
14
+ handler: DslCommandHandler<ArgName>;
15
+ }
16
+ export interface ArgumentBuilderApi {
17
+ describe(description: string): this;
18
+ }
19
+ export interface CommandBuilderApi<ArgName extends string = never> {
20
+ describe(description: string): this;
21
+ details(details: string): this;
22
+ arg<Name extends string>(name: Name, configure?: (argument: ArgumentBuilderApi) => ArgumentBuilderApi | void): CommandBuilderApi<ArgName | Name>;
23
+ handle(handler: DslCommandHandler<ArgName>): CommandDefinition<ArgName>;
24
+ }
25
+ export declare function command(path: string): CommandBuilderApi;
26
+ export declare function registerCommand(registry: CommandRegistry, definition: CommandDefinition): void;
27
+ export declare function registerCommands(registry: CommandRegistry, definitions: CommandDefinition[]): CommandRegistry;
28
+ export declare function createCommandRegistry(definitions: CommandDefinition[]): CommandRegistry;
29
+ export declare function text(value: string): TextCommandResult;
30
+ export declare function json(value: unknown): JsonCommandResult;
31
+ export declare function image(url: string, altText?: string): ImageCommandResult;
32
+ export declare function error(value: string): ErrorCommandResult;
@@ -34,6 +34,8 @@ export declare class ArgumentSegment extends BaseSegment {
34
34
  readonly valid?: (() => boolean) | undefined;
35
35
  constructor(name: string, description?: string, value?: string | undefined, valid?: (() => boolean) | undefined);
36
36
  }
37
+ export declare const cloneCommandSegment: (segment: CommandSegment) => CommandSegment;
38
+ export declare const cloneCommandSegments: (segments: CommandSegment[]) => CommandSegment[];
37
39
  /** Defines a complete command with its path and behavior */
38
40
  export declare class CommandNode {
39
41
  private readonly _segments;
@@ -88,6 +90,16 @@ export declare class CommandRegistry {
88
90
  * @returns An array of completion strings.
89
91
  */
90
92
  getCompletionNames(path: string[]): string[];
93
+ /**
94
+ * Returns completion segments whose names start with the given prefix.
95
+ * Matching is case-insensitive.
96
+ */
97
+ getMatchingCompletions(path: string[], prefix: string): CommandSegment[];
98
+ /**
99
+ * Returns a single completion when prefix matching is unambiguous.
100
+ * Returns undefined for ambiguous or no-match prefixes.
101
+ */
102
+ getUniqueCompletion(path: string[], prefix: string): CommandSegment | undefined;
91
103
  /**
92
104
  * Gets an array of segments reachable from a given path
93
105
  *
@@ -1,3 +1,4 @@
1
1
  export * from './state';
2
2
  export * from './cursor';
3
3
  export * from './command-results';
4
+ export * from './command-dsl';
@@ -0,0 +1,8 @@
1
+ import { CSSProperties } from 'react';
2
+ interface TypographySettings {
3
+ className?: string;
4
+ style?: CSSProperties;
5
+ }
6
+ export declare const resolveTextSize: (size?: string) => TypographySettings;
7
+ export declare const resolveTypography: (fontFamily?: string, fontSize?: string) => TypographySettings;
8
+ export {};
@@ -0,0 +1,2 @@
1
+ import { CommandRegistry } from '../components/Citadel/types/command-registry';
2
+ export declare function createDevOpsCommandRegistry(): CommandRegistry;
@@ -0,0 +1,2 @@
1
+ import { CommandRegistry } from '../components/Citadel/types/command-registry';
2
+ export declare function createLocalDevCommandRegistry(): CommandRegistry;
@@ -1,4 +1,5 @@
1
1
  import { CommandRegistry } from '../components/Citadel/types/command-registry';
2
+ import { CommandDefinition } from '../components/Citadel/types/command-dsl';
2
3
  import { CursorType } from '../components/Citadel/types/cursor';
3
4
  export type DisplayMode = 'panel' | 'inline';
4
5
  export declare const RUNTIME_CONFIG_CURSOR_TYPES: readonly CursorType[];
@@ -7,6 +8,8 @@ export interface RuntimeConfigControls {
7
8
  setCursorColor: (color: string) => void;
8
9
  setDisplayMode: (mode: DisplayMode) => void;
9
10
  setIncludeHelpCommand: (enabled: boolean) => void;
11
+ setMaxHeight: (value: string) => void;
10
12
  resetConfig: () => void;
11
13
  }
12
14
  export declare function registerRuntimeConfigCommands(registry: CommandRegistry, controls: RuntimeConfigControls): void;
15
+ export declare function createRuntimeConfigCommandDefinitions(controls: RuntimeConfigControls): CommandDefinition[];
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.7",
20
+ "version": "1.3.0",
21
21
  "type": "module",
22
22
  "scripts": {
23
23
  "build": "tsc && vite build",