document360-writer 0.5.84 → 0.5.85

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 -3
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -214,7 +214,7 @@ Anything only a human knows that would help document this product. For example:
214
214
  `)}),n.notifiedBuilder=!0))}catch{}return n}function ao(e){if(!Ot(io(e)))return[];let t=Se(e);return t.status==="current"?[]:[`\u{1F514} Your builder agent ${t.completedVersion?`is on v${t.completedVersion}`:"hasn't completed the hand-off yet"} \u2014 d360-writer's dev\u2194docs protocol is now v${se}.`,"Please run this prompt in your repository's coding agent (Claude Code / Codex / Cursor) for:",` ${e}`,Lt,dt(),Lt,"(Also saved in .d360-writer/messages/ \u2014 or run /devhints to re-show. This stops once your builder runs it.)"]}function vr(){return['document360-writer (its "docs agent") has been removed from this repository. Please undo its dev\u2192docs',"hand-off setup and restore this repo to how it was before \u2014 in order:","","1. In this repo's agent-memory file (CLAUDE.md, or AGENTS.md \u2014 whichever it edited), REMOVE the",' "Documentation hand-off" section that was added (the rule about dropping hint files in'," `.d360-writer/hints/`, keeping `.d360-writer/architecture/` current, checking"," `.d360-writer/messages/`, and relaying `@d360-writer` directives to `.d360-writer/directives.md`)."," Leave everything else in that file untouched.","2. The `.d360-writer/` folder is already deleted on disk. If it was committed, remove it from version"," control too \u2014 `git rm -r --cached .d360-writer` (if it still resolves) \u2014 and commit the deletions.","3. Do NOT recreate any of those files or follow the hand-off protocol anymore.","","That's it \u2014 this repo is back to its pre-docs-agent state."].join(`
215
215
  `)}function lo(){return['\u{1F9F9} One leftover: your builder still has the "Documentation hand-off" rule in its CLAUDE.md / AGENTS.md'," (reset only clears d360-writer's own .d360-writer/ folder \u2014 never your repo's files)."," To restore it, paste this prompt into your repo's coding agent (Claude Code / Codex / Cursor):",Lt,vr(),Lt]}function Ut(e){return[...e?.status==="stale"?[`\u26A0 Your builder last completed devhints v${e.completedVersion}; this hand-off is v${se}.`," Have them run the prompt below again \u2014 it now sets up two-way messages + on-demand docs.",""]:[],"\u2713 Wrote .d360-writer/DEV-HINTS-GUIDE.md + the .d360-writer/architecture/ (brief), .d360-writer/hints/, and .d360-writer/messages/ inboxes.","","\u{1F4CB} Copy this one prompt and run it in your repo's coding agent (Claude Code / Codex / Cursor):",Lt,dt(),Lt,"","That one run writes the architecture brief, adds the ongoing rule to your agent memory (CLAUDE.md / AGENTS.md)","and commits it so teammates inherit it, answers any open questions the writer left, and asks you for tribal","knowledge \u2014 no manual file edits. It also sets up the two-way channel: the writer can ask you questions","(`/inbox` on its side), and you can ask it to document a session on demand (Part 4 of the guide).","","When it finishes, come back to THIS terminal and run:"," write the docs for this repo"]}var Lt,se,aa,Ke=zn(()=>{"use strict";Lt="-".repeat(64),se=7;aa="Re-run dev\u2194docs onboarding (protocol v"});var $a={};Ms($a,{initCommand:()=>Rr,scaffoldInit:()=>Cr});import{input as an,confirm as md}from"@inquirer/prompts";import{basename as fa,join as co}from"node:path";import{existsSync as Wt,readFileSync as hd,readdirSync as gd,writeFileSync as yd}from"node:fs";import{writeProjectConfig as ma,readProjectConfig as wd,projectConfigPath as ha,writerDir as kd,DEFAULT_DOCS_DIR as ga,DEFAULT_CAPTURE_DIR as ya,DEFAULT_OUTPUT_DIR as wa}from"document360-engine";function Cr(e,t="berlin"){let n=ha(e);if(Wt(n))return{created:!1,path:n,profileName:""};let o={projectId:ba(e)??fa(e),docsDir:ga,captureDir:ya,outputDir:wa,profiles:{[t]:{connection:{environment:t},production:!1}},defaultProfile:t,authoritativeSourceFiles:xa(e)};return ma(o,e),ka(e),{created:!0,path:n,profileName:t}}function ka(e){let t=co(kd(e),".gitignore");Wt(t)||yd(t,["# Local/transient \u2014 the config files here ARE meant to be committed.",".sessions/","cache/",""].join(`
216
216
  `),"utf8")}async function Rr(){let e=process.cwd(),t=ha(e);if(Wt(t)&&!await md({message:`${t} already exists. Overwrite?`,default:!1}))return console.log(f("init cancelled.")),{kind:"continue"};let n=ba(e)??fa(e),o=await an({message:"Project ID (used to scope sessions, screenshots, etc.):",default:n}),r=await an({message:"Capture directory (where document360-capture .spec.ts files live):",default:ya}),i=await an({message:"Screenshot output directory:",default:wa}),c=await an({message:"Default connection profile name:",default:"berlin"}),p=await an({message:"Document360 environment for this profile (baked preset):",default:"berlin"}),g={projectId:o,docsDir:ga,captureDir:r,outputDir:i,profiles:{[c]:{connection:{environment:p},production:!1}},defaultProfile:c,authoritativeSourceFiles:xa(e)},w=wd(e);w?.terminologyGlossary&&(g.terminologyGlossary=w.terminologyGlossary),ma(g,e),ka(e);let k=Mt(e);console.log(""),console.log(N(`\u2713 Wrote ${t}`)),console.log(""),console.log(`Next: ${_(`d360-writer login --profile ${c}`)} ${f("(sign in; project & workspace auto-selected)")}`),console.log("");for(let D of Ut(k))console.log(D);return console.log(""),console.log(`${f("Then ask:")} ${_('"write the user docs for this repo"')}`),console.log(""),{kind:"continue"}}function ba(e){let t=co(e,"package.json");if(!Wt(t))return null;try{return JSON.parse(hd(t,"utf8")).name??null}catch{return null}}function xa(e){let t=[];for(let n of["README.md","ARCHITECTURE.md","CLAUDE.md"])Wt(co(e,n))&&t.push(n);for(let n of["src","api","docs"]){let o=co(e,n);Wt(o)&&!bd(o)&&t.push(n)}return t}function bd(e){try{return gd(e,{withFileTypes:!0}).filter(n=>n.isDirectory()&&!n.name.startsWith(".")).length>6}catch{return!1}}var uo=zn(()=>{"use strict";U();Ke()});var bl={};Ms(bl,{doctorCommand:()=>mn,renderDoctorChecks:()=>kl,runDoctorChecks:()=>wl});import{existsSync as sf}from"node:fs";import{d360GetAll as af,getAccessToken as lf,isExpired as wi,loadProfileMap as cf,loadTokens as uf,packageSkillsDir as gl,projectConfigPath as df,readProjectConfig as pf,DEFAULT_DOCS_DIR as ff,fetchManifestSummary as mf,resolveActiveProfile as hf,classifyClaudeAuth as gf,CLAUDE_CODE_SETUP_HINT as yl,resolveModelSetting as yf,probeModel as wf,detectAppType as kf,playbookSkillName as bf,D360AuthError as xf}from"document360-engine";async function wl(e){let t=[],n=Number(process.versions.node.split(".")[0]);t.push(n>=20?{level:"ok",label:`Node ${process.versions.node}`}:{level:"fail",label:`Node ${process.versions.node} \u2014 20+ required`,fix:"Install Node 20 or later (nodejs.org)"});let o=gf();o.state==="ready"?t.push({level:"ok",label:`Claude auth: ${o.kind==="api"?"API key":"subscription (Claude Code login found)"}`}):o.state==="maybe"?t.push({level:"warn",label:"Claude: no Claude Code login found (may be in the macOS Keychain)",fix:`If a docs turn ends with no output, sign in to Claude Code. ${yl}`}):t.push({level:"fail",label:"Claude: not signed in \u2014 the agent cannot run (no Claude Code credentials on this machine)",fix:yl});let r=yf(e);if(t.push({level:"ok",label:`Model: ${r.model} (${r.source==="auto"?"auto \u2014 right-sized for docs; /model to change":r.source})`}),o.state==="ready"){let P=await wf(e,r.model??void 0);P.ok?t.push({level:"ok",label:`Model reachable \u2014 replied in ${(P.latencyMs/1e3).toFixed(1)}s`}):P.timedOut?t.push({level:"fail",label:"Model unreachable \u2014 no response in 30s (a docs turn will hang, then end with 0 tokens / no output)",fix:`Usually a corporate proxy/firewall or org policy blocking the Claude model API. Check this machine's network access to the Claude endpoint; confirm with: claude -p "say hi"`}):t.push({level:"fail",label:`Model call failed \u2014 ${P.error??"no output"} (a docs turn will end with 0 tokens / no output)`,fix:'Check sign-in, the selected model (/model), and network access to the Claude endpoint; confirm with: claude -p "say hi"'})}let i=pf(e);if(!i)return t.push({level:"fail",label:`No ${df(e)}`,fix:"Run: /init (or d360-writer init)"}),t;t.push({level:"ok",label:`Project config: ${i.projectId}`});let c=(i.docsDir??ff).replace(/\/+$/,"");t.push(i.mode==="engineer"?{level:"warn",label:"Mode: engineer \u2014 agent may modify any source file (dogfooding)",fix:'Remove "mode" from .d360-writer/config.json for the writer-mode boundary'}:{level:"ok",label:`Mode: writer \u2014 edits limited to ${c}/ and .d360-writer/ (docs, capture specs, config); product source is read-only`});let p=i.authoritativeSourceFiles??[];t.push(p.length>0?{level:"ok",label:`Sources: docs grounded in ${p.length} path(s) (${p.slice(0,3).join(", ")}${p.length>3?", \u2026":""})`}:{level:"warn",label:"Sources: not set \u2014 docs are grounded in the whole repo",fix:"Run: /scope to choose which files/folders the docs are written from"});let g=i.appType??kf(e);if(g){let P=i.appType?"from config":"auto-detected",R=g==="web"||g==="cli";t.push({level:"ok",label:`Genre: ${g} (${P})${R?` \u2192 ${bf(g)} loaded`:" \u2014 no doc-type playbook for this genre yet (generic skills)"}`})}else t.push({level:"warn",label:"Genre: unclassified \u2014 no doc-type playbook is loading (generic output)",fix:"Run /genre <web|cli|service|library> to pick \u2014 raises docs to that genre's craft bar"});let w;try{w=hf(e),t.push({level:"ok",label:`Profile: ${w.name} (${w.connection.name})${w.production?" \u26A0 PRODUCTION":""}`})}catch(P){return t.push({level:"fail",label:`Profile config: ${P.message.split(".")[0]}`,fix:"Run: /init to scaffold the profiles map"}),t}let k=uf(w.name);k?wi(k)&&!k.refreshToken?t.push({level:"fail",label:"Document360: session expired (no refresh token)",fix:"/login"}):wi(k)?t.push({level:"warn",label:"Document360: token expired \u2014 will auto-refresh on next call"}):t.push({level:"ok",label:`Document360: logged in (until ${new Date(k.expiresAt).toLocaleString()})`}):t.push({level:"fail",label:"Document360: not logged in",fix:`Run: /login (or d360-writer login --profile ${w.name})`}),t.push(w.project.workspaceId?{level:"ok",label:`Workspace: ${w.project.workspaceName??w.project.workspaceId}`}:{level:"warn",label:"No workspace selected",fix:"Run: /workspace"});let D=cf(e,w.name);D?D.projectId&&w.project.projectId&&D.projectId!==w.project.projectId?t.push({level:"fail",label:`Category map projectId (${D.projectId}) \u2260 profile projectId (${w.project.projectId})`,fix:"The map section belongs to a different project \u2014 fix .d360-writer/config.json or the map before publishing"}):t.push({level:"ok",label:`Category map: ${Object.keys(D.articles).length} articles, ${Object.keys(D.categories).length} categories`}):t.push({level:"ok",label:`Category map: none yet for "${w.name}" (created on first /publish)`}),t.push(sf(gl())?{level:"ok",label:"Skills bundle present"}:{level:"fail",label:`Skills folder missing at ${gl()}`,fix:"Reinstall document360-writer (broken install)"});let x=Se(e);if(x.status==="current"?t.push({level:"ok",label:`Dev hand-off: builder up to date (devhints v${se})`}):x.status==="stale"&&t.push({level:"warn",label:`Dev hand-off: builder on devhints v${x.completedVersion}, current is v${se}`,fix:"Run /devhints and have the repo's coding agent re-run the prompt (adds two-way messages + on-demand docs)"}),k&&(!wi(k)||k.refreshToken)){let P={profile:w.name,connection:w.connection};try{await lf(P);let S=await af(P,"/v3/projects");t.push({level:"ok",label:`API reachable (${w.connection.apiUrl}) \u2014 ${S.length} project(s) visible`})}catch(S){t.push({level:"fail",label:`API call failed: ${S.message.slice(0,120)}`,fix:"/login if auth-related; otherwise check the apiUrl/network"})}let R=D?.projectId??w.project.projectId;if(R&&w.project.workspaceId)try{let S=await mf(P,R,w.project.workspaceId);if(S){let I=(S.workspace_hash??"").replace(/^sha256:/,"").slice(0,12);t.push({level:"ok",label:`Workspace sync manifest: available on ${w.connection.name} (${S.languages?.length??0} language${(S.languages?.length??0)===1?"":"s"}) \xB7 hash ${I||"(none)"}`})}else t.push({level:"warn",label:`Workspace sync manifest: not live on ${w.connection.name} yet`,fix:"No action needed \u2014 sync uses the per-article path until the manifest ships on this environment"})}catch(S){S instanceof xf||/scoped to a (?:specific|different) project|cannot access the requested project/i.test(S.message)?t.push({level:"fail",label:`Project scope: your Document360 session is signed into a different project than this repo expects (${w.project.projectName??R})`,fix:"Run /login and pick this repo's project \u2014 your token is scoped to another project"}):t.push({level:"warn",label:`Workspace sync manifest: probe failed (${S.message.slice(0,80)})`})}}return t}function kl(e){let t=[""];for(let r of e){let i=r.level==="ok"?N("\u2713"):r.level==="warn"?O("\u26A0"):$("\u2717");t.push(` ${i} ${r.label}${r.detail?f(` \u2014 ${r.detail}`):""}`),r.fix&&t.push(` ${f("fix:")} ${_(r.fix)}`)}let n=e.filter(r=>r.level==="fail").length,o=e.filter(r=>r.level==="warn").length;return t.push(""),t.push(n===0?N(`\u2713 ${o===0?"All checks passed":`Healthy (${o} warning${o===1?"":"s"})`}`):$(`\u2717 ${n} problem${n===1?"":"s"} found`)),t.push(""),t}async function mn(e,t){console.log(f("Running checks\u2026"));for(let n of kl(await wl(t.cwd)))console.log(n);return{kind:"continue"}}var $o=zn(()=>{"use strict";Ke();U()});import{Command as Wg}from"commander";import{createRequire as Fg}from"node:module";import{AUTH_MODES as Hg}from"document360-engine";import{input as Ou}from"@inquirer/prompts";import{loginPkce as Lu,refreshTokens as Mu,toStoredTokens as Vs,clearTokens as Uu,decodeJwtClaims as Bs,isExpired as Wu,loadTokens as Fu,saveTokens as Gs,resolveActiveProfile as Jn,setProfileProject as Hu,readProjectConfig as qu}from"document360-engine";U();import{select as vu}from"@inquirer/prompts";import{resolveActiveProfile as Cu,setProfileProject as Ru,resolveProjectId as Pu,listWorkspaces as Tu}from"document360-engine";async function rn(e,t){let n=Cu(e,t),o={profile:n.name,connection:n.connection},r=n.project.projectId??Pu(o);return{workspaces:await Tu(o,r),projectId:r,projectName:n.project.projectName,profile:n.name,environment:n.connection.name,current:n.project.workspaceId}}var Ws=e=>`${e.name??e.id}${e.workspace_type?` \xB7 ${e.workspace_type}`:""}`;function gr(e,t){let n=t.toLowerCase();return e.find(o=>(o.name??"").toLowerCase()===n)??e.find(o=>(o.name??"").toLowerCase().startsWith(n))??e.find(o=>o.id.startsWith(t))}function Kn(e,t,n,o,r){Ru(e,t,{projectId:n,workspaceId:o,workspaceName:r})}async function Fs(e,t,n){let o;try{o=await rn(e,n)}catch(i){return console.log($(`Could not list workspaces: ${i.message}`)),1}let r=gr(o.workspaces,t);return r?(Kn(e,o.profile,o.projectId,r.id,r.name),console.log(N(`\u2713 Workspace set to "${r.name??r.id}" for profile "${o.profile}".`)),0):(console.log($(`No workspace matches "${t}". Available: ${o.workspaces.map(i=>i.name??i.id).join(", ")}`)),1)}async function _t(e,t){let n;try{n=await rn(e,t)}catch(w){console.log($(`Could not list workspaces: ${w.message}`));return}let{workspaces:o,projectId:r,profile:i,current:c}=n;if(o.length===0){console.log(f("No workspaces found in this project."));return}if(!process.stdin.isTTY){console.log("");for(let w of o)console.log(` ${w.id===c?_("\u25CF"):" "} ${Ws(w)} ${f(w.id)}`);console.log(f("Run: d360-writer workspace use <name>"));return}let p=await vu({message:"Select the Document360 workspace for this repo:",choices:o.map(w=>({name:`${Ws(w)}${w.id===c?" (current)":""}`,value:w.id}))}),g=o.find(w=>w.id===p);Kn(e,i,r,p,g?.name),console.log(N(`\u2713 Workspace set to "${g?.name??p}" for profile "${i}".`))}U();import{select as Su}from"@inquirer/prompts";import{resolveActiveProfile as Du,setProfileProject as Au,listProjects as ju}from"document360-engine";async function ze(e,t){let n=Du(e,t),o={profile:n.name,connection:n.connection};return{projects:await ju(o),profile:n.name,environment:n.connection.name,current:n.project.projectId}}var Hs=e=>`${e.name??e.id}${e.sub_domain?` \xB7 ${e.sub_domain}`:""}`;function yr(e,t){let n=t.toLowerCase();return e.find(o=>(o.name??"").toLowerCase()===n)??e.find(o=>(o.name??"").toLowerCase().startsWith(n))??e.find(o=>o.id.startsWith(t))}function Xn(e,t,n,o){Au(e,t,{projectId:n,projectName:o,workspaceId:void 0,workspaceName:void 0})}async function qs(e,t,n){let o;try{o=await ze(e,n)}catch(i){return console.log($(`Could not list projects: ${i.message}`)),1}let r=yr(o.projects,t);return r?(Xn(e,o.profile,r.id,r.name),console.log(N(`\u2713 Project set to "${r.name??r.id}" for profile "${o.profile}". Next: pick a workspace (d360-writer workspace).`)),0):(console.log($(`No project matches "${t}". Available: ${o.projects.map(i=>i.name??i.id).join(", ")}`)),1)}async function Qn(e,t){let n;try{n=await ze(e,t)}catch(g){console.log($(`Could not list projects: ${g.message}`));return}let{projects:o,profile:r,current:i}=n;if(o.length===0){console.log(f("No projects found for this identity."));return}if(!process.stdin.isTTY){console.log("");for(let g of o)console.log(` ${g.id===i?_("\u25CF"):" "} ${Hs(g)} ${f(g.id)}`);console.log(f("Run: d360-writer project use <name>"));return}let c=await Su({message:"Select the Document360 project for this repo:",choices:o.map(g=>({name:`${Hs(g)}${g.id===i?" (current)":""}`,value:g.id}))}),p=o.find(g=>g.id===c);Xn(e,r,c,p?.name),console.log(N(`\u2713 Project set to "${p?.name??c}" for profile "${r}". Next: pick a workspace.`))}U();import Eu from"picocolors";function Nu(e=process.env){return e.FORCE_HYPERLINK==="0"||!Eu.isColorSupported?!1:e.FORCE_HYPERLINK?!0:!!(e.WT_SESSION||e.TERM_PROGRAM==="vscode"||e.TERM_PROGRAM==="iTerm.app"||e.TERM_PROGRAM==="WezTerm"||e.TERM_PROGRAM==="ghostty"||e.VTE_VERSION||e.KONSOLE_VERSION)}function Iu(e,t=e,n){return Nu(n)?`\x1B]8;;${e}\x07${t}\x1B]8;;\x07`:t}var _u=/https?:\/\/[^\s\x1b]+/g;function sn(e,t){return e.replace(_u,n=>Iu(n,n,t))}function Ys(e){return{...Bs(e.idToken)??{},...Bs(e.accessToken)??{}}}function Zn(e){let t=Ys(e),n=t.email??t.preferred_username??t.sub??"unknown",o=t.doc360_project_id?` \xB7 project ${t.doc360_project_id}`:"";return`${n}${o}`}async function eo(e){let t=Jn(process.cwd(),e.profile),n=t.connection;console.log(f(`Profile "${t.name}" \u2192 ${n.name} (${n.apiUrl})${t.production?" \u26A0 PRODUCTION":""}`));let o=await Lu(n,{manual:e.manual,promptForRedirect:i=>Ou({message:i})},i=>console.log(sn(i))),r=Vs(t.name,o);if(Gs(r),await wr(r,t.name,i=>console.log(f(i))),console.log(""),console.log(N(`\u2713 Logged in to "${t.name}" as ${Zn(r)}`)),console.log(f(` access token expires: ${r.expiresAt}`)),console.log(f(` refresh token: ${r.refreshToken?"yes":"NO \u2014 session ends at expiry"}`)),process.stdin.isTTY)try{qu(process.cwd())?.profiles?.[t.name]&&(console.log(""),await _t(process.cwd(),t.name))}catch{}}async function wr(e,t,n){let r=Ys(e).doc360_project_id;if(!(typeof r!="string"||!r))try{if(Jn(process.cwd(),t).project.projectId)return;let c;try{let{projects:p}=await ze(process.cwd(),t);c=p.find(g=>g.id===r)?.name}catch{}Hu(process.cwd(),t,{projectId:r,projectName:c}),n(` Project "${c??r}" written to profile "${t}".`)}catch{}}async function zs(e){let t=Jn(process.cwd(),e.profile),n=t.connection,o=Fu(t.name);if(!o){console.log($(`Not logged in to Document360 (profile "${t.name}").`)),console.log(f(`Run: d360-writer login --profile ${t.name}`)),process.exitCode=1;return}if(console.log(`Profile ${_(t.name)}${t.production?" \u26A0 PRODUCTION":""}: ${Zn(o)}`),Wu(o))if(o.refreshToken)try{let r=Vs(t.name,await Mu(n,o.refreshToken));Gs(r),console.log(N(`\u2713 Session refreshed \u2014 expires ${r.expiresAt}`))}catch(r){console.log(O(`Session expired and refresh failed (${r.message.slice(0,120)})`)),console.log(f(`Run: d360-writer login --profile ${t.name}`)),process.exitCode=1}else console.log(O("Session expired (no refresh token).")),console.log(f(`Run: d360-writer login --profile ${t.name}`)),process.exitCode=1;else console.log(f(` expires: ${o.expiresAt}`))}async function Ks(e){let t=Jn(process.cwd(),e.profile);Uu(t.name)?console.log(N(`\u2713 Logged out of Document360 (profile "${t.name}").`)):console.log(f(`No Document360 session for profile "${t.name}" \u2014 nothing to do.`))}U();import{readProjectConfig as Xs,writeProjectConfig as Bu,resolveActiveProfile as Vu,loadTokens as Gu,isExpired as Yu}from"document360-engine";function to(e){let t=Xs(e);if(!t?.profiles||Object.keys(t.profiles).length===0){console.log($("No profiles in .d360-writer/config.json. Run: d360-writer init")),process.exitCode=1;return}console.log("");for(let[n,o]of Object.entries(t.profiles)){let r=n===t.defaultProfile?_("\u25CF "):" ",i=o.production?O(" \u26A0 PRODUCTION"):"",c=o.connection.environment??"(inline)",p=Gu(n),g=p?Yu(p)&&!p.refreshToken?O("expired"):f("logged in"):f("not logged in");console.log(`${r}${_(n)} \u2192 ${c}${i} [${g}]`)}console.log(""),console.log(f("\u25CF = default. Switch with: d360-writer profile use <name>")),console.log("")}function no(e,t){let n=Xs(e);if(!n?.profiles?.[t]){let r=n?.profiles?Object.keys(n.profiles).join(", "):"(none \u2014 run init)";console.log($(`Unknown profile "${t}". Available: ${r}`)),process.exitCode=1;return}n.defaultProfile=t,Bu(n,e);let o=n.profiles[t].production?O(" \u26A0 PRODUCTION"):"";console.log(N(`\u2713 Default profile is now "${t}"${o}`))}function oo(e,t){try{let n=Vu(e,t);console.log(""),console.log(`Profile ${_(n.name)}${n.production?O(" \u26A0 PRODUCTION"):""}`),console.log(f(` api: ${n.connection.apiUrl}`)),console.log(f(` identity: ${n.connection.authorizationUrl}`)),console.log(f(` clientId: ${n.connection.clientId}`)),console.log(f(` scopes: ${n.connection.scopes.join(" ")}`)),console.log(f(` project: ${n.project.projectId??"(set at login)"}`)),console.log(f(` workspace:${n.project.workspaceId?" "+n.project.workspaceId:" (none)"}`)),console.log("")}catch(n){console.log($(n.message)),process.exitCode=1}}U();import{existsSync as zu,readdirSync as Ku,statSync as Qs}from"node:fs";import{join as Js}from"node:path";import{apiLogDir as Xu}from"document360-engine";function Zs(){let e=Xu();if(console.log(""),console.log(`Document360 API logs: ${_(e)}`),!zu(e)){console.log(f(" No logs yet \u2014 they appear after the first Document360 API call.")),console.log("");return}let t=Ku(e),n=t.filter(r=>r.endsWith(".jsonl")).sort().reverse(),o=t.filter(r=>/^crash-\d{4}-\d{2}-\d{2}\.log$/.test(r)).sort().reverse();n.length===0&&o.length===0&&console.log(f(" No logs yet \u2014 they appear after the first Document360 API call."));for(let r of n.slice(0,14)){let i=(Qs(Js(e,r)).size/1024).toFixed(1);console.log(` ${r} ${f(`${i} KB`)}`)}if(o.length>0){console.log(""),console.log(`Crash logs ${f("(send these if d360-writer crashed or a run died)")}:`);for(let r of o.slice(0,14)){let i=(Qs(Js(e,r)).size/1024).toFixed(1);console.log(` ${$(r)} ${f(`${i} KB`)}`)}}console.log(""),console.log(f("Failed calls include request/response bodies (tokens redacted, 4 KB cap).")),console.log(f("Set D360_LOG_BODIES=1 to also log bodies for successful calls.")),console.log("")}U();import{createSession as Qu,resolveAuth as Ju,findByName as Zu,slugify as ed,touchSession as td,upsertSession as nd,resolveActiveProfile as od}from"document360-engine";async function ea(e,t,n,o,r,i){let c=Ju(n);c.kind==="none"&&(console.error(""),console.error($("ANTHROPIC_API_KEY is not set (required for --auth api).")),console.error(`Get a key at ${_("https://console.anthropic.com/settings/keys")}`),console.error(`Or use your Claude subscription instead: ${_("d360-writer --auth subscription")}`),process.exit(2)),c.kind==="subscription"&&console.error(f("Using your Claude subscription (no API key set)."));let p=null;try{p=od(e,r)}catch(x){console.error($(`Document360 profile error: ${x.message}`)),process.exit(2)}p.production&&(console.error(O(`\u26A0 Profile "${p.name}" is PRODUCTION.`)),i||(console.error($("Refusing to run against a production profile without --yes.")),process.exit(2)),console.error(f(" --yes given \u2014 proceeding against production.")));let g;if(o){let x=Zu(e,o);x||(console.error($(`No saved session matches "${o}" in this repo.`)),console.error(f("List sessions inside the REPL with /resume.")),process.exit(2)),g=x.uuid,console.error(f(`Resuming "${x.name}"`))}let w=Qu({cwd:e,resume:g,profileName:r,allowProdWrites:i===!0}),k=g??null,D=1;for await(let x of w.send(t))switch(x.type){case"session":if(!k){k=x.sessionId;let P=new Date().toISOString();nd({uuid:k,name:ed(t),renamed:!1,titled:!1,cwd:e,firstPrompt:t,createdAt:P,updatedAt:P})}break;case"text":process.stdout.write(x.delta);break;case"tool":console.error(ae(` \u2699 ${x.name}`));break;case"result":D=x.ok?0:1,console.error(f(`(${x.inputTokens}\u2192${x.outputTokens} tokens`+(x.costUsd>0?`, $${x.costUsd<.01?x.costUsd.toFixed(4):x.costUsd.toFixed(2)}`:"")+")")),x.ok||console.error($("agent finished with an error result"));break;case"error":console.error(""),console.error($(`agent error: ${x.message}`)),process.exit(1)}k&&td(k),process.stdout.write(`
217
- `),process.exit(D)}import{createInterface as Vm}from"node:readline/promises";import{createSession as Xi,resolveAuth as Gm,getSession as Ym,setTitle as zm,slugify as Km,touchSession as ac,upsertSession as Xm,generateTitle as Qm,resolveActiveProfile as lc,resolveModelSetting as Jm,readProjectConfig as Zm,resolveAndPersistAppType as eh,decodeJwtClaims as sc,isExpired as th,loadTokens as nh,isDirectiveMention as oh,stripDirectiveMention as rh,appendDirective as ih,reconcileUpgradeActions as sh,stampArticles as ah,listArticleFiles as lh,CONTENT_CAP_VERSION as ch}from"document360-engine";var Te=[{key:"start",label:"Getting Started",rows:[{t:"text",s:"D360-Writer reads your codebase, generates end-user documentation, and publishes it to Document360."},{t:"text",s:"It needs Claude access \u2014 a Claude subscription (default) or an ANTHROPIC_API_KEY."},{t:"gap"},{t:"sub",s:"Quick start"},{t:"step",n:1,s:"Run /init \u2014 pick your environment, sign in, choose your project & workspace. It ends by printing a one-paste hand-off prompt."},{t:"step",n:2,s:"Paste that prompt into your repo's coding agent (Claude Code / Codex / Cursor). Let it finish, then follow its closing line. (Re-show it: /devhints)"},{t:"step",n:3,s:"Run /doctor to confirm every check is green."},{t:"step",n:4,s:'Type "write the docs for this repository" and follow the prompts.'},{t:"gap"},{t:"dim",s:"That's it \u2014 D360-Writer drafts your docs without you writing a line."},{t:"gap"},{t:"sub",s:"Tips"},{t:"text",s:"Just talk to it \u2014 anything not starting with / goes to the agent."},{t:"dim",s:"/ browses commands \xB7 \u2191 recalls history \xB7 esc interrupts a run \xB7 ctrl+c exits"}]},{key:"agentic",label:"Agentic",rows:[{t:"text",s:"Agentic Mode is designed for applications built using AI coding agents. D360-Writer works alongside your coding agent to continuously create and maintain your user documentation. Think of it as hiring a Technical Writer dedicated to your project."},{t:"gap"},{t:"text",s:"As your coding agent ships new features, it leaves documentation notes for D360-Writer. All you need to do is run the documentation loop."},{t:"gap"},{t:"sub",s:"Every few days"},{t:"cmd",name:"/catch-up --publish",s:"Analyze the latest code changes, read the notes left by your coding agent, update the documentation, and publish the changes."},{t:"dim",s:" (or run /catch-up to review drafts first, then /publish when you're ready)"},{t:"gap"},{t:"sub",s:"Whenever you need"},{t:"cmd",name:"/audit",s:"Preview what has changed and identify missing documentation, without writing or publishing anything."},{t:"cmd",name:"/pull",s:"Bring Document360 down \u2014 pull edits made in the portal and import any new portal articles."},{t:"cmd",name:"/inbox",s:"Review and act on messages left by your coding agent."}]},{key:"assistant",label:"Assistant",rows:[{t:"text",s:"D360-Writer is your writing assistant \u2014 it does the writing, you decide what gets written and when."},{t:"text",s:"Best for large or complex monorepos: focus it on one feature, component, or set of source folders."},{t:"gap"},{t:"sub",s:"Just ask"},{t:"good",s:'"Write the documentation for the Multiple JWT feature we shipped in the latest release."'},{t:"gap"},{t:"sub",s:"Or use the pipeline"},{t:"cmd",name:"/scope",s:"Focus D360-Writer on specific source folders (monorepos)."},{t:"cmd",name:"/draft <feature>",s:"Plan a feature's articles from its PRDs in .d360-writer/input/ + the code."},{t:"cmd",name:"/write",s:"Write the planned articles (--preview shows the plan + cost first)."},{t:"cmd",name:"/publish",s:"Publish the articles to Document360."}]},{key:"shots",label:"Screenshots",rows:[{t:"text",s:"Documenting a web app? D360-Writer marks where an image helps with a <!-- SCREENSHOT --> placeholder."},{t:"text",s:"The companion CLI d360-capture turns those into real, annotated screenshots by driving your app in a browser."},{t:"gap"},{t:"sub",s:"Flow"},{t:"step",n:1,s:"Write your docs as usual \u2014 placeholders are added where visuals help."},{t:"step",n:2,s:"Run /screenshot --all to author capture specs and refresh the capture checklist (data + test-ids the shots need)."},{t:"step",n:3,s:"Stage what the checklist asks for, then run d360-capture in your app's repo \u2014 it signs in, navigates, captures, annotates."},{t:"step",n:4,s:"Re-run /publish so the images go live on Document360."},{t:"gap"},{t:"sub",s:"Helpers"},{t:"cmd",name:"/screenshot --list",s:"See capture status \u2014 which specs exist and which are done."},{t:"cmd",name:"/capture-setup",s:"Re-show the data-staging + test-id checklist (auto-runs after /screenshot --all)."},{t:"gap"},{t:"dim",s:"d360-capture is a separate Playwright CLI \u2014 run it in the app's repo (needs its URL + a login)."}]},{key:"cmds",label:"Commands",rows:[{t:"dim",s:"Grouped by job. Type any command, or just talk to the agent."},{t:"gap"},{t:"sub",s:"Getting started"},{t:"cmd",name:"/init",s:"Set up Document360 (environment, sign-in, project, hand-off prompt)."},{t:"cmd",name:"/login",s:"Sign in to Document360."},{t:"cmd",name:"/project",s:"Choose the Document360 project."},{t:"cmd",name:"/workspace",s:"Switch the workspace."},{t:"cmd",name:"/scope",s:"Choose which repo folders back the docs (monorepos)."},{t:"cmd",name:"/devhints",s:"Re-show the builder hand-off prompt."},{t:"gap"},{t:"sub",s:"Agentic \u2014 keep docs in sync"},{t:"cmd",name:"/roadmap",s:"The docs campaign: progress + the next step."},{t:"cmd",name:"/catch-up",s:"Do all pending work \u2192 drafts (--publish goes live)."},{t:"cmd",name:"/publish",s:"Publish to Document360 (--all or a path)."},{t:"cmd",name:"/audit",s:"Preview what changed / what's missing."},{t:"cmd",name:"/pull",s:"Pull portal edits + new articles (--status: report only)."},{t:"cmd",name:"/inbox",s:"Act on your coding agent's messages."},{t:"gap"},{t:"sub",s:"Assistant \u2014 directed writing"},{t:"cmd",name:"/draft <feature>",s:"Plan a feature's articles from PRDs + code."},{t:"cmd",name:"/write",s:"Write the planned articles (--preview first)."},{t:"cmd",name:"/preview",s:"Render an article locally."},{t:"gap"},{t:"sub",s:"Screenshots"},{t:"cmd",name:"/screenshot",s:"Author capture specs (--all / --list)."},{t:"gap"},{t:"sub",s:"Setup & health"},{t:"cmd",name:"/model",s:"Set the Claude model."},{t:"cmd",name:"/profile",s:"Switch/create a Document360 connection."},{t:"cmd",name:"/mcp",s:"Connect MCP servers (Notion, Linear, \u2026)."},{t:"cmd",name:"/allow-prod",s:"Authorize writes to a production profile."},{t:"cmd",name:"/doctor",s:"Health check: auth, profile, workspace, API."},{t:"cmd",name:"/update",s:"Update D360-Writer."},{t:"cmd",name:"/reset",s:"Delete all D360-Writer files (confirms first)."},{t:"gap"},{t:"sub",s:"Session"},{t:"cmd",name:"/resume",s:"Resume a saved session."},{t:"cmd",name:"/rename",s:"Name the session."},{t:"cmd",name:"/clear",s:"Reset the conversation (resumable)."},{t:"cmd",name:"/help",s:"Show this help."},{t:"cmd",name:"/exit",s:"Quit."}]}];function rd(e){switch(e.t){case"head":return e.s;case"text":return` ${e.s}`;case"dim":return` ${e.s}`;case"sub":return e.s;case"good":return` ${e.s}`;case"step":return` ${e.n}. ${e.s}`;case"cmd":return` ${e.name.padEnd(20)} ${e.s}`;case"gap":return""}}function ta(){let e=["document360-writer \u2014 help",""];for(let t of Te){e.push(`\u2500\u2500 ${t.label} \u2500\u2500`,"");for(let n of t.rows)e.push(rd(n));e.push("")}return e.push("Tip: anything not starting with / goes to the agent."),e}async function kr(){console.log("");for(let e of ta())console.log(e);return console.log(""),console.log("Reporting a problem? Run `d360-writer logs` for the API log files."),console.log(""),{kind:"continue"}}U();import{getSession as id}from"document360-engine";async function na(e,t){let n=t.currentUuid(),o=n?id(n):void 0;return console.log(o?f(`
217
+ `),process.exit(D)}import{createInterface as Vm}from"node:readline/promises";import{createSession as Xi,resolveAuth as Gm,getSession as Ym,setTitle as zm,slugify as Km,touchSession as ac,upsertSession as Xm,generateTitle as Qm,resolveActiveProfile as lc,resolveModelSetting as Jm,readProjectConfig as Zm,resolveAndPersistAppType as eh,decodeJwtClaims as sc,isExpired as th,loadTokens as nh,isDirectiveMention as oh,stripDirectiveMention as rh,appendDirective as ih,reconcileUpgradeActions as sh,stampArticles as ah,listArticleFiles as lh,CONTENT_CAP_VERSION as ch}from"document360-engine";var Te=[{key:"start",label:"Getting Started",rows:[{t:"text",s:"D360-Writer reads your codebase, generates end-user documentation, and publishes it to Document360."},{t:"text",s:"It needs Claude access \u2014 a Claude subscription (default) or an ANTHROPIC_API_KEY."},{t:"gap"},{t:"sub",s:"Quick start"},{t:"step",n:1,s:"Run /init \u2014 pick your environment, sign in, choose your project & workspace. It ends by printing a one-paste hand-off prompt."},{t:"step",n:2,s:"Paste that prompt into your repo's coding agent (Claude Code / Codex / Cursor). Let it finish, then follow its closing line. (Re-show it: /devhints)"},{t:"step",n:3,s:"Run /doctor to confirm every check is green."},{t:"step",n:4,s:'Type "write the docs for this repository" and follow the prompts.'},{t:"gap"},{t:"dim",s:"That's it \u2014 D360-Writer drafts your docs without you writing a line."},{t:"gap"},{t:"sub",s:"Tips"},{t:"text",s:"Just talk to it \u2014 anything not starting with / goes to the agent."},{t:"dim",s:"/ browses commands \xB7 \u2191 recalls history \xB7 esc interrupts a run \xB7 ctrl+c exits"}]},{key:"agentic",label:"Agentic",rows:[{t:"text",s:"Agentic Mode is designed for applications built using AI coding agents. D360-Writer works alongside your coding agent to continuously create and maintain your user documentation. Think of it as hiring a Technical Writer dedicated to your project."},{t:"gap"},{t:"text",s:"As your coding agent ships new features, it leaves documentation notes for D360-Writer. All you need to do is run the documentation loop."},{t:"gap"},{t:"sub",s:"Every few days"},{t:"cmd",name:"/catch-up --publish",s:"Analyze the latest code changes, read the notes left by your coding agent, update the documentation, and publish the changes."},{t:"dim",s:" (or run /catch-up to review drafts first, then /publish when you're ready)"},{t:"gap"},{t:"sub",s:"Whenever you need"},{t:"cmd",name:"/audit",s:"Preview what has changed and identify missing documentation, without writing or publishing anything."},{t:"cmd",name:"/pull",s:"Bring Document360 down \u2014 pull edits made in the portal and import any new portal articles."},{t:"cmd",name:"/inbox",s:"Review and act on messages left by your coding agent."}]},{key:"assistant",label:"Assistant",rows:[{t:"text",s:"D360-Writer is your writing assistant \u2014 it does the writing, you decide what gets written and when."},{t:"text",s:"Best for large or complex monorepos: focus it on one feature, component, or set of source folders."},{t:"gap"},{t:"sub",s:"Just ask"},{t:"good",s:'"Write the documentation for the Multiple JWT feature we shipped in the latest release."'},{t:"gap"},{t:"sub",s:"Or use the pipeline"},{t:"cmd",name:"/scope",s:"Focus D360-Writer on specific source folders (monorepos)."},{t:"cmd",name:"/draft <feature>",s:"Plan a feature's articles from its PRDs in .d360-writer/input/ + the code."},{t:"cmd",name:"/write",s:"Write the planned articles (--preview shows the plan + cost first)."},{t:"cmd",name:"/publish",s:"Publish the articles to Document360."}]},{key:"shots",label:"Screenshots",rows:[{t:"text",s:"Documenting a web app? D360-Writer marks where an image helps with a <!-- SCREENSHOT --> placeholder."},{t:"text",s:"The companion CLI d360-capture turns those into real, annotated screenshots by driving your app in a browser."},{t:"gap"},{t:"sub",s:"Flow"},{t:"step",n:1,s:"Write your docs as usual \u2014 placeholders are added where visuals help."},{t:"step",n:2,s:"Run /screenshot --all to author capture specs and refresh the capture checklist (data + test-ids the shots need)."},{t:"step",n:3,s:"Stage what the checklist asks for, then run d360-capture in your app's repo \u2014 it signs in, navigates, captures, annotates."},{t:"step",n:4,s:"Re-run /publish so the images go live on Document360."},{t:"gap"},{t:"sub",s:"Helpers"},{t:"cmd",name:"/screenshot --list",s:"See capture status \u2014 which specs exist and which are done."},{t:"cmd",name:"/capture-setup",s:"Re-show the data-staging + test-id checklist (auto-runs after /screenshot --all)."},{t:"gap"},{t:"dim",s:"d360-capture is a separate Playwright CLI \u2014 run it in the app's repo (needs its URL + a login)."}]},{key:"cmds",label:"Commands",rows:[{t:"dim",s:"Grouped by job. Type any command, or just talk to the agent."},{t:"gap"},{t:"sub",s:"Getting started"},{t:"cmd",name:"/init",s:"Set up Document360 (environment, sign-in, project, hand-off prompt)."},{t:"cmd",name:"/login",s:"Sign in to Document360."},{t:"cmd",name:"/project",s:"Choose the Document360 project."},{t:"cmd",name:"/workspace",s:"Switch the workspace."},{t:"cmd",name:"/scope",s:"Choose which repo folders back the docs (monorepos)."},{t:"cmd",name:"/devhints",s:"Re-show the builder hand-off prompt."},{t:"gap"},{t:"sub",s:"Agentic \u2014 keep docs in sync"},{t:"cmd",name:"/roadmap",s:"The docs campaign: progress + the next step."},{t:"cmd",name:"/catch-up",s:"Do all pending work \u2192 drafts (--publish goes live)."},{t:"cmd",name:"/publish",s:"Publish to Document360 (--all or a path)."},{t:"cmd",name:"/audit",s:"Preview what changed / what's missing."},{t:"cmd",name:"/pull",s:"Pull portal edits + new articles (--status: report only)."},{t:"cmd",name:"/inbox",s:"Act on your coding agent's messages."},{t:"gap"},{t:"sub",s:"Assistant \u2014 directed writing"},{t:"cmd",name:"/draft <feature>",s:"Plan a feature's articles from PRDs + code."},{t:"cmd",name:"/write",s:"Write the planned articles (--preview first)."},{t:"cmd",name:"/preview",s:"Render an article locally."},{t:"gap"},{t:"sub",s:"Screenshots"},{t:"cmd",name:"/screenshot",s:"Author capture specs (--all / --list)."},{t:"gap"},{t:"sub",s:"Setup & health"},{t:"cmd",name:"/model",s:"Set the Claude model."},{t:"cmd",name:"/profile",s:"Switch/create a Document360 connection."},{t:"cmd",name:"/mcp",s:"Connect MCP servers (Notion, Linear, \u2026)."},{t:"cmd",name:"/allow-prod",s:"Authorize writes to a production profile."},{t:"cmd",name:"/doctor",s:"Health check: auth, profile, workspace, API."},{t:"cmd",name:"/update",s:"Update D360-Writer."},{t:"cmd",name:"/reset",s:"Delete all D360-Writer files (confirms first)."},{t:"gap"},{t:"sub",s:"Session"},{t:"cmd",name:"/resume",s:"Resume a saved session."},{t:"cmd",name:"/rename",s:"Name the session."},{t:"cmd",name:"/clear",s:"Clear the screen and reset the conversation (resumable)."},{t:"cmd",name:"/help",s:"Show this help."},{t:"cmd",name:"/exit",s:"Quit."}]}];function rd(e){switch(e.t){case"head":return e.s;case"text":return` ${e.s}`;case"dim":return` ${e.s}`;case"sub":return e.s;case"good":return` ${e.s}`;case"step":return` ${e.n}. ${e.s}`;case"cmd":return` ${e.name.padEnd(20)} ${e.s}`;case"gap":return""}}function ta(){let e=["document360-writer \u2014 help",""];for(let t of Te){e.push(`\u2500\u2500 ${t.label} \u2500\u2500`,"");for(let n of t.rows)e.push(rd(n));e.push("")}return e.push("Tip: anything not starting with / goes to the agent."),e}async function kr(){console.log("");for(let e of ta())console.log(e);return console.log(""),console.log("Reporting a problem? Run `d360-writer logs` for the API log files."),console.log(""),{kind:"continue"}}U();import{getSession as id}from"document360-engine";async function na(e,t){let n=t.currentUuid(),o=n?id(n):void 0;return console.log(o?f(`
218
218
  (conversation reset \u2014 "${o.name}" is still available via /resume)
219
219
  `):f(`
220
220
  (conversation reset \u2014 agent will start fresh on the next prompt)
@@ -294,7 +294,7 @@ Articles:
294
294
  `),console.log(`${N("\u25CF")} ${Pe(i.title)}${i.arg!==null?ae(`${i.sep}(${i.arg})`):""}`),r.set(e.id,{name:e.name,input:e.input}));break}case"article_diff":{let i=pt(e.oldContent,e.newContent,Math.max(40,(process.stdout.columns??80)-1));if(!i)break;let c=p=>p===1?"":"s";console.log(ae(` \u23BF Added ${i.added} line${c(i.added)}, removed ${i.removed} line${c(i.removed)}`));for(let p of i.lines)console.log(p);i.hidden>0&&console.log(f(` \u2026 +${i.hidden} more diff lines`));break}case"tool_result":{let i=r.get(e.id);if(!i)break;r.delete(e.id);let c=Io(e.output,4,e.isError?void 0:i.name,i.input),p=e.isError?$:ae;c.lines.forEach((g,w)=>console.log(p((w===0?" \u23BF ":" ")+g))),c.hidden>0&&console.log(f(` \u2026 +${c.hidden} lines`)),e.isError||dh(i.name,i.input,e.output,n);break}case"result":process.stdout.write(`
295
295
  `),console.log(f(` (${e.inputTokens}\u2192${e.outputTokens} tokens`+(e.costUsd>0?`, $${e.costUsd<.01?e.costUsd.toFixed(4):e.costUsd.toFixed(2)}`:"")+")")),console.log(""),t.uuid&&(ac(t.uuid),t.titleFired||yh(t,n));break;case"error":console.error(""),console.error($(`agent error: ${e.message}`)),o.kind==="subscription"&&e.kind==="auth"&&hh();break}}import{render as Og}from"ink";import{resolveAuth as Lg}from"document360-engine";import{useCallback as V,useEffect as ve,useMemo as ns,useRef as J,useState as W}from"react";import{Box as ne,Text as A,useApp as Nh,useInput as Ih,useStdout as _h}from"ink";import{existsSync as $n,readFileSync as os,readdirSync as Oh}from"node:fs";import{basename as vn,isAbsolute as Lh,join as rs}from"node:path";import{createSession as Mc,classifyClaudeAuth as cs,CLAUDE_CODE_SETUP_HINT as Mh,loginPkce as Uh,toStoredTokens as Wh,saveTokens as Fh,getAccessToken as Hh,resolveActiveProfile as $e,resolveProjectId as qh,getArticle as Bh,decodeJwtClaims as Bt,isExpired as Ze,loadTokens as gt,clearTokens as Vh,clearProfileProject as Gh,setTitle as Yh,slugify as zh,touchSession as is,upsertSession as Kh,generateTitle as Uc,findByName as Xh,listSessions as Qh,renameSession as Jh,suggestNextAction as Zh,readProjectConfig as te,writeProjectConfig as Wc,resolveAndPersistAppType as eg,detectAppType as tg,resolveModelSetting as us,loadProfileMap as Fc,applyPull as ng,computeSyncStatus as Hc,lintDocs as qc,compareRemoteSources as og,planPull as rg,establishBaselines as ig,rebaselineServerMeta as sg,inventoryRepo as ag,knownEnvironments as lg,resolveEnvironment as cg,planPartitions as ss,partitionEvenly as ug,screenshotPlaceholderIds as dg,trackedArticlePaths as pg,runPartitioned as Go,estimateBulkCost as Bc,resolveModelForOperation as Yo,readDocsPlan as fg,checkForUpdate as mg,detectInstallKind as hg,isSelfUpdatable as gg,devHintsGuidePath as Vc,toolFeedbackPath as yg,reconcileToolFeedback as wg,reconcileUpgradeActions as kg,stampArticles as as,listArticleFiles as Gc,CONTENT_CAP_VERSION as ls,DEFAULT_DOCS_DIR as eu,setProfileProject as bg,writeCrashLog as xg,applyStructureOrder as Yc,orderSyncLine as zc,applyRelatedArticles as Kc,relatedSyncLine as Xc}from"document360-engine";Ke();import{spawn as uc}from"node:child_process";function kh(){return process.platform==="win32"?[["clip",[]]]:process.platform==="darwin"?[["pbcopy",[]]]:[["wl-copy",[]],["xclip",["-selection","clipboard"]],["xsel",["--clipboard","--input"]]]}function bh(e,t,n){return new Promise(o=>{try{let r=process.platform==="win32"?uc([e,...t].join(" "),{stdio:["pipe","ignore","ignore"],shell:!0}):uc(e,t,{stdio:["pipe","ignore","ignore"]});r.on("error",()=>o(!1)),r.on("close",c=>o(c===0)),r.stdin?.on("error",()=>o(!1));let i=process.platform==="win32"?Buffer.from("\uFEFF"+n,"utf16le"):Buffer.from(n,"utf8");r.stdin?.end(i)}catch{o(!1)}})}async function dc(e){for(let[t,n]of kh())if(await bh(t,n,e))return!0;return!1}var xh=/\breply with (the |a )?number\b|\bpick one\b|\bpress the number\b/i;function Ji(e,t){if(t.closed)return e;let n=e.split(`
296
296
  `),o=!1;for(let r=0;r<n.length&&!t.closed;r++){let i=n[r];if(!t.cueSeen){xh.test(i)&&(t.cueSeen=!0);continue}let c=/^(\s{0,3})[-*•]\s+(.*)$/.exec(i);c?(n[r]=`${c[1]}${++t.num}. ${c[2]}`,o=!0):o&&i.trim()!==""&&/^\S/.test(i)&&(t.closed=!0)}return n.join(`
297
- `)}import{existsSync as $h,mkdirSync as vh,readFileSync as Ch,writeFileSync as Rh}from"node:fs";import{join as pc}from"node:path";import{writerDir as Ph}from"document360-engine";function fc(e){return pc(Ph(e),".sessions")}function mc(e,t){return pc(fc(e),`${t}.json`)}function hc(e,t,n){try{vh(fc(e),{recursive:!0});let o=n.filter(r=>r.kind!=="banner");Rh(mc(e,t),JSON.stringify({v:1,items:o}),"utf8")}catch{}}function Zi(e,t){try{let n=mc(e,t);if(!$h(n))return[];let o=JSON.parse(Ch(n,"utf8"));return Array.isArray(o.items)?o.items:[]}catch{return[]}}var Th=e=>`\x1B]0;${e}\x07`,Sh=e=>`\x1B]9;4;${e};${e===1?100:0}\x07`;function gc(e){process.stdout.isTTY&&process.stdout.write(e)}function Ht(e){gc(Th(e))}function Mo(e){gc(Sh(e))}var Uo=["\xB7 "," \xB7"],Wo="\u{1F7E3}";$o();uo();var Fo=[{name:"init",usage:"/init",desc:"Pick an environment, scaffold .d360-writer/config.json, and set up the builder hand-off (prints the one-paste prompt)",group:"start"},{name:"login",usage:"/login",desc:"Sign in to Document360 (browser)",group:"start"},{name:"project",usage:"/project [name]",desc:"Choose the Document360 project (picker; lists all you can access)",group:"start"},{name:"devhints",usage:"/devhints",desc:"Re-show/refresh the builder hand-off prompt (set up by /init; run anytime to hand your repo agent the latest)",group:"start"},{name:"scope",usage:"/scope",desc:"Choose which repo folders back the docs (monorepos)",group:"start"},{name:"genre",usage:"/genre [web|cli|service|library|auto]",desc:"Set/show the product genre \u2014 picks the docs craft playbook (usually auto-detected; set it if it guessed wrong)",group:"start"},{name:"mcp",usage:"/mcp [list|add|remove]",desc:"Connect MCP servers (Notion, Linear, \u2026)",group:"start"},{name:"draft",usage:"/draft [<feature>]",desc:"Draft a feature's articles from its PRDs/specs in .d360-writer/input/ + the code",group:"docs"},{name:"document",usage:"/document [<what>] [--publish]",desc:"Document a shipped change \u2014 the agent picks the action (new section/article/update); bare: act on builder requests",group:"docs"},{name:"write",usage:"/write [--preview|--scope <cat>|<path>] [--rewrite] [--concurrency N]",desc:"Write the planned articles in parallel (starts immediately; --preview shows plan + cost first; --rewrite regenerates already-written articles; --concurrency default 3)",group:"docs"},{name:"screenshot",usage:"/screenshot [--list|id|--all|path]",desc:"--list: status; else author capture specs (bulk also refreshes the capture checklist; --no-setup skips)",group:"docs"},{name:"capture-setup",usage:"/capture-setup",desc:"Re-run the data-staging checklist + dev test-id requests (auto-runs after /screenshot --all)",group:"docs"},{name:"preview",usage:"/preview [path|id]",desc:"Render an article (no arg: pick from tracked)",group:"docs"},{name:"publish",usage:"/publish [path|--all]",desc:"Publish to Document360 (no arg: pick; --all: every candidate)",group:"publish"},{name:"check",usage:"/check [<category|path>] [--fix]",desc:"Check docs for leaked internals, invented commands, and stale facts (deterministic, no tokens). Scope to a category/path; --fix has the agent correct the findings in place",group:"docs"},{name:"review",usage:"/review [<category|path>] [--fix]",desc:"Independent senior-editor review: style guide, terminology/voice, grammar/clarity, structure, improvement suggestions. Reports issues; --fix applies the corrections in place",group:"docs"},{name:"reorder",usage:"/reorder [<category>]",desc:"Reorder articles within a category to the best reading order (renumbers NN- prefixes, fixes references + map); new order syncs to Document360 on next /publish",group:"docs"},{name:"structure",usage:"/structure",desc:"Show the documentation reading order (categories \u2192 articles) as it will appear on Document360",group:"docs"},{name:"roadmap",usage:"/roadmap [done <step>]",desc:"Show the docs campaign (the multi-session plan the agent maintains) \u2014 progress + next step; `done <step>` marks one you finished yourself",group:"docs"},{name:"audit",usage:"/audit [--auto on|off]",desc:"Gap analysis: code vs docs vs Document360 (what changed); --auto runs it at launch when code changed",group:"publish"},{name:"inbox",usage:"/inbox",desc:"Act on messages from the repo's coding agent (requests to document, answers to your questions)",group:"publish"},{name:"catch-up",usage:"/catch-up [--publish]",desc:"Process ALL pending work (hints + requests + drift) \u2192 write \u2192 push to Document360 (bare = drafts; --publish goes live)",group:"publish"},{name:"pull",usage:"/pull [<path> | --status | --baseline]",desc:"Bring Document360 down: pull portal edits + import NEW portal articles. --status: drift report only \xB7 --baseline: set a sync base \xB7 <path>: one article / resolve a conflict",group:"publish"},{name:"convert",usage:"/convert [--scope <folder>] [--run]",desc:"Convert tracked articles to DFM (one-off legacy migration)",group:"publish"},{name:"profile",usage:"/profile [name|add <name> [env]]",desc:"Switch/create a Document360 connection (picker; s = session)",group:"setup"},{name:"workspace",usage:"/workspace [name]",desc:"Switch the Document360 workspace (picker)",group:"setup"},{name:"model",usage:"/model [name|default]",desc:"Set the Claude model for d360-writer",group:"setup"},{name:"logout",usage:"/logout",desc:"Sign out + clear project/workspace selection (then /login to re-pick)",group:"setup"},{name:"allow-prod",usage:"/allow-prod",desc:"Authorize writes to a production profile",group:"setup"},{name:"doctor",usage:"/doctor",desc:"Health-check: auth, profile, workspace, map, API",group:"setup"},{name:"update",usage:"/update",desc:"Update d360-writer to the latest version (then relaunch)",group:"setup"},{name:"reset",usage:"/reset",desc:"[DANGER] Delete all d360-writer files (docs, config, screenshots); types repo name to confirm",group:"setup"},{name:"resume",usage:"/resume [name]",desc:"Resume a session (no arg lists them)",group:"session"},{name:"rename",usage:"/rename [name]",desc:"Name the session (no arg: suggest one)",group:"session"},{name:"clear",usage:"/clear",desc:"Reset the conversation (resumable)",group:"session"},{name:"help",usage:"/help",desc:"Show this help",group:"session"},{name:"exit",usage:"/exit",desc:"Quit",group:"session"}],yc={"/catch-up":"write up everything your builder flagged","/audit":"check the code for anything new or missing in the docs","/pull":"pull edits + new articles from Document360","/publish":"publish your drafts to Document360","/write":"author the planned articles","/draft":"plan articles from PRDs + the code","/login":"sign in to Document360","/workspace":"choose the Document360 workspace","/project":"choose the Document360 project","/scope":"choose which folders back the docs","/genre":"set this repo's product type (picks the docs playbook)","/init":"set up this repo","/screenshot":"generate screenshots","/doctor":"run a health check"};function wc(e){let t=e.trim().replace(/^\//,"").split(/\s+/)[0]??"",n=`/${t}`;if(yc[n])return yc[n];let o=Fo.find(r=>r.name===t);return o?o.desc:""}function kc(e){if(!e.startsWith("/"))return[];let t=e.slice(1).toLowerCase().split(/\s/)[0]??"";return Fo.filter(n=>n.name.startsWith(t))}function bc(e){return/<[^>]+>/.test(e.replace(/\[[^\]]*\]/g,""))}U();import{Box as xc,Text as le}from"ink";import{jsx as ce,jsxs as Ho}from"react/jsx-runtime";function Dh({row:e}){switch(e.t){case"head":return ce(le,{color:F,bold:!0,children:e.s});case"text":return ce(le,{children:e.s});case"dim":return ce(le,{dimColor:!0,children:e.s});case"sub":return ce(le,{bold:!0,dimColor:!0,children:e.s});case"good":return ce(le,{color:"green",children:e.s});case"step":return Ho(le,{children:[ce(le,{color:F,children:`${e.n}. `}),e.s]});case"cmd":return Ho(le,{children:[" ",ce(le,{color:F,children:e.name.padEnd(20)}),ce(le,{dimColor:!0,children:e.s})]});case"gap":return ce(le,{children:" "})}}function $c({tab:e,width:t}){let n=Te[e]??Te[0],o=6+Te.reduce((i,c)=>i+c.label.length+4,0),r="\u2500".repeat(Math.min(o,Math.max(t-1,20)));return Ho(xc,{flexDirection:"column",paddingX:1,children:[Ho(le,{children:[ce(le,{color:F,bold:!0,children:"Help "}),Te.map((i,c)=>c===e?ce(le,{color:"white",backgroundColor:F,bold:!0,children:` ${i.label} `},i.key):ce(le,{dimColor:!0,children:` ${i.label} `},i.key))]}),ce(le,{color:F,children:r}),ce(xc,{flexDirection:"column",marginTop:1,children:n.rows.map((i,c)=>ce(Dh,{row:i},c))}),ce(le,{dimColor:!0,children:`
297
+ `)}import{existsSync as $h,mkdirSync as vh,readFileSync as Ch,writeFileSync as Rh}from"node:fs";import{join as pc}from"node:path";import{writerDir as Ph}from"document360-engine";function fc(e){return pc(Ph(e),".sessions")}function mc(e,t){return pc(fc(e),`${t}.json`)}function hc(e,t,n){try{vh(fc(e),{recursive:!0});let o=n.filter(r=>r.kind!=="banner");Rh(mc(e,t),JSON.stringify({v:1,items:o}),"utf8")}catch{}}function Zi(e,t){try{let n=mc(e,t);if(!$h(n))return[];let o=JSON.parse(Ch(n,"utf8"));return Array.isArray(o.items)?o.items:[]}catch{return[]}}var Th=e=>`\x1B]0;${e}\x07`,Sh=e=>`\x1B]9;4;${e};${e===1?100:0}\x07`;function gc(e){process.stdout.isTTY&&process.stdout.write(e)}function Ht(e){gc(Th(e))}function Mo(e){gc(Sh(e))}var Uo=["\xB7 "," \xB7"],Wo="\u{1F7E3}";$o();uo();var Fo=[{name:"init",usage:"/init",desc:"Pick an environment, scaffold .d360-writer/config.json, and set up the builder hand-off (prints the one-paste prompt)",group:"start"},{name:"login",usage:"/login",desc:"Sign in to Document360 (browser)",group:"start"},{name:"project",usage:"/project [name]",desc:"Choose the Document360 project (picker; lists all you can access)",group:"start"},{name:"devhints",usage:"/devhints",desc:"Re-show/refresh the builder hand-off prompt (set up by /init; run anytime to hand your repo agent the latest)",group:"start"},{name:"scope",usage:"/scope",desc:"Choose which repo folders back the docs (monorepos)",group:"start"},{name:"genre",usage:"/genre [web|cli|service|library|auto]",desc:"Set/show the product genre \u2014 picks the docs craft playbook (usually auto-detected; set it if it guessed wrong)",group:"start"},{name:"mcp",usage:"/mcp [list|add|remove]",desc:"Connect MCP servers (Notion, Linear, \u2026)",group:"start"},{name:"draft",usage:"/draft [<feature>]",desc:"Draft a feature's articles from its PRDs/specs in .d360-writer/input/ + the code",group:"docs"},{name:"document",usage:"/document [<what>] [--publish]",desc:"Document a shipped change \u2014 the agent picks the action (new section/article/update); bare: act on builder requests",group:"docs"},{name:"write",usage:"/write [--preview|--scope <cat>|<path>] [--rewrite] [--concurrency N]",desc:"Write the planned articles in parallel (starts immediately; --preview shows plan + cost first; --rewrite regenerates already-written articles; --concurrency default 3)",group:"docs"},{name:"screenshot",usage:"/screenshot [--list|id|--all|path]",desc:"--list: status; else author capture specs (bulk also refreshes the capture checklist; --no-setup skips)",group:"docs"},{name:"capture-setup",usage:"/capture-setup",desc:"Re-run the data-staging checklist + dev test-id requests (auto-runs after /screenshot --all)",group:"docs"},{name:"preview",usage:"/preview [path|id]",desc:"Render an article (no arg: pick from tracked)",group:"docs"},{name:"publish",usage:"/publish [path|--all]",desc:"Publish to Document360 (no arg: pick; --all: every candidate)",group:"publish"},{name:"check",usage:"/check [<category|path>] [--fix]",desc:"Check docs for leaked internals, invented commands, and stale facts (deterministic, no tokens). Scope to a category/path; --fix has the agent correct the findings in place",group:"docs"},{name:"review",usage:"/review [<category|path>] [--fix]",desc:"Independent senior-editor review: style guide, terminology/voice, grammar/clarity, structure, improvement suggestions. Reports issues; --fix applies the corrections in place",group:"docs"},{name:"reorder",usage:"/reorder [<category>]",desc:"Reorder articles within a category to the best reading order (renumbers NN- prefixes, fixes references + map); new order syncs to Document360 on next /publish",group:"docs"},{name:"structure",usage:"/structure",desc:"Show the documentation reading order (categories \u2192 articles) as it will appear on Document360",group:"docs"},{name:"roadmap",usage:"/roadmap [done <step>]",desc:"Show the docs campaign (the multi-session plan the agent maintains) \u2014 progress + next step; `done <step>` marks one you finished yourself",group:"docs"},{name:"audit",usage:"/audit [--auto on|off]",desc:"Gap analysis: code vs docs vs Document360 (what changed); --auto runs it at launch when code changed",group:"publish"},{name:"inbox",usage:"/inbox",desc:"Act on messages from the repo's coding agent (requests to document, answers to your questions)",group:"publish"},{name:"catch-up",usage:"/catch-up [--publish]",desc:"Process ALL pending work (hints + requests + drift) \u2192 write \u2192 push to Document360 (bare = drafts; --publish goes live)",group:"publish"},{name:"pull",usage:"/pull [<path> | --status | --baseline]",desc:"Bring Document360 down: pull portal edits + import NEW portal articles. --status: drift report only \xB7 --baseline: set a sync base \xB7 <path>: one article / resolve a conflict",group:"publish"},{name:"convert",usage:"/convert [--scope <folder>] [--run]",desc:"Convert tracked articles to DFM (one-off legacy migration)",group:"publish"},{name:"profile",usage:"/profile [name|add <name> [env]]",desc:"Switch/create a Document360 connection (picker; s = session)",group:"setup"},{name:"workspace",usage:"/workspace [name]",desc:"Switch the Document360 workspace (picker)",group:"setup"},{name:"model",usage:"/model [name|default]",desc:"Set the Claude model for d360-writer",group:"setup"},{name:"logout",usage:"/logout",desc:"Sign out + clear project/workspace selection (then /login to re-pick)",group:"setup"},{name:"allow-prod",usage:"/allow-prod",desc:"Authorize writes to a production profile",group:"setup"},{name:"doctor",usage:"/doctor",desc:"Health-check: auth, profile, workspace, map, API",group:"setup"},{name:"update",usage:"/update",desc:"Update d360-writer to the latest version (then relaunch)",group:"setup"},{name:"reset",usage:"/reset",desc:"[DANGER] Delete all d360-writer files (docs, config, screenshots); types repo name to confirm",group:"setup"},{name:"resume",usage:"/resume [name]",desc:"Resume a session (no arg lists them)",group:"session"},{name:"rename",usage:"/rename [name]",desc:"Name the session (no arg: suggest one)",group:"session"},{name:"clear",usage:"/clear",desc:"Clear the screen + reset the conversation (resumable)",group:"session"},{name:"help",usage:"/help",desc:"Show this help",group:"session"},{name:"exit",usage:"/exit",desc:"Quit",group:"session"}],yc={"/catch-up":"write up everything your builder flagged","/audit":"check the code for anything new or missing in the docs","/pull":"pull edits + new articles from Document360","/publish":"publish your drafts to Document360","/write":"author the planned articles","/draft":"plan articles from PRDs + the code","/login":"sign in to Document360","/workspace":"choose the Document360 workspace","/project":"choose the Document360 project","/scope":"choose which folders back the docs","/genre":"set this repo's product type (picks the docs playbook)","/init":"set up this repo","/screenshot":"generate screenshots","/doctor":"run a health check"};function wc(e){let t=e.trim().replace(/^\//,"").split(/\s+/)[0]??"",n=`/${t}`;if(yc[n])return yc[n];let o=Fo.find(r=>r.name===t);return o?o.desc:""}function kc(e){if(!e.startsWith("/"))return[];let t=e.slice(1).toLowerCase().split(/\s/)[0]??"";return Fo.filter(n=>n.name.startsWith(t))}function bc(e){return/<[^>]+>/.test(e.replace(/\[[^\]]*\]/g,""))}U();import{Box as xc,Text as le}from"ink";import{jsx as ce,jsxs as Ho}from"react/jsx-runtime";function Dh({row:e}){switch(e.t){case"head":return ce(le,{color:F,bold:!0,children:e.s});case"text":return ce(le,{children:e.s});case"dim":return ce(le,{dimColor:!0,children:e.s});case"sub":return ce(le,{bold:!0,dimColor:!0,children:e.s});case"good":return ce(le,{color:"green",children:e.s});case"step":return Ho(le,{children:[ce(le,{color:F,children:`${e.n}. `}),e.s]});case"cmd":return Ho(le,{children:[" ",ce(le,{color:F,children:e.name.padEnd(20)}),ce(le,{dimColor:!0,children:e.s})]});case"gap":return ce(le,{children:" "})}}function $c({tab:e,width:t}){let n=Te[e]??Te[0],o=6+Te.reduce((i,c)=>i+c.label.length+4,0),r="\u2500".repeat(Math.min(o,Math.max(t-1,20)));return Ho(xc,{flexDirection:"column",paddingX:1,children:[Ho(le,{children:[ce(le,{color:F,bold:!0,children:"Help "}),Te.map((i,c)=>c===e?ce(le,{color:"white",backgroundColor:F,bold:!0,children:` ${i.label} `},i.key):ce(le,{dimColor:!0,children:` ${i.label} `},i.key))]}),ce(le,{color:F,children:r}),ce(xc,{flexDirection:"column",marginTop:1,children:n.rows.map((i,c)=>ce(Dh,{row:i},c))}),ce(le,{dimColor:!0,children:`
298
298
  \u2190/\u2192 or tab switch \xB7 1-5 jump \xB7 esc close`})]})}var Ah=/^(?:\d+[.)]|[-*•])\s+/;function vc(e,t,n=4){let o=new Set(t.map(i=>i.toLowerCase())),r=[];for(let i of e.split(`
299
299
  `)){let c=i.trim().replace(Ah,""),p=c.match(/^`([^`]+)`$/);p&&(c=p[1].trim());let g=c.match(/^\/([a-z?][a-z0-9-]*)(?:\s+(\S.*?))?\s*$/i);if(!g||!o.has(g[1].toLowerCase()))continue;let w=`/${g[1].toLowerCase()}${g[2]?` ${g[2]}`:""}`;if(r.includes(w)||r.push(w),r.length>=n)break}return r}U();function xn(e){return e.map(t=>({label:t.label,items:t.paths.length,status:"pending"}))}function He(e,t,n){return e.map(o=>o.label===t?{...o,status:n}:o)}function Cc(e,t){return e.map(n=>n.label===t?{...n,itemsDone:Math.min((n.itemsDone??0)+1,n.items)}:n)}var jh=new Set(["Write","Edit","MultiEdit","NotebookEdit"]);function Rc(e,t,n){if(!jh.has(e))return null;let o=t?.file_path;if(typeof o!="string"||!o)return null;let r=o.replace(/\\/g,"/");return n.find(i=>{let c=i.replace(/\\/g,"/");return r===c||r.endsWith(`/${c}`)})??null}function es(e){return e.replace(/^[\w.-]+\//,"")}var qo=16,Pc={pending:"\u25CB",active:"\u25A0",done:"\u2714",failed:"\u2717"};function ht(e){return typeof e=="string"?e:e.cmd}function Tc(e){return typeof e=="string"?void 0:e.desc}function ts(e){return e.trim().split(/\s+/).slice(1).join(" ")}function Sc(e,t){let n=ts(t);return e.some(r=>ht(r).trim()===t.trim()||!!n&&ts(ht(r))===n)?e.filter(r=>ht(r).trim()!==t.trim()&&!(n&&ts(ht(r))===n)):[]}import{isDirectiveMention as $g,stripDirectiveMention as vg,appendDirective as Cg}from"document360-engine";var Eh=/\[Pasted text #\d+ \+\d+ lines?\]/g;function Dc(e){return e.replace(/\r\n?/g,`
300
300
  `)}function Ac(e){return e.includes(`
@@ -316,7 +316,7 @@ cwd: ${e}`}),sr()},[]),ve(()=>{let l=setInterval(()=>{sr()},_g);return()=>clearI
316
316
  `)});let y=Lr(e,i);if(y&&d({kind:"note",tone:"info",text:y}),!u.aborted){try{let v=await Yc({cwd:e,profileName:i}),T=zc(v);T?d({kind:"note",tone:"info",text:T}):v.skipped&&d({kind:"note",tone:"warn",text:`Order sync skipped: ${v.skipped}`})}catch(v){d({kind:"note",tone:"warn",text:`Order sync failed: ${v.message}`})}try{let v=Xc(await Kc({cwd:e,profileName:i}));v&&d({kind:"note",tone:"info",text:v})}catch(v){d({kind:"note",tone:"warn",text:`Related-articles sync failed: ${v.message}`})}}}}catch(u){d({kind:"note",tone:"error",text:`Publish run failed: ${u.message}`})}finally{Re.current=null,oe(null),I(!1),Z(u=>u+1)}},[e,i,d,t]),pr=V(async l=>{await ie(Or(l),{display:`/publish ${l}`,quietUser:!0});try{let a=await ho(e,i,l.replace(/\\/g,"/"));a.length>0&&(Yt(`Related articles not yet published (${a.length}):`),tt([`/publish --related ${l}`,...a.map(s=>`/publish ${s}`)]))}catch{}},[e,i,ie]),fr=V(l=>{let a=gt(l);if(!a||Ze(a)&&!a.refreshToken)return null;let s={...Bt(a.idToken)??{},...Bt(a.accessToken)??{}};return s.email??s.preferred_username??"signed in"},[]),mr=V((l,a)=>{if(a){let s=te(e);s&&(s.defaultProfile=l,Wc(s,e))}c(l),ke(void 0,l),d({kind:"note",tone:"ok",text:`\u2713 Switched to profile "${l}"${a?" (saved as default)":" (this session only)"} \u2014 agent restarted.`}),fr(l)||(d({kind:"note",tone:"warn",text:`Profile "${l}" is not signed in \u2014 sign in with /login.`}),z("/login")),Z(s=>s+1)},[e,d,ke,fr,z]),Wn=V((l,a,s)=>{Kn(e,l,a,s.id,s.name),d({kind:"note",tone:"ok",text:`Switched to workspace "${s.name??s.id}" (agent restarted).`}),ke(),Fc(e,l)||(d({kind:"note",tone:"ok",text:"\u2713 Connected. Configuration is done \u2014 one important step remains."}),d({kind:"note",tone:"warn",text:"\u26A0 Before I write the docs, hand the prompt below to your builder (your repo's coding agent). It gives me the architecture brief that makes the docs accurate:"}),d({kind:"note",tone:"info",text:Ut(Mt(e)).join(`
317
317
  `)}),jt(dt()),Jt.current=Se(e).status==="current"||We(e),d({kind:"note",tone:"info",text:`No separate builder agent? Then just ask me now: "write the docs for this repo" \u2014 I'll read the code directly.`}))},[e,d,ke,jt]),Fn=V(async l=>{let a;try{a=await rn(e,l)}catch{d({kind:"note",tone:"info",text:"Next: pick a workspace \u2014 run /workspace."}),z("/workspace");return}if(a.workspaces.length===0){d({kind:"note",tone:"warn",text:"This project has no workspaces yet. Create one in Document360, then run /workspace."});return}let s=a.workspaces.filter(u=>(u.workspace_type??"").toLowerCase()!=="apidocumentation"),h=s.length>0?s:a.workspaces;if(h.length===1){let u=h[0],m=a.workspaces.length-h.length;d({kind:"note",tone:"ok",text:`Selected the "${u.name??u.id}" workspace${m>0?" (skipped the API-documentation workspace)":""}.`}),Wn(a.profile,a.projectId,u);return}d({kind:"note",tone:"info",text:`Next: pick the workspace your articles publish to (${h.length} available).`}),z("/workspace")},[e,d,Wn,z]),Hn=V((l,a)=>{Xn(e,l,a.id,a.name),d({kind:"note",tone:"ok",text:`Project set to "${a.name??a.id}" (agent restarted).`}),ke(),Fn(l)},[e,d,ke,Fn]),Es=V(async l=>{let a;try{a=$e(e,l)}catch{return}if(!a.project.workspaceId){if(a.project.projectId){if(!a.project.projectName)try{let{projects:s}=await ze(e,a.name),h=s.find(u=>u.id===a.project.projectId);h?.name&&bg(e,a.name,{projectName:h.name})}catch{}await Fn(a.name);return}try{let{projects:s}=await ze(e,a.name);if(s.length===1){let h=s[0];d({kind:"note",tone:"ok",text:`Using your Document360 project "${h.name??h.id}".`}),Hn(a.name,{id:h.id,name:h.name});return}if(s.length>1){let h=s.map(u=>({id:u.id,name:u.name??u.id,sub:u.sub_domain}));d({kind:"note",tone:"info",text:"Which Document360 project should these docs publish to?"}),st({cursor:0,current:-1,rows:h,profile:a.name,environment:a.connection.name});return}}catch{}d({kind:"note",tone:"info",text:"Next: pick the Document360 project \u2014 run /project."}),z("/project")}},[e,d,Fn,Hn,z]),qn=V(()=>{let l=Ae.current[0];if(!l)return;d({kind:"note",tone:"info",text:`\u25CF ${l.title} (${l.path})`});for(let s of l.notes)d({kind:"note",tone:"warn",text:`\u26A0 ${s}`});l.overwritesLocalChanges&&d({kind:"note",tone:"warn",text:"\u26A0 This OVERWRITES local edits made since the last sync."});let a=pt(l.oldContent,l.newContent,Be());d(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."}),d({kind:"note",tone:"info",text:`Write ${l.path}? (y/n \u2014 anything else cancels)`})},[d,Be]),Ns=V(l=>{if(Ae.current.length===0)return!1;let a=l.trim().toLowerCase();if(a==="y"||a==="yes"){let s=Ae.current.shift();try{ng({cwd:e,profileName:i},s),d({kind:"note",tone:"ok",text:`\u2713 Pulled ${s.path} (sync base advanced).`}),Ae.current.length===0&&z("/pull")}catch(h){d({kind:"note",tone:"error",text:`Pull failed: ${h.message}`})}}else if(a==="n"||a==="no"){let s=Ae.current.shift();d({kind:"note",tone:"info",text:`Skipped ${s.path}.`})}else{let s=Ae.current.length;return Ae.current=[],d({kind:"note",tone:"info",text:`Pull cancelled (${s} article(s) left untouched).`}),!0}return qn(),!0},[e,i,qn,d]),Is=V(l=>{let a=jn.current;if(!a)return!1;if(jn.current=null,Ve(),l.trim()!==a.repoName)return d({kind:"note",tone:"warn",text:"Reset cancelled \u2014 nothing deleted."}),!0;let{removed:s,failed:h}=Ni(e,a.targets);d({kind:"note",tone:h.length?"warn":"ok",text:`\u2713 Reset complete \u2014 removed ${s.length} item${s.length===1?"":"s"}. The repo is back to its original state.`});for(let u of h)d({kind:"note",tone:"error",text:` \u2717 ${u.path}: ${u.error}`});return a.hadDevhints&&(d({kind:"note",tone:"warn",text:lo().join(`
318
318
  `)}),jt(vr())),d({kind:"note",tone:"info",text:`Clean slate \u2014 set up d360-writer again whenever you're ready:
319
- ${Qc}`}),z("/init"),Tn(!1),!0},[e,d,jt,Ve,z]),Bn=V(async l=>{let a=l.slice(1).trim().split(/\s+/),s=(a[0]??"").toLowerCase(),h=a.slice(1);if(Tn(!0),ko(h)&&["write","check","review","reorder"].includes(s)){let u=Jr(e,i);if(u.length===0){d({kind:"note",tone:"warn",text:"No categories yet \u2014 author some articles first, then scope to one."});return}let m=b=>s==="write"?`/write ${Xa(h,b).join(" ")}`.trim():`/${s} ${[b,...h.filter(y=>y!=="--scope")].join(" ")}`.trim();if(u.length===1){Bn(m(u[0].token));return}Pt({cursor:0,rows:u,run:b=>{Bn(m(b))}});return}switch(s){case"help":Xt({tab:0});return;case"exit":case"quit":Ce.current?.close(),r();return;case"clear":ke(),bt.current=[],Tn(!1),Ve(),d({kind:"note",tone:"info",text:"Conversation reset (the previous session is still resumable via /resume)."});return;case"login":{let u;try{u=$e(e,i)}catch(m){d({kind:"note",tone:"error",text:m.message});return}d({kind:"note",tone:"info",text:`Profile "${u.name}" \u2192 ${u.connection.name} (${u.connection.apiUrl})${u.production?" \u26A0 PRODUCTION":""}`}),K(!0);try{let m=await Uh(u.connection,{promptForRedirect:()=>Promise.reject(new Error("Manual login is CLI-only. Run: d360-writer login --manual"))},y=>d({kind:"note",tone:"info",text:y})),b=Wh(u.name,m);if(Fh(b),await wr(b,u.name,y=>d({kind:"note",tone:"info",text:y})),d({kind:"note",tone:"ok",text:`\u2713 Logged in to "${u.name}" as ${Zn(b)}`}),await Es(i),Kt.current){let y=Kt.current;Kt.current=null;let v=Fe(e,i);v.ok?(d({kind:"note",tone:"ok",text:`\u2713 Signed into the right project \u2014 tab to run ${y}.`}),z(y)):(d({kind:"note",tone:"warn",text:`${v.reason} (then ${y}.)`}),z("/login"),Kt.current=y)}else In.current&&(me(In.current,"\u21E5 tab to re-send your last prompt\u2026"),In.current=null)}catch(m){d({kind:"note",tone:"error",text:`Login failed: ${m.message}`})}finally{K(!1),Z(m=>m+1)}return}case"allow-prod":{let u=!1;try{u=$e(e,i).production}catch{}if(!u){d({kind:"note",tone:"info",text:"Current profile is not production \u2014 writes are already allowed."});return}xt.current=!0,ke(),d({kind:"note",tone:"warn",text:"\u26A0 Production writes authorized for this session."});return}case"rename":{let u=hi(h.join(" ")),m=_e.current.uuid;if(!m){if(!u){d({kind:"note",tone:"info",text:"Usage: /rename <name>"});return}er.current=u,ot(u),Ht(`${Wo} ${u}`),d({kind:"note",tone:"ok",text:`Session will be named "${u}" once it starts.`});return}if(!u){d({kind:"note",tone:"info",text:"Thinking of a name\u2026"});let b=_e.current.firstPrompt??"";Uc(b,e).then(y=>{y?(me(`/rename ${y}`),d({kind:"note",tone:"info",text:`Suggestion: "${y}" \u2014 press tab to accept, or type /rename <your name>.`})):d({kind:"note",tone:"info",text:"Usage: /rename <name>"})}).catch(()=>d({kind:"note",tone:"info",text:"Usage: /rename <name>"}));return}Jh(m,u),ot(u),Ht(`${Wo} ${u}`),d({kind:"note",tone:"ok",text:`Session renamed to "${u}".`});return}case"profile":{let u=h[0],m=te(e);if(!u){let b=Object.entries(m?.profiles??{});if(b.length===0){d({kind:"note",tone:"info",text:"No profiles. Run /init first."});return}let y=b.map(([Y,H])=>({name:Y,env:H.connection?.environment??"custom",prod:H.production===!0,who:fr(Y)})),v=i??m?.defaultProfile,T=Math.max(0,y.findIndex(Y=>Y.name===v));$t({cursor:T,current:T,rows:y});return}if(u==="add"){let b=gi(e,h[1],h[2]);if(b){d({kind:"note",tone:"error",text:b});return}d({kind:"note",tone:"ok",text:`\u2713 Profile "${h[1]}" created (environment: ${h[2]??h[1]}).`}),mr(h[1],!1);return}if(!m?.profiles?.[u]){d({kind:"note",tone:"error",text:`Unknown profile "${u}". Create it: /profile add ${u} <environment>`});return}mr(u,!0);return}case"doctor":await mn(h,{cwd:e});return;case"genre":{await Do(h,{cwd:e});try{Xo.current=!(te(e)?.appType??tg(e))}catch{}Z(u=>u+1);return}case"roadmap":{if(h[0]?.toLowerCase()==="done"){let u=Wi(e,h.slice(1).join(" ").trim());d({kind:"note",tone:u.ok?"ok":"warn",text:u.line}),Z(m=>m+1);return}d({kind:"note",tone:"info",text:Ui(e).join(`
319
+ ${Qc}`}),z("/init"),Tn(!1),!0},[e,d,jt,Ve,z]),Bn=V(async l=>{let a=l.slice(1).trim().split(/\s+/),s=(a[0]??"").toLowerCase(),h=a.slice(1);if(Tn(!0),ko(h)&&["write","check","review","reorder"].includes(s)){let u=Jr(e,i);if(u.length===0){d({kind:"note",tone:"warn",text:"No categories yet \u2014 author some articles first, then scope to one."});return}let m=b=>s==="write"?`/write ${Xa(h,b).join(" ")}`.trim():`/${s} ${[b,...h.filter(y=>y!=="--scope")].join(" ")}`.trim();if(u.length===1){Bn(m(u[0].token));return}Pt({cursor:0,rows:u,run:b=>{Bn(m(b))}});return}switch(s){case"help":Xt({tab:0});return;case"exit":case"quit":Ce.current?.close(),r();return;case"clear":ke(),bt.current=[],Tn(!1),Ve(),console.log("\x1B[?2026h\x1B[H\x1B[2J\x1B[3J\x1B[?2026l"),d({kind:"note",tone:"info",text:"Conversation reset (the previous session is still resumable via /resume)."});return;case"login":{let u;try{u=$e(e,i)}catch(m){d({kind:"note",tone:"error",text:m.message});return}d({kind:"note",tone:"info",text:`Profile "${u.name}" \u2192 ${u.connection.name} (${u.connection.apiUrl})${u.production?" \u26A0 PRODUCTION":""}`}),K(!0);try{let m=await Uh(u.connection,{promptForRedirect:()=>Promise.reject(new Error("Manual login is CLI-only. Run: d360-writer login --manual"))},y=>d({kind:"note",tone:"info",text:y})),b=Wh(u.name,m);if(Fh(b),await wr(b,u.name,y=>d({kind:"note",tone:"info",text:y})),d({kind:"note",tone:"ok",text:`\u2713 Logged in to "${u.name}" as ${Zn(b)}`}),await Es(i),Kt.current){let y=Kt.current;Kt.current=null;let v=Fe(e,i);v.ok?(d({kind:"note",tone:"ok",text:`\u2713 Signed into the right project \u2014 tab to run ${y}.`}),z(y)):(d({kind:"note",tone:"warn",text:`${v.reason} (then ${y}.)`}),z("/login"),Kt.current=y)}else In.current&&(me(In.current,"\u21E5 tab to re-send your last prompt\u2026"),In.current=null)}catch(m){d({kind:"note",tone:"error",text:`Login failed: ${m.message}`})}finally{K(!1),Z(m=>m+1)}return}case"allow-prod":{let u=!1;try{u=$e(e,i).production}catch{}if(!u){d({kind:"note",tone:"info",text:"Current profile is not production \u2014 writes are already allowed."});return}xt.current=!0,ke(),d({kind:"note",tone:"warn",text:"\u26A0 Production writes authorized for this session."});return}case"rename":{let u=hi(h.join(" ")),m=_e.current.uuid;if(!m){if(!u){d({kind:"note",tone:"info",text:"Usage: /rename <name>"});return}er.current=u,ot(u),Ht(`${Wo} ${u}`),d({kind:"note",tone:"ok",text:`Session will be named "${u}" once it starts.`});return}if(!u){d({kind:"note",tone:"info",text:"Thinking of a name\u2026"});let b=_e.current.firstPrompt??"";Uc(b,e).then(y=>{y?(me(`/rename ${y}`),d({kind:"note",tone:"info",text:`Suggestion: "${y}" \u2014 press tab to accept, or type /rename <your name>.`})):d({kind:"note",tone:"info",text:"Usage: /rename <name>"})}).catch(()=>d({kind:"note",tone:"info",text:"Usage: /rename <name>"}));return}Jh(m,u),ot(u),Ht(`${Wo} ${u}`),d({kind:"note",tone:"ok",text:`Session renamed to "${u}".`});return}case"profile":{let u=h[0],m=te(e);if(!u){let b=Object.entries(m?.profiles??{});if(b.length===0){d({kind:"note",tone:"info",text:"No profiles. Run /init first."});return}let y=b.map(([Y,H])=>({name:Y,env:H.connection?.environment??"custom",prod:H.production===!0,who:fr(Y)})),v=i??m?.defaultProfile,T=Math.max(0,y.findIndex(Y=>Y.name===v));$t({cursor:T,current:T,rows:y});return}if(u==="add"){let b=gi(e,h[1],h[2]);if(b){d({kind:"note",tone:"error",text:b});return}d({kind:"note",tone:"ok",text:`\u2713 Profile "${h[1]}" created (environment: ${h[2]??h[1]}).`}),mr(h[1],!1);return}if(!m?.profiles?.[u]){d({kind:"note",tone:"error",text:`Unknown profile "${u}". Create it: /profile add ${u} <environment>`});return}mr(u,!0);return}case"doctor":await mn(h,{cwd:e});return;case"genre":{await Do(h,{cwd:e});try{Xo.current=!(te(e)?.appType??tg(e))}catch{}Z(u=>u+1);return}case"roadmap":{if(h[0]?.toLowerCase()==="done"){let u=Wi(e,h.slice(1).join(" ").trim());d({kind:"note",tone:u.ok?"ok":"warn",text:u.line}),Z(m=>m+1);return}d({kind:"note",tone:"info",text:Ui(e).join(`
320
320
  `)});return}case"mcp":await po(h);return;case"init":{if(te(e)){d({kind:"note",tone:"info",text:"This repo is already set up \u2014 edit .d360-writer/config.json directly (or d360-writer init for the CLI wizard)."});return}let u=lg().map(m=>({name:m,apiUrl:cg(m).apiUrl}));vt({cursor:0,rows:u});return}case"resume":{let u=h.join(" ").trim(),m=Qh(e).filter(v=>v.uuid!==_e.current.uuid);if(!u){if(!m.length){d({kind:"note",tone:"info",text:"No saved sessions for this repo yet."});return}ct({query:"",cursor:0,sessions:m});return}let b=Xh(e,u);if(!b){d({kind:"note",tone:"error",text:`No session matches "${u}".`});return}ke(b.uuid),_e.current={uuid:b.uuid,firstPrompt:b.firstPrompt,titleFired:!0},ot(b.name),is(b.uuid),bt.current=[];let y=Zi(e,b.uuid);for(let v of y)d(v);d({kind:"note",tone:"ok",text:y.length?`Resumed "${b.name}" \u2014 restored ${y.length} message(s); continue where you left off.`:`Resumed "${b.name}" (agent memory reconnected; no saved transcript to replay).`});return}case"workspace":{let u=h.join(" ").trim(),m;try{m=await rn(e,i)}catch(y){d({kind:"note",tone:"error",text:`Could not list workspaces: ${y.message}`});return}if(!u){let y=m.workspaces.map(T=>({id:T.id,name:T.name??T.id,type:T.workspace_type}));if(y.length===0){d({kind:"note",tone:"info",text:"No workspaces in this project."});return}let v=Math.max(0,y.findIndex(T=>T.id===m.current));Ct({cursor:v,current:v,rows:y,profile:m.profile,projectId:m.projectId,projectName:m.projectName,environment:m.environment});return}let b=gr(m.workspaces,u);if(!b){d({kind:"note",tone:"error",text:`No workspace matches "${u}".`});return}Wn(m.profile,m.projectId,b);return}case"project":{let u=h.join(" ").trim(),m;try{m=await ze(e,i)}catch(y){d({kind:"note",tone:"error",text:`Could not list projects: ${y.message} (signed in? try /login)`});return}if(!u){let y=m.projects.map(T=>({id:T.id,name:T.name??T.id,sub:T.sub_domain}));if(y.length===0){d({kind:"note",tone:"info",text:"No projects found for this identity."});return}let v=y.findIndex(T=>T.id===m.current);st({cursor:Math.max(0,v),current:v,rows:y,profile:m.profile,environment:m.environment});return}let b=yr(m.projects,u);if(!b){d({kind:"note",tone:"error",text:`No project matches "${u}". Available: ${m.projects.map(y=>y.name??y.id).join(", ")}`});return}Hn(m.profile,b);return}case"logout":{let u;try{u=$e(e,i).name}catch(b){d({kind:"note",tone:"error",text:b.message});return}let m=Vh(u);Gh(e,u),ke(),Z(b=>b+1),d({kind:"note",tone:m?"ok":"info",text:m?`\u2713 Signed out of "${u}" and cleared its project/workspace selection.`:`Profile "${u}" was not signed in. Cleared any project/workspace selection.`}),d({kind:"note",tone:"info",text:"Run /login to sign in and pick a project."}),z("/login");return}case"publish":{if(!ar(l.trim()))return;if(h[0]==="--related"&&h[1]){let m=await ho(e,i,h[1].replace(/\\/g,"/"));if(m.length===0){d({kind:"note",tone:"ok",text:"\u2713 All related articles are already published."});return}await Un(m);return}if(h[0]&&h[0]!=="--all"){await pr(h[0]);return}let u=h[0]==="--all";d({kind:"note",tone:"info",text:"Checking what needs publishing\u2026"});try{let m=await Hc({cwd:e,profileName:i}),b=dn(m.entries),y=fo(m.entries);if(y>0&&d({kind:"note",tone:"warn",text:`\u26A0 ${y} article${y===1?"":"s"} already exist on Document360 but aren\u2019t linked \u2014 left OUT of publish (publishing would duplicate them). Run /catch-up (or ask me to link them) first.`}),b.length===0){d({kind:"note",tone:"ok",text:y>0?"\u2713 Nothing else is ahead of Document360 to publish.":"\u2713 Nothing is ahead of Document360 \u2014 no publish candidates."});let v=m.counts["unknown-base"]??0;v>0&&d({kind:"note",tone:"info",text:`(${v} article(s) have no sync base yet \u2014 publish those by path if needed.)`}),$s("Reconciling structure on Document360 (order + related articles)\u2026");try{let T=await Yc({cwd:e,profileName:i}),Y=Xc(await Kc({cwd:e,profileName:i})),H=zc(T);H?d({kind:"note",tone:"info",text:H}):T.skipped&&d({kind:"note",tone:"warn",text:`Order sync skipped: ${T.skipped}`}),Y&&d({kind:"note",tone:"info",text:Y}),d({kind:"note",tone:"ok",text:H||Y?"\u2713 Structure synced to Document360 \u2014 /structure shows the new category + article order.":"\u2713 Already in order \u2014 nothing to change."}),(H||Y)&&z("/structure")}catch(T){d({kind:"note",tone:"warn",text:`Structure sync failed: ${T.message}`})}finally{$s(null)}return}if(u){await Un(b.map(v=>v.path));return}Rt({cursor:0,rows:La(b)})}catch(m){d({kind:"note",tone:"error",text:`Could not compute sync status: ${m.message}`}),d({kind:"note",tone:"info",text:"Publish a specific article: /publish <article-path>"})}return}case"preview":{let u=h.join(" ").trim();if(!u){let b=[];try{b=Object.keys(Fc(e,$e(e,i).name)?.articles??{})}catch{}if(b.length===0){d({kind:"note",tone:"info",text:"No tracked articles to pick from yet. Usage: /preview <path-to.md | article-id>"});return}at({query:"",cursor:0,paths:b});return}let m=Lh(u)?u:rs(e,u);if($n(m)){try{d({kind:"preview",name:vn(m),text:Zc(os(m,"utf8"))})}catch(b){d({kind:"note",tone:"error",text:`Could not read ${m}: ${b.message}`})}return}if(Ag.test(u)){try{let b=$e(e,i),y={profile:b.name,connection:b.connection},v=b.project.projectId??qh(y),T=await Bh(y,v,u);d({kind:"preview",name:T.title??u,text:T.content??"*(article has no content)*"})}catch(b){d({kind:"note",tone:"error",text:`Could not fetch article: ${b.message}`})}return}d({kind:"note",tone:"error",text:`"${u}" is neither a file (relative to ${e}) nor an article id.`});return}case"model":{let u=h[0]?.trim();if(!u){let v=xo(us(e));it({cursor:v,current:v});return}let{lines:m,changed:b,effective:y}=fn(e,u);for(let v of m)d({kind:"note",tone:v.startsWith("\u26A0")?"warn":v.startsWith("\u2713")?"ok":"info",text:v});b&&(Rs(v=>v+1),Ce.current?.setModel(y));return}case"convert":{if(!te(e)){d({kind:"note",tone:"error",text:"No d360-writer config here. Run /init first."});return}let{scope:u,run:m}=Vr(h),b=pg(e,i);if(b.length===0){d({kind:"note",tone:"error",text:"No tracked articles in d360-category-map.json. Publish some first (/publish), then /convert."});return}let y=Gr(b,u);if(y.length===0){d({kind:"note",tone:"error",text:`No tracked articles under "${u}". (${b.length} are tracked overall.)`});return}let v=ss(y),T=3,Y=`/convert${u?` --scope ${u}`:""} --run`,H=Yo(e,"light");if(!m){let C=Bc({files:Yr(e,y),op:"convert",model:H.model}),E=u?`Scope: ${u} (${y.length} of ${b.length} tracked)
321
321
  `:"",q=`
322
322
  Model: ${H.model}${H.forced?" (forced)":" \u2014 mechanical work; /model to override"}`;d({kind:"note",tone:"info",text:E+Kr(v,C,T).join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document360-writer",
3
- "version": "0.5.84",
3
+ "version": "0.5.85",
4
4
  "description": "Standalone documentation agent CLI. Reads your code, writes your docs. Specialized for Document360 publishing.",
5
5
  "type": "module",
6
6
  "bin": {