i-plane 1.2.0 → 2.0.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.
@@ -0,0 +1,2 @@
1
+ import{ia as b,ka as _,ma as T}from"./cli-5v4ee99d.js";var h=(e)=>{let n=process.env.HTTPS_PROXY??process.env.https_proxy,t=process.env.HTTP_PROXY??process.env.http_proxy,r=e==="https:"?n??t:t??n;return r===void 0||r===""?void 0:r},x=(e)=>{let n=e.split(".");if(n.length!==4)return;let t=0;for(let r of n){if(!/^\d{1,3}$/.test(r))return;let s=Number(r);if(s>255)return;t=t*256+s}return t},P=(e,n)=>{let[t,r]=n.split("/");if(t===void 0||r===void 0)return!1;let s=Number(r);if(!Number.isInteger(s)||s<0||s>32)return!1;let a=x(e),o=x(t);if(a===void 0||o===void 0)return!1;let f=s===0?0:4294967295<<32-s>>>0;return(a&f)===(o&f)},v=(e)=>{let n=process.env.NO_PROXY??process.env.no_proxy??"";if(n.trim()==="")return!1;let t=e.toLowerCase().replace(/\.$/,"").replace(/^\[|\]$/g,"");for(let r of n.split(/[,\s]+/)){let s=r.trim().toLowerCase().replace(/\.$/,"").replace(/^\./,"").replace(/^\[|\]$/g,"");if(s==="")continue;if(s==="*")return!0;if(s.includes("/")&&P(t,s))return!0;if(t===s||t.endsWith(`.${s}`))return!0}return!1},w=(e)=>{let n;try{n=new URL(e)}catch{return!1}if(v(n.hostname))return!1;return h(n.protocol)!==void 0},S=(e)=>{let n=new URL(e);if(v(n.hostname))return;return h(n.protocol==="wss:"?"https:":"http:")},R=(e)=>{if(!w(e))return"directly";let n=h(new URL(e).protocol);if(n===void 0)return"directly";try{let t=new URL(n);return`through proxy ${t.protocol}//${t.host}`}catch{return"through the configured proxy"}},p=(e,n=0)=>{if(n>8||e===null||typeof e!=="object")return!1;let t=e;return t.code==="EPERM"||t.code==="EACCES"||p(t.cause,n+1)||Array.isArray(t.errors)&&t.errors.some((r)=>p(r,n+1))},k=async(e)=>{if(!w(e))return;if(process.env.NODE_USE_ENV_PROXY==="1")return;let n=new URL(e),t=h(n.protocol);if(t===void 0)return;let r;try{r=await import("undici")}catch{return}try{let s=new r.ProxyAgent(t);return(a,o)=>r.fetch(a,{...o,dispatcher:s})}catch(s){let a=s instanceof Error?s.message:String(s);throw Error(`Proxy setting is not a usable URL: ${t} (${a})`)}},A=()=>{let[e=0,n=0]=process.versions.node.split(".").map(Number);return e>=24||e===22&&n>=21},O=async(e)=>{if(!w(e))return;if(process.env.NODE_USE_ENV_PROXY==="1")return;if(process.env.I_PLANE_NO_REEXEC==="1")return;if(!A())throw Error(`A proxy is configured, but Node ${process.versions.node} cannot use it with the built-in fetch. Install the optional dependency (npm install undici) or upgrade to Node 22.21 or newer.`);let{spawnSync:n}=await import("node:child_process"),t=process.argv[1];if(t===void 0)return;return n(process.execPath,[...process.execArgv,t,...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,NODE_USE_ENV_PROXY:"1",I_PLANE_NO_REEXEC:"1"}}).status??1};var y=(e,n)=>{if(n==="")return e;let t=T(e).split(n).join("[token]");for(let r of n.split(/\s+/))if(r.length>=12)t=t.split(r).join("[token]");return t};class c extends Error{status;constructor(e,n){super(e);this.name="PlaneError",this.status=n}}var C=20000;class N{config;transport;transportReady=!1;constructor(e){if(this.config=e,e.token.value)_(e.token.value)}async fetcher(e){if(!this.transportReady)this.transport=await k(e),this.transportReady=!0;return this.transport??fetch}async request(e,n={}){let t=e.startsWith("/")?`${this.config.url.value}${e}`:`${this.config.url.value}/api/v1/workspaces/${this.config.workspace.value}/${e}`,r=new URL(t);for(let[i,d]of Object.entries(n.query??{}))if(d!==void 0)r.searchParams.set(i,String(d));let s=n.timeoutMs??C,a=await this.fetcher(r.toString()),o=new AbortController,f=Date.now(),g=setTimeout(()=>o.abort(),s),m=()=>Math.max(0,s-(Date.now()-f)),u;try{u=await a(r.toString(),{method:n.method??"GET",headers:{"X-API-Key":this.config.token.value,Accept:"application/json",...n.body===void 0?{}:{"Content-Type":"application/json"}},body:n.body===void 0?void 0:JSON.stringify(n.body),signal:o.signal,redirect:"error"})}catch(i){if(i instanceof Error&&i.name==="AbortError")throw clearTimeout(g),new c(`No answer from ${this.config.url.value} within ${s/1000}s.`);let d=i instanceof Error?i.message:String(i),l=i instanceof Error?i.cause:void 0,E=l===void 0?d:`${d} (${[l.name,l.code,l.message].filter(Boolean).join(" ")})`;if(clearTimeout(g),p(i))throw new c(y(`Connection to ${this.config.url.value} ${R(r.toString())} was denied by the operating system (EPERM/EACCES). Check sandbox network permissions and local firewall rules. No HTTP response was received from Plane.`,this.config.token.value));throw new c(y(`Cannot reach ${this.config.url.value}: ${E}`,this.config.token.value))}try{if(!u.ok)throw await this.describeFailure(u,m(),o);if(u.status===204)return;let i=await this.readBody(u,m(),o);if(i==="")return;return JSON.parse(i)}catch(i){if(i instanceof c)throw i;throw new c(y(`Expected JSON from ${r.pathname}: ${i instanceof Error?i.message:String(i)}`,this.config.token.value).slice(0,200))}finally{clearTimeout(g)}}async readBody(e,n,t){let r,s=new Promise((a,o)=>{r=setTimeout(()=>{t.abort(),o(new c(`Response body stalled; gave up after ${n/1000}s.`))},n)});try{return await Promise.race([e.text(),s])}finally{if(r!==void 0)clearTimeout(r)}}async listAll(e,n={}){let t=[],r=new Set,s=n.query?.cursor;if(s!==void 0&&s!==null)r.add(String(s));let a;do{let o=await this.request(e,{...n,query:{...n.query,...a===void 0?{}:{cursor:a}}});if(Array.isArray(o)){t.push(...o);break}if(!o||!Array.isArray(o.results)||o.next_page_results!==void 0&&typeof o.next_page_results!=="boolean")throw new c(`Unexpected paginated response: ${e}`);if(t.push(...o.results),o.next_page_results!==!0)break;if(typeof o.next_cursor!=="string"||!o.next_cursor.trim())throw new c(`Missing or invalid pagination cursor: ${e}`);if(r.has(o.next_cursor))throw new c(`Repeated pagination cursor: ${e}`);r.add(o.next_cursor),a=o.next_cursor}while(a!==void 0);return t}async describeFailure(e,n,t){let r=await this.readBody(e,n,t).catch(()=>""),s=y(r,this.config.token.value).slice(0,300);switch(e.status){case 401:case 403:return new c(`Token rejected (${e.status}). The key from ${this.config.configPath} is not valid for workspace "${this.config.workspace.value}".`,e.status);case 404:return new c(`Not found (404): ${e.url}. Check the workspace slug ("${this.config.workspace.value}") and the project identifier.`,404);case 429:return new c("Rate limited (429). Plane allows 60 API calls a minute.",429);default:return new c(`Plane answered ${e.status}${s===""?"":`: ${s}`}`,e.status)}}}
2
+ export{w as M,S as N,R as O,p as P,k as Q,O as R,c as S,N as T};
@@ -0,0 +1,2 @@
1
+ import{A as ge,B as z,C as Se,D as Z,F as Ye,G as ee,K as P,l as le,n as N,o as O,p as F,x as de,y as fe,z as me}from"./cli-hgk20taa.js";import{N as xe,S as d}from"./cli-tdf7t5es.js";import{aa as h,ba as U,ca as C}from"./cli-2sf0pmt1.js";import{fa as Ue,ga as Re,ka as q,ma as k,na as E}from"./cli-5v4ee99d.js";var se=Re(function(et,ae){var W=!0,ie=!1,oe=!1;ae.exports=function(e,t){if(t)W=!t.enabled,ie=!!t.label,oe=!!t.labelAfter;e.core.ruler.after("inline","github-task-lists",function(r){var n=r.tokens;for(var i=2;i<n.length;i++)if(Me(n,i))Ce(n[i],r.Token),ne(n[i-2],"class","task-list-item"+(!W?" enabled":"")),ne(n[Xe(n,i-2)],"class","contains-task-list")})};function ne(e,t,r){var n=e.attrIndex(t),i=[t,r];if(n<0)e.attrPush(i);else e.attrs[n]=i}function Xe(e,t){var r=e[t].level-1;for(var n=t-1;n>=0;n--)if(e[n].level===r)return n;return-1}function Me(e,t){return je(e[t])&&qe(e[t-1])&&Oe(e[t-2])&&Fe(e[t])}function Ce(e,t){if(e.children.unshift(Te(e,t)),e.children[1].content=e.children[1].content.slice(3),e.content=e.content.slice(3),ie)if(oe){e.children.pop();var r="task-item-"+Math.ceil(Math.random()*1e7-1000);e.children[0].content=e.children[0].content.slice(0,-1)+' id="'+r+'">',e.children.push(De(e.content,r,t))}else e.children.unshift(Ne(t)),e.children.push(Be(t))}function Te(e,t){var r=new t("html_inline","",0),n=W?' disabled="" ':"";if(e.content.indexOf("[ ] ")===0)r.content='<input class="task-list-item-checkbox"'+n+'type="checkbox">';else if(e.content.indexOf("[x] ")===0||e.content.indexOf("[X] ")===0)r.content='<input class="task-list-item-checkbox" checked=""'+n+'type="checkbox">';return r}function Ne(e){var t=new e("html_inline","",0);return t.content="<label>",t}function Be(e){var t=new e("html_inline","",0);return t.content="</label>",t}function De(e,t,r){var n=new r("html_inline","",0);return n.content='<label class="task-list-item-label" for="'+t+'">'+e+"</label>",n.attrs=[{for:t}],n}function je(e){return e.type==="inline"}function qe(e){return e.type==="paragraph_open"}function Oe(e){return e.type==="list_item_open"}function Fe(e){return e.content.indexOf("[ ] ")===0||e.content.indexOf("[x] ")===0||e.content.indexOf("[X] ")===0}});import{readFile as Qe}from"node:fs/promises";import{createHash as Ie,randomUUID as _e}from"node:crypto";var ue=Ue(se(),1);import*as m from"yjs";var X=(e)=>{let t=new Set,r=(n)=>{if(!(n instanceof m.XmlElement))return;if(n.nodeName.toLowerCase()==="knowledgereview")t.add("knowledgeReview");for(let i of n.toArray())r(i)};return e.forEach(r),[...t]},L=(e)=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"),x=(e,t)=>t==null||t===""?"":` ${e}="${L(t)}"`,T=(e)=>{if(Array.isArray(e))return e.map(T);if(e&&typeof e==="object")return Object.fromEntries(Object.entries(e).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,T(r)]));return e},He=new Set(["doc","paragraph","heading","bulletlist","orderedlist","listitem","tasklist","taskitem","blockquote","codeblock","horizontalrule","hardbreak","table","tablerow","tableheader","tablecell","imagecomponent","image","knowledgereview"]),pe=(e,t=!0)=>e instanceof m.XmlText?{text:T(e.toDelta())}:{kind:e.nodeName,attributes:T(Object.fromEntries(Object.entries(e.getAttributes()).filter(([r])=>r!=="id"||!(t||He.has(e.nodeName.toLowerCase()))))),children:e.toArray().map((r)=>pe(r,!1))},J=(e)=>Ie("sha256").update(JSON.stringify(pe(e))).digest("hex"),R=(e)=>e instanceof m.XmlElement&&e.nodeName==="knowledgeReview"?`Reviewed ${String(e.getAttribute("reviewedAt")??"")}: ${String(e.getAttribute("source")??"")}`:e instanceof m.XmlText?e.toDelta().map((t)=>typeof t.insert==="string"?t.insert:JSON.stringify(t.insert)).join(""):e.toArray().map((t)=>R(t)).join(" "),he=(e)=>e.toArray().map((t,r)=>{let n=t instanceof m.XmlElement?String(t.getAttribute("id")??"")||null:null;return{index:r,anchor:n,shortAnchor:n?k(n).slice(0,8):null,kind:t instanceof m.XmlElement?t.nodeName:"text",preview:k(R(t)).replace(/\s+/g," ").trim().slice(0,40)}}),B=(e,t)=>{let r=e.toArray().flatMap((i,a)=>{if(!(i instanceof m.XmlElement))return[];let l=String(i.getAttribute("id")??"");return l.length>0&&l.toLowerCase().startsWith(t.toLowerCase())?[{node:i,index:a,anchor:l}]:[]});if(r.length===0)throw new d(`No top-level block matches "${t}". Run page outline to see current anchors.`,404);if(r.length!==1)throw new h(`Ambiguous block anchor "${t}": ${r.map((i)=>`${i.anchor} [${i.index}]`).join(", ")}`);let n=r[0];if(!n)throw new d("Block disappeared.");return n},K=(e)=>{let t=0;for(let r of e.toArray())if(r instanceof m.XmlElement&&!r.getAttribute("id"))r.setAttribute("id",_e()),t++;return t},D=(e,t,r=!1)=>{if(e instanceof m.XmlText){let o=R(e),s=r?k(o):o;if(s!==o)return t.add("Sensitive text was redacted; the printed block is not a lossless copy"),L(s);return e.toDelta().map((f)=>{let c=L(typeof f.insert==="string"?f.insert:JSON.stringify(f.insert));for(let[p,w]of Object.entries(f.attributes??{})){let y=Object.fromEntries(Object.entries(w&&typeof w==="object"?w:{}).map(([A,b])=>[A,r&&typeof b==="string"?k(b):b]));if(p==="bold")c=`<strong>${c}</strong>`;else if(p==="italic")c=`<em>${c}</em>`;else if(p==="strike")c=`<s>${c}</s>`;else if(p==="code")c=`<code>${c}</code>`;else if(p==="link")c=`<a${x("href",y.href)}${x("title",y.title)}>${c}</a>`;else if(t.add(`Mark ${p} is not representable by this Markdown reader`),p==="underline")c=`&lt;u&gt;${c}&lt;/u&gt;`}return c}).join("")}let n=e.nodeName.toLowerCase(),i=Object.fromEntries(Object.entries(e.getAttributes()).map(([o,s])=>[o,r&&typeof s==="string"?k(s):s])),a=()=>e.toArray().map((o)=>D(o,t,r)).join("");if(i.textAlign&&i.textAlign!=="left")t.add("Text alignment is not representable in Markdown");if(n==="knowledgereview"){let o=String(i.reviewedAt??""),s=String(i.source??"");if(typeof i.reviewedAt!=="string"||typeof i.source!=="string"||!fe(o)||!s.trim())t.add("Review metadata is invalid");if(Object.keys(i).some((f)=>!["id","reviewedAt","source"].includes(f))||e.length)t.add("Additional review attributes or content are not represented in Markdown");if(r&&(i.reviewedAt!==e.getAttribute("reviewedAt")||i.source!==e.getAttribute("source")))t.add("Sensitive review metadata was redacted; the printed block is not a lossless copy");return z({date:o,source:s})}if(n==="doc")return a();if(n==="paragraph")return`<p>${a()}</p>`;if(n==="heading"){let o=Math.min(6,Math.max(1,Number(i.level)||1));return`<h${o}>${a()}</h${o}>`}if(n==="bulletlist")return`<ul>${a()}</ul>`;if(n==="orderedlist")return`<ol${x("start",i.start)}>${a()}</ol>`;if(n==="listitem")return`<li>${a()}</li>`;if(n==="tasklist")return`<ul>${a()}</ul>`;if(n==="taskitem"){let o=`<input type="checkbox"${i.checked===!0||i.checked==="true"?" checked":""}>`,s=a().replace(/^<p>([\s\S]*?)<\/p>/,"$1");return`<li>${o}${s}</li>`}if(n==="blockquote")return`<blockquote>${a()}</blockquote>`;if(n==="codeblock"&&i.language==="knowledge-review")t.add("The knowledge-review fence language is reserved for review metadata");if(n==="codeblock")return`<pre><code${i.language?x("class",`language-${i.language}`):""}>${L(r?k(R(e)):R(e))}</code></pre>`;if(n==="horizontalrule")return"<hr>";if(n==="hardbreak")return"<br>";if(n==="table")return`<table>${a()}</table>`;if(n==="tablerow")return`<tr>${a()}</tr>`;if(n==="tablecell"||n==="tableheader"){let o=e.toArray().filter((c)=>c instanceof m.XmlElement),s=(c)=>c.nodeName.toLowerCase()==="hardbreak"||c.toArray().some((p)=>p instanceof m.XmlElement&&s(p));if(o.length>1||o.some((c)=>c.nodeName.toLowerCase()!=="paragraph"||s(c)))t.add("Multiple paragraphs, line breaks or block structure inside table cells are flattened in Markdown");if(Number(i.colspan??1)!==1||Number(i.rowspan??1)!==1)t.add("Merged table cells are not representable in Markdown");if(i.background||i.colwidth)t.add("Table styling is not representable in Markdown");let f=n==="tablecell"?"td":"th";return`<${f}>${a()}</${f}>`}if(n==="imagecomponent"||n==="image"){if(i.width||i.height||i.alignment)t.add("Image dimensions or alignment are not representable in Markdown");return`<img${x("src",i.src)}${x("alt",i.alt)}${x("title",i.title)}>`}t.add(`Unsupported node ${e.nodeName}; preserved as XML text`);let l=e.toString();return`<pre><code class="language-xml">${L(r?de(l):l)}</code></pre>`},We=(e)=>{let t=new Set,r=e.toArray().map((n)=>D(n,t)).join("");return{markdown:N(r),losses:[...t]}},we=(e,t)=>{let{node:r,anchor:n}=B(e,t),i=new Set;return{anchor:n,fingerprint:J(r),markdown:N(D(r,i,!0)),losses:[...i]}},ke=(e)=>{let t=new Set;for(let r of e)D(r,t);return[...t]},M=new le({html:!1}).use(ue.default),ze=M.renderer.rules.fence;M.renderer.rules.fence=(e,t,r,n,i)=>{let a=e[t];if(/^knowledge-review\s/.test(a?.info.trim()??""))throw new h("A knowledge-review fence does not accept additional info fields.");if(a?.info.trim()==="knowledge-review"){let l=me(a.content);if(!n?.reviewAsCode&&n?.requiredNodes instanceof Set)n.requiredNodes.add("knowledgeReview");return n?.reviewAsCode?z(l):ge(l)}return ze?.(e,t,r,n,i)??i.renderToken(e,t,r)};M.core.ruler.before("github-task-lists","empty-task-items",(e)=>{for(let t=2;t<e.tokens.length;t++){let r=e.tokens[t],n=r?.children?.[0];if(r&&n&&/^\[[ xX]\]$/.test(r.content)&&e.tokens[t-1]?.tag==="p"&&e.tokens[t-2]?.tag==="li")r.content+=" ",n.content+=" "}});var be=(e)=>e.toArray().flatMap((t)=>t instanceof m.XmlElement?[...t.nodeName.toLowerCase()==="codeblock"?[t]:[],...be(t)]:[]),ce=(e,t=!1,r)=>M.render(e,{reviewAsCode:t,requiredNodes:r}).trim().replace(/(<li class="task-list-item">)\s*<p>([\s\S]*?)<\/p>/g,"$1$2").replace(/(<input class="task-list-item-checkbox"[^>]*>) /g,"$1"),ye=async(e,t)=>{let r=new Set,n=ce(t,!1,r);if(r.size)P([...r],await e.nodeReaders?.()??[]);if(!n){let o=new m.Doc;return{doc:o,fragment:o.getXmlFragment("default"),losses:[]}}let i=n.replace(/<img([^>]*?)\s*\/?>/g,"<image-component$1></image-component>").replace(/<ul class="contains-task-list">/g,'<ul data-type="taskList">').replace(/<li class="task-list-item">(\s*<p>)?<input\b([^>]*)>/g,(o,s,f)=>`<li data-type="taskItem" data-checked="${/\bchecked=/.test(f)}">${s??""}`),a=await e.request("/live/convert-document",{method:"POST",body:{description_html:i,variant:"rich"}}),l=new m.Doc;try{if(typeof a.description_binary!=="string"||!a.description_binary)throw Error("Missing document binary");m.applyUpdate(l,Buffer.from(a.description_binary,"base64"));let o=l.getXmlFragment("default"),s=M.parse(t,{}).filter((w)=>w.block&&w.tag==="code"&&w.info.trim()!=="knowledge-review").map((w)=>w.info.trim().split(/\s+/)[0]||null),f=be(o),c=[];if(s.length!==f.length)c.push("The converter changed the number of code blocks");else l.transact(()=>f.forEach((w,S)=>{let y=s[S];if(y)w.setAttribute("language",y);else w.removeAttribute("language")}));if(We(o).markdown!==N(ce(t,!0)))c.push("The converter changed Markdown content or formatting");return l.transact(()=>K(o)),{doc:l,fragment:o,losses:c}}catch(o){if(l.destroy(),o instanceof d)throw o;throw new d(`Cannot decode the converted document: ${o instanceof Error?o.message:String(o)}`)}};import*as j from"yjs";var V=(e,t=!1)=>{if(e.length&&!t)throw new h(`This edit can lose content or formatting: ${e.join("; ")}. Inspect the document, then pass --allow-loss to accept these losses.`)},ve=(e,t,r)=>{let n=t.block?B(e,t.block):void 0;if(n&&t.ifMatch&&!t.force&&J(n.node)!==t.ifMatch)throw new d("Block content changed since page read. Read it again and use its new --if-match fingerprint, or pass --force to overwrite the concurrent edit.",409);let i=r?.fragment.length??0;if(t.kind!=="rm"&&!r)throw new h("Expected Markdown content.");if((t.kind==="insert"||n&&t.kind==="set")&&i===0)throw new h("Empty block content. Use page rm --block to remove a block.");let a=t.kind==="insert"?[]:n?[n.node]:e.toArray(),l=[...new Set([...r?.losses??[],...ke(a)])];if(t.kind!=="rm")V(l,t.allowLoss);let o=n?.index??0;if(t.kind==="insert")o=t.after?B(e,t.after).index+1:e.length;let s=r?.fragment.toArray().map((c)=>{if(!(c instanceof j.XmlElement)&&!(c instanceof j.XmlText))throw new d("Unsupported document block; no changes were made.");return c.clone()})??[],f=e.toArray();if(t.kind!=="insert")f.splice(o,n?1:f.length);if(P(X([...f,...t.kind==="rm"?[]:r?.fragment.toArray()??[]]),t.nodeReaders??[]),t.kind!=="insert")e.delete(o,n?1:e.length);if(t.kind!=="rm"&&s.length){if(e.insert(o,s),n&&s[0]&&"setAttribute"in s[0])s[0].setAttribute("id",n.anchor)}return t.kind==="rm"?[]:l};import{HocuspocusProvider as Je,HocuspocusProviderWebsocket as Ke}from"@hocuspocus/provider";import{HttpsProxyAgent as Ve}from"https-proxy-agent";import Ge from"ws";import*as $e from"yjs";class G extends d{}class Ae{doc=new $e.Doc;fragment=this.doc.getXmlFragment("default");socket;provider;agent;pending;failure;writing=!1;acknowledged=!1;disposed=!1;deadline;constructor(e,t,r,n=20000){this.deadline=n,q(r);let i=xe(e);if(i)q(i),this.agent=new Ve(i);let a=this.agent;class l extends Ge{constructor(o){super(o,{agent:a,handshakeTimeout:n})}}this.socket=new Ke({url:e,WebSocketPolyfill:l,autoConnect:!1,maxAttempts:1,onClose:()=>this.fail(new d("Live connection closed."))}),this.socket.on("maxAttemptsFailed",()=>this.fail(new d("Cannot connect to the live server."))),this.provider=new Je({websocketProvider:this.socket,name:t,document:this.doc,awareness:null,token:r,forceSyncInterval:!1,flushDelay:!1,onClose:()=>this.fail(new d("Live document connection closed.")),onSynced:()=>this.progress(),onUnsyncedChanges:()=>this.progress(),onAuthenticationFailed:()=>this.fail(new G("Live authentication was refused."))}),this.provider.attach()}progress(){if(this.disposed||this.failure||!this.provider?.isSynced||this.provider.hasUnsyncedChanges)return;if(this.writing)this.acknowledged=!0;this.pending?.resolve()}fail(e){if(this.disposed||this.failure)return;if(this.writing&&!this.acknowledged)e=new d("Live connection failed after sending changes; delivery is uncertain. Inspect the live document before retrying. The command was not replayed.");this.failure=e,this.socket.shouldConnect=!1,this.pending?.reject(e)}async wait(e){if(this.failure)throw this.failure;let t;try{await new Promise((r,n)=>{this.pending={resolve:r,reject:n},t=setTimeout(()=>this.fail(new d("Live synchronization timed out.")),this.deadline),e(),this.progress()})}finally{clearTimeout(t),this.pending=void 0}}async ready(){await this.wait(()=>{this.socket.connect().catch(()=>this.fail(new d("Cannot connect to the live server.")))})}async write(e){if(this.failure)throw this.failure;if(!this.provider.isSynced)throw new d("Live document is not synchronized.");if(this.provider.authorizedScope!=="read-write")throw new d("The connection does not allow writing this page.");let t=!1,r=(n,i)=>{if(i===this)t=!0};this.doc.on("update",r);try{return await this.wait(()=>{this.writing=!0,this.doc.transact(()=>e(this.fragment),this)}),{delivery:t?"acknowledged":"unchanged",persistence:"asynchronous"}}finally{this.doc.off("update",r)}}destroy(){if(this.disposed)return;this.disposed=!0,this.provider.destroy(),this.socket.destroy(),this.agent?.destroy(),this.doc.destroy()}}var Pe=async(e,t,r,n={})=>{await e.preparePages?.(t);let i=!!n.writable,a=await e.liveCredentials?.(i);if(!a){q(e.config.token.value);let l=await e.request("/api/extensions/configuration/").catch((o)=>{if(o instanceof d&&o.status===404)throw new d("Page commands require the for-plane API-key pages extension.",404);throw o});if(typeof l.release!=="string"||!l.release)throw new d("The for-plane runtime has no active extension release.");a={release:l.release,token:JSON.stringify({apiKey:e.config.token.value,readOnly:!i})}}for(let l=0;l<2;l++){let o=new URL(`${e.config.url.value}/live/collaboration`);if(o.protocol=o.protocol==="https:"?"wss:":"ws:",o.searchParams.set("documentType","project_page"),o.searchParams.set("projectId",t),o.searchParams.set("workspaceSlug",e.config.workspace.value),a.release)o.searchParams.set("forPlaneRelease",a.release);let s=new Ae(o.href,r,a.token);try{return await s.ready(),s}catch(f){if(s.destroy(),l===0&&f instanceof G){let c=await e.liveCredentials?.(i,!0);if(c){a=c;continue}}throw new d(k(f instanceof Error?f.message:String(f)))}}throw new d("Live session authentication failed after one refresh.")};var Ze=async(e,t=!1)=>{let r=U(e,"file"),n=U(e,"text");if(r!==void 0&&n!==void 0)throw new h("--file and --text are mutually exclusive.");if(r!==void 0)try{return await Qe(r,"utf8")}catch{throw new h(`Cannot read Markdown file "${r}".`)}if(n!==void 0||t)return n;throw new h("Expected --file <path> or --text <markdown>.")},Ee=(e)=>{if(e.length)console.error(k(`Warning: ${e.join("; ")}`))},Q=(e)=>`${e.id} ${e.deleted?"deleted":e.delivery??"created"}${e.stamped!==void 0?`; stamped ${e.stamped} blocks`:""}${e.delivery?"; database persistence is asynchronous":""}`,Ct=async(e,t,r,n)=>{let i=O(r.positionals[0],"a project"),a=e==="page create",l=e==="page rm",o=a?F(r,"name"):O(r.positionals[1],"a page UUID or name"),s=r.flags.has("block")?F(r,"block"):void 0,f=r.flags.has("after")?F(r,"after"):void 0,c=C(r,"at-end"),p=U(r,"if-match"),w=C(r,"force"),S=C(r,"allow-loss");if(l&&!C(r,"yes"))throw new h("Deletion requires --yes.");if((p!==void 0||w)&&!s)throw new h("--if-match and --force require --block.");if(p!==void 0&&!/^[a-f0-9]{64}$/i.test(p))throw new h("--if-match expects the SHA-256 fingerprint from page read --json.");if(e==="page read"&&!s)throw new h("Expected --block <anchor>.");if(e==="page insert"&&Boolean(f)===c)throw new h("Choose exactly one of --after <anchor> or --at-end.");let y=a||e==="page set"||e==="page insert"?await Ze(r,a):void 0,A=await Se(t,i),b,I;try{if(y!==void 0)b=await ye(t,y),V(b.losses,S);let g=a?await t.request(Z(A.id),{method:"POST",body:{name:o,access:0}}):await Ye(t,A.id,o);if(a)I=g;if(a&&!b){E({id:g.id,name:g.name},n,Q);return}if(l&&!s){ee(g,!0);let v=`${Z(A.id)}${g.id}/`;if(!g.archived_at)try{await t.request(`${v}archive/`,{method:"POST"})}catch(u){throw new d(`Archiving page ${g.id} was not confirmed: ${u instanceof Error?u.message:String(u)}. Inspect this UUID before retrying; deletion was not attempted.`)}try{await t.request(v,{method:"DELETE"})}catch(u){throw new d(`Page ${g.id} was archived, but deletion was not confirmed: ${u instanceof Error?u.message:String(u)}. Inspect it by UUID before retrying.`)}E({id:g.id,deleted:!0},n,Q);return}let te=e==="page outline"||e==="page read";if(!te)ee(g);let Y=await Pe(t,A.id,g.id,{writable:!te});try{if(e==="page outline")E(he(Y.fragment),n,(v)=>v.map((u)=>`${u.index} ${u.shortAnchor??"(no anchor)"} ${u.kind} ${u.preview}`).join(`
2
+ `));else if(e==="page read"){let v=we(Y.fragment,O(s,"--block <anchor>"));Ee(v.losses),E(v,n,(u)=>u.markdown)}else{let u=X([...Y.fragment.toArray(),...b?.fragment.toArray()??[]]).length?await t.nodeReaders?.()??[]:[],re,_=[];t.markPageMutation?.();let Le=await Y.write((H)=>{if(e==="page stamp")P(X(H.toArray()),u),re=K(H);else _=ve(H,{kind:l?"rm":e==="page insert"?"insert":"set",block:s,after:f,atEnd:c,ifMatch:p?.toLowerCase(),force:w,allowLoss:S,nodeReaders:u},b)});Ee(_),E({id:g.id,...Le,stamped:re,losses:_},n,Q)}}finally{Y.destroy()}}catch(g){if(I)throw new d(`Page ${I.id} was created, but its content operation did not complete: ${g instanceof Error?g.message:String(g)}. Inspect this page before retrying; do not create a duplicate.`);throw g}finally{b?.doc.destroy()}};export{Ct as runPageContent};
@@ -0,0 +1 @@
1
+ import{a as l}from"./cli-8wxcra9k.js";import{aa as d}from"./cli-2sf0pmt1.js";import{ka as f}from"./cli-5v4ee99d.js";import{homedir as p}from"node:os";import{join as a}from"node:path";var u=(o,c)=>{let g=l(o.configPath,["PLANE_LOGIN","PLANE_PASSWORD"]),n=(s)=>{let i=process.env[s];if(i)return{value:i,origin:"env"};let t=g.get(s);return t?{value:t,origin:"file"}:void 0},r=n("PLANE_LOGIN"),e=n("PLANE_PASSWORD");if(e)f(e.value);if(!r||!e)throw new d(`This Plane does not expose the API-key pages endpoint. Set PLANE_LOGIN and PLANE_PASSWORD in the environment or ${o.configPath} to use its session API. If extensions were just installed, retry with --refresh-pages.`);return{...o,login:r,password:e,cacheDirectory:c??process.env.PLANE_SESSION_CACHE??a(process.env.XDG_CACHE_HOME??a(p(),".cache"),"i-plane","sessions")}};export{u as resolveSessionConfig};
@@ -0,0 +1 @@
1
+ import{O,P as R,Q as b,S as a}from"./cli-tdf7t5es.js";import{ka as u,ma as S}from"./cli-5v4ee99d.js";import{createHash as T,randomUUID as D}from"node:crypto";import{constants as y}from"node:fs";import{chmod as N,lstat as _,mkdir as q,open as k,rename as E,stat as F,unlink as g}from"node:fs/promises";import{join as L}from"node:path";import{setTimeout as j}from"node:timers/promises";var H=20000,x=(e)=>(u(e.sessionId),u(e.csrf),u(P(e)),e),P=(e)=>`session-id=${e.sessionId}; csrftoken=${e.csrf}`,J=(e,i,t)=>L(t,`${T("sha256").update(JSON.stringify([e,i])).digest("hex")}.json`),C=async(e)=>{try{let i=await k(e,y.O_RDONLY|y.O_NOFOLLOW|y.O_NONBLOCK),t;try{let r=await i.stat();if((r.mode&63)!==0||!r.isFile()||r.size>16384)return;t=JSON.parse(await i.readFile("utf8"))}finally{await i.close()}if(t.version!==1||typeof t.userId!=="string"||!t.userId||typeof t.sessionId!=="string"||!t.sessionId||typeof t.csrf!=="string"||!t.csrf||/[;\r\n]/.test(t.sessionId+t.csrf)||typeof t.expiresAt!=="number"||!Number.isFinite(t.expiresAt))return;return x(t),t.expiresAt>Date.now()?t:void 0}catch{return}};class U{config;cachePath;current;flight;constructor(e){if(this.config=e,this.cachePath=J(e.url.value,e.login.value,e.cacheDirectory),u(e.password.value),e.token.value)u(e.token.value)}async raw(e,i={},t=H){let r=`${this.config.url.value}${e}`,o=new AbortController,n;try{let s=await b(r)??fetch,c=new Promise((d,f)=>{n=setTimeout(()=>{o.abort(),f(new a(`Session request timed out after ${t/1000}s: ${e}`))},t)});return await Promise.race([(async()=>{let d=await s(r,{...i,redirect:"manual",signal:o.signal});return{status:d.status,headers:d.headers,text:await d.text()}})(),c])}catch(s){if(s instanceof a)throw s;let c=R(s)?`Connection ${O(r)} denied by the operating system; check sandbox network permissions.`:s instanceof Error?s.message:String(s);throw new a(S(`Session request failed: ${c}`))}finally{if(n!==void 0)clearTimeout(n)}}parse(e,i){if(e.status<200||e.status>=300){let t=e.status===403?" Check page permissions, lock state and CSRF credentials.":"";throw new a(S(`Plane session API answered ${e.status} for ${i}.${t} ${e.text}`).slice(0,450),e.status)}if(!e.text||e.status===204)return;try{return JSON.parse(e.text)}catch{throw new a(`Expected JSON from session API: ${i}`)}}async authenticate(){let e=new Map,i=Date.now()+86400000,t=(w)=>{for(let h of w.getSetCookie()){let[m=""]=h.split(";"),p=m.indexOf("="),I=m.slice(0,p).trim(),l=m.slice(p+1).trim();if(p<1||!["session-id","csrftoken"].includes(I))continue;if(/[;\r\n]/.test(l))throw new a("Invalid session cookie received.");if(l)u(l);e.set(I,l);let A=/(?:^|;)\s*max-age=(-?\d+)/i.exec(h)?.[1];if(A!==void 0)i=Math.min(i,Date.now()+Number(A)*1000)}},r=await this.raw("/auth/get-csrf-token/");t(r.headers);let o=this.parse(r,"/auth/get-csrf-token/").csrf_token??e.get("csrftoken");if(!o)throw new a("Plane did not provide a CSRF token.");u(o);let n=[...e].map(([w,h])=>`${w}=${h}`).join("; ");if(n)u(n);let s=await this.raw("/auth/sign-in/",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Referer:`${this.config.url.value}/`,Cookie:n},body:new URLSearchParams({csrfmiddlewaretoken:o,email:this.config.login.value,password:this.config.password.value}).toString()});t(s.headers);let c=e.get("session-id"),d=e.get("csrftoken");if(![200,302,303].includes(s.status)||!c||!d)throw new a("Plane sign-in failed. Check PLANE_LOGIN and PLANE_PASSWORD; this authentication flow requires password sign-in.",s.status);let f=x({userId:"",sessionId:c,csrf:d,expiresAt:i}),v=this.parse(await this.raw("/api/users/me/",{headers:{Cookie:P(f)}}),"/api/users/me/");if(!v.id)throw new a("Session was not authenticated: no user identifier returned.");return x({...f,userId:v.id})}async session(e=!1){if(!e&&this.current&&this.current.expiresAt>Date.now())return this.current;if(this.flight)return this.flight;let i=this.current;this.flight=(async()=>{let t=await C(this.cachePath);if(t&&(!e||t.sessionId!==i?.sessionId))return t;try{await q(this.config.cacheDirectory,{recursive:!0,mode:448});let s=await _(this.config.cacheDirectory);if(!s.isDirectory()||s.isSymbolicLink())throw Error("Invalid session cache directory");await N(this.config.cacheDirectory,448)}catch{throw new a(`Cannot write session cache in ${this.config.cacheDirectory}. Set PLANE_SESSION_CACHE or --session-cache to a private writable directory.`)}let r=`${this.cachePath}.lock`,o=Date.now(),n;while(!n)try{n=await k(r,"wx",384)}catch(s){if(s.code!=="EEXIST")throw new a("Cannot lock the session cache.");let c=await F(r).catch(()=>{return});if(c&&Date.now()-c.mtimeMs>90000){await g(r).catch(()=>{});continue}if(Date.now()-o>1e4)throw new a("Another command is refreshing the session; retry shortly.");await j(100)}try{let s=await C(this.cachePath);if(s&&(!e||s.sessionId!==i?.sessionId))return s;let c=await this.authenticate(),d=`${this.cachePath}.${D()}.tmp`;try{let f=await k(d,"wx",384);try{await f.writeFile(JSON.stringify({version:1,...c}))}finally{await f.close()}await E(d,this.cachePath)}finally{await g(d).catch(()=>{})}return c}finally{await n.close(),await g(r).catch(()=>{})}})();try{return this.current=await this.flight,this.current}finally{this.flight=void 0}}async request(e,i={}){let t=e.startsWith("/")?e:`/api/workspaces/${encodeURIComponent(this.config.workspace.value)}/${e}`,r=new URLSearchParams;for(let[n,s]of Object.entries(i.query??{}))if(s!==void 0)r.set(n,String(s));let o=r.size?`${t}?${r}`:t;for(let n=0;n<2;n++){let s=await this.session(n===1),c=await this.raw(o,{method:i.method??"GET",headers:{Cookie:P(s),"X-CSRFToken":s.csrf,Referer:`${this.config.url.value}/`,Accept:"application/json",...i.body===void 0?{}:{"Content-Type":"application/json"}},body:i.body===void 0?void 0:JSON.stringify(i.body)},i.timeoutMs);if(c.status===401&&n===0)continue;return this.parse(c,t)}throw new a("Session authentication failed after one refresh.",401)}async listAll(e,i={}){let t=[],r=new Set,o;do{let n=await this.request(e,{...i,query:{...i.query,...o?{cursor:o}:{}}});if(Array.isArray(n))return[...t,...n];if(!n||typeof n!=="object"||!("results"in n)||!Array.isArray(n.results))throw new a(`Unexpected list response from session API: ${e}`);t.push(...n.results);let s=n;if(o=s.next_page_results?s.next_cursor:void 0,o){if(r.has(o))throw new a("Session API repeated a pagination cursor.");r.add(o)}}while(o);return t}}export{U as SessionClient,J as cacheFile,P as cookieHeader};
package/dist/cli.js CHANGED
@@ -1,47 +1,39 @@
1
1
  #!/usr/bin/env node
2
- import{$ as Bt,A as ae,B as ne,C as y,D as _e,E as W,F as J,G as g,H as h,I as _,J as yt,K as x,M as D,N,O as m,P,Q as b,R as S,S as se,T as xe,U as I,W as Te,Y as Kt,Z as Vt,aa as Yt,c as gn,ca as nn,d as Fe,da as on,e as We,ea as rn,f as Ge,g as v,h as L,i as Xt,j as Qt,k as H,l as d,m as a,n as j,o as wt,p as en,q as qe,s as Ne,t as Ue,u as U,v as tn,w,x as ie,z as A}from"./chunks/cli-gyrf14cz.js";var B=()=>({groups:Fe,flow:Ge,notes:We,globalOptions:L}),ce=(e)=>`${e.name}${e.args===void 0?"":` ${e.args}`}`,V=(e,t,n)=>{let r=e.split(/\s+/),o=[],s="";for(let i of r)if(s==="")s=i;else if(`${s} ${i}`.length+n.length<=t)s=`${s} ${i}`;else o.push(n+s),s=i;if(s!=="")o.push(n+s);return o},Y=(e)=>{let t=[];for(let n of e.groups){if(t.push(n.title),n.summary!==void 0)t.push(...V(n.summary,96," "),"");t.push(...w(n.commands.map((r)=>({name:ce(r),text:r.alias===void 0?r.summary:`${r.summary} (alias: ${r.alias})`})))),t.push("")}t.push("FLOW"),t.push(...w(e.flow.map((n)=>({name:n.command,text:n.summary})))),t.push(""),t.push(Z(e.globalOptions),""),t.push("HOW THIS TOOL BEHAVES");for(let n of e.notes)t.push(` ${n.title}`),t.push(...V(n.body,96," ")),t.push("");return t.push("Flags and examples for one command: i-plane <command> --help"),t.join(`
3
- `)},Z=(e=L)=>["GLOBAL OPTIONS",...w(e.map((t)=>({name:`${t.flag}${t.value===void 0?"":` ${t.value}`}`,text:t.summary})))].join(`
4
- `),ue=(e,t=!0)=>{let{command:n}=e,r=[`i-plane ${ce(n)}`,"",...V(n.summary,96," ")];if(n.alias!==void 0)r.push("",` alias: ${n.alias}`);let o=(n.options??[]).filter((s)=>s.flag!=="--json");if(o.length>0)r.push("","OPTIONS"),r.push(...w(o.map((s)=>({name:s.value===void 0?s.flag:`${s.flag} ${s.value}`,text:`${s.required===!0?"Required. ":""}${s.summary}`}))));if(n.notes!==void 0&&n.notes.length>0){r.push("","USAGE NOTES");for(let s of n.notes)r.push(...V(s,96," "),"");if(r[r.length-1]==="")r.pop()}if(n.examples!==void 0&&n.examples.length>0){r.push("","EXAMPLES");for(let s of n.examples)r.push(` ${s}`)}if(n.next!==void 0&&n.next.length>0){r.push("","USUALLY NEXT");for(let s of n.next)r.push(` ${s}`)}if(t)r.push("",Z(e.globalOptions));return r.join(`
5
- `)},Me=(e,t)=>{let n=[t,"",` i-plane ${ce(e)}`];if(e.examples!==void 0&&e.examples.length>0){n.push("");for(let o of e.examples)n.push(` ${o}`)}let r=(e.options??[]).filter((o)=>o.flag!=="--json"&&o.value!==void 0);if(r.length>0)n.push(""," flags:"),n.push(...w(r.map((o)=>({name:`${o.flag} ${o.value}`,text:`${o.required===!0?"Required. ":""}${o.summary}`}))," "));return n.push("",` full help: i-plane ${e.name} --help`),n.join(`
6
- `)};import{readFileSync as dn}from"node:fs";import{homedir as He}from"node:os";import{join as me}from"node:path";var fe=me(He(),".config","plane","credentials"),ge=(e)=>{let t=new Map,n;try{n=dn(e,"utf8")}catch{return t}for(let r of n.split(`
7
- `)){let o=r.trim();if(o===""||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim(),l=o.slice(s+1).trim();if(l.startsWith('"')&&l.endsWith('"')||l.startsWith("'")&&l.endsWith("'"))l=l.slice(1,-1);t.set(i,l)}return t},O=(e,t,n,r)=>{if(e!==void 0&&e!=="")return{value:e,origin:"flag"};for(let o of t){let s=process.env[o];if(s!==void 0&&s!=="")return{value:s,origin:"env"}}for(let o of n){let s=r.get(o);if(s!==void 0&&s!=="")return{value:s,origin:"file"}}return},ln=(e,t,n)=>{let r=e.replace(/\/+$/,""),o;try{o=new URL(r)}catch{throw new d(`The url is not a valid address: ${r}
8
- it came from ${t==="file"?n:t}
9
- expected something like https://plane.example.com`)}if(o.protocol!=="http:"&&o.protocol!=="https:")throw new d(`The url must be http or https, got ${o.protocol} in ${r}`);return r},pe=(e,t,n,r)=>new d(`No ${e}. Set it one of three ways, highest wins:
10
- --${e} <value>
11
- ${t}=<value> in the environment
12
- ${n}=<value> in ${r}`),Ke=(e)=>{let t=e.configPath??process.env.PLANE_CONFIG??fe,n=ge(t);return O(e.token,["PLANE_API_KEY","PLANE_TOKEN"],["PLANE_API_KEY"],n)?.value},ye=(e,t=!1)=>{let n=e.configPath??process.env.PLANE_CONFIG??fe,r=ge(n),o=O(e.url,["PLANE_URL","PLANE_BASE_URL"],["PLANE_URL","PLANE_BASE_URL"],r),s=O(e.token,["PLANE_API_KEY","PLANE_TOKEN"],["PLANE_API_KEY"],r),i=O(e.workspace,["PLANE_WORKSPACE","PLANE_WORKSPACE_SLUG"],["PLANE_WORKSPACE","PLANE_WORKSPACE_SLUG"],r);if(o===void 0)throw pe("url","PLANE_URL","PLANE_URL",n);if(s===void 0&&!t)throw pe("token","PLANE_API_KEY","PLANE_API_KEY",n);if(i===void 0)throw pe("workspace","PLANE_WORKSPACE","PLANE_WORKSPACE",n);return{url:{value:ln(o.value,o.origin,n),origin:o.origin},token:s??{value:"",origin:"default"},workspace:i,configPath:n}},Ve=(e)=>e.length<=10?"***":`${e.slice(0,6)}…${e.slice(-4)}`,we=(e,t)=>{let n=e.configPath??process.env.PLANE_CONFIG??fe,r=ge(n);return{login:O(void 0,["PLANE_LOGIN"],["PLANE_LOGIN"],r),password:O(void 0,["PLANE_PASSWORD"],["PLANE_PASSWORD"],r),cacheDirectory:t??process.env.PLANE_SESSION_CACHE??me(process.env.XDG_CACHE_HOME??me(He(),".cache"),"i-plane","sessions")}},Be=(e,t)=>{let n=we(e,t),r=ye(e,!0);if(!n.login||!n.password)throw new d(`Pages need PLANE_LOGIN and PLANE_PASSWORD in the environment or ${r.configPath}. An API key is not required.`);return{...r,...n,login:n.login,password:n.password}};var T=["urgent","high","medium","low","none"],Pe=(e)=>{let t=T.indexOf(e);return t===-1?T.length:t},F=["backlog","unstarted","started","completed","cancelled"],q=(e)=>{let t=F.indexOf(e);return t===-1?F.length:t};var Ye=async(e,t)=>{let n=await J(e),r=await Promise.all(n.map(async(o)=>{let s=await e.request(`projects/${o.id}/summary/`);return{identifier:o.identifier,name:o.name,counts:s.counts}}));return{workspace:t.workspace.value,url:t.url.value,projects:r}},Ze=(e)=>{let t=[`WORKSPACE ${e.workspace} ${e.url}`,""];if(e.projects.length===0)t.push("no projects yet");else t.push("PROJECTS"),t.push(...w(e.projects.map((n)=>({name:n.identifier,text:`${n.name} — ${n.counts.issues} work items, ${n.counts.cycles} cycles, ${n.counts.modules} modules`}))));return t.push("","Next: i-plane list <PROJECT> Map: i-plane guide"),t.join(`
13
- `)},Je=(e)=>e.length===0?"no projects":w(e.map((t)=>({name:t.identifier,text:y(t.name)})),"").join(`
14
- `),Xe=async(e,t)=>{let n=t.positionals[0]??a(t,"project");if(n===void 0)throw new d("Which project?");let r=await g(e,n);return[...await _(e,r.id)].sort((s,i)=>q(s.group)-q(i.group))},Qe=(e)=>w(e.map((t)=>({name:t.name,text:t.group+(t.default===!0?" (default)":"")})),"").join(`
15
- `),et=async(e,t)=>{let n=t.positionals[0]??a(t,"project");if(n===void 0)throw new d("Which project?");let r=await g(e,n);return e.listAll(`projects/${r.id}/labels/`,{query:{fields:"id,name,color",per_page:100}})},tt=(e)=>e.length===0?"no labels":e.map((t)=>t.name).join(`
16
- `),nt=(e)=>e.listAll("members-lite/",{query:{per_page:100}}),ot=(e)=>e.length===0?"no members":w(e.map((t)=>({name:t.display_name??t.id,text:t.email??""})),"").join(`
17
- `),rt=(e)=>({url:{value:e.url.value,origin:e.url.origin},workspace:{value:e.workspace.value,origin:e.workspace.origin},token:{value:Ve(e.token.value),origin:e.token.origin},configPath:e.configPath}),st=(e)=>w([{name:"url",text:`${e.url.value} (${e.url.origin})`},{name:"workspace",text:`${e.workspace.value} (${e.workspace.origin})`},{name:"token",text:`${e.token.value} (${e.token.origin})`},{name:"file",text:e.configPath}],"").join(`
18
- `),it=(e)=>e.request("/api/v1/users/me/"),at=(e)=>w([{name:"name",text:e.display_name??"?"},{name:"email",text:e.email??"?"},{name:"id",text:e.id}],"").join(`
19
- `);var he=async(e,t,n)=>(await e.listAll(`projects/${t}/issues/${n}/comments/`,{query:{fields:"id,comment_html,created_at,actor",per_page:100}})).map((o)=>({id:o.id,author:typeof o.actor==="object"&&o.actor!==null?o.actor.display_name??o.actor.id:o.actor??"?",created_at:o.created_at,body:N(o.comment_html)})).sort((o,s)=>o.created_at.localeCompare(s.created_at)),dt=async(e,t)=>{let n=m(t.positionals[0],"a work item reference"),{issue:r,projectId:o}=await h(e,n,a(t,"project"));return he(e,o,r.id)},X=(e)=>e.length===0?"no comments":e.map((t)=>`${t.created_at} ${t.author} [${t.id}]
2
+ import{b as Kt,c as Yt,d as De}from"./chunks/cli-8wxcra9k.js";import{C as Ie,E as Lt,F as Et,H as Ut,I as Dt,J as zt,L as Jt,e as F,f as J,g as y,h as j,i as C,j as at,k as x,m as D,n as U,o as u,p as P,q as R,r as v,s as oe,t as ye,u as I,v as he,w as Zt}from"./chunks/cli-hgk20taa.js";import{M as Gt,Q as Wt,R as Vt,S,T as Bt}from"./chunks/cli-tdf7t5es.js";import{$ as W,U as qe,V as Le,W as Ee,X as O,Y as q,Z as Ht,_ as Ft,aa as d,ba as i,ca as h,da as Nt,ea as se}from"./chunks/cli-2sf0pmt1.js";import{ia as sn,ja as w,ka as ve,na as b,oa as ae,pa as z,qa as g,ra as we}from"./chunks/cli-5v4ee99d.js";var K=()=>({groups:qe,flow:Ee,notes:Le,globalOptions:q}),le=(e)=>`${e.name}${e.args===void 0?"":` ${e.args}`}`,B=(e,t,n)=>{let o=e.split(/\s+/),r=[],s="";for(let a of o)if(s==="")s=a;else if(`${s} ${a}`.length+n.length<=t)s=`${s} ${a}`;else r.push(n+s),s=a;if(s!=="")r.push(n+s);return r},Y=(e)=>{let t=[];for(let n of e.groups){if(t.push(n.title),n.summary!==void 0)t.push(...B(n.summary,96," "),"");t.push(...w(n.commands.map((o)=>({name:le(o),text:o.alias===void 0?o.summary:`${o.summary} (alias: ${o.alias})`})))),t.push("")}t.push("FLOW"),t.push(...w(e.flow.map((n)=>({name:n.command,text:n.summary})))),t.push(""),t.push(Z(e.globalOptions),""),t.push("HOW THIS TOOL BEHAVES");for(let n of e.notes)t.push(` ${n.title}`),t.push(...B(n.body,96," ")),t.push("");return t.push("Flags and examples for one command: i-plane <command> --help"),t.join(`
3
+ `)},Z=(e=q)=>["GLOBAL OPTIONS",...w(e.map((t)=>({name:`${t.flag}${t.value===void 0?"":` ${t.value}`}`,text:t.summary})))].join(`
4
+ `),ce=(e,t=!0)=>{let{command:n}=e,o=[`i-plane ${le(n)}`,"",...B(n.summary,96," ")];if(n.alias!==void 0)o.push("",` alias: ${n.alias}`);let r=(n.options??[]).filter((s)=>s.flag!=="--json");if(r.length>0)o.push("","OPTIONS"),o.push(...w(r.map((s)=>({name:s.value===void 0?s.flag:`${s.flag} ${s.value}`,text:`${s.required===!0?"Required. ":""}${s.summary}`}))));if(n.notes!==void 0&&n.notes.length>0){o.push("","USAGE NOTES");for(let s of n.notes)o.push(...B(s,96," "),"");if(o[o.length-1]==="")o.pop()}if(n.examples!==void 0&&n.examples.length>0){o.push("","EXAMPLES");for(let s of n.examples)o.push(` ${s}`)}if(n.next!==void 0&&n.next.length>0){o.push("","USUALLY NEXT");for(let s of n.next)o.push(` ${s}`)}if(t)o.push("",Z(e.globalOptions));return o.join(`
5
+ `)},Ue=(e,t)=>{let n=[t,"",` i-plane ${le(e)}`];if(e.examples!==void 0&&e.examples.length>0){n.push("");for(let r of e.examples)n.push(` ${r}`)}let o=(e.options??[]).filter((r)=>r.flag!=="--json"&&r.value!==void 0);if(o.length>0)n.push(""," flags:"),n.push(...w(o.map((r)=>({name:`${r.flag} ${r.value}`,text:`${r.required===!0?"Required. ":""}${r.summary}`}))," "));return n.push("",` full help: i-plane ${e.name} --help`),n.join(`
6
+ `)};var L=["urgent","high","medium","low","none"],ue=(e)=>{let t=L.indexOf(e);return t===-1?L.length:t},H=["backlog","unstarted","started","completed","cancelled"],E=(e)=>{let t=H.indexOf(e);return t===-1?H.length:t};var ze=async(e,t)=>{let n=await J(e),o=await Promise.all(n.map(async(r)=>{let s=await e.request(`projects/${r.id}/summary/`);return{identifier:r.identifier,name:r.name,counts:s.counts}}));return{workspace:t.workspace.value,url:t.url.value,projects:o}},Me=(e)=>{let t=[`WORKSPACE ${e.workspace} ${e.url}`,""];if(e.projects.length===0)t.push("no projects yet");else t.push("PROJECTS"),t.push(...w(e.projects.map((n)=>({name:n.identifier,text:`${n.name} — ${n.counts.issues} work items, ${n.counts.cycles} cycles, ${n.counts.modules} modules`}))));return t.push("","Next: i-plane list <PROJECT> Map: i-plane guide"),t.join(`
7
+ `)},He=(e)=>e.length===0?"no projects":w(e.map((t)=>({name:t.identifier,text:g(t.name)})),"").join(`
8
+ `),Fe=async(e,t)=>{let n=t.positionals[0]??i(t,"project");if(n===void 0)throw new d("Which project?");let o=await y(e,n);return[...await C(e,o.id)].sort((s,a)=>E(s.group)-E(a.group))},Ne=(e)=>w(e.map((t)=>({name:t.name,text:t.group+(t.default===!0?" (default)":"")})),"").join(`
9
+ `),Ge=async(e,t)=>{let n=t.positionals[0]??i(t,"project");if(n===void 0)throw new d("Which project?");let o=await y(e,n);return e.listAll(`projects/${o.id}/labels/`,{query:{fields:"id,name,color",per_page:100}})},We=(e)=>e.length===0?"no labels":e.map((t)=>t.name).join(`
10
+ `),Ve=(e)=>e.listAll("members-lite/",{query:{per_page:100}}),Be=(e)=>e.length===0?"no members":w(e.map((t)=>({name:t.display_name??t.id,text:t.email??""})),"").join(`
11
+ `),Ke=(e)=>({url:{value:e.url.value,origin:e.url.origin},workspace:{value:e.workspace.value,origin:e.workspace.origin},token:{value:De(e.token.value),origin:e.token.origin},configPath:e.configPath}),Ye=(e)=>w([{name:"url",text:`${e.url.value} (${e.url.origin})`},{name:"workspace",text:`${e.workspace.value} (${e.workspace.origin})`},{name:"token",text:`${e.token.value} (${e.token.origin})`},{name:"file",text:e.configPath},...e.pages?[{name:"pages",text:`${e.pages.mode}: ${e.pages.reason}${e.pages.expiresAt?` Valid until ${e.pages.expiresAt}.`:""}`}]:[]],"").join(`
12
+ `),Ze=(e)=>e.request("/api/v1/users/me/"),Je=(e)=>w([{name:"name",text:e.display_name??"?"},{name:"email",text:e.email??"?"},{name:"id",text:e.id}],"").join(`
13
+ `);var pe=async(e,t,n)=>(await e.listAll(`projects/${t}/issues/${n}/comments/`,{query:{fields:"id,comment_html,created_at,actor",per_page:100}})).map((r)=>({id:r.id,author:typeof r.actor==="object"&&r.actor!==null?r.actor.display_name??r.actor.id:r.actor??"?",created_at:r.created_at,body:U(r.comment_html)})).sort((r,s)=>r.created_at.localeCompare(s.created_at)),Xe=async(e,t)=>{let n=u(t.positionals[0],"a work item reference"),{issue:o,projectId:r}=await j(e,n,i(t,"project"));return pe(e,r,o.id)},X=(e)=>e.length===0?"no comments":e.map((t)=>`${t.created_at} ${t.author} [${t.id}]
20
14
 
21
15
  ${t.body}`).join(`
22
16
 
23
- `);var Q={pending:-2,rejected:-1,snoozed:0,accepted:1,duplicate:2},E=(e,t)=>{let n=e.issue_detail??(typeof e.issue==="object"?e.issue:void 0),r=typeof e.issue==="string"?e.issue:e.issue.id;return{id:e.id,issueId:r,ref:n?.sequence_id===void 0?r:`${t.identifier}-${n.sequence_id}`,name:y(n?.name??r),status:Object.entries(Q).find(([,o])=>o===e.status)?.[0]??String(e.status),statusCode:e.status,priority:n?.priority??"none",description:N(n?.description_html),snoozedUntil:e.snoozed_till??null,duplicateTo:e.duplicate_to??null}},$e=(e,t)=>e.listAll(`projects/${t}/intake-issues/`,{query:{per_page:100}}),cn=async(e,t,n)=>{if(W(n))return e.request(`projects/${t.id}/intake-issues/${n}/`);let o=(await $e(e,t.id)).find((s)=>E(s,t).ref.toLowerCase()===n.toLowerCase());if(o===void 0)throw new d(`No intake work item matches "${n}". Use its readable reference or underlying work item UUID.`);return o},lt=async(e,t,n)=>{if(W(n))return{issueId:n,ref:n};let r=(await $e(e,t.id)).find((o)=>E(o,t).ref.toLowerCase()===n.toLowerCase());if(r!==void 0){let o=E(r,t);return{issueId:o.issueId,ref:o.ref}}try{let o=await h(e,n,t.id,"id,project,sequence_id");if(o.projectId!==t.id)throw new d(`${n} does not belong to project ${t.identifier}.`);return{issueId:o.issue.id,ref:`${t.identifier}-${o.issue.sequence_id}`}}catch(o){if(o instanceof U&&o.status===404)throw new d(`Cannot resolve intake reference "${n}". The server can hide expired snoozes from both lookup endpoints. Pass the underlying work item UUID (issueId in JSON).`);throw o}},ct=(e)=>{let t={},n=a(e,"name");if(n!==void 0)t.name=m(n,"a work item name");let r=a(e,"priority");if(r!==void 0)t.priority=b(r,T,"priority");let o=a(e,"description");if(o!==void 0)t.description_html=D(o);return t},ut=async(e,t)=>{let n=a(t,"status"),r=n===void 0?void 0:b(n,Object.keys(Q),"status"),o=await g(e,m(t.positionals[0]??a(t,"project"),"a project reference")),s=(await $e(e,o.id)).map((i)=>E(i,o));return r===void 0?s:s.filter((i)=>i.status===r)},pt=async(e,t)=>{let n=m(t.positionals.join(" "),"an intake work item name"),r={issue:{...ct(t),name:n}},o=await g(e,P(t,"project")),s=await e.request(`projects/${o.id}/intake-issues/`,{method:"POST",body:r});return E(s,o)},mt=async(e,t)=>{let n=m(t.positionals[0],"an intake work item reference"),r=await g(e,P(t,"project"));return E(await cn(e,r,n),r)},ft=async(e,t)=>{let n=m(t.positionals[0],"an intake work item reference"),r={},o=ct(t);if(Object.keys(o).length>0)r.issue=o;let s=a(t,"status"),i=s===void 0?void 0:b(s,Object.keys(Q),"status"),l=a(t,"snooze-until"),f=a(t,"duplicate-of");if(l!==void 0&&i!=="snoozed")throw new d("--snooze-until requires --status snoozed.");if(f!==void 0&&i!=="duplicate")throw new d("--duplicate-of requires --status duplicate.");if(i!==void 0)r.status=Q[i],r.snoozed_till=null,r.duplicate_to=null;if(i==="snoozed"){let k=S(m(l,"--snooze-until YYYY-MM-DD"),"snooze-until");if(k===null)throw new d("A snoozed work item needs a date, not none.");r.snoozed_till=`${k}T00:00:00Z`}if(i==="duplicate")m(f,"--duplicate-of <ID>");I(r);let u=await g(e,P(t,"project")),c=await lt(e,u,n);if(f!==void 0){let k=await h(e,f,u.id);if(k.projectId!==u.id)throw new d("The duplicate target must belong to the same project.");if(k.issue.id===c.issueId)throw new d("A work item cannot be a duplicate of itself.");r.duplicate_to=k.issue.id}let C=await e.request(`projects/${u.id}/intake-issues/${c.issueId}/`,{method:"PATCH",body:r});return E(C,u)},gt=async(e,t)=>{if(!j(t,"yes"))throw new d("Deleting cannot be undone. Repeat with --yes.");let n=m(t.positionals[0],"an intake work item reference"),r=await g(e,P(t,"project")),o=await lt(e,r,n);return await e.request(`projects/${r.id}/intake-issues/${o.issueId}/`,{method:"DELETE"}),o},je=(e)=>e.length===0?"no intake work items":w(e.map((t)=>({name:t.ref,text:`${t.name} [${t.priority}] (${t.status})`})),"").join(`
24
- `),ee=(e)=>`${je([e])}${e.snoozedUntil===null?"":`
17
+ `);var Q={pending:-2,rejected:-1,snoozed:0,accepted:1,duplicate:2},T=(e,t)=>{let n=e.issue_detail??(typeof e.issue==="object"?e.issue:void 0),o=typeof e.issue==="string"?e.issue:e.issue.id;return{id:e.id,issueId:o,ref:n?.sequence_id===void 0?o:`${t.identifier}-${n.sequence_id}`,name:g(n?.name??o),status:Object.entries(Q).find(([,r])=>r===e.status)?.[0]??String(e.status),statusCode:e.status,priority:n?.priority??"none",description:U(n?.description_html),snoozedUntil:e.snoozed_till??null,duplicateTo:e.duplicate_to??null}},me=(e,t)=>e.listAll(`projects/${t}/intake-issues/`,{query:{per_page:100}}),en=async(e,t,n)=>{if(F(n))return e.request(`projects/${t.id}/intake-issues/${n}/`);let r=(await me(e,t.id)).find((s)=>T(s,t).ref.toLowerCase()===n.toLowerCase());if(r===void 0)throw new d(`No intake work item matches "${n}". Use its readable reference or underlying work item UUID.`);return r},Qe=async(e,t,n)=>{if(F(n))return{issueId:n,ref:n};let o=(await me(e,t.id)).find((r)=>T(r,t).ref.toLowerCase()===n.toLowerCase());if(o!==void 0){let r=T(o,t);return{issueId:r.issueId,ref:r.ref}}try{let r=await j(e,n,t.id,"id,project,sequence_id");if(r.projectId!==t.id)throw new d(`${n} does not belong to project ${t.identifier}.`);return{issueId:r.issue.id,ref:`${t.identifier}-${r.issue.sequence_id}`}}catch(r){if(r instanceof S&&r.status===404)throw new d(`Cannot resolve intake reference "${n}". The server can hide expired snoozes from both lookup endpoints. Pass the underlying work item UUID (issueId in JSON).`);throw r}},et=(e)=>{let t={},n=i(e,"name");if(n!==void 0)t.name=u(n,"a work item name");let o=i(e,"priority");if(o!==void 0)t.priority=R(o,L,"priority");let r=i(e,"description");if(r!==void 0)t.description_html=D(r);return t},tt=async(e,t)=>{let n=i(t,"status"),o=n===void 0?void 0:R(n,Object.keys(Q),"status"),r=await y(e,u(t.positionals[0]??i(t,"project"),"a project reference")),s=(await me(e,r.id)).map((a)=>T(a,r));return o===void 0?s:s.filter((a)=>a.status===o)},nt=async(e,t)=>{let n=u(t.positionals.join(" "),"an intake work item name"),o={issue:{...et(t),name:n}},r=await y(e,P(t,"project")),s=await e.request(`projects/${r.id}/intake-issues/`,{method:"POST",body:o});return T(s,r)},rt=async(e,t)=>{let n=u(t.positionals[0],"an intake work item reference"),o=await y(e,P(t,"project"));return T(await en(e,o,n),o)},ot=async(e,t)=>{let n=u(t.positionals[0],"an intake work item reference"),o={},r=et(t);if(Object.keys(r).length>0)o.issue=r;let s=i(t,"status"),a=s===void 0?void 0:R(s,Object.keys(Q),"status"),l=i(t,"snooze-until"),p=i(t,"duplicate-of");if(l!==void 0&&a!=="snoozed")throw new d("--snooze-until requires --status snoozed.");if(p!==void 0&&a!=="duplicate")throw new d("--duplicate-of requires --status duplicate.");if(a!==void 0)o.status=Q[a],o.snoozed_till=null,o.duplicate_to=null;if(a==="snoozed"){let _=v(u(l,"--snooze-until YYYY-MM-DD"),"snooze-until");if(_===null)throw new d("A snoozed work item needs a date, not none.");o.snoozed_till=`${_}T00:00:00Z`}if(a==="duplicate")u(p,"--duplicate-of <ID>");I(o);let m=await y(e,P(t,"project")),f=await Qe(e,m,n);if(p!==void 0){let _=await j(e,p,m.id);if(_.projectId!==m.id)throw new d("The duplicate target must belong to the same project.");if(_.issue.id===f.issueId)throw new d("A work item cannot be a duplicate of itself.");o.duplicate_to=_.issue.id}let k=await e.request(`projects/${m.id}/intake-issues/${f.issueId}/`,{method:"PATCH",body:o});return T(k,m)},st=async(e,t)=>{if(!h(t,"yes"))throw new d("Deleting cannot be undone. Repeat with --yes.");let n=u(t.positionals[0],"an intake work item reference"),o=await y(e,P(t,"project")),r=await Qe(e,o,n);return await e.request(`projects/${o.id}/intake-issues/${r.issueId}/`,{method:"DELETE"}),r},fe=(e)=>e.length===0?"no intake work items":w(e.map((t)=>({name:t.ref,text:`${t.name} [${t.priority}] (${t.status})`})),"").join(`
18
+ `),ee=(e)=>`${fe([e])}${e.snoozedUntil===null?"":`
25
19
  snoozed until ${e.snoozedUntil}`}${e.duplicateTo===null?"":`
26
20
  duplicate of ${e.duplicateTo}`}${e.description===""?"":`
27
21
 
28
- ${e.description}`}`;var te=async(e,t)=>{if(W(t))return t;let n=await e.listAll("members-lite/",{query:{per_page:100}}),r=n.filter((o)=>o.email?.toLowerCase()===t.toLowerCase());if(r.length===1&&r[0]!==void 0)return r[0].id;if(r.length>1)throw new d(`Ambiguous member "${t}".`);return x(n.map((o)=>({...o,name:o.display_name??o.email??o.id})),t,"member").id},Ae=async(e,t,n,r)=>{let o={},s=a(t,"name");if(s!==void 0)o.name=m(s,"a work item name");let i=a(t,"priority");if(i!==void 0)o.priority=b(i,T,"priority");let l=a(t,"description");if(l!==void 0)o.description_html=D(l);let f=a(t,"due");if(f!==void 0)o.target_date=S(f,"due");let u=a(t,"start");if(u!==void 0)o.start_date=S(u,"start");let c=a(t,"label"),C=a(t,"labels");if(c!==void 0&&C!==void 0)throw new d("Use either --label to add labels or --labels to replace them.");let k=a(t,"state");if(k!==void 0)o.state=yt(await _(e,n),k).id;let de=a(t,"parent");if(de!==void 0)if(de==="none")o.parent=null;else{let R=await h(e,de,n);if(R.issue.id===r?.id)throw new d("A work item cannot be its own parent.");o.parent=R.issue.id}let De=a(t,"assignee");if(De!==void 0){let R=[];for(let le of xe(De))R.push(await te(e,le));o.assignees=[...new Set(R)]}let ze=c??C;if(ze!==void 0){let R=xe(ze);if(c!==void 0&&R.length===0)throw new d("--label expects labels to add. Use --labels none to clear all labels.");let le=R.length===0?[]:await e.listAll(`projects/${n}/labels/`,{query:{fields:"id,name",per_page:100}}),sn=R.map((an)=>x(le,an,"label").id);o.labels=[...new Set([...c===void 0?[]:r?.labels??[],...sn])]}return o};var un="id,name,sequence_id,priority,state",pn=(e)=>typeof e.state==="object"&&e.state!==null?{name:e.state.name,group:e.state.group}:{name:"?",group:"?"},Ce=(e,t)=>{let n=pn(e);return{ref:`${t}-${e.sequence_id}`,name:y(e.name),state:n.name,group:n.group,priority:e.priority,id:e.id}},mn=(e)=>e==="none"||e===""?"":` [${e}]`,oe=(e)=>{let{rows:t,total:n}=e;if(t.length===0)return n===0?"no work items":`showing 0 of ${n} — raise or drop --limit`;let r=[...w(t.map((o)=>({name:o.ref,text:`${_e(o.name,72)}${mn(o.priority)} (${o.state})`})),"")];if(t.length<n)r.push("",`showing ${t.length} of ${n} — drop --limit to see the rest`);return r.join(`
29
- `)},Pt=async(e,t)=>{let n=t.positionals[0]??a(t,"project");if(n===void 0)throw new d("Which project?");let r=await g(e,n),o=wt(t,"limit"),s=await e.listAll(`projects/${r.id}/issues/`,{query:{fields:un,expand:"state",per_page:100}}),i=a(t,"state")?.toLowerCase(),l=a(t,"priority")?.toLowerCase(),u=[...s.map((c)=>Ce(c,r.identifier)).filter((c)=>{if(i!==void 0){if(!(c.group.toLowerCase()===i||c.state.toLowerCase().startsWith(i)))return!1}if(l!==void 0&&c.priority.toLowerCase()!==l)return!1;return!0})].sort((c,C)=>q(c.group)-q(C.group)||Pe(c.priority)-Pe(C.priority)||c.ref.localeCompare(C.ref));return{rows:o===void 0?u:u.slice(0,o),total:u.length}},ht=async(e,t,n,r)=>{let o=t.positionals[0];if(o===void 0)throw new d("Which work item?");let{issue:s,projectId:i}=await h(e,o,a(t,"project"),"id,name,sequence_id,priority,state,assignees,target_date,start_date,parent,labels,project,description_html"),f=(await _(e,i)).find((c)=>c.id===s.state);return{ref:`${(await g(e,i)).identifier}-${s.sequence_id}`,name:y(s.name),state:f?.name??"?",group:f?.group??"?",priority:s.priority,id:s.id,description:N(s.description_html),assignees:s.assignees??[],labels:s.labels??[],target_date:s.target_date??null,start_date:s.start_date??null,...j(t,"comments")?{comments:await he(e,i,s.id)}:{},parent:s.parent??null,url:`${r}/${n}/projects/${i}/issues/${s.id}`}},$t=(e)=>{let t=[{name:e.ref,text:e.name},{name:"state",text:`${e.state} (${e.group})`},{name:"priority",text:e.priority}];if(e.start_date!=null)t.push({name:"start",text:e.start_date});if(e.target_date!=null)t.push({name:"due",text:e.target_date});if(e.assignees.length>0)t.push({name:"assignees",text:String(e.assignees.length)});if(e.labels.length>0)t.push({name:"labels",text:e.labels.join(", ")});if(e.parent!=null)t.push({name:"parent",text:e.parent});t.push({name:"url",text:e.url});let n=w(t,"").join(`
30
- `),r=e.description===""?n:`${n}
22
+ ${e.description}`}`;var te=async(e,t)=>{if(F(t))return t;let n=await e.listAll("members-lite/",{query:{per_page:100}}),o=n.filter((r)=>r.email?.toLowerCase()===t.toLowerCase());if(o.length===1&&o[0]!==void 0)return o[0].id;if(o.length>1)throw new d(`Ambiguous member "${t}".`);return x(n.map((r)=>({...r,name:r.display_name??r.email??r.id})),t,"member").id},ge=async(e,t,n,o)=>{let r={},s=i(t,"name");if(s!==void 0)r.name=u(s,"a work item name");let a=i(t,"priority");if(a!==void 0)r.priority=R(a,L,"priority");let l=i(t,"description");if(l!==void 0)r.description_html=D(l);let p=i(t,"due");if(p!==void 0)r.target_date=v(p,"due");let m=i(t,"start");if(m!==void 0)r.start_date=v(m,"start");let f=i(t,"label"),k=i(t,"labels");if(f!==void 0&&k!==void 0)throw new d("Use either --label to add labels or --labels to replace them.");let _=i(t,"state");if(_!==void 0)r.state=at(await C(e,n),_).id;let ie=i(t,"parent");if(ie!==void 0)if(ie==="none")r.parent=null;else{let A=await j(e,ie,n);if(A.issue.id===o?.id)throw new d("A work item cannot be its own parent.");r.parent=A.issue.id}let Oe=i(t,"assignee");if(Oe!==void 0){let A=[];for(let de of ye(Oe))A.push(await te(e,de));r.assignees=[...new Set(A)]}let Te=f??k;if(Te!==void 0){let A=ye(Te);if(f!==void 0&&A.length===0)throw new d("--label expects labels to add. Use --labels none to clear all labels.");let de=A.length===0?[]:await e.listAll(`projects/${n}/labels/`,{query:{fields:"id,name",per_page:100}}),Xt=A.map((Qt)=>x(de,Qt,"label").id);r.labels=[...new Set([...f===void 0?[]:o?.labels??[],...Xt])]}return r};var tn="id,name,sequence_id,priority,state",nn=(e)=>typeof e.state==="object"&&e.state!==null?{name:e.state.name,group:e.state.group}:{name:"?",group:"?"},Pe=(e,t)=>{let n=nn(e);return{ref:`${t}-${e.sequence_id}`,name:g(e.name),state:n.name,group:n.group,priority:e.priority,id:e.id}},rn=(e)=>e==="none"||e===""?"":` [${e}]`,ne=(e)=>{let{rows:t,total:n}=e;if(t.length===0)return n===0?"no work items":`showing 0 of ${n} — raise or drop --limit`;let o=[...w(t.map((r)=>({name:r.ref,text:`${we(r.name,72)}${rn(r.priority)} (${r.state})`})),"")];if(t.length<n)o.push("",`showing ${t.length} of ${n} — drop --limit to see the rest`);return o.join(`
23
+ `)},it=async(e,t)=>{let n=he(t),o=t.positionals[0]??i(t,"project");if(o===void 0)throw new d("Which project?");let r=await y(e,o),s=await e.listAll(`projects/${r.id}/issues/`,{query:{fields:tn,expand:"state",per_page:100}}),a=i(t,"state")?.toLowerCase(),l=i(t,"priority")?.toLowerCase(),m=[...s.map((f)=>Pe(f,r.identifier)).filter((f)=>{if(a!==void 0){if(!(f.group.toLowerCase()===a||f.state.toLowerCase().startsWith(a)))return!1}if(l!==void 0&&f.priority.toLowerCase()!==l)return!1;return!0})].sort((f,k)=>E(f.group)-E(k.group)||ue(f.priority)-ue(k.priority)||f.ref.localeCompare(k.ref));return{rows:n===void 0?m:m.slice(0,n),total:m.length}},dt=async(e,t,n,o)=>{let r=t.positionals[0];if(r===void 0)throw new d("Which work item?");let{issue:s,projectId:a}=await j(e,r,i(t,"project"),"id,name,sequence_id,priority,state,assignees,target_date,start_date,parent,labels,project,description_html"),p=(await C(e,a)).find((f)=>f.id===s.state);return{ref:`${(await y(e,a)).identifier}-${s.sequence_id}`,name:g(s.name),state:p?.name??"?",group:p?.group??"?",priority:s.priority,id:s.id,description:U(s.description_html),assignees:s.assignees??[],labels:s.labels??[],target_date:s.target_date??null,start_date:s.start_date??null,...h(t,"comments")?{comments:await pe(e,a,s.id)}:{},parent:s.parent??null,url:`${o}/${n}/projects/${a}/issues/${s.id}`}},lt=(e)=>{let t=[{name:e.ref,text:e.name},{name:"state",text:`${e.state} (${e.group})`},{name:"priority",text:e.priority}];if(e.start_date!=null)t.push({name:"start",text:e.start_date});if(e.target_date!=null)t.push({name:"due",text:e.target_date});if(e.assignees.length>0)t.push({name:"assignees",text:String(e.assignees.length)});if(e.labels.length>0)t.push({name:"labels",text:e.labels.join(", ")});if(e.parent!=null)t.push({name:"parent",text:e.parent});t.push({name:"url",text:e.url});let n=w(t,"").join(`
24
+ `),o=e.description===""?n:`${n}
31
25
 
32
- ${e.description}`;return e.comments===void 0?r:`${r}
26
+ ${e.description}`;return e.comments===void 0?o:`${o}
33
27
 
34
28
  COMMENTS
35
29
 
36
- ${X(e.comments)}`},jt=async(e,t)=>{let n=t.positionals.join(" ").trim();if(n==="")throw new d("What is it called?");let r=a(t,"project");if(r===void 0)throw new d("Which project? Pass --project.");let o=await g(e,r),s={...await Ae(e,t,o.id),name:n},i=await e.request(`projects/${o.id}/issues/`,{method:"POST",body:s}),l=`${o.identifier}-${i.sequence_id}`,f;try{f=(await _(e,o.id)).find((c)=>c.id===i.state)}catch(u){let c=u instanceof Error?u.message:String(u);ne(`${l} was created; could not read its state: ${c}`)}return{ref:l,name:y(i.name),state:f?.name??"?",group:f?.group??"?",priority:i.priority,id:i.id}},be=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");let{issue:r,projectId:o}=await h(e,n,a(t,"project")),s=await g(e,o),i=await _(e,o),l=await Ae(e,t,o,r);I(l);let u=await e.request(`projects/${o}/issues/${r.id}/`,{method:"PATCH",body:l})??{...r,...l},c=i.find((C)=>C.id===u.state);return{ref:`${s.identifier}-${u.sequence_id}`,name:y(u.name),state:c?.name??"?",group:c?.group??"?",priority:u.priority,id:u.id}},xt=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");let{projectId:r}=await h(e,n,a(t,"project")),s=(await _(e,r)).find((l)=>l.group==="completed");if(s===void 0)throw new d("This project has no state in the completed group.");let i=new Map(t.flags);return i.set("state",s.name),be(e,{...t,flags:i})},At=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");if(!j(t,"yes"))throw new d(`Deleting is not undoable. Repeat with --yes to delete ${n}.`);let{issue:r,projectId:o}=await h(e,n,a(t,"project"));return await e.request(`projects/${o}/issues/${r.id}/`,{method:"DELETE"}),`deleted ${n}`},_t=async(e,t)=>{let n=t.positionals[0],r=t.positionals.slice(1).join(" ").trim();if(n===void 0||r==="")throw new d("Which work item, and what does the comment say?");let{issue:o,projectId:s}=await h(e,n,a(t,"project"));return await e.request(`projects/${s}/issues/${o.id}/comments/`,{method:"POST",body:{comment_html:D(r)}}),`commented on ${n}`},Ct=async(e,t)=>{let n=t.positionals.join(" ").trim();if(n==="")throw new d("What to search for?");return((await e.request("issues/search/",{query:{search:n}})).issues??[]).map((o)=>({ref:`${o.project__identifier}-${o.sequence_id}`,name:y(o.name),id:o.id}))},bt=(e)=>e.length===0?"nothing found":w(e.map((t)=>({name:t.ref,text:_e(t.name,80)})),"").join(`
37
- `);var z=(e,t,n=!1)=>g(e,m((n?t.positionals[0]:void 0)??a(t,"project"),"--project <ref>"),"id,name,identifier,timezone"),ke=async(e,t,n)=>{let r=await z(e,t,!0);return(await e.listAll(`projects/${r.id}/${n}s/`,{query:{fields:n==="cycle"?"id,name,start_date,end_date":"id,name,start_date,target_date,status",per_page:100}})).map((s)=>Re(s,r,n))},Re=(e,t,n)=>n==="cycle"&&t.timezone!==void 0?{...e,timezone:t.timezone}:e,re=(e,t,n)=>e.listAll(`projects/${t}/${n}s-lite/`,{query:{per_page:100}}),Rt=(e,t)=>{let n={},r=a(e,"name");if(r!==void 0)n.name=m(r,`a ${t} name`);let o=a(e,"description");if(o!==void 0)n.description=o;let s=a(e,"start"),i=t==="cycle"?"end":"due",l=a(e,i),f=s===void 0?null:S(s,"start"),u=l===void 0?null:S(l,i);if(t==="cycle"&&(s===void 0!==(l===void 0)||f===null!==(u===null)))throw new d("A cycle needs both --start and --end, or neither for a draft.");if(f!==null&&u!==null&&f>u)throw new d("The start date must not be after the end date.");if(s!==void 0)n.start_date=f;if(l!==void 0)n[t==="cycle"?"end_date":"target_date"]=u;if(t==="module"){let c=a(e,"status");if(c!==void 0)n.status=b(c,["backlog","planned","in-progress","paused","completed","cancelled"],"status")}return n},Ie=async(e,t,n)=>{let r={...Rt(t,n),name:m(t.positionals.join(" "),`a ${n} name`)},o=await z(e,t);if(n==="cycle"){let i=a(t,"owner");r.owned_by=i===void 0?(await e.request("/api/v1/users/me/")).id:await te(e,i),r.project_id=o.id}let s=await e.request(`projects/${o.id}/${n}s/`,{method:"POST",body:r});return Re(s,o,n)},It=async(e,t)=>{let n=m(t.positionals[0],"a cycle name or UUID"),r=Rt(t,"cycle"),o=a(t,"owner");if(o===void 0)I(r);let s=await z(e,t),i=x(await re(e,s.id,"cycle"),n,"cycle");if(o!==void 0)r.owned_by=await te(e,o);else{let f=await e.request(`projects/${s.id}/cycles/${i.id}/`,{query:{fields:"id,name,owned_by"}});if(!f.owned_by)throw new U("Cannot preserve the cycle owner: the server did not return owned_by. Pass --owner explicitly.");r.owned_by=f.owned_by}let l=await e.request(`projects/${s.id}/cycles/${i.id}/`,{method:"PATCH",body:r});return Re(l??{...i,...r},s,"cycle")},Se=async(e,t,n)=>{if(t.positionals.length===0)throw new d("Expected one or more work item references.");let r=P(t,n),o=await z(e,t),s=x(await re(e,o.id,n),r,n),i=new Set;for(let l of t.positionals){let f=await h(e,l,o.id);if(f.projectId!==o.id)throw new d(`${l} does not belong to project ${o.identifier}.`);i.add(f.issue.id)}return await e.request(`projects/${o.id}/${n}s/${s.id}/${n}-issues/`,{method:"POST",body:{issues:[...i]}}),{project:o.identifier,id:s.id,name:s.name,issues:[...i]}},Ee=async(e,t,n)=>{let r=m(t.positionals[0],`a ${n} name or UUID`),o=await z(e,t),s=x(await re(e,o.id,n),r,n),l=(await e.listAll(`projects/${o.id}/${n}s/${s.id}/${n}-issues/`,{query:{fields:"id,name,sequence_id,priority,state",expand:"state",per_page:100}})).map((f)=>Ce(f,o.identifier));return{rows:l,total:l.length}},St=async(e,t)=>{let n=m(t.positionals[0],"a source cycle"),r=m(t.positionals[1],"a target cycle"),o=await z(e,t),s=await re(e,o.id,"cycle"),i=x(s,n,"cycle"),l=x(s,r,"cycle");if(i.id===l.id)throw new d("Source and target cycles must be different.");return await e.request(`projects/${o.id}/cycles/${i.id}/transfer-issues/`,{method:"POST",body:{new_cycle_id:l.id}}),{project:o.identifier,from:i,to:l}},kt=(e,t)=>{if(e==null)return"?";if(/^\d{4}-\d{2}-\d{2}$/.test(e)||t===void 0)return e;try{return new Intl.DateTimeFormat("sv-SE",{timeZone:t,calendar:"iso8601",numberingSystem:"latn",year:"numeric",month:"2-digit",day:"2-digit"}).format(new Date(e))}catch{return e}},G=(e)=>{let t=e.end_date??e.target_date,n=e.start_date==null&&t==null?"":` ${kt(e.start_date,e.timezone)} / ${kt(t,e.timezone)}`;return`${y(e.name)} ${e.id}${n}${e.status===void 0?"":` (${e.status})`}`},ve=(e)=>e.length===0?"no entries":e.map(G).join(`
38
- `),Le=(e)=>`added ${e.issues.length} work items to ${y(e.name)}`,Et=(e)=>w([{name:"from",text:y(e.from.name)},{name:"to",text:y(e.to.name)}],"").join(`
39
- `);var vt=(e)=>{let t=m(e,"a project name");if(t.length>255||/[&+,:;$^}{*=?@#|'<>.()%!-]/.test(t))throw new d("Project name cannot contain special characters (including hyphens) or exceed 255 characters.");return t},Lt=(e)=>{let t=e.trim().toUpperCase();if(!/^[A-Z][A-Z0-9]{0,11}$/.test(t))throw new d("--identifier expects 1–12 letters or digits, starting with a letter.");return t},Ot=(e)=>{let t={};for(let[n,r]of[["intake","intake_view"],["cycles","cycle_view"],["modules","module_view"]])if(e.flags.has(n))t[r]=j(e,n);return t},Tt=async(e,t)=>{let n={...Ot(t),name:vt(t.positionals.join(" ")),identifier:Lt(P(t,"identifier"))},r=a(t,"description");if(r!==void 0)n.description=r;let o=n.intake_view===!0;if(o)delete n.intake_view;let s=await e.request("projects/",{method:"POST",body:n});if(!o)return s;try{return await e.request(`projects/${s.id}/`,{method:"PATCH",body:{intake_view:!0}})??{...s,intake_view:!0}}catch(i){return ne(`${s.identifier} was created, but intake setup failed: ${i instanceof Error?i.message:String(i)}. Retry with i-plane project update ${s.id} --intake.`),s}},qt=async(e,t)=>{let n=m(t.positionals[0],"a project reference"),r={...Ot(t)},o=a(t,"name");if(o!==void 0)r.name=vt(o);let s=a(t,"description");if(s!==void 0)r.description=s;let i=a(t,"identifier");if(i!==void 0)r.identifier=Lt(i);I(r);let l=await g(e,n);return await e.request(`projects/${l.id}/`,{method:"PATCH",body:r})??{...l,...r}},Nt=async(e,t)=>{let n=await g(e,m(t.positionals[0],"a project reference"));return await e.request(`projects/${n.id}/archive/`,{method:"POST"}),n},M=(e)=>`${e.identifier} ${y(e.name)}`,Ut=async(e,t)=>{let n={name:m(t.positionals.join(" "),"a label name")},r=P(t,"project"),o=a(t,"color");n.color=se(o??"#808080");let s=a(t,"description");if(s!==void 0)n.description=s;let i=await g(e,r);return e.request(`projects/${i.id}/labels/`,{method:"POST",body:n})},Dt=(e)=>{let t={},n=a(e,"name");if(n!==void 0)t.name=m(n,"a state name");let r=a(e,"color");if(r!==void 0)t.color=se(r);let o=a(e,"group");if(o!==void 0)t.group=b(o,F,"group");let s=a(e,"description");if(s!==void 0)t.description=s;return t},zt=async(e,t)=>{let n=m(t.positionals.join(" "),"a state name"),r=se(P(t,"color")),o=b(P(t,"group"),F,"group"),s={...Dt(t),name:n,color:r,group:o},i=await g(e,P(t,"project"));return e.request(`projects/${i.id}/states/`,{method:"POST",body:s})},Ft=async(e,t)=>{let n=m(t.positionals[0],"a state name or UUID"),r=Dt(t);I(r);let o=await g(e,P(t,"project")),s=x(await _(e,o.id),n,"state");return await e.request(`projects/${o.id}/states/${s.id}/`,{method:"PATCH",body:r})??{...s,...r}},Oe=(e)=>{if(!j(e,"yes"))throw new d("Deleting cannot be undone. Repeat with --yes.")},Wt=async(e,t)=>{Oe(t);let n=await g(e,m(t.positionals[0],"a project reference"));return await e.request(`projects/${n.id}/`,{method:"DELETE"}),n},Gt=async(e,t)=>{Oe(t);let n=m(t.positionals[0],"a label name or UUID"),r=await g(e,P(t,"project")),o=await e.listAll(`projects/${r.id}/labels/`,{query:{fields:"id,name",per_page:100}}),s=x(o,n,"label");return await e.request(`projects/${r.id}/labels/${s.id}/`,{method:"DELETE"}),s},Mt=async(e,t)=>{Oe(t);let n=m(t.positionals[0],"a state name or UUID"),r=await g(e,P(t,"project")),o=x(await _(e,r.id),n,"state");return await e.request(`projects/${r.id}/states/${o.id}/`,{method:"DELETE"}),o};var p=(e,t)=>async(n,r)=>A(await e(n),r,t),fn={cycles:p(({client:e,args:t})=>ke(e,t,"cycle"),ve),"cycle create":p(({client:e,args:t})=>Ie(e,t,"cycle"),(e)=>`created ${G(e)}`),"cycle update":p(({client:e,args:t})=>It(e,t),G),"cycle add":p(({client:e,args:t})=>Se(e,t,"cycle"),Le),"cycle issues":p(({client:e,args:t})=>Ee(e,t,"cycle"),oe),"cycle transfer":p(({client:e,args:t})=>St(e,t),Et),modules:p(({client:e,args:t})=>ke(e,t,"module"),ve),"module create":p(({client:e,args:t})=>Ie(e,t,"module"),(e)=>`created ${G(e)}`),"module add":p(({client:e,args:t})=>Se(e,t,"module"),Le),"module issues":p(({client:e,args:t})=>Ee(e,t,"module"),oe),"intake list":p(({client:e,args:t})=>ut(e,t),je),"intake create":p(({client:e,args:t})=>pt(e,t),(e)=>`created ${ee(e)}`),"intake show":p(({client:e,args:t})=>mt(e,t),ee),"intake update":p(({client:e,args:t})=>ft(e,t),ee),"intake rm":p(({client:e,args:t})=>gt(e,t),(e)=>`deleted intake entry ${e.ref}`),summary:p(({client:e,config:t})=>Ye(e,t),Ze),projects:p(({client:e})=>J(e),Je),list:p(({client:e,args:t})=>Pt(e,t),oe),show:p(({client:e,args:t,config:n})=>ht(e,t,n.workspace.value,n.url.value),$t),create:p(({client:e,args:t})=>jt(e,t),(e)=>`created ${e.ref} ${e.name}`),update:p(({client:e,args:t})=>be(e,t),(e)=>`${e.ref} ${e.name} (${e.state})`),done:p(({client:e,args:t})=>xt(e,t),(e)=>`${e.ref} ${e.state}`),delete:p(({client:e,args:t})=>At(e,t),(e)=>e),comment:p(({client:e,args:t})=>_t(e,t),(e)=>e),comments:p(({client:e,args:t})=>dt(e,t),X),search:p(({client:e,args:t})=>Ct(e,t),bt),states:p(({client:e,args:t})=>Xe(e,t),Qe),labels:p(({client:e,args:t})=>et(e,t),tt),members:p(({client:e})=>nt(e),ot),whoami:p(({client:e})=>it(e),at),"project create":p(({client:e,args:t})=>Tt(e,t),(e)=>`created ${M(e)}`),"project update":p(({client:e,args:t})=>qt(e,t),M),"project archive":p(({client:e,args:t})=>Nt(e,t),(e)=>`archived ${M(e)}`),"project rm":p(({client:e,args:t})=>Wt(e,t),(e)=>`deleted ${M(e)}`),"label create":p(({client:e,args:t})=>Ut(e,t),(e)=>`created ${y(e.name)} ${e.id}`),"label rm":p(({client:e,args:t})=>Gt(e,t),(e)=>`deleted ${y(e.name)}`),"state create":p(({client:e,args:t})=>zt(e,t),(e)=>`created ${y(e.name)} ${e.group}`),"state update":p(({client:e,args:t})=>Ft(e,t),(e)=>`${y(e.name)} ${e.group}`),"state rm":p(({client:e,args:t})=>Mt(e,t),(e)=>`deleted ${y(e.name)}`)},Ht=async(e,t,n,r,o)=>{let s=e===void 0?void 0:fn[e];if(s===void 0)throw new d(`No command "${e}". Run i-plane for the map.`);await s({client:t,args:n,config:r},o)};var yn=(e)=>async(t,n,r)=>{let{runPageContent:o}=await import("./chunks/page-content-2m19c48m.js");await o(e,t,n,r)},wn={...Object.fromEntries(["page outline","page read","page stamp","page create","page set","page insert","page rm"].map((e)=>[e,yn(e)])),pages:async(e,t,n)=>{let r=await Te(e,m(t.positionals[0],"a project"));A(await Kt(e,r.id),n,Bt)},"page show":async(e,t,n)=>{let r=m(t.positionals[0],"a project"),o=m(t.positionals[1],"a page UUID or name"),s=await Te(e,r);A(Yt(await Vt(e,s.id,o)),n,(i)=>i.markdown)}},Zt=(e)=>e==="pages"||e.startsWith("page "),Jt=async(e,t,n,r)=>{let o=wn[e];if(!o)throw new d(`Unknown page command "${e}".`);await o(t,n,r)};var Pn="1.2.0",K,hn=(e,t)=>{let n=e===void 0?void 0:v(e);if(n===void 0){if(e===void 0||e==="help"||e==="version"||H(e).length>0){let s=[...t.flags.keys()].filter((i)=>!Xt.includes(i));if(s.length>0)throw new d(`${e??"i-plane"} does not take ${s.map((i)=>`--${i}`).join(", ")}.`)}return}K=e;let r=Qt(n),o=[...t.flags.keys()].filter((s)=>!r.has(s));if(o.length>0){let s=o.map((i)=>`--${i}`).join(", ");throw new d(`${n.name} does not take ${s}. Its flags are listed below.`)}},$n=(e,t)=>{let n=e.path.length===0?void 0:e.path.join(" "),r=n===void 0?void 0:v(n)?.name??n;if(hn(r,e),r!==void 0&&H(r).length>0){let o=H(r);if(j(e,"help"))return A({commands:o,globalOptions:L},t,(s)=>`${s.commands.map((i)=>ue({command:i},!1)).join(`
30
+ ${X(e.comments)}`},ct=async(e,t)=>{let n=t.positionals.join(" ").trim();if(n==="")throw new d("What is it called?");let o=i(t,"project");if(o===void 0)throw new d("Which project? Pass --project.");let r=await y(e,o),s={...await ge(e,t,r.id),name:n},a=await e.request(`projects/${r.id}/issues/`,{method:"POST",body:s}),l=`${r.identifier}-${a.sequence_id}`,p;try{p=(await C(e,r.id)).find((f)=>f.id===a.state)}catch(m){let f=m instanceof Error?m.message:String(m);z(`${l} was created; could not read its state: ${f}`)}return{ref:l,name:g(a.name),state:p?.name??"?",group:p?.group??"?",priority:a.priority,id:a.id}},$e=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");let{issue:o,projectId:r}=await j(e,n,i(t,"project")),s=await y(e,r),a=await C(e,r),l=await ge(e,t,r,o);I(l);let m=await e.request(`projects/${r}/issues/${o.id}/`,{method:"PATCH",body:l})??{...o,...l},f=a.find((k)=>k.id===m.state);return{ref:`${s.identifier}-${m.sequence_id}`,name:g(m.name),state:f?.name??"?",group:f?.group??"?",priority:m.priority,id:m.id}},ut=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");let{projectId:o}=await j(e,n,i(t,"project")),s=(await C(e,o)).find((l)=>l.group==="completed");if(s===void 0)throw new d("This project has no state in the completed group.");let a=new Map(t.flags);return a.set("state",s.id),$e(e,{...t,flags:a})},pt=async(e,t)=>{let n=t.positionals[0];if(n===void 0)throw new d("Which work item?");if(!h(t,"yes"))throw new d(`Deleting is not undoable. Repeat with --yes to delete ${n}.`);let{issue:o,projectId:r}=await j(e,n,i(t,"project"));return await e.request(`projects/${r}/issues/${o.id}/`,{method:"DELETE"}),`deleted ${n}`},mt=async(e,t)=>{let n=t.positionals[0],o=t.positionals.slice(1).join(" ").trim();if(n===void 0||o==="")throw new d("Which work item, and what does the comment say?");let{issue:r,projectId:s}=await j(e,n,i(t,"project"));return await e.request(`projects/${s}/issues/${r.id}/comments/`,{method:"POST",body:{comment_html:D(o)}}),`commented on ${n}`},ft=async(e,t)=>{let n=he(t,1,1000)??10,o=t.positionals.join(" ").trim();if(o==="")throw new d("What to search for?");let r=await e.request("issues/search/",{query:{search:o,limit:n+1}});if(!r||!Array.isArray(r.issues))throw new S("Unexpected search response: expected an issues array.");return{rows:r.issues.slice(0,n).map((a)=>({ref:`${a.project__identifier}-${a.sequence_id}`,name:g(a.name),id:a.id})),limit:n,hasMore:r.issues.length>n}},yt=({rows:e,limit:t,hasMore:n})=>{let o=e.length===0?"nothing found":w(e.map((r)=>({name:r.ref,text:we(r.name,80)})),"").join(`
31
+ `);return n?`${o}
32
+
33
+ showing the first ${t} matches; more exist raise --limit (up to 1000) or narrow the query`:o};var M=(e,t,n=!1)=>y(e,u((n?t.positionals[0]:void 0)??i(t,"project"),"--project <ref>"),"id,name,identifier,timezone"),je=async(e,t,n)=>{let o=await M(e,t,!0);return(await e.listAll(`projects/${o.id}/${n}s/`,{query:{fields:n==="cycle"?"id,name,start_date,end_date":"id,name,start_date,target_date,status",per_page:100}})).map((s)=>xe(s,o,n))},xe=(e,t,n)=>n==="cycle"&&t.timezone!==void 0?{...e,timezone:t.timezone}:e,re=(e,t,n)=>e.listAll(`projects/${t}/${n}s-lite/`,{query:{per_page:100}}),wt=(e,t)=>{let n={},o=i(e,"name");if(o!==void 0)n.name=u(o,`a ${t} name`);let r=i(e,"description");if(r!==void 0)n.description=r;let s=i(e,"start"),a=t==="cycle"?"end":"due",l=i(e,a),p=s===void 0?null:v(s,"start"),m=l===void 0?null:v(l,a);if(t==="cycle"&&(s===void 0!==(l===void 0)||p===null!==(m===null)))throw new d("A cycle needs both --start and --end, or neither for a draft.");if(p!==null&&m!==null&&p>m)throw new d("The start date must not be after the end date.");if(s!==void 0)n.start_date=p;if(l!==void 0)n[t==="cycle"?"end_date":"target_date"]=m;if(t==="module"){let f=i(e,"status");if(f!==void 0)n.status=R(f,["backlog","planned","in-progress","paused","completed","cancelled"],"status")}return n},be=async(e,t,n)=>{let o={...wt(t,n),name:u(t.positionals.join(" "),`a ${n} name`)},r=await M(e,t);if(n==="cycle"){let a=i(t,"owner");o.owned_by=a===void 0?(await e.request("/api/v1/users/me/")).id:await te(e,a),o.project_id=r.id}let s=await e.request(`projects/${r.id}/${n}s/`,{method:"POST",body:o});return xe(s,r,n)},ht=async(e,t)=>{let n=u(t.positionals[0],"a cycle name or UUID"),o=wt(t,"cycle"),r=i(t,"owner");if(r===void 0)I(o);let s=await M(e,t),a=x(await re(e,s.id,"cycle"),n,"cycle");if(r!==void 0)o.owned_by=await te(e,r);else{let p=await e.request(`projects/${s.id}/cycles/${a.id}/`,{query:{fields:"id,name,owned_by"}});if(!p.owned_by)throw new S("Cannot preserve the cycle owner: the server did not return owned_by. Pass --owner explicitly.");o.owned_by=p.owned_by}let l=await e.request(`projects/${s.id}/cycles/${a.id}/`,{method:"PATCH",body:o});return xe(l??{...a,...o},s,"cycle")},Ce=async(e,t,n)=>{if(t.positionals.length===0)throw new d("Expected one or more work item references.");let o=P(t,n),r=await M(e,t),s=x(await re(e,r.id,n),o,n),a=new Set;for(let l of t.positionals){let p=await j(e,l,r.id);if(p.projectId!==r.id)throw new d(`${l} does not belong to project ${r.identifier}.`);a.add(p.issue.id)}return await e.request(`projects/${r.id}/${n}s/${s.id}/${n}-issues/`,{method:"POST",body:{issues:[...a]}}),{project:r.identifier,id:s.id,name:s.name,issues:[...a]}},ke=async(e,t,n)=>{let o=u(t.positionals[0],`a ${n} name or UUID`),r=await M(e,t),s=x(await re(e,r.id,n),o,n),l=(await e.listAll(`projects/${r.id}/${n}s/${s.id}/${n}-issues/`,{query:{fields:"id,name,sequence_id,priority,state",expand:"state",per_page:100}})).map((p)=>Pe(p,r.identifier));return{rows:l,total:l.length}},Pt=async(e,t)=>{let n=u(t.positionals[0],"a source cycle"),o=u(t.positionals[1],"a target cycle"),r=await M(e,t),s=await re(e,r.id,"cycle"),a=x(s,n,"cycle"),l=x(s,o,"cycle");if(a.id===l.id)throw new d("Source and target cycles must be different.");return await e.request(`projects/${r.id}/cycles/${a.id}/transfer-issues/`,{method:"POST",body:{new_cycle_id:l.id}}),{project:r.identifier,from:a,to:l}},gt=(e,t)=>{if(e==null)return"?";if(/^\d{4}-\d{2}-\d{2}$/.test(e)||t===void 0)return e;try{return new Intl.DateTimeFormat("sv-SE",{timeZone:t,calendar:"iso8601",numberingSystem:"latn",year:"numeric",month:"2-digit",day:"2-digit"}).format(new Date(e))}catch{return e}},N=(e)=>{let t=e.end_date??e.target_date,n=e.start_date==null&&t==null?"":` ${gt(e.start_date,e.timezone)} / ${gt(t,e.timezone)}`;return`${g(e.name)} ${e.id}${n}${e.status===void 0?"":` (${e.status})`}`},Re=(e)=>e.length===0?"no entries":e.map(N).join(`
34
+ `),_e=(e)=>`added ${e.issues.length} work items to ${g(e.name)}`,$t=(e)=>w([{name:"from",text:g(e.from.name)},{name:"to",text:g(e.to.name)}],"").join(`
35
+ `);var jt=(e)=>{let t=u(e,"a project name");if(t.length>255||/[&+,:;$^}{*=?@#|'<>.()%!-]/.test(t))throw new d("Project name cannot contain special characters (including hyphens) or exceed 255 characters.");return t},xt=(e)=>{let t=e.trim().toUpperCase();if(!/^[A-Z][A-Z0-9]{0,11}$/.test(t))throw new d("--identifier expects 1–12 letters or digits, starting with a letter.");return t},bt=(e)=>{let t={};for(let[n,o]of[["intake","intake_view"],["cycles","cycle_view"],["modules","module_view"]])if(e.flags.has(n))t[o]=h(e,n);return t},Ct=async(e,t)=>{let n={...bt(t),name:jt(t.positionals.join(" ")),identifier:xt(P(t,"identifier"))},o=i(t,"description");if(o!==void 0)n.description=o;let r=n.intake_view===!0;if(r)delete n.intake_view;let s=await e.request("projects/",{method:"POST",body:n});if(!r)return s;try{return await e.request(`projects/${s.id}/`,{method:"PATCH",body:{intake_view:!0}})??{...s,intake_view:!0}}catch(a){return z(`${s.identifier} was created, but intake setup failed: ${a instanceof Error?a.message:String(a)}. Retry with i-plane project update ${s.id} --intake.`),s}},kt=async(e,t)=>{let n=u(t.positionals[0],"a project reference"),o={...bt(t)},r=i(t,"name");if(r!==void 0)o.name=jt(r);let s=i(t,"description");if(s!==void 0)o.description=s;let a=i(t,"identifier");if(a!==void 0)o.identifier=xt(a);I(o);let l=await y(e,n);return await e.request(`projects/${l.id}/`,{method:"PATCH",body:o})??{...l,...o}},Rt=async(e,t)=>{let n=await y(e,u(t.positionals[0],"a project reference"));return await e.request(`projects/${n.id}/archive/`,{method:"POST"}),n},G=(e)=>`${e.identifier} ${g(e.name)}`,_t=async(e,t)=>{let n={name:u(t.positionals.join(" "),"a label name")},o=P(t,"project"),r=i(t,"color");n.color=oe(r??"#808080");let s=i(t,"description");if(s!==void 0)n.description=s;let a=await y(e,o);return e.request(`projects/${a.id}/labels/`,{method:"POST",body:n})},At=(e)=>{let t={},n=i(e,"name");if(n!==void 0)t.name=u(n,"a state name");let o=i(e,"color");if(o!==void 0)t.color=oe(o);let r=i(e,"group");if(r!==void 0)t.group=R(r,H,"group");let s=i(e,"description");if(s!==void 0)t.description=s;return t},It=async(e,t)=>{let n=u(t.positionals.join(" "),"a state name"),o=oe(P(t,"color")),r=R(P(t,"group"),H,"group"),s={...At(t),name:n,color:o,group:r},a=await y(e,P(t,"project"));return e.request(`projects/${a.id}/states/`,{method:"POST",body:s})},St=async(e,t)=>{let n=u(t.positionals[0],"a state name or UUID"),o=At(t);I(o);let r=await y(e,P(t,"project")),s=x(await C(e,r.id),n,"state");return await e.request(`projects/${r.id}/states/${s.id}/`,{method:"PATCH",body:o})??{...s,...o}},Ae=(e)=>{if(!h(e,"yes"))throw new d("Deleting cannot be undone. Repeat with --yes.")},vt=async(e,t)=>{Ae(t);let n=await y(e,u(t.positionals[0],"a project reference"));return await e.request(`projects/${n.id}/`,{method:"DELETE"}),n},Ot=async(e,t)=>{Ae(t);let n=u(t.positionals[0],"a label name or UUID"),o=await y(e,P(t,"project")),r=await e.listAll(`projects/${o.id}/labels/`,{query:{fields:"id,name",per_page:100}}),s=x(r,n,"label");return await e.request(`projects/${o.id}/labels/${s.id}/`,{method:"DELETE"}),s},Tt=async(e,t)=>{Ae(t);let n=u(t.positionals[0],"a state name or UUID"),o=await y(e,P(t,"project")),r=x(await C(e,o.id),n,"state");return await e.request(`projects/${o.id}/states/${r.id}/`,{method:"DELETE"}),r};var c=(e,t)=>async(n,o)=>b(await e(n),o,t),on={cycles:c(({client:e,args:t})=>je(e,t,"cycle"),Re),"cycle create":c(({client:e,args:t})=>be(e,t,"cycle"),(e)=>`created ${N(e)}`),"cycle update":c(({client:e,args:t})=>ht(e,t),N),"cycle add":c(({client:e,args:t})=>Ce(e,t,"cycle"),_e),"cycle issues":c(({client:e,args:t})=>ke(e,t,"cycle"),ne),"cycle transfer":c(({client:e,args:t})=>Pt(e,t),$t),modules:c(({client:e,args:t})=>je(e,t,"module"),Re),"module create":c(({client:e,args:t})=>be(e,t,"module"),(e)=>`created ${N(e)}`),"module add":c(({client:e,args:t})=>Ce(e,t,"module"),_e),"module issues":c(({client:e,args:t})=>ke(e,t,"module"),ne),"intake list":c(({client:e,args:t})=>tt(e,t),fe),"intake create":c(({client:e,args:t})=>nt(e,t),(e)=>`created ${ee(e)}`),"intake show":c(({client:e,args:t})=>rt(e,t),ee),"intake update":c(({client:e,args:t})=>ot(e,t),ee),"intake rm":c(({client:e,args:t})=>st(e,t),(e)=>`deleted intake entry ${e.ref}`),summary:c(({client:e,config:t})=>ze(e,t),Me),projects:c(({client:e})=>J(e),He),list:c(({client:e,args:t})=>it(e,t),ne),show:c(({client:e,args:t,config:n})=>dt(e,t,n.workspace.value,n.url.value),lt),create:c(({client:e,args:t})=>ct(e,t),(e)=>`created ${e.ref} ${e.name}`),update:c(({client:e,args:t})=>$e(e,t),(e)=>`${e.ref} ${e.name} (${e.state})`),done:c(({client:e,args:t})=>ut(e,t),(e)=>`${e.ref} ${e.state}`),delete:c(({client:e,args:t})=>pt(e,t),(e)=>e),comment:c(({client:e,args:t})=>mt(e,t),(e)=>e),comments:c(({client:e,args:t})=>Xe(e,t),X),search:c(({client:e,args:t})=>ft(e,t),yt),states:c(({client:e,args:t})=>Fe(e,t),Ne),labels:c(({client:e,args:t})=>Ge(e,t),We),members:c(({client:e})=>Ve(e),Be),whoami:c(({client:e})=>Ze(e),Je),"project create":c(({client:e,args:t})=>Ct(e,t),(e)=>`created ${G(e)}`),"project update":c(({client:e,args:t})=>kt(e,t),G),"project archive":c(({client:e,args:t})=>Rt(e,t),(e)=>`archived ${G(e)}`),"project rm":c(({client:e,args:t})=>vt(e,t),(e)=>`deleted ${G(e)}`),"label create":c(({client:e,args:t})=>_t(e,t),(e)=>`created ${g(e.name)} ${e.id}`),"label rm":c(({client:e,args:t})=>Ot(e,t),(e)=>`deleted ${g(e.name)}`),"state create":c(({client:e,args:t})=>It(e,t),(e)=>`created ${g(e.name)} ${e.group}`),"state update":c(({client:e,args:t})=>St(e,t),(e)=>`${g(e.name)} ${e.group}`),"state rm":c(({client:e,args:t})=>Tt(e,t),(e)=>`deleted ${g(e.name)}`)},qt=async(e,t,n,o,r)=>{let s=e===void 0?void 0:on[e];if(s===void 0)throw new d(`No command "${e}". Run i-plane for the map.`);se(e,n),await s({client:t,args:n,config:o},r)};var an=(e)=>async(t,n,o)=>{let{runPageContent:r}=await import("./chunks/page-content-kh1zbmn7.js");await r(e,t,n,o)},dn={...Object.fromEntries(["page outline","page read","page stamp","page create","page set","page insert","page rm"].map((e)=>[e,an(e)])),pages:async(e,t,n)=>{let o=await Ie(e,u(t.positionals[0],"a project"));b(await Lt(e,o.id),n,Ut)},"page show":async(e,t,n)=>{let o=u(t.positionals[0],"a project"),r=u(t.positionals[1],"a page UUID or name"),s=await Ie(e,o),a=Dt(await Et(e,s.id,r));if(a.losses.length)z(`Warning: ${a.losses.join("; ")}`);b(a,n,(l)=>l.markdown)}},Se=(e)=>e==="pages"||e.startsWith("page "),Mt=async(e,t,n,o)=>{let r=dn[e];if(!r)throw new d(`Unknown page command "${e}".`);t.beginPageCommand?.();for(let s=0;s<2;s++)try{await r(t,n,o);return}catch(a){if(!(a instanceof zt)||s>0)throw a}};var ln="2.0.1",V,cn=(e,t)=>{let n=e===void 0?void 0:O(e);if(n===void 0){if(e===void 0||e==="help"||e==="version"||W(e).length>0){let s=[...t.flags.keys()].filter((a)=>!Ht.includes(a));if(s.length>0)throw new d(`${e??"i-plane"} does not take ${s.map((a)=>`--${a}`).join(", ")}.`)}return}V=e;let o=Ft(n),r=[...t.flags.keys()].filter((s)=>!o.has(s));if(r.length>0){let s=r.map((a)=>`--${a}`).join(", ");throw new d(`${n.name} does not take ${s}. Its flags are listed below.`)}},un=(e,t)=>{let n=e.path.length===0?void 0:e.path.join(" "),o=n===void 0?void 0:O(n)?.name??n;if(cn(o,e),o!==void 0&&W(o).length>0){let r=W(o);if(h(e,"help"))return b({commands:r,globalOptions:q},t,(s)=>`${s.commands.map((a)=>ce({command:a},!1)).join(`
40
36
 
41
37
  `)}
42
38
 
43
- ${Z(s.globalOptions)}`),!0;throw new d(`Expected ${r} <${o.map((s)=>s.name.split(" ")[1]).join("|")}>. Run i-plane ${r} --help.`)}if(r!==void 0&&r!=="help"&&r!=="version"&&v(r)===void 0){let o=H(r.split(" ")[0]??"");throw new d(`No command "${r}". ${o.length?`Available commands: ${o.map((s)=>s.name).join(", ")}. Run i-plane ${r.split(" ")[0]} --help.`:"Run i-plane for the map."}`)}if(r===void 0&&!j(e,"version"))return A(B(),t,Y),!0;if(r==="guide")return A(B(),t,Y),!0;if(r==="version"||j(e,"version"))return A({version:Pn},t,(o)=>o.version),!0;if(r!==void 0&&j(e,"help")){let o=v(r);if(o!==void 0)return A({command:o,globalOptions:L},t,(s)=>ue(s)),!0}if(r==="help")return A(B(),t,Y),!0;return!1},jn=async()=>{let e=en(process.argv.slice(2)),t=j(e,"json"),n=Ke({token:a(e,"token"),configPath:a(e,"config")});if(n!==void 0)ie(n);let r=we({configPath:a(e,"config")},a(e,"session-cache"));if(r.password)ie(r.password.value);if(await nn(r.cacheDirectory),$n(e,t))return;let o=e.path.join(" ");if(Zt(o)){K=o;let u=Be({url:a(e,"url"),workspace:a(e,"workspace"),configPath:a(e,"config")},a(e,"session-cache"));if(qe(u.url.value)&&await Ne(u.url.value)===void 0){let c=await Ue(u.url.value);if(c!==void 0)process.exit(c)}await Jt(o,new rn(u),e,t);return}let s=ye({url:a(e,"url"),token:a(e,"token"),workspace:a(e,"workspace"),configPath:a(e,"config")},o==="config");if(s.token.value)ie(s.token.value);let i=e.path.length===0?void 0:e.path.join(" "),l=i===void 0?void 0:v(i)?.name??i;if(K=l,l==="config"){let u={...rt(s),session:await on(s.url.value,r)};A(u,t,(c)=>`${st(c)}
44
- session ${c.session.state}
45
- login ${c.session.login.configured?`configured (${c.session.login.origin})`:"not configured"}
46
- password ${c.session.password.configured?`configured (${c.session.password.origin})`:"not configured"}
47
- cache ${c.session.cacheDirectory}`);return}if(qe(s.url.value)&&await Ne(s.url.value)===void 0){let u=await Ue(s.url.value);if(u!==void 0)process.exit(u)}let f=new tn(s);await Ht(l,f,e,s,t)};jn().catch((e)=>{if(e instanceof d){let t=K===void 0?void 0:v(K);ae(t===void 0?e.message:Me(t,e.message),2)}if(e instanceof U)ae(e.message,1);ae(e instanceof Error?e.message:String(e),1)});
39
+ ${Z(s.globalOptions)}`),!0;throw new d(`Expected ${o} <${r.map((s)=>s.name.split(" ")[1]).join("|")}>. Run i-plane ${o} --help.`)}if(o!==void 0&&o!=="help"&&o!=="version"&&O(o)===void 0){let r=W(o.split(" ")[0]??"");throw new d(`No command "${o}". ${r.length?`Available commands: ${r.map((s)=>s.name).join(", ")}. Run i-plane ${o.split(" ")[0]} --help.`:"Run i-plane for the map."}`)}if(o===void 0&&!h(e,"version"))return b(K(),t,Y),!0;if(o==="guide")return b(K(),t,Y),!0;if(o==="version"||h(e,"version"))return b({version:ln},t,(r)=>r.version),!0;if(o!==void 0&&h(e,"help")){let r=O(o);if(r!==void 0)return b({command:r,globalOptions:q},t,(s)=>ce(s)),!0}if(o==="help")return b(K(),t,Y),!0;return!1},pn=async()=>{let e=Nt(process.argv.slice(2)),t=h(e,"json"),n=Kt({token:i(e,"token"),configPath:i(e,"config")});if(n!==void 0)ve(n);let o=e.path.join(" ");if(V=O(o)?.name,se(o,e),un(e,t))return;let r=Yt({url:i(e,"url"),token:i(e,"token"),workspace:i(e,"workspace"),configPath:i(e,"config")},o==="config"||Se(o));if(r.token.value)ve(r.token.value);let s=e.path.length===0?void 0:e.path.join(" "),a=s===void 0?void 0:O(s)?.name??s;if(V=a,a==="config"){b({...Ke(r),pages:await Zt(r.url.value,h(e,"refresh-pages"))},t,Ye);return}if(Gt(r.url.value)&&await Wt(r.url.value)===void 0){let m=await Vt(r.url.value);if(m!==void 0)process.exit(m)}let l=new Bt(r),p=i(e,"session-cache");if(Se(o))await Mt(o,new Jt(r,{refresh:h(e,"refresh-pages"),...p?{sessionDirectory:p}:{}}),e,t);else await qt(a,l,e,r,t)};pn().catch((e)=>{if(e instanceof d){let t=V===void 0?void 0:O(V);ae(t===void 0?e.message:Ue(t,e.message),2)}if(e instanceof S)ae(e.message,1);ae(e instanceof Error?e.message:String(e),1)});
@@ -27,6 +27,30 @@ The compatibility target uses the `issues/` routes. The current public
27
27
  documents `work-items/` instead. A route migration must be verified against the
28
28
  target server; do not change paths solely to match a newer documentation release.
29
29
 
30
+ ## Argument, selection and completeness contracts
31
+
32
+ Commands that address one resource reject extra positional tokens before
33
+ configuration or requests. Quote a multiword reference, such as
34
+ `i-plane project rm "Knowledge Base" --yes`. Create titles, comment/search text
35
+ and bulk cycle/module additions retain their intentional variadic inputs.
36
+
37
+ `done` preserves the selected completed-state UUID. Case-insensitive name ties
38
+ are errors for explicit state selection; a state group still selects its first
39
+ state. Use a state UUID when names collide.
40
+
41
+ `list --limit` accepts a nonnegative integer, including zero. `search --limit`
42
+ accepts integers from 1 to 1000 and defaults to 10. Search requests one additional
43
+ match from the supported endpoint to detect truncation, then returns
44
+ `{ rows, limit, hasMore }` in JSON. Text output explains when more matches exist;
45
+ raise the bound or narrow the query. No exact total is inferred. This replaces
46
+ the earlier bare search-results array and undocumented server-default cap.
47
+
48
+ Paged collections require a valid results array and a nonempty continuation
49
+ cursor when another page is advertised. Repeated cursors fail instead of
50
+ repeating requests or returning duplicated rows. A final bare array remains
51
+ supported. Calendar date fields accept valid dates in years 0001–9999; year zero
52
+ is rejected before mutations, as it is outside the backend's date range.
53
+
30
54
  ## What modules and intake are for
31
55
 
32
56
  A module groups work toward a feature, milestone or other goal and may span
@@ -102,9 +126,9 @@ API endpoints; the diagnostic points to `issueId` from an earlier JSON response.
102
126
 
103
127
  ## Project pages
104
128
 
105
- `pages` and `page show` use the internal session API. `page outline`, `page read`,
129
+ `pages` and `page show` automatically select API-key or native session page access. `page outline`, `page read`,
106
130
  `page stamp`, `page create`, `page set`, `page insert` and block removal use the
107
- live document protocol. Whole-page deletion uses the session API. See the
131
+ live document protocol. Whole-page deletion uses the selected page endpoint. See the
108
132
  [page workflow](pages.md) for credentials, fingerprints, formatting losses and
109
133
  asynchronous persistence. This internal API can change independently of Plane's
110
134
  public API; compatibility is covered by converter fixtures and live acceptance.
@@ -113,7 +137,7 @@ public API; compatibility is covered by converter fixtures and live acceptance.
113
137
 
114
138
  1. Add the command and all options to `src/registry.ts`. The parser gets value
115
139
  flags from the registry, including those of multiword commands.
116
- 2. Add an online handler to `src/dispatch.ts` or a session handler to `src/page-dispatch.ts`. Both missing handlers and handlers
140
+ 2. Add an online handler to `src/dispatch.ts` or a page handler to `src/page-dispatch.ts`. Both missing handlers and handlers
117
141
  absent from the registry fail the command-set test.
118
142
  3. Add a fixture invocation and valid option values to the registry suite. Test
119
143
  the requested method, path and body, and assert observable output. Merely
@@ -165,3 +189,60 @@ The page acceptance script creates and removes one page in the selected existing
165
189
  project. It exercises all nine commands and observes saved HTML within a bounded
166
190
  window; that window is a test limit, not a persistence guarantee. Run
167
191
  `node scripts/page-mutations.mjs` for isolated mutation checks.
192
+
193
+ ### Automatic page transport
194
+
195
+ `AutoPageClient` probes the public project-page list, prefers API-key access and
196
+ selects the native session API only when the route is absent and runtime
197
+ configuration does not advertise API-key pages. Permission failures and individual
198
+ page `404` responses never cause fallback. Capabilities are cached per instance
199
+ for five minutes, with `--refresh-pages` for immediate redetection. Config output
200
+ explains the cached selection without network access or loading session settings.
201
+
202
+ The session implementation and credentials load lazily. Session-only page access
203
+ remains supported; ordinary commands still require the public API key. A definite
204
+ HTTP `401` may refresh session authentication once; live may refresh once only
205
+ before synchronization. Live mutations are never replayed. API-key access never
206
+ refreshes through password sign-in. Both paths keep conversion on their selected
207
+ HTTP transport and reject redirects to avoid forwarding credentials.
208
+
209
+ Tests cover both identities, cache isolation/expiry/reset, installation transitions,
210
+ missing credentials, permission failures, redaction, session refresh and live
211
+ handshakes. See [pages.md](pages.md) for configuration and cache paths.
212
+
213
+ Run `node scripts/page-mutations.mjs` to check that the page tests detect intentional
214
+ regressions. `scripts/page-key-acceptance.mjs` exercises a built CLI against an
215
+ isolated deployment using a private test fixture and a browser. It creates a page,
216
+ checks both writers, stale fingerprints and deletion, then removes the test page.
217
+ The package ships command help and user documentation; repository-only contributor
218
+ instructions are excluded from the release archive.
219
+
220
+ ### Automatic transport verification
221
+
222
+ The built Node CLI passed all nine page commands against isolated Plane 1.4.2
223
+ instances both with API-key pages enabled and with the official, unmodified
224
+ backend/live images. Each run verified live editing, stale fingerprints, language
225
+ preservation, saved HTML and cleanup. The stock instance also passed session-only
226
+ access without an API key. No production rollout or npm publication was performed.
227
+
228
+ The release dry run passed 1,318 tests, TypeScript, formatting, Node smoke checks,
229
+ lazy dependency loading and package inventory checks. Nine deliberate mutations
230
+ were detected, including permission-triggered fallback and non-expiring capability
231
+ selection. These checks cover IPL-24; they do not resolve the separate PLX-11 review
232
+ findings in the extension layer and whole-page review conversion.
233
+
234
+ ### Review follow-up verification
235
+
236
+ Saved page reads preserve semantic review fences and can restore older sanitized
237
+ HTML from canonical JSON by block ID. Invalid or unmatched metadata, unsupported
238
+ wrappers, stale review order and malformed tables produce explicit losses.
239
+ A real built-CLI `page show` to file to `page set` round trip passed with exact
240
+ review date/source retained after browser reload. Unsupported underline content
241
+ reported a read loss and refused replacement without `--allow-loss`.
242
+
243
+ Late capability removal now repeats reference resolution before any mutation;
244
+ HTTP and live mutation markers prevent replay once a write has started. Targeted
245
+ independent reviews of formatting and command targeting found no remaining
246
+ confirmed issues. The complete release dry run passed 1,338 tests and twelve
247
+ intentional mutation checks. The aggregate extension review remains separately
248
+ tracked in PLX-12; these results do not claim production deployment or publication.