document360-writer 0.4.43 → 0.4.44

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.
Files changed (2) hide show
  1. package/dist/cli.js +1 -1
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -137,7 +137,7 @@ That's it \u2014 drop the file and keep building. The docs agent picks it up on
137
137
  2. /login signs in to that environment
138
138
  3. /project then /workspace \u2014 pick the project and where articles go
139
139
  Press 1 to start.`;function pu(e,t,n,o){let r=n.kind==="api"?"API key":n.kind==="subscription"?"subscription":"not configured",s=jo(e),c=ne(e),d=(c?.docsDir??"user-docs").replace(/\/+$/,""),g=c?.mode==="engineer"?"engineer \xB7 full source access (dogfooding)":`writer \xB7 edits limited to ${d}/ + config`,k={version:t,claude:r,model:s.model??"Claude Code default model",modelSource:du[s.source],who:null,sessionHint:null,profile:"\u2014",apiUrl:"\u2014",project:"\u2014",cwd:e,prod:!1,loggedOut:!0,configured:c!==null,mode:g};if(c===null)return k;try{let y=ae(e,o);k.profile=y.name,k.apiUrl=y.connection.apiUrl,k.prod=y.production,k.project=y.project.projectId??"(chosen at login)";let I=He(y.name);if(I){let b={...st(I.idToken)??{},...st(I.accessToken)??{}},C=b.email??b.preferred_username??"signed in";Ie(I)?I.refreshToken&&(k.who=C,k.loggedOut=!1,k.sessionHint="session expired \u2014 refreshing\u2026"):(k.who=C,k.loggedOut=!1,k.sessionHint=`session valid until ${new Date(I.expiresAt).toLocaleString(void 0,{hour:"2-digit",minute:"2-digit",day:"2-digit",month:"short"})}`)}}catch{}return k}function fu(e,t){try{let n=ae(e,t),o=He(n.name);if(!o)return{text:`profile "${n.name}" \u2014 not logged in (/login)`,prod:n.production};let r={...st(o.idToken)??{},...st(o.accessToken)??{}},s=r.email??r.preferred_username??"signed in";return Ie(o)&&!o.refreshToken?{text:`profile "${n.name}" \u2014 session expired (/login)`,prod:n.production}:{text:`${s} \xB7 profile "${n.name}"`,prod:n.production}}catch(n){return{text:n.message.split(".")[0],prod:!1}}}var ei=["Drafting","Composing","Outlining","Researching","Documenting","Structuring","Polishing","Synthesizing","Curating","Distilling","Weaving","Wrangling","Pondering"],kn=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],mu="Ask me to write or update an article\u2026";function hn({ch:e,dim:t}){let[n,o]=F(!0);return Ne(()=>{let r=setInterval(()=>o(s=>!s),530);return()=>clearInterval(r)},[]),S(v,{inverse:n,color:t&&!n?"gray":void 0,children:e})}var gu=/^mcp__document360__d360_(create_article|update_article|fork_article|publish_article)$/;function ti(e){let t=e.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/);return t?e.slice(t[0].length):e}var hu=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function ni(e){try{return oi(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&!t.name.startsWith(".")).length>6}catch{return!1}}function ku(e,t){let n=t??[];return n.length===0?["src","api","services","packages","modules"].some(o=>ni(St(e,o))):n.some(o=>!o.includes("/")&&!o.endsWith(".md")&&ni(St(e,o)))}function wu({startTime:e,chars:t}){let[n,o]=F(0);Ne(()=>{let g=setInterval(()=>o(k=>k+1),120);return()=>clearInterval(g)},[]);let r=kn[n%kn.length],s=ei[Math.floor(n/16)%ei.length],c=Math.floor((Date.now()-e)/1e3),d=Math.round(t/4);return U(J,{children:[S(v,{color:B,children:` ${r} ${s}\u2026 `}),S(v,{color:"gray",children:`(${$t(c)} \xB7 ~${d} tokens \xB7 esc to interrupt)`})]})}var yu=12e4;function xu({p:e}){let[t,n]=F(0);Ne(()=>{let g=setInterval(()=>n(k=>k+1),150);return()=>clearInterval(g)},[]);let o=kn[t%kn.length],r=Math.floor((Date.now()-e.startedAt)/1e3),s=Math.floor((Date.now()-e.lastAt)/1e3),c=Math.round(e.chars/4),d=Date.now()-e.lastAt>=yu;return U(J,{flexDirection:"column",children:[U(J,{children:[S(v,{color:B,children:` ${o} ${e.verb??"Converting"} `}),S(v,{color:"gray",children:`${e.done}/${e.total} \xB7 ${e.tools} tool call${e.tools===1?"":"s"} \xB7 ~${c} tokens \xB7 ${$t(r)} \xB7 esc to stop`})]}),e.active.length>0&&S(v,{dimColor:!0,children:` \u25B8 ${e.active.join(", ")} \xB7 last activity ${s}s ago`}),d&&S(v,{color:"yellow",children:` \u26A0 no activity for ${$t(s)} \u2014 press esc to stop if it's wedged`})]})}function ri({cwd:e,auth:t,profileName:n,version:o}){let{exit:r}=Dc(),[s,c]=F(n),[d,g]=F(null),[k,y]=F({text:"",pos:0}),I=k.text,b=V(l=>{y(a=>{let i=typeof l=="function"?l(a.text):l;return{text:i,pos:i.length}})},[]),C=V(l=>{y(a=>({text:a.text.slice(0,a.pos)+l+a.text.slice(a.pos),pos:a.pos+l.length}))},[]),$=V(()=>{y(l=>{if(l.pos===0)return l;let a=l.text.slice(0,l.pos),i=Fs(a)??a.slice(0,-1);return{text:i+l.text.slice(l.pos),pos:i.length}})},[]),[N,G]=F(!1),[z,le]=F(!1),[me,ye]=F(0),[ge,he]=F(null),[it,X]=F([]),Tt=K(0),[li,Rt]=F(!1),[ci,at]=F(0),Be=K(0),[lt,qe]=F(0),[Ge,jt]=F(null),Do=K(new Map),ui=K(0),ze=K([]),ce=K(null);ce.current===null&&(ce.current=Vs({cwd:e,profileName:s,allowProdWrites:!1}));let xe=K({uuid:null,firstPrompt:null,titleFired:!1}),At=K(new Map),ct=K(!1),wn=K([]),Te=K([]),yn=K(null),[Io,Ye]=F(null),[_e,Me]=F(null),[$e,Ve]=F(null),[Re,Xe]=F(null),[oe,Je]=F(null),[ue,Ke]=F(null),[be,Qe]=F(null),[de,Le]=F(null),[re,Ze]=F(null),[No,xn]=F([]),Oe=K([]),Et=K(!1),ve=K(null),[_o,Z]=F(null),Dt=K(!1),It=K(null),[pe,Ue]=F(null),[Mo,ut]=F(0),[Lo,dt]=F(0),[di,Oo]=F(0),$n=mn(()=>{try{return jo(e).model??"auto"}catch{return null}},[e,di]),{stdout:ke}=Nc(),[,pi]=F(0),Uo=K(`${ke.columns??80}x${ke.rows??24}`),je=V(()=>Math.max(20,(ke.columns??80)-1),[ke]),u=V(l=>{ze.current.push(l),console.log(Hn(l,je()))},[je]);Ne(()=>{let l=`d360-writer \xB7 ${Io??gn(e)}`;if(!N){un(0),Pt(`${vo} ${l}`);return}un(3);let a=0;Pt(`${dn[0]} ${l}`);let i=setInterval(()=>{a=(a+1)%dn.length,Pt(`${dn[a]} ${l}`)},400);return()=>clearInterval(i)},[N,e,Io]),Ne(()=>()=>un(0),[]),Ne(()=>{if(u({kind:"banner",info:pu(e,o,t,s)}),!ne(e)){u({kind:"note",tone:"info",text:`Welcome! This repo isn't set up for d360-writer yet \u2014 three steps and you're writing docs:
140
- ${Zs}`}),X(["/init"]);return}try{let l=ae(e,s),a=He(l.name);a&&Ie(a)&&a.refreshToken?Wc({profile:l.name,connection:l.connection}).then(()=>{u({kind:"note",tone:"ok",text:"\u2713 Document360 session refreshed."}),ye(i=>i+1)}).catch(()=>{u({kind:"note",tone:"warn",text:"Document360 session refresh failed \u2014 do you want to log in now? (press 1)"}),X(["/login"])}):(!a||Ie(a))&&(u({kind:"note",tone:"warn",text:`Profile "${l.name}" is not signed in \u2014 do you want to log in now? (press 1)`}),X(["/login"]))}catch{}try{let l=ne(e),a=ae(e,s),i=He(a.name);l&&i&&!Ie(i)&&ku(e,l.authoritativeSourceFiles)&&(u({kind:"note",tone:"info",text:"Large repo \u2014 the docs scope isn\u2019t set yet. Run /scope to choose which folders back your docs."}),X(["/scope"]))}catch{}},[]),Ne(()=>{let l=null,a=null,i=()=>{l&&clearTimeout(l),l=setTimeout(()=>{l=null;let h=`${ke.columns??80}x${ke.rows??24}`;h!==Uo.current&&(Uo.current=h,pi(p=>p+1),a&&clearTimeout(a),a=setTimeout(()=>{a=null,console.log("\x1B[?2026h\x1B[H\x1B[2J"+Ur(ze.current,je())+"\x1B[?2026l")},80))},400)};return ke.on("resize",i),()=>{l&&clearTimeout(l),a&&clearTimeout(a),ke.off("resize",i)}},[ke,je]);let We=Math.max(20,(ke.columns??80)-1),Wo=mn(()=>fu(e,s),[e,s,me]),bn=mn(()=>{let l=ne(e);if(!l)return{text:"Press 1 to set up this repo, or /help\u2026",isSetup:!0};try{let h=ae(e,s),p=He(h.name);if(!(!!p&&!(Ie(p)&&!p.refreshToken)))return{text:`Press 1 to sign in to Document360 (profile "${h.name}")\u2026`,isSetup:!0};if(!h.project.workspaceId)return{text:"Press 1 to pick a workspace\u2026",isSetup:!0}}catch{}let a=St(e,(l.docsDir??"user-docs").replace(/\/+$/,""));return(()=>{try{return zs(a)&&oi(a).length>0}catch{return!1}})()?{text:mu,isSetup:!1}:{text:"Let's get started \u2014 try: write the docs for this repo",isSetup:!1}},[e,s,me]),pt=cr(I),Fo=pt.length>0&&!N,vn=d!==null?qs(d,8,We):null,Nt=de?de.paths.filter(l=>!de.query||l.toLowerCase().includes(de.query.toLowerCase())).slice(0,8):[],_t=pe?pe.sessions.filter(l=>{let a=pe.query.toLowerCase();return!a||l.name.toLowerCase().includes(a)||l.firstPrompt.toLowerCase().includes(a)}).slice(0,8):[],se=V((l,a)=>{ce.current?.close(),ce.current=Vs({cwd:e,resume:l,profileName:a??s,allowProdWrites:ct.current}),l||(xe.current={uuid:null,firstPrompt:null,titleFired:!1},Ye(null)),ut(0),dt(0)},[e,s]),Ho=V((l,a,i)=>{if(gu.test(l))try{let h=ae(e,s),p=typeof a.project_id=="string"&&a.project_id||h.project.projectId,m=ln(a,i),w=[],T=cn(i);l.endsWith("publish_article")&&T&&w.push(`Live: ${T}`),m&&p&&w.push(`Preview: ${an(h.connection.portalUrl,p,m,h.project.languageCode??"en")}`),w.length>0&&u({kind:"link",lines:w})}catch{}},[e,s,u]),Ce=V(async(l,a)=>{Rt(!0),he(null),X([]);let i=++Tt.current;u({kind:"user",text:a?.echoDisplay&&a.display?a.display:l});let h=xe.current;h.firstPrompt||(h.firstPrompt=a?.display??l),Be.current=Date.now(),at(0),G(!0),At.current.clear();let p="",m="",w=null,T=()=>{w||(w=setTimeout(()=>{w=null,g(m.length>0?m:null)},60))},D=()=>{w&&clearTimeout(w),w=null,g(null)},M=()=>{if(m.trim()){let A=m.trimEnd();u({kind:"assistant",text:A})}m="",D()};try{for await(let A of ce.current.send(l))if(A.type==="session"){if(!h.uuid){h.uuid=A.sessionId;let _=new Date().toISOString(),P=zc(h.firstPrompt??"session");Yc({uuid:A.sessionId,name:P,renamed:!1,titled:!1,cwd:e,firstPrompt:h.firstPrompt??"",createdAt:_,updatedAt:_}),Ye(P)}}else if(A.type==="text"){m+=A.delta,p+=A.delta;let _=Gs(m);if(_>0){let P=m.slice(0,_).trimEnd();P&&u({kind:"assistant",text:P}),m=m.slice(_)}T(),at(P=>P+A.delta.length)}else if(A.type==="tool"){let _=rn(A.name,A.input);_&&(M(),u({kind:"tool",title:_.title,sep:_.sep,arg:_.arg}),At.current.set(A.id,{name:A.name,input:A.input}))}else if(A.type==="article_diff"){let _=Fe(A.oldContent,A.newContent,je());_&&(M(),u({kind:"diff",added:_.added,removed:_.removed,lines:_.lines,hidden:_.hidden}))}else if(A.type==="tool_result"){A.isError&&/run \/login|not logged in|session expired|rejected the token/i.test(A.output)&&(Dt.current=!0);let _=At.current.get(A.id);if(_){At.current.delete(A.id),M();let P=sn(A.output,4,A.isError?void 0:_.name,_.input);u({kind:"tool-result",lines:P.lines,hidden:P.hidden,isError:A.isError}),A.isError||Ho(_.name,_.input,A.output)}}else if(A.type==="result"){M(),ut(P=>P+A.outputTokens),dt(P=>P+A.costUsd),u({kind:"done",seconds:Math.round((Date.now()-Be.current)/1e3),tokens:A.outputTokens,costUsd:A.costUsd,ok:A.ok});let _=A.ok?Ms(p,kt.map(P=>P.name)):[];if(_.length>0?X(_):A.ok&&p.trim()&&Kc(l,p,e).then(P=>{P&&Tt.current===i&&he(P)}).catch(()=>{}),h.uuid&&(Co(h.uuid),!h.titleFired)){h.titleFired=!0;let P=h.uuid,j=h.firstPrompt;j&&Xs(j,e).then(W=>{W&&(Gc(P,W),Ye(W))}).catch(()=>{})}}else A.type==="error"&&(M(),A.kind==="auth"&&(Dt.current=!0),u({kind:"note",text:`agent error: ${A.message}`,tone:"error"}))}finally{G(!1),D(),xe.current.uuid&&Ns(e,xe.current.uuid,ze.current),Dt.current&&(Dt.current=!1,It.current=a?.display??l,X(["/login"])),Et.current&&(Et.current=!1,Oe.current.length>0&&(u({kind:"note",tone:"info",text:`(${Oe.current.length} queued message(s) discarded)`}),Oe.current=[],xn([])),u({kind:"note",tone:"warn",text:"Interrupted. What do you want to do next?"}))}},[e,u,Ho,je]),Cn=V(l=>{let a=He(l);if(!a||Ie(a)&&!a.refreshToken)return null;let i={...st(a.idToken)??{},...st(a.accessToken)??{}};return i.email??i.preferred_username??"signed in"},[]),Pn=V((l,a)=>{if(a){let i=ne(e);i&&(i.defaultProfile=l,Qc(i,e))}c(l),se(void 0,l),u({kind:"note",tone:"ok",text:`\u2713 Switched to profile "${l}"${a?" (saved as default)":" (this session only)"} \u2014 agent restarted.`}),Cn(l)||(u({kind:"note",tone:"warn",text:`Profile "${l}" is not signed in \u2014 do you want to log in now? (press 1)`}),X(["/login"])),ye(i=>i+1)},[e,u,se,Cn]),Mt=V((l,a,i)=>{Wt(e,l,a,i.id,i.name),u({kind:"note",tone:"ok",text:`Switched to workspace "${i.name??i.id}" (agent restarted).`}),se(),Js(e,l)||(u({kind:"note",tone:"info",text:"Setup complete. Press tab to start with a docs analysis."}),he("analyze this repo and propose a docs structure"))},[e,u,se]),Sn=V(async l=>{let a;try{a=await gt(e,l)}catch{u({kind:"note",tone:"info",text:"Next: pick a workspace \u2014 run /workspace."}),X(["/workspace"]);return}if(a.workspaces.length===0){u({kind:"note",tone:"warn",text:"This project has no workspaces yet. Create one in Document360, then run /workspace."});return}let i=a.workspaces.filter(p=>(p.workspace_type??"").toLowerCase()!=="apidocumentation"),h=i.length>0?i:a.workspaces;if(h.length===1){let p=h[0],m=a.workspaces.length-h.length;u({kind:"note",tone:"ok",text:`Selected the "${p.name??p.id}" workspace${m>0?" (skipped the API-documentation workspace)":""}.`}),Mt(a.profile,a.projectId,p);return}u({kind:"note",tone:"info",text:`Next: pick the workspace your articles publish to (${h.length} available).`}),X(["/workspace"])},[e,u,Mt]),Bo=V((l,a)=>{lo(e,l,a.id),u({kind:"note",tone:"ok",text:`Project set to "${a.name??a.id}" (agent restarted).`}),se(),Sn(l)},[e,u,se,Sn]),Lt=V(()=>{let l=Te.current[0];if(!l)return;u({kind:"note",tone:"info",text:`\u25CF ${l.title} (${l.path})`});for(let i of l.notes)u({kind:"note",tone:"warn",text:`\u26A0 ${i}`});l.overwritesLocalChanges&&u({kind:"note",tone:"warn",text:"\u26A0 This OVERWRITES local edits made since the last sync."});let a=Fe(l.oldContent,l.newContent,je());u(a?{kind:"diff",added:a.added,removed:a.removed,lines:a.lines,hidden:a.hidden}:{kind:"note",tone:"info",text:"Local file already matches the remote content \u2014 applying only advances the sync base."}),u({kind:"note",tone:"info",text:`Write ${l.path}? (y/n \u2014 anything else cancels)`})},[u,je]),qo=V(l=>{if(Te.current.length===0)return!1;let a=l.trim().toLowerCase();if(a==="y"||a==="yes"){let i=Te.current.shift();try{Zc({cwd:e,profileName:s},i),u({kind:"note",tone:"ok",text:`\u2713 Pulled ${i.path} (sync base advanced).`}),Te.current.length===0&&X(h=>h.length>0?h:["/sync"])}catch(h){u({kind:"note",tone:"error",text:`Pull failed: ${h.message}`})}}else if(a==="n"||a==="no"){let i=Te.current.shift();u({kind:"note",tone:"info",text:`Skipped ${i.path}.`})}else{let i=Te.current.length;return Te.current=[],u({kind:"note",tone:"info",text:`Pull cancelled (${i} article(s) left untouched).`}),!0}return Lt(),!0},[e,s,Lt,u]),Go=V(l=>{let a=yn.current;if(!a)return!1;if(yn.current=null,l.trim()!==a.repoName)return u({kind:"note",tone:"warn",text:"Reset cancelled \u2014 nothing deleted."}),!0;let{removed:i,failed:h}=ko(e,a.targets);u({kind:"note",tone:h.length?"warn":"ok",text:`\u2713 Reset complete \u2014 removed ${i.length} item${i.length===1?"":"s"}. The repo is back to its original state.`});for(let p of h)u({kind:"note",tone:"error",text:` \u2717 ${p.path}: ${p.error}`});return u({kind:"note",tone:"info",text:`Clean slate \u2014 set up d360-writer again whenever you're ready:
140
+ ${Zs}`}),X(["/init"]);return}try{let l=ae(e,s),a=He(l.name);a&&Ie(a)&&a.refreshToken?Wc({profile:l.name,connection:l.connection}).then(()=>{u({kind:"note",tone:"ok",text:"\u2713 Document360 session refreshed."}),ye(i=>i+1)}).catch(()=>{u({kind:"note",tone:"warn",text:"Document360 session refresh failed \u2014 do you want to log in now? (press 1)"}),X(["/login"])}):(!a||Ie(a))&&(u({kind:"note",tone:"warn",text:`Profile "${l.name}" is not signed in \u2014 do you want to log in now? (press 1)`}),X(["/login"]))}catch{}try{let l=ne(e),a=ae(e,s),i=He(a.name);l&&i&&!Ie(i)&&ku(e,l.authoritativeSourceFiles)&&(u({kind:"note",tone:"info",text:"Large repo \u2014 the docs scope isn\u2019t set yet. Run /scope to choose which folders back your docs."}),X(["/scope"]))}catch{}},[]),Ne(()=>{let l=null,a=null,i=()=>{l&&clearTimeout(l),l=setTimeout(()=>{l=null;let h=`${ke.columns??80}x${ke.rows??24}`;h!==Uo.current&&(Uo.current=h,pi(p=>p+1),a&&clearTimeout(a),a=setTimeout(()=>{a=null,console.log("\x1B[?2026h\x1B[H\x1B[2J"+Ur(ze.current,je())+"\x1B[?2026l")},80))},400)};return ke.on("resize",i),()=>{l&&clearTimeout(l),a&&clearTimeout(a),ke.off("resize",i)}},[ke,je]);let We=Math.max(20,(ke.columns??80)-1),Wo=mn(()=>fu(e,s),[e,s,me]),bn=mn(()=>{let l=ne(e);if(!l)return{text:"Press 1 to set up this repo, or /help\u2026",isSetup:!0};let a=St(e,(l.docsDir??"user-docs").replace(/\/+$/,"")),i=(()=>{try{return zs(a)&&oi(a).length>0}catch{return!1}})();try{let h=ae(e,s),p=He(h.name);if(!(!!p&&!(Ie(p)&&!p.refreshToken)))return{text:`Press 1 to sign in to Document360 (profile "${h.name}")\u2026`,isSetup:!0};if(!h.project.workspaceId&&!i)return{text:"Press 1 to pick a workspace\u2026",isSetup:!0}}catch{}return i?{text:mu,isSetup:!1}:{text:"Let's get started \u2014 try: write the docs for this repo",isSetup:!1}},[e,s,me]),pt=cr(I),Fo=pt.length>0&&!N,vn=d!==null?qs(d,8,We):null,Nt=de?de.paths.filter(l=>!de.query||l.toLowerCase().includes(de.query.toLowerCase())).slice(0,8):[],_t=pe?pe.sessions.filter(l=>{let a=pe.query.toLowerCase();return!a||l.name.toLowerCase().includes(a)||l.firstPrompt.toLowerCase().includes(a)}).slice(0,8):[],se=V((l,a)=>{ce.current?.close(),ce.current=Vs({cwd:e,resume:l,profileName:a??s,allowProdWrites:ct.current}),l||(xe.current={uuid:null,firstPrompt:null,titleFired:!1},Ye(null)),ut(0),dt(0)},[e,s]),Ho=V((l,a,i)=>{if(gu.test(l))try{let h=ae(e,s),p=typeof a.project_id=="string"&&a.project_id||h.project.projectId,m=ln(a,i),w=[],T=cn(i);l.endsWith("publish_article")&&T&&w.push(`Live: ${T}`),m&&p&&w.push(`Preview: ${an(h.connection.portalUrl,p,m,h.project.languageCode??"en")}`),w.length>0&&u({kind:"link",lines:w})}catch{}},[e,s,u]),Ce=V(async(l,a)=>{Rt(!0),he(null),X([]);let i=++Tt.current;u({kind:"user",text:a?.echoDisplay&&a.display?a.display:l});let h=xe.current;h.firstPrompt||(h.firstPrompt=a?.display??l),Be.current=Date.now(),at(0),G(!0),At.current.clear();let p="",m="",w=null,T=()=>{w||(w=setTimeout(()=>{w=null,g(m.length>0?m:null)},60))},D=()=>{w&&clearTimeout(w),w=null,g(null)},M=()=>{if(m.trim()){let A=m.trimEnd();u({kind:"assistant",text:A})}m="",D()};try{for await(let A of ce.current.send(l))if(A.type==="session"){if(!h.uuid){h.uuid=A.sessionId;let _=new Date().toISOString(),P=zc(h.firstPrompt??"session");Yc({uuid:A.sessionId,name:P,renamed:!1,titled:!1,cwd:e,firstPrompt:h.firstPrompt??"",createdAt:_,updatedAt:_}),Ye(P)}}else if(A.type==="text"){m+=A.delta,p+=A.delta;let _=Gs(m);if(_>0){let P=m.slice(0,_).trimEnd();P&&u({kind:"assistant",text:P}),m=m.slice(_)}T(),at(P=>P+A.delta.length)}else if(A.type==="tool"){let _=rn(A.name,A.input);_&&(M(),u({kind:"tool",title:_.title,sep:_.sep,arg:_.arg}),At.current.set(A.id,{name:A.name,input:A.input}))}else if(A.type==="article_diff"){let _=Fe(A.oldContent,A.newContent,je());_&&(M(),u({kind:"diff",added:_.added,removed:_.removed,lines:_.lines,hidden:_.hidden}))}else if(A.type==="tool_result"){A.isError&&/run \/login|not logged in|session expired|rejected the token/i.test(A.output)&&(Dt.current=!0);let _=At.current.get(A.id);if(_){At.current.delete(A.id),M();let P=sn(A.output,4,A.isError?void 0:_.name,_.input);u({kind:"tool-result",lines:P.lines,hidden:P.hidden,isError:A.isError}),A.isError||Ho(_.name,_.input,A.output)}}else if(A.type==="result"){M(),ut(P=>P+A.outputTokens),dt(P=>P+A.costUsd),u({kind:"done",seconds:Math.round((Date.now()-Be.current)/1e3),tokens:A.outputTokens,costUsd:A.costUsd,ok:A.ok});let _=A.ok?Ms(p,kt.map(P=>P.name)):[];if(_.length>0?X(_):A.ok&&p.trim()&&Kc(l,p,e).then(P=>{P&&Tt.current===i&&he(P)}).catch(()=>{}),h.uuid&&(Co(h.uuid),!h.titleFired)){h.titleFired=!0;let P=h.uuid,j=h.firstPrompt;j&&Xs(j,e).then(W=>{W&&(Gc(P,W),Ye(W))}).catch(()=>{})}}else A.type==="error"&&(M(),A.kind==="auth"&&(Dt.current=!0),u({kind:"note",text:`agent error: ${A.message}`,tone:"error"}))}finally{G(!1),D(),xe.current.uuid&&Ns(e,xe.current.uuid,ze.current),Dt.current&&(Dt.current=!1,It.current=a?.display??l,X(["/login"])),Et.current&&(Et.current=!1,Oe.current.length>0&&(u({kind:"note",tone:"info",text:`(${Oe.current.length} queued message(s) discarded)`}),Oe.current=[],xn([])),u({kind:"note",tone:"warn",text:"Interrupted. What do you want to do next?"}))}},[e,u,Ho,je]),Cn=V(l=>{let a=He(l);if(!a||Ie(a)&&!a.refreshToken)return null;let i={...st(a.idToken)??{},...st(a.accessToken)??{}};return i.email??i.preferred_username??"signed in"},[]),Pn=V((l,a)=>{if(a){let i=ne(e);i&&(i.defaultProfile=l,Qc(i,e))}c(l),se(void 0,l),u({kind:"note",tone:"ok",text:`\u2713 Switched to profile "${l}"${a?" (saved as default)":" (this session only)"} \u2014 agent restarted.`}),Cn(l)||(u({kind:"note",tone:"warn",text:`Profile "${l}" is not signed in \u2014 do you want to log in now? (press 1)`}),X(["/login"])),ye(i=>i+1)},[e,u,se,Cn]),Mt=V((l,a,i)=>{Wt(e,l,a,i.id,i.name),u({kind:"note",tone:"ok",text:`Switched to workspace "${i.name??i.id}" (agent restarted).`}),se(),Js(e,l)||(u({kind:"note",tone:"info",text:"Setup complete. Press tab to start with a docs analysis."}),he("analyze this repo and propose a docs structure"))},[e,u,se]),Sn=V(async l=>{let a;try{a=await gt(e,l)}catch{u({kind:"note",tone:"info",text:"Next: pick a workspace \u2014 run /workspace."}),X(["/workspace"]);return}if(a.workspaces.length===0){u({kind:"note",tone:"warn",text:"This project has no workspaces yet. Create one in Document360, then run /workspace."});return}let i=a.workspaces.filter(p=>(p.workspace_type??"").toLowerCase()!=="apidocumentation"),h=i.length>0?i:a.workspaces;if(h.length===1){let p=h[0],m=a.workspaces.length-h.length;u({kind:"note",tone:"ok",text:`Selected the "${p.name??p.id}" workspace${m>0?" (skipped the API-documentation workspace)":""}.`}),Mt(a.profile,a.projectId,p);return}u({kind:"note",tone:"info",text:`Next: pick the workspace your articles publish to (${h.length} available).`}),X(["/workspace"])},[e,u,Mt]),Bo=V((l,a)=>{lo(e,l,a.id),u({kind:"note",tone:"ok",text:`Project set to "${a.name??a.id}" (agent restarted).`}),se(),Sn(l)},[e,u,se,Sn]),Lt=V(()=>{let l=Te.current[0];if(!l)return;u({kind:"note",tone:"info",text:`\u25CF ${l.title} (${l.path})`});for(let i of l.notes)u({kind:"note",tone:"warn",text:`\u26A0 ${i}`});l.overwritesLocalChanges&&u({kind:"note",tone:"warn",text:"\u26A0 This OVERWRITES local edits made since the last sync."});let a=Fe(l.oldContent,l.newContent,je());u(a?{kind:"diff",added:a.added,removed:a.removed,lines:a.lines,hidden:a.hidden}:{kind:"note",tone:"info",text:"Local file already matches the remote content \u2014 applying only advances the sync base."}),u({kind:"note",tone:"info",text:`Write ${l.path}? (y/n \u2014 anything else cancels)`})},[u,je]),qo=V(l=>{if(Te.current.length===0)return!1;let a=l.trim().toLowerCase();if(a==="y"||a==="yes"){let i=Te.current.shift();try{Zc({cwd:e,profileName:s},i),u({kind:"note",tone:"ok",text:`\u2713 Pulled ${i.path} (sync base advanced).`}),Te.current.length===0&&X(h=>h.length>0?h:["/sync"])}catch(h){u({kind:"note",tone:"error",text:`Pull failed: ${h.message}`})}}else if(a==="n"||a==="no"){let i=Te.current.shift();u({kind:"note",tone:"info",text:`Skipped ${i.path}.`})}else{let i=Te.current.length;return Te.current=[],u({kind:"note",tone:"info",text:`Pull cancelled (${i} article(s) left untouched).`}),!0}return Lt(),!0},[e,s,Lt,u]),Go=V(l=>{let a=yn.current;if(!a)return!1;if(yn.current=null,l.trim()!==a.repoName)return u({kind:"note",tone:"warn",text:"Reset cancelled \u2014 nothing deleted."}),!0;let{removed:i,failed:h}=ko(e,a.targets);u({kind:"note",tone:h.length?"warn":"ok",text:`\u2713 Reset complete \u2014 removed ${i.length} item${i.length===1?"":"s"}. The repo is back to its original state.`});for(let p of h)u({kind:"note",tone:"error",text:` \u2717 ${p.path}: ${p.error}`});return u({kind:"note",tone:"info",text:`Clean slate \u2014 set up d360-writer again whenever you're ready:
141
141
  ${Zs}`}),X(["/init"]),Rt(!1),!0},[e,u]),zo=V(async l=>{let a=l.slice(1).trim().split(/\s+/),i=(a[0]??"").toLowerCase(),h=a.slice(1);switch(Rt(!0),i){case"help":u({kind:"note",tone:"info",text:Yt().join(`
142
142
  `)});return;case"exit":case"quit":ce.current?.close(),r();return;case"clear":se(),ze.current=[],Rt(!1),he(null),Tt.current++,u({kind:"note",tone:"info",text:"Conversation reset (the previous session is still resumable via /resume)."});return;case"login":{let p;try{p=ae(e,s)}catch(m){u({kind:"note",tone:"error",text:m.message});return}u({kind:"note",tone:"info",text:`Profile "${p.name}" \u2192 ${p.connection.name} (${p.connection.apiUrl})${p.production?" \u26A0 PRODUCTION":""}`}),le(!0);try{let m=await Lc(p.connection,{promptForRedirect:()=>Promise.reject(new Error("Manual login is CLI-only. Run: d360-writer login --manual"))},D=>u({kind:"note",tone:"info",text:D})),w=Oc(p.name,m);Uc(w),An(w,p.name,D=>u({kind:"note",tone:"info",text:D})),u({kind:"note",tone:"ok",text:`\u2713 Logged in to "${p.name}" as ${Ht(w)}`});let T=(()=>{try{return ae(e,s)}catch{return p}})();T.project.workspaceId||(T.project.projectId?await Sn(T.name):(u({kind:"note",tone:"info",text:"Next: pick the Document360 project."}),X(["/project"]))),It.current&&(he(It.current),It.current=null,u({kind:"note",tone:"info",text:"Press tab to re-send your last prompt."}))}catch(m){u({kind:"note",tone:"error",text:`Login failed: ${m.message}`})}finally{le(!1),ye(m=>m+1)}return}case"allow-prod":{let p=!1;try{p=ae(e,s).production}catch{}if(!p){u({kind:"note",tone:"info",text:"Current profile is not production \u2014 writes are already allowed."});return}ct.current=!0,se(),u({kind:"note",tone:"warn",text:"\u26A0 Production writes authorized for this session."});return}case"rename":{let p=oo(h.join(" ")),m=xe.current.uuid;if(!m){u({kind:"note",tone:"error",text:"Send a message first \u2014 sessions save once the agent replies."});return}if(!p){u({kind:"note",tone:"info",text:"Thinking of a name\u2026"});let w=xe.current.firstPrompt??"";Xs(w,e).then(T=>{T?(he(`/rename ${T}`),u({kind:"note",tone:"info",text:`Suggestion: "${T}" \u2014 press tab to accept, or type /rename <your name>.`})):u({kind:"note",tone:"info",text:"Usage: /rename <name>"})}).catch(()=>u({kind:"note",tone:"info",text:"Usage: /rename <name>"}));return}Jc(m,p),Ye(p),Pt(`${vo} d360-writer \xB7 ${p}`),u({kind:"note",tone:"ok",text:`Session renamed to "${p}".`});return}case"profile":{let p=h[0],m=ne(e);if(!p){let w=Object.entries(m?.profiles??{});if(w.length===0){u({kind:"note",tone:"info",text:"No profiles. Run /init first."});return}let T=w.map(([A,_])=>({name:A,env:_.connection?.environment??"custom",prod:_.production===!0,who:Cn(A)})),D=s??m?.defaultProfile,M=Math.max(0,T.findIndex(A=>A.name===D));Ve({cursor:M,current:M,rows:T});return}if(p==="add"){let w=ro(e,h[1],h[2]);if(w){u({kind:"note",tone:"error",text:w});return}u({kind:"note",tone:"ok",text:`\u2713 Profile "${h[1]}" created (environment: ${h[2]??h[1]}).`}),Pn(h[1],!1);return}if(!m?.profiles?.[p]){u({kind:"note",tone:"error",text:`Unknown profile "${p}". Create it: /profile add ${p} <environment>`});return}Pn(p,!0);return}case"doctor":await vt(h,{cwd:e});return;case"mcp":await Xt(h);return;case"init":{if(ne(e)){u({kind:"note",tone:"info",text:"This repo is already set up \u2014 edit .d360-writer.json directly (or d360-writer init for the CLI wizard)."});return}let p=nu().map(m=>({name:m,apiUrl:ou(m).apiUrl}));Xe({cursor:0,rows:p});return}case"resume":{let p=h.join(" ").trim(),m=Xc(e).filter(D=>D.uuid!==xe.current.uuid);if(!p){if(!m.length){u({kind:"note",tone:"info",text:"No saved sessions for this repo yet."});return}Ue({query:"",cursor:0,sessions:m});return}let w=Vc(e,p);if(!w){u({kind:"note",tone:"error",text:`No session matches "${p}".`});return}se(w.uuid),xe.current={uuid:w.uuid,firstPrompt:w.firstPrompt,titleFired:!0},Ye(w.name),Co(w.uuid),ze.current=[];let T=bo(e,w.uuid);for(let D of T)u(D);u({kind:"note",tone:"ok",text:T.length?`Resumed "${w.name}" \u2014 restored ${T.length} message(s); continue where you left off.`:`Resumed "${w.name}" (agent memory reconnected; no saved transcript to replay).`});return}case"workspace":{let p=h.join(" ").trim(),m;try{m=await gt(e,s)}catch(T){u({kind:"note",tone:"error",text:`Could not list workspaces: ${T.message}`});return}if(!p){let T=m.workspaces.map(M=>({id:M.id,name:M.name??M.id,type:M.workspace_type}));if(T.length===0){u({kind:"note",tone:"info",text:"No workspaces in this project."});return}let D=Math.max(0,T.findIndex(M=>M.id===m.current));Je({cursor:D,current:D,rows:T,profile:m.profile,projectId:m.projectId,environment:m.environment});return}let w=jn(m.workspaces,p);if(!w){u({kind:"note",tone:"error",text:`No workspace matches "${p}".`});return}Mt(m.profile,m.projectId,w);return}case"project":{let p=h.join(" ").trim(),m;try{m=await ao(e,s)}catch(T){u({kind:"note",tone:"error",text:`Could not list projects: ${T.message} (signed in? try /login)`});return}if(!p){let T=m.projects.map(M=>({id:M.id,name:M.name??M.id,sub:M.sub_domain}));if(T.length===0){u({kind:"note",tone:"info",text:"No projects found for this identity."});return}let D=T.findIndex(M=>M.id===m.current);Ke({cursor:Math.max(0,D),current:D,rows:T,profile:m.profile,environment:m.environment});return}let w=is(m.projects,p);if(!w){u({kind:"note",tone:"error",text:`No project matches "${p}". Available: ${m.projects.map(T=>T.name??T.id).join(", ")}`});return}Bo(m.profile,w);return}case"logout":{let p;try{p=ae(e,s).name}catch(w){u({kind:"note",tone:"error",text:w.message});return}let m=Bc(p);qc(e,p),se(),ye(w=>w+1),u({kind:"note",tone:m?"ok":"info",text:m?`\u2713 Signed out of "${p}" and cleared its project/workspace selection.`:`Profile "${p}" was not signed in. Cleared any project/workspace selection.`}),u({kind:"note",tone:"info",text:"Run /login to sign in and pick a project."}),X(["/login"]);return}case"publish":{if(h[0]&&h[0]!=="--all"){await Ce(Kt(h[0]),{display:`/publish ${h[0]}`,echoDisplay:!0});return}let p=h[0]==="--all";u({kind:"note",tone:"info",text:"Checking what needs publishing\u2026"});try{let m=await Po({cwd:e,profileName:s}),w=Jt(m.entries);if(w.length===0){u({kind:"note",tone:"ok",text:"\u2713 Nothing is ahead of Document360 \u2014 no publish candidates."});let D=m.counts["unknown-base"]??0;D>0&&u({kind:"note",tone:"info",text:`(${D} article(s) have no sync base yet \u2014 publish those by path if needed.)`});return}if(p){await Ce(yt(w.map(D=>D.path)),{display:"/publish --all",echoDisplay:!0});return}let T=w.length>1?[{path:"--all",label:`publish all ${w.length} candidates in one run`},...w]:w;Qe({cursor:0,rows:T})}catch(m){u({kind:"note",tone:"error",text:`Could not compute sync status: ${m.message}`}),u({kind:"note",tone:"info",text:"Publish a specific article: /publish <article-path>"})}return}case"preview":{let p=h.join(" ").trim();if(!p){let w=[];try{w=Object.keys(Js(e,ae(e,s).name)?.articles??{})}catch{}if(w.length===0){u({kind:"note",tone:"info",text:"No tracked articles to pick from yet. Usage: /preview <path-to.md | article-id>"});return}Le({query:"",cursor:0,paths:w});return}let m=Mc(p)?p:St(e,p);if(zs(m)){try{u({kind:"preview",name:gn(m),text:ti(Ys(m,"utf8"))})}catch(w){u({kind:"note",tone:"error",text:`Could not read ${m}: ${w.message}`})}return}if(hu.test(p)){try{let w=ae(e,s),T={profile:w.name,connection:w.connection},D=w.project.projectId??Fc(T),M=await Hc(T,D,p);u({kind:"preview",name:M.title??p,text:M.content??"*(article has no content)*"})}catch(w){u({kind:"note",tone:"error",text:`Could not fetch article: ${w.message}`})}return}u({kind:"note",tone:"error",text:`"${p}" is neither a file (relative to ${e}) nor an article id.`});return}case"model":{let p=h[0]?.trim();if(!p){let D=tn(jo(e));Me({cursor:D,current:D});return}let{lines:m,changed:w,effective:T}=bt(e,p);for(let D of m)u({kind:"note",tone:D.startsWith("\u26A0")?"warn":D.startsWith("\u2713")?"ok":"info",text:D});w&&(Oo(D=>D+1),ce.current?.setModel(T));return}case"convert":{if(!ne(e)){u({kind:"note",tone:"error",text:"No d360-writer config here. Run /init first."});return}let{scope:p,run:m}=qn(h),w=iu(e,s);if(w.length===0){u({kind:"note",tone:"error",text:"No tracked articles in d360-category-map.json. Publish some first (/publish), then /convert."});return}let T=Gn(w,p);if(T.length===0){u({kind:"note",tone:"error",text:`No tracked articles under "${p}". (${w.length} are tracked overall.)`});return}let D=Ks(T),M=3,A=`/convert${p?` --scope ${p}`:""} --run`,_=To(e,"light");if(!m){let j=Qs({files:zn(e,T),op:"convert",model:_.model}),W=p?`Scope: ${p} (${T.length} of ${w.length} tracked)
143
143
  `:"",ee=`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document360-writer",
3
- "version": "0.4.43",
3
+ "version": "0.4.44",
4
4
  "description": "Standalone documentation agent CLI. Reads your code, writes your docs. Specialized for Document360 publishing.",
5
5
  "type": "module",
6
6
  "bin": {