@markdstage/markdstage 0.1.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 +90 -0
- package/bin/markdstage.mjs +12 -0
- package/package.json +45 -0
- package/shared/README.md +1014 -0
- package/shared/THIRD-PARTY-NOTICES.md +19 -0
- package/shared/deck-state.mjs +105 -0
- package/shared/docs/custom-theme-authoring.md +208 -0
- package/shared/markdown-deck.mjs +220 -0
- package/shared/markdstage-guide.mjs +276 -0
- package/shared/presenter-window.mjs +17 -0
- package/shared/renderer/architecture-document.mjs +596 -0
- package/shared/renderer/architecture-edit.mjs +298 -0
- package/shared/renderer/architecture-editor.mjs +449 -0
- package/shared/renderer/architecture.mjs +4033 -0
- package/shared/renderer/import-path.mjs +11 -0
- package/shared/renderer/index.html +106 -0
- package/shared/renderer/renderer.js +2082 -0
- package/shared/renderer/slides.css +614 -0
- package/shared/renderer/speaker-notes.mjs +106 -0
- package/shared/renderer/theme.mjs +205 -0
- package/shared/runtime/browser.mjs +539 -0
- package/shared/runtime/custom-theme.mjs +135 -0
- package/shared/runtime/deck-session.mjs +188 -0
- package/shared/runtime/errors.mjs +17 -0
- package/shared/runtime/output-paths.mjs +159 -0
- package/shared/runtime/output.mjs +385 -0
- package/shared/runtime/presentation-server.mjs +505 -0
- package/shared/runtime/static-files.mjs +70 -0
- package/shared/schema/README.md +228 -0
- package/shared/schema/architecture-v1.schema.json +664 -0
- package/shared/schema/examples/web-app.architecture.json +119 -0
- package/shared/schema/theme-metadata-v1.schema.json +75 -0
- package/shared/schema/theme-v1.json +84 -0
- package/shared/scripts/architecture-assets.mjs +226 -0
- package/shared/scripts/asset-paths.mjs +92 -0
- package/shared/scripts/atomic-markdown-replace.mjs +46 -0
- package/shared/scripts/markdown-blocks.mjs +182 -0
- package/shared/scripts/markdown-files.mjs +63 -0
- package/shared/scripts/markdown-save-coordinator.mjs +18 -0
- package/shared/scripts/markdown-watcher.mjs +80 -0
- package/shared/scripts/theme-paths.mjs +108 -0
- package/shared/scripts/vendor-assets.mjs +132 -0
- package/shared/scripts/workspace-root.mjs +32 -0
- package/shared/vendor/highlight.LICENSE +29 -0
- package/shared/vendor/highlight.min.js +1244 -0
- package/shared/vendor/marked.min.js +6 -0
- package/shared/vendor/mermaid.min.js.part-0001 +268 -0
- package/shared/vendor/mermaid.min.js.part-0002 +304 -0
- package/shared/vendor/mermaid.min.js.part-0003 +324 -0
- package/shared/vendor/mermaid.min.js.part-0004 +374 -0
- package/shared/vendor/mermaid.min.js.part-0005 +564 -0
- package/shared/vendor/mermaid.min.js.part-0006 +1308 -0
- package/shared/vendor/mermaid.min.js.part-0007 +269 -0
- package/shared/vendor/purify.min.js +3 -0
- package/shared/vendor/vendor-assets.lock.json +60 -0
- package/src/cli.mjs +347 -0
- package/src/commands/capture.mjs +23 -0
- package/src/commands/export.mjs +18 -0
- package/src/commands/guide.mjs +23 -0
- package/src/commands/inspect.mjs +35 -0
- package/src/commands/present.mjs +91 -0
- package/src/commands/skill.mjs +114 -0
- package/src/commands/validate.mjs +79 -0
- package/src/deck.mjs +63 -0
- package/src/exit.mjs +58 -0
- package/src/runtime.mjs +77 -0
- package/src/skills.mjs +155 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! @license DOMPurify 3.1.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.7/LICENSE */
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=b(Array.prototype.forEach),m=b(Array.prototype.pop),p=b(Array.prototype.push),f=b(String.prototype.toLowerCase),d=b(String.prototype.toString),h=b(String.prototype.match),g=b(String.prototype.replace),T=b(String.prototype.indexOf),y=b(String.prototype.trim),E=b(Object.prototype.hasOwnProperty),_=b(RegExp.prototype.test),A=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return s(N,t)});var N;function b(e){return function(t){for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return c(e,t,o)}}function S(e,o){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:f;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function R(e){for(let t=0;t<e.length;t++){E(e,t)||(e[t]=null)}return e}function w(t){const n=l(null);for(const[o,r]of e(t)){E(t,o)&&(Array.isArray(r)?n[o]=R(r):r&&"object"==typeof r&&r.constructor===Object?n[o]=w(r):n[o]=r)}return n}function C(e,t){for(;null!==e;){const n=r(e,t);if(n){if(n.get)return b(n.get);if("function"==typeof n.value)return b(n.value)}e=o(e)}return function(){return null}}const L=i(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),v=i(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),D=i(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),O=i(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),x=i(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),k=i(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),M=i(["#text"]),I=i(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns","slot"]),U=i(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),P=i(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),F=i(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),H=a(/\{\{[\w\W]*|[\w\W]*\}\}/gm),z=a(/<%[\w\W]*|[\w\W]*%>/gm),B=a(/\${[\w\W]*}/gm),W=a(/^data-[\-\w.\u00B7-\uFFFF]/),G=a(/^aria-[\-\w]+$/),Y=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),j=a(/^(?:\w+script|data):/i),X=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),q=a(/^html$/i),$=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var K=Object.freeze({__proto__:null,MUSTACHE_EXPR:H,ERB_EXPR:z,TMPLIT_EXPR:B,DATA_ATTR:W,ARIA_ATTR:G,IS_ALLOWED_URI:Y,IS_SCRIPT_OR_DATA:j,ATTR_WHITESPACE:X,DOCTYPE_NAME:q,CUSTOM_ELEMENT:$});const V=1,Z=3,J=7,Q=8,ee=9,te=function(){return"undefined"==typeof window?null:window};var ne=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:te();const o=e=>t(e);if(o.version="3.1.7",o.removed=[],!n||!n.document||n.document.nodeType!==ee)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:b,Element:R,NodeFilter:H,NamedNodeMap:z=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:B,DOMParser:W,trustedTypes:G}=n,j=R.prototype,X=C(j,"cloneNode"),$=C(j,"remove"),ne=C(j,"nextSibling"),oe=C(j,"childNodes"),re=C(j,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let ie,ae="";const{implementation:le,createNodeIterator:ce,createDocumentFragment:se,getElementsByTagName:ue}=r,{importNode:me}=a;let pe={};o.isSupported="function"==typeof e&&"function"==typeof re&&le&&void 0!==le.createHTMLDocument;const{MUSTACHE_EXPR:fe,ERB_EXPR:de,TMPLIT_EXPR:he,DATA_ATTR:ge,ARIA_ATTR:Te,IS_SCRIPT_OR_DATA:ye,ATTR_WHITESPACE:Ee,CUSTOM_ELEMENT:_e}=K;let{IS_ALLOWED_URI:Ae}=K,Ne=null;const be=S({},[...L,...v,...D,...x,...M]);let Se=null;const Re=S({},[...I,...U,...P,...F]);let we=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ce=null,Le=null,ve=!0,De=!0,Oe=!1,xe=!0,ke=!1,Me=!0,Ie=!1,Ue=!1,Pe=!1,Fe=!1,He=!1,ze=!1,Be=!0,We=!1,Ge=!0,Ye=!1,je={},Xe=null;const qe=S({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let $e=null;const Ke=S({},["audio","video","img","source","image","track"]);let Ve=null;const Ze=S({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Je="http://www.w3.org/1998/Math/MathML",Qe="http://www.w3.org/2000/svg",et="http://www.w3.org/1999/xhtml";let tt=et,nt=!1,ot=null;const rt=S({},[Je,Qe,et],d);let it=null;const at=["application/xhtml+xml","text/html"];let lt=null,ct=null;const st=r.createElement("form"),ut=function(e){return e instanceof RegExp||e instanceof Function},mt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ct||ct!==e){if(e&&"object"==typeof e||(e={}),e=w(e),it=-1===at.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,lt="application/xhtml+xml"===it?d:f,Ne=E(e,"ALLOWED_TAGS")?S({},e.ALLOWED_TAGS,lt):be,Se=E(e,"ALLOWED_ATTR")?S({},e.ALLOWED_ATTR,lt):Re,ot=E(e,"ALLOWED_NAMESPACES")?S({},e.ALLOWED_NAMESPACES,d):rt,Ve=E(e,"ADD_URI_SAFE_ATTR")?S(w(Ze),e.ADD_URI_SAFE_ATTR,lt):Ze,$e=E(e,"ADD_DATA_URI_TAGS")?S(w(Ke),e.ADD_DATA_URI_TAGS,lt):Ke,Xe=E(e,"FORBID_CONTENTS")?S({},e.FORBID_CONTENTS,lt):qe,Ce=E(e,"FORBID_TAGS")?S({},e.FORBID_TAGS,lt):{},Le=E(e,"FORBID_ATTR")?S({},e.FORBID_ATTR,lt):{},je=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,ve=!1!==e.ALLOW_ARIA_ATTR,De=!1!==e.ALLOW_DATA_ATTR,Oe=e.ALLOW_UNKNOWN_PROTOCOLS||!1,xe=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Me=!1!==e.SAFE_FOR_XML,Ie=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,He=e.RETURN_DOM_FRAGMENT||!1,ze=e.RETURN_TRUSTED_TYPE||!1,Pe=e.FORCE_BODY||!1,Be=!1!==e.SANITIZE_DOM,We=e.SANITIZE_NAMED_PROPS||!1,Ge=!1!==e.KEEP_CONTENT,Ye=e.IN_PLACE||!1,Ae=e.ALLOWED_URI_REGEXP||Y,tt=e.NAMESPACE||et,we=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(we.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(we.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(we.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(De=!1),He&&(Fe=!0),je&&(Ne=S({},M),Se=[],!0===je.html&&(S(Ne,L),S(Se,I)),!0===je.svg&&(S(Ne,v),S(Se,U),S(Se,F)),!0===je.svgFilters&&(S(Ne,D),S(Se,U),S(Se,F)),!0===je.mathMl&&(S(Ne,x),S(Se,P),S(Se,F))),e.ADD_TAGS&&(Ne===be&&(Ne=w(Ne)),S(Ne,e.ADD_TAGS,lt)),e.ADD_ATTR&&(Se===Re&&(Se=w(Se)),S(Se,e.ADD_ATTR,lt)),e.ADD_URI_SAFE_ATTR&&S(Ve,e.ADD_URI_SAFE_ATTR,lt),e.FORBID_CONTENTS&&(Xe===qe&&(Xe=w(Xe)),S(Xe,e.FORBID_CONTENTS,lt)),Ge&&(Ne["#text"]=!0),Ie&&S(Ne,["html","head","body"]),Ne.table&&(S(Ne,["tbody"]),delete Ce.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ie=e.TRUSTED_TYPES_POLICY,ae=ie.createHTML("")}else void 0===ie&&(ie=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(G,c)),null!==ie&&"string"==typeof ae&&(ae=ie.createHTML(""));i&&i(e),ct=e}},pt=S({},["mi","mo","mn","ms","mtext"]),ft=S({},["annotation-xml"]),dt=S({},["title","style","font","a","script"]),ht=S({},[...v,...D,...O]),gt=S({},[...x,...k]),Tt=function(e){p(o.removed,{element:e});try{re(e).removeChild(e)}catch(t){$(e)}},yt=function(e,t){try{p(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Se[e])if(Fe||He)try{Tt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Et=function(e){let t=null,n=null;if(Pe)e="<remove></remove>"+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===it&&tt===et&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=ie?ie.createHTML(e):e;if(tt===et)try{t=(new W).parseFromString(o,it)}catch(e){}if(!t||!t.documentElement){t=le.createDocument(tt,"template",null);try{t.documentElement.innerHTML=nt?ae:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),tt===et?ue.call(t,Ie?"html":"body")[0]:Ie?t.documentElement:i},_t=function(e){return ce.call(e.ownerDocument||e,e,H.SHOW_ELEMENT|H.SHOW_COMMENT|H.SHOW_TEXT|H.SHOW_PROCESSING_INSTRUCTION|H.SHOW_CDATA_SECTION,null)},At=function(e){return e instanceof B&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof z)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof b&&e instanceof b},bt=function(e,t,n){pe[e]&&u(pe[e],(e=>{e.call(o,t,n,ct)}))},St=function(e){let t=null;if(bt("beforeSanitizeElements",e,null),At(e))return Tt(e),!0;const n=lt(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ne}),e.hasChildNodes()&&!Nt(e.firstElementChild)&&_(/<[/\w]/g,e.innerHTML)&&_(/<[/\w]/g,e.textContent))return Tt(e),!0;if(e.nodeType===J)return Tt(e),!0;if(Me&&e.nodeType===Q&&_(/<[/\w]/g,e.data))return Tt(e),!0;if(!Ne[n]||Ce[n]){if(!Ce[n]&&wt(n)){if(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n))return!1;if(we.tagNameCheck instanceof Function&&we.tagNameCheck(n))return!1}if(Ge&&!Xe[n]){const t=re(e)||e.parentNode,n=oe(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=X(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,ne(e))}}}return Tt(e),!0}return e instanceof R&&!function(e){let t=re(e);t&&t.tagName||(t={namespaceURI:tt,tagName:"template"});const n=f(e.tagName),o=f(t.tagName);return!!ot[e.namespaceURI]&&(e.namespaceURI===Qe?t.namespaceURI===et?"svg"===n:t.namespaceURI===Je?"svg"===n&&("annotation-xml"===o||pt[o]):Boolean(ht[n]):e.namespaceURI===Je?t.namespaceURI===et?"math"===n:t.namespaceURI===Qe?"math"===n&&ft[o]:Boolean(gt[n]):e.namespaceURI===et?!(t.namespaceURI===Qe&&!ft[o])&&!(t.namespaceURI===Je&&!pt[o])&&!gt[n]&&(dt[n]||!ht[n]):!("application/xhtml+xml"!==it||!ot[e.namespaceURI]))}(e)?(Tt(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!_(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Z&&(t=e.textContent,u([fe,de,he],(e=>{t=g(t,e," ")})),e.textContent!==t&&(p(o.removed,{element:e.cloneNode()}),e.textContent=t)),bt("afterSanitizeElements",e,null),!1):(Tt(e),!0)},Rt=function(e,t,n){if(Be&&("id"===t||"name"===t)&&(n in r||n in st))return!1;if(De&&!Le[t]&&_(ge,t));else if(ve&&_(Te,t));else if(!Se[t]||Le[t]){if(!(wt(e)&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,e)||we.tagNameCheck instanceof Function&&we.tagNameCheck(e))&&(we.attributeNameCheck instanceof RegExp&&_(we.attributeNameCheck,t)||we.attributeNameCheck instanceof Function&&we.attributeNameCheck(t))||"is"===t&&we.allowCustomizedBuiltInElements&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n)||we.tagNameCheck instanceof Function&&we.tagNameCheck(n))))return!1}else if(Ve[t]);else if(_(Ae,g(n,Ee,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!$e[e]){if(Oe&&!_(ye,g(n,Ee,"")));else if(n)return!1}else;return!0},wt=function(e){return"annotation-xml"!==e&&h(e,_e)},Ct=function(e){bt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Se};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=lt(a);let p="value"===a?c:y(c);if(n.attrName=s,n.attrValue=p,n.keepAttr=!0,n.forceKeepAttr=void 0,bt("uponSanitizeAttribute",e,n),p=n.attrValue,n.forceKeepAttr)continue;if(yt(a,e),!n.keepAttr)continue;if(!xe&&_(/\/>/i,p)){yt(a,e);continue}ke&&u([fe,de,he],(e=>{p=g(p,e," ")}));const f=lt(e.nodeName);if(Rt(f,s,p))if(!We||"id"!==s&&"name"!==s||(yt(a,e),p="user-content-"+p),Me&&_(/((--!?|])>)|<\/(style|title)/i,p))yt(a,e);else{if(ie&&"object"==typeof G&&"function"==typeof G.getAttributeType)if(l);else switch(G.getAttributeType(f,s)){case"TrustedHTML":p=ie.createHTML(p);break;case"TrustedScriptURL":p=ie.createScriptURL(p)}try{l?e.setAttributeNS(l,a,p):e.setAttribute(a,p),At(e)?Tt(e):m(o.removed)}catch(e){}}}bt("afterSanitizeAttributes",e,null)},Lt=function e(t){let n=null;const o=_t(t);for(bt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)bt("uponSanitizeShadowNode",n,null),St(n)||(n.content instanceof s&&e(n.content),Ct(n));bt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(nt=!e,nt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Ue||mt(t),o.removed=[],"string"==typeof e&&(Ye=!1),Ye){if(e.nodeName){const t=lt(e.nodeName);if(!Ne[t]||Ce[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof b)n=Et("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===V&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!Ie&&-1===e.indexOf("<"))return ie&&ze?ie.createHTML(e):e;if(n=Et(e),!n)return Fe?null:ze?ae:""}n&&Pe&&Tt(n.firstChild);const c=_t(Ye?e:n);for(;i=c.nextNode();)St(i)||(i.content instanceof s&&Lt(i.content),Ct(i));if(Ye)return e;if(Fe){if(He)for(l=se.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Se.shadowroot||Se.shadowrootmode)&&(l=me.call(a,l,!0)),l}let m=Ie?n.outerHTML:n.innerHTML;return Ie&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&_(q,n.ownerDocument.doctype.name)&&(m="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+m),ke&&u([fe,de,he],(e=>{m=g(m,e," ")})),ie&&ze?ie.createHTML(m):m},o.setConfig=function(){mt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ue=!0},o.clearConfig=function(){ct=null,Ue=!1},o.isValidAttribute=function(e,t,n){ct||mt({});const o=lt(e),r=lt(t);return Rt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(pe[e]=pe[e]||[],p(pe[e],t))},o.removeHook=function(e){if(pe[e])return m(pe[e])},o.removeHooks=function(e){pe[e]&&(pe[e]=[])},o.removeAllHooks=function(){pe={}},o}();return ne}));
|
|
3
|
+
//# sourceMappingURL=purify.min.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"chunkSize": 524288,
|
|
4
|
+
"assets": {
|
|
5
|
+
"mermaid.min.js": {
|
|
6
|
+
"source": "mermaid.min.js",
|
|
7
|
+
"size": 3312967,
|
|
8
|
+
"sha256": "70137e77bb273bb2ef972b86e8b0400cca8be53cb25bfc45911a186dc98665de",
|
|
9
|
+
"upstream": {
|
|
10
|
+
"name": "mermaid",
|
|
11
|
+
"version": "11.15.0",
|
|
12
|
+
"source": "https://www.npmjs.com/package/mermaid"
|
|
13
|
+
},
|
|
14
|
+
"chunks": [
|
|
15
|
+
{
|
|
16
|
+
"index": 1,
|
|
17
|
+
"file": "mermaid.min.js.part-0001",
|
|
18
|
+
"size": 524288,
|
|
19
|
+
"sha256": "edc857bf8ad368bf97ff5848dd0439461f2460ac53b58b1f6cc4d8493449aac5"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"index": 2,
|
|
23
|
+
"file": "mermaid.min.js.part-0002",
|
|
24
|
+
"size": 524288,
|
|
25
|
+
"sha256": "8c7a9e27ba496d04d25c1c9716185aaf9d5ae3ef6d093a5783a6306ac8c8d03f"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"index": 3,
|
|
29
|
+
"file": "mermaid.min.js.part-0003",
|
|
30
|
+
"size": 524288,
|
|
31
|
+
"sha256": "ef79bb7da99d7a3ce848e29df40de09ee6cca03e3b15101dd6d93080655a33cd"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"index": 4,
|
|
35
|
+
"file": "mermaid.min.js.part-0004",
|
|
36
|
+
"size": 524288,
|
|
37
|
+
"sha256": "10919790fa99d83917114b343a310d3faee9e4e6c2614c97a5c0c454f3419471"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"index": 5,
|
|
41
|
+
"file": "mermaid.min.js.part-0005",
|
|
42
|
+
"size": 524288,
|
|
43
|
+
"sha256": "98354d583d9d126593f79154e6f318c8e43ae8644b21bbef9290c91469874ae5"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"index": 6,
|
|
47
|
+
"file": "mermaid.min.js.part-0006",
|
|
48
|
+
"size": 524288,
|
|
49
|
+
"sha256": "a90f197efc189debeb94d59c848f6317c785183f0473ddad14d2fe5657979612"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"index": 7,
|
|
53
|
+
"file": "mermaid.min.js.part-0007",
|
|
54
|
+
"size": 167239,
|
|
55
|
+
"sha256": "a5f4e5d4bc208e7258bbc408dfcd9cb48599da8c34e46866b4655d4c1512907f"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/cli.mjs
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
// MarkdStage CLI entry point.
|
|
2
|
+
//
|
|
3
|
+
// Commands are parsed with node:util.parseArgs so the package keeps no runtime
|
|
4
|
+
// npm dependencies. Every command shares the runtime modules that the Canvas
|
|
5
|
+
// Extension uses, so output is identical in both environments.
|
|
6
|
+
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import { parseArgs } from "node:util";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { dirname, resolve } from "node:path";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
EXIT_CODES,
|
|
14
|
+
EXIT_DECK,
|
|
15
|
+
EXIT_FAILURE,
|
|
16
|
+
EXIT_ISSUES,
|
|
17
|
+
EXIT_OK,
|
|
18
|
+
EXIT_USAGE,
|
|
19
|
+
UsageError,
|
|
20
|
+
errorPayload,
|
|
21
|
+
exitCodeFor,
|
|
22
|
+
} from "./exit.mjs";
|
|
23
|
+
import { parsePageList } from "./deck.mjs";
|
|
24
|
+
import { presentCommand } from "./commands/present.mjs";
|
|
25
|
+
import { validateCommand, formatValidateReport } from "./commands/validate.mjs";
|
|
26
|
+
import { inspectCommand, formatInspectReport } from "./commands/inspect.mjs";
|
|
27
|
+
import { captureCommand, formatCaptureReport } from "./commands/capture.mjs";
|
|
28
|
+
import { exportCommand, formatExportReport } from "./commands/export.mjs";
|
|
29
|
+
import { guideCommand, GUIDE_TOPICS } from "./commands/guide.mjs";
|
|
30
|
+
import {
|
|
31
|
+
skillCommand,
|
|
32
|
+
formatSkillReport,
|
|
33
|
+
SKILL_TARGET_NAMES,
|
|
34
|
+
} from "./commands/skill.mjs";
|
|
35
|
+
|
|
36
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
37
|
+
|
|
38
|
+
const COMMANDS = [
|
|
39
|
+
["present", "Serve a deck on loopback and open it in a browser window."],
|
|
40
|
+
["validate", "Check deck structure, Architecture DSL blocks, and themes."],
|
|
41
|
+
["inspect", "Report 1280x720 clipping diagnostics for a deck."],
|
|
42
|
+
["capture", "Write 1280x720 PNG files for selected or clipped slides."],
|
|
43
|
+
["export", "Export the deck as a 16:9 PDF."],
|
|
44
|
+
["guide", "Print the canonical MarkdStage authoring guide."],
|
|
45
|
+
["skill", "Install or check the portable MarkdStage Agent Skills."],
|
|
46
|
+
["help", "Show help for MarkdStage or for one command."],
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const COMMAND_NAMES = new Set(COMMANDS.map(([name]) => name));
|
|
50
|
+
|
|
51
|
+
const GLOBAL_OPTIONS = {
|
|
52
|
+
help: { type: "boolean", short: "h" },
|
|
53
|
+
version: { type: "boolean", short: "v" },
|
|
54
|
+
json: { type: "boolean" },
|
|
55
|
+
workspace: { type: "string" },
|
|
56
|
+
theme: { type: "string" },
|
|
57
|
+
"theme-file": { type: "string" },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const COMMAND_OPTIONS = {
|
|
61
|
+
present: { watch: { type: "boolean" }, "no-open": { type: "boolean" } },
|
|
62
|
+
validate: {},
|
|
63
|
+
inspect: { slide: { type: "string" }, all: { type: "boolean" }, "fail-on-issues": { type: "boolean" } },
|
|
64
|
+
capture: { pages: { type: "string" }, output: { type: "string" } },
|
|
65
|
+
export: { output: { type: "string" } },
|
|
66
|
+
guide: {},
|
|
67
|
+
skill: {
|
|
68
|
+
target: { type: "string" },
|
|
69
|
+
root: { type: "string" },
|
|
70
|
+
force: { type: "boolean" },
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function usage(command) {
|
|
75
|
+
if (!command) {
|
|
76
|
+
const lines = [
|
|
77
|
+
"MarkdStage — turn Markdown into 16:9 slides.",
|
|
78
|
+
"",
|
|
79
|
+
"Usage: markdstage <command> [options]",
|
|
80
|
+
"",
|
|
81
|
+
"Commands:",
|
|
82
|
+
];
|
|
83
|
+
for (const [name, description] of COMMANDS) {
|
|
84
|
+
lines.push(` ${name.padEnd(9)} ${description}`);
|
|
85
|
+
}
|
|
86
|
+
lines.push(
|
|
87
|
+
"",
|
|
88
|
+
"Global options:",
|
|
89
|
+
" --workspace <dir> Confine every read and write to this directory.",
|
|
90
|
+
" --theme <name> Override the deck theme.",
|
|
91
|
+
" --theme-file <path> Use a custom theme metadata file.",
|
|
92
|
+
" --json Print machine-readable JSON.",
|
|
93
|
+
" -h, --help Show help for a command.",
|
|
94
|
+
" -v, --version Print the CLI version.",
|
|
95
|
+
"",
|
|
96
|
+
"Run `markdstage help <command>` or `markdstage <command> --help` for command details.",
|
|
97
|
+
"",
|
|
98
|
+
"Exit codes:",
|
|
99
|
+
...Object.entries(EXIT_CODES).map(([code, meaning]) => ` ${code} ${meaning}`),
|
|
100
|
+
);
|
|
101
|
+
return lines.join("\n");
|
|
102
|
+
}
|
|
103
|
+
const help = {
|
|
104
|
+
present: [
|
|
105
|
+
"Usage: markdstage present <file.md> [options]",
|
|
106
|
+
"",
|
|
107
|
+
" --watch Reload the deck when the Markdown file is saved.",
|
|
108
|
+
" --no-open Serve the deck without launching a browser.",
|
|
109
|
+
"",
|
|
110
|
+
"Presenting requires an installed Microsoft Edge, Google Chrome, or Chromium.",
|
|
111
|
+
],
|
|
112
|
+
validate: [
|
|
113
|
+
"Usage: markdstage validate <file.md> [--json]",
|
|
114
|
+
"",
|
|
115
|
+
"Checks deck structure, Architecture DSL blocks, themes, and theme paths.",
|
|
116
|
+
],
|
|
117
|
+
inspect: [
|
|
118
|
+
"Usage: markdstage inspect <file.md> [options]",
|
|
119
|
+
"",
|
|
120
|
+
" --slide <n> Inspect a single 1-based page.",
|
|
121
|
+
" --all Include slides that fit.",
|
|
122
|
+
" --fail-on-issues Exit with code 5 when a slide is clipped.",
|
|
123
|
+
],
|
|
124
|
+
capture: [
|
|
125
|
+
"Usage: markdstage capture <file.md> [options]",
|
|
126
|
+
"",
|
|
127
|
+
" --pages 2,4 Capture the given 1-based pages (ranges such as 2-5 work too).",
|
|
128
|
+
" --output <dir> Write PNG files to this directory.",
|
|
129
|
+
"",
|
|
130
|
+
"Without --pages only the slides reported as clipped are captured.",
|
|
131
|
+
],
|
|
132
|
+
export: [
|
|
133
|
+
"Usage: markdstage export <file.md> [--output slides.pdf]",
|
|
134
|
+
"",
|
|
135
|
+
"Produces the same 16:9 PDF as the MarkdStage canvas.",
|
|
136
|
+
],
|
|
137
|
+
guide: [
|
|
138
|
+
"Usage: markdstage guide [topic] [--json]",
|
|
139
|
+
"",
|
|
140
|
+
`Topics: ${GUIDE_TOPICS.join(", ")}.`,
|
|
141
|
+
],
|
|
142
|
+
skill: [
|
|
143
|
+
"Usage: markdstage skill <install|check> [options]",
|
|
144
|
+
"",
|
|
145
|
+
` --target <name> ${SKILL_TARGET_NAMES.join(", ")}, or all (default).`,
|
|
146
|
+
" --root <dir> Directory that receives the skill folders (default: cwd).",
|
|
147
|
+
" --force Overwrite locally modified generated files.",
|
|
148
|
+
"",
|
|
149
|
+
"Skill contents are generated from the canonical MarkdStage guide topics.",
|
|
150
|
+
],
|
|
151
|
+
help: [
|
|
152
|
+
"Usage: markdstage help [command]",
|
|
153
|
+
"",
|
|
154
|
+
"Without a command, prints the MarkdStage overview, the global options, and the",
|
|
155
|
+
"exit codes. With a command, prints the same help as `markdstage <command> --help`.",
|
|
156
|
+
],
|
|
157
|
+
}[command];
|
|
158
|
+
if (!help) throw new UsageError(`Unknown command: ${command}`);
|
|
159
|
+
return help.join("\n");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function packageVersion() {
|
|
163
|
+
const manifest = JSON.parse(
|
|
164
|
+
await readFile(resolve(PACKAGE_ROOT, "package.json"), "utf8"),
|
|
165
|
+
);
|
|
166
|
+
return manifest.version;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function requireFile(positionals, command) {
|
|
170
|
+
const file = positionals[0];
|
|
171
|
+
if (!file) {
|
|
172
|
+
throw new UsageError(`${command} requires a Markdown file.\n\n${usage(command)}`);
|
|
173
|
+
}
|
|
174
|
+
return file;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function deckOptions(file, values) {
|
|
178
|
+
return {
|
|
179
|
+
file,
|
|
180
|
+
workspace: values.workspace,
|
|
181
|
+
theme: values.theme,
|
|
182
|
+
themeFile: values["theme-file"],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export async function run(argv, io = {}) {
|
|
187
|
+
const out = io.out ?? ((text) => console.log(text));
|
|
188
|
+
const err = io.err ?? ((text) => console.error(text));
|
|
189
|
+
const json = (payload) => out(JSON.stringify(payload, null, 2));
|
|
190
|
+
|
|
191
|
+
const command = argv[0];
|
|
192
|
+
const rest = argv.slice(1);
|
|
193
|
+
if (command === "--help" || command === "-h" || command === undefined) {
|
|
194
|
+
out(usage());
|
|
195
|
+
return EXIT_OK;
|
|
196
|
+
}
|
|
197
|
+
if (command === "help") {
|
|
198
|
+
const requested = rest.find((argument) => !argument.startsWith("-"));
|
|
199
|
+
// `markdstage help --help` documents the help command itself, like every
|
|
200
|
+
// other `markdstage <command> --help`.
|
|
201
|
+
const topic =
|
|
202
|
+
requested ?? (rest.includes("--help") || rest.includes("-h") ? "help" : undefined);
|
|
203
|
+
if (topic !== undefined && !COMMAND_NAMES.has(topic)) {
|
|
204
|
+
err(`Unknown command: ${topic}\n\n${usage()}`);
|
|
205
|
+
return EXIT_USAGE;
|
|
206
|
+
}
|
|
207
|
+
out(usage(topic));
|
|
208
|
+
return EXIT_OK;
|
|
209
|
+
}
|
|
210
|
+
if (command === "--version" || command === "-v") {
|
|
211
|
+
out(await packageVersion());
|
|
212
|
+
return EXIT_OK;
|
|
213
|
+
}
|
|
214
|
+
if (command.startsWith("-")) {
|
|
215
|
+
err(`Unknown option: ${command}\n\n${usage()}`);
|
|
216
|
+
return EXIT_USAGE;
|
|
217
|
+
}
|
|
218
|
+
if (!COMMAND_OPTIONS[command]) {
|
|
219
|
+
err(`Unknown command: ${command}\n\n${usage()}`);
|
|
220
|
+
return EXIT_USAGE;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let values;
|
|
224
|
+
let positionals;
|
|
225
|
+
try {
|
|
226
|
+
({ values, positionals } = parseArgs({
|
|
227
|
+
args: rest,
|
|
228
|
+
options: { ...GLOBAL_OPTIONS, ...COMMAND_OPTIONS[command] },
|
|
229
|
+
allowPositionals: true,
|
|
230
|
+
}));
|
|
231
|
+
} catch (error) {
|
|
232
|
+
err(`${error.message}\n\n${usage(command)}`);
|
|
233
|
+
return EXIT_USAGE;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (values.help) {
|
|
237
|
+
out(usage(command));
|
|
238
|
+
return EXIT_OK;
|
|
239
|
+
}
|
|
240
|
+
if (values.version) {
|
|
241
|
+
out(await packageVersion());
|
|
242
|
+
return EXIT_OK;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
switch (command) {
|
|
247
|
+
case "present": {
|
|
248
|
+
const file = requireFile(positionals, "present");
|
|
249
|
+
const report = await presentCommand(
|
|
250
|
+
{ ...deckOptions(file, values), watch: values.watch, open: !values["no-open"], until: io.until },
|
|
251
|
+
{
|
|
252
|
+
print: values.json ? () => {} : (message) => out(message),
|
|
253
|
+
status: (message, isError) => {
|
|
254
|
+
if (isError) err(message);
|
|
255
|
+
else if (!values.json) out(message);
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
);
|
|
259
|
+
if (values.json) json(report);
|
|
260
|
+
return EXIT_OK;
|
|
261
|
+
}
|
|
262
|
+
case "validate": {
|
|
263
|
+
const file = requireFile(positionals, "validate");
|
|
264
|
+
const report = await validateCommand(deckOptions(file, values));
|
|
265
|
+
if (values.json) json(report);
|
|
266
|
+
else out(formatValidateReport(report));
|
|
267
|
+
return report.ok ? EXIT_OK : EXIT_DECK;
|
|
268
|
+
}
|
|
269
|
+
case "inspect": {
|
|
270
|
+
const file = requireFile(positionals, "inspect");
|
|
271
|
+
let index;
|
|
272
|
+
if (values.slide !== undefined) {
|
|
273
|
+
const page = Number.parseInt(values.slide, 10);
|
|
274
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
275
|
+
throw new UsageError("--slide expects a 1-based page number.");
|
|
276
|
+
}
|
|
277
|
+
index = page - 1;
|
|
278
|
+
}
|
|
279
|
+
const report = await inspectCommand({
|
|
280
|
+
...deckOptions(file, values),
|
|
281
|
+
index,
|
|
282
|
+
includeFits: values.all,
|
|
283
|
+
});
|
|
284
|
+
if (values.json) json(report);
|
|
285
|
+
else out(formatInspectReport(report));
|
|
286
|
+
return values["fail-on-issues"] && report.hasIssues ? EXIT_ISSUES : EXIT_OK;
|
|
287
|
+
}
|
|
288
|
+
case "capture": {
|
|
289
|
+
const file = requireFile(positionals, "capture");
|
|
290
|
+
let indexes;
|
|
291
|
+
if (values.pages !== undefined) {
|
|
292
|
+
try {
|
|
293
|
+
indexes = parsePageList(values.pages);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
throw new UsageError(error.message);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const report = await captureCommand({
|
|
299
|
+
...deckOptions(file, values),
|
|
300
|
+
indexes,
|
|
301
|
+
output: values.output,
|
|
302
|
+
});
|
|
303
|
+
if (values.json) json(report);
|
|
304
|
+
else out(formatCaptureReport(report));
|
|
305
|
+
return EXIT_OK;
|
|
306
|
+
}
|
|
307
|
+
case "export": {
|
|
308
|
+
const file = requireFile(positionals, "export");
|
|
309
|
+
const report = await exportCommand({
|
|
310
|
+
...deckOptions(file, values),
|
|
311
|
+
output: values.output,
|
|
312
|
+
});
|
|
313
|
+
if (values.json) json(report);
|
|
314
|
+
else out(formatExportReport(report));
|
|
315
|
+
return EXIT_OK;
|
|
316
|
+
}
|
|
317
|
+
case "guide": {
|
|
318
|
+
const report = await guideCommand({ topic: positionals[0] });
|
|
319
|
+
if (values.json) json(report);
|
|
320
|
+
else out(report.content);
|
|
321
|
+
return EXIT_OK;
|
|
322
|
+
}
|
|
323
|
+
case "skill": {
|
|
324
|
+
const report = await skillCommand({
|
|
325
|
+
action: positionals[0] ?? "install",
|
|
326
|
+
target: values.target,
|
|
327
|
+
root: values.root ? resolve(values.root) : process.cwd(),
|
|
328
|
+
force: values.force,
|
|
329
|
+
});
|
|
330
|
+
if (values.json) json(report);
|
|
331
|
+
else out(formatSkillReport(report));
|
|
332
|
+
if (report.action === "check") {
|
|
333
|
+
return report.changed || report.conflicts ? EXIT_ISSUES : EXIT_OK;
|
|
334
|
+
}
|
|
335
|
+
return report.conflicts ? EXIT_ISSUES : EXIT_OK;
|
|
336
|
+
}
|
|
337
|
+
default:
|
|
338
|
+
err(usage());
|
|
339
|
+
return EXIT_USAGE;
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
const code = exitCodeFor(error);
|
|
343
|
+
if (values.json) json(errorPayload(error));
|
|
344
|
+
else err(error?.message || String(error));
|
|
345
|
+
return code || EXIT_FAILURE;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// markdstage capture — write selected 1280x720 PNG files.
|
|
2
|
+
|
|
3
|
+
import { captureSlides } from "../runtime.mjs";
|
|
4
|
+
import { withDeckServer } from "../deck.mjs";
|
|
5
|
+
|
|
6
|
+
export async function captureCommand(options) {
|
|
7
|
+
return withDeckServer(options, async (session) =>
|
|
8
|
+
captureSlides(session, options.indexes, options.output, options.theme),
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function formatCaptureReport(report) {
|
|
13
|
+
if (!report.captured) {
|
|
14
|
+
return report.message || "No PNG files were written.";
|
|
15
|
+
}
|
|
16
|
+
const lines = [`${report.captured} PNG file(s) written to ${report.directory}`];
|
|
17
|
+
for (const file of report.files) {
|
|
18
|
+
lines.push(
|
|
19
|
+
` slide ${file.page}: ${file.path} (${file.width}x${file.height}, ${file.bytes} bytes)`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return lines.join("\n");
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// markdstage export — produce the same 16:9 PDF as the Canvas Extension.
|
|
2
|
+
|
|
3
|
+
import { exportPdf, pdfNameForSource } from "../runtime.mjs";
|
|
4
|
+
import { withDeckServer } from "../deck.mjs";
|
|
5
|
+
|
|
6
|
+
export async function exportCommand(options) {
|
|
7
|
+
return withDeckServer(options, async (session) =>
|
|
8
|
+
exportPdf(
|
|
9
|
+
session,
|
|
10
|
+
options.output || pdfNameForSource(session.sourceName),
|
|
11
|
+
options.theme,
|
|
12
|
+
),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function formatExportReport(report) {
|
|
17
|
+
return `Exported ${report.total} slide(s) to ${report.path} (${report.bytes} bytes, theme ${report.theme}).`;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// markdstage guide — the canonical markdstage_guide topics without the canvas.
|
|
2
|
+
|
|
3
|
+
import { readGuide } from "../runtime.mjs";
|
|
4
|
+
import { UsageError } from "../exit.mjs";
|
|
5
|
+
|
|
6
|
+
export const GUIDE_TOPICS = [
|
|
7
|
+
"overview",
|
|
8
|
+
"slide-format",
|
|
9
|
+
"themes",
|
|
10
|
+
"custom-themes",
|
|
11
|
+
"theme-schema",
|
|
12
|
+
"architecture-dsl",
|
|
13
|
+
"architecture-schema",
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export async function guideCommand({ topic = "overview" } = {}) {
|
|
17
|
+
if (!GUIDE_TOPICS.includes(topic)) {
|
|
18
|
+
throw new UsageError(
|
|
19
|
+
`Unknown guide topic: ${topic}. Available topics: ${GUIDE_TOPICS.join(", ")}.`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return { topic, content: await readGuide(topic) };
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// markdstage inspect — the compact 1280x720 clipping diagnostics the Canvas
|
|
2
|
+
// `inspect_layout` action returns.
|
|
3
|
+
|
|
4
|
+
import { inspectLayout } from "../runtime.mjs";
|
|
5
|
+
import { withDeckServer } from "../deck.mjs";
|
|
6
|
+
|
|
7
|
+
export async function inspectCommand(options, inspect = inspectLayout) {
|
|
8
|
+
return withDeckServer(options, async (session) =>
|
|
9
|
+
inspect(session, options.index, options.includeFits),
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function formatInspectReport(report) {
|
|
14
|
+
const lines = [
|
|
15
|
+
`${report.width}x${report.height} · ${report.inspected}/${report.total} slide(s) inspected`,
|
|
16
|
+
];
|
|
17
|
+
if (!report.slides.length) {
|
|
18
|
+
lines.push(report.hasIssues ? " (no details)" : " OK: every slide fits the 16:9 output.");
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
}
|
|
21
|
+
for (const slide of report.slides) {
|
|
22
|
+
const details = [];
|
|
23
|
+
if (slide.verticalOverflowPx) details.push(`vertical ${slide.verticalOverflowPx}px`);
|
|
24
|
+
if (slide.horizontalOverflowPx) details.push(`horizontal ${slide.horizontalOverflowPx}px`);
|
|
25
|
+
lines.push(
|
|
26
|
+
` slide ${slide.page ?? slide.index + 1} (${slide.title || "untitled"}): ${slide.status}` +
|
|
27
|
+
(details.length ? ` — ${details.join(", ")}` : ""),
|
|
28
|
+
);
|
|
29
|
+
for (const hint of slide.elements ?? []) {
|
|
30
|
+
lines.push(` ${hint.kind}: ${hint.path || hint.tag}${hint.text ? ` — ${hint.text}` : ""}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
lines.push(` ${report.issueCount} slide(s) do not fit.`);
|
|
34
|
+
return lines.join("\n");
|
|
35
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// markdstage present — serve the deck on loopback and open it in a browser.
|
|
2
|
+
|
|
3
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
import {
|
|
9
|
+
MarkdStageError,
|
|
10
|
+
buildPresenterBrowserArgs,
|
|
11
|
+
findChromiumBrowser,
|
|
12
|
+
isProcessRunning,
|
|
13
|
+
sharedPath,
|
|
14
|
+
terminateProcessTree,
|
|
15
|
+
} from "../runtime.mjs";
|
|
16
|
+
import { withDeckServer } from "../deck.mjs";
|
|
17
|
+
|
|
18
|
+
async function createWatcher(session, server, { onStatus }) {
|
|
19
|
+
const { createMarkdownWatcher } = await import(
|
|
20
|
+
pathToFileURL(sharedPath("scripts", "markdown-watcher.mjs")).href
|
|
21
|
+
);
|
|
22
|
+
return createMarkdownWatcher({
|
|
23
|
+
path: session.file,
|
|
24
|
+
onChange: async () => {
|
|
25
|
+
try {
|
|
26
|
+
// Keep the current slide, and keep the last valid deck when the file is
|
|
27
|
+
// saved in a broken intermediate state.
|
|
28
|
+
await session.load({ preserveIndex: true });
|
|
29
|
+
server.broadcast();
|
|
30
|
+
onStatus(`reloaded ${session.sourceName} (${session.slides.length} slides)`);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
onStatus(`reload failed, keeping the last valid deck: ${error?.message || error}`, true);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
onError: (error) => onStatus(`watch error: ${error?.message || error}`, true),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function presentCommand(options, io) {
|
|
40
|
+
return withDeckServer(options, async (session, server) => {
|
|
41
|
+
const watcher = options.watch ? await createWatcher(session, server, {
|
|
42
|
+
onStatus: (message, isError) => io.status(message, isError),
|
|
43
|
+
}) : null;
|
|
44
|
+
|
|
45
|
+
let browserProcess = null;
|
|
46
|
+
let profileDir = "";
|
|
47
|
+
if (options.open) {
|
|
48
|
+
const browser = findChromiumBrowser();
|
|
49
|
+
if (!browser) {
|
|
50
|
+
throw new MarkdStageError(
|
|
51
|
+
"presenter_browser_not_found",
|
|
52
|
+
"Presenting requires Microsoft Edge, Google Chrome, or Chromium. Re-run with --no-open to serve the deck only.",
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
profileDir = await mkdtemp(join(tmpdir(), "markdstage-presenter-window-"));
|
|
56
|
+
browserProcess = spawn(
|
|
57
|
+
browser,
|
|
58
|
+
buildPresenterBrowserArgs({ profileDir, presenterUrl: server.url }),
|
|
59
|
+
{ windowsHide: false, stdio: "ignore" },
|
|
60
|
+
);
|
|
61
|
+
browserProcess.once("error", (error) => {
|
|
62
|
+
io.status(`browser failed to start: ${error?.message || error}`, true);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
io.print(`MarkdStage is presenting ${session.sourceName || session.file}`);
|
|
67
|
+
io.print(` slides: ${session.slides.length}`);
|
|
68
|
+
io.print(` theme: ${session.theme}`);
|
|
69
|
+
io.print(` workspace: ${resolve(session.workspaceRoot)}`);
|
|
70
|
+
io.print(` url: ${server.url}`);
|
|
71
|
+
if (options.watch) io.print(" watching: on (the deck reloads when the file is saved)");
|
|
72
|
+
io.print("Press Ctrl+C to stop.");
|
|
73
|
+
|
|
74
|
+
await new Promise((done) => {
|
|
75
|
+
const stop = () => {
|
|
76
|
+
process.off("SIGINT", stop);
|
|
77
|
+
process.off("SIGTERM", stop);
|
|
78
|
+
done();
|
|
79
|
+
};
|
|
80
|
+
process.once("SIGINT", stop);
|
|
81
|
+
process.once("SIGTERM", stop);
|
|
82
|
+
if (browserProcess) browserProcess.once("close", stop);
|
|
83
|
+
if (options.until) options.until.then(stop, stop);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
watcher?.close();
|
|
87
|
+
if (isProcessRunning(browserProcess)) await terminateProcessTree(browserProcess);
|
|
88
|
+
if (profileDir) await rm(profileDir, { recursive: true, force: true }).catch(() => {});
|
|
89
|
+
return { ok: true, url: server.url, total: session.slides.length, theme: session.theme };
|
|
90
|
+
});
|
|
91
|
+
}
|