citadel_cli 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -12
- package/dist/citadel.css +472 -0
- package/dist/citadel.es.js +664 -627
- package/dist/citadel.umd.cjs +479 -0
- package/dist/citadel.umd.js +21 -8
- package/dist/components/Citadel/config/defaults.d.ts +4 -0
- package/dist/components/Citadel/config/types.d.ts +10 -0
- package/dist/components/Citadel/hooks/useGlobalShortcut.d.ts +2 -1
- package/dist/components/Citadel/hooks/useSlideAnimation.d.ts +1 -5
- package/dist/components/Citadel/types/command-dsl.d.ts +2 -1
- package/dist/components/Citadel/types/command-results.d.ts +7 -0
- package/package.json +3 -2
package/dist/citadel.umd.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`+
|
|
3
|
-
`)))};var X=(n=>(n[n.NONE=0]="NONE",n[n.ERROR=1]="ERROR",n[n.WARN=2]="WARN",n[n.INFO=3]="INFO",n[n.DEBUG=4]="DEBUG",n[n.TRACE=5]="TRACE",n))(X||{});const ce=!0;class k{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!ce&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!ce&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(k,"level",0),C(k,"prefix","");const I={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:X.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,showCitadelKey:".",displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},de=async()=>new O("");class Z{constructor(e,t,s){this.type=e,this.name=t,this.description=s}toString(){return this.name}}class R extends Z{constructor(){super("null",">null<","Empty segment")}}class me extends Z{constructor(e,t){super("word",e,t)}}class U extends Z{constructor(e,t,s,r){super("argument",e,t),this.value=s,this.valid=r}}const Me=n=>{if(n.type==="word")return new me(n.name,n.description);if(n.type==="argument"){const e=n;return new U(e.name,e.description,e.value,e.valid)}return new R},M=n=>n.map(e=>Me(e));class He{constructor(e,t,s=de){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=t,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class ${constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,t,s=de){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new He(e,t,s),a=this._commands.find(i=>{const d=i.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(a)throw new Error(`Duplicate commands: '${a.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const t=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===t);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(t=>{const s=t.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const i=t.segments.filter(d=>d.type==="word").map(d=>d.name);return i.length===e.length&&i.join(" ")===r})}commandExistsForPath(e){const t=this._commands.map(r=>r.segments.map(a=>a.type==="argument"?"*":a.name).join(" ")),s=e.map((r,a)=>this._commands.some(d=>{var l;return((l=d.segments[a])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return t.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(t=>t.name)}getMatchingCompletions(e,t){const s=t.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(a=>a.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,t){const s=this.getMatchingCompletions(e,t);if(s.length===1)return s[0]}getCompletions(e){if(k.debug("[getCompletions] path: ",e),!e.length){const a=this._commands.map(l=>l.segments[0]),i=(l,u)=>l.type===u.type&&l.name===u.name;return a.filter((l,u,y)=>u===y.findIndex(p=>i(p,l)))}const t=e.length;return this._commands.filter(a=>{const i=a.segments;if(i.length<=t-1)return!1;for(let d=0;d<t;d++){const l=e[d],u=i[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(a=>a.segments.length>t).map(a=>{const i=a.segments[t],d=i.type==="argument"?U:me;return new d(i.name,i.description)}).filter((a,i,d)=>i===d.findIndex(l=>l.type===a.type&&l.name===a.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class ue{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const t=await this.getStoredCommands();for(t.push(e);t.length>this.config.maxCommands;)t.shift();await this.saveCommands(t)}}class _e extends ue{constructor(t){super(t);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const t=window.localStorage.getItem(this.storageKey);return t?JSON.parse(t).map(r=>({commandSegments:Array.isArray(r.commandSegments)?M(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(t){return console.warn("Failed to load commands from localStorage:",t),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(t){console.warn("Failed to clear localStorage:",t)}}async saveCommands(t){try{const s=t.map(r=>({commandSegments:Array.isArray(r.commandSegments)?M(r.commandSegments).map(a=>({type:a.type,name:a.name,description:a.description,...a instanceof U?{value:a.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class pe extends ue{constructor(t){super(t);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(t=>({commandSegments:Array.isArray(t.commandSegments)?M(t.commandSegments):[],timestamp:t.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(t){this.storedCommands=t.map(s=>({commandSegments:Array.isArray(s.commandSegments)?M(s.commandSegments):[],timestamp:s.timestamp}))}}const z=class z{constructor(){C(this,"currentStorage")}static reset(){z.instance=void 0}static getInstance(){return z.instance||(z.instance=new z),z.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new pe(e):this.currentStorage=new _e(e)}catch(t){console.warn("Failed to create storage, falling back to memory storage:",t),this.currentStorage=new pe(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(z,"instance");let B=z;class he{constructor(){C(this,"segments",[]);C(this,"nullSegment",new R);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(t=>t!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(t=>this.push(t))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const Te={config:I,commands:new $,segmentStack:new he},q=o.createContext(Te),ze=({config:n=I,commandRegistry:e,children:t})=>{const[s,r]=o.useState(),[a]=o.useState(()=>new he),i=o.useMemo(()=>({...I,...n,storage:{...I.storage,...n.storage},cursorType:n.cursorType??I.cursorType,cursorColor:n.cursorColor??I.cursorColor,cursorSpeed:n.cursorSpeed??I.cursorSpeed,showCitadelKey:n.showCitadelKey||"."}),[n]);o.useEffect(()=>{B.getInstance().initializeStorage(i.storage??I.storage),r(B.getInstance().getStorage())},[i.storage]),o.useEffect(()=>{if(e){if(i.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=Pe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,i.includeHelpCommand]);const d=o.useMemo(()=>({config:i,commands:e||new $,storage:s,segmentStack:a}),[i,e,s,a]);return c.jsx(q.Provider,{value:d,children:t})},T=()=>{const n=o.useContext(q);if(n===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return n.config},V=()=>{const n=o.useContext(q);if(n===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return n.commands},ge=()=>{const n=o.useContext(q);if(n===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return n.storage},W=()=>{const n=o.useContext(q);if(n===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return n.segmentStack},G=class G{constructor(e,t){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${G.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=t??new ie}};C(G,"idCounter",0);let Y=G;function De(n){return{commandSegments:M(n),timestamp:Date.now()}}function fe(){const n=ge(),[e,t]=o.useState({storedCommands:[],position:null}),s=o.useCallback(async d=>{if(n)try{const l=De(d);await n.addStoredCommand(l),t(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:M(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[n]),r=o.useCallback(async()=>n?(await n.getStoredCommands()).map(l=>({...l,commandSegments:M(l.commandSegments)})):[],[n]);o.useEffect(()=>{if(!n)return;(async()=>{try{const u=(await n.getStoredCommands()).map(y=>({...y,commandSegments:M(y.commandSegments)}));return t(y=>({...y,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[n]);const a=o.useCallback(async d=>{const l=await r();if(l.length===0)return t(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,t(p=>({...p,storedCommands:l.map(g=>({...g,commandSegments:M(g.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const y=l[u];return y?{segments:M(y.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),i=o.useCallback(async()=>{try{if(!n)return;await n.clear(),t({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[n]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:a,clear:i}}const ee=()=>{const n=T(),e=V(),t=fe(),s=W(),r=ge(),[a,i]=o.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});o.useEffect(()=>{},[r]),o.useEffect(()=>{i(l=>({...l,history:{commands:t.history.storedCommands,position:t.history.position,storage:r}}))},[t.history,r]);const d={setCurrentInput:o.useCallback(l=>{k.debug("[CitadelActions] setCurrentInput: ",l),i(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:o.useCallback(l=>{k.debug("[CitadelActions] setIsEnteringArg: ",l),i(u=>({...u,isEnteringArg:l}))},[]),addOutput:o.useCallback(l=>{k.debug("[CitadelActions]addOutput: ",l),i(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:o.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const y=new Y(s);i(p=>({...p,output:[...p.output,y]}));try{const p=new Promise((w,S)=>{setTimeout(()=>{S(new Error("Request timed out"))},n.commandTimeoutMs)}),g=s.arguments.map(w=>w.value||""),x=await Promise.race([u.handler(g),p]);if(!(x instanceof j))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
1
|
+
(function(g,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("react/jsx-runtime"),require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","react-dom/client"],c):(g=typeof globalThis<"u"?globalThis:g||self,c(g.Citadel={},g.jsxRuntime,g.React,g.client))})(this,function(g,c,a,Me){"use strict";var ut=Object.defineProperty;var pt=(g,c,a)=>c in g?ut(g,c,{enumerable:!0,configurable:!0,writable:!0,value:a}):g[c]=a;var C=(g,c,a)=>pt(g,typeof c!="symbol"?c+"":c,a);var j=(t=>(t.Pending="pending",t.Success="success",t.Failure="failure",t.Timeout="timeout",t))(j||{});class _{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 oe extends _{constructor(e,n){super(n),this.data=e}render(){return c.jsx("pre",{className:"citadel-result-json",children:JSON.stringify(this.data,null,2)})}}class q extends _{constructor(e,n){super(n),this.text=e}render(){return c.jsx("div",{className:"citadel-result-text",children:this.text})}}class ie extends _{constructor(e,n="true",s="false",r){super(r),this.value=e,this.trueText=n,this.falseText=s}render(){return c.jsx("div",{className:"citadel-result-text citadel-result-boolean",children:this.value?this.trueText:this.falseText})}}class Z extends _{constructor(e,n){super(n),this.error=e,this.markFailure()}render(){return c.jsx("div",{className:"citadel-result-error",children:this.error})}}class le extends _{render(){return c.jsx("div",{className:"citadel-result-pending",children:"..."})}}class ce extends _{constructor(e,n="",s){super(s),this.imageUrl=e,this.altText=n}render(){return c.jsx("div",{className:"citadel-result-image-wrap",children:c.jsx("img",{src:this.imageUrl,alt:this.altText,className:"citadel-result-image"})})}}const Pe=t=>async function(){const n=t.commands.filter(s=>s.fullPath[0]!=="help").map(s=>{const i=`${s.segments.map(d=>d.type==="argument"?`<${d.name}>`:d.name).join(" ")} - ${s.description}`,o=s.segments.filter(d=>d.type==="argument"&&d.description).map(d=>` <${d.name}>: ${d.description}`);return{commandLine:i,argumentLines:o}}).sort((s,r)=>s.commandLine.localeCompare(r.commandLine)).flatMap(s=>[s.commandLine,...s.argumentLines]);return n.length===0?new q("No commands available yet. Add some commands to get started!"):(n.push("help - Show available commands"),new q(`Available Commands:
|
|
2
|
+
`+n.join(`
|
|
3
|
+
`)))};var R=(t=>(t[t.NONE=0]="NONE",t[t.ERROR=1]="ERROR",t[t.WARN=2]="WARN",t[t.INFO=3]="INFO",t[t.DEBUG=4]="DEBUG",t[t.TRACE=5]="TRACE",t))(R||{});const de=!0;class x{static configure(e){this.level=e.level,this.prefix=e.prefix||"[Citadel]"}static trace(...e){this.level>=5&&!de&&console.trace(this.prefix,...e)}static debug(...e){this.level>=4&&!de&&console.debug(this.prefix,...e)}static info(...e){this.level>=3&&console.info(this.prefix,...e)}static warn(...e){this.level>=2&&console.warn(this.prefix,...e)}static error(...e){this.level>=1&&console.error(this.prefix,...e)}}C(x,"level",0),C(x,"prefix","");const k={commandTimeoutMs:1e4,cursorColor:"var(--cursor-color, #fff)",cursorSpeed:530,cursorType:"blink",includeHelpCommand:!0,fontFamily:"monospace",fontSize:"0.875rem",initialHeight:"50vh",logLevel:R.ERROR,maxHeight:"80vh",minHeight:"200",outputFontSize:"0.875rem",resetStateOnHide:!1,closeOnEscape:!0,showCitadelKey:".",showOnLoad:!1,displayMode:"panel",storage:{type:"localStorage",maxCommands:100}},me=async()=>new q("");class ee{constructor(e,n,s){this.type=e,this.name=n,this.description=s}toString(){return this.name}}class te extends ee{constructor(){super("null",">null<","Empty segment")}}class ue extends ee{constructor(e,n){super("word",e,n)}}class U extends ee{constructor(e,n,s,r){super("argument",e,n),this.value=s,this.valid=r}}const He=t=>{if(t.type==="word")return new ue(t.name,t.description);if(t.type==="argument"){const e=t;return new U(e.name,e.description,e.value,e.valid)}return new te},H=t=>t.map(e=>He(e));class _e{constructor(e,n,s=me){C(this,"_segments");C(this,"_description");C(this,"_handler");this._segments=e,this._description=n,this._handler=s}get segments(){return this._segments}get description(){return this._description}get handler(){return this._handler}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get fullPath(){return this.segments.map(e=>e.name)}get fullPath_s(){return this.fullPath.join(" ")}equals(e){return this.fullPath.join(" ")===e.fullPath.join(" ")}}class K{constructor(){C(this,"_commands",[])}get commands(){return this._commands}addCommand(e,n,s=me){if(e===void 0||e.length===0)throw new Error("Command path cannot be empty");const r=new _e(e,n,s),i=this._commands.find(o=>{const d=o.segments.map(u=>u.type==="argument"?"*":u.name).join(" "),l=e.map(u=>u.type==="argument"?"*":u.name).join(" ");return d===l});if(i)throw new Error(`Duplicate commands: '${i.fullPath_s}' and '${r.fullPath_s}'`);this._commands.push(r)}removeCommand(e){const n=e.join(" "),s=this._commands.findIndex(r=>r.fullPath.join(" ")===n);return s===-1?!1:(this._commands.splice(s,1),!0)}getCommand(e){return this._commands.find(n=>{const s=n.fullPath.join(" "),r=e.join(" ");if(s===r)return!0;const o=n.segments.filter(d=>d.type==="word").map(d=>d.name);return o.length===e.length&&o.join(" ")===r})}commandExistsForPath(e){const n=this._commands.map(r=>r.segments.map(i=>i.type==="argument"?"*":i.name).join(" ")),s=e.map((r,i)=>this._commands.some(d=>{var l;return((l=d.segments[i])==null?void 0:l.type)==="argument"})?"*":r).join(" ");return n.includes(s)}getCompletionNames(e){return this.getCompletions(e).map(n=>n.name)}getMatchingCompletions(e,n){const s=n.trim().toLowerCase(),r=this.getCompletions(e);return s?r.filter(i=>i.name.toLowerCase().startsWith(s)):r}getUniqueCompletion(e,n){const s=this.getMatchingCompletions(e,n);if(s.length===1)return s[0]}getCompletions(e){if(x.debug("[getCompletions] path: ",e),!e.length){const i=this._commands.map(l=>l.segments[0]),o=(l,u)=>l.type===u.type&&l.name===u.name;return i.filter((l,u,y)=>u===y.findIndex(p=>o(p,l)))}const n=e.length;return this._commands.filter(i=>{const o=i.segments;if(o.length<=n-1)return!1;for(let d=0;d<n;d++){const l=e[d],u=o[d];if(!(l==="*"&&u.type==="argument")&&l!==u.name)return!1}return!0}).filter(i=>i.segments.length>n).map(i=>{const o=i.segments[n],d=o.type==="argument"?U:ue;return new d(o.name,o.description)}).filter((i,o,d)=>o===d.findIndex(l=>l.type===i.type&&l.name===i.name))}hasNextSegment(e){return this.getCompletions(e).length>0}}class pe{constructor(e){C(this,"config");this.config={type:"localStorage",maxCommands:100,...e}}async addStoredCommand(e){const n=await this.getStoredCommands();for(n.push(e);n.length>this.config.maxCommands;)n.shift();await this.saveCommands(n)}}class Te extends pe{constructor(n){super(n);C(this,"storageKey","citadel_command_history")}async getStoredCommands(){try{const n=window.localStorage.getItem(this.storageKey);return n?JSON.parse(n).map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments):[],timestamp:r.timestamp})):[]}catch(n){return console.warn("Failed to load commands from localStorage:",n),[]}}async clear(){try{window.localStorage.removeItem(this.storageKey)}catch(n){console.warn("Failed to clear localStorage:",n)}}async saveCommands(n){try{const s=n.map(r=>({commandSegments:Array.isArray(r.commandSegments)?H(r.commandSegments).map(i=>({type:i.type,name:i.name,description:i.description,...i instanceof U?{value:i.value}:{}})):[],timestamp:r.timestamp}));window.localStorage.setItem(this.storageKey,JSON.stringify(s))}catch(s){throw console.warn("Failed to save commands to localStorage:",s),s}}}class he extends pe{constructor(n){super(n);C(this,"storedCommands",[])}async getStoredCommands(){return this.storedCommands.map(n=>({commandSegments:Array.isArray(n.commandSegments)?H(n.commandSegments):[],timestamp:n.timestamp}))}async clear(){this.storedCommands=[]}async saveCommands(n){this.storedCommands=n.map(s=>({commandSegments:Array.isArray(s.commandSegments)?H(s.commandSegments):[],timestamp:s.timestamp}))}}const z=class z{constructor(){C(this,"currentStorage")}static reset(){z.instance=void 0}static getInstance(){return z.instance||(z.instance=new z),z.instance}initializeStorage(e){try{e.type==="memory"?this.currentStorage=new he(e):this.currentStorage=new Te(e)}catch(n){console.warn("Failed to create storage, falling back to memory storage:",n),this.currentStorage=new he(e)}}getStorage(){if(!this.currentStorage)throw new Error("Storage not initialized. Call initializeStorage first.");return this.currentStorage}};C(z,"instance");let Y=z;class ge{constructor(){C(this,"segments",[]);C(this,"nullSegment",new te);C(this,"observers",[])}subscribe(e){this.observers.push(e)}unsubscribe(e){this.observers=this.observers.filter(n=>n!==e)}notifyObservers(){this.observers.forEach(e=>e.update())}clear(){this.segments=[],this.notifyObservers()}push(e){this.segments.push(e),this.notifyObservers()}pushAll(e){e.forEach(n=>this.push(n))}pop(){const e=this.segments.pop()||this.nullSegment;return this.notifyObservers(),e}peek(){return this.segments[this.segments.length-1]||this.nullSegment}size(){return this.segments.length}isEmpty(){return this.segments.length===0}get hasArguments(){return this.segments.some(e=>e.type==="argument")}get arguments(){return this.segments.filter(e=>e.type==="argument")}path(){return this.segments.map(e=>e.name)}toArray(){return[...this.segments]}}const ze={config:k,commands:new K,segmentStack:new ge},W=a.createContext(ze),De=({config:t=k,commandRegistry:e,children:n})=>{const[s,r]=a.useState(),[i]=a.useState(()=>new ge),o=a.useMemo(()=>({...k,...t,storage:{...k.storage,...t.storage},cursorType:t.cursorType??k.cursorType,cursorColor:t.cursorColor??k.cursorColor,cursorSpeed:t.cursorSpeed??k.cursorSpeed,closeOnEscape:t.closeOnEscape??k.closeOnEscape,showCitadelKey:t.showCitadelKey??k.showCitadelKey,showOnLoad:t.showOnLoad??k.showOnLoad}),[t]);a.useEffect(()=>{Y.getInstance().initializeStorage(o.storage??k.storage),r(Y.getInstance().getStorage())},[o.storage]),a.useEffect(()=>{if(e){if(o.includeHelpCommand){if(!e.commandExistsForPath(["help"])){const l=Pe(e);e.addCommand([{type:"word",name:"help"}],"Show available commands",l)}return}e.removeCommand(["help"])}},[e,o.includeHelpCommand]);const d=a.useMemo(()=>({config:o,commands:e||new K,storage:s,segmentStack:i}),[o,e,s,i]);return c.jsx(W.Provider,{value:d,children:n})},T=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelConfig must be used within a CitadelConfigProvider");return t.config},J=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelCommands must be used within a CitadelConfigProvider");return t.commands},fe=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useCitadelStorage must be used within a CitadelConfigProvider");return t.storage},B=()=>{const t=a.useContext(W);if(t===void 0)throw new Error("useSegmentStack must be used within a CitadelConfigProvider");return t.segmentStack},X=class X{constructor(e,n){C(this,"id");C(this,"timestamp");C(this,"command");C(this,"result");this.id=`output-${Date.now()}-${X.idCounter++}`,this.command=e.toArray().map(s=>s.type==="argument"?s.value||"":s.name),this.timestamp=Date.now(),this.result=n??new le}};C(X,"idCounter",0);let G=X;function Oe(t){return{commandSegments:H(t),timestamp:Date.now()}}function ye(){const t=fe(),[e,n]=a.useState({storedCommands:[],position:null}),s=a.useCallback(async d=>{if(t)try{const l=Oe(d);await t.addStoredCommand(l),n(u=>({...u,storedCommands:[...u.storedCommands,{...l,commandSegments:H(l.commandSegments)}],position:null}))}catch(l){console.warn("Failed to save command to history:",l)}},[t]),r=a.useCallback(async()=>t?(await t.getStoredCommands()).map(l=>({...l,commandSegments:H(l.commandSegments)})):[],[t]);a.useEffect(()=>{if(!t)return;(async()=>{try{const u=(await t.getStoredCommands()).map(y=>({...y,commandSegments:H(y.commandSegments)}));return n(y=>({...y,storedCommands:u})),u}catch(l){console.warn("Failed to load command history:",l)}})()},[t]);const i=a.useCallback(async d=>{const l=await r();if(l.length===0)return n(p=>({...p,storedCommands:[],position:null})),{segments:null,position:null};let u=null;if(d==="up"?e.position===null?u=l.length-1:e.position>0?u=e.position-1:u=0:e.position===null||e.position>=l.length-1?u=null:u=e.position+1,n(p=>({...p,storedCommands:l.map(f=>({...f,commandSegments:H(f.commandSegments)})),position:u})),u===null)return{segments:[],position:null};const y=l[u];return y?{segments:H(y.commandSegments),position:u}:{segments:[],position:null}},[e.position,r]),o=a.useCallback(async()=>{try{if(!t)return;await t.clear(),n({storedCommands:[],position:null})}catch(d){console.warn("Failed to clear command history:",d)}},[t]);return{history:e,addStoredCommand:s,getStoredCommands:r,navigateHistory:i,clear:o}}const ne=()=>{const t=T(),e=J(),n=ye(),s=B(),r=fe(),[i,o]=a.useState({currentInput:"",isEnteringArg:!1,output:[],history:{commands:[],position:null,storage:r}});a.useEffect(()=>{},[r]),a.useEffect(()=>{o(l=>({...l,history:{commands:n.history.storedCommands,position:n.history.position,storage:r}}))},[n.history,r]);const d={setCurrentInput:a.useCallback(l=>{x.debug("[CitadelActions] setCurrentInput: ",l),o(u=>({...u,currentInput:l}))},[]),setIsEnteringArg:a.useCallback(l=>{x.debug("[CitadelActions] setIsEnteringArg: ",l),o(u=>({...u,isEnteringArg:l}))},[]),addOutput:a.useCallback(l=>{x.debug("[CitadelActions]addOutput: ",l),o(u=>({...u,output:[...u.output,l]}))},[]),executeCommand:a.useCallback(async()=>{const l=s.path(),u=e.getCommand(l);if(!u){console.error("[CitadelActions][executeCommand] Cannot execute command because no command was found for the given path: ",l);return}const y=new G(s);o(p=>({...p,output:[...p.output,y]}));try{const p=new Promise((v,E)=>{setTimeout(()=>{E(new Error("Request timed out"))},t.commandTimeoutMs)}),f=s.arguments.map(v=>v.value||""),b=await Promise.race([u.handler(f),p]);if(!(b instanceof _))throw new Error(`The ${l.join(".")} command returned an invalid result type. Commands must return an instance of a CommandResult.
|
|
4
4
|
For example:
|
|
5
5
|
return new JsonCommandResult({ text: "Hello World" });
|
|
6
|
-
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);x.markSuccess(),i(w=>({...w,output:w.output.map(S=>S.id===y.id?{...S,result:x}:S)}))}catch(p){const g=new Q(p instanceof Error?p.message:"Unknown error");g.markFailure(),i(x=>({...x,output:x.output.map(w=>w.id===y.id?{...w,result:g}:w)}))}},[e,n.commandTimeoutMs,s]),clearHistory:o.useCallback(async()=>{try{await t.clear()}catch(l){console.warn("Failed to clear history:",l)}},[t])};return{state:a,actions:d}},Fe=({onOpen:n,onClose:e,isVisible:t,showCitadelKey:s})=>{o.useEffect(()=>{const r=a=>{var i,d;!t&&a.key===s&&!["input","textarea"].includes(((d=(i=a.target)==null?void 0:i.tagName)==null?void 0:d.toLowerCase())||"")&&(a.preventDefault(),n()),t&&a.key==="Escape"&&(a.preventDefault(),e())};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[n,e,t,s])},je=n=>{const{isVisible:e,isClosing:t,onAnimationComplete:s}=n,r=o.useMemo(()=>e?t?"citadel_slideDown":"citadel_slideUp":"",[e,t]);return o.useEffect(()=>{if(s){const i=setTimeout(()=>{s()},200);return()=>clearTimeout(i)}},[t,s]),{style:o.useMemo(()=>({opacity:e?1:0,transform:e?"translateY(0)":t?"translateY(100%)":"translateY(-100%)",transition:"opacity 200ms ease-in-out, transform 200ms ease-in-out"}),[e,t]),animationClass:r}},Le=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),ye=n=>{const e=n==null?void 0:n.trim();return e||void 0},Ue=n=>{const e=ye(n);return e?{style:{fontSize:e}}:{}},J=(n,e)=>{const t=ye(n),r={...Ue(e).style};return t&&(r.fontFamily=t),{style:Object.keys(r).length>0?r:void 0}},Oe=({command:n,timestamp:e,status:t,fontFamily:s,fontSize:r})=>{const a=o.useMemo(()=>J(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:a.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",n.split(" ").map((i,d)=>{const l=i.startsWith("<")&&i.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",i]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),t===L.Pending&&c.jsx(Le,{}),t===L.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(t===L.Timeout||t===L.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},$e=({output:n,outputRef:e})=>{const t=T(),s=o.useMemo(()=>J(t.fontFamily,t.outputFontSize??t.fontSize),[t.fontFamily,t.fontSize,t.outputFontSize]),r=o.useCallback(()=>{if(e.current){const a=e.current;requestAnimationFrame(()=>{a.scrollTop=a.scrollHeight})}},[e]);return o.useEffect(()=>{if(r(),e.current){const a=e.current.getElementsByTagName("img"),i=a[a.length-1];if(i&&!i.complete)return i.addEventListener("load",r),()=>i.removeEventListener("load",r)}},[n,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:n.map(a=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(Oe,{command:a.command.join(" "),timestamp:new Date(a.timestamp).toLocaleTimeString(),status:a.result.status,fontFamily:t.fontFamily,fontSize:t.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:a.result.render()})]},a.id))})},Ce={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},we=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],ve=["|","/","-","\\"],qe=({style:n={type:"blink"},isValid:e=!0,errorMessage:t})=>{const s=o.useMemo(()=>({...Ce[n.type],...n}),[n]),[r,a]=o.useState(!0),[i,d]=o.useState(0);o.useEffect(()=>{if(s.speed===0)return;const y=setInterval(()=>{s.type==="blink"?a(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?ve.length:we.length))},s.speed);return()=>clearInterval(y)},[s.type,s.speed]);const l=o.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&t?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?ve:we)[i]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:t,children:u()})})};function We(n,e){switch(e.type){case"set":return k.debug(`[inputStateReducer] InputState changing from ${n} to ${e.state}`),e.state;default:return n}}const Ke=()=>{const{state:n}=ee(),e=V(),t=fe(),s=W(),[r,a]=o.useReducer(We,"idle"),i=m=>{a({type:"set",state:m})},d=o.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return k.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=o.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=o.useCallback((m,h)=>{if(!m)return h;const v=s.path().length;return h.filter(H=>{const b=H.segments[v];return!b||b.type!=="word"?!1:b.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),y=o.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=o.useCallback(m=>{const h=s.path(),v=e.getCompletions(h);return v.length===0&&m?!1:v.some(b=>b.type==="argument")?!0:e.getMatchingCompletions(h,m).some(b=>b.type==="word")},[e,s]),g=o.useCallback(m=>{k.debug("[tryAutoComplete] input: ",m);const h=y(m);return!h||h.type==="null"?new R:(k.debug("[tryAutoComplete] result: ",h),h)},[y]),x=o.useCallback((m,h)=>{if(n.history.position!==null)return;h.setCurrentInput(m),k.debug("[useCommandParser][handleInputChange] newValue: ",m);const v=d();if(v.type==="argument"||r==="entering_argument"){const A=Se(m);if(A.isQuoted)if(A.isComplete){if(!(v instanceof U))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),i("idle");return}else return;else if(A.isComplete){if(!(v instanceof U))return;v.value=m.trim()||"",k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",v),s.push(v),h.setCurrentInput(""),i("idle");return}else return}if(m.endsWith(" ")){const A=m.trim().toLowerCase(),_=e.getCompletions(s.path()).filter(E=>E.type==="word"&&E.name.toLowerCase()===A);if(_.length===1){s.push(_[0]),h.setCurrentInput(""),i("idle");return}}const b=g(m);if(b.type==="word"){k.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",b),s.push(b),h.setCurrentInput(""),i("idle");return}},[g,n,d,r,s,e]),w=o.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),i("idle")},[s]),S=o.useCallback((m,h,v)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:b,isEnteringArg:A}=h,_=Se(b);switch(m.key){case"Backspace":return b===""&&(m.preventDefault(),s.size()>0&&s.pop(),i("idle")),!0;case"Enter":{if(m.preventDefault(),_.isQuoted&&!_.isComplete)return!0;if(r==="entering_argument"||A&&b.trim()){const D=d();D instanceof U&&(D.value=b,k.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",D),s.push(D))}const E=s.path(),ne=e.getCommand(E);if(!ne)return!1;const K=ne.segments.filter(D=>D.type==="argument"),se=s.arguments;return K.length>se.length?!1:(k.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),v.executeCommand(),t.addStoredCommand(s.toArray()),w(v),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const E=await t.navigateHistory("up");return E.segments&&(s.clear(),s.pushAll(E.segments),v.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const E=await t.navigateHistory("down");return E.segments&&(s.clear(),s.pushAll(E.segments),v.setCurrentInput("")),!0})();default:{if(!A&&m.key.length===1){const E=b+m.key;if(!p(E))return m.preventDefault(),!1}return!0}}},[r,p,d,t,w,e,s]);return{handleInputChange:x,handleKeyDown:S,inputState:r,setInputStateWithLogging:i,findMatchingCommands:u,getAutocompleteSuggestion:y,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function Se(n){const e=[];let t="",s=!1,r;for(let a=0;a<n.length;a++){const i=n[a];(i==='"'||i==="'")&&(!s||i===r)?s?(e.push(t),t="",s=!1,r=void 0):(t&&(e.push(t),t=""),s=!0,r=i):!s&&i===" "?t&&(e.push(t),t=""):t+=i}return{words:e,currentWord:t,isQuoted:s,quoteChar:r,isComplete:!s&&!t}}const Be=()=>{const n=W(),[e,t]=o.useState(0);return o.useEffect(()=>{const s={update:()=>{t(r=>r+1)}};return n.subscribe(s),()=>{n.unsubscribe(s)}},[n]),e},Ve=({state:n,actions:e})=>{const t=o.useRef(null),s=V(),r=W(),{handleKeyDown:a,handleInputChange:i,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Ke(),[y,p]=o.useState(!1),g=T(),x=Be(),w=o.useRef(null),[S,m]=o.useState(0),h=o.useMemo(()=>J(g.fontFamily,g.fontSize),[g.fontFamily,g.fontSize]),v=o.useCallback(async N=>{const P=a(N,n,e);await Promise.resolve(P)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,a,n]),H=o.useCallback(N=>{i(N.target.value,e)},[e,i]),b=o.useCallback(N=>{N.preventDefault();const P=N.clipboardData.getData("text");i(P,e)},[e,i]);o.useEffect(()=>{t.current&&t.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),o.useEffect(()=>{if(d!=="idle")return;const N=u();let P="idle";switch(N.type){case"word":P="entering_command",e.setIsEnteringArg(!1);break;case"argument":P="entering_argument",e.setIsEnteringArg(!0);break}l(P)},[x,d,u,l,e]);const A=o.useMemo(()=>{const N=[],P=r.toArray().map((F,re)=>{N.push(F.name);const Ie=s.hasNextSegment(N);if(F.type==="argument"){const oe=F;return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:oe.value}),re<r.size()&&Ie&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+oe.name+oe.value)}return c.jsxs(o.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:F.name}),re<r.size()&&Ie&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+F.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:P},x)]},[x,s,r]),[_,E]=o.useState("");o.useEffect(()=>{const N=u();N.type==="argument"?E(N.name):E("")},[x,u]);const K=!n.isEnteringArg?"is-command-mode":"is-argument-mode",se=o.useMemo(()=>({left:`${S}px`,transition:"left 0.05s ease-out"}),[S]),D=o.useMemo(()=>({type:g.cursorType??I.cursorType,color:g.cursorColor||I.cursorColor,speed:g.cursorSpeed||I.cursorSpeed}),[g.cursorColor,g.cursorSpeed,g.cursorType]);return o.useLayoutEffect(()=>{const N=w.current,P=t.current;if(!N||!P){m(0);return}const F=N.getBoundingClientRect().width;m(Math.max(0,F-P.scrollLeft))},[n.currentInput,K,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[A,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:w,className:`citadel-input-measure ${K}`.trim(),"aria-hidden":"true",children:n.currentInput}),c.jsx("input",{ref:t,type:"text",role:"textbox",value:n.currentInput,onChange:H,onKeyDown:v,onPaste:b,"data-testid":"citadel-command-input",className:`citadel-input-field ${K} ${y?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:_}),c.jsx("div",{className:"citadel-input-cursor",style:se,children:c.jsx(qe,{style:D})})]})]})]})})},Ye=({currentInput:n=""})=>{const e=V(),t=T(),s=W(),r=o.useMemo(()=>J(t.fontFamily,t.fontSize),[t.fontFamily,t.fontSize]),a=n.trim().toLowerCase(),i=e.getMatchingCompletions(s.path(),a);k.debug("[AvailableCommands] nextCommandSegments: ",i);const d=o.useMemo(()=>{const p=[...i],g=m=>m.name.toLowerCase()==="help",x=p.filter(g);return[...p.filter(m=>!g(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...x]},[i]),l=o.useMemo(()=>{const p=new Map;for(const g of d){const x=d.reduce((w,S)=>{if(S===g)return w;let m=0;for(;m<g.name.length&&m<S.name.length&&g.name[m].toLowerCase()===S.name[m].toLowerCase();)m++;return Math.max(w,m+1)},1);p.set(g.name,x)}return p},[d]),u=i.some(p=>p.type==="argument"),y=i[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?i.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:y.name}),y.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",y.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const g=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,g)}),p.name.slice(g)]})},p.name)})})})})},be=({state:n,actions:e,outputRef:t})=>{const r=T().displayMode==="inline",a=o.useMemo(()=>r?{overflow:"hidden"}:void 0,[r]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:a,children:c.jsx($e,{output:n.output,outputRef:t})}),c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Ve,{state:n,actions:e}),c.jsx(Ye,{currentInput:n.isEnteringArg?"":n.currentInput})]})]})},Je=()=>{const[n,e]=o.useState(!1),[t,s]=o.useState(!1),r=T(),[a,i]=o.useState(()=>r.initialHeight||null),d=o.useRef(null),l=o.useRef(null),u=o.useRef(!1),y=o.useRef(0),p=o.useRef(0),{state:g,actions:x}=ee();Fe({onOpen:()=>e(!0),onClose:()=>s(!0),isVisible:n,showCitadelKey:r.showCitadelKey||"."});const w=o.useCallback(H=>{var E;if(!u.current)return;const b=H.clientY-y.current,A=(E=r.maxHeight)!=null&&E.endsWith("vh")?window.innerHeight*parseInt(r.maxHeight,10)/100:parseInt(r.maxHeight||"80vh",10),_=Math.min(Math.max(p.current-b,parseInt(r.minHeight||"200",10)),A);l.current&&(l.current.style.height=`${_}px`,l.current.style.bottom="0",i(`${_}px`))},[r.maxHeight,r.minHeight]),S=o.useCallback(()=>{u.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",S)},[w]),m=o.useCallback(H=>{l.current&&(u.current=!0,y.current=H.clientY,p.current=l.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",w),document.addEventListener("mouseup",S))},[w,S]);o.useEffect(()=>()=>{document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",S)},[w,S]);const h=o.useCallback(()=>{t&&(e(!1),s(!1))},[t]);je({isVisible:n,isClosing:t,onAnimationComplete:h});const v=o.useMemo(()=>({...a?{height:a}:{},maxHeight:r.maxHeight}),[r.maxHeight,a]);return n?c.jsxs("div",{ref:l,className:`panelContainer ${n?"citadel_slideUp":""} ${t?"citadel_slideDown":""}`,style:v,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:m}),c.jsx(be,{state:g,actions:x,outputRef:d})]}):null},te=n=>{if(!n)return;const e=n.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Ge=()=>{const{state:n,actions:e}=ee(),t=T(),s=o.useRef(null),r=o.useMemo(()=>({height:te(t.initialHeight),maxHeight:te(t.maxHeight),minHeight:te(t.minHeight)}),[t.initialHeight,t.maxHeight,t.minHeight]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:r,children:c.jsx(be,{state:n,actions:e,outputRef:s})})},xe=`:host {
|
|
6
|
+
Check the definition of the ${l.join(".")} command and update the return type for its handler.`);b.markSuccess(),o(v=>({...v,output:v.output.map(E=>E.id===y.id?{...E,result:b}:E)}))}catch(p){const f=new Z(p instanceof Error?p.message:"Unknown error");f.markFailure(),o(b=>({...b,output:b.output.map(v=>v.id===y.id?{...v,result:f}:v)}))}},[e,t.commandTimeoutMs,s]),clearHistory:a.useCallback(async()=>{try{await n.clear()}catch(l){console.warn("Failed to clear history:",l)}},[n])};return{state:i,actions:d}},Fe=({onOpen:t,onClose:e,isVisible:n,showCitadelKey:s,closeOnEscape:r})=>{a.useEffect(()=>{const i=o=>{var d,l;!n&&o.key===s&&!["input","textarea"].includes(((l=(d=o.target)==null?void 0:d.tagName)==null?void 0:l.toLowerCase())||"")&&(o.preventDefault(),t()),r&&n&&o.key==="Escape"&&(o.preventDefault(),e())};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[t,e,n,s,r])},Le=200,je=t=>{const{isVisible:e,isClosing:n,onAnimationComplete:s}=t,r=a.useMemo(()=>e?n?"citadel_slideDown":"citadel_slideUp":"",[e,n]);return a.useEffect(()=>{if(!n||!s)return;if(window.matchMedia("(prefers-reduced-motion: reduce)").matches){s();return}const o=setTimeout(()=>{s()},Le);return()=>clearTimeout(o)},[n,s]),{animationClass:r}},Ue=()=>c.jsx("div",{"data-testid":"spinner",className:"citadel-spinner"}),Ce=t=>{const e=t==null?void 0:t.trim();return e||void 0},$e=t=>{const e=Ce(t);return e?{style:{fontSize:e}}:{}},Q=(t,e)=>{const n=Ce(t),r={...$e(e).style};return n&&(r.fontFamily=n),{style:Object.keys(r).length>0?r:void 0}},qe=({command:t,timestamp:e,status:n,fontFamily:s,fontSize:r})=>{const i=a.useMemo(()=>Q(s,r??"0.875rem"),[s,r]);return c.jsxs("div",{className:"citadel-output-line",style:i.style,children:[c.jsxs("span",{className:"citadel-output-command",children:["> ",t.split(" ").map((o,d)=>{const l=o.startsWith("<")&&o.endsWith(">");return c.jsxs("span",{className:l?"citadel-output-command-arg":"citadel-output-command-word",children:[d>0?" ":"",o]},d)})]}),c.jsx("span",{className:"citadel-output-separator",children:"·"}),c.jsx("span",{className:"citadel-output-timestamp",children:e}),n===j.Pending&&c.jsx(Ue,{}),n===j.Success&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-success"}),(n===j.Timeout||n===j.Failure)&&c.jsx("div",{"data-testid":"success-indicator",className:"citadel-status-dot citadel-status-dot-failure"})]})},Ke=({output:t,outputRef:e})=>{const n=T(),s=a.useMemo(()=>Q(n.fontFamily,n.outputFontSize??n.fontSize),[n.fontFamily,n.fontSize,n.outputFontSize]),r=a.useCallback(()=>{if(e.current){const i=e.current;requestAnimationFrame(()=>{i.scrollTop=i.scrollHeight})}},[e]);return a.useEffect(()=>{if(r(),e.current){const i=e.current.getElementsByTagName("img"),o=i[i.length-1];if(o&&!o.complete)return o.addEventListener("load",r),()=>o.removeEventListener("load",r)}},[t,r,e]),c.jsx("div",{ref:e,className:"citadel-output","data-testid":"citadel-command-output",children:t.map(i=>c.jsxs("div",{className:"citadel-output-item",children:[c.jsx(qe,{command:i.command.join(" "),timestamp:new Date(i.timestamp).toLocaleTimeString(),status:i.result.status,fontFamily:n.fontFamily,fontSize:n.fontSize}),c.jsx("div",{className:"citadel-output-content",style:s.style,children:i.result.render()})]},i.id))})},we={blink:{character:"▋",speed:530,color:"#fff"},spin:{character:"⠋",speed:120,color:"#fff"},solid:{character:"▋",speed:0,color:"#fff"},bbs:{character:"|",speed:120,color:"#fff"}},ve=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"],Se=["|","/","-","\\"],We=({style:t={type:"blink"},isValid:e=!0,errorMessage:n})=>{const s=a.useMemo(()=>({...we[t.type],...t}),[t]),[r,i]=a.useState(!0),[o,d]=a.useState(0);a.useEffect(()=>{if(s.speed===0)return;const y=setInterval(()=>{s.type==="blink"?i(p=>!p):["spin","bbs"].includes(s.type)&&d(p=>(p+1)%(s.type==="bbs"?Se.length:ve.length))},s.speed);return()=>clearInterval(y)},[s.type,s.speed]);const l=a.useMemo(()=>({color:e?s.color:"#ff4444",transition:"color 0.15s ease-in-out"}),[e,s.color]),u=()=>!e&&n?"✗":["spin","bbs"].includes(s.type)?(s.type==="bbs"?Se:ve)[o]:s.type==="solid"||r?s.character:" ";return c.jsx("div",{className:"citadel-cursor-wrapper",children:c.jsx("span",{className:`command-cursor ${e?"":"animate-shake"}`,style:l,title:n,children:u()})})};function Be(t,e){switch(e.type){case"set":return x.debug(`[inputStateReducer] InputState changing from ${t} to ${e.state}`),e.state;default:return t}}const Ve=()=>{const{state:t}=ne(),e=J(),n=ye(),s=B(),[r,i]=a.useReducer(Be,"idle"),o=m=>{i({type:"set",state:m})},d=a.useCallback(()=>{const h=e.getCompletions(s.path())[0]||s.nullSegment;return x.debug("[getNextExpectedSegment] ",h),h},[e,s]),l=a.useCallback(()=>e.getCompletionNames(s.path()).map(h=>e.getCommand([...s.path(),h])).filter(h=>h!==void 0),[e,s]),u=a.useCallback((m,h)=>{if(!m)return h;const w=s.path().length;return h.filter(D=>{const S=D.segments[w];return!S||S.type!=="word"?!1:S.name.toLowerCase().startsWith(m.toLowerCase())})},[s]),y=a.useCallback(m=>{const h=e.getUniqueCompletion(s.path(),m);return h&&h.type==="word"?h:s.nullSegment},[e,s]),p=a.useCallback(m=>{const h=s.path(),w=e.getCompletions(h);return w.length===0&&m?!1:w.some(S=>S.type==="argument")?!0:e.getMatchingCompletions(h,m).some(S=>S.type==="word")},[e,s]),f=a.useCallback(m=>{x.debug("[tryAutoComplete] input: ",m);const h=y(m);return!h||h.type==="null"?new te:(x.debug("[tryAutoComplete] result: ",h),h)},[y]),b=a.useCallback((m,h)=>{if(t.history.position!==null)return;h.setCurrentInput(m),x.debug("[useCommandParser][handleInputChange] newValue: ",m);const w=d();if(w.type==="argument"||r==="entering_argument"){const A=be(m);if(A.isQuoted)if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return;else if(A.isComplete){if(!(w instanceof U))return;w.value=m.trim()||"",x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",w),s.push(w),h.setCurrentInput(""),o("idle");return}else return}if(m.endsWith(" ")){const A=m.trim().toLowerCase(),P=e.getCompletions(s.path()).filter(N=>N.type==="word"&&N.name.toLowerCase()===A);if(P.length===1){s.push(P[0]),h.setCurrentInput(""),o("idle");return}}const S=f(m);if(S.type==="word"){x.debug("[useCommandParser][handleInputChange][entering_command] pushing: ",S),s.push(S),h.setCurrentInput(""),o("idle");return}},[f,t,d,r,s,e]),v=a.useCallback(m=>{m.setCurrentInput(""),m.setIsEnteringArg(!1),s.clear(),o("idle")},[s]),E=a.useCallback((m,h,w)=>{if(!(m.key==="Backspace"||m.key==="Enter"||m.key==="ArrowUp"||m.key==="ArrowDown"||m.key==="ArrowLeft"||m.key==="ArrowRight"||m.key==="Escape"||m.key==="Delete"||m.key==="Home"||m.key==="End"||m.key.length===1))return!0;const{currentInput:S,isEnteringArg:A}=h,P=be(S);switch(m.key){case"Backspace":return S===""&&(m.preventDefault(),s.size()>0&&s.pop(),o("idle")),!0;case"Enter":{if(m.preventDefault(),P.isQuoted&&!P.isComplete)return!0;if(r==="entering_argument"||A&&S.trim()){const F=d();F instanceof U&&(F.value=S,x.debug("[handleKeyDown][Enter]['entering_argument'] pushing: ",F),s.push(F))}const N=s.path(),V=e.getCommand(N);if(!V)return!1;const O=V.segments.filter(F=>F.type==="argument"),$=s.arguments;return O.length>$.length?!1:(x.debug("[handleKeyDown][Enter] calling actions.executeCommand. segmentStack: ",s),w.executeCommand(),n.addStoredCommand(s.toArray()),v(w),!0)}case"ArrowUp":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("up");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();case"ArrowDown":return m.preventDefault(),(async()=>{const N=await n.navigateHistory("down");return N.segments&&(s.clear(),s.pushAll(N.segments),w.setCurrentInput("")),!0})();default:{if(!A&&m.key.length===1){const N=S+m.key;if(!p(N))return m.preventDefault(),!1}return!0}}},[r,p,d,n,v,e,s]);return{handleInputChange:b,handleKeyDown:E,inputState:r,setInputStateWithLogging:o,findMatchingCommands:u,getAutocompleteSuggestion:y,getAvailableNodes:l,getNextExpectedSegment:d,isValidCommandInput:p}};function be(t){const e=[];let n="",s=!1,r;for(let i=0;i<t.length;i++){const o=t[i];(o==='"'||o==="'")&&(!s||o===r)?s?(e.push(n),n="",s=!1,r=void 0):(n&&(e.push(n),n=""),s=!0,r=o):!s&&o===" "?n&&(e.push(n),n=""):n+=o}return{words:e,currentWord:n,isQuoted:s,quoteChar:r,isComplete:!s&&!n}}const Ye=()=>{const t=B(),[e,n]=a.useState(0);return a.useEffect(()=>{const s={update:()=>{n(r=>r+1)}};return t.subscribe(s),()=>{t.unsubscribe(s)}},[t]),e},Je=({state:t,actions:e})=>{const n=a.useRef(null),s=J(),r=B(),{handleKeyDown:i,handleInputChange:o,inputState:d,setInputStateWithLogging:l,getNextExpectedSegment:u}=Ve(),[y,p]=a.useState(!1),f=T(),b=Ye(),v=a.useRef(null),[E,m]=a.useState(0),h=a.useMemo(()=>Q(f.fontFamily,f.fontSize),[f.fontFamily,f.fontSize]),w=a.useCallback(async I=>{const M=i(I,t,e);await Promise.resolve(M)===!1&&(p(!0),setTimeout(()=>p(!1),500))},[e,i,t]),D=a.useCallback(I=>{o(I.target.value,e)},[e,o]),S=a.useCallback(I=>{I.preventDefault();const M=I.clipboardData.getData("text");o(M,e)},[e,o]);a.useEffect(()=>{n.current&&n.current.focus(),d!=="entering_command"&&l("entering_command")},[d,l]),a.useEffect(()=>{if(d!=="idle")return;const I=u();let M="idle";switch(I.type){case"word":M="entering_command",e.setIsEnteringArg(!1);break;case"argument":M="entering_argument",e.setIsEnteringArg(!0);break}l(M)},[b,d,u,l,e]);const A=a.useMemo(()=>{const I=[],M=r.toArray().map((L,re)=>{I.push(L.name);const Ae=s.hasNextSegment(I);if(L.type==="argument"){const ae=L;return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-arg",children:ae.value}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space",children:" "})]},"arg-"+ae.name+ae.value)}return c.jsxs(a.Fragment,{children:[c.jsx("span",{className:"citadel-input-segment-word",children:L.name}),re<r.size()&&Ae&&c.jsx("span",{className:"citadel-input-segment-space citadel-input-segment-space-command",children:" "})]},"word-"+L.name)});return[c.jsx("div",{className:"citadel-input-segments","data-testid":"user-input-area",children:M},b)]},[b,s,r]),[P,N]=a.useState("");a.useEffect(()=>{const I=u();I.type==="argument"?N(I.name):N("")},[b,u]);const O=!t.isEnteringArg?"is-command-mode":"is-argument-mode",$=a.useMemo(()=>({left:`${E}px`,transition:"left 0.05s ease-out"}),[E]),F=a.useMemo(()=>({type:f.cursorType??k.cursorType,color:f.cursorColor||k.cursorColor,speed:f.cursorSpeed||k.cursorSpeed}),[f.cursorColor,f.cursorSpeed,f.cursorType]);return a.useLayoutEffect(()=>{const I=v.current,M=n.current;if(!I||!M){m(0);return}const L=I.getBoundingClientRect().width;m(Math.max(0,L-M.scrollLeft))},[t.currentInput,O,h.style]),c.jsx("div",{className:"citadel-input-shell",children:c.jsxs("div",{className:"citadel-input-line",style:h.style,children:[c.jsx("div",{className:"citadel-input-prompt",children:">"}),c.jsxs("div",{className:"citadel-input-row",children:[A,c.jsxs("div",{className:"citadel-input-control",children:[c.jsx("span",{ref:v,className:`citadel-input-measure ${O}`.trim(),"aria-hidden":"true",children:t.currentInput}),c.jsx("input",{ref:n,type:"text",role:"textbox",value:t.currentInput,onChange:D,onKeyDown:w,onPaste:S,"data-testid":"citadel-command-input",className:`citadel-input-field ${O} ${y?"invalid-input-animation":""}`.trim(),spellCheck:!1,autoComplete:"off",placeholder:P}),c.jsx("div",{className:"citadel-input-cursor",style:$,children:c.jsx(We,{style:F})})]})]})]})})},Ge=({currentInput:t=""})=>{const e=J(),n=T(),s=B(),r=a.useMemo(()=>Q(n.fontFamily,n.fontSize),[n.fontFamily,n.fontSize]),i=t.trim().toLowerCase(),o=e.getMatchingCompletions(s.path(),i);x.debug("[AvailableCommands] nextCommandSegments: ",o);const d=a.useMemo(()=>{const p=[...o],f=m=>m.name.toLowerCase()==="help",b=p.filter(f);return[...p.filter(m=>!f(m)).sort((m,h)=>m.name.localeCompare(h.name,void 0,{sensitivity:"base"})),...b]},[o]),l=a.useMemo(()=>{const p=new Map;for(const f of d){const b=d.reduce((v,E)=>{if(E===f)return v;let m=0;for(;m<f.name.length&&m<E.name.length&&f.name[m].toLowerCase()===E.name[m].toLowerCase();)m++;return Math.max(v,m+1)},1);p.set(f.name,b)}return p},[d]),u=o.some(p=>p.type==="argument"),y=o[0];return c.jsx("div",{className:"citadel-available-commands","data-testid":"available-commands",children:c.jsx("div",{className:"citadel-available-commands-content",style:r.style,children:u?o.length>0?c.jsxs(c.Fragment,{children:[c.jsx("span",{className:"citadel-available-next-arg",children:y.name}),y.description&&c.jsxs("span",{className:"citadel-available-next-desc",children:["- ",y.description]})]}):null:c.jsx("div",{className:"citadel-available-chip-list",children:d==null?void 0:d.map(p=>{const f=l.get(p.name)??1;return c.jsx("div",{"data-testid":"available-command-chip",className:"citadel-available-chip",children:c.jsxs("span",{className:"citadel-available-chip-text",children:[c.jsx("strong",{className:"citadel-available-chip-prefix",children:p.name.slice(0,f)}),p.name.slice(f)]})},p.name)})})})})},xe=({state:t,actions:e,outputRef:n})=>{const r=T().displayMode==="inline",i=a.useMemo(()=>r?{overflow:"hidden"}:void 0,[r]);return c.jsxs("div",{className:"innerContainer citadel-tty",children:[c.jsx("div",{className:"citadel-tty-output-pane","data-testid":"citadel-output-pane",style:i,children:c.jsx(Ke,{output:t.output,outputRef:n})}),c.jsxs("div",{className:"citadel-tty-input-region",children:[c.jsx(Je,{state:t,actions:e}),c.jsx(Ge,{currentInput:t.isEnteringArg?"":t.currentInput})]})]})},Qe=()=>{const t=T(),[e,n]=a.useState(()=>t.showOnLoad??!1),[s,r]=a.useState(!1),[i,o]=a.useState(()=>t.initialHeight||null),d=a.useRef(null),l=a.useRef(null),u=a.useRef(!1),y=a.useRef(0),p=a.useRef(0),{state:f,actions:b}=ne(),v=a.useCallback(()=>{r(!1),n(!0)},[]),E=a.useCallback(()=>{r(!0)},[]);Fe({onOpen:v,onClose:E,isVisible:e&&!s,showCitadelKey:t.showCitadelKey||".",closeOnEscape:t.closeOnEscape??!0});const m=a.useCallback(P=>{var $;if(!u.current)return;const N=P.clientY-y.current,V=($=t.maxHeight)!=null&&$.endsWith("vh")?window.innerHeight*parseInt(t.maxHeight,10)/100:parseInt(t.maxHeight||"80vh",10),O=Math.min(Math.max(p.current-N,parseInt(t.minHeight||"200",10)),V);l.current&&(l.current.style.height=`${O}px`,l.current.style.bottom="0",o(`${O}px`))},[t.maxHeight,t.minHeight]),h=a.useCallback(()=>{u.current=!1,document.documentElement.style.userSelect="",document.documentElement.style.webkitUserSelect="",document.documentElement.style.mozUserSelect="",document.documentElement.style.msUserSelect="",document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m]),w=a.useCallback(P=>{l.current&&(u.current=!0,y.current=P.clientY,p.current=l.current.offsetHeight,document.documentElement.style.userSelect="none",document.documentElement.style.webkitUserSelect="none",document.documentElement.style.mozUserSelect="none",document.documentElement.style.msUserSelect="none",document.addEventListener("mousemove",m),document.addEventListener("mouseup",h))},[m,h]);a.useEffect(()=>()=>{document.removeEventListener("mousemove",m),document.removeEventListener("mouseup",h)},[m,h]);const D=a.useCallback(()=>{s&&(n(!1),r(!1))},[s]),{animationClass:S}=je({isVisible:e,isClosing:s,onAnimationComplete:D}),A=a.useMemo(()=>({...i?{height:i}:{},maxHeight:t.maxHeight}),[t.maxHeight,i]);return e?c.jsxs("div",{ref:l,className:`panelContainer ${S}`.trim(),style:A,children:[c.jsx("div",{className:"resizeHandle",onMouseDown:w}),c.jsx(xe,{state:f,actions:b,outputRef:d})]}):null},se=t=>{if(!t)return;const e=t.trim();if(e)return/^\d+(\.\d+)?$/.test(e)?`${e}px`:e},Xe=()=>{const{state:t,actions:e}=ne(),n=T(),s=a.useRef(null),r=a.useMemo(()=>({height:se(n.initialHeight),maxHeight:se(n.maxHeight),minHeight:se(n.minHeight)}),[n.initialHeight,n.maxHeight,n.minHeight]);return c.jsx("div",{className:"inlineContainer","data-testid":"citadel-inline-container",style:r,children:c.jsx(xe,{state:t,actions:e,outputRef:s})})},ke=`:host {
|
|
7
7
|
--citadel-bg: oklch(20.8% 0.042 265.8);
|
|
8
8
|
--citadel-surface: oklch(27.9% 0.041 260);
|
|
9
9
|
--citadel-border: oklch(37.2% 0.044 257.3);
|
|
@@ -17,6 +17,10 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
17
17
|
--citadel-min-height: 200px;
|
|
18
18
|
--citadel-max-height: 80vh;
|
|
19
19
|
--citadel-default-height: 35vh;
|
|
20
|
+
--citadel-panel-enter-duration: 200ms;
|
|
21
|
+
--citadel-panel-exit-duration: 200ms;
|
|
22
|
+
--citadel-panel-enter-easing: cubic-bezier(0.16, 1, 0.3, 1);
|
|
23
|
+
--citadel-panel-exit-easing: cubic-bezier(0.4, 0, 1, 1);
|
|
20
24
|
|
|
21
25
|
display: block;
|
|
22
26
|
pointer-events: auto;
|
|
@@ -76,6 +80,8 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
76
80
|
padding: 0;
|
|
77
81
|
background-color: var(--citadel-bg);
|
|
78
82
|
overflow: hidden;
|
|
83
|
+
transform: translateY(0);
|
|
84
|
+
will-change: transform;
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
.innerContainer {
|
|
@@ -143,11 +149,18 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
.citadel_slideUp {
|
|
146
|
-
animation: citadel_slideUp
|
|
152
|
+
animation: citadel_slideUp var(--citadel-panel-enter-duration) var(--citadel-panel-enter-easing) forwards;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
.citadel_slideDown {
|
|
150
|
-
animation: citadel_slideDown
|
|
156
|
+
animation: citadel_slideDown var(--citadel-panel-exit-duration) var(--citadel-panel-exit-easing) forwards;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@media (prefers-reduced-motion: reduce) {
|
|
160
|
+
:host {
|
|
161
|
+
--citadel-panel-enter-duration: 1ms;
|
|
162
|
+
--citadel-panel-exit-duration: 1ms;
|
|
163
|
+
}
|
|
151
164
|
}
|
|
152
165
|
|
|
153
166
|
.inlineContainer {
|
|
@@ -462,5 +475,5 @@ Check the definition of the ${l.join(".")} command and update the return type fo
|
|
|
462
475
|
object-fit: contain;
|
|
463
476
|
border-radius: 0.5rem;
|
|
464
477
|
}
|
|
465
|
-
`,
|
|
466
|
-
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const
|
|
478
|
+
`,Ze=({config:t=k,commandRegistry:e,containerId:n=null})=>{const s=a.useRef(new K),r=e??s.current,i=a.useRef(null),o=a.useMemo(()=>({width:"100%",height:"100%"}),[]),d=t.displayMode??k.displayMode??"panel";return a.useEffect(()=>{x.configure({level:t.logLevel||k.logLevel||R.ERROR,prefix:"[Citadel]"});const l=new Ee(r,t),u=d==="inline"&&!n,y=u?i.current:n?document.getElementById(n):document.body;if(y)y.appendChild(l);else{if(u){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 p;(p=l.parentElement)==null||p.removeChild(l)}},[r,n,t,d]),d==="inline"&&!n?c.jsx("div",{ref:i,style:o}):null};class Ee extends HTMLElement{constructor(n,s){var i;super();C(this,"shadow");C(this,"root",null);C(this,"commandRegistry");C(this,"config");this.shadow=this.attachShadow({mode:"open"}),this.commandRegistry=n,this.config=s;const r=((i=this.config)==null?void 0:i.displayMode)??"panel";this.setAttribute("data-display-mode",r)}connectedCallback(){try{const s=[ke].map(r=>{const i=new CSSStyleSheet;return i.replaceSync(r),i});this.shadow.adoptedStyleSheets=[...s]}catch{const s=[ke].join(`
|
|
479
|
+
`),r=document.createElement("style");r.textContent=s,this.shadow.appendChild(r)}const n=document.createElement("div");n.id="citadel-root",n.style.width="100%",n.style.height="100%",this.shadow.appendChild(n),this.root=Me.createRoot(n),this.root.render(c.jsx(De,{config:this.config||k,commandRegistry:this.commandRegistry,children:c.jsx(Re,{})}))}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",Ee);const Re=()=>(T().displayMode??"panel")==="inline"?c.jsx(Xe,{}):c.jsx(Qe,{});class et{constructor(){C(this,"_description")}describe(e){return this._description=e,this}get description(){return this._description}}class tt{constructor(e){C(this,"state");this.state={path:e,description:"",segments:nt(e)}}describe(e){return this.state.description=e,this}details(e){return this.state.details=e,this}arg(e,n){const s=new et;return n==null||n(s),this.state.segments.push({type:"argument",name:e,description:s.description}),this}handle(e){return{path:this.state.path,description:this.state.description,details:this.state.details,segments:[...this.state.segments],handler:e}}}function nt(t){const e=t.trim();if(!e)throw new Error("Command path cannot be empty");const n=e.split(".");if(n.some(s=>s.trim()===""))throw new Error(`Invalid command path "${t}". Empty segments are not allowed.`);if(n.some(s=>s.includes(" ")))throw new Error(`Invalid command path "${t}". Use dot-delimited words (e.g. "user.show").`);return n.map(s=>({type:"word",name:s}))}function st(t){return t.flatMap(e=>e.type==="argument"?[e.name]:[])}function rt(t){const e=st(t.segments);return async n=>{const s=e.reduce((r,i,o)=>(r[i]=n[o],r),{});return Promise.resolve(t.handler({rawArgs:n,namedArgs:s,commandPath:t.path}))}}function at(t){return new tt(t)}function Ne(t,e){t.addCommand(e.segments,e.description,rt(e))}function Ie(t,e){return e.forEach(n=>Ne(t,n)),t}function ot(t){const e=new K;return Ie(e,t)}function it(t){return new q(t)}function lt(t,e="true",n="false"){return new ie(t,e,n)}function ct(t){return new oe(t)}function dt(t,e=""){return new ce(t,e)}function mt(t){return new Z(t)}g.BooleanCommandResult=ie,g.Citadel=Ze,g.CommandRegistry=K,g.CommandResult=_,g.CommandStatus=j,g.DEFAULT_CURSOR_CONFIGS=we,g.ErrorCommandResult=Z,g.ImageCommandResult=ce,g.JsonCommandResult=oe,g.OutputItem=G,g.PendingCommandResult=le,g.TextCommandResult=q,g.bool=lt,g.command=at,g.createCommandRegistry=ot,g.error=mt,g.image=dt,g.json=ct,g.registerCommand=Ne,g.registerCommands=Ie,g.text=it,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -31,8 +31,12 @@ import { CitadelConfig } from './types';
|
|
|
31
31
|
* @property resetStateOnHide - When true, hiding the interface (via Escape key or other means) will clear the command input.
|
|
32
32
|
* When false, the interface preserves the last input when hidden. Default: false.
|
|
33
33
|
*
|
|
34
|
+
* @property closeOnEscape - When true, pressing Escape hides the panel in panel mode. Default: true.
|
|
35
|
+
*
|
|
34
36
|
* @property showCitadelKey - The keyboard key that shows the command interface. Default: '.' (period).
|
|
35
37
|
*
|
|
38
|
+
* @property showOnLoad - When true, panel mode starts visible on mount. Default: false.
|
|
39
|
+
*
|
|
36
40
|
* @property storage - Configuration for command history storage. Default: { type: 'localStorage', maxCommands: 100 }.
|
|
37
41
|
*/
|
|
38
42
|
export declare const defaultConfig: CitadelConfig;
|
|
@@ -69,10 +69,20 @@ export interface CitadelConfig {
|
|
|
69
69
|
* Whether to reset the state when the interface is hidden (via Escape key or other means).
|
|
70
70
|
*/
|
|
71
71
|
resetStateOnHide?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Whether to keep Escape from closing the panel in `displayMode: 'panel'`.
|
|
74
|
+
* Defaults to `true`.
|
|
75
|
+
*/
|
|
76
|
+
closeOnEscape?: boolean;
|
|
72
77
|
/**
|
|
73
78
|
* The keyboard key that shows the command interface.
|
|
74
79
|
*/
|
|
75
80
|
showCitadelKey?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Whether to show the panel immediately on mount when `displayMode: 'panel'`.
|
|
83
|
+
* Defaults to `false`.
|
|
84
|
+
*/
|
|
85
|
+
showOnLoad?: boolean;
|
|
76
86
|
/**
|
|
77
87
|
* Presentation mode for rendering the Citadel interface.
|
|
78
88
|
* - 'panel': Renders as an overlay panel anchored to the viewport bottom and toggled via keyboard shortcuts.
|
|
@@ -3,6 +3,7 @@ interface UseGlobalShortcutProps {
|
|
|
3
3
|
onClose: () => void;
|
|
4
4
|
isVisible: boolean;
|
|
5
5
|
showCitadelKey: string;
|
|
6
|
+
closeOnEscape: boolean;
|
|
6
7
|
}
|
|
7
|
-
export declare const useGlobalShortcut: ({ onOpen, onClose, isVisible, showCitadelKey }: UseGlobalShortcutProps) => void;
|
|
8
|
+
export declare const useGlobalShortcut: ({ onOpen, onClose, isVisible, showCitadelKey, closeOnEscape }: UseGlobalShortcutProps) => void;
|
|
8
9
|
export {};
|
|
@@ -3,12 +3,8 @@ interface SlideAnimationOptions {
|
|
|
3
3
|
isClosing: boolean;
|
|
4
4
|
onAnimationComplete?: () => void;
|
|
5
5
|
}
|
|
6
|
+
export declare const PANEL_CLOSE_DURATION_MS = 200;
|
|
6
7
|
export declare const useSlideAnimation: (options: SlideAnimationOptions) => {
|
|
7
|
-
style: {
|
|
8
|
-
opacity: number;
|
|
9
|
-
transform: string;
|
|
10
|
-
transition: string;
|
|
11
|
-
};
|
|
12
8
|
animationClass: string;
|
|
13
9
|
};
|
|
14
10
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CommandRegistry, CommandSegment } from './command-registry';
|
|
2
|
-
import { CommandResult, ErrorCommandResult, ImageCommandResult, JsonCommandResult, TextCommandResult } from './command-results';
|
|
2
|
+
import { BooleanCommandResult, CommandResult, ErrorCommandResult, ImageCommandResult, JsonCommandResult, TextCommandResult } from './command-results';
|
|
3
3
|
export interface CommandExecutionContext<ArgName extends string = string> {
|
|
4
4
|
rawArgs: string[];
|
|
5
5
|
namedArgs: Record<ArgName, string | undefined>;
|
|
@@ -27,6 +27,7 @@ export declare function registerCommand(registry: CommandRegistry, definition: C
|
|
|
27
27
|
export declare function registerCommands(registry: CommandRegistry, definitions: CommandDefinition[]): CommandRegistry;
|
|
28
28
|
export declare function createCommandRegistry(definitions: CommandDefinition[]): CommandRegistry;
|
|
29
29
|
export declare function text(value: string): TextCommandResult;
|
|
30
|
+
export declare function bool(value: boolean, trueText?: string, falseText?: string): BooleanCommandResult;
|
|
30
31
|
export declare function json(value: unknown): JsonCommandResult;
|
|
31
32
|
export declare function image(url: string, altText?: string): ImageCommandResult;
|
|
32
33
|
export declare function error(value: string): ErrorCommandResult;
|
|
@@ -25,6 +25,13 @@ export declare class TextCommandResult extends CommandResult {
|
|
|
25
25
|
constructor(text: string, timestamp?: number);
|
|
26
26
|
render(): React.ReactNode;
|
|
27
27
|
}
|
|
28
|
+
export declare class BooleanCommandResult extends CommandResult {
|
|
29
|
+
readonly value: boolean;
|
|
30
|
+
readonly trueText: string;
|
|
31
|
+
readonly falseText: string;
|
|
32
|
+
constructor(value: boolean, trueText?: string, falseText?: string, timestamp?: number);
|
|
33
|
+
render(): React.ReactNode;
|
|
34
|
+
}
|
|
28
35
|
export declare class ErrorCommandResult extends CommandResult {
|
|
29
36
|
readonly error: string;
|
|
30
37
|
constructor(error: string, timestamp?: number);
|
package/package.json
CHANGED
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/jchilders/citadel_cli.git"
|
|
19
19
|
},
|
|
20
|
-
"version": "1.4.
|
|
20
|
+
"version": "1.4.1",
|
|
21
21
|
"type": "module",
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "tsc && vite build",
|
|
23
|
+
"build": "tsc && vite build && node scripts/sync-package-artifacts.mjs",
|
|
24
|
+
"verify:pack": "node scripts/verify-package-artifacts.mjs",
|
|
24
25
|
"dev": "vite",
|
|
25
26
|
"lint": "eslint .",
|
|
26
27
|
"lint:fix": "eslint . --fix",
|