document360-writer 0.5.95 → 0.5.96

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 +3 -1
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -300,7 +300,9 @@ Articles:
300
300
  `)}async function ec(e,t){let n=e.includes("--fix"),o=e.find(l=>!l.startsWith("--")),r=o?` ${o}`:"",i=Oh({cwd:t.cwd,scope:o});if(n)return i.length===0?(console.log(j("\u2713 Nothing to fix \u2014 the docs are already clean.")),{kind:"continue"}):(console.log(f(`Fixing ${i.length} doc issue${i.length===1?"":"s"} (run /check again after to confirm)\u2026`)),{kind:"forward-to-agent",prompt:Yi(i),display:`/check${r} --fix`});console.log(f("Linting the docs (engine internals, unknown commands, stale facts, AI-tells)\u2026"));for(let l of Mo(i))console.log(i.length===0?j(l):L(l));return i.length>0&&console.log(f("Run /check --fix to have the agent correct these.")),console.log(""),{kind:"continue"}}W();import{lintDocs as Hh,loadStyleGuide as qh,buildReviewPrompt as Bh,readProjectConfig as Vh,DEFAULT_DOCS_DIR as Gh}from"document360-engine";W();import{readProjectConfig as Lh,loadProfileMap as Mh,resolveActiveProfile as Uh,desiredCategoryOrder as Wh,desiredArticleOrder as Fh}from"document360-engine";function tc(e){let t=e.replace(/\.(md|markdown)$/i,"").replace(/^\d+[-_]/,"").replace(/[-_]+/g," ").trim();return t?t.charAt(0).toUpperCase()+t.slice(1):e}var nc=e=>e.replace(/\\/g,"/").split("/").pop()??e;function Sn(e,t){try{if(!Lh(e))return[];let n=Uh(e,t),o=Mh(e,n.name);if(!o)return[];let r=new Map;for(let l of Fh(o)){let p=r.get(l.categoryPath);p?p.push(l):r.set(l.categoryPath,[l])}let i=[];for(let l of Wh(o)){i.push(tc(nc(l.path)));for(let p of(r.get(l.path)??[]).sort((m,k)=>m.order-k.order))i.push(` ${tc(nc(p.path))}`)}return i}catch{return[]}}async function oc(e,t){let n=Sn(t.cwd,t.profileName);if(n.length===0)return console.log(f("No documentation structure yet \u2014 run /init and author some articles first.")),{kind:"continue"};console.log(O("Documentation order (categories \u2192 articles):"));for(let o of n)console.log(o);return console.log(""),{kind:"continue"}}function zi(e,t){let n=Vh(e);if(!n)return null;let o=(n.docsDir??Gh).replace(/\\/g,"/").replace(/\/+$/,""),r=t.includes("--fix"),i=t.find(g=>!g.startsWith("--"))?.replace(/\\/g,"/").replace(/\/+$/,""),l=Hh({cwd:e}),p=i?l.filter(g=>g.path===`${o}/${i}`||g.path.startsWith(`${o}/${i}/`)):l,m=i?"":Sn(e).join(`
301
301
  `);return{prompt:Bh({docsRoot:o,scope:i,styleGuide:qh(e),deterministicFindings:p,fix:r,structure:m||void 0}),display:`/review${i?` ${i}`:""}${r?" --fix":""}`}}async function rc(e,t){if(et("review",e)){let o=Kt(t.cwd,"review",e,t.profileName);if(o.length>0){for(let r of o)console.log(f(r));return{kind:"continue"}}}let n=zi(t.cwd,e);return n?{kind:"forward-to-agent",prompt:n.prompt,display:n.display}:(console.log(C("No d360-writer config here. Run /init first.")),{kind:"continue"})}W();import{readProjectConfig as Yh}from"document360-engine";function Ki(e,t){if(!Yh(e))return null;let n=t.find(r=>!r.startsWith("--"));return{prompt:[`Reorder the articles within ${n?`the "${n}" category`:"each category"} to the best reading order.`,"Follow the manage-structure skill: decide the ideal order with senior-editor judgment per the doc-genre","playbook (overview / mental-model first; reference and troubleshooting/FAQ last), then APPLY it with the","d360_reorder_articles tool \u2014 one category at a time, all paths in the same category folder. Do not rename","files or edit the map by hand; the tool handles it. Report the new order, and remind me it reaches","Document360 on the next /publish."].join(`
302
302
  `),display:`/reorder${n?` ${n}`:""}`}}async function ic(e,t){if(et("reorder",e)){let o=Kt(t.cwd,"reorder",e,t.profileName);if(o.length>0){for(let r of o)console.log(f(r));return{kind:"continue"}}}let n=Ki(t.cwd,e);return n?{kind:"forward-to-agent",prompt:n.prompt,display:n.display}:(console.log(C("No d360-writer config here. Run /init first.")),{kind:"continue"})}W();import{readProjectConfig as zh,writeProjectConfig as sc,isAppType as Kh,playbookSkillName as Xh,detectAppType as ac}from"document360-engine";var lc=["web","cli","service","library"],Qh=new Set(["web","cli"]);function Xi(e){return Qh.has(e)?`${Xh(e)} will load`:`no ${e}-doc-playbook exists yet \u2014 generic skills apply`}async function Uo(e,t){let n=t.cwd,o=zh(n);if(!o)return console.log(C("No d360-writer config here. Run /init first.")),{kind:"continue"};let r=e[0]?.trim().toLowerCase();if(!r){let i=o.appType??ac(n);if(i){let l=o.appType?"set in config":"auto-detected";console.log(`${O("Genre:")} ${i} (${l}) \u2014 ${Xi(i)}`)}else console.log(L("Genre: unclassified \u2014 no doc-type playbook is loading."));return console.log(f(`Set it: /genre <${lc.join("|")}> \xB7 revert to auto-detect: /genre auto`)),{kind:"continue"}}if(r==="auto"||r==="clear"){if(!o.appType)return console.log(f("Already on auto-detect (no genre set in config).")),{kind:"continue"};let{appType:i,...l}=o;sc(l,n);let p=ac(n);return console.log(j(`\u2713 Genre reset to auto-detect \u2014 now: ${p?`${p} (${Xi(p)})`:"unclassified (no playbook)"} (applies from your next command).`)),{kind:"continue"}}return Kh(r)?(sc({...o,appType:r},n),console.log(j(`\u2713 Genre set to ${r} \u2014 ${Xi(r)} (applies from your next command).`)),{kind:"continue"}):(console.log(C(`Unknown genre "${r}". Choose one of: ${lc.join(", ")} (or "auto" to revert to detection).`)),{kind:"continue"})}W();import{listRoadmap as cc,roadmapProgress as dc,stampRoadmapDone as Jh}from"document360-engine";function Qi(e){let t=cc(e);if(t.length===0)return["No docs roadmap yet \u2014 the docs agent seeds .d360-writer/roadmap.md when it pins a structure,","and adds steps as the app changes. You can also write steps by hand (## [open] <step>), or ask:",'"propose the docs roadmap for this repo".'];let n=dc(e),o=[`Docs roadmap \u2014 ${n.done} of ${n.total} step${n.total===1?"":"s"} done:`,""];for(let r of t)o.push(` ${r.status==="done"?"\u2713":"\u25CB"} ${r.title}${r.run?` \xB7 ${r.run}`:""}`);return o.push(""),o.push(n.next?`Next: ${n.next.title}${n.next.run?` \u2014 ${n.next.run}`:""}`:"Campaign complete \u2014 the docs agent adds new steps as the app changes."),o.push("(Edit .d360-writer/roadmap.md freely \xB7 /roadmap done <step> marks one you finished yourself.)"),o}function Ji(e,t){if(!t.trim())return{ok:!1,line:"Usage: /roadmap done <step title>"};if(!Jh(e,t,{doneAt:new Date().toISOString()})){let r=cc(e).filter(i=>i.status==="open");return{ok:!1,line:r.length?`No open step titled "${t}". Open steps: ${r.map(i=>`"${i.title}"`).join(", ")}`:`No open step titled "${t}" \u2014 the roadmap has no open steps.`}}let o=dc(e)?.next;return{ok:!0,line:`\u2713 Marked done: ${t}${o?` \u2014 next up: ${o.title}${o.run?` (${o.run})`:""}`:" \u2014 that was the last step: campaign complete."}`}}async function uc(e,t){let n=t.cwd;if(e[0]?.toLowerCase()==="done"){let r=Ji(n,e.slice(1).join(" ").trim());return console.log(r.ok?j(r.line):L(r.line)),{kind:"continue"}}let o=Qi(n);console.log(O(o[0]??""));for(let r of o.slice(1))console.log(r.startsWith("(")?f(r):r);return{kind:"continue"}}var pc={help:jr,"?":jr,clear:ma,exit:Ar,quit:Ar,init:Or,mcp:ko,publish:Qa,audit:vn,discover:Ja,scope:el,pull:cl,resolve:sl,convert:dl,write:gl,draft:vl,document:$l,resume:Rl,rename:Pl,profile:Sl,model:Al,doctor:Cn,workspace:Ll,project:Ml,"allow-prod":Ul,login:Wl,logout:Fl,screenshot:No,"capture-setup":Rn,devhints:Ca,inbox:Gl,"catch-up":Yl,update:zl,reset:Zl,check:ec,review:rc,reorder:ic,structure:oc,genre:Uo,roadmap:uc};function fc(e){let t=e.trim();if(!t.startsWith("/"))return null;let n=t.slice(1).split(/\s+/),o=(n[0]??"").toLowerCase();return o?{name:o,args:n.slice(1)}:null}Qe();var Zh="Or just tell me what to write or update.",em='\u{1F4ED} No docs yet for this repo. Tell me "write the docs for this repo" and I\u2019ll read the code and draft a structure \u2014 or /audit to see what the docs should cover.';function ye(e){return e===1?"":"s"}function Wo(e){return e.kind==="cmd"?`\u21E5 tab to run ${e.cmd} \xB7 or just ask me anything\u2026`:null}function es(e){return e.kind==="cmd"?`I\u2019d start with ${e.cmd} \u2014 ${e.reason}.`:`Just tell me: \u201C${e.text}\u201D.`}var tm={title:"What kind of product is this repo? (sets the doc-craft playbook \u2014 otherwise the docs stay generic)",options:[{cmd:"/genre web",desc:"web app / SaaS UI"},{cmd:"/genre cli",desc:"command-line tool"},{cmd:"/genre service",desc:"API / backend service"},{cmd:"/genre library",desc:"SDK / library"}]};function nm(e){let t=[];if(e.devhints!=="current"&&e.builderStarted){let n=e.devhintsToVersion?`v${e.devhintsToVersion}`:"a newer version",o=e.devhints==="stale"&&e.devhintsCompletedVersion?` (your builder is on v${e.devhintsCompletedVersion})`:"";t.push({key:"devhints",bullet:`dev\u2194docs protocol moved to ${n}${o} \u2014 your docs aren\u2019t blocked`,lead:{kind:"cmd",cmd:"/devhints",reason:`one paste updates your builder to ${n}`},picker:null,follow:"Also run /devhints when you get a second \u2014 your builder\u2019s protocol is behind.",tone:"warn"})}if(e.genreUnknown&&t.push({key:"genre",bullet:"the doc genre isn\u2019t set \u2014 I can\u2019t load the right doc-craft playbook yet",lead:null,picker:tm,follow:"Then pick the doc genre below (it sets the playbook I write with)."}),e.discovery&&e.discovery.status!=="confident"){let n=e.discovery.openQuestions;t.push(e.discovery.status==="pending"?{key:"discovery",bullet:"your existing docs aren\u2019t grounded in a product brief yet",lead:{kind:"cmd",cmd:"/discover",reason:"it interviews your builder and grounds the docs before you rewrite or publish them"},picker:null,follow:"Then /discover grounds your docs in a product brief (do this before the rewrite/publish steps)."}:n>0?{key:"discovery",bullet:`product discovery is waiting on ${n} answer${ye(n)} from your builder \u2014 nudge them`,lead:null,picker:null,follow:"Discovery is waiting on your builder\u2019s answers \u2014 nudge them, then /catch-up folds the answers in once they reply."}:{key:"discovery",bullet:"product discovery is ready to continue",lead:{kind:"cmd",cmd:"/discover",reason:"it continues interviewing your builder to ground the docs"},picker:null,follow:"Then /discover continues building the product brief."})}if(e.hasDocs&&e.pendingWrites>0){let n=e.pendingWrites;t.push({key:"write",bullet:`${n} planned article${ye(n)} still unwritten`,lead:{kind:"cmd",cmd:"/write",reason:"it finishes the articles already planned"},picker:null,follow:`Then /write finishes the ${n} planned article${ye(n)}.`})}if(e.directives>0||e.pendingText){let n=e.directives>0&&e.pendingText?"it actions your directives and clears the builder\u2019s queue":e.directives>0?"it actions the directives you left":"it clears everything your builder queued",o=[];e.directives>0&&o.push(`${e.directives} owner directive${ye(e.directives)} waiting`),e.pendingText&&o.push(`your builder left ${e.pendingText}`),t.push({key:"catchup",bullet:o.join(`
303
- \u2022 `),lead:{kind:"cmd",cmd:"/catch-up",reason:n},picker:null,follow:"Then /catch-up clears what\u2019s queued for the docs."})}if(e.localAhead>0){let n=e.localAhead;t.push({key:"publish",bullet:`${n} article${ye(n)} changed locally \u2014 ready to publish`,lead:{kind:"cmd",cmd:"/publish",reason:`it pushes your ${n} local edit${ye(n)} up to Document360`},picker:null,follow:`Then /publish pushes your ${n} local edit${ye(n)} up.`})}if(e.hasDocs&&e.roadmap?.next){let n=e.roadmap,o=n.next;t.push({key:"roadmap",bullet:`docs campaign: ${n.done} of ${n.total} step${ye(n.total)} done \u2014 next: ${o.title}`,lead:o.run?{kind:"cmd",cmd:o.run,reason:"it\u2019s the next step of your docs campaign"}:{kind:"prompt",text:o.title,reason:"it\u2019s the next step of your docs campaign"},picker:null,follow:`Then the campaign continues: ${o.title} (/roadmap shows all ${n.total} steps).`})}if(e.behind>0){let n=e.behind;t.push({key:"audit",bullet:`${n} code change${ye(n)} since your last docs check`,lead:{kind:"cmd",cmd:"/audit",reason:"it shows what the latest code changes touch (or /audit --auto on to run it for you)"},picker:null,follow:`After that, /audit covers the ${n} newer commit${ye(n)}.`})}return t}function hc(e){return e.find(t=>t.lead||t.picker)??null}function Zi(e,t){let n=t.filter(l=>l.bullet).map(l=>` \u2022 ${l.bullet}`),o=hc(t),r=[];o?.lead?r.push(es(o.lead)):o?.picker&&r.push("Pick the genre below \u2014 one keypress, and it shapes everything I write.");for(let l of t.filter(p=>p!==o).slice(0,2))l.follow&&r.push(l.follow);let i=[e,...n];return r.length&&i.push(r.join(" ")),i.push(Zh),i.join(`
303
+ \u2022 `),lead:{kind:"cmd",cmd:"/catch-up",reason:n},picker:null,follow:"Then /catch-up clears what\u2019s queued for the docs."})}if(e.localAhead>0){let n=e.localAhead;t.push({key:"publish",bullet:`${n} article${ye(n)} changed locally \u2014 ready to publish`,lead:{kind:"cmd",cmd:"/publish",reason:`it pushes your ${n} local edit${ye(n)} up to Document360`},picker:null,follow:`Then /publish pushes your ${n} local edit${ye(n)} up.`})}if(e.hasDocs&&e.roadmap?.next){let n=e.roadmap,o=n.next;t.push({key:"roadmap",bullet:`docs campaign: ${n.done} of ${n.total} step${ye(n.total)} done \u2014 next: ${o.title}`,lead:o.run?{kind:"cmd",cmd:o.run,reason:"it\u2019s the next step of your docs campaign"}:{kind:"prompt",text:o.title,reason:"it\u2019s the next step of your docs campaign"},picker:null,follow:`Then the campaign continues: ${o.title} (/roadmap shows all ${n.total} steps).`})}if(e.behind>0){let n=e.behind;t.push({key:"audit",bullet:`${n} code change${ye(n)} since your last docs check`,lead:{kind:"cmd",cmd:"/audit",reason:"it shows what the latest code changes touch (or /audit --auto on to run it for you)"},picker:null,follow:`After that, /audit covers the ${n} newer commit${ye(n)}.`})}return t}function hc(e){return e.find(t=>t.lead||t.picker)??null}function Zi(e,t){let n=t.filter(l=>l.bullet).map(l=>` \u2022 ${l.bullet}`),o=hc(t),r=[];o?.lead?r.push(es(o.lead)):o?.picker&&r.push("Pick the genre below \u2014 one keypress, and it shapes everything I write.");for(let l of t.filter(p=>p!==o).slice(0,2))l.follow&&r.push(l.follow);let i=[[e,...n].join(`
304
+ `)];return r.length&&i.push(r.join(" ")),i.push(Zh),i.join(`
305
+
304
306
  `)}function Dn(e){if(!e.ready)return{kind:"idle"};let t=nm(e);if(!e.hasDocs){let i=hc(t);return i&&(i.lead?.kind==="cmd"||i.picker)?{kind:"recommend",rec:{note:Zi("\u{1F4ED} No docs yet for this repo \u2014 here\u2019s where things stand:",t),tone:i.tone??"info",lead:i.lead,picker:i.picker}}:{kind:"recommend",rec:{note:em,tone:"info",lead:{kind:"prompt",text:"write the docs for this repo",reason:"I\u2019ll read the code and draft a structure"},picker:null}}}if(t.length===0){let i=e.roadmap&&!e.roadmap.next?` Docs campaign complete \u2014 all ${e.roadmap.total} step${ye(e.roadmap.total)} done (/roadmap).`:"";return{kind:"recommend",rec:{note:`Welcome back. Your ${e.tracked} tracked article${ye(e.tracked)} for \u201C${e.profileName}\u201D are all in sync \u2014 /audit re-checks the code, /pull brings down portal edits.${i}`,tone:"info",lead:null,picker:null}}}let n=t.filter(i=>i.lead||i.picker),o=n[0]??null;return o?(o.key==="audit"||o.key==="roadmap"&&n[1]?.key==="audit")&&e.behind>0&&e.autoAudit&&e.allowAutoAudit?{kind:"autoAudit",note:`\u{1F4CB} ${e.behind} code change${ye(e.behind)} since your last docs check \u2014 running /audit automatically (auto-audit is on)\u2026`}:{kind:"recommend",rec:{note:Zi("Welcome back \u2014 where your docs stand:",t),tone:o.tone??"info",lead:o.lead,picker:o.picker}}:{kind:"recommend",rec:{note:Zi("Welcome back \u2014 where your docs stand:",t),tone:"info",lead:null,picker:null}}}import{existsSync as ts,readdirSync as os}from"node:fs";import{spawnSync as om}from"node:child_process";import{join as Fo}from"node:path";import{readProjectConfig as gc,resolveActiveProfile as wc,loadTokens as rm,isExpired as im,loadProfileMap as yc,countLocalAhead as sm,readDocsPlan as am,devHintsGuidePath as lm,DEFAULT_DOCS_DIR as ns,roadmapProgress as cm,listRoadmap as dm,readProductBriefState as um}from"document360-engine";Qe();function mc(e){try{return os(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&!t.name.startsWith(".")).length>6}catch{return!1}}function rs(e,t){let n=t??[];return n.length===0?["src","api","services","packages","modules"].some(o=>mc(Fo(e,o))):n.some(o=>!o.includes("/")&&!o.endsWith(".md")&&mc(Fo(e,o)))}function is(e,t){try{let n=gc(e);if(!n)return!1;let o=wc(e,t),r=yc(e,o.name);if(r&&Object.keys(r.articles).length>0)return!0;let i=Fo(e,(n.docsDir??ns).replace(/\/+$/,""));return!!(ts(i)&&os(i).length>0||ts(lm(e)))}catch{return!1}}function jn(e,t,n){try{let o=gc(e);if(!o)return null;let r=wc(e,t),i=rm(r.name),l=!!i&&(!im(i)||!!i.refreshToken),p=is(e,t)||!rs(e,o.authoritativeSourceFiles),m=yc(e,r.name),k=m?Object.keys(m.articles).length:0,g=Fo(e,(o.docsDir??ns).replace(/\/+$/,"")),T=!1;try{T=ts(g)&&os(g).length>0}catch{}let v=0;if(m?.lastAnalyzedCommit)try{let te=om("git",["rev-list","--count",`${m.lastAnalyzedCommit}..HEAD`],{cwd:e,encoding:"utf8",timeout:1200});te.status===0&&(v=parseInt((te.stdout||"").trim(),10)||0)}catch{}let _=0;try{let te=am(e);if(te.length>0){let Pe=(o.docsDir??ns).replace(/\/+$/,"");_=fi(e,Pe,te.map(ot=>ot.path)).length}}catch{}let P=Pn(e),N=Tn({...P,directives:0}),D=sm(e,t),M=je(e),B=cm(e),ee=um(e),X=ee?{status:ee.status,openQuestions:ee.openQuestions}:null;return!X&&T&&dm(e).some(Pe=>Pe.status==="open"&&(Pe.run??"").trim()==="/discover")&&(X={status:"pending",openQuestions:0}),{ready:l&&p&&!n.claudeMissing,hasDocs:T,tracked:k,pendingText:N,directives:P.directives,behind:v,pendingWrites:_,localAhead:D,autoAudit:!!o.autoAudit,profileName:r.name,allowAutoAudit:n.allowAutoAudit,devhints:M.status,devhintsCompletedVersion:M.completedVersion,devhintsToVersion:ce,builderStarted:He(e),genreUnknown:n.genreUnknown,roadmap:B,discovery:X}}catch{return null}}function kc(e,t){let n=[],o="";for(let r of e.split(/\s+/).filter(Boolean))for(o.length?o.length+1+r.length<=t?o+=` ${r}`:(n.push(o),o=r):o=r;o.length>t;)n.push(o.slice(0,t)),o=o.slice(t);return o&&n.push(o),n}function Ho(e){if(e.length===0)return[];let t=(i,l)=>`${i}${"\u2500".repeat(78)}${l}`,n=(i="")=>`\u2502 ${i.padEnd(76)} \u2502`,o=[`\u2B06 d360-writer upgraded \u2014 ${e.length===1?"one improvement affects":`${e.length} improvements affect`} the docs you've already written:`,"",t("\u250C","\u2510")];e.forEach((i,l)=>{l>0&&o.push(t("\u251C","\u2524")),o.push(n());for(let p of kc(`${l+1}. ${i.feature}`,76))o.push(n(p));o.push(n());for(let p of kc(i.why,73))o.push(n(` ${p}`));o.push(n())}),o.push(t("\u2514","\u2518")),o.push("");let r=e.length>1;return o.push(`\u2713 ${r?"These are":"This is"} now on your docs roadmap \u2014 each launch shows your next step below (/roadmap shows the full campaign).`),o}W();var pm={Bash:"command",PowerShell:"command",Read:"file_path",Write:"file_path",Edit:"file_path",NotebookEdit:"notebook_path",Glob:"pattern",Grep:"pattern",WebFetch:"url",WebSearch:"query",Agent:"description",Task:"description",Skill:"skill"},vc=160,as=200,$c=40;function xe(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,t-1)+"\u2026"}function bc(e){let t=Object.entries(e).filter(([,o])=>o!=null&&o!=="");if(t.length===0)return null;let n=t.slice(0,4).map(([o,r])=>`${o}: ${xe(typeof r=="string"?r:JSON.stringify(r),$c)}`);return t.length>4&&n.push("\u2026"),xe(n.join(", "),vc)}var tt=e=>typeof e=="string"&&e?e:null,ss=e=>typeof e=="string"&&e.length>=8?e.slice(0,8):null;function fm(e){let t=tt(e)?.replace(/\\/g,"/");if(!t)return null;let n=t.split("/").filter(Boolean);if(n.length<2)return null;let o=n[n.length-2],r=o.replace(/^\d+[-_.]/,"").split(/[-_]/).filter(Boolean);return r.length===0?o:r.map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" ")}function hm(e,t){let n=(o,r)=>({title:`Document360: ${o}`,sep:" ",arg:r});switch(e){case"d360_create_article":{let o=tt(t.title);if(!o)return null;let r=fm(t.local_path);return n("Create article",`"${xe(o,60)}"${r?` in ${r}`:""}`)}case"d360_update_article":{let o=tt(t.title),r=ss(t.article_id);return n("Update article",o?`"${xe(o,60)}"`:r?`id ${r}\u2026`:null)}case"d360_fork_article":return n("Fork article (new draft)",ss(t.article_id)?`id ${ss(t.article_id)}\u2026`:null);case"d360_publish_article":{let o=t.version_number;return n("Publish article LIVE",typeof o=="number"?`v${o}`:null)}case"d360_unpublish_article":return n("Unpublish article",null);case"d360_create_category":return n("Create category",tt(t.name)?`"${xe(tt(t.name),60)}"`:null);case"d360_upload_drive_file":{let o=tt(t.file_path);return n("Upload image",o?xe(o.replace(/\\/g,"/").split("/").pop()??o,60):null)}case"d360_sync_status":return n("Check sync status",null);default:return null}}function qo(e,t){if(e==="ToolSearch")return null;if(e.startsWith("mcp__")){let[,r="",...i]=e.split("__"),l=i.join("__");if(r==="document360"){let k=hm(l,t);if(k)return k}let p=l.replace(/^d360_/,"").replace(/_/g," ");return{title:`${r==="document360"?"Document360":r.charAt(0).toUpperCase()+r.slice(1)}: ${p}`,sep:" ",arg:bc(t)}}let n=pm[e],o=n?t[n]:void 0;return typeof o=="string"&&o?{title:e,sep:"",arg:xe(o,vc)}:{title:e,sep:"",arg:bc(t)}}function mm(e){if(e===null||typeof e!="object")return typeof e=="string"?e:null;let t=e;for(let n of["name","title","slug","id"])if(typeof t[n]=="string"&&t[n])return t[n];return null}function gm(e){if(!/^[[{]/.test(e))return null;let t;try{t=JSON.parse(e)}catch{return null}if(Array.isArray(t)){let n=t.map(mm).filter(r=>r!==null),o=`${t.length} item${t.length===1?"":"s"}`;return n.length===0?[o]:[o,...n.map(r=>xe(r,as))]}if(t!==null&&typeof t=="object"){let n=Object.entries(t).filter(([,o])=>o!==null&&(typeof o=="string"||typeof o=="number"||typeof o=="boolean")).slice(0,6).map(([o,r])=>`${o}: ${xe(String(r),$c)}`);return n.length>0?[xe(n.join(" \xB7 "),as)]:null}return null}function wm(e){let t=tt(e)?.replace(/\\/g,"/");if(!t)return null;let n=t.split("/").filter(Boolean);return n.length>1?n.slice(1).join("/"):t}function ym(e,t,n){switch(e){case"d360_create_article":{let o=wm(t?.local_path);return[`\u2713 draft created${o?` \xB7 ${o}`:""}`]}case"d360_update_article":return["\u2713 draft updated"];case"d360_fork_article":return["\u2713 forked to a new draft"];case"d360_publish_article":return["\u2713 PUBLISHED LIVE \u2014 visible to readers"];case"d360_unpublish_article":return["\u2713 reverted to draft (removed from readers)"];case"d360_create_category":{let o=tt(t?.name);return[`\u2713 category created${o?` \xB7 "${o}"`:""}`]}case"d360_upload_drive_file":{let o=n.match(/https?:\/\/\S+/);return[`\u2713 uploaded${o?` \xB7 ${xe(o[0],120)}`:""}`]}default:return null}}function Bo(e,t=4,n,o){let r=e.replace(/\r\n/g,`
305
307
  `).trimEnd();if(!r)return{lines:["(no output)"],hidden:0};if(n?.startsWith("mcp__document360__")){let l=ym(n.slice(18),o,r);if(l)return{lines:l,hidden:0}}let i=gm(r)??r.split(`
306
308
  `);return{lines:i.slice(0,t).map(l=>xe(l,as)),hidden:Math.max(0,i.length-t)}}function Vo(e,t,n,o="en"){return`${e.replace(/\/$/,"")}/${t}/document/v1/${o}/${n}`}function Go(e,t){if(typeof e.article_id=="string"&&e.article_id)return e.article_id;try{let n=JSON.parse(t),r=(Array.isArray(n)?n[0]:n)?.id;return typeof r=="string"&&r?r:null}catch{return null}}function Yo(e){try{let t=JSON.parse(e),o=(Array.isArray(t)?t[0]:t)?.url;return typeof o=="string"&&/^https?:\/\//.test(o)?o:null}catch{return null}}var Mm=/^mcp__document360__d360_(create_article|update_article|fork_article|publish_article)$/;function Um(e,t,n,o){if(Mm.test(e))try{let r=Rc(o),i=typeof t.project_id=="string"&&t.project_id||r.project.projectId,l=Go(t,n),p=Yo(n);e.endsWith("publish_article")&&p&&console.log(O(` \u2B95 Live: ${p}`)),l&&i&&console.log(O(` \u2B95 Preview: ${Vo(r.connection.portalUrl,i,l,r.project.languageCode??"en")}`))}catch{}}async function Pc(e=process.cwd(),t="auto",n,o){let r=bm(t);r.kind==="none"&&(console.error(""),console.error(C("ANTHROPIC_API_KEY is not set (required for --auth api).")),console.error(""),console.error(` ${O("export ANTHROPIC_API_KEY=sk-ant-...")} (macOS / Linux)`),console.error(` ${O('$env:ANTHROPIC_API_KEY="sk-ant-..."')} (PowerShell)`),console.error(""),console.error(`Get a key at ${O("https://console.anthropic.com/settings/keys")}`),console.error(`Or use your Claude subscription instead: ${O("d360-writer --auth subscription")}`),console.error(""),process.exit(2)),Wm(e,n),r.kind==="subscription"&&(r.stored?console.log(f(" Using your Claude subscription (no API key set).")):console.log(f(" No API key or stored Claude Code login found \u2014 trying your Claude session anyway.")),console.log(""));let i=!1,l=ls({cwd:e,profileName:n,allowProdWrites:i}),p={uuid:null,firstPrompt:null,titleFired:!1},m=km({input:process.stdin,output:process.stdout}),k=[],g=null,T=!1;m.on("line",P=>{if(g){let N=g;g=null,N(P)}else k.push(P)}),m.on("close",()=>{if(T=!0,g){let P=g;g=null,P(null)}});function v(){return k.length>0?Promise.resolve(k.shift()):T?Promise.resolve(null):(process.stdout.write(O("> ")),new Promise(P=>{g=P}))}let _={cwd:e,version:o,profileName:n,allowProdWrites:()=>i,restartAgent:()=>{l.close(),l=ls({cwd:e,profileName:n,allowProdWrites:i}),p={uuid:null,firstPrompt:null,titleFired:!1}},currentUuid:()=>p.uuid,setPendingName:P=>{p.pendingName=P},setModel:async P=>l.setModel(P),withPausedInput:async P=>{m.pause();try{return await P()}finally{m.resume()}}};try{for(;;){let P=await v();if(P===null)break;let N=P.trim();if(N){if(N.startsWith("/")){let D=fc(N);if(!D)continue;let M=pc[D.name];if(!M){console.log(C(`Unknown command: /${D.name}`)),console.log(f("Type /help for the list."));continue}let B=await M(D.args,_);if(B.kind==="exit")break;if(B.kind==="clear"){_.restartAgent();continue}if(B.kind==="allow-prod"){i=!0,_.restartAgent(),console.log(j("\u2713 Production writes authorized for this session.")),console.log("");continue}if(B.kind==="resume"){l.close(),l=ls({cwd:e,resume:B.uuid,profileName:n,allowProdWrites:i});let ee=vm(B.uuid);p={uuid:B.uuid,firstPrompt:ee?.firstPrompt??null,titleFired:!0},Cc(B.uuid),console.log(j(`\u2713 Resumed "${B.name}"`)),console.log("");continue}if(B.kind==="forward-to-agent"){p.firstPrompt||(p.firstPrompt=B.display??B.prompt);let ee=(B.display??"").trim().split(/\s+/),X=(ee[0]==="/check"||ee[0]==="/review")&&ee.includes("--fix"),te=ee.slice(1).find(ot=>!ot.startsWith("--")),Pe=X?Om(e,te):[];if(await cs(l,B.prompt,r,p,e),X)try{_m(e,Pe,{reviewedCap:Lm})}catch{}}else Fm(e,n);continue}if(Am(N)){let D=Em(N);if(D){try{Nm(e,{title:D,by:"owner (d360-writer terminal)",at:new Date().toISOString()})}catch{}p.firstPrompt||(p.firstPrompt=N),await cs(l,`The owner left this documentation directive (already recorded in .d360-writer/directives.md): "${D}". Action it now: ground it in the sources, write/update the article(s) as DRAFTS (do not publish unless asked), following the active doc-type playbook. When finished, call d360_directive_done with the exact title "${D}" and the article path(s) you wrote.`,r,p,e);continue}}p.firstPrompt||(p.firstPrompt=N),await cs(l,N,r,p,e)}}}finally{l.close(),m.close()}}function Wm(e,t){console.log(""),console.log(hn("document360-writer")),console.log(f(` cwd: ${e}`));let n=Pm(e);if(console.log(f(` model: ${n.model}${n.source==="auto"?" (auto \u2014 right-sized for docs; /model to change)":` (${n.source})`}`)),console.log(Hm(e,t)),!Tm(e))console.log(L(" First run: /init (scaffolds config + prints the builder hand-off prompt) \u2192 /login, then ask me to write the docs."));else{let o=!1;try{if(ho(e),!He(e))for(let r of mo(e))console.log(L(` ${r}`))}catch{}try{let r=Sm(e);r.persisted&&r.appType?console.log(f(` \u2713 Detected a ${r.appType} app \u2014 enabled the ${r.appType}-doc-playbook (change with /genre).`)):r.source==="unknown"&&(o=!0)}catch{}try{let r=Im(e);for(let i of Ho(r.applied))console.log(L(` ${i}`))}catch{}try{let r=jn(e,t,{claudeMissing:!1,allowAutoAudit:!1,genreUnknown:o}),i=r?Dn(r):null;if(i?.kind==="recommend"&&i.rec.note){let l=i.rec.tone==="warn"?L:f;for(let p of i.rec.note.split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document360-writer",
3
- "version": "0.5.95",
3
+ "version": "0.5.96",
4
4
  "description": "Standalone documentation agent CLI. Reads your code, writes your docs. Specialized for Document360 publishing.",
5
5
  "type": "module",
6
6
  "bin": {