@manan_joshi/atelier 0.1.4 → 0.2.0

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 (3) hide show
  1. package/README.md +3 -14
  2. package/dist/index.js +21 -11
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -30,25 +30,14 @@ atl login
30
30
  atl whoami
31
31
  atl scan
32
32
  atl save <id-or-path>
33
+ atl apply <id-or-path> --preview
34
+ atl apply <id-or-path> --backup
35
+ atl profile switch <name> --preview
33
36
  atl saved list
34
37
  atl saved show <stable-id>
35
38
  atl logout
36
39
  ```
37
40
 
38
- ## API
39
-
40
- The CLI defaults to the hosted Atelier API:
41
-
42
- ```text
43
- https://atelier.mananjoshi.me/api
44
- ```
45
-
46
- For local development, override it with:
47
-
48
- ```bash
49
- ATELIER_API_URL=http://127.0.0.1:8787 atl login
50
- ```
51
-
52
41
  ## Security
53
42
 
54
43
  Saved config contents are encrypted locally before upload. Atelier stores encrypted snapshots and metadata, not plaintext config contents.
package/dist/index.js CHANGED
@@ -1,13 +1,23 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import{stdin as w,stdout as G}from"process";import{existsSync as Ct,readFileSync as St}from"fs";import{homedir as rn,platform as nn}from"os";import{join as q,resolve as on}from"path";import{Command as an}from"commander";import{execFileSync as j}from"child_process";import{chmodSync as $e,existsSync as ee,mkdirSync as Ae,readFileSync as me,rmSync as Mt,writeFileSync as ve}from"fs";import{homedir as _t,platform as Xt}from"os";import{dirname as xe,join as te}from"path";var Ce=te(_t(),".config","atelier"),h=te(Ce,"session.json"),C=te(Ce,"config.json"),re="dev.atelier.session",Yt="https://atelier.mananjoshi.me/api",Jt="Ov23liiscZlMXcJ2RLnd";function J(){return process.env.ATELIER_API_URL??Yt}function Wt(){return process.env.ATELIER_GITHUB_CLIENT_ID??Jt}async function Se(e){let t=e.apiUrl??J(),r=e.clientId??Wt(),n=await Qt(r);await e.onPrompt({verificationUri:n.verification_uri,userCode:n.user_code,expiresIn:n.expires_in});let a=await Ot(r,n,e.onPoll),i=await fetch(`${t}/auth/github/exchange`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({githubAccessToken:a})});if(!i.ok)throw new Error(`Atelier API rejected GitHub login (${i.status})`);let c=await i.json();return It({apiUrl:t,user:c.user,token:c.token}),{apiUrl:t,user:c.user}}async function Re(){let e=S();if(!e)return;let t=await fetch(`${e.apiUrl}/me`,{headers:{authorization:`Bearer ${e.token}`}});if(!t.ok)return;return{user:(await t.json()).user,apiUrl:e.apiUrl}}function S(){let e=W();if(!e)return;let t=Nt(e);if(!t)return;return{apiUrl:e.apiUrl,user:e.user,token:t}}function y(){return ke().activeProfile??"personal"}function ne(e){Lt({...ke(),activeProfile:e})}function Ue(){let e=W();if(e?.tokenStorage==="keychain")Ht(e.user.id);if(ee(h))Mt(h)}function W(){if(!ee(h))return;return JSON.parse(me(h,"utf-8"))}function ke(){if(!ee(C))return{};return JSON.parse(me(C,"utf-8"))}function Lt(e){Ae(xe(C),{recursive:!0}),ve(C,JSON.stringify(e,null,2)+`
4
- `,"utf-8"),$e(C,384)}function It(e){Ae(xe(h),{recursive:!0});let t=Xt()==="darwin",r={apiUrl:e.apiUrl,user:e.user,tokenStorage:t?"keychain":"file",createdAt:new Date().toISOString()};if(t)Gt(e.user.id,e.token);else r.token=e.token;ve(h,JSON.stringify(r,null,2)+`
5
- `,"utf-8"),$e(h,384)}function Nt(e){if(e.tokenStorage==="file")return e.token;return qt(e.user.id)}async function Qt(e){let t=await fetch("https://github.com/login/device/code",{method:"POST",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({client_id:e,scope:"read:user user:email"})});if(!t.ok)throw new Error(`GitHub device-code request failed (${t.status})`);return t.json()}async function Ot(e,t,r){let n=t.interval,a=Date.now()+t.expires_in*1000;while(Date.now()<a){await Ft(n*1000),await r?.("Waiting for GitHub authorization\u2026");let i=await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({client_id:e,device_code:t.device_code,grant_type:"urn:ietf:params:oauth:grant-type:device_code"})});if(!i.ok)throw new Error(`GitHub token polling failed (${i.status})`);let c=await i.json();if(c.access_token)return c.access_token;if(c.error==="authorization_pending")continue;if(c.error==="slow_down"){n+=5;continue}if(c.error==="access_denied")throw new Error("GitHub login was denied");if(c.error==="expired_token")throw new Error("GitHub login code expired");throw new Error(c.error_description??"GitHub login failed")}throw new Error("GitHub login timed out")}function Gt(e,t){j("security",["add-generic-password","-a",e,"-s",re,"-w",t,"-U"],{stdio:"ignore"})}function qt(e){try{return j("security",["find-generic-password","-a",e,"-s",re,"-w"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return}}function Ht(e){try{j("security",["delete-generic-password","-a",e,"-s",re],{stdio:"ignore"})}catch{}}function Ft(e){return new Promise((t)=>setTimeout(t,e))}async function Ze(){return(await(await p("/profiles")).json()).profiles}async function Me(e){return(await(await p("/profiles",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e})})).json()).profile}async function R(e){let t=await p(`/profiles/${encodeURIComponent(e)}`);if(t.status===404)return;return(await t.json()).profile}async function U(){return await(await p("/vault")).json()}async function _e(e){await p("/vault",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}async function Xe(e){let t=await p(`/profiles/${encodeURIComponent(e)}/key`);if(t.status===404)return;return(await t.json()).profileKey}async function oe(e,t){return(await(await p(`/profiles/${encodeURIComponent(e)}/key`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(t)})).json()).profileKey}async function Ye(e){return(await(await p(`/profiles/${encodeURIComponent(e)}/configs`)).json()).configs}async function Je(e,t){let r=await p(`/profiles/${encodeURIComponent(e)}/configs/${encodeURIComponent(t)}`);if(r.status===404)return;return(await r.json()).config}async function We(e,t,r){return await(await p(`/profiles/${encodeURIComponent(e)}/configs/${encodeURIComponent(t)}/versions`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})).json()}async function p(e,t={}){let r=S();if(!r)throw new Error("Not logged in. Run `atl login`.");let n=await fetch(`${r.apiUrl}${e}`,{...t,headers:{...t.headers,authorization:`Bearer ${r.token}`}});if(!n.ok&&n.status!==404){let a=await n.json().catch(()=>{return});throw new Error(a?.error??`Atelier API request failed (${n.status})`)}return n}import{createCipheriv as yr,createHash as br,randomBytes as pr}from"crypto";import{readFile as wr}from"fs/promises";import{execFileSync as le}from"child_process";import{createCipheriv as Pt,createDecipheriv as Vt,randomBytes as k,scryptSync as Dt}from"crypto";import{chmodSync as Et,existsSync as Ie,mkdirSync as jt,readFileSync as er,rmSync as tr,writeFileSync as rr}from"fs";import{homedir as nr,platform as se}from"os";import{dirname as or,join as Ne}from"path";var fe="dev.atelier.vault",ir=Ne(nr(),".config","atelier"),B=Ne(ir,"vault-key.json"),Le={N:32768,r:8,p:1},ar=67108864,ie="aes-256-gcm";async function ge(){let e=A();return{initialized:(await U()).initialized,unlocked:Boolean(ce(e.user.id)),activeProfile:y()}}async function ue(e,t=y()){lr(e);let r=A();if((await U()).initialized)throw new Error("Atelier vault already exists. Run `atl vault unlock` if this machine is locked.");let a=await R(t);if(!a)throw new Error(`Profile not found: ${t}`);let i=k(32),c=k(32),f=k(16),D=He(e,f,Le),E=ae(i,D),x=ae(c,i);return await _e({kdf:{algorithm:"scrypt",salt:L(f),params:Le},encryptedVaultKey:E}),await oe(t,{version:1,algorithm:x.algorithm,nonce:x.nonce,encryptedKey:x.ciphertext}),de(r.user.id,i),{profileName:a.name}}async function Qe(e){let t=A(),r=await U();if(!r.initialized)throw new Error("Atelier vault is not initialized. Run `atl save <id>` or `atl vault init`.");let n=qe(r,e);return de(t.user.id,n),{activeProfile:y()}}function Oe(){let e=A();sr(e.user.id)}async function cr(e,t=y()){let r=A(),n=ce(r.user.id);if(n)return n;if(!e)throw new Error("Vault passphrase is required");let a=await U();if(!a.initialized){await ue(e,t);let i=ce(r.user.id);if(!i)throw new Error("Vault initialized but local key was not stored");return i}return qe(a,e)}async function Ge(e,t=y()){let r=await cr(e,t),n=await Xe(t);if(n)return Fe(n.encryptedKey,n.nonce,r);let a=k(32),i=ae(a,r);return await oe(t,{version:1,algorithm:i.algorithm,nonce:i.nonce,encryptedKey:i.ciphertext}),a}function qe(e,t){if(!e.kdf||!e.encryptedVaultKey)throw new Error("Vault payload is incomplete");if(e.kdf.algorithm!=="scrypt")throw new Error(`Unsupported vault KDF: ${e.kdf.algorithm}`);let r=I(e.kdf.salt),n=He(t,r,e.kdf.params),a=Fe(e.encryptedVaultKey.ciphertext,e.encryptedVaultKey.nonce,n);return de(A().user.id,a),a}function He(e,t,r){return Dt(e,t,32,{N:r.N,r:r.r,p:r.p,maxmem:ar})}function ae(e,t){let r=k(12),n=Pt(ie,t,r),a=Buffer.concat([n.update(e),n.final()]),i=n.getAuthTag();return{algorithm:ie,nonce:L(r),ciphertext:L(Buffer.concat([a,i]))}}function Fe(e,t,r){let n=Buffer.from(I(e)),a=Buffer.from(I(t)),i=n.subarray(0,-16),c=n.subarray(-16),f=Vt(ie,r,a);return f.setAuthTag(c),Buffer.concat([f.update(i),f.final()])}function lr(e){if(e.length<12)throw new Error("Vault passphrase must be at least 12 characters.")}function A(){let e=S();if(!e)throw new Error("Not logged in. Run `atl login`.");return e}function de(e,t){let r=L(t);if(se()==="darwin"){le("security",["add-generic-password","-a",e,"-s",fe,"-w",r,"-U"],{stdio:"ignore"});return}jt(or(B),{recursive:!0}),rr(B,JSON.stringify({userId:e,key:r},null,2)+`
6
- `,"utf-8"),Et(B,384)}function ce(e){let t=se()==="darwin"?fr(e):gr(e);return t?Buffer.from(I(t)):void 0}function sr(e){if(se()==="darwin"){try{le("security",["delete-generic-password","-a",e,"-s",fe],{stdio:"ignore"})}catch{}return}if(Ie(B))tr(B)}function fr(e){try{return le("security",["find-generic-password","-a",e,"-s",fe,"-w"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return}}function gr(e){if(!Ie(B))return;let t=JSON.parse(er(B,"utf-8"));return t.userId===e?t.key:void 0}function L(e){return Buffer.from(e).toString("base64url")}function I(e){return new Uint8Array(Buffer.from(e,"base64url"))}function Pe(e){let t=[];if(!e.exists)t.push("file does not exist");if(e.isDirectory||e.kind==="directory"||e.format==="directory")t.push("directory saving is not supported yet");if(e.kind==="generated")t.push("generated/cache files are not saved");if(e.kind==="private"||e.shareability==="private")t.push("private/auth files are blocked");if(e.secretFindings.length>0)t.push("detected secret material");if(e.size!==void 0&&e.size>1048576)t.push(`file is larger than ${dr(1048576)}`);if(ur(e))t.push("binary files are not supported yet");return{ok:t.length===0,reasons:t}}function ye(e){let t=Pe(e);if(!t.ok)throw new Error(`Cannot save ${e.id}: ${t.reasons.join("; ")}`)}function ur(e){if(e.previewSuppressedReason?.toLowerCase().includes("binary"))return!0;return["binary","sqlite","db"].includes(e.format.toLowerCase())}function dr(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${Math.round(t)} KiB`;return`${Math.round(t/1024)} MiB`}var Ve="aes-256-gcm";async function je(e,t={}){ye(e);let r=y(),n=await Ge(t.passphrase,r),a=await wr(e.path),i=hr(a,n),c=await We(r,e.id,{kind:"file",pathHint:e.displayPath,contentSha256:De(a),ciphertextSha256:De(i.ciphertextBytes),sizeBytes:a.byteLength,algorithm:i.algorithm,profileKeyVersion:1,nonce:i.nonce,ciphertext:i.ciphertext});return{profileName:r,stableId:e.id,version:c.version,reused:c.reused}}function hr(e,t){let r=pr(12),n=yr(Ve,t,r),a=Buffer.concat([n.update(e),n.final()]),i=n.getAuthTag(),c=Buffer.concat([a,i]);return{algorithm:Ve,nonce:Ee(r),ciphertext:Ee(c),ciphertextBytes:c}}function De(e){return br("sha256").update(e).digest("hex")}function Ee(e){return Buffer.from(e).toString("base64url")}import{execFileSync as ct}from"child_process";import{existsSync as K,lstatSync as Tr,mkdirSync as $r,readdirSync as we,readFileSync as Z,statSync as m,writeFileSync as Ar}from"fs";import{homedir as mr,userInfo as vr}from"os";import{dirname as lt,join as z,relative as st,resolve as xr}from"path";var et=[{domain:"AI Tools",app:"Pi",items:[{id:"pi.dir",path:"~/.pi",kind:"directory",format:"directory",shareability:"machine-specific"}]},{domain:"Shell",app:"Starship",items:[{id:"starship.config",path:"~/.config/starship.toml",kind:"config",format:"toml",shareability:"shareable"}]},{domain:"Editors",app:"Zed",items:[{id:"zed.dir",path:"~/.config/zed",kind:"directory",format:"directory",shareability:"shareable"},{id:"zed.settings",path:"~/.config/zed/settings.json",kind:"config",format:"jsonc",shareability:"shareable"},{id:"zed.themes",path:"~/.config/zed/themes",kind:"config",format:"directory",shareability:"shareable"},{id:"zed.prompts",path:"~/.config/zed/prompts",kind:"generated",format:"directory",shareability:"machine-specific"}]},{domain:"Git",app:"Git",items:[{id:"git.config",path:"~/.gitconfig",kind:"config",format:"gitconfig",shareability:"machine-specific"},{id:"git.config-dir",path:"~/.config/git",kind:"directory",format:"directory",shareability:"machine-specific"},{id:"git.ignore",path:"~/.gitignore",kind:"config",format:"gitignore",shareability:"machine-specific"}]},{domain:"Private/Auth",app:"Credentials",privateByDefault:!0,items:[{id:"auth.ssh",path:"~/.ssh",kind:"private",format:"directory",shareability:"private"},{id:"auth.aws",path:"~/.aws",kind:"private",format:"directory",shareability:"private"},{id:"auth.gh",path:"~/.config/gh",kind:"private",format:"directory",shareability:"private"},{id:"auth.gcloud-adc",path:"~/.config/gcloud/application_default_credentials.json",kind:"private",format:"json",shareability:"private"},{id:"auth.docker",path:"~/.docker/config.json",kind:"private",format:"json",shareability:"private"},{id:"auth.pi",path:"~/.config/pi/auth.json",kind:"private",format:"json",shareability:"private"}]},{domain:"Shell",app:"Zsh",items:[{id:"zsh.home-rc",path:"~/.zshrc",kind:"config",format:"shell",shareability:"shareable"},{id:"zsh.home-env",path:"~/.zshenv",kind:"config",format:"shell",shareability:"private"},{id:"zsh.dir",path:"~/.config/zsh",kind:"directory",format:"directory",shareability:"machine-specific"},{id:"zsh.env",path:"~/.config/zsh/.zshenv",kind:"config",format:"shell",shareability:"private"},{id:"zsh.rc",path:"~/.config/zsh/.zshrc",kind:"config",format:"shell",shareability:"shareable"},{id:"zsh.conf",path:"~/.config/zsh/conf.d",kind:"directory",format:"directory",shareability:"shareable"},{id:"zsh.zcompdump",path:"~/.config/zsh/.zcompdump",kind:"generated",format:"text",shareability:"machine-specific"},{id:"zsh.sessions",path:"~/.config/zsh/.zsh_sessions",kind:"generated",format:"directory",shareability:"machine-specific"}]},{domain:"Terminals",app:"cmux",items:[{id:"cmux.dir",path:"~/.config/cmux",kind:"directory",format:"directory",shareability:"shareable"},{id:"cmux.config",path:"~/.config/cmux/cmux.json",kind:"config",format:"jsonc",shareability:"shareable"},{id:"cmux.ghostty",path:"~/Library/Application Support/com.cmuxterm.app/config.ghostty",kind:"config",format:"ghostty",shareability:"shareable"},{id:"cmux.browser-history",path:"~/Library/Application Support/com.cmuxterm.app/browser_history.json",kind:"generated",format:"json",shareability:"machine-specific"}]}];var be=[["GitHub token",/gh[pousr]_[A-Za-z0-9_]{20,}/g],["Slack token",/xox[baprs]-[A-Za-z0-9-]{20,}/g],["AWS access key",/AKIA[0-9A-Z]{16}/g],["Private key",/-----BEGIN (?:RSA |OPENSSH |EC |DSA )?PRIVATE KEY-----/g],["Generic token assignment",/(?:token|api[_-]?key|secret|webhook|password)\s*[=:]\s*["']?[^"'\s]{12,}/gi]];function tt(e){let t=[],r=e.split(/\r?\n/);for(let[n,a]of be)for(let i of e.matchAll(a)){let c=i.index??0,f=e.slice(0,c).split(/\r?\n/).length;t.push({type:n,line:f,preview:N(i[0])})}return r.forEach((n,a)=>{for(let i of n.matchAll(/[A-Za-z0-9_+\/=.-]{32,}/g)){let c=i[0];if(!Br(c,n)&&nt(c,n))t.push({type:"High-entropy string",line:a+1,preview:N(c)})}}),Kr(t)}function N(e){if(e.length<=8)return"[redacted]";return`${e.slice(0,4)}\u2026${e.slice(-4)}`}function rt(e){let t=e;for(let[,r]of be)t=t.replace(r,(n)=>N(n));return t=t.replace(/[A-Za-z0-9_+\/=.-]{32,}/g,(r)=>{if(nt(r,e))return N(r);return r}),t}function Br(e,t){return be.some(([,r])=>{return r.lastIndex=0,Array.from(t.matchAll(r)).some((n)=>n[0].includes(e)||e.includes(n[0]))})}function nt(e,t){if(e.startsWith("amazon."))return!1;if(e.includes("anthropic.claude"))return!1;if(/^[A-Za-z0-9.-]+@[A-Za-z0-9.-]+$/.test(e))return!1;if(/model/i.test(t)&&/^[A-Za-z0-9_.-]+$/.test(e))return!1;return zr(e)>4.2&&/[A-Za-z]/.test(e)&&/[0-9]/.test(e)}function zr(e){let t=new Map;for(let n of e)t.set(n,(t.get(n)??0)+1);let r=0;for(let n of t.values()){let a=n/e.length;r-=a*Math.log2(a)}return r}function Kr(e){let t=new Set;return e.filter((r)=>{let n=`${r.type}:${r.line}:${r.preview}`;if(t.has(n))return!1;return t.add(n),!0})}function ot(e){let n=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1").replace(/,\s*([}\]])/g,"$1");return JSON.parse(n)}var T=mr(),Cr=new Set([".zsh",".zshrc",".zshenv",".sh",".json",".jsonc",".toml",".md",".yml",".yaml",".gitconfig",".gitignore",".ghostty",""]),Sr=[/cache/i,/history/i,/session/i,/state/i,/\.mdb$/i,/\.sqlite/i,/\.db$/i,/zcompdump/i,/logs?/i],Rr=[/credential/i,/secret/i,/token/i,/auth\.json$/i,/hosts\.yml$/i,/config\.json$/i],O;async function ft(e){O=e.includeLegacyManagers?Nr():void 0;let r=Ur(e.repoRoot).flatMap((i)=>i.items.map((c)=>({definition:i,item:c}))),n=new Set,a=[];for(let{definition:i,item:c}of r){let f=pe(c.path);n.add(f),a.push(kr(i,c,f))}for(let i of Zr()){if(n.has(i.path))continue;n.add(i.path),a.push(it(i))}for(let i of e.manualPaths??[]){let c=pe(i);if(n.has(c))continue;n.add(c),a.push(it({path:c,reason:"manual path"}))}return a.sort((i,c)=>`${i.domain}:${i.app}:${i.path}`.localeCompare(`${c.domain}:${c.app}:${c.path}`)),{version:1,generatedAt:new Date().toISOString(),repoRoot:e.repoRoot,home:T,items:a,summary:{total:a.length,existing:a.filter((i)=>i.exists).length,secrets:a.filter((i)=>i.secretFindings.length>0).length,drift:a.filter((i)=>i.mirrors.some((c)=>c.exists&&c.identical===!1)).length,generated:a.filter((i)=>i.kind==="generated").length,private:a.filter((i)=>i.shareability==="private").length}}}function gt(e,t={}){let r=t.path??z(e.repoRoot,".atelier","state","inventory.json");return $r(lt(r),{recursive:!0}),Ar(r,JSON.stringify(e,null,2)+`
7
- `,"utf-8"),r}function Ur(e){let t=z(e,"packages","registry","definitions");if(!K(t))return et;return we(t).filter((r)=>r.endsWith(".jsonc")).map((r)=>ot(Z(z(t,r),"utf-8")))}function kr(e,t,r){return ut({path:r,domain:e.domain,app:e.app,kind:t.kind,format:t.format,shareability:t.shareability,reason:"registry match",mirrors:t.mirrors??[],privateByDefault:e.privateByDefault,id:t.id})}function it(e){let t=Or(e.path),r=qr(e.path),n=Hr(e.path,r);return ut({path:e.path,domain:Gr(e.path),app:t,kind:r,format:Fr(e.path),shareability:n,reason:e.reason,mirrors:[],privateByDefault:n==="private"})}function ut(e){let t=K(e.path),r=t?Tr(e.path):void 0,n=t?m(e.path):void 0,a=!!n?.isDirectory(),i=!!r?.isSymbolicLink(),c=t&&!a&&dt(e.path)?tt(Z(e.path,"utf-8")):[],f=e.mirrors.map((x)=>_r(e.path,pe(x))),D=Jr(e.kind,e.shareability,c.length,f),E=Yr(e.path,t,a,e.shareability,e.privateByDefault,e.kind);return{id:e.id??Qr(e.path),domain:e.domain,app:e.app,path:e.path,displayPath:M(e.path),kind:e.kind,format:e.format,shareability:e.shareability,exists:t,isDirectory:a,isSymlink:i,mode:n?`0${(n.mode&511).toString(8)}`:void 0,owner:t?vr().username:void 0,size:n?.size,git:t?Wr(e.path):void 0,legacyManagers:t?Lr(e.path):{},mirrors:f,secretFindings:c,...E,recommendation:D,reason:e.reason}}function Zr(){let e=[],t=z(T,".config");if(!K(t))return e;for(let r of we(t,{withFileTypes:!0})){if(r.name.startsWith("."))continue;let n=z(t,r.name);if(e.push({path:n,reason:"~/.config app directory"}),!r.isDirectory())continue;for(let a of Mr(n).slice(0,80)){let i=z(n,a.name);if(he(i)){e.push({path:i,reason:"generated/app-state candidate"});continue}if(a.isFile()&&Be(a.name))e.push({path:i,reason:"shallow ~/.config config candidate"});if(a.isDirectory()&&["conf.d","themes","snippets","plugins"].includes(a.name))e.push({path:i,reason:"shallow ~/.config config directory"})}}return e}function Mr(e){try{return we(e,{withFileTypes:!0})}catch{return[]}}function _r(e,t){let r=K(t);if(!r||!K(e)||m(e).isDirectory()||m(t).isDirectory())return{path:t,displayPath:M(t),exists:r};let n=Z(e,"utf-8"),a=Z(t,"utf-8");return{path:t,displayPath:M(t),exists:r,identical:n===a,diff:n===a?void 0:Xr(a,n)}}function Xr(e,t){let r=e.split(/\r?\n/),n=t.split(/\r?\n/),a=Math.max(r.length,n.length),i=[];for(let c=0;c<a;c++){if(r[c]===n[c])continue;if(r[c]!==void 0)i.push(`-${r[c]}`);if(n[c]!==void 0)i.push(`+${n[c]}`)}return i.slice(0,200).join(`
8
- `)}function Yr(e,t,r,n,a,i){if(!t)return{previewSuppressedReason:"missing"};if(r)return{previewSuppressedReason:"directory"};if(n==="private"||a||i==="private")return{previewSuppressedReason:"private/auth metadata-only"};if(!dt(e))return{previewSuppressedReason:"binary or unsupported file type"};let c=Z(e,"utf-8");return{preview:rt(c).slice(0,20000)}}function Jr(e,t,r,n){if(r>0)return"rotate-secret";if(e==="generated")return"ignore-generated";if(t==="private")return"mark-private";if(n.some((a)=>a.exists&&a.identical===!1))return"resolve-drift";if(t==="machine-specific")return"review-machine-specific";if(e==="config"||e==="directory")return"adopt-candidate";return"none"}function Wr(e){let t=m(e).isDirectory()?e:lt(e),r=Q(["rev-parse","--show-toplevel"],t);if(!r)return;let n=st(r,e),a=!!Q(["check-ignore","-q",n],r,!0),i=!!Q(["ls-files","--error-unmatch",n],r,!0),c=i&&!!Q(["status","--porcelain","--",n],r);return{root:r,tracked:i,modified:c,ignored:a}}function Lr(e){if(!O)return{};return{yadm:Ir(e)}}function Ir(e){let t=M(e).replace(/^~\//,"");if(O?.modified.has(t))return"modified";if(O?.tracked.has(t))return"tracked";return"unknown"}function Nr(){let e=new Set((at("yadm",["ls-files"])??"").split(`
9
- `).filter(Boolean)),t=new Set((at("yadm",["status","--porcelain"])??"").split(`
10
- `).map((r)=>r.slice(3).trim()).filter(Boolean));return{tracked:e,modified:t}}function Q(e,t,r=!1){try{return ct("git",e,{cwd:t,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||(r?"ok":void 0)}catch{return}}function at(e,t){try{return ct(e,t,{cwd:T,encoding:"utf-8",stdio:["ignore","pipe","ignore"]})}catch{return}}function pe(e){return xr(e.replace(/^~(?=\/|$)/,T))}function M(e){return e.startsWith(T)?`~${e.slice(T.length)}`:e}function Qr(e){return M(e).replace(/[^A-Za-z0-9_.-]+/g,":")}function Or(e){let t=st(z(T,".config"),e);if(!t.startsWith(".."))return t.split(/[\\/]/)[0]||"Unknown";return"Unknown"}function Gr(e){if(e.includes("/.config/"))return"~/.config";if(e.includes("/.ssh")||e.includes("/.aws"))return"Private/Auth";return"Unknown"}function qr(e){if(he(e))return"generated";if(Rr.some((t)=>t.test(e)))return"private";if(K(e)&&m(e).isDirectory())return"directory";if(Be(e))return"config";return"unknown"}function Hr(e,t){if(t==="private")return"private";if(t==="generated")return"machine-specific";if(e.includes("/credentials")||e.includes("/.ssh")||e.includes("/.aws"))return"private";return"machine-specific"}function Fr(e){if(K(e)&&m(e).isDirectory())return"directory";if(e.endsWith(".jsonc"))return"jsonc";if(e.endsWith(".json"))return"json";if(e.endsWith(".toml"))return"toml";if(e.endsWith(".zsh"))return"shell";if(e.endsWith(".md"))return"markdown";return"text"}function he(e){return Sr.some((t)=>t.test(e))}function Be(e){return/(^config\.|settings\.|rc$|\.rc$|\.zshrc$|\.zshenv$|\.jsonc?$|\.toml$|\.ya?ml$|\.zsh$|\.conf$|\.ini$)/i.test(e)}function dt(e){let t=e.split("/").pop()??"";if(he(e))return!1;if(t.includes("lock")||t.endsWith(".mdb")||t.endsWith(".sqlite")||t.endsWith(".db"))return!1;let r=t.includes(".")?t.slice(t.lastIndexOf(".")):"";return Cr.has(r)||Be(t)}import{Box as s,Text as l,render as Pr}from"ink";import{jsxDEV as o,Fragment as tn}from"react/jsx-dev-runtime";function g(e){return Pr(o(tn,{children:e},void 0,!1,void 0,this)).waitUntilExit()}function ze({inventory:e,path:t}){return o(s,{flexDirection:"column",gap:1,children:[o(b,{title:"Scan complete",subtitle:t},void 0,!1,void 0,this),o(s,{gap:2,children:[o(v,{label:"total",value:e.summary.total,color:"cyan"},void 0,!1,void 0,this),o(v,{label:"existing",value:e.summary.existing,color:"green"},void 0,!1,void 0,this),o(v,{label:"private",value:e.summary.private,color:"red"},void 0,!1,void 0,this),o(v,{label:"generated",value:e.summary.generated,color:"magenta"},void 0,!1,void 0,this),o(v,{label:"secrets",value:e.summary.secrets,color:"red"},void 0,!1,void 0,this),o(v,{label:"drift",value:e.summary.drift,color:"blue"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function yt({items:e,title:t}){return o(s,{flexDirection:"column",children:[o(b,{title:t,subtitle:`${e.length} item${e.length===1?"":"s"}`},void 0,!1,void 0,this),o(s,{flexDirection:"column",marginTop:1,children:e.map((r)=>o(s,{gap:1,children:[o(l,{color:r.exists?"white":"gray",children:r.exists?"\u25CF":"\u25CB"},void 0,!1,void 0,this),o(l,{color:mt(r),children:r.domain},void 0,!1,void 0,this),o(l,{color:"gray",children:"/"},void 0,!1,void 0,this),o(l,{color:"cyan",children:r.app},void 0,!1,void 0,this),o(l,{children:r.displayPath},void 0,!1,void 0,this),o($,{label:r.shareability,color:vt(r.shareability)},void 0,!1,void 0,this),r.secretFindings.length>0?o($,{label:"secret",color:"red"},void 0,!1,void 0,this):null,r.mirrors.some((n)=>n.exists&&n.identical===!1)?o($,{label:"drift",color:"blue"},void 0,!1,void 0,this):null]},r.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function bt({item:e}){return o(s,{flexDirection:"column",gap:1,children:[o(b,{title:e.app,subtitle:e.displayPath},void 0,!1,void 0,this),o(s,{gap:1,children:[o($,{label:e.domain,color:"cyan"},void 0,!1,void 0,this),o($,{label:e.kind,color:mt(e)},void 0,!1,void 0,this),o($,{label:e.shareability,color:vt(e.shareability)},void 0,!1,void 0,this),o($,{label:e.recommendation,color:"yellow"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),o(Vr,{rows:[["reason",e.reason],["exists",String(e.exists)],["mode",e.mode??"\u2014"],["symlink",String(e.isSymlink)],["git",en(e)],["legacy",jr(e)]]},void 0,!1,void 0,this),e.secretFindings.length>0?o(s,{flexDirection:"column",children:[o(l,{color:"red",bold:!0,children:"Secret warnings"},void 0,!1,void 0,this),e.secretFindings.map((t,r)=>o(l,{color:"red",children:[" ",t.type,t.line?` line ${t.line}`:"",": ",t.preview]},`${t.type}-${r}`,!0,void 0,this))]},void 0,!0,void 0,this):null,e.mirrors.length>0?o(s,{flexDirection:"column",children:[o(l,{color:"blue",bold:!0,children:"Mirrors"},void 0,!1,void 0,this),e.mirrors.map((t)=>o(l,{children:[" ",t.displayPath," \u2014 ",t.exists?t.identical===!1?"differs":"identical":"missing"]},t.path,!0,void 0,this))]},void 0,!0,void 0,this):null,o(s,{flexDirection:"column",children:[o(l,{bold:!0,children:e.preview?"Safe preview":"Preview"},void 0,!1,void 0,this),o(l,{color:e.preview?"white":"gray",children:e.preview?e.preview.slice(0,3000):`Suppressed: ${e.previewSuppressedReason??"not available"}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function pt({verificationUri:e,userCode:t,expiresIn:r}){return o(s,{flexDirection:"column",gap:1,children:[o(b,{title:"Login with GitHub",subtitle:`code expires in ${Math.round(r/60)} minutes`},void 0,!1,void 0,this),o(s,{flexDirection:"column",children:[o(l,{children:"Open:"},void 0,!1,void 0,this),o(l,{color:"blue",underline:!0,children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this),o(s,{gap:1,children:[o(l,{children:"Enter code:"},void 0,!1,void 0,this),o(l,{color:"green",bold:!0,children:t},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function wt({login:e,apiUrl:t}){return o(s,{flexDirection:"column",children:[o(b,{title:"Logged in",subtitle:t},void 0,!1,void 0,this),o(l,{color:"green",children:["\u2713 ",e]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function ht({login:e,apiUrl:t}){if(!e)return o(l,{color:"yellow",children:"Not logged in. Run `atl login`."},void 0,!1,void 0,this);return o(s,{flexDirection:"column",children:[o(b,{title:"Current account",subtitle:t},void 0,!1,void 0,this),o(l,{color:"green",children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Bt(){return o(l,{color:"green",children:"\u2713 Logged out"},void 0,!1,void 0,this)}function zt({profiles:e,activeProfile:t}){return o(s,{flexDirection:"column",children:[o(b,{title:"Profiles",subtitle:`active: ${t}`},void 0,!1,void 0,this),o(s,{flexDirection:"column",marginTop:1,children:e.map((r)=>o(s,{gap:1,children:[o(l,{color:r.name===t?"green":"gray",children:r.name===t?"\u25CF":"\u25CB"},void 0,!1,void 0,this),o(l,{bold:r.name===t,children:r.name},void 0,!1,void 0,this),o(l,{color:"gray",children:r.createdAt},void 0,!1,void 0,this)]},r.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function _({title:e,name:t}){return o(s,{flexDirection:"column",children:[o(b,{title:e},void 0,!1,void 0,this),o(l,{color:"green",children:["\u2713 ",t]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Kt({configs:e,profileName:t}){return o(s,{flexDirection:"column",children:[o(b,{title:"Saved configs",subtitle:t},void 0,!1,void 0,this),e.length===0?o(l,{color:"gray",children:"No saved configs yet."},void 0,!1,void 0,this):e.map((r)=>o(s,{flexDirection:"column",marginTop:1,children:[o(l,{bold:!0,children:r.stableId},void 0,!1,void 0,this),o(l,{color:"gray",children:r.pathHint??"no path hint"},void 0,!1,void 0,this),r.latestVersion?o(l,{color:"green",children:[r.latestVersion.contentSha256.slice(0,12)," \xB7 ",r.latestVersion.sizeBytes," bytes \xB7 ",r.latestVersion.createdAt]},void 0,!0,void 0,this):null]},r.id,!0,void 0,this))]},void 0,!0,void 0,this)}function Tt({config:e,profileName:t}){return o(s,{flexDirection:"column",children:[o(b,{title:e.stableId,subtitle:t},void 0,!1,void 0,this),o(l,{color:"gray",children:e.pathHint??"no path hint"},void 0,!1,void 0,this),o(s,{flexDirection:"column",marginTop:1,children:(e.versions??[]).map((r)=>o(l,{children:[r.contentSha256.slice(0,12)," \xB7 ",r.sizeBytes," bytes \xB7 ",r.createdAt]},r.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $t({stableId:e,profileName:t,versionHash:r,sizeBytes:n,reused:a}){return o(s,{flexDirection:"column",children:[o(b,{title:a?"Config already saved":"Config saved",subtitle:t},void 0,!1,void 0,this),o(l,{color:"green",children:["\u2713 ",e]},void 0,!0,void 0,this),o(l,{color:"gray",children:["Version ",r.slice(0,12)," \xB7 ",n," bytes \xB7 encrypted"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function At({checks:e}){let t=e.filter((n)=>n.status==="fail").length,r=e.filter((n)=>n.status==="warn").length;return o(s,{flexDirection:"column",gap:1,children:[o(b,{title:"Doctor",subtitle:t?`${t} failing`:r?`${r} warning${r===1?"":"s"}`:"all checks passed"},void 0,!1,void 0,this),o(s,{flexDirection:"column",children:e.map((n)=>o(s,{gap:1,children:[o(l,{color:Er(n.status),children:Dr(n.status)},void 0,!1,void 0,this),o(l,{bold:!0,children:n.label},void 0,!1,void 0,this),o(l,{color:"gray",children:n.detail},void 0,!1,void 0,this)]},n.label,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Ke({query:e}){return o(l,{color:"red",children:["No inventory item matched: ",e]},void 0,!0,void 0,this)}function b({title:e,subtitle:t}){return o(s,{flexDirection:"column",children:[o(l,{bold:!0,color:"cyan",children:"\u25C6 Atelier"},void 0,!1,void 0,this),o(s,{gap:1,children:[o(l,{bold:!0,children:e},void 0,!1,void 0,this),t?o(l,{color:"gray",children:t},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function v({label:e,value:t,color:r}){return o(s,{flexDirection:"column",borderStyle:"round",borderColor:r,paddingX:1,children:[o(l,{color:r,bold:!0,children:t},void 0,!1,void 0,this),o(l,{color:"gray",children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $({label:e,color:t}){return o(l,{color:t,children:["[",e,"]"]},void 0,!0,void 0,this)}function Vr({rows:e}){return o(s,{flexDirection:"column",children:e.map(([t,r])=>o(s,{gap:1,children:[o(l,{color:"gray",children:t.padEnd(10)},void 0,!1,void 0,this),o(l,{children:r},void 0,!1,void 0,this)]},t,!0,void 0,this))},void 0,!1,void 0,this)}function mt(e){let t=typeof e==="string"?e:e.kind;if(t==="private")return"red";if(t==="generated")return"magenta";if(t==="config")return"green";return"yellow"}function vt(e){if(e==="private")return"red";if(e==="shareable")return"green";return"yellow"}function Dr(e){if(e==="pass")return"\u2713";if(e==="warn")return"!";return"\u2717"}function Er(e){if(e==="pass")return"green";if(e==="warn")return"yellow";return"red"}function jr(e){let t=Object.entries(e.legacyManagers??{});if(t.length===0)return"not scanned";return t.map(([r,n])=>`${r}: ${n}`).join(", ")}function en(e){if(!e.git)return"not in repo";return`${e.git.tracked?"tracked":"untracked"}${e.git.modified?", modified":""} @ ${e.git.root}`}import{jsxDEV as u}from"react/jsx-dev-runtime";var cn=on(import.meta.dir,"../../.."),Rt=ln(),X=q(Rt,"inventory.json"),xt,d=new an;d.name("atl").description("Atelier config management CLI").version("0.1.4");d.command("login").description("Login to Atelier with GitHub device auth").option("--api-url <url>","Atelier API URL",J()).action(async(e)=>{let t=await Se({apiUrl:e.apiUrl,onPrompt:async(r)=>{await g(u(pt,{verificationUri:r.verificationUri,userCode:r.userCode,expiresIn:r.expiresIn},void 0,!1,void 0,this))}});await g(u(wt,{login:t.user.login,apiUrl:t.apiUrl},void 0,!1,void 0,this))});d.command("whoami").description("Show the current Atelier account").action(async()=>{let e=await Re();if(await g(u(ht,{login:e?.user.login,apiUrl:e?.apiUrl},void 0,!1,void 0,this)),!e)process.exitCode=1});d.command("logout").description("Remove the local Atelier session").action(async()=>{Ue(),await g(u(Bt,{},void 0,!1,void 0,this))});var F=d.command("profile").description("Manage account-backed config profiles");F.command("list").description("List remote profiles").action(async()=>{await g(u(zt,{profiles:await Ze(),activeProfile:y()},void 0,!1,void 0,this))});F.command("create").description("Create a remote profile").argument("<name>").action(async(e)=>{let t=await Me(e);await g(u(_,{title:"Profile created",name:t.name},void 0,!1,void 0,this))});F.command("switch").description("Set the active local profile after verifying it exists remotely").argument("<name>").action(async(e)=>{let t=await R(e);if(!t)throw new Error(`Profile not found: ${e}`);ne(t.name),await g(u(_,{title:"Active profile",name:t.name},void 0,!1,void 0,this))});F.command("current").description("Show the active local profile").action(async()=>{await g(u(_,{title:"Active profile",name:y()},void 0,!1,void 0,this))});d.command("checkout").description("Alias for `atl profile switch`").argument("<name>").action(async(e)=>{let t=await R(e);if(!t)throw new Error(`Profile not found: ${e}`);ne(t.name),await g(u(_,{title:"Active profile",name:t.name},void 0,!1,void 0,this))});var P=d.command("vault").description("Advanced vault controls");P.command("status").description("Show vault initialization and local unlock state").action(async()=>{let e=await ge();console.log(`Vault: ${e.initialized?"initialized":"not initialized"}`),console.log(`Local state: ${e.unlocked?"unlocked":"locked"}`),console.log(`Active profile: ${e.activeProfile}`)});P.command("init").description("Initialize the encrypted vault now instead of waiting for first save").action(async()=>{let e=await kt("Create an Atelier vault passphrase: "),t=await ue(e);console.log(`Vault initialized for profile ${t.profileName}`)});P.command("unlock").description("Unlock this machine with the vault passphrase").action(async()=>{let e=await H("Vault passphrase: "),t=await Qe(e);console.log(`Vault unlocked for profile ${t.activeProfile}`)});P.command("lock").description("Remove local unlocked vault material from this machine").action(async()=>{Oe(),console.log("Vault locked")});d.command("save").description("Save a config snapshot to the active encrypted profile").argument("<id-or-path>").action(async(e)=>{await sn(e)});var Ut=d.command("saved").description("Inspect encrypted configs saved remotely");Ut.command("list").description("List saved configs for the active profile").action(async()=>{let e=y();await g(u(Kt,{configs:await Ye(e),profileName:e},void 0,!1,void 0,this))});Ut.command("show").description("Show saved metadata and version history").argument("<stable-id>").action(async(e)=>{let t=y(),r=await Je(t,e);if(!r)throw new Error(`Saved config not found: ${e}`);await g(u(Tt,{config:r,profileName:t},void 0,!1,void 0,this))});d.command("scan").description("Scan this machine and write local inventory").option("--path <path...>","additional manual path(s) to scan").option("--legacy","include legacy manager signals like yadm").action(async(e)=>{let t=await ft({repoRoot:cn,manualPaths:e.path??[],includeLegacyManagers:e.legacy}),r=gt(t,{path:X});await g(u(ze,{inventory:t,path:r},void 0,!1,void 0,this))});d.command("list").description("List inventory items with polished terminal output").option("--domain <domain>","filter by domain").option("--app <app>","filter by app").option("--secrets","only items with secret warnings").option("--drift","only items with mirror drift").option("--generated","only generated/app-state items").option("--private","only private items").option("--missing","only missing registry items").option("--json","print JSON instead of Ink output").action(async(e)=>{let t=Y(),r=fn(t.items,e);if(e.json)return V(r);await g(u(yt,{items:r,title:"Inventory"},void 0,!1,void 0,this))});d.command("inspect").description("Inspect one inventory item by id or path").argument("<id-or-path>").option("--json","print JSON instead of Ink output").action(async(e,t)=>{let r=Y(),n=Zt(r,e);if(t.json)return V(n??null);await g(n?u(bt,{item:n},void 0,!1,void 0,this):u(Ke,{query:e},void 0,!1,void 0,this))});d.command("summary").description("Print the last scan summary").option("--json","print JSON instead of Ink output").action(async(e)=>{let t=Y();if(e.json)return V(t.summary);await g(u(ze,{inventory:t,path:X},void 0,!1,void 0,this))});d.command("doctor").description("Check Atelier CLI, account, inventory, and local environment health").option("--json","print JSON instead of Ink output").action(async(e)=>{let t=gn();if(e.json)V(t);else await g(u(At,{checks:t},void 0,!1,void 0,this));if(t.some((r)=>r.status==="fail"))process.exitCode=1});d.parseAsync(process.argv).catch((e)=>{console.error(e instanceof Error?e.message:e),process.exit(1)});function V(e){console.log(JSON.stringify(e,null,2))}function Y(){if(!Ct(X))throw new Error("No inventory found. Run `atl scan` first.");return JSON.parse(St(X,"utf-8"))}function ln(){if(process.env.ATELIER_STATE_DIR)return process.env.ATELIER_STATE_DIR;if(process.env.XDG_STATE_HOME)return q(process.env.XDG_STATE_HOME,"atelier");if(nn()==="win32"&&process.env.LOCALAPPDATA)return q(process.env.LOCALAPPDATA,"Atelier");return q(rn(),".local","state","atelier")}async function sn(e){let t=Y(),r=Zt(t,e);if(!r){await g(u(Ke,{query:e},void 0,!1,void 0,this)),process.exitCode=1;return}let n=await ge(),a;if(!n.initialized)a=await kt("Create an Atelier vault passphrase: ");else if(!n.unlocked)a=await H("Vault passphrase: ");let i=await je(r,{passphrase:a});await g(u($t,{stableId:i.stableId,profileName:i.profileName,versionHash:i.version.contentSha256,sizeBytes:i.version.sizeBytes,reused:i.reused},void 0,!1,void 0,this))}async function kt(e){let t=await H(e),r=await H("Confirm vault passphrase: ");if(t!==r)throw new Error("Vault passphrases do not match");return t}async function H(e){if(!w.isTTY)return G.write(e),xt??=St(0,"utf-8").split(/\r?\n/),xt.shift()??"";return G.write(e),w.setEncoding("utf-8"),w.resume(),w.setRawMode(!0),await new Promise((t)=>{let r="",n=()=>{w.off("data",i),w.setRawMode(!1),w.pause()},a=()=>{n(),G.write(`
11
- `),t(r)},i=(c)=>{for(let f of String(c)){if(f==="\x03")n(),G.write(`
12
- `),process.exit(130);if(f==="\r"||f===`
13
- `){a();return}if(f==="\x7F"){r=r.slice(0,-1);continue}r+=f}};w.on("data",i)})}function fn(e,t){return e.filter((r)=>{if(t.domain&&r.domain.toLowerCase()!==t.domain.toLowerCase())return!1;if(t.app&&r.app.toLowerCase()!==t.app.toLowerCase())return!1;if(t.secrets&&r.secretFindings.length===0)return!1;if(t.drift&&!r.mirrors.some((n)=>n.exists&&n.identical===!1))return!1;if(t.generated&&r.kind!=="generated")return!1;if(t.private&&r.shareability!=="private")return!1;if(t.missing&&r.exists)return!1;return!0})}function Zt(e,t){let r=Te(t);return e.items.find((n)=>n.id===t||Te(n.path)===r||Te(n.displayPath)===r)??e.items.find((n)=>n.displayPath.includes(t)||n.path.includes(t))}function Te(e){return e.replace(/^~(?=\/|$)/,process.env.HOME??"").toLowerCase()}function gn(){let e=[],t=Ct(X)?Y():void 0,r=W();return e.push({label:"runtime",status:process.versions.bun?"pass":"fail",detail:process.versions.bun?`Bun ${process.versions.bun}`:"Bun is required"}),e.push({label:"api",status:"pass",detail:J()}),e.push({label:"session",status:r?"pass":"warn",detail:r?`logged in as ${r.user.login}`:"not logged in; run `atl login`"}),e.push({label:"state directory",status:"pass",detail:Rt}),e.push({label:"inventory",status:t?"pass":"warn",detail:t?`${t.summary.existing}/${t.summary.total} existing, generated ${t.generatedAt}`:"missing; run `atl scan`"}),e.push({label:"secret warnings",status:t&&t.summary.secrets>0?"warn":"pass",detail:t?`${t.summary.secrets} item${t.summary.secrets===1?"":"s"} flagged`:"no inventory"}),e}
3
+ import{stdin as S,stdout as F}from"process";import{existsSync as $e,readFileSync as pr,statSync as Ni}from"fs";import{homedir as Vi,platform as Di}from"os";import{join as Ce,resolve as hn}from"path";import{Command as Ei}from"commander";import{createDecipheriv as ao,createHash as fo}from"crypto";import{existsSync as go,mkdirSync as qr}from"fs";import{copyFile as uo,readFile as yo,writeFile as wo}from"fs/promises";import{homedir as He,platform as bo}from"os";import{basename as vo,dirname as Nr,join as P,resolve as po}from"path";import{createPatch as mo}from"diff";import{execFileSync as Re}from"child_process";import{chmodSync as mr,existsSync as Me,mkdirSync as Ar,readFileSync as hr,rmSync as In,writeFileSync as Tr}from"fs";import{homedir as Rn,platform as Mn}from"os";import{dirname as Br,join as Ue}from"path";var kr=Ue(Rn(),".config","atelier"),Z=Ue(kr,"session.json"),ee=Ue(kr,"config.json"),Le="dev.atelier.session",Un="https://atelier.mananjoshi.me/api",Ln="Ov23liiscZlMXcJ2RLnd";function ge(){return process.env.ATELIER_API_URL??Un}function Fn(){return process.env.ATELIER_GITHUB_CLIENT_ID??Ln}async function Sr(e){let r=e.apiUrl??ge(),t=e.clientId??Fn(),n=await Xn(t);await e.onPrompt({verificationUri:n.verification_uri,userCode:n.user_code,expiresIn:n.expires_in});let c=await Wn(t,n,e.onPoll),o=await fetch(`${r}/auth/github/exchange`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({githubAccessToken:c})});if(!o.ok)throw new Error(`Atelier API rejected GitHub login (${o.status})`);let s=await o.json();return Zn({apiUrl:r,user:s.user,token:s.token}),{apiUrl:r,user:s.user}}async function Cr(){let e=re();if(!e)return;let r=await fetch(`${e.apiUrl}/me`,{headers:{authorization:`Bearer ${e.token}`}});if(!r.ok)return;return{user:(await r.json()).user,apiUrl:e.apiUrl}}function re(){let e=ue();if(!e)return;let r=Jn(e);if(!r)return;return{apiUrl:e.apiUrl,user:e.user,token:r}}function T(){return xr().activeProfile??"personal"}function $r(e){_n({...xr(),activeProfile:e})}function zr(){let e=ue();if(e?.tokenStorage==="keychain")On(e.user.id);if(Me(Z))In(Z)}function ue(){if(!Me(Z))return;return JSON.parse(hr(Z,"utf-8"))}function xr(){if(!Me(ee))return{};return JSON.parse(hr(ee,"utf-8"))}function _n(e){Ar(Br(ee),{recursive:!0}),Tr(ee,JSON.stringify(e,null,2)+`
4
+ `,"utf-8"),mr(ee,384)}function Zn(e){Ar(Br(Z),{recursive:!0});let r=Mn()==="darwin",t={apiUrl:e.apiUrl,user:e.user,tokenStorage:r?"keychain":"file",createdAt:new Date().toISOString()};if(r)Qn(e.user.id,e.token);else t.token=e.token;Tr(Z,JSON.stringify(t,null,2)+`
5
+ `,"utf-8"),mr(Z,384)}function Jn(e){if(e.tokenStorage==="file")return e.token;return Yn(e.user.id)}async function Xn(e){let r=await fetch("https://github.com/login/device/code",{method:"POST",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({client_id:e,scope:"read:user user:email"})});if(!r.ok)throw new Error(`GitHub device-code request failed (${r.status})`);return r.json()}async function Wn(e,r,t){let n=r.interval,c=Date.now()+r.expires_in*1000;while(Date.now()<c){await Gn(n*1000),await t?.("Waiting for GitHub authorization\u2026");let o=await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({client_id:e,device_code:r.device_code,grant_type:"urn:ietf:params:oauth:grant-type:device_code"})});if(!o.ok)throw new Error(`GitHub token polling failed (${o.status})`);let s=await o.json();if(s.access_token)return s.access_token;if(s.error==="authorization_pending")continue;if(s.error==="slow_down"){n+=5;continue}if(s.error==="access_denied")throw new Error("GitHub login was denied");if(s.error==="expired_token")throw new Error("GitHub login code expired");throw new Error(s.error_description??"GitHub login failed")}throw new Error("GitHub login timed out")}function Qn(e,r){Re("security",["add-generic-password","-a",e,"-s",Le,"-w",r,"-U"],{stdio:"ignore"})}function Yn(e){try{return Re("security",["find-generic-password","-a",e,"-s",Le,"-w"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return}}function On(e){try{Re("security",["delete-generic-password","-a",e,"-s",Le],{stdio:"ignore"})}catch{}}function Gn(e){return new Promise((r)=>setTimeout(r,e))}async function Kr(){return(await(await x("/profiles")).json()).profiles}async function Ir(e){return(await(await x("/profiles",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e})})).json()).profile}async function de(e){let r=await x(`/profiles/${encodeURIComponent(e)}`);if(r.status===404)return;return(await r.json()).profile}async function te(){return await(await x("/vault")).json()}async function Rr(e){await x("/vault",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(e)})}async function Mr(e){let r=await x(`/profiles/${encodeURIComponent(e)}/key`);if(r.status===404)return;return(await r.json()).profileKey}async function Fe(e,r){return(await(await x(`/profiles/${encodeURIComponent(e)}/key`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(r)})).json()).profileKey}async function ne(e,r={}){let n=await(await x(`/profiles/${encodeURIComponent(e)}/configs`)).json();return r.includeInternal?n.configs:n.configs.filter((c)=>c.kind!=="folder-file")}async function ye(e,r){let t=await x(`/profiles/${encodeURIComponent(e)}/configs/${encodeURIComponent(r)}`);if(t.status===404)return;return(await t.json()).config}async function Ur(e,r,t){return await(await x(`/profiles/${encodeURIComponent(e)}/configs/${encodeURIComponent(r)}/versions`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})).json()}async function we(e,r,t){let n=await x(`/profiles/${encodeURIComponent(e)}/configs/${encodeURIComponent(r)}/versions/${encodeURIComponent(t)}/blob`);if(n.status===404)return;return await n.json()}async function x(e,r={}){let t=re();if(!t)throw new Error("Not logged in. Run `atl login`.");let n=await fetch(`${t.apiUrl}${e}`,{...r,headers:{...r.headers,authorization:`Bearer ${t.token}`}});if(!n.ok&&n.status!==404){let c=await n.json().catch(()=>{return});throw new Error(c?.error??`Atelier API request failed (${n.status})`)}return n}import{execFileSync as Xe}from"child_process";import{createCipheriv as Hn,createDecipheriv as Pn,randomBytes as oe,scryptSync as qn}from"crypto";import{chmodSync as Nn,existsSync as Fr,mkdirSync as Vn,readFileSync as Dn,rmSync as En,writeFileSync as jn}from"fs";import{homedir as eo,platform as We}from"os";import{dirname as ro,join as _r}from"path";var Qe="dev.atelier.vault",to=_r(eo(),".config","atelier"),J=_r(to,"vault-key.json"),Lr={N:32768,r:8,p:1},no=67108864,_e="aes-256-gcm";async function pe(){let e=H();return{initialized:(await te()).initialized,unlocked:Boolean(Je(e.user.id)),activeProfile:T()}}async function Ye(e,r=T()){io(e);let t=H();if((await te()).initialized)throw new Error("Atelier vault already exists. Run `atl vault unlock` if this machine is locked.");let c=await de(r);if(!c)throw new Error(`Profile not found: ${r}`);let o=oe(32),s=oe(32),l=oe(16),u=Wr(e,l,Lr),f=Ze(o,u),b=Ze(s,o);return await Rr({kdf:{algorithm:"scrypt",salt:be(l),params:Lr},encryptedVaultKey:f}),await Fe(r,{version:1,algorithm:b.algorithm,nonce:b.nonce,encryptedKey:b.ciphertext}),Oe(t.user.id,o),{profileName:c.name}}async function Zr(e){let r=H(),t=await te();if(!t.initialized)throw new Error("Atelier vault is not initialized. Run `atl save <id>` or `atl vault init`.");let n=Xr(t,e);return Oe(r.user.id,n),{activeProfile:T()}}function Jr(){let e=H();co(e.user.id)}async function oo(e,r=T()){let t=H(),n=Je(t.user.id);if(n)return n;if(!e)throw new Error("Vault passphrase is required");let c=await te();if(!c.initialized){await Ye(e,r);let o=Je(t.user.id);if(!o)throw new Error("Vault initialized but local key was not stored");return o}return Xr(c,e)}async function G(e,r=T()){let t=await oo(e,r),n=await Mr(r);if(n)return Qr(n.encryptedKey,n.nonce,t);let c=oe(32),o=Ze(c,t);return await Fe(r,{version:1,algorithm:o.algorithm,nonce:o.nonce,encryptedKey:o.ciphertext}),c}function Xr(e,r){if(!e.kdf||!e.encryptedVaultKey)throw new Error("Vault payload is incomplete");if(e.kdf.algorithm!=="scrypt")throw new Error(`Unsupported vault KDF: ${e.kdf.algorithm}`);let t=ve(e.kdf.salt),n=Wr(r,t,e.kdf.params),c=Qr(e.encryptedVaultKey.ciphertext,e.encryptedVaultKey.nonce,n);return Oe(H().user.id,c),c}function Wr(e,r,t){return qn(e,r,32,{N:t.N,r:t.r,p:t.p,maxmem:no})}function Ze(e,r){let t=oe(12),n=Hn(_e,r,t),c=Buffer.concat([n.update(e),n.final()]),o=n.getAuthTag();return{algorithm:_e,nonce:be(t),ciphertext:be(Buffer.concat([c,o]))}}function Qr(e,r,t){let n=Buffer.from(ve(e)),c=Buffer.from(ve(r)),o=n.subarray(0,-16),s=n.subarray(-16),l=Pn(_e,t,c);return l.setAuthTag(s),Buffer.concat([l.update(o),l.final()])}function io(e){if(e.length<12)throw new Error("Vault passphrase must be at least 12 characters.")}function H(){let e=re();if(!e)throw new Error("Not logged in. Run `atl login`.");return e}function Oe(e,r){let t=be(r);if(We()==="darwin"){Xe("security",["add-generic-password","-a",e,"-s",Qe,"-w",t,"-U"],{stdio:"ignore"});return}Vn(ro(J),{recursive:!0}),jn(J,JSON.stringify({userId:e,key:t},null,2)+`
6
+ `,"utf-8"),Nn(J,384)}function Je(e){let r=We()==="darwin"?so(e):lo(e);return r?Buffer.from(ve(r)):void 0}function co(e){if(We()==="darwin"){try{Xe("security",["delete-generic-password","-a",e,"-s",Qe],{stdio:"ignore"})}catch{}return}if(Fr(J))En(J)}function so(e){try{return Xe("security",["find-generic-password","-a",e,"-s",Qe,"-w"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return}}function lo(e){if(!Fr(J))return;let r=JSON.parse(Dn(J,"utf-8"));return r.userId===e?r.key:void 0}function be(e){return Buffer.from(e).toString("base64url")}function ve(e){return new Uint8Array(Buffer.from(e,"base64url"))}var Ao="aes-256-gcm",ho=new TextDecoder("utf-8",{fatal:!0});async function Vr(e,r={}){let t=r.profileName??T(),n=await Co(t,e);if(!n)throw new Error(`Saved config not found: ${e}`);let c=await G(r.passphrase,t);if(n.kind==="folder-manifest")return await To(t,n,c,r);let o=await qe(t,n,c,{preview:r.preview});return await et(o,r)}async function Dr(e,r={}){let n=(await ne(e)).filter((s)=>(s.kind==="file"||s.kind==="folder-manifest")&&s.pathHint&&Ne(s));if(n.length===0)return{profileName:e,results:[],blocked:!1,preview:Boolean(r.preview),backup:Boolean(r.backup)};let c=await G(r.passphrase,e),o=await Promise.all(n.map((s)=>Bo(e,s,c,{preview:r.preview})));return await jr(e,o.flat(),r)}async function To(e,r,t,n){if(!r.pathHint)throw new Error(`Saved folder has no target path: ${r.stableId}`);let c=await Er(e,r,t,{preview:n.preview});return{...await jr(e,c,n),stableId:r.stableId,displayPath:r.pathHint}}async function Bo(e,r,t,n){if(r.kind==="folder-manifest")return await Er(e,r,t,n);return[await qe(e,r,t,n)]}async function Er(e,r,t,n){let c=await So(e,r,t),o=[];for(let s of c.files)o.push(await ko(e,s.stableId,s.pathHint,s.versionId,s.contentSha256,t,n));return o}async function jr(e,r,t){if(t.preview)return{profileName:e,results:r.map((s)=>s.result),blocked:!1,preview:!0,backup:Boolean(t.backup)};if(r.some((s)=>s.result.status==="update")&&!t.backup)return{profileName:e,results:r.map((s)=>{if(s.result.status==="update")return{...s.result,status:"blocked",reason:"local file differs; rerun with --preview to inspect or --backup to replace safely"};if(s.result.status==="create")return{...s.result,reason:"would create missing local file after blocked changes are resolved"};return s.result}),blocked:!0,preview:!1,backup:!1};let c=nt(),o=[];for(let s of r)o.push(await et(s,{...t,backupRunId:c}));return{profileName:e,results:o,blocked:!1,preview:!1,backup:Boolean(t.backup)}}async function et(e,r){let{result:t,savedBytes:n}=e;if(t.status==="unchanged")return t;if(t.status==="create"){if(!r.preview)await Yr(t.targetPath,n);return{...t,reason:r.preview?"would create missing local file":"created missing local file"}}if(r.preview)return t;if(!r.backup)return{...t,status:"blocked",reason:"local file differs; rerun with --preview to inspect or --backup to replace safely"};let c=await $o(t.stableId,t.targetPath,r.backupRunId??nt());return await Yr(t.targetPath,n),{...t,reason:"replaced differing local file after creating backup",backupPath:c}}async function ko(e,r,t,n,c,o,s){let l=await we(e,r,n);if(!l)throw new Error(`Saved folder file blob not found: ${r}`);if(l.version.contentSha256!==c)throw new Error(`Saved folder file hash mismatch for ${r}`);return await qe(e,{id:r,stableId:r,kind:"file",pathHint:t,latestVersion:l.version},o,s,l.ciphertext)}async function qe(e,r,t,n,c){if(r.kind!=="file")throw new Error(`Cannot apply non-file config: ${r.stableId}`);if(!r.pathHint)throw new Error(`Saved config has no target path: ${r.stableId}`);let o=Ne(r);if(!o)throw new Error(`Saved config has no versions: ${r.stableId}`);let s=c?{version:o,ciphertext:c}:await we(e,r.stableId,o.id);if(!s)throw new Error(`Saved config blob not found: ${r.stableId}`);let l=rt(s.ciphertext,s.version.nonce,t),u=tt(r.pathHint),f=r.pathHint,b=go(u),m=b?await yo(u):void 0,y=Pe(l);if(y!==o.contentSha256)throw new Error(`Saved content hash mismatch for ${r.stableId}`);if(!b)return{savedBytes:l,result:{profileName:e,stableId:r.stableId,targetPath:u,displayPath:f,status:"create",reason:n.preview?"would create missing local file":"created missing local file",diff:Or("",l,f),version:Ge(o)}};if(Pe(m)===y)return{savedBytes:l,result:{profileName:e,stableId:r.stableId,targetPath:u,displayPath:f,status:"unchanged",reason:"local file already matches saved version",version:Ge(o)}};return{savedBytes:l,result:{profileName:e,stableId:r.stableId,targetPath:u,displayPath:f,status:"update",reason:n.preview?"would replace differing local file":"local file differs",diff:Or(m,l,f),version:Ge(o)}}}async function So(e,r,t){let n=Ne(r);if(!n)throw new Error(`Saved folder has no versions: ${r.stableId}`);let c=await we(e,r.stableId,n.id);if(!c)throw new Error(`Saved folder manifest blob not found: ${r.stableId}`);let o=rt(c.ciphertext,c.version.nonce,t);if(Pe(o)!==n.contentSha256)throw new Error(`Saved folder manifest hash mismatch for ${r.stableId}`);let l=JSON.parse(o.toString("utf-8"));if(l.version!==1||!Array.isArray(l.files))throw new Error(`Invalid folder manifest: ${r.stableId}`);if(l.files.some((u)=>!u.stableId||!u.pathHint||!u.versionId||!u.contentSha256))throw new Error(`Invalid folder manifest entries: ${r.stableId}`);return l}async function Co(e,r){let t=await ye(e,r);if(t)return t;let n=Hr(r);return(await ne(e)).find((o)=>o.pathHint&&Hr(o.pathHint)===n)}function Ne(e){return e.latestVersion??e.versions?.[0]}function rt(e,r,t){let n=Buffer.from(e,"base64url"),c=Buffer.from(r,"base64url"),o=n.subarray(0,-16),s=n.subarray(-16),l=ao(Ao,t,c);return l.setAuthTag(s),Buffer.concat([l.update(o),l.final()])}async function Yr(e,r){qr(Nr(e),{recursive:!0}),await wo(e,r)}async function $o(e,r,t){let n=P(zo(),t,Pr(e),Pr(r));return qr(Nr(n),{recursive:!0}),await uo(r,n),n}function zo(){if(process.env.ATELIER_STATE_DIR)return P(process.env.ATELIER_STATE_DIR,"backups");if(process.env.XDG_STATE_HOME)return P(process.env.XDG_STATE_HOME,"atelier","backups");if(bo()==="win32"&&process.env.LOCALAPPDATA)return P(process.env.LOCALAPPDATA,"Atelier","backups");return P(He(),".local","state","atelier","backups")}function Or(e,r,t){let n=typeof e==="string"?e:Gr(e),c=Gr(r);if(n===void 0||c===void 0)return;return mo(`local ${t}`,n,c,"local","saved").split(`
7
+ `).slice(2).join(`
8
+ `)}function Gr(e){if(e.includes(0))return;try{return ho.decode(e)}catch{return}}function tt(e){if(e==="~")return He();if(e.startsWith("~/"))return P(He(),e.slice(2));return po(e)}function Hr(e){return tt(e).toLowerCase()}function Pe(e){return fo("sha256").update(e).digest("hex")}function Ge(e){return{id:e.id,contentSha256:e.contentSha256,sizeBytes:e.sizeBytes,createdAt:e.createdAt}}function nt(){return new Date().toISOString().replaceAll(":","-").replaceAll(".","-")}function Pr(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||vo(e)||"item"}import{createCipheriv as Uo,createHash as wt,randomBytes as bt}from"crypto";import{existsSync as vt}from"fs";import{lstat as Lo,mkdir as pt,readFile as X,readdir as mt,stat as At,unlink as Fo,writeFile as ht}from"fs/promises";import{homedir as ie,platform as _o}from"os";import{basename as je,extname as Zo,join as K,relative as Jo,resolve as Xo}from"path";var Ve=[["GitHub token",/gh[pousr]_[A-Za-z0-9_]{20,}/g],["Slack token",/xox[baprs]-[A-Za-z0-9-]{20,}/g],["AWS access key",/AKIA[0-9A-Z]{16}/g],["Private key",/-----BEGIN (?:RSA |OPENSSH |EC |DSA )?PRIVATE KEY-----/g],["Generic token assignment",/(?:token|api[_-]?key|secret|webhook|password)\s*[=:]\s*["']?[^"'\s]{12,}/gi]];function Ae(e){let r=[],t=e.split(/\r?\n/);for(let[n,c]of Ve)for(let o of e.matchAll(c)){let s=o.index??0,l=e.slice(0,s).split(/\r?\n/).length;r.push({type:n,line:l,preview:me(o[0])})}return t.forEach((n,c)=>{for(let o of n.matchAll(/[A-Za-z0-9_+\/=.-]{32,}/g)){let s=o[0];if(!xo(s,n)&&it(s,n))r.push({type:"High-entropy string",line:c+1,preview:me(s)})}}),Io(r)}function me(e){if(e.length<=8)return"[redacted]";return`${e.slice(0,4)}\u2026${e.slice(-4)}`}function ot(e){let r=e;for(let[,t]of Ve)r=r.replace(t,(n)=>me(n));return r=r.replace(/[A-Za-z0-9_+\/=.-]{32,}/g,(t)=>{if(it(t,e))return me(t);return t}),r}function xo(e,r){return Ve.some(([,t])=>{return t.lastIndex=0,Array.from(r.matchAll(t)).some((n)=>n[0].includes(e)||e.includes(n[0]))})}function it(e,r){if(e.startsWith("amazon."))return!1;if(e.includes("anthropic.claude"))return!1;if(/^[A-Za-z0-9.-]+@[A-Za-z0-9.-]+$/.test(e))return!1;if(/model/i.test(r)&&/^[A-Za-z0-9_.-]+$/.test(e))return!1;return Ko(e)>4.2&&/[A-Za-z]/.test(e)&&/[0-9]/.test(e)}function Ko(e){let r=new Map;for(let n of e)r.set(n,(r.get(n)??0)+1);let t=0;for(let n of r.values()){let c=n/e.length;t-=c*Math.log2(c)}return t}function Io(e){let r=new Set;return e.filter((t)=>{let n=`${t.type}:${t.line}:${t.preview}`;if(r.has(n))return!1;return r.add(n),!0})}var he=1048576;function ct(e){let r=[];if(!e.exists)r.push("file does not exist");if(e.isDirectory||e.kind==="directory"||e.format==="directory")r.push("directory saving is not supported yet");if(e.kind==="generated")r.push("generated/cache files are not saved");if(e.kind==="private"||e.shareability==="private")r.push("private/auth files are blocked");if(e.secretFindings.length>0)r.push("detected secret material");if(e.size!==void 0&&e.size>1048576)r.push(`file is larger than ${Mo(1048576)}`);if(Ro(e))r.push("binary files are not supported yet");return{ok:r.length===0,reasons:r}}function De(e){let r=ct(e);if(!r.ok)throw new Error(`Cannot save ${e.id}: ${r.reasons.join("; ")}`)}function Ro(e){if(e.previewSuppressedReason?.toLowerCase().includes("binary"))return!0;return["binary","sqlite","db"].includes(e.format.toLowerCase())}function Mo(e){if(e<1024)return`${e} B`;let r=e/1024;if(r<1024)return`${Math.round(r)} KiB`;return`${Math.round(r/1024)} MiB`}var st="aes-256-gcm",Wo=1,lt=2000,Qo=new TextDecoder("utf-8",{fatal:!0}),Tt=new Set([".git","node_modules","dist","build",".next",".turbo","cache","caches","logs","tmp","temp"]),Bt=[/cache/i,/history/i,/session/i,/state/i,/\.mdb$/i,/\.sqlite/i,/\.db$/i,/zcompdump/i,/logs?/i,/lock$/i,/lock\./i],kt=[/credential/i,/secret/i,/token/i,/auth/i,/cookie/i,/session/i,/id_rsa/i,/id_ed25519/i,/\.pem$/i,/\.key$/i,/hosts\.ya?ml$/i],at=25,ft=new Set([".conf",".config",".ini",".json",".jsonc",".toml",".yaml",".yml"]),gt=new Set([".cjs",".css",".fish",".js",".lua",".md",".mjs",".ps1",".py",".sh",".ts",".txt",".vim",".zsh"]),ut=new Set(["config","config.json","config.jsonc","settings.json","settings.jsonc","preferences.json","keymap.json","keybindings.json",".zshrc",".zshenv",".gitconfig",".editorconfig",".npmrc",".tool-versions","starship.toml"]),dt=new Set(["readme","readme.md","license","install.sh","setup.sh"]),Yo=[/local/i,/backup/i,/archive/i,/old/i,/copy/i,/sample/i,/example/i,/template/i];async function St(e,r={}){De(e);let t=T(),n=await G(r.passphrase,t),c=await X(e.path),o=await Ee(t,n,e.id,"file",e.displayPath,c);return{profileName:t,stableId:e.id,version:o.version,reused:o.reused}}async function er(e){let r=typeof e==="string"?ci(e):e.path,t=Te(r),n=await At(r).catch(()=>{return});if(!n)throw new Error(`Folder does not exist: ${t}`);if(!n.isDirectory())throw new Error(`Not a folder: ${t}`);let c=typeof e==="string"?Ft(t):e.id,o=[],s=[];return await Ut(r,async(u,f)=>{let b=Te(u),m=Lt(f);if(o.length>=lt){s.push(N(u,b,m,`folder save is limited to ${lt} files`));return}let y=await Eo(c,u,m);if("reason"in y)s.push(N(u,b,m,y.reason));else o.push(y)},s),o.sort((u,f)=>u.relativePath.localeCompare(f.relativePath)),s.sort((u,f)=>u.relativePath.localeCompare(f.relativePath)),jo(o),await Oo({stableId:c,rootPath:r,rootDisplayPath:t,files:o,skipped:s})}async function Ct(e,r={}){let t=await er(e),n=T(),c=r.resumeRunId?await Do(r.resumeRunId):void 0,o=c?.selectedFiles.map((y)=>y.relativePath)??r.includeRelativePaths??t.files.filter((y)=>y.selectedByDefault).map((y)=>y.relativePath),s=new Set(o),l={...t,files:t.files.filter((y)=>s.has(y.relativePath))};if(l.files.length===0)throw new Error(`No eligible files selected in ${l.rootDisplayPath}`);let u=c?Object.fromEntries(c.selectedFiles.map((y)=>[y.relativePath,y.contentSha256])):r.expectedContentSha256ByRelativePath;Go(l,u);let f=c??await qo(n,l);Po(f,n,l);let b=await G(r.passphrase,n),m=[];try{f.status="uploading",f.currentStep="uploading-files",f.error=void 0,await q(f);for(let w of l.files){let M=f.uploadedFiles.find((d)=>d.relativePath===w.relativePath&&d.contentSha256===w.contentSha256);if(M){m.push(M);continue}let O=await X(w.path);if(ce(O)!==w.contentSha256)throw new Error(`Folder file changed during save: ${w.relativePath}`);let U=await Ee(n,b,w.stableId,"folder-file",w.displayPath,O),k={...w,version:U.version,reused:U.reused};m.push(k),f.uploadedFiles.push(k),await q(f)}f.currentStep="verifying-files",await q(f),await Ho(l.files);let y={version:Wo,rootPathHint:l.rootDisplayPath,savedAt:new Date().toISOString(),files:m.map((w)=>({stableId:w.stableId,relativePath:w.relativePath,pathHint:w.displayPath,versionId:w.version.id,contentSha256:w.version.contentSha256,sizeBytes:w.sizeBytes,createdAt:w.version.createdAt}))},h=Buffer.from(JSON.stringify(y,null,2),"utf-8");f.currentStep="uploading-manifest",await q(f);let z=await Ee(n,b,l.stableId,"folder-manifest",l.rootDisplayPath,h);return await Kt(f.runId),{profileName:n,stableId:l.stableId,rootDisplayPath:l.rootDisplayPath,manifestVersion:z.version,files:m,skipped:l.skipped,reused:z.reused}}catch(y){throw f.status="failed",f.error=y instanceof Error?y.message:String(y),await q(f),new Error(`Folder save failed before manifest commit. Rerun the same save to resume. ${y instanceof Error?y.message:String(y)}`)}}async function $t(e,r){let t=T(),n=new Date().toISOString(),c=await xt(t,e.stableId,e.rootPath),o={version:1,profileName:t,stableId:e.stableId,rootPath:e.rootPath,rootDisplayPath:e.rootDisplayPath,includeRelativePaths:[...new Set(r)].sort(),createdAt:c?.createdAt??n,updatedAt:n};return await Vo(o),o}async function Oo(e){let r=T(),t=await xt(r,e.stableId,e.rootPath);if(!t)return e;let n=new Set(t.includeRelativePaths),c=new Set(e.files.map((f)=>f.relativePath)),o=e.files.filter((f)=>n.has(f.relativePath)).map((f)=>f.relativePath).sort(),s=t.includeRelativePaths.filter((f)=>!c.has(f)).sort(),l=e.files.filter((f)=>f.selectedByDefault&&!n.has(f.relativePath)).map((f)=>f.relativePath).sort(),u=e.files.filter((f)=>!f.selectedByDefault&&!n.has(f.relativePath)).map((f)=>f.relativePath).sort();for(let f of e.files)f.selectedByDefault=n.has(f.relativePath),f.defaultSelectionReason=f.selectedByDefault?"selected by saved recipe":"not selected by saved recipe";return{...e,recipe:t,recipeDelta:{selectedExisting:o,missingSelected:s,newRecommended:l,newUnreviewed:u}}}async function zt(e){let r=T();return(await No()).filter((n)=>n.status==="failed"&&n.profileName===r&&n.stableId===e.stableId&&n.rootPath===e.rootPath).sort((n,c)=>c.updatedAt.localeCompare(n.updatedAt))[0]}async function rr(e){await Kt(e)}function Go(e,r){if(!r)return;for(let t of e.files){let n=r[t.relativePath];if(n&&n!==t.contentSha256)throw new Error(`Folder file changed since review plan was created: ${t.relativePath}`)}}async function Ho(e){for(let r of e){let t=await X(r.path);if(ce(t)!==r.contentSha256)throw new Error(`Folder file changed during save: ${r.relativePath}`)}}function Po(e,r,t){if(e.profileName!==r||e.stableId!==t.stableId||e.rootPath!==t.rootPath)throw new Error("Folder save run does not match this folder/profile")}async function qo(e,r){let t=new Date().toISOString(),n={version:1,runId:`${si()}-${bt(4).toString("hex")}`,status:"uploading",currentStep:"created",profileName:e,stableId:r.stableId,rootPath:r.rootPath,rootDisplayPath:r.rootDisplayPath,selectedFiles:r.files,uploadedFiles:[],createdAt:t,updatedAt:t};return await q(n),n}async function No(){let e=nr();if(!vt(e))return[];let r=await mt(e).catch(()=>[]);return(await Promise.all(r.filter((n)=>n.endsWith(".json")).map(async(n)=>{try{return JSON.parse(await X(K(e,n),"utf-8"))}catch{return}}))).filter((n)=>Boolean(n&&n.version===1&&n.runId))}async function xt(e,r,t){let n=It(e,r,t);if(!vt(n))return;try{let c=JSON.parse(await X(n,"utf-8"));if(c.version!==1||c.profileName!==e||c.stableId!==r||c.rootPath!==t)return;return c}catch{return}}async function Vo(e){await pt(Rt(),{recursive:!0}),await ht(It(e.profileName,e.stableId,e.rootPath),JSON.stringify(e,null,2)+`
9
+ `,"utf-8")}async function Do(e){return JSON.parse(await X(tr(e),"utf-8"))}async function q(e){await pt(nr(),{recursive:!0}),await ht(tr(e.runId),JSON.stringify({...e,updatedAt:new Date().toISOString()},null,2)+`
10
+ `,"utf-8")}async function Kt(e){await Fo(tr(e)).catch(()=>{return})}function tr(e){return K(nr(),`${_t(e)}.json`)}function nr(){return K(Mt(),"folder-save-runs")}function It(e,r,t){let n=wt("sha256").update(`${e}\x00${r}\x00${t}`).digest("hex").slice(0,24);return K(Rt(),`${_t(r)}-${n}.json`)}function Rt(){return K(Mt(),"folder-save-recipes")}function Mt(){if(process.env.ATELIER_STATE_DIR)return process.env.ATELIER_STATE_DIR;if(process.env.XDG_STATE_HOME)return K(process.env.XDG_STATE_HOME,"atelier");if(_o()==="win32"&&process.env.LOCALAPPDATA)return K(process.env.LOCALAPPDATA,"Atelier");return K(ie(),".local","state","atelier")}async function Ee(e,r,t,n,c,o){let s=ii(o,r);return await Ur(e,t,{kind:n,pathHint:c,contentSha256:ce(o),ciphertextSha256:ce(s.ciphertextBytes),sizeBytes:o.byteLength,algorithm:s.algorithm,profileKeyVersion:1,nonce:s.nonce,ciphertext:s.ciphertext})}async function Ut(e,r,t){let n=await mt(e,{withFileTypes:!0}).catch(()=>[]);for(let c of n){let o=K(e,c.name),s=Jo(e,o),l=Lt(s),u=Te(o);if(ri(c.name)){t.push(N(o,u,l,"generated or private path segment"));continue}let f=await Lo(o).catch(()=>{return});if(!f){t.push(N(o,u,l,"cannot inspect path"));continue}if(f.isSymbolicLink()){t.push(N(o,u,l,"symlinks are skipped"));continue}if(f.isDirectory()){await Ut(o,async(b,m)=>{await r(b,K(s,m))},t);continue}if(!f.isFile()){t.push(N(o,u,l,"not a regular file"));continue}await r(o,s)}}async function Eo(e,r,t){let n=await At(r).catch(()=>{return});if(!n)return{reason:"cannot inspect file"};if(n.size>he)return{reason:`file is larger than ${li(he)}`};if(ti(t))return{reason:"generated or state file"};if(ni(t))return{reason:"private or secret-like path"};let c=await X(r).catch(()=>{return});if(!c)return{reason:"cannot read file"};let o=oi(c);if(o===void 0)return{reason:"binary files are not supported yet"};if(Ae(o).length>0)return{reason:"detected secret material"};let s=ei(t,n.size);return{stableId:`${e}:${Ft(t)}`,path:r,displayPath:Te(r),relativePath:t,sizeBytes:n.size,contentSha256:ce(c),confidence:s.confidence,confidenceReasons:s.reasons,selectedByDefault:!1}}function N(e,r,t,n){return{path:e,displayPath:r,relativePath:t,reason:n,confidence:"blocked",confidenceReasons:[n]}}function jo(e){let r=0;for(let t of e){if(t.confidence!=="high-confidence"){t.selectedByDefault=!1,t.defaultSelectionReason="not selected by default";continue}if(r>=at){t.selectedByDefault=!1,t.defaultSelectionReason=`high-confidence preselection limit of ${at} reached`;continue}t.selectedByDefault=!0,t.defaultSelectionReason="high-confidence config file",r+=1}}function ei(e,r){let t=je(e).toLowerCase(),n=Zo(t),c=or(e),o=[];if(Yo.some((s)=>s.test(e)))return o.push("name suggests example, backup, or local-only material"),{confidence:"low-confidence",reasons:o};if(e.startsWith("."))o.push("dotfile-style config path");if(c.length<=2)o.push("shallow folder path");if(ut.has(t))o.push("recognized config filename");if(ft.has(n))o.push(`recognized config extension ${n}`);if(ut.has(t)||ft.has(n)&&c.length<=3)return{confidence:"high-confidence",reasons:o};if(dt.has(t))o.push("recognized supporting document");if(gt.has(n))o.push(`recognized text extension ${n}`);if(r<=65536)o.push("small text file");if(dt.has(t)||gt.has(n)||c.length<=3)return{confidence:"medium-confidence",reasons:o};return o.push("unrecognized text file in a deeper folder path"),{confidence:"low-confidence",reasons:o}}function ri(e){let r=e.toLowerCase();return Tt.has(r)||Bt.some((t)=>t.test(e))||kt.some((t)=>t.test(e))}function ti(e){return or(e).some((r)=>Tt.has(r.toLowerCase())||Bt.some((t)=>t.test(r)))}function ni(e){return or(e).some((r)=>kt.some((t)=>t.test(r)))}function or(e){return e.split(/[\\/]+/).filter(Boolean)}function oi(e){if(e.includes(0))return;try{return Qo.decode(e)}catch{return}}function ii(e,r){let t=bt(12),n=Uo(st,r,t),c=Buffer.concat([n.update(e),n.final()]),o=n.getAuthTag(),s=Buffer.concat([c,o]);return{algorithm:st,nonce:yt(t),ciphertext:yt(s),ciphertextBytes:s}}function ci(e){if(e==="~")return ie();if(e.startsWith("~/"))return K(ie(),e.slice(2));return Xo(e)}function Te(e){return e.startsWith(ie())?`~${e.slice(ie().length)}`:e}function Lt(e){return e.split(/[\\/]+/).join("/")}function Ft(e){return e.replace(/[^A-Za-z0-9_.-]+/g,":").replace(/^:+|:+$/g,"")||je(e)||"folder"}function si(){return new Date().toISOString().replaceAll(":","-").replaceAll(".","-")}function _t(e){return e.replace(/[^a-zA-Z0-9._-]+/g,"_").replace(/^_+|_+$/g,"")||je(e)||"item"}function ce(e){return wt("sha256").update(e).digest("hex")}function yt(e){return Buffer.from(e).toString("base64url")}function li(e){if(e<1024)return`${e} B`;let r=e/1024;if(r<1024)return`${Math.round(r)} KiB`;return`${Math.round(r/1024)} MiB`}import{execFileSync as Qt}from"child_process";import{existsSync as Q,lstatSync as ai,mkdirSync as fi,readdirSync as cr,readFileSync as se,statSync as V,writeFileSync as gi}from"fs";import{homedir as ui,userInfo as di}from"os";import{dirname as Yt,join as W,relative as Ot,resolve as yi}from"path";var Zt=[{domain:"AI Tools",app:"Pi",items:[{id:"pi.dir",path:"~/.pi",kind:"directory",format:"directory",shareability:"machine-specific"}]},{domain:"Shell",app:"Starship",items:[{id:"starship.config",path:"~/.config/starship.toml",kind:"config",format:"toml",shareability:"shareable"}]},{domain:"Editors",app:"Zed",items:[{id:"zed.dir",path:"~/.config/zed",kind:"directory",format:"directory",shareability:"shareable"},{id:"zed.settings",path:"~/.config/zed/settings.json",kind:"config",format:"jsonc",shareability:"shareable"},{id:"zed.themes",path:"~/.config/zed/themes",kind:"config",format:"directory",shareability:"shareable"},{id:"zed.prompts",path:"~/.config/zed/prompts",kind:"generated",format:"directory",shareability:"machine-specific"}]},{domain:"Git",app:"Git",items:[{id:"git.config",path:"~/.gitconfig",kind:"config",format:"gitconfig",shareability:"machine-specific"},{id:"git.config-dir",path:"~/.config/git",kind:"directory",format:"directory",shareability:"machine-specific"},{id:"git.ignore",path:"~/.gitignore",kind:"config",format:"gitignore",shareability:"machine-specific"}]},{domain:"Private/Auth",app:"Credentials",privateByDefault:!0,items:[{id:"auth.ssh",path:"~/.ssh",kind:"private",format:"directory",shareability:"private"},{id:"auth.aws",path:"~/.aws",kind:"private",format:"directory",shareability:"private"},{id:"auth.gh",path:"~/.config/gh",kind:"private",format:"directory",shareability:"private"},{id:"auth.gcloud-adc",path:"~/.config/gcloud/application_default_credentials.json",kind:"private",format:"json",shareability:"private"},{id:"auth.docker",path:"~/.docker/config.json",kind:"private",format:"json",shareability:"private"},{id:"auth.pi",path:"~/.config/pi/auth.json",kind:"private",format:"json",shareability:"private"}]},{domain:"Shell",app:"Zsh",items:[{id:"zsh.home-rc",path:"~/.zshrc",kind:"config",format:"shell",shareability:"shareable"},{id:"zsh.home-env",path:"~/.zshenv",kind:"config",format:"shell",shareability:"private"},{id:"zsh.dir",path:"~/.config/zsh",kind:"directory",format:"directory",shareability:"machine-specific"},{id:"zsh.env",path:"~/.config/zsh/.zshenv",kind:"config",format:"shell",shareability:"private"},{id:"zsh.rc",path:"~/.config/zsh/.zshrc",kind:"config",format:"shell",shareability:"shareable"},{id:"zsh.conf",path:"~/.config/zsh/conf.d",kind:"directory",format:"directory",shareability:"shareable"},{id:"zsh.zcompdump",path:"~/.config/zsh/.zcompdump",kind:"generated",format:"text",shareability:"machine-specific"},{id:"zsh.sessions",path:"~/.config/zsh/.zsh_sessions",kind:"generated",format:"directory",shareability:"machine-specific"}]},{domain:"Terminals",app:"cmux",items:[{id:"cmux.dir",path:"~/.config/cmux",kind:"directory",format:"directory",shareability:"shareable"},{id:"cmux.config",path:"~/.config/cmux/cmux.json",kind:"config",format:"jsonc",shareability:"shareable"},{id:"cmux.ghostty",path:"~/Library/Application Support/com.cmuxterm.app/config.ghostty",kind:"config",format:"ghostty",shareability:"shareable"},{id:"cmux.browser-history",path:"~/Library/Application Support/com.cmuxterm.app/browser_history.json",kind:"generated",format:"json",shareability:"machine-specific"}]}];function Jt(e){let n=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1").replace(/,\s*([}\]])/g,"$1");return JSON.parse(n)}var Y=ui(),wi=new Set([".zsh",".zshrc",".zshenv",".sh",".json",".jsonc",".toml",".md",".yml",".yaml",".gitconfig",".gitignore",".ghostty",""]),bi=[/cache/i,/history/i,/session/i,/state/i,/\.mdb$/i,/\.sqlite/i,/\.db$/i,/zcompdump/i,/logs?/i],vi=[/credential/i,/secret/i,/token/i,/auth\.json$/i,/hosts\.yml$/i,/config\.json$/i],ke;async function Gt(e){ke=e.includeLegacyManagers?xi():void 0;let t=pi(e.repoRoot).flatMap((o)=>o.items.map((s)=>({definition:o,item:s}))),n=new Set,c=[];for(let{definition:o,item:s}of t){let l=ir(s.path);n.add(l),c.push(mi(o,s,l))}for(let o of Ai()){if(n.has(o.path))continue;n.add(o.path),c.push(Xt(o))}for(let o of e.manualPaths??[]){let s=ir(o);if(n.has(s))continue;n.add(s),c.push(Xt({path:s,reason:"manual path"}))}return c.sort((o,s)=>`${o.domain}:${o.app}:${o.path}`.localeCompare(`${s.domain}:${s.app}:${s.path}`)),{version:1,generatedAt:new Date().toISOString(),repoRoot:e.repoRoot,home:Y,items:c,summary:{total:c.length,existing:c.filter((o)=>o.exists).length,secrets:c.filter((o)=>o.secretFindings.length>0).length,drift:c.filter((o)=>o.mirrors.some((s)=>s.exists&&s.identical===!1)).length,generated:c.filter((o)=>o.kind==="generated").length,private:c.filter((o)=>o.shareability==="private").length}}}function Ht(e,r={}){let t=r.path??W(e.repoRoot,".atelier","state","inventory.json");return fi(Yt(t),{recursive:!0}),gi(t,JSON.stringify(e,null,2)+`
11
+ `,"utf-8"),t}function pi(e){let r=W(e,"packages","registry","definitions");if(!Q(r))return Zt;return cr(r).filter((t)=>t.endsWith(".jsonc")).map((t)=>Jt(se(W(r,t),"utf-8")))}function mi(e,r,t){return Pt({path:t,domain:e.domain,app:e.app,kind:r.kind,format:r.format,shareability:r.shareability,reason:"registry match",mirrors:r.mirrors??[],privateByDefault:e.privateByDefault,id:r.id})}function Xt(e){let r=Ii(e.path),t=Mi(e.path),n=Ui(e.path,t);return Pt({path:e.path,domain:Ri(e.path),app:r,kind:t,format:Li(e.path),shareability:n,reason:e.reason,mirrors:[],privateByDefault:n==="private"})}function Pt(e){let r=Q(e.path),t=r?ai(e.path):void 0,n=r?V(e.path):void 0,c=!!n?.isDirectory(),o=!!t?.isSymbolicLink(),s=r&&!c&&qt(e.path)?Ae(se(e.path,"utf-8")):[],l=e.mirrors.map((b)=>Ti(e.path,ir(b))),u=Si(e.kind,e.shareability,s.length,l),f=ki(e.path,r,c,e.shareability,e.privateByDefault,e.kind);return{id:e.id??Ki(e.path),domain:e.domain,app:e.app,path:e.path,displayPath:le(e.path),kind:e.kind,format:e.format,shareability:e.shareability,exists:r,isDirectory:c,isSymlink:o,mode:n?`0${(n.mode&511).toString(8)}`:void 0,owner:r?di().username:void 0,size:n?.size,git:r?Ci(e.path):void 0,legacyManagers:r?$i(e.path):{},mirrors:l,secretFindings:s,...f,recommendation:u,reason:e.reason}}function Ai(){let e=[],r=W(Y,".config");if(!Q(r))return e;for(let t of cr(r,{withFileTypes:!0})){if(t.name.startsWith("."))continue;let n=W(r,t.name);if(e.push({path:n,reason:"~/.config app directory"}),!t.isDirectory())continue;for(let c of hi(n).slice(0,80)){let o=W(n,c.name);if(sr(o)){e.push({path:o,reason:"generated/app-state candidate"});continue}if(c.isFile()&&lr(c.name))e.push({path:o,reason:"shallow ~/.config config candidate"});if(c.isDirectory()&&["conf.d","themes","snippets","plugins"].includes(c.name))e.push({path:o,reason:"shallow ~/.config config directory"})}}return e}function hi(e){try{return cr(e,{withFileTypes:!0})}catch{return[]}}function Ti(e,r){let t=Q(r);if(!t||!Q(e)||V(e).isDirectory()||V(r).isDirectory())return{path:r,displayPath:le(r),exists:t};let n=se(e,"utf-8"),c=se(r,"utf-8");return{path:r,displayPath:le(r),exists:t,identical:n===c,diff:n===c?void 0:Bi(c,n)}}function Bi(e,r){let t=e.split(/\r?\n/),n=r.split(/\r?\n/),c=Math.max(t.length,n.length),o=[];for(let s=0;s<c;s++){if(t[s]===n[s])continue;if(t[s]!==void 0)o.push(`-${t[s]}`);if(n[s]!==void 0)o.push(`+${n[s]}`)}return o.slice(0,200).join(`
12
+ `)}function ki(e,r,t,n,c,o){if(!r)return{previewSuppressedReason:"missing"};if(t)return{previewSuppressedReason:"directory"};if(n==="private"||c||o==="private")return{previewSuppressedReason:"private/auth metadata-only"};if(!qt(e))return{previewSuppressedReason:"binary or unsupported file type"};let s=se(e,"utf-8");return{preview:ot(s).slice(0,20000)}}function Si(e,r,t,n){if(t>0)return"rotate-secret";if(e==="generated")return"ignore-generated";if(r==="private")return"mark-private";if(n.some((c)=>c.exists&&c.identical===!1))return"resolve-drift";if(r==="machine-specific")return"review-machine-specific";if(e==="config"||e==="directory")return"adopt-candidate";return"none"}function Ci(e){let r=V(e).isDirectory()?e:Yt(e),t=Be(["rev-parse","--show-toplevel"],r);if(!t)return;let n=Ot(t,e),c=!!Be(["check-ignore","-q",n],t,!0),o=!!Be(["ls-files","--error-unmatch",n],t,!0),s=o&&!!Be(["status","--porcelain","--",n],t);return{root:t,tracked:o,modified:s,ignored:c}}function $i(e){if(!ke)return{};return{yadm:zi(e)}}function zi(e){let r=le(e).replace(/^~\//,"");if(ke?.modified.has(r))return"modified";if(ke?.tracked.has(r))return"tracked";return"unknown"}function xi(){let e=new Set((Wt("yadm",["ls-files"])??"").split(`
13
+ `).filter(Boolean)),r=new Set((Wt("yadm",["status","--porcelain"])??"").split(`
14
+ `).map((t)=>t.slice(3).trim()).filter(Boolean));return{tracked:e,modified:r}}function Be(e,r,t=!1){try{return Qt("git",e,{cwd:r,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||(t?"ok":void 0)}catch{return}}function Wt(e,r){try{return Qt(e,r,{cwd:Y,encoding:"utf-8",stdio:["ignore","pipe","ignore"]})}catch{return}}function ir(e){return yi(e.replace(/^~(?=\/|$)/,Y))}function le(e){return e.startsWith(Y)?`~${e.slice(Y.length)}`:e}function Ki(e){return le(e).replace(/[^A-Za-z0-9_.-]+/g,":")}function Ii(e){let r=Ot(W(Y,".config"),e);if(!r.startsWith(".."))return r.split(/[\\/]/)[0]||"Unknown";return"Unknown"}function Ri(e){if(e.includes("/.config/"))return"~/.config";if(e.includes("/.ssh")||e.includes("/.aws"))return"Private/Auth";return"Unknown"}function Mi(e){if(sr(e))return"generated";if(vi.some((r)=>r.test(e)))return"private";if(Q(e)&&V(e).isDirectory())return"directory";if(lr(e))return"config";return"unknown"}function Ui(e,r){if(r==="private")return"private";if(r==="generated")return"machine-specific";if(e.includes("/credentials")||e.includes("/.ssh")||e.includes("/.aws"))return"private";return"machine-specific"}function Li(e){if(Q(e)&&V(e).isDirectory())return"directory";if(e.endsWith(".jsonc"))return"jsonc";if(e.endsWith(".json"))return"json";if(e.endsWith(".toml"))return"toml";if(e.endsWith(".zsh"))return"shell";if(e.endsWith(".md"))return"markdown";return"text"}function sr(e){return bi.some((r)=>r.test(e))}function lr(e){return/(^config\.|settings\.|rc$|\.rc$|\.zshrc$|\.zshenv$|\.jsonc?$|\.toml$|\.ya?ml$|\.zsh$|\.conf$|\.ini$)/i.test(e)}function qt(e){let r=e.split("/").pop()??"";if(sr(e))return!1;if(r.includes("lock")||r.endsWith(".mdb")||r.endsWith(".sqlite")||r.endsWith(".db"))return!1;let t=r.includes(".")?r.slice(r.lastIndexOf(".")):"";return wi.has(t)||lr(r)}import{Box as g,Text as a,render as fr,useApp as Dt,useInput as Fi}from"ink";import{useEffect as _i,useMemo as Zi,useState as E}from"react";import{jsxDEV as i,Fragment as qi}from"react/jsx-dev-runtime";function v(e){return fr(i(qi,{children:e},void 0,!1,void 0,this)).waitUntilExit()}async function gr(e,r){return await new Promise((t,n)=>{let c=fr(i(Ji,{operation:e,options:r,onDone:(o,s)=>{if(c.unmount(),s)n(s);else t(o)}},void 0,!1,void 0,this))})}function Ji({operation:e,options:r,onDone:t}){let{exit:n}=Dt(),[c,o]=E(0),s=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];return _i(()=>{let l=!1,u=setInterval(()=>o((f)=>f+1),80);return e().then((f)=>{if(l)return;clearInterval(u),t(f),n()},(f)=>{if(l)return;clearInterval(u),t(void 0,f),n()}),()=>{l=!0,clearInterval(u)}},[]),i(g,{flexDirection:"column",children:[i(B,{title:r.title,subtitle:r.subtitle},void 0,!1,void 0,this),i(a,{color:"cyan",children:[s[c%s.length]," ",r.detail??"Working\u2026"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}async function Et(e){return await new Promise((r)=>{let t=fr(i(Xi,{plan:e,onDone:(n)=>{r(n),t.unmount()}},void 0,!1,void 0,this))})}function ur({inventory:e,path:r}){return i(g,{flexDirection:"column",gap:1,children:[i(B,{title:"Scan complete",subtitle:r},void 0,!1,void 0,this),i(g,{gap:2,children:[i(D,{label:"total",value:e.summary.total,color:"cyan"},void 0,!1,void 0,this),i(D,{label:"existing",value:e.summary.existing,color:"green"},void 0,!1,void 0,this),i(D,{label:"private",value:e.summary.private,color:"red"},void 0,!1,void 0,this),i(D,{label:"generated",value:e.summary.generated,color:"magenta"},void 0,!1,void 0,this),i(D,{label:"secrets",value:e.summary.secrets,color:"red"},void 0,!1,void 0,this),i(D,{label:"drift",value:e.summary.drift,color:"blue"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function jt({items:e,title:r}){return i(g,{flexDirection:"column",children:[i(B,{title:r,subtitle:`${e.length} item${e.length===1?"":"s"}`},void 0,!1,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:e.map((t)=>i(g,{gap:1,children:[i(a,{color:t.exists?"white":"gray",children:t.exists?"\u25CF":"\u25CB"},void 0,!1,void 0,this),i(a,{color:pn(t),children:t.domain},void 0,!1,void 0,this),i(a,{color:"gray",children:"/"},void 0,!1,void 0,this),i(a,{color:"cyan",children:t.app},void 0,!1,void 0,this),i(a,{children:t.displayPath},void 0,!1,void 0,this),i(L,{label:t.shareability,color:mn(t.shareability)},void 0,!1,void 0,this),t.secretFindings.length>0?i(L,{label:"secret",color:"red"},void 0,!1,void 0,this):null,t.mirrors.some((n)=>n.exists&&n.identical===!1)?i(L,{label:"drift",color:"blue"},void 0,!1,void 0,this):null]},t.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function en({item:e}){return i(g,{flexDirection:"column",gap:1,children:[i(B,{title:e.app,subtitle:e.displayPath},void 0,!1,void 0,this),i(g,{gap:1,children:[i(L,{label:e.domain,color:"cyan"},void 0,!1,void 0,this),i(L,{label:e.kind,color:pn(e)},void 0,!1,void 0,this),i(L,{label:e.shareability,color:mn(e.shareability)},void 0,!1,void 0,this),i(L,{label:e.recommendation,color:"yellow"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i(Wi,{rows:[["reason",e.reason],["exists",String(e.exists)],["mode",e.mode??"\u2014"],["symlink",String(e.isSymlink)],["git",Pi(e)],["legacy",Hi(e)]]},void 0,!1,void 0,this),e.secretFindings.length>0?i(g,{flexDirection:"column",children:[i(a,{color:"red",bold:!0,children:"Secret warnings"},void 0,!1,void 0,this),e.secretFindings.map((r,t)=>i(a,{color:"red",children:[" ",r.type,r.line?` line ${r.line}`:"",": ",r.preview]},`${r.type}-${t}`,!0,void 0,this))]},void 0,!0,void 0,this):null,e.mirrors.length>0?i(g,{flexDirection:"column",children:[i(a,{color:"blue",bold:!0,children:"Mirrors"},void 0,!1,void 0,this),e.mirrors.map((r)=>i(a,{children:[" ",r.displayPath," \u2014 ",r.exists?r.identical===!1?"differs":"identical":"missing"]},r.path,!0,void 0,this))]},void 0,!0,void 0,this):null,i(g,{flexDirection:"column",children:[i(a,{bold:!0,children:e.preview?"Safe preview":"Preview"},void 0,!1,void 0,this),i(a,{color:e.preview?"white":"gray",children:e.preview?e.preview.slice(0,3000):`Suppressed: ${e.previewSuppressedReason??"not available"}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function rn({verificationUri:e,userCode:r,expiresIn:t}){return i(g,{flexDirection:"column",gap:1,children:[i(B,{title:"Login with GitHub",subtitle:`code expires in ${Math.round(t/60)} minutes`},void 0,!1,void 0,this),i(g,{flexDirection:"column",children:[i(a,{children:"Open:"},void 0,!1,void 0,this),i(a,{color:"blue",underline:!0,children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this),i(g,{gap:1,children:[i(a,{children:"Enter code:"},void 0,!1,void 0,this),i(a,{color:"green",bold:!0,children:r},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function tn({login:e,apiUrl:r}){return i(g,{flexDirection:"column",children:[i(B,{title:"Logged in",subtitle:r},void 0,!1,void 0,this),i(a,{color:"green",children:["\u2713 ",e]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function nn({login:e,apiUrl:r}){if(!e)return i(a,{color:"yellow",children:"Not logged in. Run `atl login`."},void 0,!1,void 0,this);return i(g,{flexDirection:"column",children:[i(B,{title:"Current account",subtitle:r},void 0,!1,void 0,this),i(a,{color:"green",children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function on(){return i(a,{color:"green",children:"\u2713 Logged out"},void 0,!1,void 0,this)}function cn({profiles:e,activeProfile:r}){return i(g,{flexDirection:"column",children:[i(B,{title:"Profiles",subtitle:`active: ${r}`},void 0,!1,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:e.map((t)=>i(g,{gap:1,children:[i(a,{color:t.name===r?"green":"gray",children:t.name===r?"\u25CF":"\u25CB"},void 0,!1,void 0,this),i(a,{bold:t.name===r,children:t.name},void 0,!1,void 0,this),i(a,{color:"gray",children:t.createdAt},void 0,!1,void 0,this)]},t.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function dr({title:e,name:r}){return i(g,{flexDirection:"column",children:[i(B,{title:e},void 0,!1,void 0,this),i(a,{color:"green",children:["\u2713 ",r]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function sn({configs:e,profileName:r}){return i(g,{flexDirection:"column",children:[i(B,{title:"Saved configs",subtitle:r},void 0,!1,void 0,this),e.length===0?i(a,{color:"gray",children:"No saved configs yet."},void 0,!1,void 0,this):e.map((t)=>i(g,{flexDirection:"column",marginTop:1,children:[i(a,{bold:!0,children:t.stableId},void 0,!1,void 0,this),i(a,{color:"gray",children:t.pathHint??"no path hint"},void 0,!1,void 0,this),t.latestVersion?i(a,{color:"green",children:[t.latestVersion.contentSha256.slice(0,12)," \xB7 ",t.latestVersion.sizeBytes," bytes \xB7 ",t.latestVersion.createdAt]},void 0,!0,void 0,this):null]},t.id,!0,void 0,this))]},void 0,!0,void 0,this)}function ln({config:e,profileName:r}){return i(g,{flexDirection:"column",children:[i(B,{title:e.stableId,subtitle:r},void 0,!1,void 0,this),i(a,{color:"gray",children:e.pathHint??"no path hint"},void 0,!1,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:(e.versions??[]).map((t)=>i(a,{children:[t.contentSha256.slice(0,12)," \xB7 ",t.sizeBytes," bytes \xB7 ",t.createdAt]},t.id,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function an({stableId:e,profileName:r,versionHash:t,sizeBytes:n,reused:c}){return i(g,{flexDirection:"column",children:[i(B,{title:c?"Config already saved":"Config saved",subtitle:r},void 0,!1,void 0,this),i(a,{color:"green",children:["\u2713 ",e]},void 0,!0,void 0,this),i(a,{color:"gray",children:["Version ",t.slice(0,12)," \xB7 ",n," bytes \xB7 encrypted"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function Xi({plan:e,onDone:r}){let{exit:t}=Dt(),[n,c]=E("overview"),[o,s]=E(0),[l,u]=E(()=>new Set(e.files.filter((d)=>d.selectedByDefault).map((d)=>d.relativePath))),[f,b]=E(""),[m,y]=E(!1),h=An(e),z=e.files.filter((d)=>l.has(d.relativePath)),w=Zi(()=>{let d=f.trim().toLowerCase(),$=e.files.filter((A)=>{if(n==="overview")return!1;if(n==="selected")return l.has(A.relativePath);if(n==="all")return!0;return A.confidence===n});if(!d)return $;return $.filter((A)=>A.relativePath.toLowerCase().includes(d))},[n,e.files,f,l]),M=Math.max(0,Math.min(o-8,Math.max(0,w.length-18))),O=w.slice(M,M+18),_=w[o],U=(d)=>{r(d),t()},k=(d)=>{c(d),s(0),b(""),y(!1)};if(Fi((d,$)=>{if(m){if($.return){y(!1),s(0);return}if($.escape){y(!1),b(""),s(0);return}if($.backspace||$.delete){b((A)=>A.slice(0,-1));return}if(d&&!$.ctrl)b((A)=>A+d);return}if(d==="q"){U(void 0);return}if($.escape||d==="b"){if(n==="overview")U(void 0);else k("overview");return}if(d==="c"||$.return&&n==="overview"){U([...l].sort());return}if(d==="s"){k("selected");return}if(d==="h"){k("high-confidence");return}if(d==="m"){k("medium-confidence");return}if(d==="l"){k("low-confidence");return}if(d==="f"||d==="/"){if(n==="overview")k("all");y(!0);return}if($.upArrow||d==="k"){s((A)=>Math.max(0,A-1));return}if($.downArrow||d==="j"){s((A)=>Math.min(Math.max(w.length-1,0),A+1));return}if(d===" "){let A=w[o];if(!A)return;u((I)=>{let R=new Set(I);if(R.has(A.relativePath))R.delete(A.relativePath);else R.add(A.relativePath);return R});return}if(d==="a"){u((A)=>new Set([...A,...w.map((I)=>I.relativePath)]));return}if(d==="n")u((A)=>{let I=new Set(A);for(let R of w)I.delete(R.relativePath);return I})}),n==="overview")return i(g,{flexDirection:"column",children:[i(B,{title:"Review folder save",subtitle:e.rootDisplayPath},void 0,!1,void 0,this),i(a,{color:"gray",children:[e.files.length," eligible \xB7 ",e.skipped.length," skipped \xB7 ",l.size," selected now"]},void 0,!0,void 0,this),i(a,{color:"gray",children:[h.high," high \xB7 ",h.medium," medium \xB7 ",h.low," low confidence"]},void 0,!0,void 0,this),i(fn,{plan:e},void 0,!1,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:[i(a,{color:"green",bold:!0,children:"Will save now"},void 0,!1,void 0,this),z.slice(0,12).map((d)=>i(a,{color:"green",children:["\u2713 ",ar(d.confidence)," ",d.relativePath," \xB7 ",Vt(d.sizeBytes)]},d.relativePath,!0,void 0,this)),z.length>12?i(a,{color:"gray",children:["\u2026 ",z.length-12," more selected"]},void 0,!0,void 0,this):null,z.length===0?i(a,{color:"yellow",children:"No files are selected yet. Review high, medium, or low confidence groups before saving."},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:[i(a,{color:"yellow",children:"Review before adding more"},void 0,!1,void 0,this),i(a,{color:"gray",children:"h high confidence \xB7 m medium confidence \xB7 l low confidence \xB7 s selected \xB7 f find all"},void 0,!1,void 0,this),i(a,{color:"gray",children:"enter/c save selected \xB7 q cancel"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),e.skipped.length>0?i(a,{color:"yellow",children:[e.skipped.length," blocked path",e.skipped.length===1?"":"s",". Use --preview to inspect reasons."]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this);return i(g,{flexDirection:"column",children:[i(B,{title:`Review ${Gi(n)}`,subtitle:e.rootDisplayPath},void 0,!1,void 0,this),i(a,{color:"gray",children:[w.length," visible \xB7 ",l.size," selected total"]},void 0,!0,void 0,this),i(a,{color:m?"cyan":"gray",children:["Filter: ",f||"all",m?"\u2588":""]},void 0,!0,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:[O.map((d,$)=>{let I=M+$===o,R=l.has(d.relativePath);return i(a,{color:I?"cyan":R?"green":void 0,children:[I?"\u203A":" "," [",R?"x":" ","] ",ar(d.confidence)," ",d.relativePath," \xB7 ",Vt(d.sizeBytes)]},d.relativePath,!0,void 0,this)}),w.length===0?i(a,{color:"yellow",children:"No files match this view."},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),_?i(a,{color:"gray",children:["Reason: ",_.confidenceReasons.join(", "),_.defaultSelectionReason?` \xB7 ${_.defaultSelectionReason}`:""]},void 0,!0,void 0,this):null,i(a,{color:"gray",children:"space toggle \xB7 a select visible \xB7 n clear visible \xB7 / filter \xB7 b back \xB7 c save selected \xB7 q cancel"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function fn({plan:e}){let r=e.recipeDelta;if(!e.recipe||!r)return null;return i(g,{flexDirection:"column",marginTop:1,children:[i(a,{color:"cyan",children:["Using saved recipe from ",e.recipe.updatedAt]},void 0,!0,void 0,this),i(a,{color:"gray",children:[r.selectedExisting.length," selected \xB7 ",r.newRecommended.length," new recommended \xB7 ",r.newUnreviewed.length," new unreviewed \xB7 ",r.missingSelected.length," missing"]},void 0,!0,void 0,this),r.newRecommended.length>0?i(a,{color:"yellow",children:["New recommended: ",r.newRecommended.slice(0,5).join(", "),r.newRecommended.length>5?"\u2026":""]},void 0,!0,void 0,this):null,r.missingSelected.length>0?i(a,{color:"yellow",children:["Missing from recipe: ",r.missingSelected.slice(0,5).join(", "),r.missingSelected.length>5?"\u2026":""]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function Se({plan:e}){let r=An(e);return i(g,{flexDirection:"column",children:[i(B,{title:"Folder save preview",subtitle:e.rootDisplayPath},void 0,!1,void 0,this),i(a,{color:"gray",children:[e.files.length," eligible \xB7 ",r.defaultSelected," selected by default \xB7 ",e.skipped.length," skipped"]},void 0,!0,void 0,this),i(a,{color:"gray",children:[r.high," high \xB7 ",r.medium," medium \xB7 ",r.low," low confidence"]},void 0,!0,void 0,this),i(fn,{plan:e},void 0,!1,void 0,this),i(g,{flexDirection:"column",marginTop:1,children:[e.files.slice(0,25).map((t)=>i(a,{color:t.selectedByDefault?"green":t.confidence==="medium-confidence"?"yellow":"gray",children:[t.selectedByDefault?"\u2713":" "," ",ar(t.confidence)," ",t.relativePath," \xB7 ",t.sizeBytes," bytes \xB7 ",t.confidenceReasons.join(", ")]},t.relativePath,!0,void 0,this)),e.files.length>25?i(a,{color:"gray",children:["\u2026 ",e.files.length-25," more file",e.files.length-25===1?"":"s"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this),e.skipped.length>0?i(g,{flexDirection:"column",marginTop:1,children:[i(a,{color:"yellow",children:"Skipped"},void 0,!1,void 0,this),e.skipped.slice(0,25).map((t,n)=>i(a,{color:"gray",children:["- ",t.relativePath," \xB7 ",t.reason]},`${t.displayPath}:${t.reason}:${n}`,!0,void 0,this)),e.skipped.length>25?i(a,{color:"gray",children:["\u2026 ",e.skipped.length-25," more skipped"]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function gn({result:e}){return i(g,{flexDirection:"column",children:[i(B,{title:e.reused?"Folder already saved":"Folder saved",subtitle:e.profileName},void 0,!1,void 0,this),i(a,{color:"green",children:["\u2713 ",e.rootDisplayPath]},void 0,!0,void 0,this),i(a,{color:"gray",children:[e.files.length," file",e.files.length===1?"":"s"," saved \xB7 ",e.skipped.length," skipped \xB7 manifest ",e.manifestVersion.contentSha256.slice(0,12)]},void 0,!0,void 0,this),e.skipped.length>0?i(a,{color:"yellow",children:"Run with --preview to inspect skipped paths."},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function un({result:e,preview:r}){let t=r?"Apply preview":e.status==="blocked"?"Apply blocked":"Config applied";return i(g,{flexDirection:"column",children:[i(B,{title:t,subtitle:e.profileName},void 0,!1,void 0,this),i(vn,{result:e},void 0,!1,void 0,this),i(a,{children:e.displayPath},void 0,!1,void 0,this),i(a,{color:"gray",children:e.reason},void 0,!1,void 0,this),e.backupPath?i(a,{color:"yellow",children:["Backup: ",e.backupPath]},void 0,!0,void 0,this):null,i(a,{color:"gray",children:["Version ",e.version.contentSha256.slice(0,12)," \xB7 ",e.version.sizeBytes," bytes \xB7 encrypted"]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function dn({result:e}){return i(wn,{result:e,title:e.preview?"Folder apply preview":e.blocked?"Folder apply blocked":"Folder applied",emptyText:"No saved files in this folder."},void 0,!1,void 0,this)}function yn({result:e}){return i(wn,{result:e,title:e.preview?"Profile switch preview":e.blocked?"Profile switch blocked":"Profile switched",emptyText:"No saved configs in this profile."},void 0,!1,void 0,this)}function wn({result:e,title:r,emptyText:t}){let n=e.results.filter((o)=>o.status==="create"||o.status==="update").length,c=e.results.filter((o)=>o.status==="blocked").length;return i(g,{flexDirection:"column",children:[i(B,{title:r,subtitle:e.profileName},void 0,!1,void 0,this),e.results.length===0?i(a,{color:"gray",children:t},void 0,!1,void 0,this):null,e.results.length>0?i(a,{color:"gray",children:[n," change",n===1?"":"s"," \xB7 ",c," blocked \xB7 ",e.results.length," total"]},void 0,!0,void 0,this):null,i(g,{flexDirection:"column",marginTop:1,children:e.results.map((o)=>i(g,{flexDirection:"column",children:[i(vn,{result:o},void 0,!1,void 0,this),i(a,{color:"gray",children:[" ",o.displayPath]},void 0,!0,void 0,this),i(a,{color:"gray",children:[" ",o.reason]},void 0,!0,void 0,this),o.backupPath?i(a,{color:"yellow",children:[" Backup: ",o.backupPath]},void 0,!0,void 0,this):null]},o.stableId,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function bn({checks:e}){let r=e.filter((n)=>n.status==="fail").length,t=e.filter((n)=>n.status==="warn").length;return i(g,{flexDirection:"column",gap:1,children:[i(B,{title:"Doctor",subtitle:r?`${r} failing`:t?`${t} warning${t===1?"":"s"}`:"all checks passed"},void 0,!1,void 0,this),i(g,{flexDirection:"column",children:e.map((n)=>i(g,{gap:1,children:[i(a,{color:Yi(n.status),children:Qi(n.status)},void 0,!1,void 0,this),i(a,{bold:!0,children:n.label},void 0,!1,void 0,this),i(a,{color:"gray",children:n.detail},void 0,!1,void 0,this)]},n.label,!0,void 0,this))},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function yr({query:e}){return i(a,{color:"red",children:["No inventory item matched: ",e]},void 0,!0,void 0,this)}function B({title:e,subtitle:r}){return i(g,{flexDirection:"column",children:[i(a,{bold:!0,color:"cyan",children:"\u25C6 Atelier"},void 0,!1,void 0,this),i(g,{gap:1,children:[i(a,{bold:!0,children:e},void 0,!1,void 0,this),r?i(a,{color:"gray",children:r},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function D({label:e,value:r,color:t}){return i(g,{flexDirection:"column",borderStyle:"round",borderColor:t,paddingX:1,children:[i(a,{color:t,bold:!0,children:r},void 0,!1,void 0,this),i(a,{color:"gray",children:e},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function L({label:e,color:r}){return i(a,{color:r,children:["[",e,"]"]},void 0,!0,void 0,this)}function vn({result:e}){return i(g,{gap:1,children:[i(a,{color:Nt(e.status),children:Oi(e.status)},void 0,!1,void 0,this),i(a,{bold:!0,children:e.stableId},void 0,!1,void 0,this),i(L,{label:e.status,color:Nt(e.status)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Wi({rows:e}){return i(g,{flexDirection:"column",children:e.map(([r,t])=>i(g,{gap:1,children:[i(a,{color:"gray",children:r.padEnd(10)},void 0,!1,void 0,this),i(a,{children:t},void 0,!1,void 0,this)]},r,!0,void 0,this))},void 0,!1,void 0,this)}function pn(e){let r=typeof e==="string"?e:e.kind;if(r==="private")return"red";if(r==="generated")return"magenta";if(r==="config")return"green";return"yellow"}function mn(e){if(e==="private")return"red";if(e==="shareable")return"green";return"yellow"}function Qi(e){if(e==="pass")return"\u2713";if(e==="warn")return"!";return"\u2717"}function Yi(e){if(e==="pass")return"green";if(e==="warn")return"yellow";return"red"}function Nt(e){if(e==="unchanged")return"green";if(e==="create")return"cyan";if(e==="update")return"yellow";return"red"}function Oi(e){if(e==="unchanged")return"\u2713";if(e==="create")return"+";if(e==="update")return"\xB1";return"\u2717"}function An(e){return{high:e.files.filter((r)=>r.confidence==="high-confidence").length,medium:e.files.filter((r)=>r.confidence==="medium-confidence").length,low:e.files.filter((r)=>r.confidence==="low-confidence").length,defaultSelected:e.files.filter((r)=>r.selectedByDefault).length}}function ar(e){if(e==="high-confidence")return"high";if(e==="medium-confidence")return"medium";return"low"}function Gi(e){if(e==="selected")return"selected files";if(e==="high-confidence")return"high confidence files";if(e==="medium-confidence")return"medium confidence files";if(e==="low-confidence")return"low confidence files";return"all files"}function Vt(e){if(e<1024)return`${e} B`;let r=e/1024;if(r<1024)return`${Math.round(r)} KiB`;return`${Math.round(r/1024)} MiB`}function Hi(e){let r=Object.entries(e.legacyManagers??{});if(r.length===0)return"not scanned";return r.map(([t,n])=>`${t}: ${n}`).join(", ")}function Pi(e){if(!e.git)return"not in repo";return`${e.git.tracked?"tracked":"untracked"}${e.git.modified?", modified":""} @ ${e.git.root}`}import{jsxDEV as p}from"react/jsx-dev-runtime";var ji=hn(import.meta.dir,"../../.."),Tn=rc(),j=Ce(Tn,"inventory.json"),ze,ec=25,C=new Ei;C.name("atl").description("Atelier config management CLI").version("0.2.0");C.command("login").description("Login to Atelier with GitHub device auth").option("--api-url <url>","Atelier API URL",ge()).action(async(e)=>{let r=await Sr({apiUrl:e.apiUrl,onPrompt:async(t)=>{await v(p(rn,{verificationUri:t.verificationUri,userCode:t.userCode,expiresIn:t.expiresIn},void 0,!1,void 0,this))}});await v(p(tn,{login:r.user.login,apiUrl:r.apiUrl},void 0,!1,void 0,this))});C.command("whoami").description("Show the current Atelier account").action(async()=>{let e=await Cr();if(await v(p(nn,{login:e?.user.login,apiUrl:e?.apiUrl},void 0,!1,void 0,this)),!e)process.exitCode=1});C.command("logout").description("Remove the local Atelier session").action(async()=>{zr(),await v(p(on,{},void 0,!1,void 0,this))});var xe=C.command("profile").description("Manage account-backed config profiles");xe.command("list").description("List remote profiles").action(async()=>{await v(p(cn,{profiles:await Kr(),activeProfile:T()},void 0,!1,void 0,this))});xe.command("create").description("Create a remote profile").argument("<name>").action(async(e)=>{let r=await Ir(e);await v(p(dr,{title:"Profile created",name:r.name},void 0,!1,void 0,this))});xe.command("switch").description("Apply a remote profile to this machine and make it active").argument("<name>").option("--preview","show profile changes without writing files or switching").option("--backup","back up differing local files before replacing them").action(async(e,r)=>{await Sn(e,r)});xe.command("current").description("Show the active local profile").action(async()=>{await v(p(dr,{title:"Active profile",name:T()},void 0,!1,void 0,this))});C.command("checkout").description("Alias for `atl profile switch`").argument("<name>").option("--preview","show profile changes without writing files or switching").option("--backup","back up differing local files before replacing them").action(async(e,r)=>{await Sn(e,r)});var Ke=C.command("vault").description("Advanced vault controls");Ke.command("status").description("Show vault initialization and local unlock state").action(async()=>{let e=await pe();console.log(`Vault: ${e.initialized?"initialized":"not initialized"}`),console.log(`Local state: ${e.unlocked?"unlocked":"locked"}`),console.log(`Active profile: ${e.activeProfile}`)});Ke.command("init").description("Initialize the encrypted vault now instead of waiting for first save").action(async()=>{let e=await Cn("Create an Atelier vault passphrase: "),r=await Ye(e);console.log(`Vault initialized for profile ${r.profileName}`)});Ke.command("unlock").description("Unlock this machine with the vault passphrase").action(async()=>{let e=await ae("Vault passphrase: "),r=await Zr(e);console.log(`Vault unlocked for profile ${r.activeProfile}`)});Ke.command("lock").description("Remove local unlocked vault material from this machine").action(async()=>{Jr(),console.log("Vault locked")});C.command("save").description("Save a config snapshot to the active encrypted profile").argument("<id-or-path>").option("--preview","show which folder files would be saved without uploading").option("--review","open the interactive folder review picker").action(async(e,r)=>{await tc(e,r)});C.command("apply").description("Apply a saved config to this machine").argument("<id-or-path>").option("--preview","show the local changes without writing files").option("--backup","back up a differing local file before replacing it").action(async(e,r)=>{await cc(e,r)});var Bn=C.command("saved").description("Inspect encrypted configs saved remotely");Bn.command("list").description("List saved configs for the active profile").action(async()=>{let e=T();await v(p(sn,{configs:await ne(e),profileName:e},void 0,!1,void 0,this))});Bn.command("show").description("Show saved metadata and version history").argument("<stable-id>").action(async(e)=>{let r=T(),t=await ye(r,e);if(!t)throw new Error(`Saved config not found: ${e}`);await v(p(ln,{config:t,profileName:r},void 0,!1,void 0,this))});C.command("scan").description("Scan this machine and write local inventory").option("--path <path...>","additional manual path(s) to scan").option("--legacy","include legacy manager signals like yadm").action(async(e)=>{let r=await Gt({repoRoot:ji,manualPaths:e.path??[],includeLegacyManagers:e.legacy}),t=Ht(r,{path:j});await v(p(ur,{inventory:r,path:t},void 0,!1,void 0,this))});C.command("list").description("List inventory items with polished terminal output").option("--domain <domain>","filter by domain").option("--app <app>","filter by app").option("--secrets","only items with secret warnings").option("--drift","only items with mirror drift").option("--generated","only generated/app-state items").option("--private","only private items").option("--missing","only missing registry items").option("--json","print JSON instead of Ink output").action(async(e)=>{let r=fe(),t=lc(r.items,e);if(e.json)return Ie(t);await v(p(jt,{items:t,title:"Inventory"},void 0,!1,void 0,this))});C.command("inspect").description("Inspect one inventory item by id or path").argument("<id-or-path>").option("--json","print JSON instead of Ink output").action(async(e,r)=>{let t=fe(),n=zn(t,e);if(r.json)return Ie(n??null);await v(n?p(en,{item:n},void 0,!1,void 0,this):p(yr,{query:e},void 0,!1,void 0,this))});C.command("summary").description("Print the last scan summary").option("--json","print JSON instead of Ink output").action(async(e)=>{let r=fe();if(e.json)return Ie(r.summary);await v(p(ur,{inventory:r,path:j},void 0,!1,void 0,this))});C.command("doctor").description("Check Atelier CLI, account, inventory, and local environment health").option("--json","print JSON instead of Ink output").action(async(e)=>{let r=fc();if(e.json)Ie(r);else await v(p(bn,{checks:r},void 0,!1,void 0,this));if(r.some((t)=>t.status==="fail"))process.exitCode=1});C.parseAsync(process.argv).catch((e)=>{console.error(e instanceof Error?e.message:e),process.exit(1)});function Ie(e){console.log(JSON.stringify(e,null,2))}function kn(e){return e.split(`
15
+ `).map((r)=>{if(r.startsWith("+")&&!r.startsWith("+++"))return`\x1B[32m${r}\x1B[0m`;if(r.startsWith("-")&&!r.startsWith("---"))return`\x1B[31m${r}\x1B[0m`;if(r.startsWith("@@"))return`\x1B[36m${r}\x1B[0m`;return r}).join(`
16
+ `)}function fe(){if(!$e(j))throw new Error("No inventory found. Run `atl scan` first.");return JSON.parse(pr(j,"utf-8"))}function rc(){if(process.env.ATELIER_STATE_DIR)return process.env.ATELIER_STATE_DIR;if(process.env.XDG_STATE_HOME)return Ce(process.env.XDG_STATE_HOME,"atelier");if(Di()==="win32"&&process.env.LOCALAPPDATA)return Ce(process.env.LOCALAPPDATA,"Atelier");return Ce(Vi(),".local","state","atelier")}async function tc(e,r){let t=$e(j)?fe():void 0,n=t?zn(t,e):void 0,c=xn(e),o=!n&&$e(c)&&Ni(c).isDirectory();if(!n&&!o){await v(p(yr,{query:e},void 0,!1,void 0,this)),process.exitCode=1;return}if(n?.isDirectory||o){let u=n??c,f=await er(u);if(r.preview){await v(p(Se,{plan:f},void 0,!1,void 0,this));return}let b=await zt(f),m=b?await ic(b):void 0;if(m==="cancel")return;let y=f.files.filter((k)=>k.selectedByDefault).map((k)=>k.relativePath),h,z,w=!1;if(m&&m!=="restart")h=m.selectedFiles.map((k)=>k.relativePath),z=m.runId;else if(r.review||f.files.length>ec||y.length===0){if(w=!0,!S.isTTY)throw await v(p(Se,{plan:f},void 0,!1,void 0,this)),new Error(`Folder has ${f.files.length} eligible files and ${y.length} recommended selections; rerun in an interactive terminal to review selections.`);if(h=await Et(f),!h){console.log("Folder save cancelled");return}if(h.length===0){console.log("No files selected"),process.exitCode=1;return}}else if(h=y,await v(p(Se,{plan:f},void 0,!1,void 0,this)),!await vr(`Save ${y.length} recommended file${y.length===1?"":"s"}? [y/N] `)){console.log("Folder save cancelled");return}let M=h&&!z&&await nc(f,h,w),O=Object.fromEntries(f.files.map((k)=>[k.relativePath,k.contentSha256])),_=await br({initialize:!0}),U=await gr(()=>Ct(u,{passphrase:_,includeRelativePaths:h,expectedContentSha256ByRelativePath:O,resumeRunId:z}),{title:"Saving folder",subtitle:f.rootDisplayPath,detail:`Encrypting and uploading ${h.length} file${h.length===1?"":"s"}\u2026`});if(M&&h)await $t(f,h),console.log(f.recipe?"Updated folder save recipe":"Saved folder save recipe");await v(p(gn,{result:U},void 0,!1,void 0,this));return}if(r.preview)throw new Error("--preview is only supported for folder saves");let s=await br({initialize:!0}),l=await gr(()=>St(n,{passphrase:s}),{title:"Saving config",subtitle:n.displayPath,detail:"Encrypting and uploading file\u2026"});await v(p(an,{stableId:l.stableId,profileName:l.profileName,versionHash:l.version.contentSha256,sizeBytes:l.version.sizeBytes,reused:l.reused},void 0,!1,void 0,this))}async function nc(e,r,t){if(!S.isTTY||r.length===0)return!1;if(e.recipe){if(!t||oc(e.recipe.includeRelativePaths,r))return!1;return await vr("Update saved folder recipe with this selection? [y/N] ")}return await vr("Remember this folder selection as a recipe for future saves? [y/N] ")}function oc(e,r){if(e.length!==r.length)return!1;let t=new Set(r);return e.every((n)=>t.has(n))}async function ic(e){let r=e.uploadedFiles.length,t=e.selectedFiles.length,n=e.error?` Last error: ${e.error}`:"";if(!S.isTTY)throw new Error(`Previous folder save failed before commit (${r}/${t} files uploaded). Rerun in an interactive terminal to resume, restart, or discard.${n}`);console.log(`Previous folder save failed before commit for ${e.rootDisplayPath}.`),console.log(`Uploaded ${r}/${t} selected files. Manifest was not committed.${n}`);while(!0){let c=(await $n("Resume upload, restart review, discard recovery, or cancel? [r/s/d/q] ")).trim().toLowerCase();if(c==="r"||c==="resume"||c==="")return e;if(c==="s"||c==="restart")return await rr(e.runId),"restart";if(c==="d"||c==="discard")return await rr(e.runId),console.log("Discarded folder save recovery record"),"cancel";if(c==="q"||c==="cancel")return"cancel"}}async function cc(e,r){let t=await br({initialize:!1}),n=await Vr(e,{passphrase:t,preview:r.preview,backup:r.backup});if(ac(n)){if(await v(p(dn,{result:n},void 0,!1,void 0,this)),r.preview||n.blocked)Kn(n.results);if(n.blocked)process.exitCode=1;return}if(await v(p(un,{result:n,preview:r.preview},void 0,!1,void 0,this)),n.diff&&(r.preview||n.status==="blocked"))console.log(kn(n.diff));if(n.status==="blocked")process.exitCode=1}async function Sn(e,r){let t=await de(e);if(!t)throw new Error(`Profile not found: ${e}`);let n=await sc(),c=await Dr(t.name,{passphrase:n,preview:r.preview,backup:r.backup});if(!r.preview&&!c.blocked)$r(t.name);if(await v(p(yn,{result:c},void 0,!1,void 0,this)),r.preview||c.blocked)Kn(c.results);if(c.blocked)process.exitCode=1}async function sc(){let e=await pe();if(e.initialized&&!e.unlocked)return await ae("Vault passphrase: ");return}async function br({initialize:e}){let r=await pe();if(!r.initialized){if(!e)throw new Error("Atelier vault is not initialized. Run `atl save <id>` first.");return await Cn("Create an Atelier vault passphrase: ")}if(!r.unlocked)return await ae("Vault passphrase: ");return}async function Cn(e){let r=await ae(e),t=await ae("Confirm vault passphrase: ");if(r!==t)throw new Error("Vault passphrases do not match");return r}async function vr(e){let r=await $n(e);return r.trim().toLowerCase()==="y"||r.trim().toLowerCase()==="yes"}async function $n(e){if(!S.isTTY)return F.write(e),ze??=pr(0,"utf-8").split(/\r?\n/),ze.shift()??"";return F.write(e),S.setEncoding("utf-8"),S.resume(),await new Promise((r)=>{let t="",n=()=>{S.off("data",o),S.pause()},c=()=>{n(),r(t)},o=(s)=>{for(let l of String(s)){if(l==="\x03")n(),F.write(`
17
+ `),process.exit(130);if(l==="\r"||l===`
18
+ `){F.write(`
19
+ `),c();return}t+=l}};S.on("data",o)})}async function ae(e){if(!S.isTTY)return F.write(e),ze??=pr(0,"utf-8").split(/\r?\n/),ze.shift()??"";return F.write(e),S.setEncoding("utf-8"),S.resume(),S.setRawMode(!0),await new Promise((r)=>{let t="",n=()=>{S.off("data",o),S.setRawMode(!1),S.pause()},c=()=>{n(),F.write(`
20
+ `),r(t)},o=(s)=>{for(let l of String(s)){if(l==="\x03")n(),F.write(`
21
+ `),process.exit(130);if(l==="\r"||l===`
22
+ `){c();return}if(l==="\x7F"){t=t.slice(0,-1);continue}t+=l}};S.on("data",o)})}function lc(e,r){return e.filter((t)=>{if(r.domain&&t.domain.toLowerCase()!==r.domain.toLowerCase())return!1;if(r.app&&t.app.toLowerCase()!==r.app.toLowerCase())return!1;if(r.secrets&&t.secretFindings.length===0)return!1;if(r.drift&&!t.mirrors.some((n)=>n.exists&&n.identical===!1))return!1;if(r.generated&&t.kind!=="generated")return!1;if(r.private&&t.shareability!=="private")return!1;if(r.missing&&t.exists)return!1;return!0})}function zn(e,r){let t=wr(r);return e.items.find((n)=>n.id===r||wr(n.path)===t||wr(n.displayPath)===t)??e.items.find((n)=>n.displayPath.includes(r)||n.path.includes(r))}function wr(e){return xn(e).toLowerCase()}function xn(e){return hn(e.replace(/^~(?=\/|$)/,process.env.HOME??""))}function ac(e){return"results"in e}function Kn(e){for(let r of e)if(r.diff&&(r.status==="update"||r.status==="blocked"))console.log(`
23
+ ${r.stableId}`),console.log(kn(r.diff))}function fc(){let e=[],r=$e(j)?fe():void 0,t=ue();return e.push({label:"runtime",status:process.versions.bun?"pass":"fail",detail:process.versions.bun?`Bun ${process.versions.bun}`:"Bun is required"}),e.push({label:"api",status:"pass",detail:ge()}),e.push({label:"session",status:t?"pass":"warn",detail:t?`logged in as ${t.user.login}`:"not logged in; run `atl login`"}),e.push({label:"state directory",status:"pass",detail:Tn}),e.push({label:"inventory",status:r?"pass":"warn",detail:r?`${r.summary.existing}/${r.summary.total} existing, generated ${r.generatedAt}`:"missing; run `atl scan`"}),e.push({label:"secret warnings",status:r&&r.summary.secrets>0?"warn":"pass",detail:r?`${r.summary.secrets} item${r.summary.secrets===1?"":"s"} flagged`:"no inventory"}),e}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manan_joshi/atelier",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Atelier config management CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,7 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "commander": "15.0.0",
21
+ "diff": "8.0.4",
21
22
  "ink": "7.0.5",
22
23
  "react": "19.2.7"
23
24
  },