@elixpo/lixblogs-cli 1.5.7 → 1.5.9

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.
package/README.md CHANGED
@@ -24,6 +24,20 @@ Press Enter to open the verification URL or copy it to another device. The
24
24
  username becomes the profile alias unless `--profile` overrides it. Use
25
25
  `profiles` and `use <username>` to switch accounts.
26
26
 
27
+ For CI, containers, and scheduled automation, create a scoped token in
28
+ **LixBlogs → Settings → API** and expose it only to the CLI process:
29
+
30
+ ```bash
31
+ LIXBLOGS_TOKEN="$LIXBLOGS_PAT" lixblogs blog list --json --no-input
32
+ lixblogs --token-file /run/secrets/lixblogs blog list --json --no-input
33
+ LIXBLOGS_TOKEN_FILE=/run/secrets/lixblogs lixblogs whoami --json --no-input
34
+ ```
35
+
36
+ Resolution order is `--token-file`, `LIXBLOGS_TOKEN`, `LIXBLOGS_TOKEN_FILE`,
37
+ then the active device-login profile. Direct tokens are not copied into the
38
+ keychain or profile registry. Scopes and personal/organization boundaries
39
+ remain server-enforced.
40
+
27
41
  ### Blog lifecycle
28
42
 
29
43
  ```bash
package/dist/lixblogs.mjs CHANGED
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import{parseArgs as ro}from"node:util";import{spawn as oo}from"node:child_process";var Y={environment:"production",profile:"default",accountsBaseUrl:"https://accounts.elixpo.com",apiBaseUrl:"https://blogs.elixpo.com"},Le={development:{clientId:"lixblogs-cli-dev",audience:"localhost"},staging:{clientId:"lixblogs-cli-staging",audience:"staging.blogs.elixpo.com"},production:{clientId:"lixblogs-cli-prod",audience:"blogs.elixpo.com"},test:{clientId:"lixblogs-cli-dev",audience:"localhost"}};function S({flags:t={},env:e=process.env}={}){let r=t.env??e.LIXBLOGS_ENV??Y.environment,o=t.profile??e.LIXBLOGS_PROFILE??Y.profile,n=Le[r]||Le.production,i=t.authProvider??e.LIXBLOGS_AUTH_PROVIDER??(r==="production"?"elixpo":"mock"),s=t.accountsUrl??e.LIXBLOGS_ACCOUNTS_URL??Y.accountsBaseUrl,a=t.apiUrl??e.LIXBLOGS_API_URL??Y.apiBaseUrl,l=t.clientId??e.LIXBLOGS_CLIENT_ID??n.clientId,u=t.audience??e.LIXBLOGS_AUDIENCE??n.audience;return{environment:r,profile:o,profileExplicit:t.profile!==void 0||e.LIXBLOGS_PROFILE!==void 0,authProvider:i,accountsBaseUrl:s,apiBaseUrl:a,clientId:l,audience:u}}var U=class{get providerId(){throw new Error("AuthProvider.providerId must be implemented by subclass")}async requestDeviceCode(e){throw new Error("AuthProvider.requestDeviceCode must be implemented by subclass")}async pollDeviceCode(e){throw new Error("AuthProvider.pollDeviceCode must be implemented by subclass")}async refresh(e){throw new Error("AuthProvider.refresh must be implemented by subclass")}async revoke(e){throw new Error("AuthProvider.revoke must be implemented by subclass")}};var Ue={APPROVE_IMMEDIATELY:"mock-approve-",PENDING_THEN_APPROVE:"mock-pending-then-approve-",DENY:"mock-deny-",EXPIRE:"mock-expire-",SLOW_DOWN_THEN_APPROVE:"mock-slow-down-then-approve-"},wr=5,De=0;function br(t){return De+=1,`${t}${De}`}var Z=class extends U{constructor(){super(),this._devicesCodes=new Map,this._revoked=new Set,this._refreshWillFail=new Set}get providerId(){return"mock"}async requestDeviceCode({scopes:e,scenario:r="APPROVE_IMMEDIATELY"}){let o=Ue[r]??Ue.APPROVE_IMMEDIATELY,n=br(o),i=n.slice(-6).toUpperCase();return this._devicesCodes.set(n,{scenario:r,pollCount:0,createdAt:Date.now(),scopes:[...e]}),{deviceCode:n,userCode:i,verificationUri:"https://mock.lixblogs.local/device",verificationUriComplete:`https://mock.lixblogs.local/device?user_code=${encodeURIComponent(i)}`,expiresInSeconds:r==="EXPIRE"?1:600,pollIntervalSeconds:1}}async pollDeviceCode({deviceCode:e}){let r=this._devicesCodes.get(e);return r?r.scenario==="EXPIRE"?{status:"expired"}:r.scenario==="DENY"?{status:"denied"}:r.scenario==="PENDING_THEN_APPROVE"&&(r.pollCount+=1,r.pollCount<2)?{status:"pending"}:r.scenario==="SLOW_DOWN_THEN_APPROVE"&&(r.pollCount+=1,r.pollCount<2)?{status:"slow_down",pollIntervalIncreaseSeconds:wr}:{status:"approved",token:{accessToken:`mock-access-${e}`,refreshToken:`mock-refresh-${e}`,expiresInSeconds:3600,scopes:r.scopes}}:{status:"denied"}}async refresh({refreshToken:e,scopes:r=[]}){if(this._revoked.has(e))throw new Error("refresh token has been revoked");if(this._refreshWillFail.has(e))throw new Error("mock refresh failure (test-injected)");return{accessToken:`mock-access-refreshed-${e}`,refreshToken:e,expiresInSeconds:3600,scopes:r}}async revoke({token:e}){this._revoked.add(e)}_simulateRefreshFailureFor(e){this._refreshWillFail.add(e)}};var Ne="urn:ietf:params:oauth:grant-type:device_code",vr=1,xr=15e3,Ir={access_denied:"Login was denied.",authorization_pending:"Login is awaiting approval.",expired_token:"The device authorization expired. Start login again.",invalid_client:"The LixBlogs CLI client is not registered for this environment.",invalid_grant:"This session is no longer valid. Log in again.",invalid_request:"Accounts rejected the authentication request.",invalid_scope:"The requested LixBlogs permissions are not available for this client.",server_error:"Accounts could not complete authentication. Try again later.",slow_down:"Accounts requested slower polling.",temporarily_unavailable:"Accounts is temporarily unavailable. Try again later."},E=class extends Error{constructor(e,{status:r=0,requiresLogin:o=!1}={}){super(Ir[e]||"Authentication failed."),this.name="AuthProviderError",this.code=e||"authentication_failed",this.status=r,this.requiresLogin=o}},P=class extends Error{constructor(e){super(e),this.name="CompatibilityError",this.code="incompatible_accounts_contract"}};function we(t){return String(t||"0.0.0").split(".").slice(0,3).map(e=>Number.parseInt(e,10)||0)}function _r(t,e){let r=we(t),o=we(e);for(let n=0;n<3;n+=1)if(r[n]!==o[n])return r[n]>o[n];return!0}function Er(t){let e=new URL(t);if(e.pathname=e.pathname.replace(/\/$/,""),e.search="",e.hash="",e.protocol!=="https:"&&e.hostname!=="localhost"&&e.hostname!=="127.0.0.1")throw new P("Accounts must use HTTPS outside local development.");return e.toString().replace(/\/$/,"")}async function H(t){try{return await t.json()}catch{throw new E("server_error",{status:t.status})}}function Q(t,e){let r=typeof t?.error=="string"?t.error:"server_error";return new E(r,{status:e.status,requiresLogin:r==="invalid_grant"||r==="access_denied"||r==="expired_token"})}function Be(t,e){if(!e.ok)throw Q(t,e);if(typeof t?.access_token!="string"||typeof t?.refresh_token!="string"||!Number.isFinite(Number(t?.expires_in)))throw new E("server_error",{status:e.status});return{accessToken:t.access_token,refreshToken:t.refresh_token,expiresInSeconds:Number(t.expires_in),scopes:typeof t.scope=="string"?t.scope.split(/\s+/).filter(Boolean):[]}}var ee=class extends U{constructor({accountsBaseUrl:e="https://accounts.elixpo.com",clientId:r="lixblogs-cli-prod",audience:o="blogs.elixpo.com",cliVersion:n="1.2.0",fetchImpl:i=globalThis.fetch,timeoutMs:s=xr}={}){if(super(),typeof i!="function")throw new TypeError("A fetch implementation is required.");this.accountsBaseUrl=Er(e),this.clientId=r,this.audience=o,this.cliVersion=n,this.fetchImpl=i,this.timeoutMs=s,this._metadata=null,this._discoveryPromise=null}get providerId(){return"elixpo"}async _fetch(e,r={}){let o=new AbortController,n=setTimeout(()=>o.abort(),this.timeoutMs);try{return await this.fetchImpl(e,{...r,signal:r.signal||o.signal,headers:{accept:"application/json",...r.headers}})}catch{throw new E("temporarily_unavailable")}finally{clearTimeout(n)}}async discover({scopes:e=[]}={}){if(!this._metadata){this._discoveryPromise||(this._discoveryPromise=this._loadDiscovery());try{this._metadata=await this._discoveryPromise}finally{this._discoveryPromise=null}}if(e.filter(o=>!this._metadata.scopes_supported.includes(o)).length)throw new E("invalid_scope");return this._metadata}async _loadDiscovery(){let e=await this._fetch(`${this.accountsBaseUrl}/.well-known/oauth-authorization-server`),r=await H(e);if(!e.ok)throw new E("temporarily_unavailable",{status:e.status});if(we(r.elixpo_contract_version)[0]!==vr)throw new P("Accounts uses an unsupported device-flow contract version.");if(!_r(this.cliVersion,r.elixpo_min_compatible_cli_version))throw new P(`This CLI is too old for Accounts. Upgrade to version ${r.elixpo_min_compatible_cli_version} or newer.`);if(!Array.isArray(r.grant_types_supported)||!r.grant_types_supported.includes(Ne))throw new P("Accounts does not advertise OAuth device authorization.");let n=["device_authorization_endpoint","token_endpoint","revocation_endpoint"];for(let i of n){if(typeof r[i]!="string")throw new P(`Accounts discovery is missing ${i}.`);let s=new URL(r[i]),a=new URL(this.accountsBaseUrl);if(s.origin!==a.origin)throw new P(`Accounts discovery returned an untrusted ${i}.`)}return{...r,scopes_supported:Array.isArray(r.scopes_supported)?r.scopes_supported:[]}}async requestDeviceCode({scopes:e}){let r=await this.discover({scopes:e}),o=await this._fetch(r.device_authorization_endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:this.clientId,scope:e.join(" "),audience:this.audience})}),n=await H(o);if(!o.ok)throw Q(n,o);if(typeof n.device_code!="string"||typeof n.user_code!="string"||typeof n.verification_uri!="string")throw new E("server_error",{status:o.status});return{deviceCode:n.device_code,userCode:n.user_code,verificationUri:n.verification_uri,verificationUriComplete:n.verification_uri_complete||n.verification_uri,expiresInSeconds:Number(n.expires_in)||600,pollIntervalSeconds:Number(n.interval)||5}}async pollDeviceCode({deviceCode:e}){let r=await this.discover(),o=new URLSearchParams({grant_type:Ne,device_code:e,client_id:this.clientId}),n=await this._fetch(r.token_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:o}),i=await H(n);if(n.ok)return{status:"approved",token:Be(i,n)};if(i?.error==="authorization_pending")return{status:"pending"};if(i?.error==="slow_down"){let s=r.elixpo_device_flow_polling||{};return{status:"slow_down",pollIntervalIncreaseSeconds:Math.max(5,Number(s.slow_down_interval_seconds||10)-Number(s.interval_seconds||5))}}if(i?.error==="access_denied")return{status:"denied"};if(i?.error==="expired_token")return{status:"expired"};throw Q(i,n)}async refresh({refreshToken:e,scopes:r}){let o=await this.discover({scopes:r||[]}),n=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.clientId});r?.length&&n.set("scope",r.join(" "));let i=await this._fetch(o.token_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:n}),s=await H(i);return Be(s,i)}async revoke({token:e}){let r=await this.discover(),o=await this._fetch(r.revocation_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({token:e,client_id:this.clientId})});if(!o.ok){let n=await H(o);throw Q(n,o)}}};var Me="elixpo",be=class extends Error{constructor(e){super(e),this.name="ProductionAuthGateError"}};function Fe({providerId:t,environment:e}){if(e==="production"&&t!==Me)throw new be(`Provider "${t}" is not approved for production. Only "${Me}" may be used in production.`)}function D(t){if(t.authProvider==="mock"&&t.environment==="production")throw new Error("The mock auth provider cannot run in production.");if(t.authProvider!=="mock"&&t.authProvider!=="elixpo")throw new Error(`Unknown auth provider "${t.authProvider}".`);let e=t.authProvider==="mock"?new Z:new ee({accountsBaseUrl:t.accountsBaseUrl,clientId:t.clientId,audience:t.audience,cliVersion:t.cliVersion||"1.2.0",fetchImpl:t.fetchImpl});return Fe({providerId:e.providerId,environment:t.environment}),e}var T=class extends Error{constructor(e){super(e),this.name="CredentialStoreUnavailableError"}},j=class{async get(e){throw new Error("CredentialStore.get must be implemented by subclass")}async set(e,r){throw new Error("CredentialStore.set must be implemented by subclass")}async delete(e){throw new Error("CredentialStore.delete must be implemented by subclass")}async listProfiles(){throw new Error("CredentialStore.listProfiles must be implemented by subclass")}},te=class extends j{constructor(){super(),this._store=new Map}async get(e){return this._store.get(e)??null}async set(e,r){this._store.set(e,r)}async delete(e){this._store.delete(e)}async listProfiles(){return[...this._store.keys()]}},re=class extends j{constructor(e){super(),this._realStore=e}async get(e){try{return await this._realStore.get(e)}catch(r){throw new T(`OS keychain is unavailable: ${r.message}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`)}}async set(e,r){try{await this._realStore.set(e,r)}catch(o){throw new T(`OS keychain is unavailable: ${o.message}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`)}}async delete(e){try{await this._realStore.delete(e)}catch(r){throw new T(`OS keychain is unavailable: ${r.message}`)}}async listProfiles(){try{return await this._realStore.listProfiles()}catch(e){throw new T(`OS keychain is unavailable: ${e.message}`)}}};import{Entry as kr}from"@napi-rs/keyring";var Sr="lixblogs-cli",$r="__lixblogs_availability_probe__";function oe(t){return new kr(Sr,t)}async function Ge(){let t=oe($r);try{return t.setPassword("probe"),t.deletePassword(),{available:!0}}catch(e){return{available:!1,error:String(e.message??e).split(`
3
- `)[0].trim()}}}var ve=class extends j{async get(e){let r=oe(e),o;try{o=r.getPassword()}catch(n){if(ze(n))return null;throw n}return o==null?null:JSON.parse(o)}async set(e,r){oe(e).setPassword(JSON.stringify(r))}async delete(e){let r=oe(e);try{r.deletePassword()}catch(o){if(ze(o))return;throw o}}async listProfiles(){throw new Error("KeychainCredentialStore.listProfiles is not supported directly \u2014 use ProfileRegistry to track known profile IDs, then look up each one via get().")}};function ze(t){let e=String(t?.message??"");return/no such|not found|nosuchkeyring|nosuchitem/i.test(e)}var ne=class extends j{constructor(e){super(),this._keychain=new ve,this._registry=e}async get(e){return this._keychain.get(e)}async set(e,r){await this._keychain.set(e,r),await this._registry.add(e)}async delete(e){await this._keychain.delete(e),await this._registry.remove(e)}async listProfiles(){return this._registry.list()}};import{promises as ie}from"node:fs";import Ve from"node:path";import qr from"node:os";function Ar(){return Ve.join(qr.homedir(),".config","lixblogs","profiles.json")}var v=class{constructor(e=Ar()){this._path=e}async list(){return(await this._read()).profiles}async getActive(){let e=await this._read();return e.activeProfile&&e.profiles.includes(e.activeProfile)?e.activeProfile:e.profiles[0]||null}async setActive(e){$(e);let r=await this._read();if(!r.profiles.includes(e))throw new Error(`Profile "${e}" does not exist. Log in with it first.`);await this._write(r.profiles,e)}async _read(){try{let e=await ie.readFile(this._path,"utf8"),r=JSON.parse(e);return{profiles:Array.isArray(r.profiles)?r.profiles.filter(n=>typeof n=="string"):[],activeProfile:typeof r.activeProfile=="string"?r.activeProfile:null}}catch(e){if(e.code==="ENOENT")return{profiles:[],activeProfile:null};throw e}}async add(e){$(e);let r=await this._read(),o=new Set(r.profiles);o.add(e),await this._write([...o],r.activeProfile||e)}async remove(e){let r=await this._read(),o=r.profiles.filter(i=>i!==e),n=r.activeProfile===e?o[0]||null:r.activeProfile;await this._write(o,n)}async _write(e,r=null){await ie.mkdir(Ve.dirname(this._path),{recursive:!0});let o=`${this._path}.${process.pid}.tmp`;await ie.writeFile(o,JSON.stringify({activeProfile:r,profiles:e},null,2),{encoding:"utf8",mode:384}),await ie.rename(o,this._path)}};function $(t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(t||""))throw new Error("Profile names must be 1-64 characters using letters, numbers, dot, dash, or underscore.");return t}async function Je({allowInsecureFallback:t=!1,profileRegistry:e}={}){let r=await Ge();if(!r.available){if(!t)throw new T(`OS keychain is unavailable: ${r.error}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`);return process.stderr.write(`warning: OS keychain unavailable (${r.error}); using in-memory fallback because --allow-insecure-fallback was passed. Credentials will NOT persist between CLI runs.
4
- `),new te}let o=e||new v,n=new ne(o);return new re(n)}var Ie="[REDACTED]",Rr=/token|refresh|secret|password|authorization/i,Pr=/^(mock-(access|refresh)-|Bearer\s+)\S+/i;function He(t){return typeof t=="string"&&Pr.test(t)?Ie:t}function xe(t){if(Array.isArray(t))return t.map(e=>xe(e));if(t&&typeof t=="object"){let e={};for(let[r,o]of Object.entries(t))Rr.test(r)?e[r]=Ie:typeof o=="object"&&o!==null?e[r]=xe(o):e[r]=He(o);return e}return He(t)}function se(t,e){return JSON.stringify(xe(t),null,e)}function N(t){return typeof t!="string"?t:t.replace(/(mock-(access|refresh)-\S+|Bearer\s+\S+)/gi,Ie)}async function We({provider:t,credentialStore:e,profileId:r,scopes:o,openBrowser:n,resolveProfileId:i,sleep:s=l=>new Promise(u=>setTimeout(u,l)),onStatus:a=()=>{}}){let l;try{l=await t.requestDeviceCode({scopes:o})}catch(c){return{ok:!1,reason:N(c.message)}}a({type:"verification_pending",verificationUri:l.verificationUri,verificationUriComplete:l.verificationUriComplete,userCode:l.userCode,expiresInSeconds:l.expiresInSeconds}),n&&await n(l.verificationUriComplete||l.verificationUri);let u=l.pollIntervalSeconds*1e3,d=Date.now()+l.expiresInSeconds*1e3;for(;Date.now()<d;){await s(u);let c;try{c=await t.pollDeviceCode({deviceCode:l.deviceCode})}catch(f){return{ok:!1,reason:N(f.message)}}if(c.status==="approved"){let f=r;if(i)try{f=await i({accessToken:c.token.accessToken,requestedProfileId:r})}catch(k){return{ok:!1,reason:N(k.message)}}return await e.set(f,{accessToken:c.token.accessToken,refreshToken:c.token.refreshToken,expiresAt:Date.now()+c.token.expiresInSeconds*1e3,scopes:c.token.scopes}),a({type:"approved"}),{ok:!0,profileId:f}}if(c.status==="denied")return a({type:"denied"}),{ok:!1,reason:"Login was denied."};if(c.status==="expired")return a({type:"expired"}),{ok:!1,reason:"Device code expired before login was approved."};if(c.status==="slow_down"){u+=c.pollIntervalIncreaseSeconds*1e3,a({type:"slow_down",newIntervalMs:u});continue}a({type:"pending"})}return{ok:!1,reason:"Device code expired before login was approved."}}async function Ke({credentialStore:t,profileId:e}){let r=e?[e]:await t.listProfiles(),o=[];for(let n of r){let i=await t.get(n);if(!i){o.push({profileId:n,loggedIn:!1});continue}o.push({profileId:n,loggedIn:!0,expired:Date.now()>=i.expiresAt,scopes:i.scopes})}return o}async function Xe({credentialStore:t,profileId:e}){return await t.delete(e),{ok:!0}}async function Ye({provider:t,credentialStore:e,profileId:r,confirmed:o}){if(o!==!0)return{ok:!1,reason:"Revoke was not confirmed. This is a destructive action and requires explicit confirmation (interactive prompt, or --yes in a non-interactive session)."};let n=await e.get(r);return n?(await t.revoke({token:n.refreshToken}),await e.delete(r),{ok:!0}):{ok:!1,reason:`No stored credentials for profile "${r}".`}}async function Ze({credentialStore:t,profileRegistry:e}){let r=await e.getActive(),o=await t.listProfiles(),n=[];for(let i of o){let s=await t.get(i);n.push({profileId:i,active:i===r,loggedIn:!!s,expired:s?Date.now()>=s.expiresAt:void 0,scopes:s?.scopes||[]})}return{activeProfile:r,profiles:n}}async function Qe({credentialStore:t,profileRegistry:e,profileId:r}){return await t.get(r)?(await e.setActive(r),{ok:!0,profileId:r}):{ok:!1,reason:`Profile "${r}" is not logged in.`}}async function et({accessToken:t,apiBaseUrl:e,fetchImpl:r=globalThis.fetch}){let o=new URL("/api/v1/me",e),n=await r(o,{headers:{accept:"application/json",authorization:`Bearer ${t}`}}),i;try{i=await n.json()}catch{throw new Error("LixBlogs could not resolve the signed-in username.")}if(!n.ok||typeof i?.data?.username!="string")throw new Error(i?.error?.message||"LixBlogs could not resolve the signed-in username.");return $(i.data.username)}var Tr=6e4,tt=new WeakMap;function Or(t){let e=tt.get(t);return e||(e=new Map,tt.set(t,e)),e}var ae=class extends Error{constructor(e){super(`Profile "${e}" needs to log in again.`),this.name="LoginRequiredError",this.code="login_required"}},_e=class extends Error{constructor(e,r){super("The configured LixBlogs origin is not serving the API v1 JSON contract."),this.name="ApiContractUnavailableError",this.code="api_contract_unavailable",this.status=e,this.details={contentType:r||"unknown"},this.hint="Deploy the LixBlogs API v1 stack, or select an origin that exposes /api/v1."}},B=class{constructor({provider:e,credentialStore:r,profileId:o,apiBaseUrl:n="https://blogs.elixpo.com",fetchImpl:i=globalThis.fetch,refreshSkewMs:s=Tr}){this.provider=e,this.credentialStore=r,this.profileId=o,this.apiBaseUrl=new URL(n),this.fetchImpl=i,this.refreshSkewMs=s}async _refresh(e,{force:r=!1}={}){let o=Or(this.credentialStore),n=o.get(this.profileId);if(n)return n;let i=(async()=>{let s=await this.credentialStore.get(this.profileId)||e;if(!r&&s.expiresAt-Date.now()>this.refreshSkewMs)return s;try{let a=await this.provider.refresh({refreshToken:s.refreshToken,scopes:s.scopes}),l={accessToken:a.accessToken,refreshToken:a.refreshToken,expiresAt:Date.now()+a.expiresInSeconds*1e3,scopes:a.scopes};return await this.credentialStore.set(this.profileId,l),l}catch(a){throw a instanceof E&&a.requiresLogin?(await this.credentialStore.delete(this.profileId),new ae(this.profileId)):a}})();o.set(this.profileId,i);try{return await i}finally{o.get(this.profileId)===i&&o.delete(this.profileId)}}async credentials({forceRefresh:e=!1}={}){let r=await this.credentialStore.get(this.profileId);if(!r)throw new ae(this.profileId);return e||r.expiresAt-Date.now()<=this.refreshSkewMs?this._refresh(r,{force:e}):r}async request(e,r={}){let o=await this.requestRaw(e,r),n=o.headers.get("content-type")||"";if(!n.toLowerCase().includes("application/json"))throw new _e(o.status,n);return o}async requestRaw(e,r={}){let o=new URL(e,this.apiBaseUrl);if(o.origin!==this.apiBaseUrl.origin||!o.pathname.startsWith("/api/v1/"))throw new Error("Authenticated CLI requests are restricted to the configured LixBlogs /api/v1 resource server.");let n=await this.credentials(),i=()=>this.fetchImpl(o.toString(),{...r,headers:{...r.headers,authorization:`Bearer ${n.accessToken}`}}),s=await i();return s.status===401&&(n=await this.credentials({forceRefresh:!0}),s=await i()),s}async requireScopes(e){let r=await this.credentials(),o=e.filter(n=>!r.scopes.includes(n));if(o.length){let n=new Error(`Login again with the required scope${o.length>1?"s":""}: ${o.join(", ")}`);throw n.name="InsufficientScopeError",n.code="insufficient_scope",n.missingScopes=o,n}}};import{randomUUID as rt}from"node:crypto";var h=class extends Error{constructor(e,r,{status:o,requestId:n,details:i}={}){super(r),this.name="BlogApiError",this.code=e||"api_error",this.status=o||0,this.requestId=n||null,this.details=i||null}};async function jr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new h(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return{payload:e,etag:t.headers.get("etag")}}var W=class{constructor(e,{sleep:r=o=>new Promise(n=>setTimeout(n,o))}={}){this.http=e,this.sleep=r}async request(e,r={}){let o={...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}},i=(o.method||"GET")==="GET"||!!o.headers["idempotency-key"];for(let s=0;s<2;s+=1)try{let a=await this.http.request(e,o);if(i&&s===0&&(a.status===429||a.status>=500)){let l=Math.min(2,Number.parseInt(a.headers.get("retry-after")||"1",10)||1);await this.sleep(l*1e3);continue}return jr(a)}catch(a){if(!i||s>0||a instanceof h||a?.code)throw a;await this.sleep(250)}throw new h("request_failed","The LixBlogs request failed after retrying.")}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async whoami(){return await this.requireScopes(["lixblogs:profile:read"]),(await this.request("/api/v1/me")).payload.data}async list({status:e="all",limit:r=20,cursor:o}={}){await this.requireScopes(["lixblogs:blog:read"]);let n=new URLSearchParams({status:e,limit:String(r)});return o&&n.set("cursor",o),(await this.request(`/api/v1/blogs?${n}`)).payload}async get(e){await this.requireScopes(["lixblogs:blog:read"]);let r=await this.request(`/api/v1/blogs/${encodeURIComponent(e)}`);return{...r.payload.data,etag:r.payload.data.etag||r.etag}}async create(e,{idempotencyKey:r=rt()}={}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request("/api/v1/blogs",{method:"POST",headers:{"idempotency-key":r},body:JSON.stringify(e)})).payload.data}async update(e,r,{etag:o}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}`,{method:"PATCH",headers:{"if-match":o},body:JSON.stringify(r)})).payload.data}async publish(e,{etag:r,status:o="published",idempotencyKey:n=rt()}){return await this.requireScopes(["lixblogs:blog:publish"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/publish`,{method:"POST",headers:{"if-match":r,"idempotency-key":n},body:JSON.stringify({status:o})})).payload.data}async unpublish(e,{etag:r}){return await this.requireScopes(["lixblogs:blog:publish"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/unpublish`,{method:"POST",headers:{"if-match":r}})).payload.data}async delete(e,{etag:r,permanent:o=!1}){return await this.requireScopes(["lixblogs:blog:delete",...o?["lixblogs:blog:delete:permanent"]:[]]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}${o?"?permanent=true":""}`,{method:"DELETE",headers:{"if-match":r,...o?{"x-confirm-permanent-delete":e}:{}}})).payload.data}async restore(e,{etag:r}){return await this.requireScopes(["lixblogs:blog:delete"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/restore`,{method:"POST",headers:{"if-match":r}})).payload.data}async versions(e){return await this.requireScopes(["lixblogs:blog:read"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions`)).payload.data}async version(e,r){await this.requireScopes(["lixblogs:blog:read"]);let o=new URLSearchParams({version:r});return(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions?${o}`)).payload.data}async restoreVersion(e,r,{etag:o}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions`,{method:"POST",headers:{"if-match":o},body:JSON.stringify({versionId:r})})).payload.data}async comments(e){return await this.requireScopes(["lixblogs:blog:read"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments`)).payload.data}async comment(e,r,{parentId:o}={}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments`,{method:"POST",body:JSON.stringify({content:r,parentId:o})})).payload.data}async deleteComment(e,r){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments/${encodeURIComponent(r)}`,{method:"DELETE"})).payload.data}};async function Cr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new h(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return{payload:e,etag:t.headers.get("etag")}}var le=class{constructor(e,{sleep:r=o=>new Promise(n=>setTimeout(n,o))}={}){this.http=e,this.sleep=r}async request(e,r={}){let o={...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}},i=(o.method||"GET")==="GET";for(let s=0;s<2;s+=1)try{let a=await this.http.request(e,o);if(i&&s===0&&(a.status===429||a.status>=500)){let l=Math.min(2,Number.parseInt(a.headers.get("retry-after")||"1",10)||1);await this.sleep(l*1e3);continue}return Cr(a)}catch(a){if(!i||s>0||a instanceof h||a?.code)throw a;await this.sleep(250)}throw new h("request_failed","The LixBlogs request failed after retrying.")}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async list(){return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request("/api/v1/orgs")).payload}async get(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}`)).payload.data}async collections(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}/collections`)).payload.data}async members(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}/members`)).payload.data}async targets(){await this.requireScopes(["lixblogs:organizations:read"]);let o=((await this.list())?.data||[]).filter(i=>i.canWrite),n=await Promise.all(o.map(async i=>{let s=[];try{s=await this.collections(i.id)}catch{s=[]}return{target:`org:${i.id}`,orgId:i.id,slug:i.slug,name:i.name,role:i.role,collections:s.map(a=>({id:a.id,slug:a.slug,name:a.name}))}}));return{personal:{target:"personal",name:"Personal Blog"},organizations:n}}};import{randomUUID as ce}from"node:crypto";async function Lr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new h(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return e.data}var ue=class{constructor(e){this.http=e}async request(e,r={}){let o=await this.http.request(e,{...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}});return Lr(o)}async list(e){return await this.http.requireScopes(["lixblogs:collaboration:read"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`)}async invitations(){return await this.http.requireScopes(["lixblogs:collaboration:read"]),this.request("/api/v1/collaboration/invitations")}async invite(e,{user:r,role:o,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"POST",headers:{"idempotency-key":n},body:JSON.stringify({user:r,role:o})})}async role(e,{user:r,role:o,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"PATCH",headers:{"idempotency-key":n},body:JSON.stringify({user:r,role:o})})}async remove(e,{user:r,idempotencyKey:o=ce()}={}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"DELETE",headers:{"idempotency-key":o},body:JSON.stringify({...r?{user:r}:{}})})}async resolveInvitation(e,{action:r,showOnProfile:o=!0,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request("/api/v1/collaboration/invitations",{method:"POST",headers:{"idempotency-key":n},body:JSON.stringify({blogId:e,action:r,showOnProfile:o})})}};async function Ur(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new h(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return e}var de=class{constructor(e){this.http=e}async query(e={}){let r=e.scope||"personal";await this.http.requireScopes(["lixblogs:analytics:read",...r.startsWith("org:")?["lixblogs:organizations:read"]:[]]);let o=new URLSearchParams({scope:r,range:e.range||(e.from||e.to?"custom":"30d"),dimension:e.dimension||"overview",limit:String(e.limit||20)});return e.from&&o.set("from",e.from),e.to&&o.set("to",e.to),e.cursor&&o.set("cursor",e.cursor),Ur(await this.http.request(`/api/v1/analytics?${o}`,{headers:{accept:"application/json"}}))}};var pe=class{constructor(e){this.http=e}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async _request(e,r={}){let o=await this.http.request(e,r),n;try{n=await o.json()}catch{n=null}if(!o.ok||n?.error){let i=new Error(n?.error?.message||`Request failed with HTTP ${o.status}`);throw i.code=n?.error?.code||`http_${o.status}`,i.status=o.status,i.requestId=n?.error?.requestId||o.headers.get("x-request-id")||null,i.details=n?.error?.details||null,i}return n.data}async cloudinaryStatus(){return await this.requireScopes(["lixblogs:integrations:cloudinary:read"]),this._request("/api/v1/integrations/cloudinary")}async cloudinaryDisconnect(){return await this.requireScopes(["lixblogs:integrations:cloudinary:disconnect"]),this._request("/api/v1/integrations/cloudinary",{method:"DELETE"})}async pollinationsStatus({refresh:e=!1}={}){return await this.requireScopes(["lixblogs:media:read"]),this._request(`/api/v1/integrations/pollinations${e?"?refresh=1":""}`)}async pollinationsDisconnect(){return await this.requireScopes(["lixblogs:media:write"]),this._request("/api/v1/integrations/pollinations",{method:"DELETE"})}};import{randomUUID as ot}from"node:crypto";var Dr=Object.freeze({"image/avif":"avif","image/bmp":"bmp","image/jpeg":"jpg","image/png":"png","image/svg+xml":"svg","image/webp":"webp"});async function Ee(t){let e=await t.json().catch(()=>({})),r=new Error(e.error?.message||e.error||`Media request failed with HTTP ${t.status}`);return r.code=e.error?.code||e.code||`http_${t.status}`,r.status=t.status,r}var fe=class{constructor(e){this.http=e}async generate({prompt:e,model:r="flux",seed:o,width:n,height:i,destination:s="inline",generationId:a=ot(),reference:l}){await this.http.requireScopes(["lixblogs:media:write"]);let u,d;if(l){u=new FormData;for(let[f,k]of Object.entries({prompt:e,model:r,seed:o,width:n,height:i,destination:s,generationId:a}))k!==void 0&&u.append(f,String(k));u.append("referenceImage",new Blob([l.bytes],{type:l.mimeType}),l.name||"reference-image"),d={accept:"image/*, application/json"}}else u=JSON.stringify({prompt:e,model:r,seed:o,width:n,height:i,destination:s,generationId:a}),d={"content-type":"application/json",accept:"image/*, application/json"};let c=await this.http.requestRaw("/api/v1/media/generate",{method:"POST",headers:d,body:u});if(!c.ok)throw await Ee(c);return{bytes:new Uint8Array(await c.arrayBuffer()),mimeType:c.headers.get("content-type")||"image/jpeg",generationId:a}}async upload({bytes:e,mimeType:r,blogId:o,mediaType:n="inline",uploadId:i=ot()}){await this.http.requireScopes(["lixblogs:media:write"]);let s=new FormData,a=Dr[r];if(!a)throw new Error(`Unsupported image MIME type: ${r}`);s.append("file",new Blob([e],{type:r}),`lixblogs-${i}.${a}`),s.append("type",n),s.append("uploadId",i),o&&s.append("blogId",o);let l=await this.http.requestRaw("/api/v1/media/upload",{method:"POST",body:s,headers:{accept:"application/json"}});if(!l.ok)throw await Ee(l);return l.json()}async delete(e){if(!e)throw new Error("A media ID is required.");await this.http.requireScopes(["lixblogs:media:write"]);let r=await this.http.request(`/api/v1/media/${encodeURIComponent(e)}`,{method:"DELETE"});if(!r.ok)throw await Ee(r);let o=await r.json();return o.data||o}};var g=Object.freeze({OK:0,ERROR:1,USAGE:2,CONFLICT:3,AUTH:4,CONFIRMATION:5}),Nr=Object.freeze({login:["auth","login"],logout:["auth","logout"],whoami:["auth","whoami"],profiles:["auth","profiles"],use:["auth","use"]});function nt(t){let[e,...r]=t,o=Nr[e];return o?[...o,...r]:t}function it(t,e="cli_error"){if(t&&typeof t=="object"&&t.error&&!Array.isArray(t.error))return t;let r=t&&typeof t=="object"?t:{message:String(t||"Command failed.")};return{ok:!1,error:{code:r.code||e,message:r.message||"Command failed.",hint:r.hint||null,requestId:r.requestId||null,...r.details?{details:r.details}:{}}}}function y(t,e){if(t.yes)return;let r=new Error(`${e} requires --yes in non-interactive operation.`);throw r.code="confirmation_required",r.hint="Review the operation, then run it again with --yes.",r.exitCode=g.CONFIRMATION,r}var I=Object.freeze({reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",violet:"\x1B[38;5;141m",green:"\x1B[38;5;42m",yellow:"\x1B[38;5;220m",red:"\x1B[38;5;203m",gray:"\x1B[38;5;245m"});function p(t=process.stdout,e=process.env){return!!t.isTTY&&e.NO_COLOR===void 0&&e.TERM!=="dumb"}function _(t,e,r){return r?`${e}${t}${I.reset}`:t}function at({url:t,code:e,expiresInSeconds:r,profile:o,interactive:n,color:i=!1}){let s=`${_("\u25C6",I.violet,i)} ${_("LixBlogs",I.bold,i)}`,a=n?"Press Enter to open here, or use the URL on another device.":"Open the URL in any browser and approve this device.";return["",` ${s}`,` ${_("Device login",I.dim,i)}`," \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",` URL ${t}`,` Code ${_(e,I.bold,i)}`,` Expires ${Math.ceil(r/60)} min`,o?` Profile ${o} ${_("(local credential slot)",I.dim,i)}`:` Profile ${_("your Accounts username after approval",I.dim,i)}`,"",` ${a}`," No localhost callback or exposed port is required.",""].join(`
5
- `)}function x(t,e=!1){return` ${_(`\u2713 ${t}`,I.green,e)}`}function q(t,e=!1){return` ${_(`! ${t}`,I.yellow,e)}`}function C(t,e=!1){return` ${_(`\u2022 ${t}`,I.gray,e)}`}function lt(t,e=!1){return` ${_(`\u2715 ${t}`,I.red,e)}`}var st=Object.freeze(["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"]);function Br(t,{stream:e=process.stderr,enabled:r=!!e.isTTY,intervalMs:o=80,color:n=p(e)}={}){if(!r)return{stop(){}};let i=0,s=()=>{e.write(`\r\x1B[2K${_(st[i],I.violet,n)} ${_(t,I.gray,n)}`),i=(i+1)%st.length};s();let a=setInterval(s,o);a.unref?.();let l=!1;return{stop(){l||(l=!0,clearInterval(a),e.write("\r\x1B[2K"))}}}async function A(t,e,r,o={}){let n=Br(e,{...o,enabled:o.enabled??(!t?.json&&!t?.quiet&&!!(o.stream||process.stderr).isTTY)});try{return await r()}finally{n.stop()}}function ct({input:t=process.stdin,open:e,url:r}){if(!t.isTTY||typeof e!="function")return()=>{};let o=()=>{Promise.resolve(e(r)).catch(()=>{})};return t.setEncoding?.("utf8"),t.once("data",o),t.resume?.(),()=>{t.off?.("data",o),t.pause?.()}}function ut(t){return[{type:"text",text:t}]}function M(t){let e=String(t||""),r=[],o=/(\*\*([^*]+)\*\*|\*([^*]+)\*|`([^`]+)`|\[([^\]]+)\]\((https:\/\/[^)]+)\))/g,n=0;for(let i of e.matchAll(o))i.index>n&&r.push({type:"text",text:e.slice(n,i.index)}),i[2]!==void 0?r.push({type:"text",text:i[2],styles:{bold:!0}}):i[3]!==void 0?r.push({type:"text",text:i[3],styles:{italic:!0}}):i[4]!==void 0?r.push({type:"text",text:i[4],styles:{code:!0}}):r.push({type:"link",href:i[6],content:[{type:"text",text:i[5],styles:{}}]}),n=i.index+i[0].length;return n<e.length&&r.push({type:"text",text:e.slice(n)}),r.length?r:ut(e)}function dt(t){let e=String(t||"").replace(/\r\n/g,`
2
+ import{parseArgs as ao}from"node:util";import{spawn as lo}from"node:child_process";var W={environment:"production",profile:"default",accountsBaseUrl:"https://accounts.elixpo.com",apiBaseUrl:"https://blogs.elixpo.com"},De={development:{clientId:"lixblogs-cli-dev",audience:"localhost"},staging:{clientId:"lixblogs-cli-staging",audience:"staging.blogs.elixpo.com"},production:{clientId:"lixblogs-cli-prod",audience:"blogs.elixpo.com"},test:{clientId:"lixblogs-cli-dev",audience:"localhost"}};function O({flags:t={},env:e=process.env}={}){let r=t.env??e.LIXBLOGS_ENV??W.environment,o=t.profile??e.LIXBLOGS_PROFILE??W.profile,n=De[r]||De.production,i=t.authProvider??e.LIXBLOGS_AUTH_PROVIDER??(r==="production"?"elixpo":"mock"),s=t.accountsUrl??e.LIXBLOGS_ACCOUNTS_URL??W.accountsBaseUrl,a=t.apiUrl??e.LIXBLOGS_API_URL??W.apiBaseUrl,l=t.clientId??e.LIXBLOGS_CLIENT_ID??n.clientId,c=t.audience??e.LIXBLOGS_AUDIENCE??n.audience;return{environment:r,profile:o,profileExplicit:t.profile!==void 0||e.LIXBLOGS_PROFILE!==void 0,authProvider:i,accountsBaseUrl:s,apiBaseUrl:a,clientId:l,audience:c}}var D=class{get providerId(){throw new Error("AuthProvider.providerId must be implemented by subclass")}async requestDeviceCode(e){throw new Error("AuthProvider.requestDeviceCode must be implemented by subclass")}async pollDeviceCode(e){throw new Error("AuthProvider.pollDeviceCode must be implemented by subclass")}async refresh(e){throw new Error("AuthProvider.refresh must be implemented by subclass")}async revoke(e){throw new Error("AuthProvider.revoke must be implemented by subclass")}};var Ne={APPROVE_IMMEDIATELY:"mock-approve-",PENDING_THEN_APPROVE:"mock-pending-then-approve-",DENY:"mock-deny-",EXPIRE:"mock-expire-",SLOW_DOWN_THEN_APPROVE:"mock-slow-down-then-approve-"},xr=5,Be=0;function _r(t){return Be+=1,`${t}${Be}`}var Y=class extends D{constructor(){super(),this._devicesCodes=new Map,this._revoked=new Set,this._refreshWillFail=new Set}get providerId(){return"mock"}async requestDeviceCode({scopes:e,scenario:r="APPROVE_IMMEDIATELY"}){let o=Ne[r]??Ne.APPROVE_IMMEDIATELY,n=_r(o),i=n.slice(-6).toUpperCase();return this._devicesCodes.set(n,{scenario:r,pollCount:0,createdAt:Date.now(),scopes:[...e]}),{deviceCode:n,userCode:i,verificationUri:"https://mock.lixblogs.local/device",verificationUriComplete:`https://mock.lixblogs.local/device?user_code=${encodeURIComponent(i)}`,expiresInSeconds:r==="EXPIRE"?1:600,pollIntervalSeconds:1}}async pollDeviceCode({deviceCode:e}){let r=this._devicesCodes.get(e);return r?r.scenario==="EXPIRE"?{status:"expired"}:r.scenario==="DENY"?{status:"denied"}:r.scenario==="PENDING_THEN_APPROVE"&&(r.pollCount+=1,r.pollCount<2)?{status:"pending"}:r.scenario==="SLOW_DOWN_THEN_APPROVE"&&(r.pollCount+=1,r.pollCount<2)?{status:"slow_down",pollIntervalIncreaseSeconds:xr}:{status:"approved",token:{accessToken:`mock-access-${e}`,refreshToken:`mock-refresh-${e}`,expiresInSeconds:3600,scopes:r.scopes}}:{status:"denied"}}async refresh({refreshToken:e,scopes:r=[]}){if(this._revoked.has(e))throw new Error("refresh token has been revoked");if(this._refreshWillFail.has(e))throw new Error("mock refresh failure (test-injected)");return{accessToken:`mock-access-refreshed-${e}`,refreshToken:e,expiresInSeconds:3600,scopes:r}}async revoke({token:e}){this._revoked.add(e)}_simulateRefreshFailureFor(e){this._refreshWillFail.add(e)}};var Me="urn:ietf:params:oauth:grant-type:device_code",kr=1,Ir=15e3,Er={access_denied:"Login was denied.",authorization_pending:"Login is awaiting approval.",expired_token:"The device authorization expired. Start login again.",invalid_client:"The LixBlogs CLI client is not registered for this environment.",invalid_grant:"This session is no longer valid. Log in again.",invalid_request:"Accounts rejected the authentication request.",invalid_scope:"The requested LixBlogs permissions are not available for this client.",server_error:"Accounts could not complete authentication. Try again later.",slow_down:"Accounts requested slower polling.",temporarily_unavailable:"Accounts is temporarily unavailable. Try again later."},I=class extends Error{constructor(e,{status:r=0,requiresLogin:o=!1}={}){super(Er[e]||"Authentication failed."),this.name="AuthProviderError",this.code=e||"authentication_failed",this.status=r,this.requiresLogin=o}},A=class extends Error{constructor(e){super(e),this.name="CompatibilityError",this.code="incompatible_accounts_contract"}};function be(t){return String(t||"0.0.0").split(".").slice(0,3).map(e=>Number.parseInt(e,10)||0)}function Sr(t,e){let r=be(t),o=be(e);for(let n=0;n<3;n+=1)if(r[n]!==o[n])return r[n]>o[n];return!0}function $r(t){let e=new URL(t);if(e.pathname=e.pathname.replace(/\/$/,""),e.search="",e.hash="",e.protocol!=="https:"&&e.hostname!=="localhost"&&e.hostname!=="127.0.0.1")throw new A("Accounts must use HTTPS outside local development.");return e.toString().replace(/\/$/,"")}async function V(t){try{return await t.json()}catch{throw new I("server_error",{status:t.status})}}function Z(t,e){let r=typeof t?.error=="string"?t.error:"server_error";return new I(r,{status:e.status,requiresLogin:r==="invalid_grant"||r==="access_denied"||r==="expired_token"})}function Fe(t,e){if(!e.ok)throw Z(t,e);if(typeof t?.access_token!="string"||typeof t?.refresh_token!="string"||!Number.isFinite(Number(t?.expires_in)))throw new I("server_error",{status:e.status});return{accessToken:t.access_token,refreshToken:t.refresh_token,expiresInSeconds:Number(t.expires_in),scopes:typeof t.scope=="string"?t.scope.split(/\s+/).filter(Boolean):[]}}var Q=class extends D{constructor({accountsBaseUrl:e="https://accounts.elixpo.com",clientId:r="lixblogs-cli-prod",audience:o="blogs.elixpo.com",cliVersion:n="1.2.0",fetchImpl:i=globalThis.fetch,timeoutMs:s=Ir}={}){if(super(),typeof i!="function")throw new TypeError("A fetch implementation is required.");this.accountsBaseUrl=$r(e),this.clientId=r,this.audience=o,this.cliVersion=n,this.fetchImpl=i,this.timeoutMs=s,this._metadata=null,this._discoveryPromise=null}get providerId(){return"elixpo"}async _fetch(e,r={}){let o=new AbortController,n=setTimeout(()=>o.abort(),this.timeoutMs);try{return await this.fetchImpl(e,{...r,signal:r.signal||o.signal,headers:{accept:"application/json",...r.headers}})}catch{throw new I("temporarily_unavailable")}finally{clearTimeout(n)}}async discover({scopes:e=[]}={}){if(!this._metadata){this._discoveryPromise||(this._discoveryPromise=this._loadDiscovery());try{this._metadata=await this._discoveryPromise}finally{this._discoveryPromise=null}}if(e.filter(o=>!this._metadata.scopes_supported.includes(o)).length)throw new I("invalid_scope");return this._metadata}async _loadDiscovery(){let e=await this._fetch(`${this.accountsBaseUrl}/.well-known/oauth-authorization-server`),r=await V(e);if(!e.ok)throw new I("temporarily_unavailable",{status:e.status});if(be(r.elixpo_contract_version)[0]!==kr)throw new A("Accounts uses an unsupported device-flow contract version.");if(!Sr(this.cliVersion,r.elixpo_min_compatible_cli_version))throw new A(`This CLI is too old for Accounts. Upgrade to version ${r.elixpo_min_compatible_cli_version} or newer.`);if(!Array.isArray(r.grant_types_supported)||!r.grant_types_supported.includes(Me))throw new A("Accounts does not advertise OAuth device authorization.");let n=["device_authorization_endpoint","token_endpoint","revocation_endpoint"];for(let i of n){if(typeof r[i]!="string")throw new A(`Accounts discovery is missing ${i}.`);let s=new URL(r[i]),a=new URL(this.accountsBaseUrl);if(s.origin!==a.origin)throw new A(`Accounts discovery returned an untrusted ${i}.`)}return{...r,scopes_supported:Array.isArray(r.scopes_supported)?r.scopes_supported:[]}}async requestDeviceCode({scopes:e}){let r=await this.discover({scopes:e}),o=await this._fetch(r.device_authorization_endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:this.clientId,scope:e.join(" "),audience:this.audience})}),n=await V(o);if(!o.ok)throw Z(n,o);if(typeof n.device_code!="string"||typeof n.user_code!="string"||typeof n.verification_uri!="string")throw new I("server_error",{status:o.status});return{deviceCode:n.device_code,userCode:n.user_code,verificationUri:n.verification_uri,verificationUriComplete:n.verification_uri_complete||n.verification_uri,expiresInSeconds:Number(n.expires_in)||600,pollIntervalSeconds:Number(n.interval)||5}}async pollDeviceCode({deviceCode:e}){let r=await this.discover(),o=new URLSearchParams({grant_type:Me,device_code:e,client_id:this.clientId}),n=await this._fetch(r.token_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:o}),i=await V(n);if(n.ok)return{status:"approved",token:Fe(i,n)};if(i?.error==="authorization_pending")return{status:"pending"};if(i?.error==="slow_down"){let s=r.elixpo_device_flow_polling||{};return{status:"slow_down",pollIntervalIncreaseSeconds:Math.max(5,Number(s.slow_down_interval_seconds||10)-Number(s.interval_seconds||5))}}if(i?.error==="access_denied")return{status:"denied"};if(i?.error==="expired_token")return{status:"expired"};throw Z(i,n)}async refresh({refreshToken:e,scopes:r}){let o=await this.discover({scopes:r||[]}),n=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.clientId});r?.length&&n.set("scope",r.join(" "));let i=await this._fetch(o.token_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:n}),s=await V(i);return Fe(s,i)}async revoke({token:e}){let r=await this.discover(),o=await this._fetch(r.revocation_endpoint,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({token:e,client_id:this.clientId})});if(!o.ok){let n=await V(o);throw Z(n,o)}}};var ze="elixpo",ve=class extends Error{constructor(e){super(e),this.name="ProductionAuthGateError"}};function Ge({providerId:t,environment:e}){if(e==="production"&&t!==ze)throw new ve(`Provider "${t}" is not approved for production. Only "${ze}" may be used in production.`)}function ee(t){if(t.authProvider==="mock"&&t.environment==="production")throw new Error("The mock auth provider cannot run in production.");if(t.authProvider!=="mock"&&t.authProvider!=="elixpo")throw new Error(`Unknown auth provider "${t.authProvider}".`);let e=t.authProvider==="mock"?new Y:new Q({accountsBaseUrl:t.accountsBaseUrl,clientId:t.clientId,audience:t.audience,cliVersion:t.cliVersion||"1.2.0",fetchImpl:t.fetchImpl});return Ge({providerId:e.providerId,environment:t.environment}),e}var T=class extends Error{constructor(e){super(e),this.name="CredentialStoreUnavailableError"}},P=class{async get(e){throw new Error("CredentialStore.get must be implemented by subclass")}async set(e,r){throw new Error("CredentialStore.set must be implemented by subclass")}async delete(e){throw new Error("CredentialStore.delete must be implemented by subclass")}async listProfiles(){throw new Error("CredentialStore.listProfiles must be implemented by subclass")}},te=class extends P{constructor(){super(),this._store=new Map}async get(e){return this._store.get(e)??null}async set(e,r){this._store.set(e,r)}async delete(e){this._store.delete(e)}async listProfiles(){return[...this._store.keys()]}},re=class extends P{constructor(e){super(),this._realStore=e}async get(e){try{return await this._realStore.get(e)}catch(r){throw new T(`OS keychain is unavailable: ${r.message}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`)}}async set(e,r){try{await this._realStore.set(e,r)}catch(o){throw new T(`OS keychain is unavailable: ${o.message}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`)}}async delete(e){try{await this._realStore.delete(e)}catch(r){throw new T(`OS keychain is unavailable: ${r.message}`)}}async listProfiles(){try{return await this._realStore.listProfiles()}catch(e){throw new T(`OS keychain is unavailable: ${e.message}`)}}};import{Entry as qr}from"@napi-rs/keyring";var Ar="lixblogs-cli",Tr="__lixblogs_availability_probe__";function oe(t){return new qr(Ar,t)}async function Je(){let t=oe(Tr);try{return t.setPassword("probe"),t.deletePassword(),{available:!0}}catch(e){return{available:!1,error:String(e.message??e).split(`
3
+ `)[0].trim()}}}var xe=class extends P{async get(e){let r=oe(e),o;try{o=r.getPassword()}catch(n){if(Ve(n))return null;throw n}return o==null?null:JSON.parse(o)}async set(e,r){oe(e).setPassword(JSON.stringify(r))}async delete(e){let r=oe(e);try{r.deletePassword()}catch(o){if(Ve(o))return;throw o}}async listProfiles(){throw new Error("KeychainCredentialStore.listProfiles is not supported directly \u2014 use ProfileRegistry to track known profile IDs, then look up each one via get().")}};function Ve(t){let e=String(t?.message??"");return/no such|not found|nosuchkeyring|nosuchitem/i.test(e)}var ne=class extends P{constructor(e){super(),this._keychain=new xe,this._registry=e}async get(e){return this._keychain.get(e)}async set(e,r){await this._keychain.set(e,r),await this._registry.add(e)}async delete(e){await this._keychain.delete(e),await this._registry.remove(e)}async listProfiles(){return this._registry.list()}};import{promises as ie}from"node:fs";import He from"node:path";import Rr from"node:os";function Or(){return He.join(Rr.homedir(),".config","lixblogs","profiles.json")}var _=class{constructor(e=Or()){this._path=e}async list(){return(await this._read()).profiles}async getActive(){let e=await this._read();return e.activeProfile&&e.profiles.includes(e.activeProfile)?e.activeProfile:e.profiles[0]||null}async setActive(e){S(e);let r=await this._read();if(!r.profiles.includes(e))throw new Error(`Profile "${e}" does not exist. Log in with it first.`);await this._write(r.profiles,e)}async _read(){try{let e=await ie.readFile(this._path,"utf8"),r=JSON.parse(e);return{profiles:Array.isArray(r.profiles)?r.profiles.filter(n=>typeof n=="string"):[],activeProfile:typeof r.activeProfile=="string"?r.activeProfile:null}}catch(e){if(e.code==="ENOENT")return{profiles:[],activeProfile:null};throw e}}async add(e){S(e);let r=await this._read(),o=new Set(r.profiles);o.add(e),await this._write([...o],r.activeProfile||e)}async remove(e){let r=await this._read(),o=r.profiles.filter(i=>i!==e),n=r.activeProfile===e?o[0]||null:r.activeProfile;await this._write(o,n)}async _write(e,r=null){await ie.mkdir(He.dirname(this._path),{recursive:!0});let o=`${this._path}.${process.pid}.tmp`;await ie.writeFile(o,JSON.stringify({activeProfile:r,profiles:e},null,2),{encoding:"utf8",mode:384}),await ie.rename(o,this._path)}};function S(t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(t||""))throw new Error("Profile names must be 1-64 characters using letters, numbers, dot, dash, or underscore.");return t}async function Ke({allowInsecureFallback:t=!1,profileRegistry:e}={}){let r=await Je();if(!r.available){if(!t)throw new T(`OS keychain is unavailable: ${r.error}. Re-run with an explicit fallback flag if you want to opt in to a less secure storage method.`);return process.stderr.write(`warning: OS keychain unavailable (${r.error}); using in-memory fallback because --allow-insecure-fallback was passed. Credentials will NOT persist between CLI runs.
4
+ `),new te}let o=e||new _,n=new ne(o);return new re(n)}import{readFile as Pr}from"node:fs/promises";var Lr=/^lix_pat_[A-Za-z0-9_-]{32,120}$/,L=class extends Error{constructor(e){super(e),this.name="ApiTokenConfigurationError",this.code="invalid_api_token_configuration"}};function _e(t,e){let r=String(t||"").trim();if(!Lr.test(r))throw new L(`${e} does not contain a valid LixBlogs personal access token.`);return r}async function Xe({flags:t={},env:e=process.env,readFileImpl:r=Pr}={}){let o=t.tokenFile,n=e.LIXBLOGS_TOKEN,i=e.LIXBLOGS_TOKEN_FILE;if(o)try{return{token:_e(await r(o,"utf8"),`Token file ${o}`),source:"token-file"}}catch(s){throw s instanceof L?s:new L(`Could not read token file ${o}: ${s.message}`)}if(n)return{token:_e(n,"LIXBLOGS_TOKEN"),source:"environment"};if(i)try{return{token:_e(await r(i,"utf8"),`Token file ${i}`),source:"environment-file"}}catch(s){throw s instanceof L?s:new L(`Could not read token file ${i}: ${s.message}`)}return null}var Ie="[REDACTED]",jr=/token|refresh|secret|password|authorization/i,Cr=/^(mock-(access|refresh)-|lix_pat_|Bearer\s+)\S+/i;function We(t){return typeof t=="string"&&Cr.test(t)?Ie:t}function ke(t){if(Array.isArray(t))return t.map(e=>ke(e));if(t&&typeof t=="object"){let e={};for(let[r,o]of Object.entries(t))jr.test(r)?e[r]=Ie:typeof o=="object"&&o!==null?e[r]=ke(o):e[r]=We(o);return e}return We(t)}function se(t,e){return JSON.stringify(ke(t),null,e)}function N(t){return typeof t!="string"?t:t.replace(/(mock-(access|refresh)-\S+|lix_pat_[A-Za-z0-9_-]+|Bearer\s+\S+)/gi,Ie)}async function Ye({provider:t,credentialStore:e,profileId:r,scopes:o,openBrowser:n,resolveProfileId:i,sleep:s=l=>new Promise(c=>setTimeout(c,l)),onStatus:a=()=>{}}){let l;try{l=await t.requestDeviceCode({scopes:o})}catch(u){return{ok:!1,reason:N(u.message)}}a({type:"verification_pending",verificationUri:l.verificationUri,verificationUriComplete:l.verificationUriComplete,userCode:l.userCode,expiresInSeconds:l.expiresInSeconds}),n&&await n(l.verificationUriComplete||l.verificationUri);let c=l.pollIntervalSeconds*1e3,h=Date.now()+l.expiresInSeconds*1e3;for(;Date.now()<h;){await s(c);let u;try{u=await t.pollDeviceCode({deviceCode:l.deviceCode})}catch(w){return{ok:!1,reason:N(w.message)}}if(u.status==="approved"){let w=r;if(i)try{w=await i({accessToken:u.token.accessToken,requestedProfileId:r})}catch(E){return{ok:!1,reason:N(E.message)}}return await e.set(w,{accessToken:u.token.accessToken,refreshToken:u.token.refreshToken,expiresAt:Date.now()+u.token.expiresInSeconds*1e3,scopes:u.token.scopes}),a({type:"approved"}),{ok:!0,profileId:w}}if(u.status==="denied")return a({type:"denied"}),{ok:!1,reason:"Login was denied."};if(u.status==="expired")return a({type:"expired"}),{ok:!1,reason:"Device code expired before login was approved."};if(u.status==="slow_down"){c+=u.pollIntervalIncreaseSeconds*1e3,a({type:"slow_down",newIntervalMs:c});continue}a({type:"pending"})}return{ok:!1,reason:"Device code expired before login was approved."}}async function Ze({credentialStore:t,profileId:e}){let r=e?[e]:await t.listProfiles(),o=[];for(let n of r){let i=await t.get(n);if(!i){o.push({profileId:n,loggedIn:!1});continue}o.push({profileId:n,loggedIn:!0,expired:Date.now()>=i.expiresAt,scopes:i.scopes})}return o}async function Qe({credentialStore:t,profileId:e}){return await t.delete(e),{ok:!0}}async function et({provider:t,credentialStore:e,profileId:r,confirmed:o}){if(o!==!0)return{ok:!1,reason:"Revoke was not confirmed. This is a destructive action and requires explicit confirmation (interactive prompt, or --yes in a non-interactive session)."};let n=await e.get(r);return n?(await t.revoke({token:n.refreshToken}),await e.delete(r),{ok:!0}):{ok:!1,reason:`No stored credentials for profile "${r}".`}}async function tt({credentialStore:t,profileRegistry:e}){let r=await e.getActive(),o=await t.listProfiles(),n=[];for(let i of o){let s=await t.get(i);n.push({profileId:i,active:i===r,loggedIn:!!s,expired:s?Date.now()>=s.expiresAt:void 0,scopes:s?.scopes||[]})}return{activeProfile:r,profiles:n}}async function rt({credentialStore:t,profileRegistry:e,profileId:r}){return await t.get(r)?(await e.setActive(r),{ok:!0,profileId:r}):{ok:!1,reason:`Profile "${r}" is not logged in.`}}async function ot({accessToken:t,apiBaseUrl:e,fetchImpl:r=globalThis.fetch}){let o=new URL("/api/v1/me",e),n=await r(o,{headers:{accept:"application/json",authorization:`Bearer ${t}`}}),i;try{i=await n.json()}catch{throw new Error("LixBlogs could not resolve the signed-in username.")}if(!n.ok||typeof i?.data?.username!="string")throw new Error(i?.error?.message||"LixBlogs could not resolve the signed-in username.");return S(i.data.username)}var Ur=6e4,nt=new WeakMap;function Dr(t){let e=nt.get(t);return e||(e=new Map,nt.set(t,e)),e}var ae=class extends Error{constructor(e){super(`Profile "${e}" needs to log in again.`),this.name="LoginRequiredError",this.code="login_required"}},Ee=class extends Error{constructor(e,r){super("The configured LixBlogs origin is not serving the API v1 JSON contract."),this.name="ApiContractUnavailableError",this.code="api_contract_unavailable",this.status=e,this.details={contentType:r||"unknown"},this.hint="Deploy the LixBlogs API v1 stack, or select an origin that exposes /api/v1."}},J=class{constructor({provider:e,credentialStore:r,profileId:o,apiBaseUrl:n="https://blogs.elixpo.com",fetchImpl:i=globalThis.fetch,refreshSkewMs:s=Ur,accessToken:a=null}){this.provider=e,this.credentialStore=r,this.profileId=o,this.apiBaseUrl=new URL(n),this.fetchImpl=i,this.refreshSkewMs=s,this.accessToken=a}async _refresh(e,{force:r=!1}={}){let o=Dr(this.credentialStore),n=o.get(this.profileId);if(n)return n;let i=(async()=>{let s=await this.credentialStore.get(this.profileId)||e;if(!r&&s.expiresAt-Date.now()>this.refreshSkewMs)return s;try{let a=await this.provider.refresh({refreshToken:s.refreshToken,scopes:s.scopes}),l={accessToken:a.accessToken,refreshToken:a.refreshToken,expiresAt:Date.now()+a.expiresInSeconds*1e3,scopes:a.scopes};return await this.credentialStore.set(this.profileId,l),l}catch(a){throw a instanceof I&&a.requiresLogin?(await this.credentialStore.delete(this.profileId),new ae(this.profileId)):a}})();o.set(this.profileId,i);try{return await i}finally{o.get(this.profileId)===i&&o.delete(this.profileId)}}async credentials({forceRefresh:e=!1}={}){if(this.accessToken)return{accessToken:this.accessToken,refreshToken:null,expiresAt:null,scopes:null,credentialType:"personal_access_token"};let r=await this.credentialStore.get(this.profileId);if(!r)throw new ae(this.profileId);return e||r.expiresAt-Date.now()<=this.refreshSkewMs?this._refresh(r,{force:e}):r}async request(e,r={}){let o=await this.requestRaw(e,r),n=o.headers.get("content-type")||"";if(!n.toLowerCase().includes("application/json"))throw new Ee(o.status,n);return o}async requestRaw(e,r={}){let o=new URL(e,this.apiBaseUrl);if(o.origin!==this.apiBaseUrl.origin||!o.pathname.startsWith("/api/v1/"))throw new Error("Authenticated CLI requests are restricted to the configured LixBlogs /api/v1 resource server.");let n=await this.credentials(),i=()=>this.fetchImpl(o.toString(),{...r,headers:{...r.headers,authorization:`Bearer ${n.accessToken}`}}),s=await i();return s.status===401&&!this.accessToken&&(n=await this.credentials({forceRefresh:!0}),s=await i()),s}async requireScopes(e){let r=await this.credentials();if(!Array.isArray(r.scopes))return;let o=e.filter(n=>!r.scopes.includes(n));if(o.length){let n=new Error(`Login again with the required scope${o.length>1?"s":""}: ${o.join(", ")}`);throw n.name="InsufficientScopeError",n.code="insufficient_scope",n.missingScopes=o,n}}};import{randomUUID as it}from"node:crypto";var m=class extends Error{constructor(e,r,{status:o,requestId:n,details:i}={}){super(r),this.name="BlogApiError",this.code=e||"api_error",this.status=o||0,this.requestId=n||null,this.details=i||null}};async function Nr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new m(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return{payload:e,etag:t.headers.get("etag")}}var H=class{constructor(e,{sleep:r=o=>new Promise(n=>setTimeout(n,o))}={}){this.http=e,this.sleep=r}async request(e,r={}){let o={...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}},i=(o.method||"GET")==="GET"||!!o.headers["idempotency-key"];for(let s=0;s<2;s+=1)try{let a=await this.http.request(e,o);if(i&&s===0&&(a.status===429||a.status>=500)){let l=Math.min(2,Number.parseInt(a.headers.get("retry-after")||"1",10)||1);await this.sleep(l*1e3);continue}return Nr(a)}catch(a){if(!i||s>0||a instanceof m||a?.code)throw a;await this.sleep(250)}throw new m("request_failed","The LixBlogs request failed after retrying.")}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async whoami(){return await this.requireScopes(["lixblogs:profile:read"]),(await this.request("/api/v1/me")).payload.data}async list({status:e="all",limit:r=20,cursor:o}={}){await this.requireScopes(["lixblogs:blog:read"]);let n=new URLSearchParams({status:e,limit:String(r)});return o&&n.set("cursor",o),(await this.request(`/api/v1/blogs?${n}`)).payload}async get(e){await this.requireScopes(["lixblogs:blog:read"]);let r=await this.request(`/api/v1/blogs/${encodeURIComponent(e)}`);return{...r.payload.data,etag:r.payload.data.etag||r.etag}}async create(e,{idempotencyKey:r=it()}={}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request("/api/v1/blogs",{method:"POST",headers:{"idempotency-key":r},body:JSON.stringify(e)})).payload.data}async update(e,r,{etag:o}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}`,{method:"PATCH",headers:{"if-match":o},body:JSON.stringify(r)})).payload.data}async publish(e,{etag:r,status:o="published",idempotencyKey:n=it()}){return await this.requireScopes(["lixblogs:blog:publish"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/publish`,{method:"POST",headers:{"if-match":r,"idempotency-key":n},body:JSON.stringify({status:o})})).payload.data}async unpublish(e,{etag:r}){return await this.requireScopes(["lixblogs:blog:publish"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/unpublish`,{method:"POST",headers:{"if-match":r}})).payload.data}async delete(e,{etag:r,permanent:o=!1}){return await this.requireScopes(["lixblogs:blog:delete",...o?["lixblogs:blog:delete:permanent"]:[]]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}${o?"?permanent=true":""}`,{method:"DELETE",headers:{"if-match":r,...o?{"x-confirm-permanent-delete":e}:{}}})).payload.data}async restore(e,{etag:r}){return await this.requireScopes(["lixblogs:blog:delete"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/restore`,{method:"POST",headers:{"if-match":r}})).payload.data}async versions(e){return await this.requireScopes(["lixblogs:blog:read"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions`)).payload.data}async version(e,r){await this.requireScopes(["lixblogs:blog:read"]);let o=new URLSearchParams({version:r});return(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions?${o}`)).payload.data}async restoreVersion(e,r,{etag:o}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/versions`,{method:"POST",headers:{"if-match":o},body:JSON.stringify({versionId:r})})).payload.data}async comments(e){return await this.requireScopes(["lixblogs:blog:read"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments`)).payload.data}async comment(e,r,{parentId:o}={}){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments`,{method:"POST",body:JSON.stringify({content:r,parentId:o})})).payload.data}async deleteComment(e,r){return await this.requireScopes(["lixblogs:blog:write"]),(await this.request(`/api/v1/blogs/${encodeURIComponent(e)}/comments/${encodeURIComponent(r)}`,{method:"DELETE"})).payload.data}};async function Br(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new m(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return{payload:e,etag:t.headers.get("etag")}}var le=class{constructor(e,{sleep:r=o=>new Promise(n=>setTimeout(n,o))}={}){this.http=e,this.sleep=r}async request(e,r={}){let o={...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}},i=(o.method||"GET")==="GET";for(let s=0;s<2;s+=1)try{let a=await this.http.request(e,o);if(i&&s===0&&(a.status===429||a.status>=500)){let l=Math.min(2,Number.parseInt(a.headers.get("retry-after")||"1",10)||1);await this.sleep(l*1e3);continue}return Br(a)}catch(a){if(!i||s>0||a instanceof m||a?.code)throw a;await this.sleep(250)}throw new m("request_failed","The LixBlogs request failed after retrying.")}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async list(){return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request("/api/v1/orgs")).payload}async get(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}`)).payload.data}async collections(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}/collections`)).payload.data}async members(e){if(!e)throw new Error("An organization ID or handle is required.");return await this.requireScopes(["lixblogs:organizations:read"]),(await this.request(`/api/v1/orgs/${encodeURIComponent(e)}/members`)).payload.data}async targets(){await this.requireScopes(["lixblogs:organizations:read"]);let o=((await this.list())?.data||[]).filter(i=>i.canWrite),n=await Promise.all(o.map(async i=>{let s=[];try{s=await this.collections(i.id)}catch{s=[]}return{target:`org:${i.id}`,orgId:i.id,slug:i.slug,name:i.name,role:i.role,collections:s.map(a=>({id:a.id,slug:a.slug,name:a.name}))}}));return{personal:{target:"personal",name:"Personal Blog"},organizations:n}}};import{randomUUID as ce}from"node:crypto";async function Mr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new m(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return e.data}var ue=class{constructor(e){this.http=e}async request(e,r={}){let o=await this.http.request(e,{...r,headers:{accept:"application/json",...r.body?{"content-type":"application/json"}:{},...r.headers}});return Mr(o)}async list(e){return await this.http.requireScopes(["lixblogs:collaboration:read"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`)}async invitations(){return await this.http.requireScopes(["lixblogs:collaboration:read"]),this.request("/api/v1/collaboration/invitations")}async invite(e,{user:r,role:o,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"POST",headers:{"idempotency-key":n},body:JSON.stringify({user:r,role:o})})}async role(e,{user:r,role:o,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"PATCH",headers:{"idempotency-key":n},body:JSON.stringify({user:r,role:o})})}async remove(e,{user:r,idempotencyKey:o=ce()}={}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request(`/api/v1/blogs/${encodeURIComponent(e)}/collaborators`,{method:"DELETE",headers:{"idempotency-key":o},body:JSON.stringify({...r?{user:r}:{}})})}async resolveInvitation(e,{action:r,showOnProfile:o=!0,idempotencyKey:n=ce()}){return await this.http.requireScopes(["lixblogs:collaboration:write"]),this.request("/api/v1/collaboration/invitations",{method:"POST",headers:{"idempotency-key":n},body:JSON.stringify({blogId:e,action:r,showOnProfile:o})})}};async function Fr(t){let e;try{e=await t.json()}catch{e=null}if(!t.ok||e?.error)throw new m(e?.error?.code||`http_${t.status}`,e?.error?.message||`LixBlogs returned HTTP ${t.status}.`,{status:t.status,requestId:e?.error?.requestId||t.headers.get("x-request-id"),details:e?.error?.details});return e}var de=class{constructor(e){this.http=e}async query(e={}){let r=e.scope||"personal";await this.http.requireScopes(["lixblogs:analytics:read",...r.startsWith("org:")?["lixblogs:organizations:read"]:[]]);let o=new URLSearchParams({scope:r,range:e.range||(e.from||e.to?"custom":"30d"),dimension:e.dimension||"overview",limit:String(e.limit||20)});return e.from&&o.set("from",e.from),e.to&&o.set("to",e.to),e.cursor&&o.set("cursor",e.cursor),Fr(await this.http.request(`/api/v1/analytics?${o}`,{headers:{accept:"application/json"}}))}};var pe=class{constructor(e){this.http=e}async requireScopes(e){typeof this.http.requireScopes=="function"&&await this.http.requireScopes(e)}async _request(e,r={}){let o=await this.http.request(e,r),n;try{n=await o.json()}catch{n=null}if(!o.ok||n?.error){let i=new Error(n?.error?.message||`Request failed with HTTP ${o.status}`);throw i.code=n?.error?.code||`http_${o.status}`,i.status=o.status,i.requestId=n?.error?.requestId||o.headers.get("x-request-id")||null,i.details=n?.error?.details||null,i}return n.data}async cloudinaryStatus(){return await this.requireScopes(["lixblogs:integrations:cloudinary:read"]),this._request("/api/v1/integrations/cloudinary")}async cloudinaryDisconnect(){return await this.requireScopes(["lixblogs:integrations:cloudinary:disconnect"]),this._request("/api/v1/integrations/cloudinary",{method:"DELETE"})}async pollinationsStatus({refresh:e=!1}={}){return await this.requireScopes(["lixblogs:media:read"]),this._request(`/api/v1/integrations/pollinations${e?"?refresh=1":""}`)}async pollinationsDisconnect(){return await this.requireScopes(["lixblogs:media:write"]),this._request("/api/v1/integrations/pollinations",{method:"DELETE"})}};import{randomUUID as st}from"node:crypto";var zr=Object.freeze({"image/avif":"avif","image/bmp":"bmp","image/jpeg":"jpg","image/png":"png","image/svg+xml":"svg","image/webp":"webp"});async function Se(t){let e=await t.json().catch(()=>({})),r=new Error(e.error?.message||e.error||`Media request failed with HTTP ${t.status}`);return r.code=e.error?.code||e.code||`http_${t.status}`,r.status=t.status,r}var fe=class{constructor(e){this.http=e}async generate({prompt:e,model:r="flux",seed:o,width:n,height:i,destination:s="inline",generationId:a=st(),reference:l}){await this.http.requireScopes(["lixblogs:media:write"]);let c,h;if(l){c=new FormData;for(let[w,E]of Object.entries({prompt:e,model:r,seed:o,width:n,height:i,destination:s,generationId:a}))E!==void 0&&c.append(w,String(E));c.append("referenceImage",new Blob([l.bytes],{type:l.mimeType}),l.name||"reference-image"),h={accept:"image/*, application/json"}}else c=JSON.stringify({prompt:e,model:r,seed:o,width:n,height:i,destination:s,generationId:a}),h={"content-type":"application/json",accept:"image/*, application/json"};let u=await this.http.requestRaw("/api/v1/media/generate",{method:"POST",headers:h,body:c});if(!u.ok)throw await Se(u);return{bytes:new Uint8Array(await u.arrayBuffer()),mimeType:u.headers.get("content-type")||"image/jpeg",generationId:a}}async upload({bytes:e,mimeType:r,blogId:o,mediaType:n="inline",uploadId:i=st()}){await this.http.requireScopes(["lixblogs:media:write"]);let s=new FormData,a=zr[r];if(!a)throw new Error(`Unsupported image MIME type: ${r}`);s.append("file",new Blob([e],{type:r}),`lixblogs-${i}.${a}`),s.append("type",n),s.append("uploadId",i),o&&s.append("blogId",o);let l=await this.http.requestRaw("/api/v1/media/upload",{method:"POST",body:s,headers:{accept:"application/json"}});if(!l.ok)throw await Se(l);return l.json()}async delete(e){if(!e)throw new Error("A media ID is required.");await this.http.requireScopes(["lixblogs:media:write"]);let r=await this.http.request(`/api/v1/media/${encodeURIComponent(e)}`,{method:"DELETE"});if(!r.ok)throw await Se(r);let o=await r.json();return o.data||o}};var p=Object.freeze({OK:0,ERROR:1,USAGE:2,CONFLICT:3,AUTH:4,CONFIRMATION:5}),Gr=Object.freeze({login:["auth","login"],logout:["auth","logout"],whoami:["auth","whoami"],profiles:["auth","profiles"],use:["auth","use"]});function at(t){let[e,...r]=t,o=Gr[e];return o?[...o,...r]:t}function lt(t,e="cli_error"){if(t&&typeof t=="object"&&t.error&&!Array.isArray(t.error))return t;let r=t&&typeof t=="object"?t:{message:String(t||"Command failed.")};return{ok:!1,error:{code:r.code||e,message:r.message||"Command failed.",hint:r.hint||null,requestId:r.requestId||null,...r.details?{details:r.details}:{}}}}function g(t,e){if(t.yes)return;let r=new Error(`${e} requires --yes in non-interactive operation.`);throw r.code="confirmation_required",r.hint="Review the operation, then run it again with --yes.",r.exitCode=p.CONFIRMATION,r}var x=Object.freeze({reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",violet:"\x1B[38;5;141m",green:"\x1B[38;5;42m",yellow:"\x1B[38;5;220m",red:"\x1B[38;5;203m",gray:"\x1B[38;5;245m"});function d(t=process.stdout,e=process.env){return!!t.isTTY&&e.NO_COLOR===void 0&&e.TERM!=="dumb"}function k(t,e,r){return r?`${e}${t}${x.reset}`:t}function ut({url:t,code:e,expiresInSeconds:r,profile:o,interactive:n,color:i=!1}){let s=`${k("\u25C6",x.violet,i)} ${k("LixBlogs",x.bold,i)}`,a=n?"Press Enter to open here, or use the URL on another device.":"Open the URL in any browser and approve this device.";return["",` ${s}`,` ${k("Device login",x.dim,i)}`," \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",` URL ${t}`,` Code ${k(e,x.bold,i)}`,` Expires ${Math.ceil(r/60)} min`,o?` Profile ${o} ${k("(local credential slot)",x.dim,i)}`:` Profile ${k("your Accounts username after approval",x.dim,i)}`,"",` ${a}`," No localhost callback or exposed port is required.",""].join(`
5
+ `)}function v(t,e=!1){return` ${k(`\u2713 ${t}`,x.green,e)}`}function $(t,e=!1){return` ${k(`! ${t}`,x.yellow,e)}`}function j(t,e=!1){return` ${k(`\u2022 ${t}`,x.gray,e)}`}function dt(t,e=!1){return` ${k(`\u2715 ${t}`,x.red,e)}`}var ct=Object.freeze(["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"]);function Vr(t,{stream:e=process.stderr,enabled:r=!!e.isTTY,intervalMs:o=80,color:n=d(e)}={}){if(!r)return{stop(){}};let i=0,s=()=>{e.write(`\r\x1B[2K${k(ct[i],x.violet,n)} ${k(t,x.gray,n)}`),i=(i+1)%ct.length};s();let a=setInterval(s,o);a.unref?.();let l=!1;return{stop(){l||(l=!0,clearInterval(a),e.write("\r\x1B[2K"))}}}async function q(t,e,r,o={}){let n=Vr(e,{...o,enabled:o.enabled??(!t?.json&&!t?.quiet&&!!(o.stream||process.stderr).isTTY)});try{return await r()}finally{n.stop()}}function pt({input:t=process.stdin,open:e,url:r}){if(!t.isTTY||typeof e!="function")return()=>{};let o=()=>{Promise.resolve(e(r)).catch(()=>{})};return t.setEncoding?.("utf8"),t.once("data",o),t.resume?.(),()=>{t.off?.("data",o),t.pause?.()}}function ft(t){return[{type:"text",text:t}]}function B(t){let e=String(t||""),r=[],o=/(\*\*([^*]+)\*\*|\*([^*]+)\*|`([^`]+)`|\[([^\]]+)\]\((https:\/\/[^)]+)\))/g,n=0;for(let i of e.matchAll(o))i.index>n&&r.push({type:"text",text:e.slice(n,i.index)}),i[2]!==void 0?r.push({type:"text",text:i[2],styles:{bold:!0}}):i[3]!==void 0?r.push({type:"text",text:i[3],styles:{italic:!0}}):i[4]!==void 0?r.push({type:"text",text:i[4],styles:{code:!0}}):r.push({type:"link",href:i[6],content:[{type:"text",text:i[5],styles:{}}]}),n=i.index+i[0].length;return n<e.length&&r.push({type:"text",text:e.slice(n)}),r.length?r:ft(e)}function mt(t){let e=String(t||"").replace(/\r\n/g,`
6
6
  `).split(`
7
- `),r=[],o=[],n=()=>{o.length&&(r.push({type:"paragraph",content:M(o.join(" ").trim())}),o=[])};for(let i=0;i<e.length;i+=1){let a=e[i].trim();if(!a){n();continue}let l=a.match(/^```([\w+-]*)/);if(l){n();let ye=[];for(i+=1;i<e.length&&!/^```/.test(e[i].trim());)ye.push(e[i++]);r.push(l[1].toLowerCase()==="mermaid"?{type:"mermaidBlock",props:{diagram:ye.join(`
8
- `)}}:{type:"codeBlock",props:{language:l[1].toLowerCase()},content:ut(ye.join(`
9
- `))});continue}let u=a.match(/^(#{1,3})\s+(.+)/);if(u){n(),r.push({type:"heading",props:{level:String(u[1].length)},content:M(u[2])});continue}let d=a.match(/^(?:[-*]\s+)?\[([ xX])\](?:\s+(.*))?$/);if(d){n(),r.push({type:"checkListItem",props:{checked:d[1].toLowerCase()==="x"},content:M(d[2]||"")});continue}let c=a.match(/^[-*]\s+(.+)/);if(c){n(),r.push({type:"bulletListItem",content:M(c[1])});continue}let f=a.match(/^\d+\.\s+(.+)/);if(f){n(),r.push({type:"numberedListItem",content:M(f[1])});continue}let k=a.match(/^>\s?(.*)/);if(k){n(),r.push({type:"quote",content:M(k[1])});continue}let he=a.match(/^!\[([^\]]*)\]\((https:\/\/[^)]+)\)$/);if(he){n(),r.push({type:"image",props:{url:he[2],caption:he[1]}});continue}if(/^([-*_])\1{2,}$/.test(a)){n(),r.push({type:"divider"});continue}o.push(a)}return n(),r}function pt(t){return(t?.content||[]).map(e=>typeof e=="string"?e:e?.type==="link"?pt(e):e?.text||"").join("")}function ft(t){return(t?.content||[]).map(e=>{if(typeof e=="string")return e;if(e?.type==="link")return`[${ft(e)}](${e.href})`;let r=e?.text||"";return e?.styles?.code&&(r=`\`${r}\``),e?.styles?.italic&&(r=`*${r}*`),e?.styles?.bold&&(r=`**${r}**`),r}).join("")}function K(t){return(t||[]).map(e=>{let r=ft(e);return e.type==="heading"?`${"#".repeat(Number(e.props?.level)||1)} ${r}`:e.type==="checkListItem"?`- [${e.props?.checked?"x":" "}] ${r}`:e.type==="bulletListItem"?`- ${r}`:e.type==="numberedListItem"?`1. ${r}`:e.type==="quote"?`> ${r}`:e.type==="codeBlock"?`\`\`\`${e.props?.language||""}
10
- ${pt(e)}
7
+ `),r=[],o=[],n=()=>{o.length&&(r.push({type:"paragraph",content:B(o.join(" ").trim())}),o=[])};for(let i=0;i<e.length;i+=1){let a=e[i].trim();if(!a){n();continue}let l=a.match(/^```([\w+-]*)/);if(l){n();let we=[];for(i+=1;i<e.length&&!/^```/.test(e[i].trim());)we.push(e[i++]);r.push(l[1].toLowerCase()==="mermaid"?{type:"mermaidBlock",props:{diagram:we.join(`
8
+ `)}}:{type:"codeBlock",props:{language:l[1].toLowerCase()},content:ft(we.join(`
9
+ `))});continue}let c=a.match(/^(#{1,3})\s+(.+)/);if(c){n(),r.push({type:"heading",props:{level:String(c[1].length)},content:B(c[2])});continue}let h=a.match(/^(?:[-*]\s+)?\[([ xX])\](?:\s+(.*))?$/);if(h){n(),r.push({type:"checkListItem",props:{checked:h[1].toLowerCase()==="x"},content:B(h[2]||"")});continue}let u=a.match(/^[-*]\s+(.+)/);if(u){n(),r.push({type:"bulletListItem",content:B(u[1])});continue}let w=a.match(/^\d+\.\s+(.+)/);if(w){n(),r.push({type:"numberedListItem",content:B(w[1])});continue}let E=a.match(/^>\s?(.*)/);if(E){n(),r.push({type:"quote",content:B(E[1])});continue}let ye=a.match(/^!\[([^\]]*)\]\((https:\/\/[^)]+)\)$/);if(ye){n(),r.push({type:"image",props:{url:ye[2],caption:ye[1]}});continue}if(/^([-*_])\1{2,}$/.test(a)){n(),r.push({type:"divider"});continue}o.push(a)}return n(),r}function gt(t){return(t?.content||[]).map(e=>typeof e=="string"?e:e?.type==="link"?gt(e):e?.text||"").join("")}function ht(t){return(t?.content||[]).map(e=>{if(typeof e=="string")return e;if(e?.type==="link")return`[${ht(e)}](${e.href})`;let r=e?.text||"";return e?.styles?.code&&(r=`\`${r}\``),e?.styles?.italic&&(r=`*${r}*`),e?.styles?.bold&&(r=`**${r}**`),r}).join("")}function K(t){return(t||[]).map(e=>{let r=ht(e);return e.type==="heading"?`${"#".repeat(Number(e.props?.level)||1)} ${r}`:e.type==="checkListItem"?`- [${e.props?.checked?"x":" "}] ${r}`:e.type==="bulletListItem"?`- ${r}`:e.type==="numberedListItem"?`1. ${r}`:e.type==="quote"?`> ${r}`:e.type==="codeBlock"?`\`\`\`${e.props?.language||""}
10
+ ${gt(e)}
11
11
  \`\`\``:e.type==="mermaidBlock"?`\`\`\`mermaid
12
12
  ${e.props?.diagram||""}
13
13
  \`\`\``:e.type==="image"?`![${e.props?.caption||""}](${e.props?.url||""})`:e.type==="divider"?"---":r}).join(`
14
14
 
15
- `)}import{promises as X}from"node:fs";import{tmpdir as Mr}from"node:os";import ke from"node:path";import{spawn as Fr}from"node:child_process";async function zr(t){let e="";t.setEncoding("utf8");for await(let r of t)e+=r;return e}async function Gr(t="",e=process.env.EDITOR||process.env.VISUAL){if(!e)throw new Error("$EDITOR or $VISUAL must be set when using --editor.");let r=await X.mkdtemp(ke.join(Mr(),"lixblogs-")),o=ke.join(r,"post.md");await X.writeFile(o,t,{mode:384});try{return await new Promise((n,i)=>{let s=Fr(e,[o],{stdio:"inherit",shell:!0});s.once("error",i),s.once("exit",a=>a===0?n():i(new Error(`Editor exited with code ${a}.`)))}),await X.readFile(o,"utf8")}finally{await X.rm(r,{recursive:!0,force:!0})}}async function Se(t,{stdin:e=process.stdin,initial:r=""}={}){let o=[t.file!==void 0,t.stdin,t.content!==void 0,t.editor].filter(Boolean).length;if(o>1)throw new Error("Use only one of --file, --stdin, --content, or --editor.");if(!o)return null;let n;return t.file!==void 0?n=await X.readFile(ke.resolve(t.file),"utf8"):t.stdin?n=await zr(e):t.content!==void 0?n=t.content:n=await Gr(r),{markdown:n,blocks:dt(n)}}function $e(t){let e={},r={title:"title",subtitle:"subtitle",slug:"slug",emoji:"emoji",publication:"publishedAs",collection:"collectionId",cover:"coverUrl"};for(let[o,n]of Object.entries(r))t[o]!==void 0&&(e[n]=t[o]);return t.tag!==void 0&&(e.tags=t.tag),t["member-only"]&&(e.memberOnly=!0),t["no-member-only"]&&(e.memberOnly=!1),t.secret&&(e.secret=!0),t["not-secret"]&&(e.secret=!1),t["allow-comments"]&&(e.allowComments=!0),t["no-comments"]&&(e.allowComments=!1),(t["cover-x"]!==void 0||t["cover-y"]!==void 0)&&(e.coverPosition={x:Number(t["cover-x"]??50),y:Number(t["cover-y"]??50)}),t["cover-zoom"]!==void 0&&(e.coverZoom=Number(t["cover-zoom"])),e}function Vr(t){let e=[],r=o=>{for(let n of o||[]){for(let i of n?.content||[]){let s=typeof i=="string"?i:i?.text||"";e.push(...s.trim().split(/\s+/).filter(Boolean))}n?.children&&r(n.children)}};return r(t),e.length}function me(t,{publishing:e=!1}={}){if(t.title!==void 0&&(typeof t.title!="string"||t.title.length>300))throw new Error("Title must be 300 characters or fewer.");if(t.subtitle!==void 0&&(typeof t.subtitle!="string"||t.subtitle.length>500))throw new Error("Subtitle must be 500 characters or fewer.");if(t.tags!==void 0&&(!Array.isArray(t.tags)||t.tags.length>5))throw new Error("Use at most five tags.");if(t.coverUrl&&!/^https:\/\//i.test(t.coverUrl))throw new Error("Cover URLs must use HTTPS.");if(t.publishedAs&&t.publishedAs!=="personal"&&!/^org:[^:]+$/.test(t.publishedAs))throw new Error("Publication must be personal or org:<id>.");if(t.content!==void 0){if(!Array.isArray(t.content))throw new Error("Blog content must be a block array.");if(Buffer.byteLength(JSON.stringify(t.content),"utf8")>15e5)throw new Error("Blog content exceeds the 1.5 MB limit.")}if(e){if(!t.title?.trim())throw new Error("A title is required before publishing.");if(Vr(t.content)<20)throw new Error("A post needs at least 20 words before publishing.")}return t}import{promises as qe}from"node:fs";import Ae from"node:path";var Jr=new Set(["create","edit","publish","unpublish","delete","trash","restore","restore-version"]);async function mt({client:t,action:e,result:r}){if(!Jr.has(e)||r?.dryRun||!r?.id||r.url&&r.status)return r;try{let o=await t.get(r.id);return{...r,status:o.status||r.status,url:o.url||r.url}}catch{return r}}async function gt({client:t,options:e}){return t.list({status:e.status,limit:e.limit,cursor:e.cursor})}async function Re({client:t,id:e}){if(!e)throw new Error("A blog ID is required.");let r=await t.get(e);return{...r,markdown:K(r.content)}}async function ht({client:t,options:e,stdin:r}){let o=await Se(e,{stdin:r}),n={...$e(e),content:o?.blocks||[]};return me(n),e["dry-run"]?{dryRun:!0,input:n,markdown:o?.markdown||""}:t.create(n,{idempotencyKey:e["idempotency-key"]})}async function yt({client:t,id:e,options:r,stdin:o}){if(!e)throw new Error("A blog ID is required.");let n=await t.get(e),i=await Se(r,{stdin:o,initial:K(n.content)}),s={...$e(r),...i?{content:i.blocks}:{}};if(!Object.keys(s).length)throw new Error("No blog changes were provided.");if(me(s),r["dry-run"])return{dryRun:!0,id:e,etag:n.etag,input:s,markdown:i?.markdown};try{return await t.update(e,s,{etag:r.etag||n.etag})}catch(a){if(!(a instanceof h)||a.code!=="revision_conflict")throw a;let l=await t.get(e),u=r.conflictDirectory||Ae.resolve(".lixblogs-conflicts");await qe.mkdir(u,{recursive:!0});let d=e.replace(/[^A-Za-z0-9._-]/g,"_"),c=Ae.join(u,`${d}-local.json`),f=Ae.join(u,`${d}-server.md`);throw await Promise.all([qe.writeFile(c,JSON.stringify(s,null,2),{mode:384}),qe.writeFile(f,K(l.content),{mode:384})]),a.details={...a.details,localPath:c,serverPath:f,serverEtag:l.etag},a}}async function wt({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);me(o,{publishing:!0});let n=r.status||"published";if(!["published","unlisted"].includes(n))throw new Error("--status must be published or unlisted.");return r["dry-run"]?{dryRun:!0,id:e,from:o.status,to:n}:(y(r,"Publishing this blog"),t.publish(e,{etag:r.etag||o.etag,status:n,idempotencyKey:r["idempotency-key"]}))}async function bt({client:t,id:e,options:r={}}){if(!e)throw new Error("A blog ID is required.");if(r.version){let o=await t.version(e,r.version);return{...o,markdown:K(o.content)}}return{data:await t.versions(e)}}async function vt({client:t,id:e,options:r}){if(!e||!r.version)throw new Error("A blog ID and --version are required.");y(r,"Restoring this historical version");let o=await t.get(e);return t.restoreVersion(e,r.version,{etag:r.etag||o.etag})}async function xt({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);return r["dry-run"]?{dryRun:!0,id:e,from:o.status,to:"draft"}:(y(r,"Unpublishing this blog"),t.unpublish(e,{etag:r.etag||o.etag}))}async function Pe({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");if(!r.yes)throw new Error("Deletion requires --yes. Trash is the default; add --permanent for irreversible deletion.");let o=await t.get(e);if(r["dry-run"])return{dryRun:!0,id:e,permanent:r.permanent};let n=await t.delete(e,{etag:r.etag||o.etag,permanent:r.permanent});return{...n,status:r.permanent?"deleted":"trashed",url:o.url||n.url}}async function It({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);return r["dry-run"]?{dryRun:!0,id:e,restoreTo:o.preDeleteStatus||"draft"}:(y(r,"Restoring this blog"),t.restore(e,{etag:r.etag||o.etag}))}var Hr={create:"Blog created",edit:"Blog updated",publish:"Blog published",unpublish:"Blog unpublished",delete:"Blog deleted",trash:"Blog moved to trash",restore:"Blog restored","restore-version":"Blog version restored"};function _t(t,e){let r=t==="delete"&&e?.status==="trashed"?"Blog moved to trash":Hr[t]||"Blog updated",o=e?.status?` [${e.status}]`:"",n=e?.url?` ${e.url}`:"";return`${r}${o}${n}`}function Et(t,e,r){if(t==="delete")return`Media ${e.id} deleted.`;let o=t==="generate"?"generated":"uploaded";return e.blog?`Image ${o} and attached to blog ${r}.`:`Image ${o} and stored.`}async function kt({client:t}){return t.list()}async function St({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.get(e)}async function $t({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.collections(e)}async function qt({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.members(e)}async function At({client:t}){return t.targets()}function F(t){if(!t)throw new Error("A blog ID is required.")}async function Rt({client:t,id:e}){return F(e),t.list(e)}async function Pt({client:t}){return t.invitations()}async function Tt({client:t,id:e,options:r}){if(F(e),!r.user)throw new Error("--user is required.");if(!["viewer","editor","admin"].includes(r.role))throw new Error("--role must be viewer, editor, or admin.");return r["dry-run"]?{dryRun:!0,action:"invite",blogId:e,user:r.user,role:r.role}:(y(r,"Inviting this collaborator"),t.invite(e,{user:r.user,role:r.role,idempotencyKey:r["idempotency-key"]}))}async function Ot({client:t,id:e,options:r}){if(F(e),!r.user)throw new Error("--user is required.");if(!["viewer","editor","admin"].includes(r.role))throw new Error("--role must be viewer, editor, or admin.");return r["dry-run"]?{dryRun:!0,action:"role",blogId:e,user:r.user,role:r.role}:(y(r,"Changing this collaborator role"),t.role(e,{user:r.user,role:r.role,idempotencyKey:r["idempotency-key"]}))}async function jt({client:t,id:e,options:r}){return F(e),r["dry-run"]?{dryRun:!0,action:"remove",blogId:e,user:r.user||"self"}:(y(r,"Removing this collaborator or invitation"),t.remove(e,{user:r.user,idempotencyKey:r["idempotency-key"]}))}async function Ct({client:t,id:e,options:r}){return F(e),r["dry-run"]?{dryRun:!0,action:"accept",blogId:e,showOnProfile:!r["hide-on-profile"]}:(y(r,"Accepting this collaboration invitation"),t.resolveInvitation(e,{action:"accept",showOnProfile:!r["hide-on-profile"],idempotencyKey:r["idempotency-key"]}))}async function Lt({client:t,id:e,options:r}){return F(e),r["dry-run"]?{dryRun:!0,action:"decline",blogId:e}:(y(r,"Declining this collaboration invitation"),t.resolveInvitation(e,{action:"decline",idempotencyKey:r["idempotency-key"]}))}import{access as Wr,cp as Nt,readFile as Kr,readdir as Xr}from"node:fs/promises";import b from"node:path";import{fileURLToPath as Yr}from"node:url";var Te=b.dirname(Yr(import.meta.url)),Bt=b.basename(Te)==="dist"?b.resolve(Te,".."):b.resolve(Te,"../../.."),Ut=b.join(Bt,"skills"),Dt=b.resolve(Bt,"../..",".agents","skills");async function L(t){try{return await Wr(t),!0}catch{return!1}}async function ge(){if(await L(Ut))return Ut;if(await L(Dt))return Dt;let t=new Error("No bundled LixBlogs skills were found. Reinstall @elixpo/lixblogs-cli.");throw t.code="skills_unavailable",t}function Mt(t){if(!/^lixblogs-[a-z0-9-]+$/.test(t||"")){let e=new Error("A valid lixblogs-* skill name is required.");throw e.code="invalid_skill_name",e}return t}async function Ft(t,e){let r=await Kr(b.join(t,e,"SKILL.md"),"utf8"),o=r.match(/^description:\s*(.+)$/m)?.[1]||r.match(/^description:\s*>-\s*\n\s*(.+)$/m)?.[1]||"",n=r.match(/`@elixpo\/lixblogs-cli`\s+([0-9.]+)/)?.[1]||null;return{name:e,description:o.trim(),minimumCliVersion:n,content:r}}async function Oe(){let t=await ge(),e=await Xr(t,{withFileTypes:!0});return Promise.all(e.filter(r=>r.isDirectory()&&r.name.startsWith("lixblogs-")).map(r=>Ft(t,r.name))).then(r=>r.map(({content:o,...n})=>n).sort((o,n)=>o.name.localeCompare(n.name)))}async function zt({name:t}){let e=await ge(),r=Mt(t);if(!await L(b.join(e,r,"SKILL.md"))){let o=new Error(`Skill "${r}" is not bundled.`);throw o.code="skill_not_found",o}return Ft(e,r)}async function Gt({name:t,options:e}){let r=await ge(),o=Mt(t),n=b.join(r,o);if(!await L(b.join(n,"SKILL.md"))){let a=new Error(`Skill "${o}" is not bundled.`);throw a.code="skill_not_found",a}let i=b.resolve(e.target||".agents/skills"),s=b.join(i,o);if(e["dry-run"])return{dryRun:!0,name:o,target:s,replace:await L(s)};if(await L(s)){if(!e.force){let a=new Error(`Skill already exists at ${s}.`);throw a.code="skill_exists",a.hint="Inspect the existing skill or re-run with --force --yes to replace it.",a}y(e,`Replacing ${s}`)}else y(e,`Installing ${o} into ${i}`);return await Nt(n,s,{recursive:!0,force:!!e.force}),{installed:!0,name:o,target:s}}async function Vt({options:t}){let e=await ge(),r=await Oe(),o=b.resolve(t.target||".agents/skills"),n=await Promise.all(r.map(async({name:s})=>{let a=b.join(o,s);return{name:s,target:a,replace:await L(a)}}));if(t["dry-run"])return{dryRun:!0,all:!0,targetRoot:o,skills:n};let i=n.filter(({replace:s})=>s);if(i.length&&!t.force){let s=new Error(`Skills already exist: ${i.map(({name:a})=>a).join(", ")}.`);throw s.code="skill_exists",s.hint="Inspect the existing skills or re-run with --all --force --yes to replace the complete set.",s}return y(t,`${i.length?"Replacing":"Installing"} all LixBlogs skills in ${o}`),await Promise.all(n.map(({name:s,target:a})=>Nt(b.join(e,s),a,{recursive:!0,force:!!t.force}))),{installed:!0,all:!0,targetRoot:o,skills:n.map(({name:s,target:a})=>({name:s,target:a}))}}import{writeFile as Zr}from"node:fs/promises";var Qr=new Set(["overview","timeline","posts","sources","devices","countries"]),eo=new Set(["7d","30d","90d","12m","custom"]);function Wt(t={}){let e=t.dimension||"overview",r=t.range||(t.from||t.to?"custom":"30d");if(!Qr.has(e))throw new Error(`Unsupported analytics dimension: ${e}.`);if(!eo.has(r))throw new Error(`Unsupported analytics range: ${r}.`);if(r==="custom"&&(!t.from||!t.to))throw new Error("Custom analytics ranges require --from and --to.");return{scope:t.scope?.[0]||t.publication||"personal",range:r,from:t.from,to:t.to,dimension:e,limit:t.limit,cursor:t.cursor}}async function Kt({client:t,options:e}){return t.query(Wt(e))}function Jt(t){let e=t==null?"":typeof t=="object"?JSON.stringify(t):String(t);return/[",\n]/.test(e)?`"${e.replaceAll('"','""')}"`:e}function Ht(t){let e=t?.data?.values;return Array.isArray(e)?e:e?.labels&&Array.isArray(e.labels)?e.labels.map((r,o)=>({label:r,views:e.views?.[o]||0,reads:e.reads?.[o]||0})):e?.totals?Object.entries(e.totals).map(([r,o])=>({metric:r,value:o,previous:e.previous?.[r],change:e.changes?.[r]})):[]}async function Xt({client:t,options:e}){if(!e.output)throw new Error("Analytics export requires --output <file>.");let r=e.format||"json";if(!["json","csv"].includes(r))throw new Error("Analytics export format must be json or csv.");let o=await t.query(Wt(e)),n;if(r==="json")n=`${JSON.stringify(o,null,2)}
16
- `;else{let i=Ht(o),s=[...new Set(i.flatMap(a=>Object.keys(a)))];n=`${s.map(Jt).join(",")}
17
- ${i.map(a=>s.map(l=>Jt(a[l])).join(",")).join(`
15
+ `)}import{promises as X}from"node:fs";import{tmpdir as Jr}from"node:os";import $e from"node:path";import{spawn as Hr}from"node:child_process";async function Kr(t){let e="";t.setEncoding("utf8");for await(let r of t)e+=r;return e}async function Xr(t="",e=process.env.EDITOR||process.env.VISUAL){if(!e)throw new Error("$EDITOR or $VISUAL must be set when using --editor.");let r=await X.mkdtemp($e.join(Jr(),"lixblogs-")),o=$e.join(r,"post.md");await X.writeFile(o,t,{mode:384});try{return await new Promise((n,i)=>{let s=Hr(e,[o],{stdio:"inherit",shell:!0});s.once("error",i),s.once("exit",a=>a===0?n():i(new Error(`Editor exited with code ${a}.`)))}),await X.readFile(o,"utf8")}finally{await X.rm(r,{recursive:!0,force:!0})}}async function qe(t,{stdin:e=process.stdin,initial:r=""}={}){let o=[t.file!==void 0,t.stdin,t.content!==void 0,t.editor].filter(Boolean).length;if(o>1)throw new Error("Use only one of --file, --stdin, --content, or --editor.");if(!o)return null;let n;return t.file!==void 0?n=await X.readFile($e.resolve(t.file),"utf8"):t.stdin?n=await Kr(e):t.content!==void 0?n=t.content:n=await Xr(r),{markdown:n,blocks:mt(n)}}function Ae(t){let e={},r={title:"title",subtitle:"subtitle",slug:"slug",emoji:"emoji",publication:"publishedAs",collection:"collectionId",cover:"coverUrl"};for(let[o,n]of Object.entries(r))t[o]!==void 0&&(e[n]=t[o]);return t.tag!==void 0&&(e.tags=t.tag),t["member-only"]&&(e.memberOnly=!0),t["no-member-only"]&&(e.memberOnly=!1),t.secret&&(e.secret=!0),t["not-secret"]&&(e.secret=!1),t["allow-comments"]&&(e.allowComments=!0),t["no-comments"]&&(e.allowComments=!1),(t["cover-x"]!==void 0||t["cover-y"]!==void 0)&&(e.coverPosition={x:Number(t["cover-x"]??50),y:Number(t["cover-y"]??50)}),t["cover-zoom"]!==void 0&&(e.coverZoom=Number(t["cover-zoom"])),e}function Wr(t){let e=[],r=o=>{for(let n of o||[]){for(let i of n?.content||[]){let s=typeof i=="string"?i:i?.text||"";e.push(...s.trim().split(/\s+/).filter(Boolean))}n?.children&&r(n.children)}};return r(t),e.length}function me(t,{publishing:e=!1}={}){if(t.title!==void 0&&(typeof t.title!="string"||t.title.length>300))throw new Error("Title must be 300 characters or fewer.");if(t.subtitle!==void 0&&(typeof t.subtitle!="string"||t.subtitle.length>500))throw new Error("Subtitle must be 500 characters or fewer.");if(t.tags!==void 0&&(!Array.isArray(t.tags)||t.tags.length>5))throw new Error("Use at most five tags.");if(t.coverUrl&&!/^https:\/\//i.test(t.coverUrl))throw new Error("Cover URLs must use HTTPS.");if(t.publishedAs&&t.publishedAs!=="personal"&&!/^org:[^:]+$/.test(t.publishedAs))throw new Error("Publication must be personal or org:<id>.");if(t.content!==void 0){if(!Array.isArray(t.content))throw new Error("Blog content must be a block array.");if(Buffer.byteLength(JSON.stringify(t.content),"utf8")>15e5)throw new Error("Blog content exceeds the 1.5 MB limit.")}if(e){if(!t.title?.trim())throw new Error("A title is required before publishing.");if(Wr(t.content)<20)throw new Error("A post needs at least 20 words before publishing.")}return t}import{promises as Te}from"node:fs";import Re from"node:path";var Yr=new Set(["create","edit","publish","unpublish","delete","trash","restore","restore-version"]);async function yt({client:t,action:e,result:r}){if(!Yr.has(e)||r?.dryRun||!r?.id||r.url&&r.status)return r;try{let o=await t.get(r.id);return{...r,status:o.status||r.status,url:o.url||r.url}}catch{return r}}async function wt({client:t,options:e}){return t.list({status:e.status,limit:e.limit,cursor:e.cursor})}async function Oe({client:t,id:e}){if(!e)throw new Error("A blog ID is required.");let r=await t.get(e);return{...r,markdown:K(r.content)}}async function bt({client:t,options:e,stdin:r}){let o=await qe(e,{stdin:r}),n={...Ae(e),content:o?.blocks||[]};return me(n),e["dry-run"]?{dryRun:!0,input:n,markdown:o?.markdown||""}:t.create(n,{idempotencyKey:e["idempotency-key"]})}async function vt({client:t,id:e,options:r,stdin:o}){if(!e)throw new Error("A blog ID is required.");let n=await t.get(e),i=await qe(r,{stdin:o,initial:K(n.content)}),s={...Ae(r),...i?{content:i.blocks}:{}};if(!Object.keys(s).length)throw new Error("No blog changes were provided.");if(me(s),r["dry-run"])return{dryRun:!0,id:e,etag:n.etag,input:s,markdown:i?.markdown};try{return await t.update(e,s,{etag:r.etag||n.etag})}catch(a){if(!(a instanceof m)||a.code!=="revision_conflict")throw a;let l=await t.get(e),c=r.conflictDirectory||Re.resolve(".lixblogs-conflicts");await Te.mkdir(c,{recursive:!0});let h=e.replace(/[^A-Za-z0-9._-]/g,"_"),u=Re.join(c,`${h}-local.json`),w=Re.join(c,`${h}-server.md`);throw await Promise.all([Te.writeFile(u,JSON.stringify(s,null,2),{mode:384}),Te.writeFile(w,K(l.content),{mode:384})]),a.details={...a.details,localPath:u,serverPath:w,serverEtag:l.etag},a}}async function xt({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);me(o,{publishing:!0});let n=r.status||"published";if(!["published","unlisted"].includes(n))throw new Error("--status must be published or unlisted.");return r["dry-run"]?{dryRun:!0,id:e,from:o.status,to:n}:(g(r,"Publishing this blog"),t.publish(e,{etag:r.etag||o.etag,status:n,idempotencyKey:r["idempotency-key"]}))}async function _t({client:t,id:e,options:r={}}){if(!e)throw new Error("A blog ID is required.");if(r.version){let o=await t.version(e,r.version);return{...o,markdown:K(o.content)}}return{data:await t.versions(e)}}async function kt({client:t,id:e,options:r}){if(!e||!r.version)throw new Error("A blog ID and --version are required.");g(r,"Restoring this historical version");let o=await t.get(e);return t.restoreVersion(e,r.version,{etag:r.etag||o.etag})}async function It({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);return r["dry-run"]?{dryRun:!0,id:e,from:o.status,to:"draft"}:(g(r,"Unpublishing this blog"),t.unpublish(e,{etag:r.etag||o.etag}))}async function Pe({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");if(!r.yes)throw new Error("Deletion requires --yes. Trash is the default; add --permanent for irreversible deletion.");let o=await t.get(e);if(r["dry-run"])return{dryRun:!0,id:e,permanent:r.permanent};let n=await t.delete(e,{etag:r.etag||o.etag,permanent:r.permanent});return{...n,status:r.permanent?"deleted":"trashed",url:o.url||n.url}}async function Et({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");let o=await t.get(e);return r["dry-run"]?{dryRun:!0,id:e,restoreTo:o.preDeleteStatus||"draft"}:(g(r,"Restoring this blog"),t.restore(e,{etag:r.etag||o.etag}))}var Zr={create:"Blog created",edit:"Blog updated",publish:"Blog published",unpublish:"Blog unpublished",delete:"Blog deleted",trash:"Blog moved to trash",restore:"Blog restored","restore-version":"Blog version restored"};function St(t,e){let r=t==="delete"&&e?.status==="trashed"?"Blog moved to trash":Zr[t]||"Blog updated",o=e?.status?` [${e.status}]`:"",n=e?.url?` ${e.url}`:"";return`${r}${o}${n}`}function $t(t,e,r){if(t==="delete")return`Media ${e.id} deleted.`;let o=t==="generate"?"generated":"uploaded";return e.blog?`Image ${o} and attached to blog ${r}.`:`Image ${o} and stored.`}async function qt({client:t}){return t.list()}async function At({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.get(e)}async function Tt({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.collections(e)}async function Rt({client:t,id:e}){if(!e)throw new Error("An organization ID or handle is required.");return t.members(e)}async function Ot({client:t}){return t.targets()}function M(t){if(!t)throw new Error("A blog ID is required.")}async function Pt({client:t,id:e}){return M(e),t.list(e)}async function Lt({client:t}){return t.invitations()}async function jt({client:t,id:e,options:r}){if(M(e),!r.user)throw new Error("--user is required.");if(!["viewer","editor","admin"].includes(r.role))throw new Error("--role must be viewer, editor, or admin.");return r["dry-run"]?{dryRun:!0,action:"invite",blogId:e,user:r.user,role:r.role}:(g(r,"Inviting this collaborator"),t.invite(e,{user:r.user,role:r.role,idempotencyKey:r["idempotency-key"]}))}async function Ct({client:t,id:e,options:r}){if(M(e),!r.user)throw new Error("--user is required.");if(!["viewer","editor","admin"].includes(r.role))throw new Error("--role must be viewer, editor, or admin.");return r["dry-run"]?{dryRun:!0,action:"role",blogId:e,user:r.user,role:r.role}:(g(r,"Changing this collaborator role"),t.role(e,{user:r.user,role:r.role,idempotencyKey:r["idempotency-key"]}))}async function Ut({client:t,id:e,options:r}){return M(e),r["dry-run"]?{dryRun:!0,action:"remove",blogId:e,user:r.user||"self"}:(g(r,"Removing this collaborator or invitation"),t.remove(e,{user:r.user,idempotencyKey:r["idempotency-key"]}))}async function Dt({client:t,id:e,options:r}){return M(e),r["dry-run"]?{dryRun:!0,action:"accept",blogId:e,showOnProfile:!r["hide-on-profile"]}:(g(r,"Accepting this collaboration invitation"),t.resolveInvitation(e,{action:"accept",showOnProfile:!r["hide-on-profile"],idempotencyKey:r["idempotency-key"]}))}async function Nt({client:t,id:e,options:r}){return M(e),r["dry-run"]?{dryRun:!0,action:"decline",blogId:e}:(g(r,"Declining this collaboration invitation"),t.resolveInvitation(e,{action:"decline",idempotencyKey:r["idempotency-key"]}))}import{access as Qr,cp as Ft,readFile as eo,readdir as to}from"node:fs/promises";import b from"node:path";import{fileURLToPath as ro}from"node:url";var Le=b.dirname(ro(import.meta.url)),zt=b.basename(Le)==="dist"?b.resolve(Le,".."):b.resolve(Le,"../../.."),Bt=b.join(zt,"skills"),Mt=b.resolve(zt,"../..",".agents","skills");async function C(t){try{return await Qr(t),!0}catch{return!1}}async function ge(){if(await C(Bt))return Bt;if(await C(Mt))return Mt;let t=new Error("No bundled LixBlogs skills were found. Reinstall @elixpo/lixblogs-cli.");throw t.code="skills_unavailable",t}function Gt(t){if(!/^lixblogs-[a-z0-9-]+$/.test(t||"")){let e=new Error("A valid lixblogs-* skill name is required.");throw e.code="invalid_skill_name",e}return t}async function Vt(t,e){let r=await eo(b.join(t,e,"SKILL.md"),"utf8"),o=r.match(/^description:\s*(.+)$/m)?.[1]||r.match(/^description:\s*>-\s*\n\s*(.+)$/m)?.[1]||"",n=r.match(/`@elixpo\/lixblogs-cli`\s+([0-9.]+)/)?.[1]||null;return{name:e,description:o.trim(),minimumCliVersion:n,content:r}}async function je(){let t=await ge(),e=await to(t,{withFileTypes:!0});return Promise.all(e.filter(r=>r.isDirectory()&&r.name.startsWith("lixblogs-")).map(r=>Vt(t,r.name))).then(r=>r.map(({content:o,...n})=>n).sort((o,n)=>o.name.localeCompare(n.name)))}async function Jt({name:t}){let e=await ge(),r=Gt(t);if(!await C(b.join(e,r,"SKILL.md"))){let o=new Error(`Skill "${r}" is not bundled.`);throw o.code="skill_not_found",o}return Vt(e,r)}async function Ht({name:t,options:e}){let r=await ge(),o=Gt(t),n=b.join(r,o);if(!await C(b.join(n,"SKILL.md"))){let a=new Error(`Skill "${o}" is not bundled.`);throw a.code="skill_not_found",a}let i=b.resolve(e.target||".agents/skills"),s=b.join(i,o);if(e["dry-run"])return{dryRun:!0,name:o,target:s,replace:await C(s)};if(await C(s)){if(!e.force){let a=new Error(`Skill already exists at ${s}.`);throw a.code="skill_exists",a.hint="Inspect the existing skill or re-run with --force --yes to replace it.",a}g(e,`Replacing ${s}`)}else g(e,`Installing ${o} into ${i}`);return await Ft(n,s,{recursive:!0,force:!!e.force}),{installed:!0,name:o,target:s}}async function Kt({options:t}){let e=await ge(),r=await je(),o=b.resolve(t.target||".agents/skills"),n=await Promise.all(r.map(async({name:s})=>{let a=b.join(o,s);return{name:s,target:a,replace:await C(a)}}));if(t["dry-run"])return{dryRun:!0,all:!0,targetRoot:o,skills:n};let i=n.filter(({replace:s})=>s);if(i.length&&!t.force){let s=new Error(`Skills already exist: ${i.map(({name:a})=>a).join(", ")}.`);throw s.code="skill_exists",s.hint="Inspect the existing skills or re-run with --all --force --yes to replace the complete set.",s}return g(t,`${i.length?"Replacing":"Installing"} all LixBlogs skills in ${o}`),await Promise.all(n.map(({name:s,target:a})=>Ft(b.join(e,s),a,{recursive:!0,force:!!t.force}))),{installed:!0,all:!0,targetRoot:o,skills:n.map(({name:s,target:a})=>({name:s,target:a}))}}import{writeFile as oo}from"node:fs/promises";var no=new Set(["overview","timeline","posts","sources","devices","countries"]),io=new Set(["7d","30d","90d","12m","custom"]);function Yt(t={}){let e=t.dimension||"overview",r=t.range||(t.from||t.to?"custom":"30d");if(!no.has(e))throw new Error(`Unsupported analytics dimension: ${e}.`);if(!io.has(r))throw new Error(`Unsupported analytics range: ${r}.`);if(r==="custom"&&(!t.from||!t.to))throw new Error("Custom analytics ranges require --from and --to.");return{scope:t.scope?.[0]||t.publication||"personal",range:r,from:t.from,to:t.to,dimension:e,limit:t.limit,cursor:t.cursor}}async function Zt({client:t,options:e}){return t.query(Yt(e))}function Xt(t){let e=t==null?"":typeof t=="object"?JSON.stringify(t):String(t);return/[",\n]/.test(e)?`"${e.replaceAll('"','""')}"`:e}function Wt(t){let e=t?.data?.values;return Array.isArray(e)?e:e?.labels&&Array.isArray(e.labels)?e.labels.map((r,o)=>({label:r,views:e.views?.[o]||0,reads:e.reads?.[o]||0})):e?.totals?Object.entries(e.totals).map(([r,o])=>({metric:r,value:o,previous:e.previous?.[r],change:e.changes?.[r]})):[]}async function Qt({client:t,options:e}){if(!e.output)throw new Error("Analytics export requires --output <file>.");let r=e.format||"json";if(!["json","csv"].includes(r))throw new Error("Analytics export format must be json or csv.");let o=await t.query(Yt(e)),n;if(r==="json")n=`${JSON.stringify(o,null,2)}
16
+ `;else{let i=Wt(o),s=[...new Set(i.flatMap(a=>Object.keys(a)))];n=`${s.map(Xt).join(",")}
17
+ ${i.map(a=>s.map(l=>Xt(a[l])).join(",")).join(`
18
18
  `)}
19
- `}return await Zr(e.output,n,{encoding:"utf8",flag:"wx"}),{output:e.output,format:r,rows:Ht(o).length}}async function Yt({integrationsClient:t,confirmed:e}){if(e!==!0)return{ok:!1,reason:"Disconnect was not confirmed. This is a destructive action and requires explicit confirmation (interactive prompt, or --yes in a non-interactive session)."};try{return{ok:!0,data:await t.cloudinaryDisconnect()}}catch(r){return{ok:!1,error:r}}}async function Zt({integrationsClient:t}){try{return{ok:!0,data:await t.cloudinaryStatus()}}catch(e){return{ok:!1,error:e}}}import{randomUUID as Qt}from"node:crypto";import{promises as je}from"node:fs";import z from"node:path";function to(t){let e=r=>t[r]===void 0?void 0:Number.parseInt(t[r],10);return{width:e("width"),height:e("height"),seed:e("seed")}}var er=Object.freeze({".avif":"image/avif",".bmp":"image/bmp",".jpeg":"image/jpeg",".jpg":"image/jpeg",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"});async function tr({blogClient:t,blogId:e,media:r,type:o,caption:n}){if(!e)return null;for(let i=0;i<3;i+=1){let s=await t.get(e),a=o==="cover"?{coverUrl:r.url}:{content:[...s.content||[],{id:Qt(),type:"image",props:{url:r.url,caption:n||"",_mediaId:r.id||""},content:[],children:[]}]};try{return await t.update(e,a,{etag:s.etag})}catch(l){if(!(l instanceof h&&l.code==="revision_conflict")||i===2)throw l}}return null}async function rr({mediaClient:t,blogClient:e,options:r}){let o=r.prompt?.trim();if(!o)throw new Error("--prompt is required.");let n=r.type||"inline";if(!["inline","cover"].includes(n))throw new Error("--type must be inline or cover.");let i;if(r.reference){let c=z.resolve(r.reference),f=z.extname(c).toLowerCase(),k=er[f];if(!k)throw new Error("Unsupported reference image type. Use AVIF, BMP, JPEG, PNG, SVG, or WebP.");i={bytes:await je.readFile(c),mimeType:k,name:z.basename(c)}}let s=await t.generate({prompt:o,model:r.model||"flux",destination:n,reference:i,...to(r)}),a=s.mimeType.includes("png")?"png":s.mimeType.includes("webp")?"webp":"jpg",l=z.resolve(r.output||`lixblogs-${s.generationId}.${a}`);await je.writeFile(l,s.bytes,{mode:384});let u=null,d=null;return r.blog&&(u=await t.upload({bytes:s.bytes,mimeType:s.mimeType,blogId:r.blog,mediaType:n,uploadId:s.generationId}),r.attach&&(d=await tr({blogClient:e,blogId:r.blog,media:u,type:n,caption:r.caption}))),{generationId:s.generationId,output:l,mimeType:s.mimeType,media:u,blog:d}}async function or({mediaClient:t,blogClient:e,options:r}){if(!r.file)throw new Error("--file is required.");if(!r.blog)throw new Error("--blog is required.");let o=r.type||"inline",n=z.resolve(r.file),i=await je.readFile(n),s=z.extname(n).toLowerCase(),a=er[s];if(!a)throw new Error("Unsupported image type. Use AVIF, BMP, JPEG, PNG, SVG, or WebP.");let l=await t.upload({bytes:i,mimeType:a,blogId:r.blog,mediaType:o,uploadId:r["upload-id"]||Qt()}),u=r.attach?await tr({blogClient:e,blogId:r.blog,media:l,type:o,caption:r.caption}):null;return{media:l,blog:u}}async function nr({mediaClient:t,id:e,options:r}){if(!e)throw new Error("A media ID is required.");y(r,"Deleting this media asset from its storage provider");let o=await t.delete(e);return o?.data||o}async function ir({client:t,id:e}){if(!e)throw new Error("A blog ID is required.");return t.comments(e)}async function sr({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");if(!r.content?.trim())throw new Error("--content is required.");return t.comment(e,r.content.trim())}async function ar({client:t,id:e,options:r}){if(!e||!r.parent)throw new Error("A blog ID and --parent comment ID are required.");if(!r.content?.trim())throw new Error("--content is required.");return t.comment(e,r.content.trim(),{parentId:r.parent})}async function lr({client:t,id:e,options:r}){if(!e||!r.comment)throw new Error("A blog ID and --comment ID are required.");return y(r,"Deleting this comment"),t.deleteComment(e,r.comment)}var no={profile:{type:"string"},env:{type:"string"},json:{type:"boolean",default:!1},quiet:{type:"boolean",default:!1},yes:{type:"boolean",short:"y",default:!1},"allow-insecure-fallback":{type:"boolean",default:!1},"auth-provider":{type:"string"},"accounts-url":{type:"string"},"api-url":{type:"string"},"client-id":{type:"string"},audience:{type:"string"},scope:{type:"string",multiple:!0},open:{type:"boolean",default:!1},status:{type:"string"},limit:{type:"string"},cursor:{type:"string"},range:{type:"string"},from:{type:"string"},to:{type:"string"},dimension:{type:"string"},format:{type:"string"},output:{type:"string"},file:{type:"string"},stdin:{type:"boolean",default:!1},content:{type:"string"},editor:{type:"boolean",default:!1},title:{type:"string"},subtitle:{type:"string"},slug:{type:"string"},tag:{type:"string",multiple:!0},emoji:{type:"string"},publication:{type:"string"},collection:{type:"string"},cover:{type:"string"},"member-only":{type:"boolean",default:!1},"no-member-only":{type:"boolean",default:!1},secret:{type:"boolean",default:!1},"not-secret":{type:"boolean",default:!1},"dry-run":{type:"boolean",default:!1},"no-input":{type:"boolean",default:!1},etag:{type:"string"},permanent:{type:"boolean",default:!1},"idempotency-key":{type:"string"},user:{type:"string"},role:{type:"string"},"hide-on-profile":{type:"boolean",default:!1},target:{type:"string"},force:{type:"boolean",default:!1},all:{type:"boolean",default:!1},prompt:{type:"string"},reference:{type:"string"},model:{type:"string"},seed:{type:"string"},width:{type:"string"},height:{type:"string"},blog:{type:"string"},type:{type:"string"},attach:{type:"boolean",default:!1},caption:{type:"string"},"upload-id":{type:"string"},version:{type:"string"},parent:{type:"string"},comment:{type:"string"},"allow-comments":{type:"boolean",default:!1},"no-comments":{type:"boolean",default:!1},"cover-x":{type:"string"},"cover-y":{type:"string"},"cover-zoom":{type:"string"},help:{type:"boolean",short:"h",default:!1}},io=`lixblogs \u2014 LixBlogs CLI
19
+ `}return await oo(e.output,n,{encoding:"utf8",flag:"wx"}),{output:e.output,format:r,rows:Wt(o).length}}async function er({integrationsClient:t,confirmed:e}){if(e!==!0)return{ok:!1,reason:"Disconnect was not confirmed. This is a destructive action and requires explicit confirmation (interactive prompt, or --yes in a non-interactive session)."};try{return{ok:!0,data:await t.cloudinaryDisconnect()}}catch(r){return{ok:!1,error:r}}}async function tr({integrationsClient:t}){try{return{ok:!0,data:await t.cloudinaryStatus()}}catch(e){return{ok:!1,error:e}}}import{randomUUID as rr}from"node:crypto";import{promises as Ce}from"node:fs";import F from"node:path";function so(t){let e=r=>t[r]===void 0?void 0:Number.parseInt(t[r],10);return{width:e("width"),height:e("height"),seed:e("seed")}}var or=Object.freeze({".avif":"image/avif",".bmp":"image/bmp",".jpeg":"image/jpeg",".jpg":"image/jpeg",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"});async function nr({blogClient:t,blogId:e,media:r,type:o,caption:n}){if(!e)return null;for(let i=0;i<3;i+=1){let s=await t.get(e),a=o==="cover"?{coverUrl:r.url}:{content:[...s.content||[],{id:rr(),type:"image",props:{url:r.url,caption:n||"",_mediaId:r.id||""},content:[],children:[]}]};try{return await t.update(e,a,{etag:s.etag})}catch(l){if(!(l instanceof m&&l.code==="revision_conflict")||i===2)throw l}}return null}async function ir({mediaClient:t,blogClient:e,options:r}){let o=r.prompt?.trim();if(!o)throw new Error("--prompt is required.");let n=r.type||"inline";if(!["inline","cover"].includes(n))throw new Error("--type must be inline or cover.");let i;if(r.reference){let u=F.resolve(r.reference),w=F.extname(u).toLowerCase(),E=or[w];if(!E)throw new Error("Unsupported reference image type. Use AVIF, BMP, JPEG, PNG, SVG, or WebP.");i={bytes:await Ce.readFile(u),mimeType:E,name:F.basename(u)}}let s=await t.generate({prompt:o,model:r.model||"flux",destination:n,reference:i,...so(r)}),a=s.mimeType.includes("png")?"png":s.mimeType.includes("webp")?"webp":"jpg",l=F.resolve(r.output||`lixblogs-${s.generationId}.${a}`);await Ce.writeFile(l,s.bytes,{mode:384});let c=null,h=null;return r.blog&&(c=await t.upload({bytes:s.bytes,mimeType:s.mimeType,blogId:r.blog,mediaType:n,uploadId:s.generationId}),r.attach&&(h=await nr({blogClient:e,blogId:r.blog,media:c,type:n,caption:r.caption}))),{generationId:s.generationId,output:l,mimeType:s.mimeType,media:c,blog:h}}async function sr({mediaClient:t,blogClient:e,options:r}){if(!r.file)throw new Error("--file is required.");if(!r.blog)throw new Error("--blog is required.");let o=r.type||"inline",n=F.resolve(r.file),i=await Ce.readFile(n),s=F.extname(n).toLowerCase(),a=or[s];if(!a)throw new Error("Unsupported image type. Use AVIF, BMP, JPEG, PNG, SVG, or WebP.");let l=await t.upload({bytes:i,mimeType:a,blogId:r.blog,mediaType:o,uploadId:r["upload-id"]||rr()}),c=r.attach?await nr({blogClient:e,blogId:r.blog,media:l,type:o,caption:r.caption}):null;return{media:l,blog:c}}async function ar({mediaClient:t,id:e,options:r}){if(!e)throw new Error("A media ID is required.");g(r,"Deleting this media asset from its storage provider");let o=await t.delete(e);return o?.data||o}async function lr({client:t,id:e}){if(!e)throw new Error("A blog ID is required.");return t.comments(e)}async function cr({client:t,id:e,options:r}){if(!e)throw new Error("A blog ID is required.");if(!r.content?.trim())throw new Error("--content is required.");return t.comment(e,r.content.trim())}async function ur({client:t,id:e,options:r}){if(!e||!r.parent)throw new Error("A blog ID and --parent comment ID are required.");if(!r.content?.trim())throw new Error("--content is required.");return t.comment(e,r.content.trim(),{parentId:r.parent})}async function dr({client:t,id:e,options:r}){if(!e||!r.comment)throw new Error("A blog ID and --comment ID are required.");return g(r,"Deleting this comment"),t.deleteComment(e,r.comment)}var co={profile:{type:"string"},env:{type:"string"},json:{type:"boolean",default:!1},quiet:{type:"boolean",default:!1},yes:{type:"boolean",short:"y",default:!1},"allow-insecure-fallback":{type:"boolean",default:!1},"auth-provider":{type:"string"},"accounts-url":{type:"string"},"api-url":{type:"string"},"token-file":{type:"string"},"client-id":{type:"string"},audience:{type:"string"},scope:{type:"string",multiple:!0},open:{type:"boolean",default:!1},status:{type:"string"},limit:{type:"string"},cursor:{type:"string"},range:{type:"string"},from:{type:"string"},to:{type:"string"},dimension:{type:"string"},format:{type:"string"},output:{type:"string"},file:{type:"string"},stdin:{type:"boolean",default:!1},content:{type:"string"},editor:{type:"boolean",default:!1},title:{type:"string"},subtitle:{type:"string"},slug:{type:"string"},tag:{type:"string",multiple:!0},emoji:{type:"string"},publication:{type:"string"},collection:{type:"string"},cover:{type:"string"},"member-only":{type:"boolean",default:!1},"no-member-only":{type:"boolean",default:!1},secret:{type:"boolean",default:!1},"not-secret":{type:"boolean",default:!1},"dry-run":{type:"boolean",default:!1},"no-input":{type:"boolean",default:!1},etag:{type:"string"},permanent:{type:"boolean",default:!1},"idempotency-key":{type:"string"},user:{type:"string"},role:{type:"string"},"hide-on-profile":{type:"boolean",default:!1},target:{type:"string"},force:{type:"boolean",default:!1},all:{type:"boolean",default:!1},prompt:{type:"string"},reference:{type:"string"},model:{type:"string"},seed:{type:"string"},width:{type:"string"},height:{type:"string"},blog:{type:"string"},type:{type:"string"},attach:{type:"boolean",default:!1},caption:{type:"string"},"upload-id":{type:"string"},version:{type:"string"},parent:{type:"string"},comment:{type:"string"},"allow-comments":{type:"boolean",default:!1},"no-comments":{type:"boolean",default:!1},"cover-x":{type:"string"},"cover-y":{type:"string"},"cover-zoom":{type:"string"},help:{type:"boolean",short:"h",default:!1}},uo=`lixblogs \u2014 LixBlogs CLI
20
20
 
21
21
  Usage:
22
22
  lixblogs login [--profile <name>] [--open]
@@ -81,6 +81,7 @@ Global flags:
81
81
  --auth-provider <provider> elixpo, or mock in development/test only
82
82
  --accounts-url <url> override the Accounts discovery origin
83
83
  --api-url <url> LixBlogs API origin (default: https://blogs.elixpo.com)
84
+ --token-file <path> read a personal access token from a file
84
85
  --scope <scope> request an OAuth scope (repeatable)
85
86
  --file <path> read blog Markdown from a file
86
87
  --stdin read blog Markdown from stdin
@@ -103,17 +104,18 @@ Global flags:
103
104
  Machine mode:
104
105
  --json --no-input produces stable JSON on stdout, diagnostics on stderr, and
105
106
  never prompts. Publishing and destructive state changes require --yes.
106
- `,so=["openid","profile","email","lixblogs:profile:read","lixblogs:profile:write","lixblogs:blog:read","lixblogs:blog:write","lixblogs:blog:publish","lixblogs:blog:delete","lixblogs:media:read","lixblogs:media:write","lixblogs:organizations:read","lixblogs:organizations:write","lixblogs:collaboration:read","lixblogs:collaboration:write","lixblogs:analytics:read","lixblogs:notifications:read"];function O(t){return{profile:t.profile,env:t.env,authProvider:t["auth-provider"],accountsUrl:t["accounts-url"],apiUrl:t["api-url"],clientId:t["client-id"],audience:t.audience}}async function V(t,e){return t.profileExplicit?$(t.profile):await e.getActive()||$(t.profile)}async function Ce(t){let e=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",r=process.platform==="win32"?["/c","start","",t]:[t],o=oo(e,r,{detached:!0,stdio:"ignore"});o.on("error",()=>{}),o.unref()}function w(t,e){t.json&&process.stdout.write(se(e)+`
107
- `)}function m(t,e,r=g.ERROR){let o=e&&typeof e=="object"?e:{message:String(e)},n=N(o.message),i=it({...o,message:n});if(t.json)process.stdout.write(se(i)+`
108
- `);else if(!t.quiet){let s=p(process.stderr);process.stderr.write(`${lt(n,s)}
109
- `),o.hint&&process.stderr.write(`${q(`Hint: ${o.hint}`,s)}
110
- `),o.requestId&&process.stderr.write(`${C(`Request: ${o.requestId}`,s)}
111
- `)}process.exitCode=o.exitCode||r}async function R(t,e){try{return await Je({allowInsecureFallback:t["allow-insecure-fallback"],profileRegistry:e})}catch(r){return m(t,`${r.message}${t["allow-insecure-fallback"]?"":" Re-run with --allow-insecure-fallback to opt in to non-persistent storage instead."}`),null}}async function ur(t){let e=S({flags:O(t)}),r=new v,o=$(e.profile),n=t.scope?.length?[...t.scope]:[...so];!e.profileExplicit&&!n.includes("lixblogs:profile:read")&&n.push("lixblogs:profile:read");let i;try{i=D(e)}catch(u){return m(t,u.message)}let s=await R(t,r);if(!s)return;let a=()=>{},l;try{l=await We({provider:i,credentialStore:s,profileId:o,scopes:n,openBrowser:t.open?Ce:void 0,resolveProfileId:e.profileExplicit?void 0:({accessToken:u})=>et({accessToken:u,apiBaseUrl:e.apiBaseUrl}),onStatus:u=>{if(t.json){u.type!=="pending"&&w(t,{event:u.type,...u});return}if(!t.quiet)if(u.type==="verification_pending"){let d=u.verificationUriComplete||u.verificationUri,c=!!process.stdin.isTTY&&!t["no-input"];process.stdout.write(at({url:d,code:u.userCode,expiresInSeconds:u.expiresInSeconds,profile:e.profileExplicit?o:null,interactive:c,color:p()})),c&&!t.open&&(a=ct({input:process.stdin,open:Ce,url:d}))}else u.type==="approved"?console.log(x("Access approved by Elixpo Accounts.",p())):u.type==="denied"?console.log(q("Access denied.",p())):u.type==="expired"&&console.log(q("Device code expired.",p()))}})}finally{a()}if(!l.ok)return m(t,l.reason);await r.add(l.profileId),await r.setActive(l.profileId),w(t,{ok:!0,profile:l.profileId}),!t.json&&!t.quiet&&(console.log(x(`Credentials saved to local profile "${l.profileId}".`,p())),console.log(C("Add another account with `lixblogs login`; switch with `lixblogs use <username>`.",p())))}async function ao(t){let e=S({flags:O(t)}),r=new v,o=await V(e,r),n=await R(t,r);if(!n)return;let i=await Ke({credentialStore:n,profileId:o});if(w(t,i),!t.json)for(let s of i)s.loggedIn?console.log(`${s.profileId}: logged in${s.expired?" (expired)":""} \u2014 scopes: ${s.scopes.join(", ")}`):console.log(`${s.profileId}: not logged in`)}async function J(t){let e=S({flags:O(t)}),r=new v,o=await V(e,r),n=await R(t,r);if(!n)return null;let i;try{i=D(e)}catch(a){return m(t,a),null}let s=new B({provider:i,credentialStore:n,profileId:o,apiBaseUrl:e.apiBaseUrl});return{client:new W(s),http:s,config:e,credentialStore:n,profileId:o}}async function lo(t){let e=await J(t);if(e)try{let[r,o]=await A(t,"Loading account\u2026",()=>Promise.all([e.client.whoami(),e.credentialStore.get(e.profileId)])),n={ok:!0,profile:e.profileId,environment:e.config.environment,identity:r,scopes:o?.scopes||[],expiresAt:o?.expiresAt?new Date(o.expiresAt).toISOString():null,expired:o?Date.now()>=o.expiresAt:!0};w(t,n),!t.json&&!t.quiet&&(console.log(`${r.displayName||r.username} (@${r.username})`),console.log(`Profile: ${e.profileId} \xB7 ${n.environment}`),console.log(`Scopes: ${n.scopes.join(", ")||"none"}`),console.log(`Expires: ${n.expiresAt||"unknown"}`))}catch(r){m(t,r,r.status===401||r.status===403?g.AUTH:g.ERROR)}}async function co(t){let e=S({flags:O(t)}),r=new URL("/register",e.accountsBaseUrl).toString();if(t["no-input"]){w(t,{ok:!0,registrationUrl:r,next:"lixblogs login"}),!t.json&&!t.quiet&&console.log(r);return}await Ce(r),t.quiet||console.log(C(`Create your account at ${r}, then approve the device login.`,p())),await ur(t)}async function uo(t){let e=S({flags:O(t)}),r=new v,o=await V(e,r),n=await R(t,r);if(!n)return;let i=await Xe({credentialStore:n,profileId:o});w(t,i),!t.json&&!t.quiet&&console.log(x(`Logged out profile "${o}".`,p()))}async function po(t){let e=S({flags:O(t)}),r=new v,o=await V(e,r);if(!t.yes)return m(t,"This is a destructive action. Re-run with --yes to confirm (interactive confirmation prompt not yet implemented).");let n;try{n=D(e)}catch(a){return m(t,a.message)}let i=await R(t,r);if(!i)return;let s=await Ye({provider:n,credentialStore:i,profileId:o,confirmed:!0});if(!s.ok)return m(t,s.reason);w(t,s),!t.json&&!t.quiet&&console.log(x(`Revoked and logged out profile "${o}".`,p()))}async function G(t,e,r){let o=S({flags:O(t)}),n=new v,i=await V(o,n);if((r==="cloudinary-disconnect"||r==="pollinations-disconnect")&&!t.yes)return m(t,"This is a destructive action. Re-run with --yes to confirm (interactive confirmation prompt not yet implemented).");let s;try{s=D(o)}catch(c){return m(t,c.message)}let a=await R(t,n);if(!a)return;let l=new B({provider:s,credentialStore:a,profileId:i,apiBaseUrl:o.apiBaseUrl}),u=new pe(l),d=await A(t,r.endsWith("status")?"Checking integration\u2026":"Disconnecting integration\u2026",async()=>{if(r==="cloudinary-status")return Zt({integrationsClient:u});if(r==="cloudinary-disconnect")return Yt({integrationsClient:u,confirmed:!0});try{return{ok:!0,data:r==="pollinations-status"?await u.pollinationsStatus({refresh:t.force}):await u.pollinationsDisconnect()}}catch(c){return{ok:!1,error:c}}});if(!d.ok)return m(t,d.error||d.reason);w(t,d),!t.json&&!t.quiet&&console.log(r==="cloudinary-status"?C(`Cloudinary: ${d.data.connected?`connected (${d.data.cloudName})`:"not connected"}`,p()):r==="pollinations-status"?C(`Pollinations: ${d.data.connected?`connected${d.data.handle?` as ${d.data.handle}`:""} \xB7 ${d.data.balance??"unknown"} Pollen`:`${d.data.status}. Connect at ${d.data.connectUrl||"https://blogs.elixpo.com/settings?tab=integrations"}`}`,p()):x(`${r.startsWith("pollinations")?"Pollinations":"Cloudinary"} connection disconnected.`,p()))}async function fo(t){let e=new v,r=await R(t,e);if(!r)return;let o=await Ze({credentialStore:r,profileRegistry:e});if(w(t,o),!t.json){o.profiles.length||console.log(q("No profiles. Run `lixblogs auth login` first.",p()));for(let n of o.profiles)console.log(`${n.active?"*":" "} ${n.profileId}${n.expired?" (expired)":""}`)}}async function mo(t,e){let r;try{r=$(e[0])}catch(s){return m(t,s.message)}let o=new v,n=await R(t,o);if(!n)return;let i=await Qe({credentialStore:n,profileRegistry:o,profileId:r});if(!i.ok)return m(t,i.reason);w(t,i),!t.json&&!t.quiet&&console.log(x(`Using profile "${r}".`,p()))}var dr={list:gt,get:Re,preview:Re,create:ht,edit:yt,publish:wt,unpublish:xt,delete:Pe,trash:Pe,restore:It,history:bt,"restore-version":vt},pr={list:kt,get:St,collections:$t,members:qt,targets:At},fr={list:Rt,invitations:Pt,invite:Tt,role:Ot,remove:jt,accept:Ct,decline:Lt},mr={list:({options:t})=>Oe(t),inspect:({id:t})=>zt({name:t}),install:({id:t,options:e})=>e.all?Vt({options:e}):Gt({name:t,options:e})},gr={query:Kt,export:Xt},hr={generate:rr,upload:or,delete:nr},yr={list:ir,add:sr,reply:ar,delete:lr};async function go(t,e,r){let o=S({flags:O(t)}),n=new v,i=await V(o,n),s=await R(t,n);if(!s)return;let a;try{a=D(o)}catch(c){return m(t,c.message)}let l=new B({provider:a,credentialStore:s,profileId:i,apiBaseUrl:o.apiBaseUrl}),u=new W(l),d={...t,limit:t.limit===void 0?void 0:Number.parseInt(t.limit,10)};try{let c=await A(t,`${r==="list"?"Loading":r==="get"||r==="preview"?"Opening":"Updating"} blog\u2026`,async()=>{let f=await dr[r]({client:u,id:e[0],options:d,stdin:process.stdin});return mt({client:u,action:r,result:f})});if(w(t,{ok:!0,...c}),!t.json&&!t.quiet)if(r==="list"){for(let f of c.data||[])console.log(`${f.id} ${f.status} ${f.title||"(untitled)"}`);c.meta?.nextCursor&&console.log(C(`Next cursor: ${c.meta.nextCursor}`,p()))}else if(r==="get"||r==="preview")console.log(`${c.title||"(untitled)"} [${c.status}]
112
- ${c.markdown||""}`);else if(r==="history")if(c.markdown!==void 0)console.log(`${c.id} ${c.label||"snapshot"} ${c.created_at} ${c.username||"system"}`),process.stdout.write(`${c.markdown}
113
- `);else for(let f of c.data||[])console.log(`${f.id} ${f.label||"snapshot"} ${f.created_at} ${f.word_count||0} words ${f.username||"system"} ${f.excerpt||""}`);else c.dryRun?console.log(q(`Dry run: ${r} validated; no changes sent.`,p())):console.log(x(_t(r,c),p()))}catch(c){if(t.json&&c instanceof h){process.stdout.write(se({ok:!1,error:{code:c.code,message:c.message,requestId:c.requestId,details:c.details}})+`
114
- `),process.exitCode=c.status===412?3:1;return}return m(t,c,c.status===412?g.CONFLICT:g.ERROR)}}async function ho(t,e,r){let o=await J(t);if(!o)return;let n=new le(o.http);try{let i=await A(t,"Loading organization\u2026",()=>pr[r]({client:n,id:e[0],options:t}));if(w(t,{ok:!0,data:i}),t.json||t.quiet)return;if(r==="targets"){console.log("personal Personal Blog");for(let a of i.organizations||[]){console.log(`${a.target} ${a.role} ${a.name}`);for(let l of a.collections||[])console.log(` collection:${l.id} ${l.name}`)}return}let s=r==="list"?i.data||[]:Array.isArray(i)?i:[i];for(let a of s)console.log([a.id||a.userId||a.orgId,a.role,a.slug||a.username,a.name||a.displayName].filter(Boolean).join(" "))}catch(i){m(t,i,i.status===401||i.status===403?g.AUTH:g.ERROR)}}async function yo(t,e,r){let o=await J(t);if(o)try{let i=await A(t,r==="generate"?"Generating image\u2026":r==="upload"?"Uploading image\u2026":"Deleting media\u2026",()=>hr[r]({mediaClient:new fe(o.http),blogClient:o.client,id:e[0],options:t}));w(t,{ok:!0,data:i}),!t.json&&!t.quiet&&console.log(x(Et(r,i,t.blog),p()))}catch(n){m(t,n,n.status===401||n.status===403?g.AUTH:g.ERROR)}}async function wo(t,e,r){let o=await J(t);if(o)try{let n=await A(t,r==="list"?"Loading comments\u2026":"Updating comments\u2026",()=>yr[r]({client:o.client,id:e[0],options:t}));if(w(t,{ok:!0,data:n}),!t.json&&!t.quiet)if(r==="list")for(let i of n)console.log(`${i.id} ${i.parent_id?"reply":"comment"} ${i.display_name||i.username||"Anonymous"} ${i.content}`);else console.log(x(`${r} completed for ${n.id}.`,p()))}catch(n){m(t,n,n.status===401||n.status===403?g.AUTH:g.ERROR)}}async function bo(t,e,r){let o=await J(t);if(!o)return;let n=new ue(o.http);try{let i=await A(t,"Updating collaborators\u2026",()=>fr[r]({client:n,id:e[0],options:t}));if(w(t,{ok:!0,data:i}),t.json||t.quiet)return;if(i.dryRun){console.log(q(`Dry run: ${i.action} validated; no changes sent.`,p()));return}if(r!=="list"&&r!=="invitations"){console.log(x(`${r} completed for ${i.blogId||i.userId||e[0]}.`,p()));return}let s=r==="invitations"?i:r==="list"?i.collaborators||[]:[i];for(let a of s)console.log([a.blogId||a.userId,a.status,a.role,a.username||a.title,a.notificationState].filter(Boolean).join(" "))}catch(i){m(t,i,i.status===401||i.status===403?g.AUTH:g.ERROR)}}async function vo(t,e,r){try{let o=await mr[r]({id:e[0],options:t});if(w(t,{ok:!0,data:o}),t.json||t.quiet)return;if(r==="list")for(let n of o)console.log(`${n.name} CLI >= ${n.minimumCliVersion||"unknown"} ${n.description}`);else r==="inspect"?process.stdout.write(o.content):o.dryRun&&o.all?console.log(q(`Dry run: install ${o.skills.length} skills to ${o.targetRoot}.`,p())):o.dryRun?console.log(q(`Dry run: install ${o.name} to ${o.target}${o.replace?" (replace)":""}.`,p())):o.all?console.log(x(`Installed ${o.skills.length} LixBlogs skills at ${o.targetRoot}.`,p())):console.log(x(`Installed ${o.name} at ${o.target}.`,p()))}catch(o){m(t,o)}}async function xo(t,e,r){let o=await J(t);if(!o)return;let n=new de(o.http),i={...t,limit:t.limit===void 0?void 0:Number.parseInt(t.limit,10)};try{let s=await A(t,r==="export"?"Exporting analytics\u2026":"Loading analytics\u2026",()=>gr[r]({client:n,options:i}));if(w(t,{ok:!0,data:s}),t.json||t.quiet)return;if(r==="export"){console.log(x(`Exported ${s.rows} rows to ${s.output}.`,p()));return}let a=s.data;if(console.log(`${a.scope.label} \xB7 ${a.dimension} \xB7 ${a.range.key}`),a.dimension==="overview")for(let[l,u]of Object.entries(a.values.totals))console.log(`${l} ${u} ${a.values.changes[l]}%`);else if(a.dimension==="timeline")a.values.labels.forEach((l,u)=>console.log(`${l} ${a.values.views[u]} ${a.values.reads[u]}`));else{for(let l of a.values)console.log(Object.values(l).join(" "));s.meta?.nextCursor&&console.log(`Next cursor: ${s.meta.nextCursor}`)}}catch(s){m(t,s,s.status===401||s.status===403?g.AUTH:g.ERROR)}}var cr={auth:{login:ur,status:ao,whoami:lo,logout:uo,revoke:po,profiles:fo,use:mo},blog:Object.fromEntries(Object.keys(dr).map(t=>[t,(e,r)=>go(e,r,t)])),org:Object.fromEntries(Object.keys(pr).map(t=>[t,(e,r)=>ho(e,r,t)])),collab:Object.fromEntries(Object.keys(fr).map(t=>[t,(e,r)=>bo(e,r,t)])),skill:Object.fromEntries(Object.keys(mr).map(t=>[t,(e,r)=>vo(e,r,t)])),analytics:Object.fromEntries(Object.keys(gr).map(t=>[t,(e,r)=>xo(e,r,t)])),media:Object.fromEntries(Object.keys(hr).map(t=>[t,(e,r)=>yo(e,r,t)])),comment:Object.fromEntries(Object.keys(yr).map(t=>[t,(e,r)=>wo(e,r,t)])),integrations:{"cloudinary-status":(t,e)=>G(t,e,"cloudinary-status"),"cloudinary-disconnect":(t,e)=>G(t,e,"cloudinary-disconnect"),"pollinations-status":(t,e)=>G(t,e,"pollinations-status"),"pollinations-disconnect":(t,e)=>G(t,e,"pollinations-disconnect")},disconnect:{cloudinary:(t,e)=>G(t,e,"cloudinary-disconnect"),pollinations:(t,e)=>G(t,e,"pollinations-disconnect")}};async function Io(){let t,e;try{({values:t,positionals:e}=ro({args:process.argv.slice(2),options:no,allowPositionals:!0,strict:!0}))}catch(s){process.stderr.write(`Error: Invalid flag. ${s.message}
115
- `),process.exitCode=g.USAGE;return}if(t.help||e.length===0){process.stdout.write(io);return}if(e[0]==="register"){await co(t);return}e=nt(e);let[r,o]=e,n=cr[r];if(!n){process.stderr.write(`Error: Unknown command category "${r}".
116
- `),process.stderr.write(`Available categories: ${Object.keys(cr).join(", ")}
117
- `),process.exitCode=g.USAGE;return}let i=n[o];if(!i){process.stderr.write(`Error: Unknown ${r} command "${o}".
107
+ Set LIXBLOGS_TOKEN or LIXBLOGS_TOKEN_FILE for non-interactive authentication.
108
+ `,po=["openid","profile","email","lixblogs:profile:read","lixblogs:profile:write","lixblogs:blog:read","lixblogs:blog:write","lixblogs:blog:publish","lixblogs:blog:delete","lixblogs:media:read","lixblogs:media:write","lixblogs:organizations:read","lixblogs:organizations:write","lixblogs:collaboration:read","lixblogs:collaboration:write","lixblogs:analytics:read","lixblogs:notifications:read"];function G(t){return{profile:t.profile,env:t.env,authProvider:t["auth-provider"],accountsUrl:t["accounts-url"],apiUrl:t["api-url"],clientId:t["client-id"],audience:t.audience}}async function he(t,e){return t.profileExplicit?S(t.profile):await e.getActive()||S(t.profile)}async function Ue(t){let e=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",r=process.platform==="win32"?["/c","start","",t]:[t],o=lo(e,r,{detached:!0,stdio:"ignore"});o.on("error",()=>{}),o.unref()}function y(t,e){t.json&&process.stdout.write(se(e)+`
109
+ `)}function f(t,e,r=p.ERROR){let o=e&&typeof e=="object"?e:{message:String(e)},n=N(o.message),i=lt({...o,message:n});if(t.json)process.stdout.write(se(i)+`
110
+ `);else if(!t.quiet){let s=d(process.stderr);process.stderr.write(`${dt(n,s)}
111
+ `),o.hint&&process.stderr.write(`${$(`Hint: ${o.hint}`,s)}
112
+ `),o.requestId&&process.stderr.write(`${j(`Request: ${o.requestId}`,s)}
113
+ `)}process.exitCode=o.exitCode||r}async function U(t,e){try{return await Ke({allowInsecureFallback:t["allow-insecure-fallback"],profileRegistry:e})}catch(r){return f(t,`${r.message}${t["allow-insecure-fallback"]?"":" Re-run with --allow-insecure-fallback to opt in to non-persistent storage instead."}`),null}}async function fr(t){let e=O({flags:G(t)}),r=new _,o=S(e.profile),n=t.scope?.length?[...t.scope]:[...po];!e.profileExplicit&&!n.includes("lixblogs:profile:read")&&n.push("lixblogs:profile:read");let i;try{i=ee(e)}catch(c){return f(t,c.message)}let s=await U(t,r);if(!s)return;let a=()=>{},l;try{l=await Ye({provider:i,credentialStore:s,profileId:o,scopes:n,openBrowser:t.open?Ue:void 0,resolveProfileId:e.profileExplicit?void 0:({accessToken:c})=>ot({accessToken:c,apiBaseUrl:e.apiBaseUrl}),onStatus:c=>{if(t.json){c.type!=="pending"&&y(t,{event:c.type,...c});return}if(!t.quiet)if(c.type==="verification_pending"){let h=c.verificationUriComplete||c.verificationUri,u=!!process.stdin.isTTY&&!t["no-input"];process.stdout.write(ut({url:h,code:c.userCode,expiresInSeconds:c.expiresInSeconds,profile:e.profileExplicit?o:null,interactive:u,color:d()})),u&&!t.open&&(a=pt({input:process.stdin,open:Ue,url:h}))}else c.type==="approved"?console.log(v("Access approved by Elixpo Accounts.",d())):c.type==="denied"?console.log($("Access denied.",d())):c.type==="expired"&&console.log($("Device code expired.",d()))}})}finally{a()}if(!l.ok)return f(t,l.reason);await r.add(l.profileId),await r.setActive(l.profileId),y(t,{ok:!0,profile:l.profileId}),!t.json&&!t.quiet&&(console.log(v(`Credentials saved to local profile "${l.profileId}".`,d())),console.log(j("Add another account with `lixblogs login`; switch with `lixblogs use <username>`.",d())))}async function fo(t){let e=O({flags:G(t)}),r=new _,o=await he(e,r),n=await U(t,r);if(!n)return;let i=await Ze({credentialStore:n,profileId:o});if(y(t,i),!t.json)for(let s of i)s.loggedIn?console.log(`${s.profileId}: logged in${s.expired?" (expired)":""} \u2014 scopes: ${s.scopes.join(", ")}`):console.log(`${s.profileId}: not logged in`)}async function R(t){let e=O({flags:G(t)}),r;try{r=await Xe({flags:{tokenFile:t["token-file"]}})}catch(l){return f(t,l,p.AUTH),null}if(r){let l=new J({accessToken:r.token,apiBaseUrl:e.apiBaseUrl});return{client:new H(l),http:l,config:e,credentialStore:null,profileId:null,credentialSource:r.source}}let o=new _,n=await he(e,o),i=await U(t,o);if(!i)return null;let s;try{s=ee(e)}catch(l){return f(t,l),null}let a=new J({provider:s,credentialStore:i,profileId:n,apiBaseUrl:e.apiBaseUrl});return{client:new H(a),http:a,config:e,credentialStore:i,profileId:n,credentialSource:"device-oauth"}}async function mo(t){let e=await R(t);if(e)try{let[r,o]=await q(t,"Loading account\u2026",()=>Promise.all([e.client.whoami(),e.http.credentials()])),n={ok:!0,profile:e.profileId||r.username,environment:e.config.environment,authentication:o.credentialType||"device_oauth",identity:r,scopes:o?.scopes,expiresAt:o?.expiresAt?new Date(o.expiresAt).toISOString():null,expired:o?.expiresAt?Date.now()>=o.expiresAt:!1};y(t,n),!t.json&&!t.quiet&&(console.log(`${r.displayName||r.username} (@${r.username})`),console.log(`Profile: ${n.profile} \xB7 ${n.environment}`),console.log(`Authentication: ${n.authentication}`),console.log(`Scopes: ${n.scopes?.join(", ")||"validated by server"}`),console.log(`Expires: ${n.expiresAt||"unknown"}`))}catch(r){f(t,r,r.status===401||r.status===403?p.AUTH:p.ERROR)}}async function go(t){let e=O({flags:G(t)}),r=new URL("/register",e.accountsBaseUrl).toString();if(t["no-input"]){y(t,{ok:!0,registrationUrl:r,next:"lixblogs login"}),!t.json&&!t.quiet&&console.log(r);return}await Ue(r),t.quiet||console.log(j(`Create your account at ${r}, then approve the device login.`,d())),await fr(t)}async function ho(t){let e=O({flags:G(t)}),r=new _,o=await he(e,r),n=await U(t,r);if(!n)return;let i=await Qe({credentialStore:n,profileId:o});y(t,i),!t.json&&!t.quiet&&console.log(v(`Logged out profile "${o}".`,d()))}async function yo(t){let e=O({flags:G(t)}),r=new _,o=await he(e,r);if(!t.yes)return f(t,"This is a destructive action. Re-run with --yes to confirm (interactive confirmation prompt not yet implemented).");let n;try{n=ee(e)}catch(a){return f(t,a.message)}let i=await U(t,r);if(!i)return;let s=await et({provider:n,credentialStore:i,profileId:o,confirmed:!0});if(!s.ok)return f(t,s.reason);y(t,s),!t.json&&!t.quiet&&console.log(v(`Revoked and logged out profile "${o}".`,d()))}async function z(t,e,r){if((r==="cloudinary-disconnect"||r==="pollinations-disconnect")&&!t.yes)return f(t,"This is a destructive action. Re-run with --yes to confirm (interactive confirmation prompt not yet implemented).");let o=await R(t);if(!o)return;let n=new pe(o.http),i=await q(t,r.endsWith("status")?"Checking integration\u2026":"Disconnecting integration\u2026",async()=>{if(r==="cloudinary-status")return tr({integrationsClient:n});if(r==="cloudinary-disconnect")return er({integrationsClient:n,confirmed:!0});try{return{ok:!0,data:r==="pollinations-status"?await n.pollinationsStatus({refresh:t.force}):await n.pollinationsDisconnect()}}catch(s){return{ok:!1,error:s}}});if(!i.ok)return f(t,i.error||i.reason);y(t,i),!t.json&&!t.quiet&&console.log(r==="cloudinary-status"?j(`Cloudinary: ${i.data.connected?`connected (${i.data.cloudName})`:"not connected"}`,d()):r==="pollinations-status"?j(`Pollinations: ${i.data.connected?`connected${i.data.handle?` as ${i.data.handle}`:""} \xB7 ${i.data.balance??"unknown"} Pollen`:`${i.data.status}. Connect at ${i.data.connectUrl||"https://blogs.elixpo.com/settings?tab=integrations"}`}`,d()):v(`${r.startsWith("pollinations")?"Pollinations":"Cloudinary"} connection disconnected.`,d()))}async function wo(t){let e=new _,r=await U(t,e);if(!r)return;let o=await tt({credentialStore:r,profileRegistry:e});if(y(t,o),!t.json){o.profiles.length||console.log($("No profiles. Run `lixblogs auth login` first.",d()));for(let n of o.profiles)console.log(`${n.active?"*":" "} ${n.profileId}${n.expired?" (expired)":""}`)}}async function bo(t,e){let r;try{r=S(e[0])}catch(s){return f(t,s.message)}let o=new _,n=await U(t,o);if(!n)return;let i=await rt({credentialStore:n,profileRegistry:o,profileId:r});if(!i.ok)return f(t,i.reason);y(t,i),!t.json&&!t.quiet&&console.log(v(`Using profile "${r}".`,d()))}var mr={list:wt,get:Oe,preview:Oe,create:bt,edit:vt,publish:xt,unpublish:It,delete:Pe,trash:Pe,restore:Et,history:_t,"restore-version":kt},gr={list:qt,get:At,collections:Tt,members:Rt,targets:Ot},hr={list:Pt,invitations:Lt,invite:jt,role:Ct,remove:Ut,accept:Dt,decline:Nt},yr={list:({options:t})=>je(t),inspect:({id:t})=>Jt({name:t}),install:({id:t,options:e})=>e.all?Kt({options:e}):Ht({name:t,options:e})},wr={query:Zt,export:Qt},br={generate:ir,upload:sr,delete:ar},vr={list:lr,add:cr,reply:ur,delete:dr};async function vo(t,e,r){let o=await R(t);if(!o)return;let n=o.client,i={...t,limit:t.limit===void 0?void 0:Number.parseInt(t.limit,10)};try{let s=await q(t,`${r==="list"?"Loading":r==="get"||r==="preview"?"Opening":"Updating"} blog\u2026`,async()=>{let a=await mr[r]({client:n,id:e[0],options:i,stdin:process.stdin});return yt({client:n,action:r,result:a})});if(y(t,{ok:!0,...s}),!t.json&&!t.quiet)if(r==="list"){for(let a of s.data||[])console.log(`${a.id} ${a.status} ${a.title||"(untitled)"}`);s.meta?.nextCursor&&console.log(j(`Next cursor: ${s.meta.nextCursor}`,d()))}else if(r==="get"||r==="preview")console.log(`${s.title||"(untitled)"} [${s.status}]
114
+ ${s.markdown||""}`);else if(r==="history")if(s.markdown!==void 0)console.log(`${s.id} ${s.label||"snapshot"} ${s.created_at} ${s.username||"system"}`),process.stdout.write(`${s.markdown}
115
+ `);else for(let a of s.data||[])console.log(`${a.id} ${a.label||"snapshot"} ${a.created_at} ${a.word_count||0} words ${a.username||"system"} ${a.excerpt||""}`);else s.dryRun?console.log($(`Dry run: ${r} validated; no changes sent.`,d())):console.log(v(St(r,s),d()))}catch(s){if(t.json&&s instanceof m){process.stdout.write(se({ok:!1,error:{code:s.code,message:s.message,requestId:s.requestId,details:s.details}})+`
116
+ `),process.exitCode=s.status===412?3:1;return}return f(t,s,s.status===412?p.CONFLICT:p.ERROR)}}async function xo(t,e,r){let o=await R(t);if(!o)return;let n=new le(o.http);try{let i=await q(t,"Loading organization\u2026",()=>gr[r]({client:n,id:e[0],options:t}));if(y(t,{ok:!0,data:i}),t.json||t.quiet)return;if(r==="targets"){console.log("personal Personal Blog");for(let a of i.organizations||[]){console.log(`${a.target} ${a.role} ${a.name}`);for(let l of a.collections||[])console.log(` collection:${l.id} ${l.name}`)}return}let s=r==="list"?i.data||[]:Array.isArray(i)?i:[i];for(let a of s)console.log([a.id||a.userId||a.orgId,a.role,a.slug||a.username,a.name||a.displayName].filter(Boolean).join(" "))}catch(i){f(t,i,i.status===401||i.status===403?p.AUTH:p.ERROR)}}async function _o(t,e,r){let o=await R(t);if(o)try{let i=await q(t,r==="generate"?"Generating image\u2026":r==="upload"?"Uploading image\u2026":"Deleting media\u2026",()=>br[r]({mediaClient:new fe(o.http),blogClient:o.client,id:e[0],options:t}));y(t,{ok:!0,data:i}),!t.json&&!t.quiet&&console.log(v($t(r,i,t.blog),d()))}catch(n){f(t,n,n.status===401||n.status===403?p.AUTH:p.ERROR)}}async function ko(t,e,r){let o=await R(t);if(o)try{let n=await q(t,r==="list"?"Loading comments\u2026":"Updating comments\u2026",()=>vr[r]({client:o.client,id:e[0],options:t}));if(y(t,{ok:!0,data:n}),!t.json&&!t.quiet)if(r==="list")for(let i of n)console.log(`${i.id} ${i.parent_id?"reply":"comment"} ${i.display_name||i.username||"Anonymous"} ${i.content}`);else console.log(v(`${r} completed for ${n.id}.`,d()))}catch(n){f(t,n,n.status===401||n.status===403?p.AUTH:p.ERROR)}}async function Io(t,e,r){let o=await R(t);if(!o)return;let n=new ue(o.http);try{let i=await q(t,"Updating collaborators\u2026",()=>hr[r]({client:n,id:e[0],options:t}));if(y(t,{ok:!0,data:i}),t.json||t.quiet)return;if(i.dryRun){console.log($(`Dry run: ${i.action} validated; no changes sent.`,d()));return}if(r!=="list"&&r!=="invitations"){console.log(v(`${r} completed for ${i.blogId||i.userId||e[0]}.`,d()));return}let s=r==="invitations"?i:r==="list"?i.collaborators||[]:[i];for(let a of s)console.log([a.blogId||a.userId,a.status,a.role,a.username||a.title,a.notificationState].filter(Boolean).join(" "))}catch(i){f(t,i,i.status===401||i.status===403?p.AUTH:p.ERROR)}}async function Eo(t,e,r){try{let o=await yr[r]({id:e[0],options:t});if(y(t,{ok:!0,data:o}),t.json||t.quiet)return;if(r==="list")for(let n of o)console.log(`${n.name} CLI >= ${n.minimumCliVersion||"unknown"} ${n.description}`);else r==="inspect"?process.stdout.write(o.content):o.dryRun&&o.all?console.log($(`Dry run: install ${o.skills.length} skills to ${o.targetRoot}.`,d())):o.dryRun?console.log($(`Dry run: install ${o.name} to ${o.target}${o.replace?" (replace)":""}.`,d())):o.all?console.log(v(`Installed ${o.skills.length} LixBlogs skills at ${o.targetRoot}.`,d())):console.log(v(`Installed ${o.name} at ${o.target}.`,d()))}catch(o){f(t,o)}}async function So(t,e,r){let o=await R(t);if(!o)return;let n=new de(o.http),i={...t,limit:t.limit===void 0?void 0:Number.parseInt(t.limit,10)};try{let s=await q(t,r==="export"?"Exporting analytics\u2026":"Loading analytics\u2026",()=>wr[r]({client:n,options:i}));if(y(t,{ok:!0,data:s}),t.json||t.quiet)return;if(r==="export"){console.log(v(`Exported ${s.rows} rows to ${s.output}.`,d()));return}let a=s.data;if(console.log(`${a.scope.label} \xB7 ${a.dimension} \xB7 ${a.range.key}`),a.dimension==="overview")for(let[l,c]of Object.entries(a.values.totals))console.log(`${l} ${c} ${a.values.changes[l]}%`);else if(a.dimension==="timeline")a.values.labels.forEach((l,c)=>console.log(`${l} ${a.values.views[c]} ${a.values.reads[c]}`));else{for(let l of a.values)console.log(Object.values(l).join(" "));s.meta?.nextCursor&&console.log(`Next cursor: ${s.meta.nextCursor}`)}}catch(s){f(t,s,s.status===401||s.status===403?p.AUTH:p.ERROR)}}var pr={auth:{login:fr,status:fo,whoami:mo,logout:ho,revoke:yo,profiles:wo,use:bo},blog:Object.fromEntries(Object.keys(mr).map(t=>[t,(e,r)=>vo(e,r,t)])),org:Object.fromEntries(Object.keys(gr).map(t=>[t,(e,r)=>xo(e,r,t)])),collab:Object.fromEntries(Object.keys(hr).map(t=>[t,(e,r)=>Io(e,r,t)])),skill:Object.fromEntries(Object.keys(yr).map(t=>[t,(e,r)=>Eo(e,r,t)])),analytics:Object.fromEntries(Object.keys(wr).map(t=>[t,(e,r)=>So(e,r,t)])),media:Object.fromEntries(Object.keys(br).map(t=>[t,(e,r)=>_o(e,r,t)])),comment:Object.fromEntries(Object.keys(vr).map(t=>[t,(e,r)=>ko(e,r,t)])),integrations:{"cloudinary-status":(t,e)=>z(t,e,"cloudinary-status"),"cloudinary-disconnect":(t,e)=>z(t,e,"cloudinary-disconnect"),"pollinations-status":(t,e)=>z(t,e,"pollinations-status"),"pollinations-disconnect":(t,e)=>z(t,e,"pollinations-disconnect")},disconnect:{cloudinary:(t,e)=>z(t,e,"cloudinary-disconnect"),pollinations:(t,e)=>z(t,e,"pollinations-disconnect")}};async function $o(){let t,e;try{({values:t,positionals:e}=ao({args:process.argv.slice(2),options:co,allowPositionals:!0,strict:!0}))}catch(s){process.stderr.write(`Error: Invalid flag. ${s.message}
117
+ `),process.exitCode=p.USAGE;return}if(t.help||e.length===0){process.stdout.write(uo);return}if(e[0]==="register"){await go(t);return}e=at(e);let[r,o]=e,n=pr[r];if(!n){process.stderr.write(`Error: Unknown command category "${r}".
118
+ `),process.stderr.write(`Available categories: ${Object.keys(pr).join(", ")}
119
+ `),process.exitCode=p.USAGE;return}let i=n[o];if(!i){process.stderr.write(`Error: Unknown ${r} command "${o}".
118
120
  `),process.stderr.write(`Available commands: ${Object.keys(n).map(s=>`${r} ${s}`).join(", ")}
119
- `),process.exitCode=g.USAGE;return}await i(t,e.slice(2))}Io();
121
+ `),process.exitCode=p.USAGE;return}await i(t,e.slice(2))}$o();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elixpo/lixblogs-cli",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "Official CLI for LixBlogs — publish, manage, and inspect blogs through the supported API. Built for creators and agent automation.",
5
5
  "author": {
6
6
  "name": "Elixpo",