@hlix/cli 0.7.0 → 0.7.2

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.
@@ -1,261 +0,0 @@
1
- #!/usr/bin/env node
2
- class e extends Error{code;details;constructor(j,P,O){super(P);if(this.name="CliError",this.code=j,O!==void 0)this.details=O}}var R=1,se=(j,P)=>({schemaVersion:1,command:j,data:P}),Zt=(j,P)=>({schemaVersion:1,command:j,error:P});function re(j){return`${JSON.stringify(j,null,2)}
3
- `}function ye(j){let P=Math.max(0,...j.map(([O])=>O.length));return j.map(([O,T])=>`${O.padEnd(P)} ${T}`).join(`
4
- `)}function Je(j,P){let O=j.map((F,N)=>Math.max(F.length,...P.map((M)=>(M[N]??"").length))),T=(F)=>F.map((N,M)=>N.padEnd(O[M])).join(" ").trimEnd();return[T(j),T(O.map((F)=>"-".repeat(F))),...P.map(T)].join(`
5
- `)}import{statSync as ca}from"node:fs";import{dirname as la,resolve as da}from"node:path";import{closeSync as mr,constants as Qt,existsSync as Nn,fsyncSync as Ys,lstatSync as fr,mkdirSync as Yi,openSync as Xs,readFileSync as Zs,renameSync as Xi,statSync as Qs,unlinkSync as eo,writeFileSync as Zi}from"node:fs";import{homedir as Qi}from"node:os";import{dirname as ea,join as gr}from"node:path";function _t(j=process.env){let P=j.HLIX_CONFIG_HOME??j.XDG_CONFIG_HOME??gr(Qi(),".config");return gr(P,"hlix","credentials.json")}function to(j=process.env){let P=j.HLIX_API_KEY;if(!P&&j.HLIX_SESSION_TOKEN)return{baseUrl:j.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:"",sessionToken:j.HLIX_SESSION_TOKEN,...j.HLIX_WORKSPACE_ID?{organizationId:j.HLIX_WORKSPACE_ID}:{}};if(P)return{baseUrl:j.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:P,...j.HLIX_WORKSPACE_ID?{organizationId:j.HLIX_WORKSPACE_ID}:{}};try{let O=JSON.parse(Zs(_t(j),"utf8"));return O.apiKey&&O.baseUrl?O:null}catch{return null}}function no(j=process.env){let P=_t(j);return Nn(P)?P:null}function hr(j=process.env){let P=_t(j);if(!Nn(P))return{path:P,removed:!1,reason:"absent"};let O=fr(P);if(O.isSymbolicLink()||!O.isFile())throw Error("Refusing to remove a credential path that is not a regular file.");let T=process.getuid?.();if(T!==void 0&&Qs(P).uid!==T)throw Error("Refusing to remove a credential file owned by another user.");let F;try{F=JSON.parse(Zs(P,"utf8"))}catch{F=null}let N=F;if(!N||typeof N.apiKey!=="string"||typeof N.baseUrl!=="string")throw Error(`Refusing to remove ${P}: it is not a credential written by this CLI.`);return eo(P),{path:P,removed:!0,reason:"removed"}}function ro(j,P=process.env){let O=_t(P),T=ea(O);if(Yi(T,{recursive:!0,mode:448}),fr(T).isSymbolicLink())throw Error("Refusing to write credentials through a symlinked directory.");if(Nn(O)){let M=fr(O);if(M.isSymbolicLink()||!M.isFile())throw Error("Refusing to replace a credential path that is not a regular file.");let L=process.getuid?.();if(L!==void 0&&Qs(O).uid!==L)throw Error("Refusing to replace a credential file owned by another user.")}let F=gr(T,`.credentials.${process.pid}.${crypto.randomUUID()}.tmp`),N;try{N=Xs(F,Qt.O_WRONLY|Qt.O_CREAT|Qt.O_EXCL|Qt.O_NOFOLLOW,384),Zi(N,`${JSON.stringify(j,null,2)}
6
- `,"utf8"),Ys(N),mr(N),N=void 0,Xi(F,O);let M=Xs(T,Qt.O_RDONLY);try{try{Ys(M)}catch(L){let H=L.code;if(H!=="EINVAL"&&H!=="ENOTSUP")throw L}}finally{mr(M)}}catch(M){if(N!==void 0)mr(N);if(Nn(F))eo(F);throw M}return O}import{appendFileSync as ta,constants as Fn,existsSync as wr,lstatSync as vr,mkdirSync as na,openSync as ra,closeSync as so,fsyncSync as sa,readFileSync as br,renameSync as oa,unlinkSync as ia,writeFileSync as yr}from"node:fs";import{dirname as aa,join as en,resolve as Mn}from"node:path";function oo(j){if(!wr(j))return;let P=vr(j);if(P.isSymbolicLink()||!P.isFile())throw Error(`Refusing to replace a non-regular Hlix file: ${j}`)}function Ge(j,P){let O=aa(j);if(na(O,{recursive:!0,mode:448}),vr(O).isSymbolicLink())throw Error(`Refusing to write through a symlinked Hlix directory: ${O}`);oo(j);let T=en(O,`.hlix-${process.pid}-${crypto.randomUUID()}.tmp`),F;try{F=ra(T,Fn.O_WRONLY|Fn.O_CREAT|Fn.O_EXCL|Fn.O_NOFOLLOW,384),yr(F,`${JSON.stringify(P,null,2)}
7
- `,"utf8"),sa(F),so(F),F=void 0,oa(T,j)}catch(N){if(F!==void 0)so(F);if(wr(T))ia(T);throw N}}function tn(j){return en(Mn(j),".hlix","config.json")}function io(j){return en(Mn(j),".hlix","state.json")}function ot(j){try{let P=JSON.parse(br(tn(j),"utf8"));return P.schemaVersion===1&&P.workspaceId&&P.apiUrl?P:null}catch{return null}}function gt(j,P){Ge(tn(j),P);let O=en(Mn(j),".hlix",".gitignore");if(!wr(O))yr(O,`state.json
8
- import.json
9
- import.bundle
10
- `,{mode:420,flag:"wx"});oo(O);let T=br(O,"utf8").split(/\r?\n/),F=["import.json","import.bundle"].filter((M)=>!T.includes(M));if(F.length)ta(O,`
11
- ${F.join(`
12
- `)}
13
- `);let N=en(Mn(j),".hlixignore");if(!vr(N,{throwIfNoEntry:!1}))yr(N,`# Additional project-local paths to exclude from Hlix snapshots.
14
- `,{mode:420,flag:"wx"})}function it(j,P){Ge(io(j),{...P,snapshotOnly:P.snapshotOnly??s(j)?.snapshotOnly,includedPaths:P.includedPaths??s(j)?.includedPaths})}function s(j){try{let P=JSON.parse(br(io(j),"utf8"));return P.schemaVersion===1&&P.revisionId&&P.generation>0?P:null}catch{return null}}var kr="https://server.hlix.ai";function u(j){if(!j.credential)return null;if(j.credentialSource==="session")return"session (desktop)";if(j.credentialSource==="env")return"environment (HLIX_API_KEY)";return`file (${j.credentialPath})`}function t(j){let P=da(j);for(;;){let O=ot(P);if(O)return{root:P,config:O};let T=la(P);if(T===P)return null;P=T}}function co(j){try{return ca(j).isDirectory()}catch{return!1}}function Hn(j){if(typeof j!=="string")return;let P=j.trim();return P?P:void 0}var ao=(j,P)=>j.replace(/\/+$/,"")===P.replace(/\/+$/,"");function r(j){let{env:P,flags:O,cwd:T}=j,F=t(T),N=to(P),M=N?P.HLIX_API_KEY?"env":P.HLIX_SESSION_TOKEN?"session":"file":null,L=M==="file"?N:null,H=Hn(O["base-url"]),U=Hn(P.HLIX_BASE_URL),D=Hn(O.workspace),z=Hn(P.HLIX_WORKSPACE_ID),W=H??U??F?.config.apiUrl??L?.baseUrl??kr,J=H?"flag":U?"env":F?.config.apiUrl?"project":L?.baseUrl?"credential":"default",V=D??z??F?.config.workspaceId??L?.organizationId??null,B=D?"flag":z?"env":F?.config.workspaceId?"project":L?.organizationId?"credential":null;return{baseUrl:W,baseUrlSource:J,workspaceId:V,workspaceSource:B,credential:N,credentialSource:M,credentialPath:_t(P),binding:F,conflict:ua(F,{flagBaseUrl:H,envBaseUrl:U,flagWorkspace:D,envWorkspace:z})}}function ua(j,P){if(!j)return null;let O=`${j.root} is bound to`,T="Drop the override, or point --cwd at a folder bound to it.";if(P.flagWorkspace&&P.flagWorkspace!==j.config.workspaceId)return`${O} workspace ${j.config.workspaceId}, but --workspace names ${P.flagWorkspace}. ${T}`;if(P.envWorkspace&&P.envWorkspace!==j.config.workspaceId)return`${O} workspace ${j.config.workspaceId}, but HLIX_WORKSPACE_ID names ${P.envWorkspace}. ${T}`;if(P.flagBaseUrl&&!ao(P.flagBaseUrl,j.config.apiUrl))return`${O} ${j.config.apiUrl}, but --base-url names ${P.flagBaseUrl}. ${T}`;if(P.envBaseUrl&&!ao(P.envBaseUrl,j.config.apiUrl))return`${O} ${j.config.apiUrl}, but HLIX_BASE_URL names ${P.envBaseUrl}. ${T}`;return null}import{resolve as Ea}from"node:path";import{parseArgs as $a}from"node:util";import pa from"openapi-fetch";function Sr(j){return pa({baseUrl:j.baseUrl,headers:j.headers,fetch:j.fetch})}var At=(j)=>({kind:"apiKey",apiKey:j});var jr=(j)=>({kind:"bearer",token:j});function ma(j){switch(j.kind){case"apiKey":return{"x-api-key":j.apiKey};case"session":return{cookie:j.cookie};case"bearer":return{authorization:`Bearer ${j.token}`}}}function fa(j){return j?{"X-Organization-Id":j}:{}}function lo(j,P){return{...ma(j),...fa(P)}}function ga(j){if(typeof j!=="object"||j===null)return null;let{error:P}=j;return typeof P==="string"?P:null}class Ie extends Error{status;body;requestId;method;url;constructor(j,P){super(j);this.name=new.target.name,this.status=P.status,this.body=P.body,this.requestId=P.requestId??null,this.method=P.method,this.url=P.url}}class Ot extends Ie{issues;constructor(j,P,O){super(j,P);this.issues=O}}class nn extends Ie{}class rn extends Ie{}class sn extends Ie{}class qe extends Ie{}class ht extends Ie{}class on extends Ie{retryAfter;constructor(j,P,O){super(j,P);this.retryAfter=O}}class an extends Ie{}class at extends Ie{}class Ke extends Error{method;url;constructor(j,P){super(j,{cause:P.cause});this.name="HlixTransportError",this.method=P.method,this.url=P.url}}function ha(j){if(typeof j!=="object"||j===null)return null;let P=j;if(P.success!==!1)return null;let O=P.error?.message;if(typeof O!=="string")return null;try{let T=JSON.parse(O);return Array.isArray(T)?T:[]}catch{return[]}}function ya(j){let P=j.get("retry-after");if(!P)return null;let O=Number(P);return Number.isFinite(O)&&O>=0?O:null}function Tt(j,P,O){let T={status:j.status,body:P,requestId:j.headers.get("x-request-id"),method:O.method,url:O.url},F=ga(P),N=`${O.method} ${O.url} failed with ${j.status}`,M=ha(P);if(M)return new Ot(`${O.method} ${O.url}: request body failed validation`,T,M);let L=F??N;switch(j.status){case 400:return new nn(L,T);case 401:return new rn(L,T);case 403:return new sn(L,T);case 404:return new qe(L,T);case 409:return new ht(L,T);case 429:return new on(L,T,ya(j.headers));case 501:return new an(L,T);default:return j.status>=500?new at(L,T):new Ie(L,T)}}var uo=new Set(["GET","HEAD","PUT","DELETE","OPTIONS","TRACE"]);function Ln(j){return uo.has(j.toUpperCase())}var wa=new Set([429,500,502,503,504]);function va(j){return wa.has(j)}var Er={attempts:3,baseDelayMs:200,maxDelayMs:5000};function $r(j,P,O,T=Math.random){if(O!==null)return Math.min(O*1000,P.maxDelayMs);let F=Math.min(P.baseDelayMs*2**j,P.maxDelayMs);return Math.round(T()*F)}function Pr(j){if(!Ln(j.method))return!1;if(j.attempt+1>=j.policy.attempts)return!1;return j.status===null||va(j.status)}var ba=(j)=>new Promise((P)=>setTimeout(P,j));function ka(j){let P=j.headers.get("retry-after");if(!P)return null;let O=Number(P);return Number.isFinite(O)&&O>=0?O:null}function po(j){let{base:P,policy:O}=j,T=j.sleep??ba,F=j.random??Math.random;return async(N)=>{let M=N.method.toUpperCase(),L=Ln(M)?N.clone():null;for(let H=0;;H+=1){let U=H===0?N:L.clone(),D;try{D=await P(U)}catch(z){if(!L||!Pr({method:M,attempt:H,policy:O,status:null}))throw new Ke(`${M} ${N.url}: ${z instanceof Error?z.message:String(z)}`,{method:M,url:N.url,cause:z});await T($r(H,O,null,F));continue}if(!Pr({method:M,attempt:H,policy:O,status:D.status}))return D;if(!L)return D;await T($r(H,O,ka(D),F))}}}function ce(j,P){if(j.response.ok)return j.data;throw Tt(j.response,j.error??j.data,P)}var cn=(j)=>typeof j==="string"?j:"";function Ir(j){let P;try{P=JSON.parse(j)}catch{return null}if(typeof P!=="object"||P===null)return null;let O=P;switch(O.type){case"idle":return{type:"idle"};case"done":return{type:"done"};case"active":return typeof O.runId==="string"?{type:"active",runId:O.runId}:{type:"active"};case"on_chat_model_stream":return{type:"on_chat_model_stream",delta:cn(O.delta)};case"reasoning":return{type:"reasoning",delta:cn(O.delta)};case"on_tool_start":return{type:"on_tool_start",name:cn(O.name),input:O.input};case"on_tool_end":return{type:"on_tool_end",name:cn(O.name),output:O.output};case"error":return{type:"error",message:cn(O.message)};default:return null}}var Cr=(j)=>j.type==="done"||j.type==="idle"||j.type==="error";var Sa=()=>({event:null,data:[],id:null,retry:null});function mo(j,P,O){switch(P){case"event":j.event=O;return;case"data":j.data.push(O);return;case"id":if(!O.includes("\x00"))j.id=O;return;case"retry":{if(/^\d+$/.test(O))j.retry=Number(O);return}default:return}}function go(j){let P=j.data.join(`
15
- `),{event:O,id:T}=j;if(j.data=[],j.event=null,P==="")return null;return{event:O,data:P,id:T,retry:j.retry}}function fo(j,P){if(P==="")return go(j);if(P.startsWith(":"))return null;let O=P.indexOf(":");if(O===-1)return mo(j,P,""),null;let T=P.slice(0,O),F=P.slice(O+1);if(F.startsWith(" "))F=F.slice(1);return mo(j,T,F),null}function ja(j){let P=[],O=0;for(let T=0;T<j.length;T+=1){let F=j[T];if(F!==`
16
- `&&F!=="\r")continue;if(P.push(j.slice(O,T)),F==="\r"&&j[T+1]===`
17
- `)T+=1;O=T+1}return{lines:P,rest:j.slice(O)}}async function*xr(j,P){let O=j.getReader(),T=new TextDecoder,F=Sa(),N="",M=()=>void O.cancel().catch(()=>{});P?.addEventListener("abort",M,{once:!0});try{for(;;){let{done:H,value:U}=await O.read();if(H)break;N+=T.decode(U,{stream:!0});let{lines:D,rest:z}=ja(N);N=z;for(let W of D){let J=fo(F,W);if(J)yield J}if(P?.aborted)return}if(N+=T.decode(),N!==""){let H=fo(F,N);if(H)yield H}let L=go(F);if(L)yield L}finally{P?.removeEventListener("abort",M),O.releaseLock()}}function Rr(j){let P;try{P=JSON.parse(j)}catch{return null}if(typeof P!=="object"||P===null)return null;let O=P;if(O.kind==="ready")return{kind:"ready"};if(O.kind==="workspace")return{kind:"workspace"};if(O.kind==="head"&&typeof O.revisionId==="string"&&typeof O.generation==="number")return{kind:"head",revisionId:O.revisionId,generation:O.generation};return null}function ho(j){return j instanceof Ie&&j.status>=400&&j.status<500&&j.status!==408&&j.status!==429}var Un={firstDelayMs:1000,maxDelayMs:30000};function Nt(j,P){return new Promise((O)=>{if(P?.aborted)return O();let T=setTimeout(F,j);function F(){clearTimeout(T),P?.removeEventListener("abort",F),O()}P?.addEventListener("abort",F,{once:!0})})}class Ft{raw;baseUrl;headers;fetcher;constructor(j){this.baseUrl=j.baseUrl.replace(/\/+$/,""),this.headers=lo(j.credential,j.organizationId);let P={...Er,...j.retry},O=j.fetch??((T)=>globalThis.fetch(T));this.fetcher=po({base:O,policy:P}),this.raw=Sr({baseUrl:this.baseUrl,headers:this.headers,fetch:this.fetcher})}at(j,P){return{method:j,url:`${this.baseUrl}${P}`}}workspaces={list:async(j={})=>ce(await this.raw.GET("/v1/api/workspaces",j),this.at("GET","/v1/api/workspaces"))};projects={list:async()=>ce(await this.raw.GET("/v1/api/projects"),this.at("GET","/v1/api/projects")),get:async(j,P={})=>ce(await this.raw.GET("/v1/api/projects/{id}",{...P,params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}`)),create:async(j)=>ce(await this.raw.POST("/v1/api/projects",{body:j}),this.at("POST","/v1/api/projects")),delete:async(j)=>ce(await this.raw.DELETE("/v1/api/projects/{id}",{params:{path:{id:j}}}),this.at("DELETE",`/v1/api/projects/${j}`)),start:async(j,P)=>ce(await this.raw.POST("/v1/api/projects/{id}/start",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/start`)),refreshPreview:async(j)=>ce(await this.raw.POST("/v1/api/projects/{id}/preview/refresh",{params:{path:{id:j}}}),this.at("POST",`/v1/api/projects/${j}/preview/refresh`)),connectRepo:async(j,P)=>{let O=await this.raw.POST("/v1/api/projects/{id}/repos/connect",{params:{path:{id:j}},body:P});return ce(O,this.at("POST",`/v1/api/projects/${j}/repos/connect`))},terminal:async(j)=>ce(await this.raw.GET("/v1/api/projects/{id}/terminal",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/terminal`)),observeAgent:(j,P,O)=>this.observeAgent(j,P,O),workspace:(j)=>({environment:async()=>ce(await this.raw.GET("/v1/api/projects/{id}/environment",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/environment`)),fs:async(P)=>ce(await this.raw.POST("/v1/api/projects/{id}/workspace/fs",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/workspace/fs`)),exec:async(P)=>ce(await this.raw.POST("/v1/api/projects/{id}/workspace/exec",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/workspace/exec`))})};secrets={listEntries:async(j)=>ce(await this.raw.GET("/v1/api/secrets/project/{projectId}/entries",{params:{path:{projectId:j}}}),this.at("GET",`/v1/api/secrets/project/${j}/entries`)),upsertEntries:async(j,P)=>ce(await this.raw.PUT("/v1/api/secrets/project/{projectId}/entries",{params:{path:{projectId:j}},body:P}),this.at("PUT",`/v1/api/secrets/project/${j}/entries`)),importFiles:async(j,P)=>ce(await this.raw.PUT("/v1/api/secrets/project/{projectId}/files",{params:{path:{projectId:j}},body:{files:P}}),this.at("PUT",`/v1/api/secrets/project/${j}/files`)),deleteEntry:async(j,P,O)=>ce(await this.raw.DELETE("/v1/api/secrets/project/{projectId}/entries/{key}",{params:{path:{projectId:j,key:P},...O===void 0?{}:{query:{source:O}}}}),this.at("DELETE",`/v1/api/secrets/project/${j}/entries/${encodeURIComponent(P)}`)),exportEntries:async(j,P={})=>{let O=`/v1/api/secrets/project/${j}/export`,T=`${this.baseUrl}${O}`,F=await this.fetcher(new Request(T,{method:"POST",headers:{...this.headers,"content-type":"application/json"},body:JSON.stringify({...P.source===void 0?{}:{source:P.source},...P.format===void 0?{}:{format:P.format}})}));if(!F.ok)throw Tt(F,await F.json().catch(()=>{return}),{method:"POST",url:T});return F.text()}};imports={create:async(j)=>{let P=await this.raw.POST("/v1/api/imports",{body:j});return ce(P,this.at("POST","/v1/api/imports"))},get:async(j,P={})=>ce(await this.raw.GET("/v1/api/imports/{id}",{signal:P.signal,params:{path:{id:j}}}),this.at("GET",`/v1/api/imports/${j}`)),finalize:async(j,P,O={})=>{let T=await this.raw.POST("/v1/api/imports/{id}/finalize",{signal:O.signal,params:{path:{id:j}},body:P});return ce(T,this.at("POST",`/v1/api/imports/${j}/finalize`))},finalizeAndWait:async(j,P,O={})=>{let T=AbortSignal.timeout(O.timeoutMs??600000),F=O.signal?AbortSignal.any([O.signal,T]):T;try{return await this.imports.finalize(j,P,{signal:F})}catch(N){if(F.throwIfAborted(),!(N instanceof at||N instanceof Ke||N instanceof ht))throw N}return this.imports.waitUntilReady(j,{...O,signal:F})},waitUntilReady:async(j,P={})=>{let O=AbortSignal.timeout(P.timeoutMs??600000),T=P.signal?AbortSignal.any([P.signal,O]):O;while(!0){T.throwIfAborted();try{let F=await this.imports.get(j,{signal:T});if(F.import.status==="ready")return F;if(F.import.status!=="finalizing")throw Error(`Import ${j} is ${F.import.status}: ${F.import.error??"rerun hlix import to resume this session"}`)}catch(F){if(T.throwIfAborted(),!(F instanceof at||F instanceof Ke))throw F}await Nt(P.pollIntervalMs??2000,T)}},uploadBundle:async(j,P,O={})=>{let T=O.chunkSize??8388608;if(T<=0||T%262144!==0)throw Error("Import upload chunkSize must be a positive multiple of 256 KiB");let F=j.url.startsWith("/")?`${this.baseUrl}${j.url}`:j.url;if(j.kind==="hlix-stream"){let M=new Request(F,{method:"PUT",headers:{...this.headers,"content-type":"application/x-git-bundle","content-length":String(P.size)},body:P,signal:O.signal}),L=await this.fetcher(M);if(!L.ok)await this.throwUploadError(L,F);O.onProgress?.(P.size,P.size);return}let N=0;while(N<P.size){let M=Math.min(N+T,P.size),L=new Request(F,{method:"PUT",headers:{"content-type":"application/x-git-bundle","content-length":String(M-N),"content-range":`bytes ${N}-${M-1}/${P.size}`},body:P.slice(N,M),signal:O.signal}),H=await this.fetcher(L);if(H.status!==308&&!H.ok)await this.throwUploadError(H,F);let U=H.headers.get("range")?.match(/bytes=0-(\d+)/)?.[1];if(N=U?Number(U)+1:M,!Number.isSafeInteger(N)||N<M||N>P.size)throw Error("Import upload server returned an invalid acknowledged range");O.onProgress?.(N,P.size)}}};revisions={head:async(j,P={})=>ce(await this.raw.GET("/v1/api/projects/{id}/revisions/head",{...P,params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/revisions/head`)),protectedFiles:async(j)=>ce(await this.raw.GET("/v1/api/projects/{id}/protected-files",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/protected-files`)),createUpload:async(j,P)=>{let O=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads",{params:{path:{id:j}},body:P});return ce(O,this.at("POST",`/v1/api/projects/${j}/revisions/uploads`))},finalize:async(j,P,O)=>{let T=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads/{uploadId}/finalize",{params:{path:{id:j,uploadId:P}},body:O});return ce(T,this.at("POST",`/v1/api/projects/${j}/revisions/uploads/${P}/finalize`))},uploadBundle:async(j,P,O={})=>this.imports.uploadBundle(j,P,O),watch:(j,P)=>this.watchRevisions(j,P),downloadBundle:async(j,P)=>{let O=`/v1/api/projects/${j}/revisions/${P}/bundle`,T=new Request(`${this.baseUrl}${O}`,{method:"GET",headers:this.headers}),F=await this.fetcher(T);if(!F.ok)await this.throwUploadError(F,`${this.baseUrl}${O}`);return F.blob()}};resources={importSkill:async(j,P)=>ce(await this.raw.POST("/v1/api/projects/{id}/resources/skill",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/resources/skill`)),importAgent:async(j,P)=>ce(await this.raw.POST("/v1/api/projects/{id}/resources/agent",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/resources/agent`)),importMcp:async(j,P)=>ce(await this.raw.POST("/v1/api/projects/{id}/resources/mcp",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/projects/${j}/resources/mcp`))};async throwUploadError(j,P){let O=null;try{O=await j.json()}catch{O=await j.text().catch(()=>null)}throw Tt(j,O,{method:"PUT",url:P})}tasks={list:async(j)=>ce(await this.raw.GET("/v1/api/tasks",{params:{query:j??{}}}),this.at("GET","/v1/api/tasks")),get:async(j)=>ce(await this.raw.GET("/v1/api/tasks/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/tasks/${j}`)),create:async(j)=>ce(await this.raw.POST("/v1/api/tasks",{body:j}),this.at("POST","/v1/api/tasks")),update:async(j,P)=>ce(await this.raw.PATCH("/v1/api/tasks/{id}",{params:{path:{id:j}},body:P}),this.at("PATCH",`/v1/api/tasks/${j}`)),listComments:async(j)=>ce(await this.raw.GET("/v1/api/tasks/{id}/comments",{params:{path:{id:j}}}),this.at("GET",`/v1/api/tasks/${j}/comments`)),addComment:async(j,P)=>ce(await this.raw.POST("/v1/api/tasks/{id}/comments",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/tasks/${j}/comments`)),review:async(j)=>ce(await this.raw.GET("/v1/api/tasks/{id}/review",{params:{path:{id:j}}}),this.at("GET",`/v1/api/tasks/${j}/review`)),stream:(j,P)=>this.stream(`/v1/api/tasks/${j}/stream`,P)};modelConfig={setProjectHarness:async(j,P)=>ce(await this.raw.PUT("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:j}},body:{harness:P}}),this.at("PUT",`/v1/api/model-config/harness/${j}`)),clearProjectHarness:async(j)=>ce(await this.raw.DELETE("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:j}}}),this.at("DELETE",`/v1/api/model-config/harness/${j}`)),setHarness:async(j)=>ce(await this.raw.PUT("/v1/api/model-config/harness",{body:{harness:j}}),this.at("PUT","/v1/api/model-config/harness")),clearHarness:async()=>ce(await this.raw.DELETE("/v1/api/model-config/harness"),this.at("DELETE","/v1/api/model-config/harness")),resolvedHarness:async()=>ce(await this.raw.GET("/v1/api/model-config/harness/resolved"),this.at("GET","/v1/api/model-config/harness/resolved")),resolvedProjectHarness:async(j)=>ce(await this.raw.GET("/v1/api/model-config/harness/{projectId}/resolved",{params:{path:{projectId:j}}}),this.at("GET",`/v1/api/model-config/harness/${j}/resolved`))};ai={models:async(j,P)=>ce(await this.raw.GET("/v1/api/ai/w/{workspaceId}/models",{params:{path:{workspaceId:j}},...P?.signal?{signal:P.signal}:{}}),this.at("GET",`/v1/api/ai/w/${j}/models`))};cycles={list:async(j)=>ce(await this.raw.GET("/v1/api/cycles",{params:{query:j??{}}}),this.at("GET","/v1/api/cycles")),get:async(j)=>ce(await this.raw.GET("/v1/api/cycles/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/cycles/${j}`)),propose:async(j)=>ce(await this.raw.POST("/v1/api/cycles",{body:j}),this.at("POST","/v1/api/cycles")),stream:(j,P)=>this.stream(`/v1/api/cycles/${j}/stream`,P)};clientInvoices={list:async(j)=>ce(await this.raw.GET("/v1/api/client-billing/invoices",{params:{query:j??{}}}),this.at("GET","/v1/api/client-billing/invoices")),get:async(j)=>ce(await this.raw.GET("/v1/api/client-billing/invoices/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/client-billing/invoices/${j}`)),createDraft:async(j)=>ce(await this.raw.POST("/v1/api/client-billing/invoices",{body:j}),this.at("POST","/v1/api/client-billing/invoices")),issue:async(j)=>ce(await this.raw.POST("/v1/api/client-billing/invoices/{id}/issue",{params:{path:{id:j}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${j}/issue`)),void:async(j,P)=>ce(await this.raw.POST("/v1/api/client-billing/invoices/{id}/void",{params:{path:{id:j}},body:{reason:P}}),this.at("POST",`/v1/api/client-billing/invoices/${j}/void`)),pay:async(j)=>ce(await this.raw.POST("/v1/api/client-billing/invoices/{id}/pay",{params:{path:{id:j}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${j}/pay`)),paymentLink:async(j,P={})=>ce(await this.raw.POST("/v1/api/client-billing/invoices/{id}/payment-link",{params:{path:{id:j}},body:P}),this.at("POST",`/v1/api/client-billing/invoices/${j}/payment-link`))};async*observeAgent(j,P,O){let T=`/v1/api/projects/${j}/agents/${P}/observe`;for await(let F of this.stream(T,O)){let N=Ir(F.data);if(!N)continue;if(yield N,Cr(N))return}}async*watchRevisions(j,P){let O=`/v1/api/projects/${j}/revisions/watch`,T=P?.signal,F=Un.firstDelayMs;while(!T?.aborted){try{for await(let N of this.stream(O,P)){let M=Rr(N.data);if(!M)continue;if(M.kind==="ready")F=Un.firstDelayMs;yield M}}catch(N){if(T?.aborted)return;if(ho(N))throw N}await Nt(F,T),F=Math.min(F*2,Un.maxDelayMs)}}async*stream(j,P){let O=`${this.baseUrl}${j}`,T=new Request(O,{headers:{...this.headers,accept:"text/event-stream"},signal:P?.signal}),F=await globalThis.fetch(T);if(!F.ok||!F.body){let N=null;try{N=await F.json()}catch{N=null}throw Tt(F,N,{method:"GET",url:O})}yield*xr(F.body,P?.signal)}}function _r(j){if(j instanceof e)return{code:j.code,status:null};if(j instanceof Ot)return{code:"invalid_request",status:400};if(j instanceof nn)return{code:"bad_request",status:400};if(j instanceof rn)return{code:"unauthenticated",status:401};if(j instanceof sn)return{code:"forbidden",status:403};if(j instanceof qe)return{code:"not_found",status:404};if(j instanceof ht)return{code:"conflict",status:409};if(j instanceof on)return{code:"rate_limited",status:429};if(j instanceof an)return{code:"not_implemented",status:501};if(j instanceof at)return{code:"server_error",status:j.status};if(j instanceof Ke)return{code:"unreachable",status:null};return{code:"unknown",status:null}}var Dn=(j)=>{if(j instanceof Ot&&j.issues.length>0){let P=j.issues.slice(0,5).map((T)=>{let F=T;return` - ${Array.isArray(F.path)&&F.path.length>0?`${F.path.join(".")}: `:""}${typeof F.message==="string"?F.message:JSON.stringify(T)}`}),O=j.issues.length-P.length;return`${j.message}
18
- ${P.join(`
19
- `)}${O>0?`
20
- … ${O} more`:""}`}return j instanceof Error?j.message:String(j)};function n(j,P){let O=r({env:j,flags:P.flags,cwd:P.cwd});if(O.conflict)throw new e("workspace_mismatch",O.conflict);if(!O.credential)throw new e("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");return new Ft({baseUrl:O.baseUrl,credential:O.credential.sessionToken?jr(O.credential.sessionToken):At(O.credential.apiKey),...O.workspaceId?{organizationId:O.workspaceId}:{}})}function yo(j){let P=Math.max(...j.map((T)=>T.name.length));return`hlix — the hlix control-plane CLI
21
-
22
- Usage:
23
- hlix <command> [options]
24
-
25
- Commands:
26
- ${[` hlix ${"".padEnd(P)} Open Hlix Code (interactive)`,...j.map((T)=>` hlix ${T.name.padEnd(P)} ${T.summary}`)].join(`
27
- `)}
28
-
29
- Options:
30
- --json Machine-readable output (a versioned, stable contract)
31
- --cwd <dir> Operate on another directory instead of the current one
32
- --workspace <id> Workspace to act in, overriding the folder's binding
33
- --base-url <url> API to talk to, overriding the folder's binding
34
- --help Show this help
35
- --version Show the installed CLI version
36
-
37
- Hlix Code (hlix with no command):
38
- --sandbox <choice> cloud, docker or local; --local is short for local
39
- --docker-image <r> image the docker sandbox runs in
40
- --harness <name> which coder does the work
41
- --project <id> project to act in, when this folder is not bound
42
- -p "<prompt>" one turn, print the answer, exit
43
- --json with -p: one JSON object per event instead of prose
44
- --allow-writes with -p: let the turn change files and run commands
45
- --yolo approve every tool call for the whole session
46
-
47
- A command targets the workspace named by, in order: an explicit flag, the
48
- HLIX_* environment, the nearest .hlix/config.json, then the stored credential.
49
- Run \`hlix status\` to see which one applied.
50
- `}function vo(j,P){let O=[...Array(P.length+1).keys()];for(let T=1;T<=j.length;T+=1){let F=[T];for(let N=1;N<=P.length;N+=1)F[N]=Math.min(O[N]+1,F[N-1]+1,O[N-1]+(j[T-1]===P[N-1]?0:1));O=F}return O[P.length]}function Pa(j,P,O){let T=/Unknown option '--([^'=]+)/.exec(O)?.[1];if(!T)return O;let F=P.findIndex((H)=>H.startsWith("-")),N=F===-1?P:P.slice(0,F),M=new Set(["json","help","version","cwd","workspace","base-url",...zn(j,N)?.command.options??[]]),L=null;for(let H of M){let U=vo(T,H);if(U<=2&&(!L||U<L.distance))L={name:H,distance:U}}return L?`${O}
51
- Did you mean --${L.name}?`:O}function wo(j,P){let O=new Set;for(let N of j)O.add(N.name),O.add(N.name.split(" ")[0]);let T=null;for(let N of O){let M=vo(P,N);if(M<=2&&(!T||M<T.distance))T={name:N,distance:M}}if(!T)return null;if(j.some((N)=>N.name===T.name))return T.name;let F=j.filter((N)=>N.name.startsWith(`${T.name} `)).sort((N,M)=>N.name.length-M.name.length)[0];return F?F.name:T.name}function zn(j,P){for(let O of[...j].sort((T,F)=>F.name.length-T.name.length)){let T=O.name.split(" ");if(T.every((F,N)=>P[N]===F))return{command:O,rest:P.slice(T.length)}}return null}function Ia(j,P,O){let T=Pa(j,P,O);if(!/^Unknown option '/.test(O))return T;let F=T.replace(/\. To specify a positional argument[\s\S]*?after '--'[^\n]*/,"."),N=zn(j,P.filter((M)=>!M.startsWith("-")));return N?`${F}
52
-
53
- ${N.command.usage}`:F}async function a(j,P,O){if(P.some((K)=>K==="--api-key"||K.startsWith("--api-key=")))return O.stderr("error: API keys are never accepted as command-line arguments. Run `hlix auth login` and use the hidden prompt.\n"),2;let T;try{T=$a({args:P,allowPositionals:!0,strict:!0,options:{json:{type:"boolean"},help:{type:"boolean"},version:{type:"boolean"},cwd:{type:"string"},"base-url":{type:"string"},workspace:{type:"string"},"dry-run":{type:"boolean"},"no-connect-origin":{type:"boolean"},attach:{type:"boolean"},print:{type:"boolean"},web:{type:"boolean"},"env-file":{type:"string"},include:{type:"string"},history:{type:"string"},name:{type:"string"},stack:{type:"string"},status:{type:"string"},project:{type:"string"},yes:{type:"boolean"},global:{type:"boolean"},org:{type:"boolean"},title:{type:"string"},description:{type:"string"},force:{type:"boolean"},runtime:{type:"string"},duty:{type:"string"},profile:{type:"string"},server:{type:"string"},"allow-stdio":{type:"boolean"},source:{type:"string"},format:{type:"string"},out:{type:"string"},"from-stdin":{type:"boolean"},once:{type:"boolean"}}})}catch(K){let ie=P.includes("--json"),ee=Ia(j,P,Dn(K));if(O.onFailure?.({code:"invalid_usage",message:ee,status:null}),ie)O.stdout(re(Zt("cli",{code:"invalid_usage",message:ee,status:null})));else O.stderr(`${ee}
54
- `);return 2}let F=T.values.json===!0,N=T.positionals;if(T.values.version===!0){let{version:K}=await import("./package-d2qfdjga.js");return O.stdout(`${K}
55
- `),0}if(N.length===0||T.values.help===!0){let K=zn(j,N);return O.stdout(K?`${K.command.usage}
56
- `:yo(j)),N.length===0&&T.values.help!==!0?1:0}let M=zn(j,N);if(!M){let K=N.join(" "),ie=wo(j,K)??wo(j,N[0]),ee=ie?`Unknown command: ${K}
57
- Did you mean \`hlix ${ie}\`?`:`Unknown command: ${K}`;if(O.onFailure?.({code:"unknown_command",message:ee,status:null}),F)O.stdout(re(Zt(K,{code:"unknown_command",message:ee,status:null})));else O.stderr(`${ee}
58
-
59
- ${yo(j)}`);return 2}let L=new Set(["json","help","version","cwd","workspace","base-url"]),H=new Set(M.command.options??[]),U=Object.entries(T.values).filter(([K,ie])=>ie!==void 0&&!L.has(K)&&!H.has(K)).map(([K])=>`--${K}`),D=M.command.args??{min:0,max:0},z=M.rest.length<D.min?{code:"missing_argument",message:M.command.usage.split(`
60
- `)[0]}:M.rest.length>D.max?{code:"invalid_usage",message:M.command.usage.split(`
61
- `)[0]}:null,W=typeof T.values.cwd==="string"?T.values.cwd:void 0,J=Ea(W??"."),V=W!==void 0&&!co(J)?{code:"invalid_usage",message:`--cwd is not a directory: ${J}`}:null,B=U.length>0?{code:"invalid_usage",message:`Unsupported option for ${M.command.name}: ${U.join(", ")}`}:V??z;if(B){if(O.onFailure?.({...B,status:null}),F)O.stdout(re(Zt(M.command.name,{...B,status:null})));else{let K=M.command.usage.startsWith(B.message)?M.command.usage:`${B.message}
62
-
63
- ${M.command.usage}`;O.stderr(`error: ${K}
64
- `)}return 2}let G=T.values,X={...O,args:M.rest,json:F,flags:G,cwd:J,requireClient:(K)=>n(O.env,{cwd:K??J,flags:G})};try{return await M.command.run(X)}catch(K){let{code:ie,status:ee}=_r(K);if(O.onFailure?.({code:ie,message:Dn(K),status:ee,...K instanceof e&&K.details!==void 0?{details:K.details}:{}}),F)O.stdout(re(Zt(M.command.name,{code:ie,message:Dn(K),status:ee})));else if(O.stderr(`error: ${Dn(K)}
65
- `),process.env.HLIX_DEBUG&&K instanceof Error&&K.stack)O.stderr(`${K.stack}
66
- `);return ie==="unauthenticated"||ie==="forbidden"?3:1}}import{readFileSync as Ca}from"node:fs";import{homedir as xa}from"node:os";import{join as Ra}from"node:path";var bo=20000;function p(j){if(j===void 0)return;let P=typeof j==="number"?j:Number(j.trim());return Number.isInteger(P)&&P>=bo?P:void 0}var l=["cloud","docker","local"],_a={"claude-code":!0,codex:!0,"cursor-agent":!0,hlix:!0},o=Object.keys(_a),m="hlix",ko={dockerImage:"docker sandbox only",harness:"local and docker sandboxes only",memoryTokens:"all sandboxes",model:"local and docker sandboxes only",sandbox:"all sandboxes",yolo:"all sandboxes"},Mt=["dockerImage","harness","memoryTokens","model","sandbox","yolo"],Ar=["projectId","workspaceId","apiUrl"];function Or(j=process.env){return Ra(j.HLIX_CONFIG_HOME??xa(),".hlix","config.json")}function So(j=process.env){try{let P=JSON.parse(Ca(Or(j),"utf8"));return P.schemaVersion===1?P:null}catch{return null}}function g(j,P=process.env){let O=So(P),T=t(j),F=T?.root??null,N=T?.config??null,M={},L={},H=(U)=>{let D=N?.[U],z=O?.[U];if(D!==void 0)M[U]=D,L[U]="project";else if(z!==void 0)M[U]=z,L[U]="global"};for(let U of Mt)H(U);for(let U of Ar){let D=N?.[U];if(D!==void 0)M[U]=D,L[U]="project"}return{merged:M,sources:L,global:O,project:N,paths:{global:Or(P),project:F?tn(F):null}}}function jo(j){return[...Mt,...Ar].map((O)=>({key:O,value:j.merged[O]??null,source:j.sources[O]??"default"}))}function Aa(j,P){if(j==="sandbox"&&!l.includes(P))return`sandbox must be one of ${l.join(", ")}; got "${P}".`;if(j==="harness"&&!o.includes(P))return`harness must be one of ${o.join(", ")}; got "${P}".`;if(j==="model"&&P.trim()==="")return"model must not be empty.";if(j==="memoryTokens"&&p(P)===void 0)return`memoryTokens must be a whole number of tokens, at least ${bo}; got "${P}".`;if(j==="dockerImage"&&P.trim()==="")return"dockerImage must not be empty.";if(j==="yolo"&&S(P)===void 0)return`yolo must be true or false; got "${P}".`;return null}function S(j){if(j===void 0)return;let P=j.trim().toLowerCase();if(["true","1","yes","on"].includes(P))return!0;if(["false","0","no","off"].includes(P))return!1;return}function Tr(j){if(Mt.includes(j))return j;let P=Ar.includes(j);throw new e("invalid_usage",P?`${j} is written by \`hlix init\` and \`hlix import\`, not by \`hlix config set\`.`:`Unknown setting: ${j}. Known settings: ${Mt.join(", ")}.`)}function Eo(j,P){let O=Aa(j,P);if(O)throw new e("invalid_usage",O);return P}function h(j){if(j.scope==="global"){let T=Or(j.env),F=So(j.env)??{schemaVersion:1};return Ge(T,{...F,[j.key]:j.value}),T}let P=t(j.cwd);if(!P)throw new e("not_initialized","This folder is not bound to hlix. Run `hlix init` here, or set it machine-wide with --global.");let O=tn(P.root);return Ge(O,{...P.config,[j.key]:j.value}),O}import{createHash as Oa}from"node:crypto";import{mkdirSync as Ta,readdirSync as Ro,readFileSync as Na,rmSync as Fa,statSync as _o,writeFileSync as Ma}from"node:fs";import{homedir as Ha,tmpdir as La}from"node:os";import{basename as Ao,isAbsolute as Ua,join as ue,relative as Da}from"node:path";var i=(j=process.env)=>j.HOME??j.USERPROFILE??Ha();function Re(j){try{if(!_o(j).isFile())return null;return Na(j,"utf8")}catch{return null}}function za(j){try{return _o(j).isDirectory()}catch{return!1}}function Ht(j,P){try{return Ro(j,{withFileTypes:!0}).filter((O)=>O.isFile()&&O.name.endsWith(P)).map((O)=>ue(j,O.name)).sort()}catch{return[]}}function Ba(j){try{return Ro(j,{withFileTypes:!0}).filter((P)=>P.isDirectory()||P.isSymbolicLink()).map((P)=>ue(j,P.name)).sort()}catch{return[]}}function Fr(j){let P=j.replace(/^\uFEFF/,""),O=P.indexOf(`
67
- `);if(!P.startsWith("---")||O===-1)return{fields:{},body:P.trim()};let T=P.indexOf(`
68
- ---`,O);if(T===-1)return{fields:{},body:P.trim()};let F={};for(let M of P.slice(O+1,T).split(`
69
- `)){let L=/^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(M);if(!L)continue;F[L[1]]=L[2].trim().replace(/^["']|["']$/g,"")}let N=P.indexOf(`
70
- `,T+1);return{fields:F,body:N===-1?"":P.slice(N+1).trim()}}function Wa(j){let P=j.trimStart(),O=/^"((?:[^"\\]|\\.)*)"/.exec(P)??/^'([^']*)'/.exec(P);if(O)return O[1].replace(/\\"/g,'"').replace(/\\n/g,`
71
- `);if(P.startsWith("["))return[...P.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'/g)].map((F)=>F[1]??F[2]??"");if(P.startsWith("{")){let F={};for(let N of P.matchAll(/([A-Za-z0-9_.-]+)\s*=\s*"((?:[^"\\]|\\.)*)"/g))F[N[1]]=N[2].replace(/\\"/g,'"');return F}let T=/^[^\s#]+/.exec(P)?.[0];if(T===void 0)return;if(T==="true"||T==="false")return T==="true";if(/^-?\d+(\.\d+)?$/.test(T))return Number(T);return T}function Oo(j){let P={"":{}},O="",T=j.split(`
72
- `);for(let F=0;F<T.length;F+=1){let M=T[F].trim();if(!M||M.startsWith("#"))continue;let L=/^\[\[?([^\]]+)\]\]?$/.exec(M);if(L){O=L[1].trim(),P[O]??={};continue}let H=/^([A-Za-z0-9_.-]+|"[^"]+")\s*=\s*(.*)$/.exec(M);if(!H)continue;let U=H[1].replace(/^"|"$/g,""),D=H[2];if(D.startsWith('"""')){let W=[],J=D.slice(3);if(J.includes('"""'))W.push(J.slice(0,J.indexOf('"""')));else{if(J)W.push(J);while(F+1<T.length){F+=1;let V=T[F],B=V.indexOf('"""');if(B===-1){W.push(V);continue}W.push(V.slice(0,B));break}}P[O][U]=W.join(`
73
- `).replace(/^\n/,"");continue}let z=Wa(D);if(z!==void 0)P[O][U]=z}return P}function Nr(j,P){return j.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g,(O,T,F)=>{let N=P[T];return N!==void 0&&N!==""?N:F??""})}var $o=(j,P)=>{let O={};for(let[T,F]of Object.entries(j))if(typeof F==="string")O[T]=Nr(F,P);return O},Ja=[{relative:"GEMINI.md",source:"gemini"},{relative:ue(".gemini","GEMINI.md"),source:"gemini"},{relative:".cursorrules",source:"cursor"},{relative:".windsurfrules",source:"windsurf"},{relative:ue(".github","copilot-instructions.md"),source:"copilot"}],Ga=[{relative:ue(".gemini","GEMINI.md"),source:"gemini"}],qa=[{relative:ue(".cursor","rules"),source:"cursor",extension:".mdc"},{relative:ue(".windsurf","rules"),source:"windsurf",extension:".md"}];function Ka(j,P){let O=ue(j,".clinerules"),T=za(O)?Ht(O,".md"):[O],F=[];for(let N of T){let M=Re(N)?.trim();if(M)F.push({path:N,source:"cline",scope:P,content:M})}return F}function Va(j,P,O){let{fields:T,body:F}=Fr(P);if(T.alwaysApply==="false")return{path:j,source:"cursor",scope:O,reason:"alwaysApply: false"};if(!F)return{path:j,source:"cursor",scope:O,reason:"no rule body"};let N=T.globs?.replace(/^\[|\]$/g,"").trim();return{path:j,source:"cursor",scope:O,content:F,...N?{note:`Applies to: ${N}`}:{}}}var Ya=["AGENTS.md","CLAUDE.md"],To=["",".claude"],E=["commands"];function Xa(j,P){let O=[],T=new Set;for(let F of[...To,P])for(let N of Ya){let M=ue(j,F,N),L=Re(M)?.trim();if(!L||T.has(L))continue;T.add(L),O.push({path:M,content:L})}return O}function Po(j,P){return Xa(j,P).map((O)=>O.content)}var f=["AGENTS.md","CLAUDE.md","GEMINI.md"];function Mr(j,P){for(let O of f)for(let T of[...To,P]){let F=ue(j,T,O),N=Re(F)?.trim();if(N)return{path:F,content:N}}return null}var Hr=(j=process.env)=>ue(j.HLIX_CONFIG_HOME??ue(i(j),".hlix"),"AGENTS.md");function y(j){let P=j.env??process.env,O=Hr(P),T=Re(O)?.trim();return{global:T?{path:O,content:T}:null,project:Mr(j.cwd,j.configDir)}}var Io=(j)=>{let P=Math.round(j.length/4);return P>=1000?`${(P/1000).toFixed(1)}k tokens`:`${P} tokens`};function I(j,P,O=process.env){let T=[...j.global?[Fo(j.global.path,O)]:[],...j.project?[dn(j.project.path,P)]:[]];return T.length===0?"":`rules: ${T.join(" + ")}`}function w(j,P,O=process.env,T=[]){let F=(N,M,L)=>M?`${N.padEnd(8)} ${L(M.path)} (${Io(M.content)})`:`${N.padEnd(8)} none`;return[F("user",j.global,(N)=>Fo(N,O)),F("project",j.project,(N)=>dn(N,P)),...T.map((N)=>`${"nested".padEnd(8)} ${dn(N.path,P)} (${Io(N.content)})`),"","User rules go first, the project's after, so the project wins a conflict.",T.length===0?"A subdirectory's own rules file is added when the agent first works in it.":"A nested file was added when the agent first touched a path under it.","Edit them with `hlix rules --edit` (this project) or `hlix rules --edit --global`."].join(`
74
- `)}var Co=[{dir:".claude",source:"claude",harnessReads:!0},{dir:".agents",source:"agents",harnessReads:!0},{dir:".hlix",source:"hlix",harnessReads:!0},{dir:".codex",source:"codex",harnessReads:!1}],Za=[{relative:ue(".cursor","commands"),source:"cursor"},{relative:ue(".codex","prompts"),source:"codex"}],Qa=[{relative:ue(".cursor","mcp.json"),source:"cursor",key:"mcpServers",format:"json"},{relative:ue(".windsurf","mcp.json"),source:"windsurf",key:"mcpServers",format:"json"},{relative:ue(".gemini","settings.json"),source:"gemini",key:"mcpServers",format:"json"},{relative:ue(".vscode","mcp.json"),source:"vscode",key:"servers",format:"json"},{relative:ue(".codex","config.toml"),source:"codex",key:"mcp_servers",format:"toml"},{relative:".mcp.json",source:"claude",key:"mcpServers",format:"json"}];function No(j){return[...Qa,{relative:ue(j,"mcp.json"),source:"hlix",key:"mcpServers",format:"json"}]}var ec="found, not loaded (machine-wide; enable per project by copying into .hlix/mcp.json)",tc=(j)=>No(j).filter((P)=>P.source!=="vscode");function nc(j,P){if(!j||typeof j!=="object"||Array.isArray(j))return{reason:"not an object"};let O=j;if(O.enabled===!1||O.disabled===!0)return{reason:"disabled"};let T=typeof O.command==="string"&&O.command!=="",F=typeof O.url==="string"&&O.url!=="";if(T&&F)return{reason:'has both "command" and "url"'};if(T){let H=Array.isArray(O.args)?O.args.filter((D)=>typeof D==="string"):void 0,U=O.env&&typeof O.env==="object"&&!Array.isArray(O.env)?$o(O.env,P):void 0;return{config:{command:O.command,...H&&H.length>0?{args:H}:{},...U&&Object.keys(U).length>0?{env:U}:{}}}}if(!F)return{reason:'missing "command" or "url"'};let N=O.headers??O.http_headers,M=N&&typeof N==="object"&&!Array.isArray(N)?$o(N,P):{},L=O.bearer_token_env_var;if(typeof L==="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(L)&&!Object.keys(M).some((H)=>H.toLowerCase()==="authorization"))M.Authorization=`Bearer ${Nr(`\${${L}}`,P)}`;return{config:{url:Nr(O.url,P),...Object.keys(M).length>0?{headers:M}:{}}}}function xo(j,P,O,T){let F=Re(j),N=[],M=[];if(F===null)return{servers:N,skipped:M};let L=[];if(P.format==="toml"){let H=Oo(F);L=Object.entries(H).filter(([U])=>U.startsWith(`${P.key}.`)).map(([U,D])=>[U.slice(P.key.length+1),D])}else try{let U=JSON.parse(F)?.[P.key];if(U&&typeof U==="object"&&!Array.isArray(U))L=Object.entries(U)}catch{return M.push({path:j,source:P.source,scope:O,reason:"not valid JSON"}),{servers:N,skipped:M}}for(let[H,U]of L){let D=nc(U,T);if("reason"in D){M.push({path:j,source:P.source,scope:O,reason:`${H}: ${D.reason}`});continue}N.push({path:j,source:P.source,scope:O,name:H,config:D.config})}return{servers:N,skipped:M}}function rc(j,P,O){let{fields:T,body:F}=Fr(P);if(!F)return{path:j,source:"claude",scope:O,reason:"no instructions"};let N=T.tools?.replace(/^\[|\]$/g,"").split(",").map((M)=>M.trim()).filter(Boolean);return{path:j,source:"claude",scope:O,name:T.name||Ao(j,".md"),description:T.description??"",instructions:F,...N&&N.length>0&&N[0]!=="*"?{tools:N}:{},...T.model?{model:T.model}:{}}}function sc(j){let P=Oo(j)[""]??{},O=typeof P.prompt==="string"?P.prompt.trim():"";if(!O)return null;return{description:typeof P.description==="string"?P.description:"",body:O}}function b(j,P,O={}){let T=O.configDir??".hlix",F=O.env??process.env,N={instructions:[],skills:[],commands:[],generatedCommands:[],mcpServers:[],subagents:[],skipped:[]},M=(V)=>{if("reason"in V)N.skipped.push(V);else N.instructions.push(V)};for(let V of Ja){let B=ue(j,V.relative),G=Re(B)?.trim();if(G)N.instructions.push({path:B,source:V.source,scope:"project",content:G})}for(let V of qa)for(let B of Ht(ue(j,V.relative),V.extension)){let G=Re(B);if(G===null)continue;if(V.source==="cursor"){M(Va(B,G,"project"));continue}let{body:X}=Fr(G);if(X)N.instructions.push({path:B,source:V.source,scope:"project",content:X})}for(let V of Ka(j,"project"))M(V);let L=Po(j,T),H=ue(j,".codex","AGENTS.md"),U=Re(H)?.trim();if(U&&L.includes(U))N.skipped.push({path:H,source:"codex",scope:"project",reason:"same content as the project's AGENTS.md"});else if(U)N.instructions.push({path:H,source:"codex",scope:"project",content:U});for(let V of Ga){let B=ue(P,V.relative),G=Re(B)?.trim();if(G)N.instructions.push({path:B,source:V.source,scope:"global",content:G})}let D=ue(P,".codex","AGENTS.md"),z=Re(D)?.trim(),W=Po(P,T);if(z&&W.includes(z))N.skipped.push({path:D,source:"codex",scope:"global",reason:"same content as the machine's AGENTS.md"});else if(z)N.instructions.push({path:D,source:"codex",scope:"global",content:z});for(let[V,B]of[[j,"project"],[P,"global"]])for(let G of Co){let X=ue(V,G.dir===".hlix"?T:G.dir,"skills");if(!Ba(X).some((ie)=>Re(ue(ie,"SKILL.md"))!==null))continue;N.skills.push({path:X,source:G.source,scope:B,harnessReads:G.harnessReads})}for(let[V,B]of[[j,"project"],[P,"global"]]){for(let G of Co){if(!G.harnessReads)continue;let X=ue(V,G.dir,"commands");if(Ht(X,".md").length===0)continue;N.commands.push({path:X,source:G.source,scope:B,harnessReads:!0})}for(let G of Za){let X=ue(V,G.relative);if(Ht(X,".md").length===0)continue;N.commands.push({path:X,source:G.source,scope:B})}for(let G of Ht(ue(V,".gemini","commands"),".toml")){let X=Re(G),K=X===null?null:sc(X);if(!K){N.skipped.push({path:G,source:"gemini",scope:B,reason:"no prompt field"});continue}N.generatedCommands.push({path:G,source:"gemini",scope:B,name:Ao(G,".toml"),body:`---
75
- description: ${K.description}
76
- ---
77
-
78
- ${K.body}
79
- `})}}for(let V of No(T)){let B=xo(ue(j,V.relative),V,"project",F);N.skipped.push(...B.skipped);for(let G of B.servers){let X=N.mcpServers.findIndex((K)=>K.name===G.name);if(X===-1)N.mcpServers.push(G);else N.mcpServers[X]=G}}for(let V of tc(T)){let B=xo(ue(P,V.relative),V,"global",F);for(let G of B.servers)N.skipped.push({path:G.path,source:G.source,scope:"global",reason:`${G.name}: ${ec}`})}let J=[{dir:ue(".claude","agents"),source:"claude"},{dir:ue(T,"agents"),source:"hlix"}];for(let[V,B]of[[j,"project"],[P,"global"]])for(let G of J.flatMap((X)=>Ht(ue(V,X.dir),".md"))){let X=Re(G);if(X===null)continue;let K=rc(G,X,B);if("reason"in K)N.skipped.push(K);else if(N.subagents.some((ie)=>ie.name===K.name))N.skipped.push({path:G,source:"claude",scope:B,reason:`a project agent already claims the name ${K.name}`});else N.subagents.push(K)}return N}function C(j,P){if(j.length===0)return null;let O=ue(La(),"hlix-standards-commands",Oa("sha256").update(P).digest("hex").slice(0,16));try{Fa(O,{recursive:!0,force:!0}),Ta(O,{recursive:!0});for(let T of j)Ma(ue(O,`${T.name}.md`),T.body,"utf8");return O}catch{return null}}var oc=60000,dn=(j,P)=>{let O=Da(P,j);return!O||O.startsWith("..")||Ua(O)?j:O},Fo=(j,P=process.env)=>{let O=P.HLIX_CONFIG_HOME;if(O&&j.startsWith(`${O}/`))return`~/.hlix/${j.slice(O.length+1)}`;let T=i(P);return T&&j.startsWith(`${T}/`)?`~/${j.slice(T.length+1)}`:j};function _(j,P,O=oc){if(j.length===0)return"";let T=["# Project standards from other agent tools","","These files were written for other coding agents working in this same","project. Treat them as the project's instructions and follow them."].join(`
80
- `),F=[],N=T.length,M=!1;for(let H of j){let U=`# From ${dn(H.path,P)} (${H.source})`,D=H.note?`${U}
81
- ${H.note}`:U,z=O-N-D.length-4;if(z<=0){M=!0;break}let W=H.content.length<=z?H.content:`${H.content.slice(0,z)}
82
- [truncated]`;if(W.length<H.content.length)M=!0;F.push(`${D}
83
-
84
- ${W}`),N+=D.length+W.length+4}let L=M?`
85
-
86
- [The standards block reached its ${O}-character cap; some rules above are cut short or omitted.]`:"";return`${T}
87
-
88
- ${F.join(`
89
-
90
- `)}${L}`}var ln=(j,P,O)=>`${j} ${j===1?P:O}`;function A(j){let P=[];if(j.instructions.length>0)P.push(ln(j.instructions.length,"instruction file","instruction files"));if(j.skills.length>0)P.push(ln(j.skills.length,"skill directory","skill directories"));let O=j.commands.length+j.generatedCommands.length;if(O>0)P.push(ln(O,"command source","command sources"));if(j.mcpServers.length>0)P.push(ln(j.mcpServers.length,"mcp server","mcp servers"));if(j.subagents.length>0)P.push(ln(j.subagents.length,"subagent","subagents"));if(P.length===0)return"";let T=[...new Set([...j.instructions,...j.skills,...j.commands,...j.generatedCommands,...j.mcpServers,...j.subagents].map((F)=>F.source))].sort();return`standards: ${P.join(" · ")} (${T.join(", ")})`}function Mo(j,P){let O=[],T=(N,M)=>{if(M.length===0)return;O.push(N,...M.map((L)=>` ${L}`),"")},F=(N)=>`${N.source}${N.scope==="global"?" (global)":""} ${dn(N.path,P)}`;if(T("Instructions",j.instructions.map((N)=>`${F(N)}${N.note?` — ${N.note}`:""}`)),T("Skills",j.skills.map((N)=>`${F(N)}${N.harnessReads?" — already read by the harness":""}`)),T("Commands",[...j.commands.map((N)=>`${F(N)}${N.harnessReads?" — already read by the harness":""}`),...j.generatedCommands.map((N)=>`${F(N)} → /${N.name}`)]),T("MCP servers",j.mcpServers.map((N)=>`${F(N)} → ${N.name} (${"command"in N.config?"stdio":"http"})`)),T("Subagents",j.subagents.map((N)=>`${F(N)} → ${N.name}`)),T("Skipped",j.skipped.map((N)=>`${F(N)} — ${N.reason}`)),O.length===0)return`No standards from other agent tools were found in this folder.
91
- `;return`${O.join(`
92
- `).trimEnd()}
93
- `}async function ic(j,P,O){let T=P.map((L)=>L.id);if(O){if(!T.includes(O))throw new e("workspace_mismatch",P.length===0?`This key belongs to a user who is not a member of any workspace, including ${O}.`:`This key cannot act in workspace ${O}. Available: ${T.join(", ")}.`);return O}if(P.length===0)throw new e("workspace_required","This key belongs to a user who is not a member of any workspace. Create or join one first.");let F=P[0];if(F&&P.length===1)return j.stderr(`Using your only workspace: ${F.name} (${F.id})
94
- `),F.id;if(j.json||!j.promptChoice)throw new e("missing_argument",`--workspace is required here: this key can act in ${P.length} workspaces. Pass one of: ${T.join(", ")}.`);let N=Math.max(...P.map((L)=>L.name.length));j.stderr(`${P.map((L,H)=>` ${H+1}) ${L.name.padEnd(N)} ${L.slug} ${L.role} ${L.id}`).join(`
95
- `)}
96
- `);let M=await j.promptChoice(`Workspace [1-${P.length}]: `,P.length);return T[M]}var Lr={name:"auth login",summary:"Verify and store a credential for this machine",usage:["Usage: hlix auth login [--workspace <id>] [--base-url <url>]",""," --base-url Defaults to https://server.hlix.ai"," --workspace Workspace (organization) id to act in. Optional: the key's"," own workspaces are listed after it is read, and the only"," one is taken automatically.","","The API key is read from a hidden prompt and never accepted as an argument.","For CI, set HLIX_API_KEY and HLIX_WORKSPACE_ID in the environment."].join(`
97
- `),supportsJson:!0,options:["base-url","workspace"],async run(j){let P=typeof j.flags.workspace==="string"?j.flags.workspace:j.env.HLIX_WORKSPACE_ID,O=j.env.HLIX_API_KEY??await j.readSecret?.("Hlix API key: ")??"";if(!O)throw new e("missing_credential","No API key entered. Run from a terminal or set HLIX_API_KEY for CI.");let T=typeof j.flags["base-url"]==="string"?j.flags["base-url"]:j.env.HLIX_BASE_URL??kr,F=new URL(T),N=F.hostname==="localhost"||F.hostname==="127.0.0.1"||F.hostname==="::1";if(F.protocol!=="https:"&&!(F.protocol==="http:"&&N))throw new e("invalid_base_url","--base-url must use HTTPS (HTTP is allowed only for localhost).");let M=new Ft({baseUrl:T,credential:At(O),retry:{attempts:1}}),L=await ic(j,await M.workspaces.list(),P);await new Ft({baseUrl:T,credential:At(O),organizationId:L,retry:{attempts:1}}).projects.list();let U=ro({baseUrl:T,apiKey:O,organizationId:L},j.env);if(j.json)j.stdout(re(se(Lr.name,{baseUrl:T,organizationId:L,credentialPath:U})));else j.stdout(`Signed in to ${T}
98
- Credential stored at ${U}
99
- `);return 0}},Ur={name:"auth status",summary:"Show which credential is in use, where it came from, and whether it works",usage:["Usage: hlix auth status [--json]","","Names the SOURCE of the credential — the stored file, HLIX_API_KEY, or the","desktop app's own session when hlix was opened from its Terminal tab — and","verifies it against the API. The credential itself is never printed, not even","a prefix: machine output gets piped into logs."].join(`
100
- `),supportsJson:!0,async run(j){let P=r({env:j.env,flags:j.flags,cwd:j.cwd});if(P.conflict)throw new e("workspace_mismatch",P.conflict);if(!P.credential)throw new e("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");try{await j.requireClient().projects.list()}catch(T){throw j.stderr(`credential from ${P.credentialSource}, workspace ${P.workspaceId??"none"}, api ${P.baseUrl}
101
- `),T}let O={credentialSource:P.credentialSource,credentialPath:P.credentialSource==="file"?P.credentialPath:null,baseUrl:P.baseUrl,baseUrlSource:P.baseUrlSource,workspaceId:P.workspaceId,workspaceSource:P.workspaceSource,valid:!0};if(j.json)return j.stdout(re(se(Ur.name,O))),0;return j.stdout(`${ye([["credential",u(P)??"none"],["api",`${P.baseUrl} (from ${P.baseUrlSource})`],["workspace",P.workspaceId?`${P.workspaceId} (from ${P.workspaceSource})`:"none"],["status","valid"]])}
102
- `),0}},Lt={name:"auth logout",summary:"Remove the stored credential from this machine",usage:["Usage: hlix auth logout [--yes] [--json]","","Removes ~/.config/hlix/credentials.json after confirming. A credential","supplied through HLIX_API_KEY is not removed — unset it in the shell that","set it — and neither is the desktop app's own session; sign out in the app."].join(`
103
- `),supportsJson:!0,options:["yes"],async run(j){let P=r({env:j.env,flags:j.flags,cwd:j.cwd});if(P.credentialSource==="env"||P.credentialSource==="session"){let T=P.credentialSource==="session",F=T?"session":"environment",N=T?"This session belongs to the Hlix desktop app; sign out there to end it.":"HLIX_API_KEY is set in this environment; unset it there to sign out.",M=no(j.env);if(!M){let H={removed:!1,reason:F,path:null};if(j.json)j.stdout(re(se(Lt.name,H)));else j.stdout(`${N}
104
- `);return 0}if(j.flags.yes!==!0){let H={removed:!1,reason:F,path:M};if(j.json)j.stdout(re(se(Lt.name,H)));else j.stdout(`${N}
105
- A stored credential also exists at ${M} — repeat with --yes to remove it.
106
- `);return 0}let L=hr(j.env);if(j.json)j.stdout(re(se(Lt.name,L)));else j.stdout(`Removed ${L.path}
107
- ${T?"The desktop app's session is still in use; sign out there to finish.":"HLIX_API_KEY is still set in this environment; unset it there to finish signing out."}
108
- `);return 0}if(j.flags.yes!==!0&&P.credential){if(j.json||!j.confirm)throw new e("approval_required","Removing the stored credential needs approval. Repeat with `--yes`.");if(!await j.confirm(`Remove the stored credential at ${P.credentialPath}? Signing back in needs the API key again.`))throw new e("cancelled","Logout cancelled.")}let O=hr(j.env);if(j.json)j.stdout(re(se(Lt.name,O)));else j.stdout(O.removed?`Removed ${O.path}
109
- `:`No stored credential at ${O.path}
110
- `);return 0}};var Ho=Mt.join(" | "),Dr={name:"config list",summary:"Show every setting in effect and which file supplied it",usage:["Usage: hlix config list [--cwd <dir>] [--json]","","Merges the machine-wide file with this folder's, per key, and names the","source of each value: project, global, or default (no file names it)."].join(`
111
- `),supportsJson:!0,async run(j){let P=g(j.cwd,j.env),O=jo(P);if(j.json)return j.stdout(re(se(Dr.name,{settings:O,paths:P.paths}))),0;return j.stdout(`${Je(["setting","value","source","applies to"],O.map((T)=>[T.key,T.value??"-",T.source,ko[T.key]??"this folder's binding"]))}
112
- `),j.stdout(`
113
- global ${P.paths.global}
114
- `),j.stdout(`project ${P.paths.project??"- (this folder is not bound to hlix)"}
115
- `),0}},zr={name:"config get",summary:"Print one setting's effective value",usage:[`Usage: hlix config get <${Ho}> [--cwd <dir>] [--json]`,"","Prints the value the cascade resolves for one key, or exits 1 when no","file names it."].join(`
116
- `),supportsJson:!0,args:{min:1,max:1},async run(j){let P=Tr(j.args[0]),O=g(j.cwd,j.env),T=O.merged[P]??null,F=O.sources[P]??"default";if(j.json)return j.stdout(re(se(zr.name,{key:P,value:T,source:F}))),T===null?1:0;if(T===null)return j.stderr(`${P} is not set. Set it with \`hlix config set ${P} <value>\`.
117
- `),1;return j.stdout(`${T}
118
- `),0}},Br={name:"config set",summary:"Set one setting for this folder, or for the machine with --global",usage:[`Usage: hlix config set <${Ho}> <value> [--global] [--cwd <dir>] [--json]`,"","Writes this folder's .hlix/config.json, or the machine-wide file with","--global. Other keys in the file are left untouched. The binding keys","(projectId, workspaceId, apiUrl) are written by init/import and are","refused here."].join(`
119
- `),supportsJson:!0,options:["global"],args:{min:2,max:2},async run(j){let P=Tr(j.args[0]),O=Eo(P,j.args[1]),T=j.flags.global===!0?"global":"project",F=h({key:P,value:O,scope:T,cwd:j.cwd,env:j.env});if(j.json)return j.stdout(re(se(Br.name,{key:P,value:O,scope:T,path:F}))),0;return j.stdout(`${P} = ${O} (${T}: ${F})
120
- `),0}};function yt(j,P){if(typeof j!=="object"||j===null)return"";let O=j[P];return O===null||O===void 0?"":String(O)}var Wr={name:"projects list",summary:"List the projects in your workspace",usage:"Usage: hlix projects list [--json]",supportsJson:!0,async run(j){let P=await j.requireClient().projects.list();if(j.json)return j.stdout(re(se(Wr.name,P))),0;let O=Array.isArray(P)?P:[];if(O.length===0)return j.stdout(`No projects.
121
- `),0;return j.stdout(`${Je(["ID","NAME","STACK"],O.map((T)=>[yt(T,"id"),yt(T,"name"),yt(T,"stack")]))}
122
- `),0}},Jr={name:"projects get",summary:"Show one project, defaulting to the one this folder is bound to",usage:["Usage: hlix projects get [project-id] [--json]","","With no id, the project this folder is bound to is used."].join(`
123
- `),supportsJson:!0,args:{min:0,max:1},async run(j){let P=j.args[0]??t(j.cwd)?.config.projectId;if(!P)throw new e("missing_argument","A project id is required, or run this inside a folder bound to a project.");let O=await j.requireClient().projects.get(P);if(j.json)return j.stdout(re(se(Jr.name,O))),0;let T=O.repos;return j.stdout(`${ye([["id",yt(O,"id")],["name",yt(O,"name")],["stack",yt(O,"stack")],["status",yt(O,"status")],["repos",Array.isArray(T)?String(T.length):""]].filter(([,F])=>F!==""))}
124
- `),0}},Gr={name:"projects delete",summary:"Delete a project from your workspace",usage:"Usage: hlix projects delete <id|name> [--yes] [--json]",supportsJson:!0,options:["yes"],args:{min:1,max:1},async run(j){let P=j.requireClient(),O=j.args[0],T=await P.projects.list(),F=T.find((U)=>U.id===O),N=F?[F]:T.filter((U)=>U.name===O);if(N.length===0)throw new e("not_found",`No project named or identified by "${O}".`);if(N.length>1)throw new e("invalid_usage",`More than one project is named "${O}". Use its ID.`);let M=N[0],L=`Delete project "${M.name}"?`;if(j.stderr(`${L}
125
- `),j.flags.yes!==!0){if(t(j.cwd)?.config.projectId===M.id)throw new e("approval_required","This folder is bound to that project. Pass --yes to delete it.");if(j.json||!j.confirm)throw new e("approval_required","Project deletion requires --yes when not interactive.");if(!await j.confirm(L))throw new e("cancelled","Project deletion cancelled.")}let H=await P.projects.delete(M.id);if(j.json)j.stdout(re(se(Gr.name,H)));else j.stdout(`Deleted project "${M.name}".
126
- `);return 0}};function qr(j,P){let O=j.args[0];if(!O)throw new e("missing_argument",`A ${P} id is required.`);return O}function Lo(j,P){let O=j.flags[P];return typeof O==="string"&&O.trim()?O.trim():void 0}function Fe(j,P){if(typeof j!=="object"||j===null)return"";let O=j[P];return O===null||O===void 0?"":String(O)}var Kr={name:"tasks list",summary:"List tasks, defaulting to the project this folder is bound to",usage:["Usage: hlix tasks list [--project <id>] [--status <status>] [--json]","","With no --project, a folder bound to a project lists that project's tasks;","anywhere else it lists the workspace's tasks."].join(`
127
- `),supportsJson:!0,options:["project","status"],async run(j){let P=Lo(j,"project")??t(j.cwd)?.config.projectId,O=Lo(j,"status"),T=await j.requireClient().tasks.list({...P?{projectId:P}:{},...O?{status:O}:{}});if(j.json)return j.stdout(re(se(Kr.name,T))),0;let F=Array.isArray(T)?T:[];if(F.length===0)return j.stdout(`No tasks.
128
- `),0;return j.stdout(`${Je(["ID","STATUS","TITLE"],F.map((N)=>[Fe(N,"id"),Fe(N,"status"),Fe(N,"title")||Fe(N,"description").split(`
129
- `)[0]||""]))}
130
- `),0}},Vr={name:"tasks get",summary:"Show one task",usage:"Usage: hlix tasks get <task-id> [--json]",supportsJson:!0,args:{min:1,max:1},async run(j){let P=qr(j,"task"),O=await j.requireClient().tasks.get(P);if(j.json)return j.stdout(re(se(Vr.name,O))),0;return j.stdout(`${ye([["id",Fe(O,"id")],["status",Fe(O,"status")],["title",Fe(O,"title")],["project",Fe(O,"projectId")],["description",Fe(O,"description")]])}
131
- `),0}},Yr={name:"tasks review",summary:"Show the verified review evidence for a task",usage:"Usage: hlix tasks review <task-id> [--json]",supportsJson:!0,args:{min:1,max:1},async run(j){let P=qr(j,"task"),O=await j.requireClient().tasks.review(P);if(j.json)return j.stdout(re(se(Yr.name,O))),0;return j.stdout(`${JSON.stringify(O,null,2)}
132
- `),0}},Xr={name:"tasks watch",summary:"Stream a task's status changes until it finishes",usage:["Usage: hlix tasks watch <task-id> [--json]","","Streams the task's server-sent status frames and exits when the task","reaches a terminal status or the server closes the stream.","","With --json, each frame is printed as one envelope per line (JSONL) so a","consumer can read them as they arrive."].join(`
133
- `),supportsJson:!0,args:{min:1,max:1},async run(j){let P=qr(j,"task"),O=j.requireClient();for await(let T of O.tasks.stream(P)){let F;try{F=JSON.parse(T.data)}catch{F=T.data}if(j.json)j.stdout(`${JSON.stringify(se(Xr.name,F))}
134
- `);else{let N=Fe(F,"status"),M=Fe(F,"error");j.stdout(M?`error: ${M}
135
- `:`${N||T.data}
136
- `)}}return 0}};import{realpath as jl}from"node:fs/promises";import{resolve as El}from"node:path";import{parse as pc}from"jsonc-parser";import{parse as mc}from"smol-toml";import{parse as fc}from"yaml";var ac={install:null,previewCommand:null,previewPort:null,verifyCommand:null,packageManager:null},cc=[["next",3000],["nuxt",3000],["@remix-run/dev",5173],["@sveltejs/kit",5173],["astro",4321],["@angular/cli",4200],["gatsby",8000],["expo",8081],["react-scripts",3000],["vite",5173]],lc=["test","typecheck","check","lint"],dc=["dev","start","serve","preview"];function Uo(j){let P=new Set(j.rootFiles),O={};if(j.packageJson)try{let z=JSON.parse(j.packageJson);if(z&&typeof z==="object")O=z}catch{}let T=typeof O.packageManager==="string"?O.packageManager.split("@")[0]:"",F=T==="bun"||P.has("bun.lock")||P.has("bun.lockb")?"bun":T==="pnpm"||P.has("pnpm-lock.yaml")?"pnpm":T==="yarn"||P.has("yarn.lock")?"yarn":T==="npm"||P.has("package.json")?"npm":null;if(!F)return ac;let N=wt(O.scripts)?O.scripts:{},M=(z)=>`${F} run ${z}`,L=dc.find((z)=>typeof N[z]==="string"),H=lc.find((z)=>typeof N[z]==="string"),U={...wt(O.dependencies)?O.dependencies:{},...wt(O.devDependencies)?O.devDependencies:{}},D=L?uc(String(N[L]))??cc.find(([z])=>(z in U))?.[1]??null:null;return{install:`${F} install`,previewCommand:L?M(L):null,previewPort:D,verifyCommand:H?M(H):null,packageManager:F}}function uc(j){let P=j.match(/(?:--port(?:=|\s+)|-p\s+|\bPORT=)(\d{2,5})\b/),O=P?Number(P[1]):NaN;return Number.isInteger(O)&&O>0&&O<=65535?O:null}function wt(j){return Boolean(j)&&typeof j==="object"&&!Array.isArray(j)}function Do(j){let P=new Set(j.rootFiles),O=new Set;if(P.has("package.json")){for(let F of["coverage",".cache"])O.add(F);if(["package-lock.json","pnpm-lock.yaml","yarn.lock","bun.lock","bun.lockb"].some((F)=>P.has(F)))O.add("node_modules")}if(P.has("Cargo.toml"))O.add("target");if(["pyproject.toml","requirements.txt","setup.py"].some((F)=>P.has(F)))O.add("__pycache__");if(P.has("composer.json")&&P.has("composer.lock"))O.add("vendor");for(let F of Zr({...j,rootFiles:P}))O.add(F);return[...O].sort()}function ze(j,P,O){let T=(j.match(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`|\/\*[\s\S]*?\*\/|\/\/[^\n]*|[A-Za-z_$][\w$]*|[^\s]/g)??[]).filter((H)=>!H.startsWith("//")&&!H.startsWith("/*"));if(T[0]!=="{"){let H=T.findIndex((D,z)=>D==="export"&&T[z+1]==="default"),U=T.findIndex((D,z)=>D==="module"&&T.slice(z+1,z+4).join("")===".exports=");if(H<0&&U<0)return null;if(T=T.slice(H>=0?H+2:U+4),["defineConfig","defineNuxtConfig"].includes(T[0]??"")&&T[1]==="(")T=T.slice(2);if(T[0]!=="{")return null}if(T.some((H,U)=>H==="."&&T[U+1]==="."&&T[U+2]==="."))return null;let F=(H="")=>H.replace(/^["']|["']$/g,""),N=[],M,L=0;for(let H=0;H<T.length;H++){let U=T[H];if(U==="{")N.push(T[H-1]===":"?F(T[H-2]):"");if(U==="}")N.pop();if(!N.length)break;if(U==="["&&["{",","].includes(T[H-1]??""))return null;if(P&&N.length===1&&F(U)===P){if(T[H+1]!==":"||T[H+2]!=="{"||++L>1)return null}if(F(U)===O&&(P?N.length===2&&N.at(-1)===P:N.length===1)&&T[H+1]!==":")return null;if(F(U)!==O||T[H+1]!==":"||(P?N.length!==2||N.at(-1)!==P:N.length!==1))continue;let D=T[H+2]??"";if(M!==void 0||!/^["'`][^\\$]*["'`]$/.test(D)||![",","}"].includes(T[H+3]??""))return null;M=D.slice(1,-1)}return M}function Zr(j){let P={};try{let W=JSON.parse(j.packageJson??"{}");if(wt(W))P=W}catch{}let O={...wt(P.dependencies)?P.dependencies:{},...wt(P.devDependencies)?P.devDependencies:{}},T=wt(P.scripts)?Object.entries(P.scripts).filter((W)=>typeof W[1]==="string"):[],F=(W,J=W)=>(W in O)||T.some(([,V])=>new RegExp(`(?:^|[;&|\\s])${J}(?:\\s|$)`).test(V)),N=j.configFiles??{},M=new Set,L=(W)=>{if(typeof W!=="string")return null;let J=W.replace(/^\.\//,"").replace(/\/$/,"");return J&&!J.startsWith("/")&&!/[\\:*?\[\]#!$`"'\r\n]/.test(J)&&!J.split("/").some((V)=>!V||[".","..",".git",".hlix"].includes(V))?J:null},H=(W)=>{let J=L(W);if(J)M.add(J)},U=(W,J)=>{let V=T.filter(([K,ie])=>/(?:^|:)build(?:$|:)/.test(K)||new RegExp(`\\b${W} build\\b`).test(ie)),B=V.filter(([,K])=>new RegExp(`(?:^|\\s)${W}(?:\\s|$)`).test(K));if(!B.length&&(V.length||P.workspaces!==void 0))return null;if(V.some((K)=>!B.includes(K)&&/--(?:out|dist|root|config|project)|\s-[dpc]\b/.test(K[1])))return null;let G,X=!1;for(let[,K]of B){if(/[$`\\;|<>\n]/.test(K)||/(?:^|\s)(?:cd|pushd|popd)\s/.test(K))return null;for(let ie of K.split("&&")){let ee=ie.match(/"[^"\n]*"|'[^'\n]*'|[^\s]+/g)??[];if(ee.some((te)=>/["']/.test(te)&&!/^(?:"[^"\n]*"|'[^'\n]*')$/.test(te)))return null;let Z=ee.map((te)=>te.replace(/^["']|["']$/g,"")),q=Z.indexOf(W);if(q<0)continue;if(q!==0&&!(q===1&&["npx","bunx"].includes(Z[0])))return null;let ne=Z.slice(q+1);if(ne[0]==="build")ne.shift();let Q;for(let te=0;te<ne.length;te++){let[pe,...me]=ne[te].split("="),fe=me.length?me.join("="):void 0;if(!J.includes(pe)||Q!==void 0)return null;let $e=fe??ne[++te],Se=L($e);if(!Se)return null;Q=Se}if(X&&Q!==G)return null;X=!0,G=Q}}return G},D=(W)=>{let J=[...new Set([...j.rootFiles,...Object.keys(N)])].filter((V)=>V.startsWith(`${W}.config.`)||W==="turbo"&&V==="turbo.json");if(!J.length)return"{}";return J.length===1?N[J[0]]??null:null},z=(W,J,V,B,G,X,K)=>{let ie=D(W),ee=U(W,G);if(ie===null||ee===null)return;let Z=X?ze(ie,null,X):void 0,q=ze(ie,J,V);if(Z===null||q===null)return;let ne=Z===void 0||Z==="."||Z==="./"?"":L(Z);if(ne===null)return;let te=L(ee??q??B);if(!te)return;H(ne?`${ne}/${te}`:te);for(let pe of K??[])H(ne?`${ne}/${pe}`:pe)};if(F("vite"))z("vite","build","outDir","dist",["--outDir","--out-dir"],"root");if(F("next")){let W=D("next"),J=W===null?null:ze(W,null,"output");if(W!==null&&(J===void 0||J==="standalone"||J==="export"&&ze(W,null,"distDir")===void 0))z("next",null,"distDir",".next",[],void 0,J==="export"?["out"]:[])}if(F("astro"))z("astro",null,"outDir","dist",["--outDir","--out-dir"],"root");if(F("nuxt")){let W=D("nuxt");if(W!==null&&ze(W,null,"nitro")===void 0&&ze(W,null,"extends")===void 0)z("nuxt",null,"buildDir",".nuxt",[],"rootDir",[".output"])}if(F("turbo"))z("turbo",null,"cacheDir",".turbo",["--cache-dir"]);if(F("webpack")){let W=D("webpack");if(W!==null&&ze(W,null,"context")===void 0)z("webpack","output","path","dist",["--output-path"])}if(F("rollup"))z("rollup","output","dir",void 0,["--dir","-d"]);if(F("parcel")||F("parcel-bundler","parcel")){let W=U("parcel",["--dist-dir"]);if(W!==null&&P.targets===void 0&&!["main","module","browser"].some((J)=>typeof P[J]==="string"))H(W??"dist")}if(F("react-scripts")&&U("react-scripts",[])!==null)H("build");if(F("typescript","tsc")){let W=U("tsc",["--outDir"]),J=Object.keys(N).filter((V)=>/^tsconfig(?:\.[^/]*)?\.json$/.test(V));if(W!==null&&J.length===1&&J[0]==="tsconfig.json"){let V=N["tsconfig.json"];if(ze(V,null,"extends")===void 0&&ze(V,null,"references")===void 0){let B=ze(V,"compilerOptions","outDir");if(B!==null)H(W??B)}}}if(Qr(N)){H("build"),H("dist");for(let W of j.rootFiles)if(W.endsWith(".egg-info"))H(W)}return[...M].sort()}function Qr(j){let P=(j["pyproject.toml"]??"").split(/^\[build-system\]\s*$/m)[1]?.split(/^\[/m)[0]??"";return/^build-backend\s*=\s*["'][^"']+["']/m.test(P)||/(?:from\s+(?:setuptools|distutils.core)\s+import\s+.*\bsetup\b|(?:setuptools|distutils.core)\.setup\s*\()/.test(j["setup.py"]??"")}var be=(j)=>j&&typeof j==="object"&&!Array.isArray(j)?j:{},Ut=(j)=>Array.isArray(j)?j.filter((P)=>typeof P==="string"):[];function zo(j){let P=[];function O(ee,Z="json"){let q=j.get(ee);if(!q)return{};try{if(Z==="yaml")return be(fc(q,{maxAliasCount:50}));if(Z==="toml")return be(mc(q));if(Z==="jsonc"){let ne=[],Q=pc(q,ne,{allowTrailingComma:!0});if(ne.length)throw Error("invalid JSONC");return be(Q)}return be(JSON.parse(q))}catch{return P.push(`Could not parse ${ee}`),{}}}let T=[...j.keys()].sort(),F=O("package.json"),N=Uo({packageJson:j.get("package.json")??null,rootFiles:T.filter((ee)=>!ee.includes("/"))}),M=typeof F.packageManager==="string"?/^(npm|pnpm|yarn|bun)@(.+)$/.exec(F.packageManager):null,L=Object.create(null);for(let[ee,Z]of Object.entries(be(F.engines)))if(typeof Z==="string")L[ee]=Z;if(M)L[M[1]]=M[2].split("+")[0];let H=O("composer.json"),U={...be(H["require-dev"]),...be(H.require)},D={...typeof U.php==="string"?{constraint:U.php}:{},extensions:Object.keys(U).filter((ee)=>ee.startsWith("ext-")).map((ee)=>ee.slice(4)).sort()};for(let[ee,Z]of[[".nvmrc","node"],[".node-version","node"],[".python-version","python"],[".php-version","php"],[".bun-version","bun"]]){let q=j.get(ee)?.trim();if(q)L[Z]=q}for(let ee of(j.get(".tool-versions")??"").split(/\r?\n/)){let[Z,q]=ee.replace(/#.*/,"").trim().split(/\s+/);if(Z&&q)L[Z==="nodejs"?"node":Z]=q}for(let ee of[".mise.toml","mise.toml"])for(let[Z,q]of Object.entries(be(O(ee,"toml").tools)))if(typeof q==="string"||typeof q==="number")L[Z]=String(q);else P.push(`Unsupported tool version for ${Z} in ${ee}`);let z=[];for(let ee of T.filter((Z)=>/(^|\/)package.json$/.test(Z))){let Z=ee==="package.json"?F:O(ee),q={...be(Z.dependencies),...be(Z.devDependencies)};for(let ne of["nuxt","next","astro","@sveltejs/kit","vite"])if(ne in q)z.push({path:ee,name:ne})}for(let[ee,Z]of[["yiisoft/yii2","yii2"],["laravel/framework","laravel"]])if(ee in U)z.push({path:"composer.json",name:Z});let W=new Set,J=Object.create(null);function V(ee,Z){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(ee))return;if(W.add(ee),/(?:^|_)HOST$/.test(ee)&&typeof Z==="string"&&/^[a-zA-Z0-9_.-]+$/.test(Z))J[ee]=Z}for(let ee of T.filter((Z)=>/(^|\/)\.env\.(example|sample|template)$/.test(Z)))for(let Z of(j.get(ee)??"").split(/\r?\n/)){let q=/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*(?:#.*)?$/.exec(Z);if(q)V(q[1],q[2].replace(/^['"]|['"]$/g,""))}let B=[],G=[];for(let ee of T.filter((Z)=>/(^|\/)(?:docker-compose|compose)(?:[.-][^/]*)?\.ya?ml$/.test(Z)))for(let[Z,q]of Object.entries(be(O(ee,"yaml").services))){let ne=be(q),Q=typeof ne.image==="string"?ne.image:"",te=Q.split("/").at(-1)?.split(/[:@]/)[0],pe=te==="mysql"||te==="mariadb"?"mysql":te==="postgres"?"postgres":te==="redis"?"redis":null;if(pe)B.push({file:ee,name:Z,kind:pe,image:Q});else if(te!=="traefik"&&te!=="nginx"&&te!=="caddy")G.push({file:ee,name:Z});for(let[me,fe]of Object.entries(be(ne.environment)))V(me,fe);for(let me of Ut(ne.environment)){let fe=me.indexOf("=");V(fe<0?me:me.slice(0,fe),fe<0?null:me.slice(fe+1))}}let X=T.find((ee)=>ee===".devcontainer/devcontainer.json")??T.find((ee)=>ee==="devcontainer.json"),K;if(X){let ee=O(X,"jsonc");for(let Z of[ee.containerEnv,ee.remoteEnv])for(let[q,ne]of Object.entries(be(Z)))V(q,ne);K={...typeof ee.image==="string"?{image:ee.image}:{},services:[...typeof ee.service==="string"?[ee.service]:[],...Ut(ee.runServices)],ports:Array.isArray(ee.forwardPorts)?ee.forwardPorts.filter((Z)=>Number.isInteger(Z)&&Number(Z)>0&&Number(Z)<=65535):[],commands:[ee.onCreateCommand,ee.updateContentCommand,ee.postCreateCommand,ee.postStartCommand].filter((Z)=>typeof Z==="string")}}let ie=Ut(F.workspaces).length?Ut(F.workspaces):Ut(be(F.workspaces).packages);return ie.push(...Ut(O("pnpm-workspace.yaml","yaml").packages)),{language:j.has("package.json")?"typescript":j.has("pyproject.toml")||j.has("requirements.txt")?"python":j.has("go.mod")?"go":j.has("Cargo.toml")?"rust":j.has("composer.json")?"php":j.has("Gemfile")?"ruby":"other",commands:N,packageManager:M?{name:M[1],version:M[2]}:N.packageManager?{name:N.packageManager}:null,lockfiles:T.filter((ee)=>/(^|\/)(bun.lockb?|pnpm-lock.yaml|yarn.lock|package-lock.json|composer.lock|uv.lock|poetry.lock|Pipfile.lock|Cargo.lock|Gemfile.lock)$/.test(ee)),toolchain:L,php:D,workspaces:[...new Set(ie)].sort(),frameworks:z,turbo:j.has("turbo.json")||"turbo"in be(F.devDependencies)||"turbo"in be(F.dependencies),services:B,unsupportedServices:G,envKeys:[...W].sort(),envHosts:J,...K?{devcontainer:K}:{},warnings:P}}import{createHash as vn}from"node:crypto";import{createReadStream as Ic}from"node:fs";import{lstat as ai,mkdir as Cc,readFile as yn,readdir as xc,readlink as Rc,realpath as ci,stat as li,writeFile as _c}from"node:fs/promises";import{basename as bt,dirname as Ac,join as bn,relative as qn,resolve as Kn,sep as Oc}from"node:path";import{execFile as Tc,spawnSync as Nc}from"node:child_process";import hn from"ignore";import{createReadStream as gc}from"node:fs";import{lstat as Bt,mkdtemp as hc,readFile as es,readdir as Jn,rename as yc,rm as wc,writeFile as vc}from"node:fs/promises";import{join as _e}from"node:path";import Bo from"ignore";function Dt(j,P){if(Array.isArray(P))return P.some((O)=>Dt(j,O));if(!P||j.split("/").some((O)=>O===".git"||O===".hlix"))return!1;return j===P||j.startsWith(`${P}/`)}function un(j,P){if(typeof P!=="string")return P?.some((O)=>un(j,O))??!1;return Dt(j,P)||P.startsWith(`${j}/`)}function Bn(j,P,O,T){let F=new Map,N=j.length,M=0;for(let D of j){let z=D.path.indexOf("/"),W=z<0?D.path:D.path.slice(0,z+1),J=F.get(W)??{count:0,bytes:0,included:!1};J.count++,J.bytes+=D.size??0,J.included||=Dt(D.path,T),F.set(W,J),M+=D.size??0}let L=M>O,H=[...F].sort(([D,z],[W,J])=>Number(z.included)-Number(J.included)||(L?J.bytes-z.bytes:J.count-z.count)||D.localeCompare(W)),U=[];for(let[D,z]of H){if(N<=P&&M<=O)break;U.push(D),N-=z.count,M-=z.bytes}return U}function zt(j,P){return P.some((O)=>j===O||O.endsWith("/")&&j.startsWith(O))}function pn(j){return`upload limit; add /${j} to .hlixignore, or try --include ${j.replace(/\/$/,"")}`.slice(0,200)}function Wn(j){if(j.length<=5000)return j;return[...j.slice(0,4999),{path:j[4999].path,reason:`${j.length-4999} additional skipped paths (including this path); full list: hlix import --dry-run --json`}]}var Go="# --- managed by Hlix: safe to edit above/below, this block is regenerated ---",ts="# --- end managed by Hlix ---",Gn=new Set(["agent-artifacts",".context",".claude/worktrees"]),bc=/(?:^|\/)(?:Makefile|Dockerfile|Containerfile|Justfile|Rakefile|Gemfile)(?:\.[^/]*)?$/i,kc=/\.(?:md|txt|json)$/i,Wo=/(?:^|\n)\s*(?:\/\/|\/\*+|\*|#|<!--)\s*(?:@generated\b|generated by\b|do not edit\b)|(?:^|\n)\s*\/\/[#@]\s*sourceMappingURL=/i,Jo=/\.(?:log(?:\.\d+)?|tmp|cache|pyc|tsbuildinfo|map)$/i;function mn(j){let P=[...j.matchAll(new RegExp(`^${Go}\\r?$`,"gm"))],O=[...j.matchAll(new RegExp(`^${ts}\\r?$`,"gm"))];if(!P.length&&!O.length)return{before:j,after:"",managed:""};if(P.length!==1||O.length!==1||O[0].index<P[0].index)return null;let T=P[0].index,N=O[0].index+ts.length,M=j.slice(N).match(/^\r?\n/)?.[0]??"";return{before:j.slice(0,T),after:j.slice(N+M.length),managed:j.slice(T,N)}}function ns(j){let P=mn(j);return(P?P.before+`
137
- `+P.after:j).split(/\r?\n/).filter((O)=>O.startsWith("!")&&O.length>1).map((O)=>O.slice(1))}async function qo(j,P){let O=_e(j,".hlixignore"),T="";try{let F=await Bt(O).catch((Q)=>{if(Q.code==="ENOENT")return null;throw Q});if(F&&!F.isFile())return{warning:"Kept .hlixignore unchanged: managed rules require a regular file."};if(F)T=await es(O,"utf8");let N=mn(T);if(!N)return{warning:"Kept .hlixignore unchanged: repair its managed-block markers before refreshing."};let M=ns(T),L=Bo().add(M),H=[],U=[],D=Bo(),z=new Set;for(let Q of P.tracked){let te=Q.split("/");while(te.length)z.add(te.join("/")),te.pop()}let W=0,J=0,V=()=>W<30000&&J<268435456,B=(Q)=>z.has(Q)||un(Q,P.includes)||M.some((te)=>{let pe=te.replace(/^\//,"").split(/[?*[\\]/)[0];return!pe||pe.startsWith(`${Q}/`)||L.ignores(`${Q}/`)||L.ignores(Q)}),G=async(Q,te,pe=!1)=>{if(P.signal?.throwIfAborted(),!V()||B(Q)||P.protectedPath(Q,te))return!1;W++;let me=await Bt(_e(j,Q));if(me.isSymbolicLink())return te;if(me.isDirectory()){let Se=(await Jn(_e(j,Q))).sort();for(let Ne of Se){if(Ne===".git")continue;if(!await G(`${Q}/${Ne}`,te,pe))return!1}return!0}if(!me.isFile()||J+me.size>268435456)return!1;let fe="",$e="";for await(let Se of gc(_e(j,Q),{encoding:"utf8",signal:P.signal})){if(J+=Buffer.byteLength(Se),fe.length<4096)fe+=Se.slice(0,4096-fe.length);let Ne=$e+Se;if(P.protectedContent(Q,Ne))return!1;$e=Ne.slice(-4096)}return te||Wo.test(fe)||Wo.test($e)||!bc.test(Q)&&!/^#!|^<\?php/.test(fe)&&(pe&&kc.test(Q)||Jo.test(Q))},X=new Set,K=async(Q,te=[],pe=!1)=>{if(P.signal?.throwIfAborted(),!V())return;let me=_e(j,Q),fe=await Jn(me,{withFileTypes:!0}),$e=async(de)=>fe.find((we)=>we.name===de)?.isFile()&&(await Bt(_e(me,de))).size<1048576?es(_e(me,de),"utf8"):null,Se=await $e("package.json"),Ne=await $e("composer.json"),ge=!1,St=new Set;try{let de=JSON.parse(await $e("composer.lock")??"null");ge=Array.isArray(de?.packages);for(let le of[...de?.packages??[],...de?.["packages-dev"]??[]]){if(typeof le.name==="string")St.add(le.name);if(le.dist?.type==="path")ge=!1}}catch{}try{let de=JSON.parse(Se??"{}"),le=Array.isArray(de.workspaces)?de.workspaces:de.workspaces?.packages;for(let we of Array.isArray(le)?le:[]){if(typeof we!=="string"||we.startsWith("!"))continue;let pt=(Q?`${Q}/`:"")+we.replace(/^\.\//,"");U.push(pt),D.add(pt)}}catch{}let jt=[Se,Ne].filter(Boolean).join(`
138
- `),nt={};for(let de of fe){if(!/^(?:(?:vite|next|nuxt|astro|webpack|rollup)\.config\.[cm]?[jt]s|tsconfig(?:\.[^/]*)?\.json|turbo\.json|pyproject\.toml|setup\.py)$/.test(de.name))continue;let le=await $e(de.name);if(le!==null)nt[de.name]=le}let Et={packageJson:Se,rootFiles:fe.map((de)=>de.name),configFiles:nt};pe||=Qr(nt);let Rn=Do(Et);for(let de of Zr(Et))X.add(Q?`${Q}/${de}`:de);let ut=new Set([...Rn,...te]);for(let de of fe.sort((le,we)=>le.name<we.name?-1:le.name>we.name?1:0)){if([".git",".hlix",".hlixignore"].includes(de.name)||de.isSymbolicLink())continue;let le=Q?`${Q}/${de.name}`:de.name;if(/[\n\r\\*?[\]!#]/.test(le)||le.endsWith(" "))continue;if(W++,!V())return;if(de.isDirectory()){let we=await Bt(_e(j,le,".git")).then(()=>P.isRepository(le),()=>!1),pt=Gn.has(le)||[...Gn].some((Ae)=>le.startsWith(`${Ae}/`)),_n=P.gitIgnored.directories.some((Ae)=>`${le}/`.startsWith(Ae)),mt=D.ignores(`${le}/`)||U.some((Ae)=>Ae.split(/[?*[\\]/)[0].startsWith(`${le}/`))||jt.includes(de.name)||/(?:^|\/)(?:src|lib|apps|packages|tests|resources|public)(?:\/|$)/.test(le),$t=we&&(pt||_n)&&!mt;if(de.name==="vendor"&&ge)for(let Ae of await Jn(_e(j,le),{withFileTypes:!0})){if(["autoload.php","composer","bin"].includes(Ae.name))continue;if(!Ae.isDirectory()){ge=!1;break}for(let Kt of await Jn(_e(j,le,Ae.name)))if(!St.has(`${Ae.name}/${Kt}`))ge=!1}let rt=Rn.includes(de.name)&&(de.name==="node_modules"||de.name==="vendor"&&ge&&!/"type"\s*:\s*"path"/.test(Ne??"")),An=X.has(le)||pe&&de.name.endsWith(".egg-info");if(((de.name==="node_modules"||de.name==="vendor"?rt:ut.has(de.name))||Gn.has(le)&&!mt||["logs","runtime","tmp"].includes(de.name)||$t||An)&&!B(le)&&await G(le,rt||$t||An,ut.has(de.name)||Gn.has(le))){H.push(`/${le}/`);continue}if(!we&&!["node_modules","vendor"].includes(de.name))await K(le,ut.has("__pycache__")?["__pycache__"]:[],pe)}else if(de.isFile()&&(Jo.test(de.name)||(await Bt(_e(j,le))).size>P.maxFileBytes)&&!B(le)&&await G(le,!1))H.push(`/${le}`)}};await K("");let ie=T.includes(`\r
139
- `)?`\r
140
- `:`
141
- `,ee=[Go,...H.sort(),ts,""].join(ie),q=N.before+(N.before&&!N.before.endsWith(`
142
- `)?ie:"")+ee+N.after;if(P.write!==!1&&q!==T){let Q=await hc(_e(j,".hlixignore-"));try{let te=_e(Q,"rules");await vc(te,q,{mode:F?.mode??420});let pe=await Bt(O).catch((me)=>{if(me.code==="ENOENT")return null;throw me});if(pe?!pe.isFile()||pe.ino!==F?.ino||pe.dev!==F?.dev||await es(O,"utf8")!==T:F!==null)return{warning:"Kept .hlixignore unchanged: it changed while generated paths were being checked."};await yc(te,O)}finally{await wc(Q,{recursive:!0,force:!0})}}let ne=H.every((Q)=>Q.endsWith("/"))?"generated folders":"generated paths";return{rules:H,report:`Hlix ignored ${H.length} ${ne} — see .hlixignore`}}catch(F){return P.signal?.throwIfAborted(),{warning:`Kept .hlixignore unchanged: could not safely refresh generated paths (${F.code??"unreadable"}).`}}}import{readFile as jc}from"node:fs/promises";import{join as Ec}from"node:path";function Sc(j){let P=j.trim();if(!P||/^[|>[{]/.test(P))return null;let O=P.match(/^(["'])([\s\S]*)\1$/);if(!O&&/^["']/.test(P))return null;return(O?O[2].trim():P.replace(/(?:^|\s)#.*$/,"").trim())||null}function Ko(j){let P=j.split(/\r?\n/),O=P.findIndex((M)=>/^tasks:\s*(?:#.*)?$/.test(M));if(O===-1)return{tasks:[],partial:/^tasks:\s*\S/m.test(j)};let T=[],F=!1,N=-1;for(let M of P.slice(O+1)){if(!M.trim()||/^\s*#/.test(M))continue;let L=M.length-M.trimStart().length,H=M.match(/^(\s*-(?:\s+|$))(.*)$/);if(H){if(N!==-1&&L>=N)continue;if(T.push({}),N=H[2]?H[1].length:-1,!H[2])continue}else if(L===0)break;else if(T.length===0)continue;else if(N===-1)N=L;else if(L!==N)continue;let U=(H?H[2]:M.trim()).match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);if(!U)continue;let D=U[1];if(D!=="name"&&D!=="before"&&D!=="init"&&D!=="command")continue;let z=Sc(U[2]);if(z===null)F=!0;else T[T.length-1][D]=z}return{tasks:T,partial:F}}async function vt(j,P){try{return await jc(Ec(j,...P.split("/")),"utf8")}catch(O){if(O.code==="ENOENT")return null;throw O}}function Vo(j){try{let P=j.replace(/(^|[^:\\])\/\/.*$/gm,"$1").replace(/\/\*[\s\S]*?\*\//g,"").replace(/,\s*([}\]])/g,"$1");return JSON.parse(P)}catch{return null}}function ct(j){if(typeof j==="string"&&j.trim())return[j.trim()];if(Array.isArray(j))return j.flatMap(ct);if(j&&typeof j==="object")return Object.values(j).flatMap(ct);return[]}function rs(j){if(!j||typeof j!=="object")return[];return Object.keys(j).filter((P)=>/^[A-Za-z_][A-Za-z0-9_]*$/.test(P))}function $c(j,P){let O=new Set,T=[/\bprocess\.env\.([A-Za-z_][A-Za-z0-9_]*)/g,/\bimport\.meta\.env\.([A-Za-z_][A-Za-z0-9_]*)/g,/\bos\.(?:getenv|environ\.get)\(\s*["']([A-Za-z_][A-Za-z0-9_]*)/g,/\bos\.Getenv\(\s*["']([A-Za-z_][A-Za-z0-9_]*)/g,/\bENV\[\s*["']([A-Za-z_][A-Za-z0-9_]*)/g];if(P)T.push(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}/g);for(let F of T)for(let N of j.matchAll(F))O.add(N[1]);return[...O]}function Pc(j,P){if(j.has("bun.lock")||j.has("bun.lockb")||P?.startsWith("bun@"))return"bun install";if(j.has("pnpm-lock.yaml")||P?.startsWith("pnpm@"))return"pnpm install";if(j.has("yarn.lock")||P?.startsWith("yarn@"))return"yarn install";if(j.has("package.json"))return"npm install";return null}function Yo(j){let P=typeof j==="number"?j:Number(j);return Number.isInteger(P)&&P>0&&P<=65535?P:null}function Te(j,P,O){if(!j.some((T)=>T.path===P&&T.kind===O))j.push({path:P,kind:O})}async function Xo(j,P,O){let T=[],F=[],N=[],M=[],L=new Map,H=new Set,U=new Set,D=[],z={},W=null,J=0,V=await vt(j,".cursor/environment.json");if(V){Te(T,".cursor/environment.json","cursor");let q=Vo(V);if(!q)D.push("Could not parse .cursor/environment.json; it remains quarantined.");else{F.push(...ct(q.install));let ne=ct(q.start);if(ne[0])W=ne[0];if(Array.isArray(q.terminals))for(let Q of q.terminals){if(!Q||typeof Q!=="object")continue;let te=Q;if(typeof te.command!=="string"||!te.command.trim())continue;M.push({name:typeof te.name==="string"&&te.name.trim()?te.name.trim():"Terminal",command:te.command.trim(),...typeof te.cwd==="string"&&te.cwd.trim()?{cwd:te.cwd.trim()}:{}})}}}let B=P.has(".devcontainer/devcontainer.json")?".devcontainer/devcontainer.json":P.has("devcontainer.json")?"devcontainer.json":null;if(B){Te(T,B,"devcontainer");let q=Vo(O.get(B)??await vt(j,B)??"");if(!q)D.push(`Could not parse ${B}; it remains quarantined.`);else{F.push(...ct(q.onCreateCommand),...ct(q.updateContentCommand),...ct(q.postCreateCommand));let ne=ct(q.postStartCommand);if(!W&&ne[0])W=ne[0];for(let Q of rs(q.secrets))H.add(Q);for(let Q of[...rs(q.containerEnv),...rs(q.remoteEnv)])H.add(Q);if(Array.isArray(q.forwardPorts))for(let Q of q.forwardPorts){let te=Yo(Q);if(te)L.set(te,{port:te,visibility:"private"})}}}if(P.has(".gitpod.yml")){Te(T,".gitpod.yml","gitpod");let q=O.get(".gitpod.yml")??await vt(j,".gitpod.yml");if(q===null)D.push("Could not read .gitpod.yml; its task commands were not imported.");else{let ne=Ko(q);J=ne.tasks.filter((Q)=>Q.before).length;for(let Q of ne.tasks){if(Q.before)F.push(Q.before);if(Q.init)F.push(Q.init);if(!Q.command)continue;if(!W)W=Q.command;else M.push({name:Q.name??"Terminal",command:Q.command})}if(ne.partial)D.push("Some .gitpod.yml task values are not plain `key: value` scalars and were not imported; review .gitpod.yml before approving cloud setup.")}}for(let q of["Dockerfile","docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"])if(P.has(q))Te(T,q,"docker");for(let q of["project.toml","nixpacks.toml","railpack.json","Aptfile"])if(P.has(q))Te(T,q,"buildpack");for(let q of["fly.toml","railway.json","render.yaml","vercel.json","netlify.toml"])if(P.has(q))Te(T,q,"platform");let G=O.get("package.json")??await vt(j,"package.json");if(G){Te(T,"package.json","package");try{let q=JSON.parse(G);if(q.engines?.node)z.node=q.engines.node;let ne=Pc(P,q.packageManager);if(ne&&F.length===J)F.push(ne);if(q.scripts?.build&&N.length===0)N.push(`${q.packageManager?.split("@")[0]??(P.has("bun.lock")?"bun":"npm")} run build`);let Q=q.scripts?.dev?`${P.has("bun.lock")?"bun":"npm"} run dev`:null,te=q.scripts?.start?`${P.has("bun.lock")?"bun":"npm"} run start`:Q;if(!W&&te)W=te}catch{D.push("Could not parse package.json for environment discovery.")}}if(P.has("uv.lock"))F.push("uv sync --frozen");else if(P.has("poetry.lock"))F.push("poetry install --no-interaction");else if(P.has("requirements.txt"))F.push("python -m pip install -r requirements.txt");if(P.has("go.mod"))F.push("go mod download");if(P.has("Procfile")){Te(T,"Procfile","procfile");let ne=(O.get("Procfile")??"").split(/\r?\n/).find((Q)=>/^web\s*:/.test(Q));if(ne)W=ne.replace(/^web\s*:\s*/,"").trim()||W}let X=[[".node-version","node"],[".nvmrc","node"],[".python-version","python"]];for(let[q,ne]of X){let Q=(O.get(q)??await vt(j,q))?.trim();if(Q)z[ne]=Q,Te(T,q,"tool-version")}let K=O.get(".tool-versions")??await vt(j,".tool-versions");if(K){Te(T,".tool-versions","tool-version");for(let q of K.split(/\r?\n/)){let[ne,Q]=q.trim().split(/\s+/,2);if(!Q)continue;if(ne==="nodejs")z.node=Q;else if(ne==="python")z.python=Q;else if(ne==="bun")z.bun=Q}}let ie=O.get("mise.toml")??await vt(j,"mise.toml");if(ie){Te(T,"mise.toml","tool-version");for(let q of ie.matchAll(/^\s*(node|python|bun)\s*=\s*["']([^"']+)["']/gm))z[q[1]]=q[2]}for(let[q,ne]of O){let Q=/(?:^|\/)(?:Dockerfile|Procfile)$/i.test(q)||/\.(?:jsonc?|ya?ml|toml|ini|conf|config|env|sh|bash|zsh|fish)$/i.test(q);for(let te of $c(ne,Q))U.add(te);for(let te of ne.matchAll(/(?:--port(?:=|\s+)|PORT\s*=\s*)(\d{2,5})/g)){let pe=Yo(te[1]);if(pe)L.set(pe,{port:pe,visibility:"private"})}}if(T.length===0&&P.size>0)Te(T,"repository","detected");let ee=(q)=>[...new Set(q.filter(Boolean))],Z=T.length+F.length+(W?1:0);return{sources:T.sort((q,ne)=>q.path.localeCompare(ne.path)),toolchain:z,install:ee(F),build:ee(N),start:W,terminals:M,ports:[...L.values()].sort((q,ne)=>q.port-ne.port),requiredSecretKeys:[...H].sort(),observedSecretKeys:[...U].sort(),confidence:Z>=4?"high":Z>=2?"medium":"low",warnings:D}}var Zo=2;var di=300000,Fc=25000,Qo=52428800,Mc=524288000,wn=1e4,Hc="Potential secrets exist in Git history",Lc="Never delete .git folders or files to get past this; use .hlixignore instead.",Vn=1048576,fn=20971520,ui=[".git/",".hlix/","node_modules/",".next/",".turbo/",".cache/","dist/","build/","coverage/","__pycache__/",".venv/","venv/","target/",".DS_Store"],Uc=hn().add(ui);function pi(j,P){return!Dt(j,P)&&Uc.ignores(j)}var as="Required project environment value was not found locally: ",Dc=/(^|\/)\.env\.(example|sample|template)$/i,zc=/(^|\/)\.env(?:\.[^/]+)?$/i,Bc=/(^|\/)(?:\.envrc|\.netrc|\.npmrc|\.pypirc|credentials(?:\.[^/]+)?(?:\.json|\.toml)?|service-account[^/]*\.json|firebase-adminsdk[^/]*\.json|application_default_credentials\.json|\.docker\/config\.json|\.cargo\/credentials(?:\.toml)?|\.gem\/credentials|\.bundle\/config|(?:pip|pypi)\.conf|\.aws\/credentials|[^/]+\.(?:pem|key|p12|pfx)|[^/]*\.(?:auto\.)?tfvars(?:\.json)?|application[^/]*\.(?:properties|ya?ml)|(?:local|keystore|gradle|secrets?)\.properties|appsettings[^/]*\.json|local\.settings\.json|config\/database\.ya?ml|wrangler\.toml|fly\.toml|serverless\.ya?ml|(?:credentials|secrets?)[^/]*\.(?:json|ya?ml|toml|ini|conf|cfg))$/i,Wc=/\.(?:example|sample|template)$/i,Jc=/(^|\/)\.(?:npmrc|yarnrc(?:\.yml)?|pypirc)$/i,Gc=/(?:^|\/)(?:__tests__|tests?|fixtures)\/|\.(?:test|spec)\.[^/]+$|\.snap$/i,qc=/\.(?:md|mdx|txt|rst)$/i,Kc=/fake|dummy|example|placeholder|unused|changeme|xxxx|redacted|your[_-]|<[^>]*>/i,Vc=/^(.)\1+$/,Yc=/RegExp\(/,cs="BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|npm_[A-Za-z0-9]{30,}|gh[opusr]_[A-Za-z0-9_]{30,}|AKIA[0-9A-Z]{16}|xox[baprs]-[A-Za-z0-9-]{20,}",Xc=new RegExp(cs,"g"),Zc=/(^|\/)(?:\.mcp\.json|mcp\.json|claude_desktop_config\.json)$/i,Qc=/(^|\/)(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.github\/copilot-instructions\.md)$/i,el=/(^|\/)(?:\.agents|\.claude)\/skills\//i,is=/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|npm_[A-Za-z0-9]{30,}|gh[opusr]_[A-Za-z0-9_]{30,}|glpat-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{30,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{20,}/,dm=new RegExp(is.source,"g"),ei=/\.(?:json|ya?ml|toml|ini|conf|config)$/i,ti=/(?:^|[,{\s])(?:["']?(?:api[_-]?key|access[_-]?token|auth(?:orization)?|client[_-]?secret|password|private[_-]?key|secret|token)["']?)\s*(?::|=)\s*["']?(?!\$\{|process\.env|import\.meta\.env|os\.(?:getenv|environ\.get)|<|replace|example|changeme)[A-Za-z0-9+/_=.:-]{12,}/im,gn=new Set(["HLIX_AGENT_RUN_ID","HLIX_API_KEY","HLIX_API_URL","HLIX_BASE_URL","HLIX_PROJECT_ID","HLIX_SESSION_TOKEN","HLIX_WORKSPACE_ID"]),ss="Your hlix credentials were left out of the project's secrets — the platform provides them.",os=new Set(["CI","HOME","LANG","LOGNAME","NODE_ENV","OLDPWD","PATH","PORT","PWD","SHELL","SHLVL","TERM","TMPDIR","USER","_"]),tl=100,ni=12;function nl(j){let P=j.slice(0,ni).join(", "),O=j.length-ni;return j.length===1?`Observed environment reference has no local value: ${j[0]}`:`${j.length} observed environment references have no local value: ${P}${O>0?`, +${O} more`:""}`}var rl=250;function lt(j){return j.split(Oc).join("/")}function Ve(j){if(j>=1048576)return`${(j/1048576).toFixed(1)} MB`;if(j>=1024)return`${(j/1024).toFixed(1)} KB`;return`${j} bytes`}function ri(j,P=5){return[...j].sort((O,T)=>T.size-O.size||O.path.localeCompare(T.path)).slice(0,P).map((O)=>`${O.path} (${Ve(O.size)})`).join(", ")}function sl(j,P=5){let O=new Map;for(let T of j){let F=T.indexOf("/"),N=F===-1?".":T.slice(0,F);O.set(N,(O.get(N)??0)+1)}return[...O].sort((T,F)=>F[1]-T[1]||T[0].localeCompare(F[0])).slice(0,P).map(([T,F])=>`${T}/ (${F} files)`).join(", ")}function Me(j,P,O=10485760){return Nc("git",["-C",j,...P],{encoding:"utf8",timeout:di,maxBuffer:O,stdio:["ignore","pipe","pipe"]})}function c(j,P,O={}){return new Promise((T)=>{Tc("git",["-C",j,...P],{encoding:"utf8",timeout:di,maxBuffer:O.maxBuffer??10485760,...O.signal?{signal:O.signal}:{}},(F,N)=>{let M=F?.code;T({status:F===null?0:typeof M==="number"?M:1,stdout:typeof N==="string"?N:""})})})}async function ol(j){let P=vn("sha256");for await(let O of Ic(j))P.update(O);return P.digest("hex")}function Ye(j){if(Array.isArray(j))return`[${j.map(Ye).join(",")}]`;if(j&&typeof j==="object")return`{${Object.entries(j).sort(([P],[O])=>P.localeCompare(O)).map(([P,O])=>`${JSON.stringify(P)}:${Ye(O)}`).join(",")}}`;return JSON.stringify(j)}function mi(j){let P={};for(let[O,T]of String(j).replace(/^\uFEFF/,"").split(/\r?\n/).entries()){let F=T.trim();if(!F||F.startsWith("#"))continue;let M=(F.startsWith("export ")?F.slice(7).trimStart():F).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!M)throw Error(`Invalid dotenv assignment on line ${O+1}`);let L=M[2]??"";if(L.startsWith('"')){if(!L.endsWith('"'))throw Error(`Unclosed dotenv quote on line ${O+1}`);L=L.slice(1,-1).replace(/\\n/g,`
143
- `).replace(/\\r/g,"\r")}else if(L.startsWith("'")){if(!L.endsWith("'"))throw Error(`Unclosed dotenv quote on line ${O+1}`);L=L.slice(1,-1)}else L=L.replace(/\s+#.*$/,"").trimEnd();P[M[1]]=L}return P}function il(j,P){return j.split(/(?<=\n)/).filter((O)=>{let T=O.trim(),N=(T.startsWith("export ")?T.slice(7).trimStart():T).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=/)?.[1];return N===void 0||!P.has(N)}).join("")}function al(j){let P=null;for(let O=0;O<j.length;O+=1){let T=j[O];if(T==="\\"&&P!=="single"){if(j[O+1]!=="$")return!0;O+=1;continue}if(T==="'"&&P!=="double"){P=P==="single"?null:"single";continue}if(T==='"'&&P!=="single"){P=P==="double"?null:"double";continue}if(P!=="single"&&(T==="$"||T==="`"))return!0;if(P===null&&(T==="<"||T===">")&&j[O+1]==="(")return!0}return P!==null}function cl(j){let P={},O=new Set,T=new Set;for(let F of String(j).replace(/^\uFEFF/,"").split(/\r?\n/)){let N=F.trim();if(!N||N.startsWith("#"))continue;let L=(N.startsWith("export ")?N.slice(7).trimStart():N).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!L)continue;let H=L[1],U=L[2]??"";if(O.add(H),al(U)){delete P[H],T.add(H);continue}try{let z=mi(`${H}=${U}`)[H];if(z===void 0)throw Error("missing literal");P[H]=U.trimStart().startsWith("'")?z:z.replace(/\\\$/g,"$"),T.delete(H)}catch{delete P[H],T.add(H)}}return{values:P,keys:[...O].sort(),dynamicKeys:[...T].sort()}}async function ll(j){let P=Me(j,["rev-parse","--show-toplevel"]);if(P.status!==0)return!1;try{return await ci(P.stdout.trim())===j}catch{return!1}}function dl(j,P){if(!P)return new Set;let O=Me(j,["ls-files","-z"]);if(O.status!==0)throw Error("Could not enumerate tracked files.");return new Set(O.stdout.split("\x00").filter(Boolean).map(lt))}function ul(j,P){if(!P)return[];let O=Me(j,["config","--get-regexp","^remote\\..*\\.url$"]);if(O.status!==0)return[];let T=[];for(let F of O.stdout.split(`
144
- `)){let N=F.trim();if(!N)continue;let M=/^remote\.(.*)\.url (.+)$/.exec(N);if(M)T.push({name:M[1],url:M[2]})}return T}function pl(j,P){if(!P)return{files:new Set,directories:[]};let O=Me(j,["ls-files","-z","--others","--ignored","--exclude-standard","--directory"]);if(O.status!==0)throw Error("Could not enumerate ignored files.");let T=new Set,F=[];for(let N of O.stdout.split("\x00").filter(Boolean)){let M=lt(N);if(M.endsWith("/"))F.push(M);else T.add(M)}return{files:T,directories:F}}async function si(j,P){let O=[],T=[],F=[],N="";for(let U of[".gitignore",".hlixignore"])try{let D=bn(j,U),z=await ai(D);if(U===".gitignore"&&z.isSymbolicLink()){T.push(U);continue}if(z.isFile()||z.isSymbolicLink())try{if(z.isSymbolicLink()&&!(await li(D)).isFile()){O.push(U);continue}let W=await yn(D,"utf8");if(U===".hlixignore")N=W;let J=U===".hlixignore"?mn(W):null;if(P&&J?.managed)W=W.replace(J.managed,P.join(`
145
- `));F.push(W)}catch{O.push(U)}}catch(D){if(D.code!=="ENOENT")O.push(U)}let M=mn(N)?.managed??"",L=M?[".git/",".hlix/"]:ui,H=ns(N);return{hardMatcher:hn().add(H.length?[".git/",".hlix/"]:L),matcher:hn().add([...L,...F.flatMap((U)=>U.split(/\r?\n/))]),unignored:hn().add(H),managedMatcher:hn().add(P??M),hasManaged:Boolean(M),unreadable:O,symlinked:T}}function Yn(j){if(Zc.test(j))return"mcp";if(el.test(j))return"skill";if(Qc.test(j))return"agent";return null}function Xn(j){if(zc.test(j)&&!Dc.test(j))return"dotenv";if(Bc.test(j))return"credential";return null}function ml(j,P){if(P)return[lt(P)];let O=new Map([[".env",0],[".env.development",1],[".env.local",2],[".env.development.local",3]]),T=j.filter((F)=>O.has(bt(F).toLocaleLowerCase("en-US"))).sort((F,N)=>F.slice(0,-bt(F).length).localeCompare(N.slice(0,-bt(N).length))||O.get(bt(F).toLocaleLowerCase("en-US"))-O.get(bt(N).toLocaleLowerCase("en-US")));return T.length>0?T:j.length===1?[...j]:[]}function fl(j,P){try{let O=JSON.parse(P);if(!O.mcpServers||typeof O.mcpServers!=="object")return[];return Object.entries(O.mcpServers).map(([T,F])=>{let N=F&&typeof F==="object"?F:{},M=N.type==="http"||N.type==="sse"||N.type==="stdio"?N.type:typeof N.command==="string"?"stdio":typeof N.url==="string"?"http":"unknown",L=N.env&&typeof N.env==="object"?N.env:{};return{sourcePath:j,name:T,transport:M,...typeof N.command==="string"?{command:N.command}:{},...Array.isArray(N.args)&&N.args.every((H)=>typeof H==="string")?{args:N.args}:{},...typeof N.url==="string"?{url:N.url}:{},envKeys:Object.keys(L).sort(),enabled:!1}})}catch{return[]}}function gl(j){let P=!1,O=!1;for(let T of j.split(/\r?\n/)){let F=T.trim();if(!F||F.startsWith("#")||F.startsWith(";")||F.startsWith("["))continue;let N=F.indexOf("=");if(N===-1)continue;let M=F.slice(0,N).trim().toLowerCase(),L=F.slice(N+1).trim().replace(/^["']|["']$/g,"");if(!L||/^\$(?:\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*)$/.test(L))continue;if(M.endsWith("_authtoken")||M.endsWith("_password"))return!0;if(M.endsWith("password"))O=!0;else if(M.endsWith("username"))P=!0}return P&&O}async function hl(j,P,O,T){if(Wc.test(O))return!1;if(!Jc.test(O))return!0;let F=await c(j,["show",`${P}:${O}`],{...T?{signal:T}:{}});return F.status===0&&gl(F.stdout)}function yl(j,P,O){let T=j.lastIndexOf("/",P),F=j.indexOf("/",O);return T!==-1&&F!==-1&&!/\s/.test(j.slice(T,P)+j.slice(O,F))}function wl(j){if(Gc.test(j))return"test fixture";if(qc.test(j))return"documentation or pattern definition";return null}function vl(j,P){let O=null;for(let T of j.split(/\r?\n/))for(let F of T.matchAll(P)){let N=F[0],M=F.index??0,L=Yc.test(T)||yl(T,M,M+N.length)?"documentation or pattern definition":Kc.test(N)||Vc.test(N)?"placeholder value":null;if(L===null)return null;O??=L}return O}async function bl(j,P,O,T){let F=wl(O);if(F!==null)return F;let N=await c(j,["show",`${P}:${O}`],{...T?{signal:T}:{}});return N.status===0?vl(N.stdout,Xc):null}async function oi(j,P,O){let T=[],F="unknown";for(let N of j.split(/\r?\n/)){if(N.startsWith("@@"))F=N.slice(2);else if(N.trim()){let M=lt(N.trim());if(await O(F,M))T.push({commit:F,path:M,reason:P})}if(T.length>=100)break}return T}async function ii(j,P,O={}){if(!P)return{head:null,branch:null,refs:[],commitCount:0,complete:!0,findings:[],blockingFindings:[],waivedReasons:[]};let T=Me(j,["rev-parse","HEAD"]).stdout.trim()||null,F=Me(j,["symbolic-ref","--short","-q","HEAD"]),N=F.status===0?F.stdout.trim()||null:null,M=Number.parseInt(Me(j,["rev-list","--count","--all"]).stdout.trim(),10)||0,L=Me(j,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]),H=L.stdout.split(`
146
- `).filter(Boolean).map((X)=>{let[K,ie]=X.split("\x00");return{name:K,oid:ie}}).filter(({name:X,oid:K})=>/^refs\/(?:heads|tags)\/.+/.test(X)&&/^[0-9a-f]{40,64}$/.test(K)).sort((X,K)=>X.name.localeCompare(K.name)),U=O.signal,D=U?{signal:U}:{};O.onProgress?.(`history: ${M} commit${M===1?"":"s"}…`);let z=["log","--all",`--max-count=${wn}`,"--pretty=format:@@%H","--name-only"],W=await c(j,[...z,"--",".env",".env.*","*.pem","*.key",".npmrc","*.tfvars"],D),J=await c(j,["log","--all",`--max-count=${wn}`,"-G",cs,"--pretty=format:@@%H","--name-only"],D);U?.throwIfAborted();let V=new Map;for(let X of[...await oi(W.stdout,"sensitive-path",(K,ie)=>hl(j,K,ie,U)),...await oi(J.stdout,"secret-pattern",async()=>!0)])V.set(`${X.commit}:${X.path}:${X.reason}`,X);let B=[...V.values()].slice(0,100),G=new Map;for(let X of B){if(X.reason!=="secret-pattern")continue;let K=await bl(j,X.commit,X.path,U);if(K!==null)G.set(X,K)}return O.onProgress?.(`history: ${M} commit${M===1?"":"s"} scanned`),{head:T,branch:N,refs:H,commitCount:M,complete:M<=wn&&H.length<=1000&&L.status===0&&W.status===0&&J.status===0,findings:B,blockingFindings:B.filter((X)=>!G.has(X)),waivedReasons:[...G.values()]}}function kl(j,P){let O=P?.XDG_CACHE_HOME??(P?.HOME?bn(P.HOME,".cache"):null);if(!O)return null;return bn(O,"hlix","history",`${vn("sha256").update(j).digest("hex")}.json`)}async function Sl(j,P,O){let T=P?kl(j,O.environment):null;if(!T)return ii(j,P,O);let F=vn("sha256").update([Me(j,["for-each-ref","--format=%(refname)%00%(objectname)"]).stdout,Me(j,["rev-parse","HEAD"]).stdout,Me(j,["symbolic-ref","--short","-q","HEAD"]).stdout,cs,String(wn)].join("\x00")).digest("hex");try{let M=JSON.parse(await yn(T,"utf8"));if(M.key===F&&M.history)return O.onProgress?.(`history: ${M.history.commitCount} commits, unchanged since the last scan`),M.history}catch{}let N=await ii(j,P,O);if(N.complete)try{await Cc(Ac(T),{recursive:!0,mode:448}),await _c(T,JSON.stringify({key:F,history:N}),{mode:384})}catch{}return N}async function He(j,P={}){let O=await ci(Kn(j));if(!(await li(O)).isDirectory())throw Error("Import target must be a directory.");let T=await ll(O),F=ul(O,T),N=dl(O,T),M=new Set(T?(await c(O,["ls-files","--stage","-z"])).stdout.split("\x00").filter((Y)=>Y.startsWith("160000 ")).map((Y)=>Y.slice(Y.indexOf("\t")+1)):[]),L=pl(O,T),H=[...new Set([...s(O)?.includedPaths??[],...P.include?[P.include]:[]].map((Y)=>Y.replace(/^\.\//,"").replace(/\/$/,"")))],U=await si(O),D=P.refreshIgnore||U.hasManaged?await qo(O,{write:P.refreshIgnore===!0,tracked:T?N:new Set((await c(O,["ls-files","-z"])).stdout.split("\x00").filter(Boolean)),includes:H,gitIgnored:L,signal:P.signal,maxFileBytes:P.maxFileBytes??Qo,isRepository:async(Y)=>{let oe=await c(bn(O,Y),["rev-parse","--show-toplevel"]);return oe.status===0&&Kn(oe.stdout.trim())===Kn(O,Y)},protectedPath:(Y,oe)=>Boolean(Xn(Y)||!oe&&Yn(Y)),protectedContent:(Y,oe)=>is.test(oe)||ei.test(Y)&&ti.test(oe)}):void 0,{hardMatcher:z,matcher:W,unignored:J,managedMatcher:V,unreadable:B,symlinked:G}=D?await si(O,D.rules??[]):U,X=B.length?`Upload left unchanged: cannot read ${B.join(", ")}; check the ignore file target and permissions before retrying.`:void 0,K=[],ie=[],ee=[],Z=[],q=[],ne=[],Q=[],te=[],pe=P.envFile?lt(qn(O,Kn(O,P.envFile))):void 0,me=pe!==void 0&&pe!==""&&pe!==".."&&!pe.startsWith("../");if(P.envFile&&!me)te.push(`Selected environment file must stay inside the project: ${P.envFile}`);let fe=new Map,$e=new Map,Se=new Map,Ne=new Map,ge=D?.warning?[D.warning]:[],St=new Set,jt=[],nt=[],Et=new Map,Rn=P.maxFiles??Fc,ut=P.maxFileBytes??Qo,de=P.maxTotalBytes??Mc,le=P.historyMode==="sanitize",we=0,pt=0,_n=async(Y,oe=!1)=>{let ve=await xc(Y,{withFileTypes:!0}).catch((Pe)=>{let Ce=lt(qn(O,Y))||"repository";if(Q.push({path:Ce,reason:`Cannot read folder (${Pe.code??"unreadable"}); check read and search permissions`}),ge.push(`Cannot read folder ${Ce}; check its read and search permissions. Existing cloud files are preserved.`),Y===O)X="Upload left unchanged: cannot read the project folder; check its permissions.";return[]});ve.sort((Pe,Ce)=>Pe.name.localeCompare(Ce.name));for(let Pe of ve){if(P.signal?.throwIfAborted(),pt+=1,pt%rl===0)P.onProgress?.(`scanning … ${K.length} files`);let Ce=bn(Y,Pe.name),ae=lt(qn(O,Ce));if(Pe.name===".git"){if(ae!==".git"&&!oe)St.add(lt(qn(O,Y)));continue}if(ae.length>1000||ae.includes("\\")||ae.includes("\x00")){ge.push(`Skipped a path that cannot be represented safely: ${ae.slice(0,350)}`);continue}try{let je=await ai(Ce),Vt=Pe.isDirectory()?`${ae}/`:ae,Ks=N.has(ae)&&!M.has(ae),Yt=!(Dt(ae,H)||J.ignores(Vt))&&!Ks&&(W.ignores(Vt)||L.files.has(ae)||L.directories.some((he)=>Vt.startsWith(he))),Vs=!un(ae,H)&&z.ignores(Vt);if(Vs){if(ae!==".hlix")Q.push({path:ae,reason:"built-in ignore"});continue}if(Yt&&V.ignores(Vt))Q.push({path:ae,reason:"Hlix-managed ignore"});if(je.isSymbolicLink()){if(Yt)continue;if(ie.push({path:ae,target:await Rc(Ce)}),Yn(ae)||Xn(ae))ee.push(ae);continue}if(Pe.isDirectory()){if(Vs)continue;if(M.has(ae)&&!Yt)St.add(ae);await _n(Ce,Yt);continue}let Pt=Yn(ae),It=Xn(ae);if(Yt&&!Pt&&!It)continue;if(!Pe.isFile()){Q.push({path:ae,reason:"non-regular-file"});continue}if(je.size>ut&&!Pt&&!It){Q.push({path:ae,reason:pn(ae)});continue}if(je.size>ut){te.push(`File ${ae} is ${Ve(je.size)}, over the ${Ve(ut)} per-file limit. Exclude it with .hlixignore.`);continue}let Xt=await ol(Ce);if(Pt){if(je.size>Vn){te.push(`Protected configuration ${ae} is ${Ve(je.size)}, over the ${Ve(Vn)} per-file limit. Move the large content out of it, or exclude it with .hlixignore.`);continue}let he=await yn(Ce);if(we+=he.byteLength,nt.push({path:ae,size:he.byteLength}),we>fn)continue;if(q.push({path:ae,kind:Pt,size:je.size,sha256:Xt}),jt.push({path:ae,kind:Pt,contentBase64:he.toString("base64")}),Pt==="mcp")ne.push(...fl(ae,he.toString("utf8")));continue}if(It){if(je.size>Vn){te.push(`Protected file ${ae} is ${Ve(je.size)}, over the ${Ve(Vn)} per-file limit. Move the large content out of it, or exclude it with .hlixignore.`);continue}let he=await yn(Ce);if(we+=he.byteLength,nt.push({path:ae,size:he.byteLength}),we>fn)continue;let ft=[],Ct=new Set;if(It==="dotenv")try{let Tn=mi(he),xt={};for(let[st,Rt]of Object.entries(Tn)){if(gn.has(st)){Ct.add(st);continue}xt[st]=Rt}fe.set(ae,xt),ft=Object.keys(xt).sort()}catch{te.push(`Could not parse environment file: ${ae}`)}else if(bt(ae)===".envrc"){let Tn=cl(he),xt={},st=new Set,Rt=[];for(let[xe,Vi]of Object.entries(Tn.values)){if(gn.has(xe)){Ct.add(xe);continue}if(os.has(xe)){ge.push(`Ignored ambient runtime assignment in ${ae}: ${xe}`);continue}st.add(xe),xt[xe]=Vi}$e.set(ae,xt);for(let xe of Tn.dynamicKeys){if(gn.has(xe)){Ct.add(xe);continue}if(os.has(xe)){ge.push(`Ignored ambient runtime assignment in ${ae}: ${xe}`);continue}st.add(xe),Rt.push(xe)}if(Se.set(ae,[...st].sort()),Ne.set(ae,Rt.sort()),ft=[...st].sort(),Rt.length>0)ge.push(`Did not execute dynamic .envrc assignments; collect their resolved local values when available: ${Rt.join(", ")}`)}if(Ct.size>0)ge.push(ss),he=Buffer.from(il(he.toString("utf8"),Ct),"utf8"),Xt=vn("sha256").update(he).digest("hex");Z.push({path:ae,kind:It,keys:ft,size:he.byteLength,sha256:Xt}),jt.push({path:ae,kind:It,contentBase64:he.toString("base64")});continue}if(je.size<=1048576){let he=await yn(Ce),ft=he.toString("utf8");if(Et.set(ae,ft),is.test(ft)||ei.test(ae)&&ti.test(ft)){if(we+=he.byteLength,nt.push({path:ae,size:he.byteLength}),we>fn)continue;Z.push({path:ae,kind:"detected-content",keys:[],size:je.size,sha256:Xt}),jt.push({path:ae,kind:"detected-content",contentBase64:he.toString("base64")});continue}}K.push({path:ae,size:je.size,sha256:Xt,tracked:Ks,executable:(je.mode&73)!==0})}catch(je){if(P.signal?.throwIfAborted(),Xn(ae)||Yn(ae))throw je;Q.push({path:ae,reason:`Cannot read file (${je.code??"unreadable"})`})}}};await _n(O);let mt=Bn([...K,...ie],Math.max(0,Rn-Z.length-q.length),de,H);if(mt.length)K=K.filter((Y)=>!zt(Y.path,mt)),ie=ie.filter((Y)=>!zt(Y.path,mt)),Q.push(...mt.map((Y)=>({path:Y.replace(/\/$/,""),reason:pn(Y)})));if(P.onProgress?.(`scanning … ${K.length} files`),P.onProgress?.(`secrets: ${Z.length+q.length} files`),P.signal?.throwIfAborted(),ee.length>0){let Y=ee.slice(0,5).join(", "),oe=ee.length-5;ge.push(`Imported as symlinks, so no content was read or uploaded for them and the cloud recreates the link: ${Y}${oe>0?`, +${oe} more`:""}`)}for(let Y of G)ge.push(`Ignore file ${Y} is a symlink, so its rules were not applied. Replace it with a regular file inside the project.`);if(X)ge.push(X);if(we>fn)te.push(`Protected project files total ${Ve(we)}, over the ${Ve(fn)} limit. Largest: ${ri(nt)}. Move large assets out of skill and config folders, or add them to .hlixignore.`);if(Z.length>2000)te.push(`Project has ${Z.length} environment and credential files, over the 2000 limit. Largest: ${ri(Z)}. Exclude the ones the cloud project does not need with .hlixignore.`);if(q.length>5000)te.push(`Project has ${q.length} agent, skill and MCP files, over the 5000 limit. Largest folders: ${sl(q.map((Y)=>Y.path))}. Exclude the ones the cloud project does not need with .hlixignore.`);K.sort((Y,oe)=>Y.path.localeCompare(oe.path)),ie.sort((Y,oe)=>Y.path.localeCompare(oe.path)),Z.sort((Y,oe)=>Y.path.localeCompare(oe.path)),q.sort((Y,oe)=>Y.path.localeCompare(oe.path)),ne.sort((Y,oe)=>`${Y.sourcePath}:${Y.name}`.localeCompare(`${oe.sourcePath}:${oe.name}`));let $t=ml([...fe.keys()].sort(),me?pe:void 0);if(P.envFile&&me&&!fe.has($t[0]))te.push(`Selected environment file was not found or is not a dotenv file: ${P.envFile}`);let rt=new Map;for(let[Y,oe]of fe)for(let ve of Object.keys(oe))rt.set(ve,[...rt.get(ve)??[],Y]);for(let[Y,oe]of Se)for(let ve of oe)rt.set(ve,[...rt.get(ve)??[],Y]);let An=[...rt].filter(([,Y])=>Y.length>1).map(([Y,oe])=>({key:Y,paths:oe.sort()})).sort((Y,oe)=>Y.key.localeCompare(oe.key)),Ue={};for(let Y of $t)Object.assign(Ue,fe.get(Y)??{});let Ae=[...$e.keys()].sort((Y,oe)=>{if(Y===".envrc")return 1;if(oe===".envrc")return-1;return Y.localeCompare(oe)}),Kt=new Set;for(let Y of Ae){let oe=new Set(Ne.get(Y)??[]);for(let ve of Se.get(Y)??[]){if(oe.has(ve)){delete Ue[ve],Kt.add(ve);continue}let Pe=$e.get(Y)?.[ve];if(Pe!==void 0)Ue[ve]=Pe;Kt.delete(ve)}}for(let Y of St)ge.push(`${Y} has its own Git repository — uploaded as files, its history not included`);let Ji=P.historyMode==="abort_on_findings"?"abort_on_findings":"preserve";if(le)ge.push("Git history omitted; uploading a snapshot of the current files.");let Oe=await Sl(O,T,P);if(!Oe.complete)ge.push(`Git history scan exceeded ${wn} commits or failed; history is preserved, but the findings may be incomplete.`);if(T&&!Oe.head)le=!0,ge.push("Git has no readable HEAD; uploading the current files as a snapshot.");let Bs=Oe.waivedReasons;for(let Y of[...new Set(Bs)].sort()){let oe=Bs.filter((Pe)=>Pe===Y).length,ve=oe===1;ge.push(`${oe} Git history finding${ve?"":"s"} did not block this import — ${Y}, not ${ve?"a real credential":"real credentials"}; --history preserve is not needed for ${ve?"it":"them"}.`)}if(Oe.blockingFindings.length>0){let Y=Oe.blockingFindings.length;ge.unshift([`${Hc} (${Y} finding${Y===1?"":"s"}${Y>5?", first 5 shown":""}); ${le?"history is omitted":"history is preserved"}:`,...Oe.blockingFindings.slice(0,5).map((oe)=>` ${oe.commit.slice(0,7)} ${oe.path} — ${oe.reason}`)," To exclude old commits, use --history sanitize; local Git history stays intact."].join(`
147
- `))}let Ws=new Set(K.map((Y)=>Y.path)),Gi=await Xo(O,Ws,Et),{observedSecretKeys:qi,...De}=Gi;De.warnings.unshift(...ge);let On=new Set(De.requiredSecretKeys);for(let Y of Kt)On.add(Y);for(let Y of ne)for(let oe of Y.envKeys)On.add(oe);for(let Y of gn)if(On.delete(Y))De.warnings.push(ss);De.requiredSecretKeys=[...On].sort();for(let Y of De.requiredSecretKeys){if(Ue[Y]!==void 0)continue;let oe=P.environment?.[Y];if(oe===void 0){te.push(`${as}${Y}`);continue}Ue[Y]=oe}let pr=[];for(let Y of qi){if(gn.has(Y)){De.warnings.push(ss);continue}if(os.has(Y))continue;if(Ue[Y]!==void 0)continue;let oe=P.environment?.[Y];if(oe===void 0){pr.push(Y);continue}Ue[Y]=oe}if(pr.length>0)De.warnings.push(nl(pr.sort()));De.warnings=[...new Set(De.warnings.flatMap((Y)=>Y.split(`
148
- `)))].map((Y)=>Y.slice(0,500)).slice(0,tl);let Js=zo(new Map([...Ws].map((Y)=>[Y,Et.get(Y)??null]))),Gs={schemaVersion:Zo,rootName:P.rootName??bt(O),stack:Js.language,git:{detected:T&&!le,head:le?null:Oe.head,branch:le?null:Oe.branch,refs:le?[]:Oe.refs,commitCount:le?0:Oe.commitCount,historyScanComplete:Oe.complete,historyMode:Ji},files:K,symlinks:ie,secretFiles:Z,activeEnvFiles:$t,secretKeys:Object.keys(Ue).sort(),envCollisions:An,quarantinedResources:q,mcpServers:ne,historicalSecretFindings:Oe.blockingFindings,skipped:Wn(Q),environment:De,totals:{files:K.length,bytes:K.reduce((Y,oe)=>Y+oe.size,0)}},qs=Ye(Gs),Ki=vn("sha256").update(qs).digest("hex");return{root:O,includedPaths:H,ignoreReport:P.refreshIgnore?D?.report??D?.warning:void 0,uploadWarning:X,stackFacts:Js,manifest:Gs,...Q.length>5000?{skippedEntries:Q}:{},manifestJson:qs,manifestSha256:Ki,secretValues:Ue,protectedFiles:jt.sort((Y,oe)=>Y.path.localeCompare(oe.path)),blocking:[...new Set(te)].map((Y)=>`${Y}
149
- ${Lc}`),blockingHistoryFindings:[],gitRemotes:F}}var ls={name:"init",summary:"Configure a local folder for Hlix",usage:["Usage: hlix init [folder] [--project <id>] [--json]","","Creates .hlix/config.json, .hlix/.gitignore, and .hlixignore.","Project configuration is safe to commit; local revision state is ignored.",""," --project <id> Bind the folder to an existing cloud project"," Then `hlix pull`, or `hlix push` if it has no files yet"].join(`
150
- `),supportsJson:!0,options:["project"],args:{min:0,max:1},async run(j){if(j.args.length>1)throw Error("init accepts at most one folder.");let P=await jl(El(j.cwd,j.args[0]??".")),O=r({env:j.env,flags:j.flags,cwd:P});if(O.conflict)throw new e("workspace_mismatch",O.conflict);if(!O.workspaceId)throw Error("No workspace selected. Run `hlix auth login --workspace <id>` first.");let T=j.requireClient(P);await T.projects.list();let F=ot(P),N=typeof j.flags.project==="string"?j.flags.project:void 0;if(N&&F?.projectId&&F.projectId!==N)throw new e("workspace_mismatch",`This folder is bound to project ${F.projectId}; refusing to rebind it to ${N}.`);if(N)await T.projects.get(N);let M={...F??{schemaVersion:1,workspaceId:O.workspaceId,apiUrl:O.baseUrl},...N?{projectId:N}:{}};gt(P,M);let L=await He(P,{environment:j.env,refreshIgnore:!0}),H={root:P,config:M,ignoreReport:L.ignoreReport,scan:{files:L.manifest.totals.files,bytes:L.manifest.totals.bytes,secretFiles:L.manifest.secretFiles.map((U)=>U.path),quarantinedResources:L.manifest.quarantinedResources.map((U)=>U.path),blocking:L.blocking}};if(j.json)j.stdout(re(se(ls.name,H)));else{if(L.ignoreReport)j.stdout(`${L.ignoreReport}
151
- `);if(j.stdout(`Initialized ${P}
152
- Project: ${M.projectId??"not imported yet"}
153
- Workspace: ${M.workspaceId}
154
- `),L.blocking.length)j.stdout(`
155
- Review before import:
156
- ${L.blocking.map((U)=>`- ${U}`).join(`
157
- `)}
158
- `)}return 0}};import{randomUUID as Xl}from"node:crypto";import{constants as Zl,existsSync as rr,readFileSync as Ql,rmSync as tt,rmdirSync as ed}from"node:fs";import{copyFile as td,readFile as Ai,realpath as nd}from"node:fs/promises";import{basename as rd,join as Ee,relative as hs,resolve as nr}from"node:path";import{createHash as $l}from"node:crypto";import{constants as Zn}from"node:fs";import{chmod as fi,copyFile as Pl,lstat as ds,mkdir as Il,mkdtemp as Cl,open as xl,realpath as Rl,rename as _l,rm as kt,symlink as Al,writeFile as Ol}from"node:fs/promises";import{tmpdir as Tl}from"node:os";import{dirname as wi,join as Xe,relative as Nl,resolve as Fl,sep as gi}from"node:path";import{spawnSync as Ml}from"node:child_process";var Hl=300000;function Qn(j){let P=j;if(typeof P==="string")try{P=JSON.parse(P)}catch{return{}}if(!P||typeof P!=="object")return{};let O=P,T=O.git&&typeof O.git==="object"?O.git:{},F=T.historyMode==="preserve"||T.historyMode==="abort_on_findings"?T.historyMode:void 0,N=typeof O.rootName==="string"&&O.rootName.trim()?O.rootName:void 0;return{historyMode:F,rootName:N}}function vi(j,P){let O=j;if(typeof O==="string")try{O=JSON.parse(O)}catch{return[]}if(!O||typeof O!=="object")return[];let T=O[P];if(!Array.isArray(T))return[];return T.filter((F)=>!!F&&typeof F==="object")}function bi(j){return vi(j,"files").flatMap((P)=>typeof P.path==="string"&&typeof P.sha256==="string"?[{path:P.path,sha256:P.sha256}]:[])}function us(j){return vi(j,"symlinks").flatMap((P)=>typeof P.path==="string"&&typeof P.target==="string"?[{path:P.path,target:P.target}]:[])}function kn(j,P){let O=Ml("git",["-C",j,...P],{encoding:"utf8",timeout:Hl,maxBuffer:52428800,stdio:["ignore","pipe","pipe"]});if(O.status!==0)throw Error(O.stderr.trim().split(`
159
- `).at(-1)??"Git command failed");return O.stdout.trim()}function hi(j){return $l("sha256").update(j).digest("hex")}async function Wt(j,P,O){let T=await Rl(j),F=Fl(T,...P.split("/"));if(F!==T&&!F.startsWith(T+gi))throw Error(`Protected path escapes the project: ${P}`);let N=Nl(T,wi(F)),M=T;for(let L of N.split(gi).filter(Boolean)){M=Xe(M,L);try{let H=await ds(M);if(H.isSymbolicLink()&&O){O.push(M);break}if(!H.isDirectory()||H.isSymbolicLink())throw Error(`Protected path crosses a non-directory: ${P}`)}catch(H){if(H.code!=="ENOENT")throw H;if(!O)await Il(M,{mode:448})}}return F}async function yi(j,P,O){let T=await Wt(j,P);try{let M=await ds(T);if(!M.isFile()||M.isSymbolicLink())throw Error(`Refusing to replace non-regular protected file: ${P}`)}catch(M){if(M.code!=="ENOENT")throw M}let F=Xe(wi(T),`.hlix-pull-${crypto.randomUUID()}.tmp`),N=await xl(F,Zn.O_WRONLY|Zn.O_CREAT|Zn.O_EXCL|Zn.O_NOFOLLOW,384);try{await N.writeFile(O),await N.sync()}finally{await N.close()}try{await _l(F,T)}catch(M){throw await kt(F,{force:!0}),M}}async function Ll(j,P,O){let T=O.length,F=await Wt(j,P,O);if(O.length>T)return;try{let N=await ds(F);if(N.isSymbolicLink()){O.push(F);return}if(!N.isFile())throw Error(`Refusing to replace non-regular project file: ${P}`)}catch(N){if(N.code!=="ENOENT")throw N}}async function er(j,P,O,T,F){let N=await Cl(Xe(Tl(),"hlix-pull-"));await fi(N,448);let M=Xe(N,"project.bundle"),L=Xe(N,"checkout");try{let H=Buffer.from(await T.arrayBuffer());if(H.byteLength!==O.bundleSize||hi(H)!==O.bundleSha256)throw Error("Downloaded revision bundle failed integrity verification.");if(await Ol(M,H,{mode:384}),kn(N,["clone","--no-hardlinks","--branch","main",M,L]),kn(L,["bundle","verify",M]),kn(L,["rev-parse","HEAD"])!==O.commitSha)throw Error("Downloaded revision bundle does not match the cloud commit.");let U=O.manifest,D=new Map;for(let B of[...U.secretFiles,...U.quarantinedResources])D.set(B.path,B);if(F&&F.files.length!==D.size)throw Error("Cloud protected files do not match the revision manifest.");let z=new Map;for(let B of F?.files??[]){let G=D.get(B.path),X=Buffer.from(B.contentBase64,"base64");if(X.toString("base64").replace(/=+$/,"")!==B.contentBase64.replace(/=+$/,"")||!G||G.kind!==B.kind||X.byteLength!==G.size||hi(X)!==G.sha256)throw Error(`Cloud protected file failed integrity verification: ${B.path}`);z.set(B.path,X)}let W=us(O.manifest),J=new Set([...U.files.map((B)=>B.path),...W.map((B)=>B.path),...P.manifest.secretFiles.map((B)=>B.path),...P.manifest.quarantinedResources.map((B)=>B.path),...z.keys()]),V=[];for(let B of[...J].sort())await Ll(j,B,V);for(let[B,G]of z)await yi(L,B,G);for(let B of[...new Set(V)].sort())await kt(B,{force:!0});if(P.manifest.git.detected){kn(j,["fetch",M,"refs/heads/main"]),kn(j,["reset","--hard","FETCH_HEAD"]);let B=new Set([...U.files.map((G)=>G.path),...W.map((G)=>G.path)]);for(let G of[...P.manifest.files,...P.manifest.symlinks])if(!B.has(G.path))await kt(Xe(j,...G.path.split("/")),{force:!0})}else{for(let B of[...P.manifest.files,...P.manifest.symlinks])await kt(Xe(j,...B.path.split("/")),{force:!0});for(let B of U.files){let G=await Wt(j,B.path);await Pl(Xe(L,...B.path.split("/")),G),await fi(G,B.executable?493:420)}for(let B of W){let G=await Wt(j,B.path);await kt(G,{force:!0}),await Al(B.target,G)}}if(F){for(let B of[...P.manifest.secretFiles,...P.manifest.quarantinedResources])if(!z.has(B.path))await kt(Xe(j,...B.path.split("/")),{force:!0})}for(let[B,G]of z)await yi(j,B,G)}finally{await kt(N,{recursive:!0,force:!0})}}function ke(j){return new Map([...bi(j).map((P)=>[P.path,`blob:${P.sha256}`]),...us(j).map((P)=>[P.path,`link:${P.target}`])])}function Jt(j,P,O){let T=ke(O.manifest),F=ke(j.manifest),N=0,M=0;for(let[H,U]of F){let D=T.get(H);if(D===void 0)N+=1;else if(D!==U)M+=1}let L=0;for(let H of T.keys())if(!F.has(H))L+=1;return{localChanged:!P.manifestSha256||j.manifestSha256!==P.manifestSha256,cloudChanged:O.id!==P.revisionId||O.generation!==P.generation,local:{revisionId:P.revisionId,generation:P.generation},cloud:{revisionId:O.id,generation:O.generation,commitSha:O.commitSha},files:{local:F.size,cloud:T.size,localOnly:N,cloudOnly:L,differing:M}}}function ps(j,P,O){let{localChanged:T,cloudChanged:F}=P;if(j==="push")return F?"conflict":T?"push":"none";if(j==="pull"){if(!F)return"none";return T&&!O?"conflict":"pull"}if(T&&F)return"conflict";return T?"push":F?"pull":"none"}function ms(j,P,O){return j==="pull"&&P.localChanged&&!O}var Ul={push:{push:"Would push the local changes as a new cloud revision.",pull:"",none:"Nothing to push — local matches the last synced revision.",conflict:"Would refuse: the cloud changed since this folder's base revision."},pull:{push:"",pull:"Would replace local files with the cloud revision.",none:"Nothing to pull — the cloud head is the local base revision.",conflict:"Would refuse: local files changed. Re-run with --force to replace them."},sync:{push:"Would push the local changes as a new cloud revision.",pull:"Would pull the cloud revision into this folder.",none:"Already in sync.",conflict:"Would refuse: local and cloud both changed since the last sync."}};function Dl(j,P,O){if(P==="push"&&O.cloud.generation===0)return`Would push ${O.files.local} files as revision 1 — this project has no cloud revision yet.`;return Ul[j][P]}function ki(j,P,O,T){let F=O.files;return[`${j} --dry-run: ${Dl(j,P,O)}`,...T?["Requires --yes (or interactive approval) to execute."]:[],"",ye([["local",`generation ${O.local.generation} (${O.local.revisionId})${O.localChanged?" — modified":""}`],["cloud",`generation ${O.cloud.generation} (${O.cloud.revisionId})${O.cloudChanged?" — ahead":""}`],["files",`${F.local} local, ${F.cloud} cloud — ${F.localOnly} local-only, ${F.cloudOnly} cloud-only, ${F.differing} differing`]])].join(`
160
- `)}var zl=new Set(["https:","http:","ssh:","git:"]);function Si(j,P){if(!j.trim())return null;let T=P.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\.git$/i,"").split("/").filter(Boolean);if(T.length!==2)return null;let[F,N]=T;return{host:j.toLowerCase(),owner:F,name:N}}function ji(j){let P=j.trim();if(!P)return null;if(!/^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(P)){let T=/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/.exec(P);return T?Si(T[1],T[2]):null}let O;try{O=new URL(P)}catch{return null}if(!zl.has(O.protocol))return null;return Si(O.hostname,O.pathname)}function Ei(j){return j.host==="github.com"}function $i(j){let P=j.find((O)=>O.name==="origin");if(P)return P;return j.length===1?j[0]:void 0}import{createHash as xi}from"node:crypto";import{createReadStream as Bl}from"node:fs";import{chmod as fs,copyFile as Wl,lstat as Pi,mkdir as gs,mkdtemp as Jl,readdir as Gl,readlink as ql,rm as tr,symlink as Kl}from"node:fs/promises";import{tmpdir as Vl}from"node:os";import{dirname as Ii,join as Ze}from"node:path";import{spawnSync as Sn}from"node:child_process";var jn=300000;function Be(j,P){let O=Sn("git",["-C",j,...P],{encoding:"utf8",timeout:jn,maxBuffer:20971520,stdio:["ignore","pipe","pipe"]});if(O.status!==0){let T=O.stderr.trim().split(`
161
- `).at(-1)??"git command failed";throw Error(T)}return O.stdout.trim()}async function Ci(j){let P=xi("sha256");for await(let O of Bl(j))P.update(O);return P.digest("hex")}async function Yl(j){for(let P of await Gl(j)){if(P===".git")continue;await tr(Ze(j,P),{recursive:!0,force:!0})}}async function En(j,P={}){if(j.uploadWarning)throw Error(j.uploadWarning);if(j.blocking.length>0)throw Error(`Project scan has blocking findings:
162
- - ${j.blocking.join(`
163
- - `)}`);let O=await Jl(Ze(Vl(),"hlix-snapshot-"));await fs(O,448);let T=Ze(O,"repo"),F=Ze(O,"source.git"),N=Ze(O,"project.bundle");try{if(j.manifest.git.detected){let J=Sn("git",["clone","--mirror","--no-hardlinks",j.root,F],{encoding:"utf8",timeout:jn,stdio:["ignore","pipe","pipe"]});if(J.status!==0)throw Error(J.stderr.trim()||"Could not mirror repository.");let V=new Map(Be(F,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]).split(`
164
- `).filter(Boolean).map((G)=>G.split("\x00",2)));for(let G of j.manifest.git.refs)if(V.get(G.name)!==G.oid)throw Error(`Git ref changed after scan: ${G.name}`);let B=Sn("git",["clone","--no-hardlinks",F,T],{encoding:"utf8",timeout:jn,stdio:["ignore","pipe","pipe"]});if(B.status!==0)throw Error(B.stderr.trim()||"Could not create snapshot clone.");if(!j.manifest.git.head)throw Error("Git repository has no HEAD commit.");Be(T,["checkout","-B","main",j.manifest.git.head])}else await gs(T,{recursive:!0,mode:448}),Be(T,["init","-b","main"]);await Yl(T);for(let J of j.manifest.files){let V=Ze(j.root,...J.path.split("/")),B=await Pi(V);if(!B.isFile()||B.isSymbolicLink())throw Error(`Source changed after scan: ${J.path}`);if(B.size!==J.size||await Ci(V)!==J.sha256)throw Error(`Source changed after scan: ${J.path}`);let G=Ze(T,...J.path.split("/"));await gs(Ii(G),{recursive:!0,mode:493}),await Wl(V,G),await fs(G,J.executable?493:420)}for(let J of j.manifest.symlinks){let V=Ze(j.root,...J.path.split("/"));if(await ql(V).catch(()=>null)!==J.target)throw Error(`Source changed after scan: ${J.path}`);let B=Ze(T,...J.path.split("/"));await gs(Ii(B),{recursive:!0,mode:493}),await Kl(J.target,B)}Be(T,["config","user.name","Hlix Import"]),Be(T,["config","user.email","import@hlix.ai"]),Be(T,["read-tree","--empty"]),Be(T,["add","--force","-A"]),Be(T,["commit","--allow-empty","-m","chore(hlix): import snapshot"]);let M=Be(T,["rev-parse","HEAD"]),L=j.manifest.git.refs.filter((J)=>J.name!=="refs/heads/main");if(L.length>0){let J=Sn("git",["-C",T,"update-ref","--stdin"],{encoding:"utf8",timeout:jn,input:L.map((V)=>`update ${V.name} ${V.oid}`).join(`
165
- `)+`
166
- `,stdio:["pipe","pipe","pipe"]});if(J.status!==0)throw Error(J.stderr.trim()||"Could not recreate the approved Git refs.")}let H=L.map((J)=>J.name),U=Sn("git",["-C",T,"bundle","create",N,"--stdin"],{encoding:"utf8",timeout:jn,input:["refs/heads/main",...H].join(`
167
- `)+`
168
- `,stdio:["pipe","pipe","pipe"]});if(U.status!==0)throw Error(U.stderr.trim()||"Could not create the approved Git bundle.");Be(T,["bundle","verify",N]),await fs(N,384);let D=(await Pi(N)).size,z=P.maxBundleBytes??524288000;if(D>z){if(j.manifest.git.detected)j.manifest.git={...j.manifest.git,detected:!1,head:null,branch:null,refs:[],commitCount:0},j.manifest.environment.warnings.push("Git history omitted to fit the upload limit; current files are preserved.");else{let J=[...j.manifest.files,...j.manifest.symlinks];if(!J.length)throw Error("The upload limit cannot fit an empty Git snapshot.");let V=Bn(J,Math.max(0,J.length-1),Math.floor(j.manifest.totals.bytes*z/D*0.9));j.manifest.files=j.manifest.files.filter((G)=>!zt(G.path,V)),j.manifest.symlinks=j.manifest.symlinks.filter((G)=>!zt(G.path,V));let B=[...j.skippedEntries??j.manifest.skipped,...V.map((G)=>({path:G.replace(/\/$/,""),reason:pn(G)}))];j.skippedEntries=B.length>5000?B:void 0,j.manifest.skipped=Wn(B),j.manifest.totals={files:j.manifest.files.length,bytes:j.manifest.files.reduce((G,X)=>G+X.size,0)}}return j.manifestJson=Ye(j.manifest),j.manifestSha256=xi("sha256").update(j.manifestJson).digest("hex"),await tr(O,{recursive:!0,force:!0}),En(j,P)}let W=await Ci(N);return{bundlePath:N,bundleSha256:W,bundleSize:D,commitSha:M,dispose:()=>tr(O,{recursive:!0,force:!0})}}catch(M){throw await tr(O,{recursive:!0,force:!0}),M}}function Qe(j,P){let O=j[P];return typeof O==="string"&&O.trim()?O.trim():void 0}function sd(j){return[Ee(j,".hlix","config.json"),Ee(j,".hlix",".gitignore"),Ee(j,".hlixignore")].filter((P)=>!rr(P))}function Ri(j,P){for(let O of P)tt(O,{force:!0});if(P.length===0)return;try{ed(Ee(j,".hlix"))}catch{}}var od=44,_i=(j)=>`${j.padEnd(od)}\r`;async function id(j,P){let O=$i(P);if(!O)return{kind:"none"};let T=ji(O.url);if(!T)return{kind:"unresolved",remoteName:O.name,remoteUrl:O.url,reason:"could not be parsed as a repository URL"};if(!Ei(T))return{kind:"unresolved",remoteName:O.name,remoteUrl:O.url,reason:`not a GitHub repository (${T.host})`};let N=(await j.projects.list()).find((M)=>(M.repos??[]).some((L)=>L.owner.toLowerCase()===T.owner.toLowerCase()&&L.name.toLowerCase()===T.name.toLowerCase()));if(N)return{kind:"owned",owner:T.owner,name:T.name,projectId:N.id,projectName:N.name};return{kind:"connect",owner:T.owner,name:T.name}}function Oi(j,P=!0){let{manifest:O}=j,T=[...O.secretFiles,...O.quarantinedResources].map((M)=>M.path),F=O.environment.warnings,N=(M)=>M.slice(0,8).join(", ")+(M.length>8?`, +${M.length-8} more (full list: hlix import --dry-run --json)`:"");return[`Uploaded: ${O.totals.files} files, ${O.symlinks?.length??0} links, ${O.totals.bytes} bytes, ${O.git.commitCount} commits${P?" (scan preview)":""}`,`Skipped: ${N(O.skipped.filter((M)=>M.reason!=="built-in ignore"&&M.reason!=="Hlix-managed ignore").map((M)=>`${M.path} (${M.reason})`))||"ignored paths"}`,`Secrets: ${T.length} files ${P?"to move":"moved"} encrypted${T.length?` (${N(T)})`:""}`,`Warnings: ${F.length?N(F):"none"}`,`Blocked: ${j.blocking.length?j.blocking.join(`
169
- `):"none"}`].join(`
170
- `)+`
171
- `}function et(j,P){if(j.json)j.stdout(re(se(dt.name,{action:"none",warning:P})));else j.stdout(`${P}
172
- `);return 0}function ad(j){let P=j.manifest.environment.install,O=j.manifest.secretFiles.length+j.manifest.quarantinedResources.length;if(P.length===0&&O===0&&j.manifest.secretKeys.length===0)return null;let T=["Hlix will upload this project and encrypted protected files to your selected workspace."];if(P.length>0)T.push("Detected cloud setup commands:",...P.map((F)=>`- ${F}`));if(j.manifest.secretKeys.length>0)T.push("Project secret keys available to cloud tasks:",...j.manifest.secretKeys.map((F)=>`- ${F}`));if(j.manifest.quarantinedResources.length>0)T.push("Quarantined resources (preserved but not activated):",...j.manifest.quarantinedResources.map((F)=>`- ${F.kind}: ${F.path}`));if(j.manifest.environment.warnings.length>0)T.push("Environment warnings:",...j.manifest.environment.warnings.map((F)=>`- ${F}`));return T.push("Setup runs inside the isolated Coding Workspace and may access project secrets."),T.join(`
173
- `)}var dt={name:"import",summary:"Import a local project into your Hlix workspace",usage:["Usage: hlix import [folder] [options]","","Options:"," --attach If the origin repo already belongs to a project, bind this"," folder to it instead of importing as a new one (no prompt)"," --dry-run Scan and report without uploading"," --env-file <path> Override automatic development dotenv precedence"," --history <mode> preserve (default) or sanitize (current files only)"," --include <path> Include one ignored path (secrets still move encrypted)"," --name <name> Cloud project name (defaults to folder name)"," --no-connect-origin Never connect or check the local repo's origin remote"," --stack <stack> Override detected stack"," --yes Approve the reviewed upload and cloud setup"," --json Machine-readable output (never contains secret values)"].join(`
174
- `),supportsJson:!0,options:["attach","dry-run","env-file","history","include","name","no-connect-origin","stack","yes"],args:{min:0,max:1},async run(j){if(j.args.length>1)throw Error("import accepts at most one folder.");let P=await nd(nr(j.cwd,j.args[0]??".")),O=r({env:j.env,flags:j.flags,cwd:P});if(O.conflict)return et(j,`Import left the binding unchanged: ${O.conflict}`);if(!O.workspaceId||!O.credential)throw new e("workspace_required","No workspace selected. Run `hlix auth login` first.");let T=ot(P),F=Ee(P,".hlix","import.json");if(rr(F)&&j.flags["dry-run"]!==!0){let H;try{H=JSON.parse(Ql(F,"utf8"))}catch{return et(j,"Import left the saved session unchanged: recovery data could not be read. Preserve .hlix/import.json for recovery.")}if(!H||H.schemaVersion!==1||!H.request||!H.originPlan)return et(j,"Import left the saved session unchanged: invalid recovery data. Preserve .hlix/import.json for recovery.");if(H.workspaceId!==O.workspaceId||H.apiUrl!==O.baseUrl)return et(j,"Import left the saved session unchanged: it belongs to another workspace or API.");if(T?.projectId){let D=H.importId?await j.requireClient(P).imports.get(H.importId,{signal:j.signal}):void 0;if(T.projectId!==(D?.import.projectId??D?.import.requestedProjectId))return tt(F,{force:!0}),tt(Ee(P,".hlix","import.bundle"),{force:!0}),et(j,"Discarded a stale import session; kept this folder's current project binding.")}let U=await ld(j,{...H,root:P});if(U!==null)return U;j.flags.name??=H.request.name,j.flags.stack??=H.request.stack,j.flags.include??=H.include,j.flags["env-file"]??=H.envFile,j.flags.history??=H.sanitize?"sanitize":"preserve"}if(T?.projectId&&j.flags["dry-run"]!==!0){if(j.json)j.stdout(re(se(dt.name,{action:"none",warning:"This folder is already imported; kept its binding. Use hlix push to upload changes."})));else j.stdout(`This folder is already imported; kept its binding. Use hlix push to upload changes.
175
- `);return 0}let N=Qe(j.flags,"history");if(N&&N!=="preserve"&&N!=="abort-on-findings"&&N!=="sanitize")throw Error("--history must be `preserve`, `sanitize`, or `abort-on-findings`.");let M=Qe(j.flags,"include");if(M&&(hs(P,nr(P,M))===".."||hs(P,nr(P,M)).startsWith("../")||M.split(/[\\/]/).some((H)=>H===".git"||H===".hlix")))throw new e("invalid_usage","--include must name a path inside this folder, excluding .git and .hlix metadata.");if(M)j.flags.include=hs(P,nr(P,M)).replaceAll("\\","/");let L=[];if(!T&&j.flags["dry-run"]!==!0)L=sd(P),gt(P,{schemaVersion:1,workspaceId:O.workspaceId,apiUrl:O.baseUrl});try{return await cd(j,{root:P,workspaceId:O.workspaceId,apiUrl:O.baseUrl,historyFlag:N})}catch(H){if(j.signal?.aborted){if(!rr(F))Ri(P,L);throw new e("cancelled","Import cancelled.")}if(H instanceof e&&H.code==="cancelled"){if(!rr(F))Ri(P,L)}throw H}}};async function cd(j,P){let{root:O,historyFlag:T}=P,F=j.json?void 0:(U)=>j.stderr(_i(U)),N=await He(O,{refreshIgnore:j.flags["dry-run"]!==!0,...Qe(j.flags,"env-file")?{envFile:Qe(j.flags,"env-file")}:{},environment:j.env,historyMode:T==="sanitize"?"sanitize":"preserve",include:Qe(j.flags,"include")?.replace(/^\.\//,"").replace(/\/$/,""),...F?{onProgress:F}:{},...j.signal?{signal:j.signal}:{}});if(F)j.stderr(`
176
- `);if(!j.json&&N.ignoreReport)j.stderr(`${N.ignoreReport}
177
- `);if(N.uploadWarning)return et(j,N.uploadWarning);if(j.signal?.throwIfAborted(),j.flags["dry-run"]!==!0&&N.blocking.length===0){let U=ad(N);if(U&&j.flags.yes!==!0){if(j.json||!j.confirm)throw new e("approval_required","Import needs approval for protected files or cloud setup. Review with `hlix import --dry-run`, then repeat with `--yes`.");if(!await j.confirm(U))throw new e("cancelled","Import cancelled.")}}let M={kind:"none"};if(j.flags["dry-run"]!==!0&&N.blocking.length===0&&j.flags["no-connect-origin"]!==!0){if(M=await id(j.requireClient(O),N.gitRemotes),M.kind==="owned"){let U=j.flags.attach===!0;if(!U&&!j.json&&j.flags.yes!==!0&&j.confirm){let D=[`Repository ${M.owner}/${M.name} is already attached to project "${M.projectName}" in this workspace.`,"This folder looks like a worktree or branch of that project.",`Attach this folder's work to "${M.projectName}" instead of creating a new project?`].join(`
178
- `);if(U=await j.confirm(D),!U)j.stderr(`Continuing as a new, repo-less import.
179
- `)}else if(!U&&!j.json)j.stderr(`Repository ${M.owner}/${M.name} belongs to project "${M.projectName}"; rerun with --attach to bind this folder to it.
180
- `);if(U){gt(O,{schemaVersion:1,projectId:M.projectId,workspaceId:P.workspaceId,apiUrl:P.apiUrl});let D={root:O,projectId:M.projectId,projectName:M.projectName};if(j.json)j.stdout(re(se(dt.name,D)));else j.stdout(`Attached ${O}
181
- Project: ${M.projectName} (${M.projectId})
182
- Run \`hlix pull\` to sync this folder.
183
- `);return 0}}else if(M.kind==="connect"){if(!j.json)j.stderr(`Origin repository ${M.owner}/${M.name} detected — connecting it to this project.
184
- `)}else if(M.kind==="unresolved"&&!j.json)j.stderr(`Origin remote '${M.remoteName}' (${M.remoteUrl}) was not connected: ${M.reason}.
185
- `)}let L={root:O,name:Qe(j.flags,"name")??rd(O),stack:Qe(j.flags,"stack")??N.manifest.stack,files:N.manifest.totals.files,bytes:N.manifest.totals.bytes,symlinks:N.manifest.symlinks,activeEnvFiles:N.manifest.activeEnvFiles,secretKeys:N.manifest.secretKeys,protectedFiles:N.manifest.secretFiles.length+N.manifest.quarantinedResources.length,environment:N.manifest.environment,historicalSecretFindings:N.manifest.historicalSecretFindings,quarantinedResources:N.manifest.quarantinedResources,mcpServers:N.manifest.mcpServers,skipped:N.skippedEntries??N.manifest.skipped,blocking:N.blocking,manifestSha256:N.manifestSha256};if(j.flags["dry-run"]===!0){if(j.json)j.stdout(re(se(dt.name,L)));else j.stdout(Oi(N));return N.blocking.length?1:0}if(N.blocking.length)throw new e("scan_blocked",`Project scan blocked import:
186
- - ${N.blocking.join(`
187
- - `)}`,{findings:N.blockingHistoryFindings,fixtureFindings:0,blocking:N.blocking});j.signal?.throwIfAborted();let H;try{H=await En(N)}catch(U){j.signal?.throwIfAborted();let D=`Import left this folder unchanged because a consistent snapshot could not be built: ${U instanceof Error?U.message:"local files unavailable"}. Run hlix import again after local writes finish.`;if(j.json)j.stdout(re(se(dt.name,{action:"none",warning:D})));else j.stdout(`${D}
188
- `);return 0}try{j.signal?.throwIfAborted();let U=j.requireClient(O),D={schemaVersion:1,root:O,workspaceId:P.workspaceId,apiUrl:P.apiUrl,originPlan:M,include:Qe(j.flags,"include")?.replace(/^\.\//,"").replace(/\/$/,""),envFile:Qe(j.flags,"env-file"),sanitize:!N.manifest.git.detected,request:{idempotencyKey:Xl(),name:L.name,stack:L.stack,defaultBranch:"main",historyMode:N.manifest.git.historyMode,manifest:N.manifest,manifestSha256:N.manifestSha256,bundleSha256:H.bundleSha256,bundleSize:H.bundleSize,commitSha:H.commitSha}};gt(O,ot(O)),await td(H.bundlePath,Ee(O,".hlix","import.bundle"),Zl.COPYFILE_EXCL),Ge(Ee(O,".hlix","import.json"),D);let z=await U.imports.create(D.request);if(D.importId=z.import.id,D.upload=z.upload,Ge(Ee(O,".hlix","import.json"),D),z.import.status==="pending_upload"){if(!z.upload)throw Error(`Import ${z.import.id} is ${z.import.status} but has no upload target.`);await U.imports.uploadBundle(z.upload,new Blob([Uint8Array.from(await Ai(H.bundlePath))]),{signal:j.signal,onProgress:(J,V)=>{if(!j.json)j.stderr(_i(`uploading ${J}/${V} bytes`))}})}let W=z.import.status==="ready"?{import:z.import}:await U.imports.finalizeAndWait(z.import.id,{secrets:N.secretValues,protectedFiles:N.protectedFiles},{signal:j.signal});return sr(j,D,W.import)}finally{await H.dispose()}}async function sr(j,P,O){let{root:T,originPlan:F}=P,N=j.requireClient(T),M=O.projectId??O.requestedProjectId;if(!M||!O.revisionId||!O.generation)throw Error("Import completed without project revision metadata.");let L=ot(T);if(L?.projectId&&L.projectId!==M)return tt(Ee(T,".hlix","import.json"),{force:!0}),tt(Ee(T,".hlix","import.bundle"),{force:!0}),et(j,"Discarded a stale import session; kept this folder's current project binding.");if(F.kind==="connect")try{await N.projects.connectRepo(M,{owner:F.owner,name:F.name})}catch(U){if(!j.json){let D=U instanceof Error?U.message:String(U);j.stderr(`Origin repository ${F.owner}/${F.name} could not be connected: ${D}
189
- `)}}gt(T,{schemaVersion:1,projectId:M,workspaceId:P.workspaceId,apiUrl:P.apiUrl}),it(T,{schemaVersion:1,revisionId:O.revisionId,generation:O.generation,commitSha:P.request.commitSha,manifestSha256:P.request.manifestSha256,historyMode:P.request.manifest.git.historyMode,snapshotOnly:P.sanitize,includedPaths:P.include?[P.include]:[],rootName:P.request.manifest.rootName,files:Object.fromEntries(ke(P.request.manifest))});let H={projectId:M,revisionId:O.revisionId,generation:O.generation,commitSha:P.request.commitSha,files:P.request.manifest.totals.files,bytes:P.request.manifest.totals.bytes};if(j.json)j.stdout(re(se(dt.name,H)));else j.stderr(`
190
- `),j.stdout(Oi({manifest:P.request.manifest,blocking:[]},!1)+`Imported ${P.request.name}.
191
- `);return tt(Ee(T,".hlix","import.json"),{force:!0}),tt(Ee(T,".hlix","import.bundle"),{force:!0}),0}async function ld(j,P){let{root:O}=P,T=j.requireClient(O),F=Ee(O,".hlix","import.json");if(!j.json)j.stderr(`Resuming the saved import.
192
- `);let N;if(P.importId)N=await T.imports.get(P.importId,{signal:j.signal});else{let U=await T.imports.create(P.request);P.upload=U.upload,N=U}if(P.importId=N.import.id,Ge(F,P),N.import.projectId||N.import.status==="ready")return sr(j,P,N.import);if(N.import.status==="finalizing"&&Date.parse(N.import.updatedAt)>Date.now()-900000){let U=await T.imports.waitUntilReady(P.importId,{signal:j.signal});return sr(j,P,U.import)}if(["pending_upload","uploaded","failed","expired"].includes(N.import.status)&&Date.parse(N.import.expiresAt)<=Date.now())return tt(Ee(O,".hlix","import.bundle"),{force:!0}),tt(F,{force:!0}),j.stderr(`Saved import expired before completion; discarded its recovery state and starting a fresh import.
193
- `),null;if(!["pending_upload","uploaded","finalizing"].includes(N.import.status))return et(j,`Import left the saved session unchanged: the server reports ${N.import.status}. No replacement project was created.`);let M=await He(O,{environment:j.env,historyMode:P.sanitize?"sanitize":P.request.historyMode,include:P.include,envFile:P.envFile,signal:j.signal});if(M.uploadWarning)return et(j,M.uploadWarning);let L=(U)=>Ye([U.secretFiles,U.quarantinedResources,U.secretKeys]);if(L(M.manifest)!==L(P.request.manifest)||M.blocking.length)throw Error("Protected files changed since the pending import. Restore the reviewed files and rerun hlix import; the saved import has been preserved.");if(N.import.status==="pending_upload"){if(!P.upload)throw Error(`Import ${P.importId} has no saved upload target.`);await T.imports.uploadBundle(P.upload,new Blob([Uint8Array.from(await Ai(Ee(O,".hlix","import.bundle")))]),{signal:j.signal})}let H=await T.imports.finalizeAndWait(P.importId,{secrets:M.secretValues,protectedFiles:M.protectedFiles},{signal:j.signal});return sr(j,P,H.import)}import{spawnSync as dd}from"node:child_process";import{existsSync as ud,mkdirSync as pd,writeFileSync as md}from"node:fs";import{dirname as fd}from"node:path";function gd(j){return j==="global"?["# My rules","","Hlix Code reads this file in every project you open, before the project's","own rules. Write how you want an agent to work with you: the tone, the","things to always do, the things to never do.",""].join(`
194
- `):["# Project rules","","Hlix Code and every other coding agent that opens this repository read","this file. Write the rules that are true of THIS project: how to run its","tests, its conventions, what not to touch.",""].join(`
195
- `)}function hd(j){return j.VISUAL?.trim()||j.EDITOR?.trim()||"vi"}var ys={name:"rules",summary:"Show or edit the rules files the coding agent reads",usage:["Usage: hlix rules [--edit] [--global] [--cwd <dir>] [--json]","","Without --edit it reports which files Hlix Code loads and how big they are.","","--edit opens one in $EDITOR, creating it with a short header if it does not","exist yet. --global edits your own rules (~/.hlix/AGENTS.md, read in every",`project); without it the project's file (${f.join(", then ")}).`].join(`
196
- `),supportsJson:!0,options:["edit","global"],async run(j){let P=y({cwd:j.cwd,configDir:".hlix",env:j.env}),O=j.flags.global===!0;if(j.flags.edit===!0){if(j.json)throw new e("invalid_usage","`hlix rules --edit` opens an editor, so it has no --json form.");let T=O?Hr(j.env):Mr(j.cwd,".hlix")?.path??`${j.cwd}/AGENTS.md`;if(!ud(T))pd(fd(T),{recursive:!0}),md(T,gd(O?"global":"project"),"utf8"),j.stdout(`Created ${T}.
197
- `);let F=hd(j.env),N=dd(F,[T],{stdio:"inherit"});if(N.error)throw new e("invalid_usage",`Could not run ${F}: ${N.error.message}`);return N.status??0}if(j.json){let T=(F)=>F?{path:F.path,characters:F.content.length}:null;return j.stdout(re(se(ys.name,{user:T(P.global),project:T(P.project)}))),0}return j.stdout(`${w(P,j.cwd)}
198
- `),0}};var ws={name:"standards",summary:"Show the standards other agent tools left in this folder",usage:["Usage: hlix standards [--cwd <dir>] [--json]","","Reads the instruction files, skills, slash commands, MCP servers and","subagents this project already carries for Claude Code, Cursor, Windsurf,","Gemini, Codex, Cline, Copilot and VS Code, and shows where each came from.","Hlix Code loads all of it at startup; nothing has to be copied or rewritten.","","Server urls, headers and environment values are never printed."].join(`
199
- `),supportsJson:!0,async run(j){let P=b(j.cwd,i(j.env),{env:j.env});if(j.json)return j.stdout(re(se(ws.name,{instructions:P.instructions.map((O)=>({path:O.path,source:O.source,scope:O.scope,characters:O.content.length,...O.note?{note:O.note}:{}})),skills:P.skills,commands:[...P.commands.map((O)=>({path:O.path,source:O.source,scope:O.scope})),...P.generatedCommands.map((O)=>({path:O.path,source:O.source,scope:O.scope,command:O.name}))],mcpServers:P.mcpServers.map((O)=>({path:O.path,source:O.source,scope:O.scope,name:O.name,transport:"command"in O.config?"stdio":"http"})),subagents:P.subagents.map((O)=>({path:O.path,source:O.source,scope:O.scope,name:O.name,description:O.description,...O.model?{model:O.model}:{}})),skipped:P.skipped}))),0;return j.stdout(Mo(P,j.cwd)),0}};var Ni=(j)=>j instanceof Error?j.message:String(j),Ti=(j)=>j.split(/\s*\n\s*/).join(" ").trim();async function x(j,P,O,T,F){try{let N=await He(P,{historyMode:O,environment:j.env,rootName:T}),M=s(P)?.files,L=ke(N.manifest);return{changedFiles:M?[...new Set([...Object.keys(M),...L.keys()])].filter((U)=>M[U]!==L.get(U)).length:null,files:N.manifest.totals.files,manifestSha256:N.manifestSha256,changed:F?N.manifestSha256!==F:null,blocking:N.blocking,error:null}}catch(N){return{changedFiles:null,files:null,manifestSha256:null,changed:null,blocking:[],error:Ni(N)}}}var vs={name:"status",summary:"Show the workspace, folder binding, and local-vs-cloud drift",usage:["Usage: hlix status [--cwd <dir>] [--json]","","Reports the resolved workspace and API with the source that decided each,","whether this folder is bound to a project, and whether the working tree or","the cloud head has moved since the last sync. Every finding is a line in","the output, so the command itself always exits 0; only an argument error","(rejected before it runs) exits 2."].join(`
200
- `),supportsJson:!0,async run(j){let P=r({env:j.env,flags:j.flags,cwd:j.cwd}),O=P.binding,T=O?s(O.root):null,F=O?await x(j,O.root,T?.snapshotOnly?"sanitize":T?.historyMode??"preserve",T?.rootName,T?.manifestSha256):null,N=null;if(O?.config.projectId&&P.credential&&!P.conflict)try{let H=(await j.requireClient().revisions.head(O.config.projectId)).revision;N={revisionId:H.id,generation:H.generation,changed:T?H.id!==T.revisionId||H.generation!==T.generation:null,error:null,errorMessage:null}}catch(H){N={revisionId:"",generation:0,changed:null,error:_r(H).code,errorMessage:H instanceof qe?"no cloud revision yet — `hlix push` uploads this folder as revision 1":Ni(H)}}let M={cwd:j.cwd,workspace:{id:P.workspaceId,source:P.workspaceSource},api:{baseUrl:P.baseUrl,source:P.baseUrlSource},credential:{present:P.credential!==null,source:P.credentialSource,path:P.credentialPath},conflict:P.conflict,project:O?{root:O.root,projectId:O.config.projectId??null,workspaceId:O.config.workspaceId,apiUrl:O.config.apiUrl}:null,revision:T?{id:T.revisionId,generation:T.generation,commitSha:T.commitSha}:null,local:F,cloud:N};if(j.json)return j.stdout(re(se(vs.name,M))),0;let L=[["folder",j.cwd],["workspace",P.workspaceId?`${P.workspaceId} (from ${P.workspaceSource})`:"none — run `hlix auth login --workspace <id>`"],["api",`${P.baseUrl} (from ${P.baseUrlSource})`],["credential",u(P)??"none — run `hlix auth login`"],["project",O?O.config.projectId??`initialized at ${O.root}, not imported yet`:"none — run `hlix import .` to bind this folder"]];if(T)L.push(["revision",`generation ${T.generation} (${T.revisionId})`]);if(F){if(L.push(["local",F.error?`could not scan: ${F.error}`:F.changed===null?`${F.files} files, no synced base revision`:F.changed?`${F.files} files, modified since the last sync`:`${F.files} files, matches the last sync`]),F.blocking.length>0)L.push(["blocking",F.blocking.join("; ")])}if(N)L.push(["cloud",N.error==="not_found"?Ti(N.errorMessage??N.error):N.error?`not checked — ${Ti(N.errorMessage??N.error)}`:N.changed?`generation ${N.generation} available — run \`hlix pull\``:`generation ${N.generation}, up to date`]);if(P.conflict)L.push(["conflict",P.conflict]);return j.stdout(`${ye(L)}
201
- `),0}};import{spawnSync as Fi}from"node:child_process";var bs={name:"terminal",summary:"Open a shell into the project's Coding Workspace",usage:["Usage: hlix terminal [project-id] [--print] [--web] [--json]","","With no id, the project this folder is bound to is used."," --print Show the ssh command and browser url instead of connecting"," --web Open the browser terminal instead of ssh"].join(`
202
- `),supportsJson:!0,options:["print","web"],args:{min:0,max:1},async run(j){let P=j.args[0]??t(j.cwd)?.config.projectId;if(!P)throw new e("missing_argument","A project id is required, or run this inside a folder bound to a project.");let O=await j.requireClient().projects.terminal(P);if(j.json)return j.stdout(re(se(bs.name,O))),O.available?0:1;if(!O.available){let M=O.environmentState?` (environment: ${O.environmentState})`:"";throw new e("not_found",`${O.reason??"Terminal unavailable"}${M}`)}let T=j.flags.print===!0,F=j.flags.web===!0;if(T||F&&!O.webTerminalUrl||!F&&!O.sshCommand)return j.stdout(`${ye([["ssh",O.sshCommand??"not available"],["browser",O.webTerminalUrl??"not available"]])}
203
- `),0;if(F){if(Fi(process.platform==="darwin"?"open":"xdg-open",[O.webTerminalUrl],{stdio:"ignore"}).status!==0)j.stdout(`${O.webTerminalUrl}
204
- `);return 0}return Fi("sh",["-c",O.sshCommand],{stdio:"inherit"}).status??1}};import{createHash as Mi}from"node:crypto";import{relative as yd,resolve as wd}from"node:path";import{readFile as vd,realpath as bd}from"node:fs/promises";function kd(j,P,O){return Mi("sha256").update(`project-push-v1\x00${j}\x00${P}\x00${O}`).digest("hex")}var Sd={schemaVersion:1,revisionId:"",generation:0,commitSha:""},Pn={id:"",generation:0,commitSha:"",manifest:{}};async function Gt(j,P){try{return await j.revisions.head(P)}catch(O){if(O instanceof qe)return null;throw O}}async function Hi(j,P){let O=await Gt(j,P);if(O)return O;throw new e("not_found","This project has no cloud files yet, so there is nothing to pull or push against. Import the folder into a new project with `hlix import`, or create the first revision from the dashboard.")}async function Le(j,{allowUnsynced:P=!1}={}){let O=t(j);if(!O?.config.projectId)throw new e("not_initialized","This folder is not bound to an imported Hlix project. Run `hlix import .` first.");let T=s(O.root)??(P?Sd:null);if(!T)throw new e("not_initialized","This folder is bound to a project but has never been pulled. Run `hlix pull` first.");return{root:await bd(O.root),config:O.config,state:T}}async function We(j,P,O,T,F,N=!1){let M=await He(j,{historyMode:s(j)?.snapshotOnly?"sanitize":O,environment:P,rootName:T,include:F,refreshIgnore:N});if(M.blocking.length>0)throw new e("scan_blocked",`Project scan blocked sync:
205
- - ${M.blocking.join(`
206
- - `)}`);return M}async function ks(j,P,O,T){let{state:F,config:N}=await Le(T,{allowUnsynced:!0}),M=j.requireClient(),[L,H]=await Promise.all([We(T,j.env,F.snapshotOnly?"sanitize":F.historyMode??"preserve",F.rootName,typeof j.flags.include==="string"?j.flags.include:void 0),O==="pull"?Hi(M,N.projectId):Gt(M,N.projectId)]),U=Jt(L,F,H?.revision??Pn),D=ps(O,U,j.flags.force===!0),z=ms(D,U,j.flags.yes===!0);if(j.json)j.stdout(re(se(P,{dryRun:!0,action:D,approvalRequired:z,...U})));else j.stdout(`${ki(O,D,U,z)}
207
- `);if(O==="push")return 0;return D==="conflict"?1:0}async function jd(j,P){if(j.flags.yes===!0)return;if(j.json||!j.confirm)throw new e("approval_required","`pull --force` replaces local files. Review with `hlix pull --dry-run`, then repeat with `--yes`.");let O=[`hlix pull --force will replace this folder with cloud revision ${P.cloud.generation}.`,`Local-only files to delete: ${P.files.localOnly}`,`Files to replace with the cloud copy: ${P.files.differing}`,"Local changes that were never pushed cannot be recovered by Hlix."].join(`
208
- `);if(!await j.confirm(O))throw new e("cancelled","Pull cancelled.")}function Ed(j,P){let O=P??{},T={...j.manifest,secretFiles:O.secretFiles??[],activeEnvFiles:O.activeEnvFiles??[],secretKeys:O.secretKeys??[],envCollisions:O.envCollisions??[],quarantinedResources:O.quarantinedResources??[],mcpServers:O.mcpServers??[]};return{manifest:T,manifestSha256:Mi("sha256").update(Ye(T)).digest("hex")}}async function cr(j,P,O,T,{inheritProtected:F=!1}={}){let{state:N,config:M}=await Le(j,{allowUnsynced:!0}),L=P.requireClient(),H=N.snapshotOnly?"sanitize":N.historyMode??"preserve",U=O??await We(j,P.env,H,N.rootName,void 0,!0);if(!P.json&&U.ignoreReport)P.stderr(`${U.ignoreReport}
209
- `);if(U.uploadWarning){if(!P.json)P.stderr(`${U.uploadWarning}
210
- `);return{action:"none",warning:U.uploadWarning,revisionId:N.revisionId,generation:N.generation}}if(!P.json)for(let X of U.manifest.skipped.filter((K)=>K.reason!=="built-in ignore"&&K.reason!=="Hlix-managed ignore"))P.stderr(`Skipped: ${X.path} (${X.reason})
211
- `);let D=T??(await Gt(L,M.projectId))?.revision??Pn,z=D.manifest,W=[...z?.files??[],...z?.symlinks??[]],J=ke(U.manifest),V=W.filter((X)=>!J.has(X.path)&&pi(X.path,U.includedPaths)||(U.skippedEntries??U.manifest.skipped).some((K)=>X.path===K.path||X.path.startsWith(`${K.path}/`)));if(V.length){let X=`Push left the cloud unchanged: skipped local paths include ${V.slice(0,10).map((K)=>K.path).join(", ")}. Use --include or adjust .hlixignore before pushing.`;if(!P.json)P.stderr(`${X}
212
- `);return{action:"none",warning:X,revisionId:N.revisionId,generation:N.generation}}if(D.id!==N.revisionId||D.generation!==N.generation){if(F)throw new e("conflict","Cloud changed since the local base. Kept both copies unchanged; run hlix sync to reconcile them.");if(!P.json)P.stderr(`Cloud changed since the local base. Kept both copies unchanged; run hlix sync to reconcile them.
213
- `);return{action:"none",warning:"Cloud changed since the local base. Kept both copies unchanged; run hlix sync to reconcile them.",revisionId:N.revisionId,generation:N.generation}}if(N.manifestSha256&&U.manifestSha256===N.manifestSha256)return it(j,{...N,includedPaths:U.includedPaths}),{action:"none",revisionId:N.revisionId,generation:N.generation};let B;try{B=await En(U)}catch(X){return{action:"none",warning:`Push left both copies unchanged because a consistent snapshot could not be built: ${X instanceof Error?X.message:"local files unavailable"}. Retry after local writes finish.`,revisionId:N.revisionId,generation:N.generation}}let G=F?Ed(U,D.manifest):{manifest:U.manifest,manifestSha256:U.manifestSha256};try{if(W.filter((ee)=>(U.skippedEntries??U.manifest.skipped).some((Z)=>ee.path===Z.path||ee.path.startsWith(`${Z.path}/`))).length)return{action:"none",warning:"Push left the cloud unchanged because fitting the upload would omit existing cloud files.",revisionId:N.revisionId,generation:N.generation};let K=await L.revisions.createUpload(M.projectId,{idempotencyKey:kd(N.revisionId,G.manifestSha256,B.bundleSha256),expectedRevisionId:N.revisionId||null,expectedGeneration:N.generation,manifest:G.manifest,manifestSha256:G.manifestSha256,bundleSha256:B.bundleSha256,bundleSize:B.bundleSize,commitSha:B.commitSha});if(K.revisionUpload.status==="pending_upload"){if(!K.upload)throw Error("Revision upload has no bundle target.");await L.revisions.uploadBundle(K.upload,new Blob([Uint8Array.from(await vd(B.bundlePath))]),{onProgress:(ee,Z)=>{if(!P.json)P.stderr(`Uploading ${ee}/${Z} bytes\r`)}})}let ie=await L.revisions.finalize(M.projectId,K.revisionUpload.id,F?{secrets:{},protectedFiles:[],inheritProtected:!0}:{secrets:U.secretValues,protectedFiles:U.protectedFiles});if(!ie.revision)throw Error("Revision finalized without head metadata.");return it(j,{schemaVersion:1,revisionId:ie.revision.id,generation:ie.revision.generation,commitSha:ie.revision.commitSha,manifestSha256:F?U.manifestSha256:ie.revision.manifestSha256,historyMode:N.historyMode??"preserve",snapshotOnly:!U.manifest.git.detected,includedPaths:U.includedPaths,rootName:N.rootName??U.manifest.rootName,files:Object.fromEntries(ke(U.manifest))}),{action:"push",...ie.revision}}finally{await B.dispose()}}async function Li(j,P,O,T,F){let{state:N,config:M}=await Le(j,{allowUnsynced:!0}),L=P.requireClient(),H=N.snapshotOnly?"sanitize":N.historyMode??"preserve",U=T??await We(j,P.env,H,N.rootName),D=F??(await Hi(L,M.projectId)).revision;if(D.id===N.revisionId&&D.generation===N.generation)return{action:"none",revisionId:N.revisionId,generation:N.generation};let z=N.manifestSha256?U.manifestSha256!==N.manifestSha256:(()=>{let{files:K}=Jt(U,N,D);return K.localOnly+K.differing>0})();if(z&&!O)throw new e("conflict","Local files changed since the last sync. Push them, or use `hlix pull --force` to replace them.");if(z)await jd(P,Jt(U,N,D));let[W,J]=await Promise.all([L.revisions.downloadBundle(M.projectId,D.id),L.revisions.protectedFiles(M.projectId)]);await er(j,U,D,W,J);let V=Qn(D.manifest),B=V.historyMode??H,G=V.rootName??N.rootName??U.manifest.rootName,X=await We(j,P.env,B,G);return it(j,{schemaVersion:1,revisionId:D.id,generation:D.generation,commitSha:D.commitSha,manifestSha256:X.manifestSha256,historyMode:B==="sanitize"?"preserve":B,snapshotOnly:N.snapshotOnly,rootName:G,files:Object.fromEntries(ke(X.manifest))}),{action:"pull",revisionId:D.id,generation:D.generation,commitSha:D.commitSha}}function or(j,P,O){if(j.json)j.stdout(re(se(P,O)));else if("action"in O&&O.action==="none")j.stdout("warning"in O?`${O.warning}
214
- `:`Already in sync.
215
- `);else j.stdout(`${String("action"in O?O.action:"sync")} complete.
216
- `)}var $n={name:"push",summary:"Push local changes as an immutable cloud revision",usage:["Usage: hlix push [--include <path>] [--dry-run] [--json]","","Uploads this folder as the next cloud revision of the bound project.","A project with no cloud revision yet takes this folder as revision 1."," --dry-run Show what would change, upload nothing"," --json Machine-readable output"].join(`
217
- `),supportsJson:!0,options:["dry-run","include"],async run(j){if(j.args.length)throw Error("push accepts no positional arguments.");let P;try{P=await Le(j.cwd,{allowUnsynced:!0})}catch(M){if(!(M instanceof e)||M.code!=="not_initialized")throw M;return or(j,$n.name,{action:"none",warning:M.message}),0}let{root:O}=P,{state:T}=await Le(O,{allowUnsynced:!0}),F=typeof j.flags.include==="string"?yd(O,wd(O,j.flags.include)).replaceAll("\\","/"):void 0;if(F===".."||F?.startsWith("../")||F?.split("/").some((M)=>M===".git"||M===".hlix"))throw new e("invalid_usage","--include must name a path inside this folder, excluding .git and .hlix metadata.");if(j.flags.include=F,j.flags["dry-run"]===!0)return ks(j,$n.name,"push",O);let N=await We(O,j.env,T.snapshotOnly?"sanitize":T.historyMode??"preserve",T.rootName,F,!0);return or(j,$n.name,await cr(O,j,N)),0}},ir={name:"pull",summary:"Pull the cloud head into the local project",usage:["Usage: hlix pull [--force] [--yes] [--dry-run] [--json]",""," --force Replace local changes with the cloud revision"," --yes Skip the confirmation --force otherwise requires"," --dry-run Report the divergence and change nothing"].join(`
218
- `),supportsJson:!0,options:["force","yes","dry-run"],async run(j){if(j.args.length)throw Error("pull accepts no positional arguments.");let{root:P}=await Le(j.cwd,{allowUnsynced:!0});if(j.flags["dry-run"]===!0)return ks(j,ir.name,"pull",P);return or(j,ir.name,await Li(P,j,j.flags.force===!0)),0}},ar={name:"sync",summary:"Reconcile local and cloud changes without guessing conflicts",usage:"Usage: hlix sync [--dry-run] [--json]",supportsJson:!0,options:["dry-run"],async run(j){if(j.args.length)throw Error("sync accepts no positional arguments.");let{root:P,state:O,config:T}=await Le(j.cwd,{allowUnsynced:!0});if(j.flags["dry-run"]===!0)return ks(j,ar.name,"sync",P);let F=j.requireClient(),[N,M]=await Promise.all([We(P,j.env,O.snapshotOnly?"sanitize":O.historyMode??"preserve",O.rootName),Gt(F,T.projectId)]),L=M?.revision??Pn,H=Jt(N,O,L);if(H.localChanged&&H.cloudChanged)throw new e("conflict","Both local and cloud changed since the last sync. Pull or push explicitly after reviewing the conflict.");let U=H.localChanged?await cr(P,j,N,L):H.cloudChanged?await Li(P,j,!1,N,M?.revision):{action:"none",revisionId:O.revisionId,generation:O.generation};return or(j,ar.name,U),0}};import{lstat as $d,readFile as Pd,readlink as Id,rm as Di,symlink as Cd,writeFile as xd,chmod as Rd}from"node:fs/promises";import{watch as _d}from"node:fs";function v(j){return[...j.pulled!==void 0?[`mirror: pulled revision ${j.pulled} from the cloud`]:[],...j.conflicts.map((P)=>`mirror: ${P.path} changed here and in the cloud — kept the cloud's, yours is ${P.savedAs}`),...j.pushed!==void 0?[`mirror: pushed revision ${j.pushed} to the cloud`]:[]]}async function Ad(j,P){let O=new Map;for(let T of P){let F=`${j}/${T}`;try{let N=await $d(F);if(N.isSymbolicLink())O.set(T,{kind:"link",target:await Id(F)});else if(N.isFile())O.set(T,{kind:"file",bytes:await Pd(F),mode:N.mode&511})}catch(N){if(N.code!=="ENOENT")throw N}}return O}async function Ss(j,P,O){let T=await Wt(j,P);if(await Di(T,{force:!0}),O.kind==="link"){await Cd(O.target,T);return}await xd(T,O.bytes,{mode:O.mode}),await Rd(T,O.mode)}var Od=(j)=>j.toISOString().replace(/\.\d+Z$/,"Z").replace(/[-:]/g,"");async function Td(j,P,O,T,F,N){let M=new Map(Object.entries(F.files??{})),L=ke(T.manifest),H=ke(N.manifest),U=[],D=[],z=[];for(let Z of new Set([...L.keys(),...H.keys()])){let q=L.get(Z),ne=H.get(Z),Q=M.get(Z);if(q===ne||q===Q)continue;if(ne===Q){if(q===void 0)D.push(Z);else U.push(Z);continue}if(q!==void 0)z.push(Z)}let W=[...T.manifest.secretFiles,...T.manifest.quarantinedResources].map((Z)=>Z.path),J=await Ad(j,[...U,...z,...W]),V=await P.client.revisions.downloadBundle(O,N.id);await er(j,T,N,V,null);for(let Z of W){let q=J.get(Z);if(q)await Ss(j,Z,q)}let B=Qn(N.manifest),G=B.historyMode??F.historyMode??"preserve",X=B.rootName??F.rootName??T.manifest.rootName,K=await We(j,P.env,G,X);it(j,{schemaVersion:1,revisionId:N.id,generation:N.generation,commitSha:N.commitSha,manifestSha256:K.manifestSha256,historyMode:G,rootName:X,snapshotOnly:F.snapshotOnly,files:Object.fromEntries(ke(K.manifest))});for(let Z of U){let q=J.get(Z);if(q)await Ss(j,Z,q)}for(let Z of D)await Di(`${j}/${Z}`,{force:!0});let ie=`.local-${Od((P.now??(()=>new Date))())}`,ee=[];for(let Z of z){let q=J.get(Z);if(!q)continue;await Ss(j,`${Z}${ie}`,q),ee.push({path:Z,savedAs:`${Z}${ie}`})}return ee}function Ui(j,P){if(!P)return!1;if(!P.files)return P.manifestSha256===j.manifestSha256;let O=Object.entries(P.files),T=ke(j.manifest);return O.length===T.size&&O.every(([F,N])=>T.get(F)===N)}var Nd=(j)=>({requireClient:()=>j.client,env:j.env??{},json:!0,stderr:()=>{}});async function js(j,P,{cloud:O,onReport:T}){let{config:F,state:N}=await Le(j,{allowUnsynced:!0}),M=F.projectId,L={conflicts:[]},H=await We(j,P.env,N.historyMode??"preserve",N.rootName),U;if(O){let D=(await Gt(P.client,M))?.revision,z=ke(H.manifest),W=N.files?[...new Set([...Object.keys(N.files),...z.keys()])].filter((J)=>N.files[J]!==z.get(J)).length:Ui(H,N)?0:z.size;if(T?.({conflicts:[],drift:{localChanges:W,cloudChanged:Boolean(D&&(D.id!==N.revisionId||D.generation!==N.generation))}}),D&&(D.id!==N.revisionId||D.generation!==N.generation))L.conflicts=await Td(j,P,M,H,N,D),L.pulled=D.generation,H=await We(j,P.env,N.historyMode??"preserve",N.rootName);U=D??Pn}if(Ui(H,s(j)))return L;if(!O){let D=ke(H.manifest),z=N.files??{},W=[...new Set([...Object.keys(z),...D.keys()])].filter((J)=>z[J]!==D.get(J)).length;T?.({conflicts:[],drift:{localChanges:W,cloudChanged:!1}})}try{let D=await cr(j,Nd(P),H,U,{inheritProtected:!0});if(D.action==="push")L.pushed=D.generation;return L}catch(D){if(!O&&D instanceof e&&D.code==="conflict")return js(j,P,{cloud:!0,...T?{onReport:T}:{}});throw D}}function Fd(j){if(!j)return!1;let P=j.split("\\").join("/");return/^(\.git|\.hlix|node_modules)(\/|$)/.test(P)||/\/(\.git|node_modules)(\/|$)/.test(P)}var Md=300;async function k(j,P,O){let{config:T}=await Le(j,{allowUnsynced:!0}),F=O.signal,N=!1,M=!1,L=null,H=!1,U=async()=>{while(N||M){if(await Nt(Md,F),F?.aborted)return;let W=N;N=!1,M=!1;try{let J=await js(j,P,{cloud:W,onReport:O.onReport});if(O.onReport(J),W&&!H)H=!0,O.onCaughtUp?.()}catch(J){O.onError(J)}}},D=()=>{if(L||F?.aborted)return;L=U().finally(()=>{if(L=null,N||M)D()})},z=_d(j,{recursive:!0,...F?{signal:F}:{}},(W,J)=>{if(Fd(typeof J==="string"?J:null))return;M=!0,D()});z.on("error",O.onError);try{for await(let W of P.client.revisions.watch(T.projectId,F?{signal:F}:{})){if(W.kind==="head"&&W.generation===s(j)?.generation)continue;N=!0,D()}}finally{z.close(),await L}}function Hd(j,P){if(j.json)j.stdout(`${JSON.stringify(se(In.name,P))}
219
- `);else for(let O of v(P))j.stdout(`${O}
220
- `)}var In={name:"mirror",summary:"Keep this folder a live mirror of the project's cloud files",usage:["Usage: hlix mirror [--once] [--json]","","Catches this folder up with the cloud, then follows both ways until","stopped: a change in the cloud is pulled down, a save here is pushed up.","When both sides changed one file, the cloud's version wins and yours is","kept beside it as <file>.local-<timestamp>. `.env` and other protected","files are never written down."," --once One catch-up pass, then exit"," --json One envelope per pass, one per line (JSONL)"].join(`
221
- `),supportsJson:!0,options:["once"],agentTool:!1,async run(j){if(j.args.length)throw Error("mirror accepts no positional arguments.");let{root:P,config:O}=await Le(j.cwd,{allowUnsynced:!0}),T={client:j.requireClient(),env:j.env};if(j.flags.once===!0){let F=await js(P,T,{cloud:!0});if(j.json)j.stdout(re(se(In.name,F)));else{let N=v(F);j.stdout(N.length?`${N.join(`
222
- `)}
223
- `:`Already in sync.
224
- `)}return 0}if(!j.json)j.stdout(`Mirroring ${P} with project ${O.projectId}. Ctrl-C stops.
225
- `);return await k(P,T,{...j.signal?{signal:j.signal}:{},onCaughtUp:()=>{let F=s(P)?.generation??0;if(j.json)j.stdout(`${JSON.stringify(se(In.name,{caughtUp:!0,generation:F}))}
226
- `);else j.stdout(`Caught up at revision ${F}; following the cloud.
227
- `)},onReport:(F)=>Hd(j,F),onError:(F)=>j.stderr(`mirror: ${F instanceof Error?F.message:String(F)}
228
- `)}),0}};import{lstat as $s,readFile as Ld,realpath as Ud}from"node:fs/promises";import{basename as Es,dirname as Dd,extname as zd,join as lr,parse as zi,resolve as dr}from"node:path";function qt(j,P){let O=j.flags[P];return typeof O==="string"&&O.trim()?O.trim():void 0}function Ps(j){let P=qt(j,"project");if(P)return{root:j.cwd,projectId:P};return Bd(j.cwd)}function Bd(j){let P=t(j);if(!P?.config.projectId)throw new e("not_initialized","This folder is not bound to an Hlix project. Run `hlix import .` first.");return{root:P.root,projectId:P.config.projectId}}async function Is(j,P){let O=await $s(j);if(O.isSymbolicLink()||!O.isFile())throw Error(`Refusing to import a non-regular file: ${j}`);if(O.size>P)throw Error(`Import file exceeds ${P} bytes: ${j}`);return{path:await Ud(j),content:await Ld(j,"utf8")}}function Cs(j,P,O,T){if(j.json)j.stdout(re(se(P,O)));else j.stdout(`${T}
229
- `)}function Wd(j){let P=/^---\r?\n([\s\S]*?)\r?\n---/.exec(j)?.[1];return(P?/^name:\s*(.+?)\s*$/m.exec(P)?.[1]:void 0)?.replace(/^["']|["']$/g,"").trim()||void 0}var Jd=[lr(".claude","skills"),lr(".agents","skills"),lr(".hlix","skills")];async function Gd(j,P){let O=[dr(j,P),...Jd.map((T)=>dr(j,T,P))];for(let T of O)if(await $s(T).then(()=>!0,()=>!1))return T;throw new e("not_found",`No skill at ${P}. Pass the SKILL.md or its folder, for example .claude/skills/${P}.`)}var xs={name:"skill import",summary:"Activate a local skill for the bound cloud project",usage:"Usage: hlix skill import <SKILL.md|folder> [--name <slug>] [--project <id>] [--json]",supportsJson:!0,options:["name","project"],args:{min:1,max:1},async run(j){if(j.args.length!==1)throw Error("skill import requires one file or folder.");let P=Ps(j),O=await Gd(j.cwd,j.args[0]),T=await $s(O);if(T.isSymbolicLink())throw Error(`Refusing to import a symlink: ${O}`);let F=T.isDirectory()?lr(O,"SKILL.md"):O,N=await Is(F,200000),M=T.isDirectory()?Es(O):Es(F)==="SKILL.md"?Es(Dd(F)):zi(F).name,L=qt(j,"name")??M;if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(L))throw Error("Skill name must be a lowercase kebab-case slug.");let H=await j.requireClient().resources.importSkill(P.projectId,{slug:L,content:N.content});return Cs(j,xs.name,H.skill,`Imported skill ${L}`),0}},Rs={name:"agent import",summary:"Create a project-scoped agent from a local Markdown brief",usage:"Usage: hlix agent import <markdown-file> [--name <name>] [--runtime <runtime>] [--duty <duty>] [--profile <profile>] [--project <id>] [--json]",supportsJson:!0,options:["name","runtime","duty","profile","project"],args:{min:1,max:1},async run(j){if(j.args.length!==1)throw Error("agent import requires one Markdown file.");let P=Ps(j),O=dr(j.cwd,j.args[0]);if(![".md",".mdx"].includes(zd(O).toLowerCase()))throw Error("Agent imports must be Markdown files.");let T=await Is(O,20000),F=qt(j,"runtime")??m;if(!o.includes(F)){let H=new Intl.ListFormat("en",{type:"disjunction"}).format(o);throw Error(`--runtime must be ${H}.`)}let N=qt(j,"duty")??"executor";if(N!=="executor"&&N!=="intake")throw Error("--duty must be executor or intake.");let M=qt(j,"name")??Wd(T.content)??zi(O).name.replace(/[-_]+/g," "),L=await j.requireClient().resources.importAgent(P.projectId,{name:M,instructions:T.content,runtimeKind:F,duty:N});return Cs(j,Rs.name,L.agent,L.agent.duty==="intake"?`Imported agent ${L.agent.name} as this project's intake agent`:`Imported agent ${L.agent.name}`),0}},_s={name:"mcp import",summary:"Explicitly activate one validated local MCP server",usage:"Usage: hlix mcp import <.mcp.json> [--server <name>] [--allow-stdio] [--project <id>] [--json]",supportsJson:!0,options:["server","allow-stdio","project"],args:{min:1,max:1},async run(j){if(j.args.length!==1)throw Error("mcp import requires one MCP JSON file.");let P=Ps(j),O=await Is(dr(j.cwd,j.args[0]),200000),T;try{T=JSON.parse(O.content)}catch{throw Error("MCP config is not valid JSON.")}let F=Object.entries(T.mcpServers??{});if(F.length===0)throw Error("MCP config contains no servers.");let N=qt(j,"server");if(!N&&F.length>1)throw Error("MCP config contains multiple servers; select one with --server <name>.");let M=N?F.find(([B])=>B===N):F[0];if(!M)throw Error(`MCP server not found: ${N}`);let[L,H]=M,U=H.type==="http"||H.type==="sse"?H.type:typeof H.command==="string"?"stdio":typeof H.url==="string"?"http":null;if(!U)throw Error(`MCP server ${L} has no supported transport.`);if(U==="stdio"&&j.flags["allow-stdio"]!==!0)throw Error("Stdio MCP servers execute a local command in the cloud; repeat with --allow-stdio.");let D=H.env&&typeof H.env==="object"&&!Array.isArray(H.env)?H.env:{},z=H.headers&&typeof H.headers==="object"&&!Array.isArray(H.headers)?H.headers:{};if(Object.values(z).some((B)=>typeof B!=="string"))throw Error(`MCP server ${L} headers must be strings.`);for(let[B,G]of Object.entries(D)){if(typeof G!=="string")continue;let X=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(G)?.[1];if(X&&X!==B)throw new e("invalid_usage",`MCP server ${L}: env ${B} references \${${X}}, but a placeholder must be the variable's own name — write "${B}": "\${${B}}" and store the secret as ${B}.`)}let W=Object.values(z).flatMap((B)=>[...B.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)].map((G)=>G[1]));if(Object.keys(z).length>0&&W.length===0)throw Error("MCP remote headers must use ${KEY} placeholders; literal credentials are refused.");let J=/^(?:(?:Bearer|Basic|Token) )?\$\{[A-Za-z_][A-Za-z0-9_]*\}$/i;if(Object.values(z).some((B)=>!J.test(B)))throw Error("MCP remote headers must be ${KEY} or an approved auth scheme followed by ${KEY}.");let V=await j.requireClient().resources.importMcp(P.projectId,{name:L,transport:U,...typeof H.command==="string"?{command:H.command}:{},...Array.isArray(H.args)&&H.args.every((B)=>typeof B==="string")?{args:H.args}:{},...typeof H.url==="string"?{url:H.url}:{},...Object.keys(z).length>0?{headers:z}:{},envKeys:[...new Set([...Object.keys(D),...W])].sort()});return Cs(j,_s.name,V.mcpServer,`Imported MCP server ${L}`),0}};import{spawnSync as qd}from"node:child_process";import{chmod as Kd,realpath as Vd,writeFile as Yd}from"node:fs/promises";import{basename as Xd,dirname as Zd,relative as Qd,resolve as Wi,sep as eu}from"node:path";var Bi=64;function xn(j){let P=t(j.cwd),T=(typeof j.flags.project==="string"?j.flags.project:void 0)??P?.config.projectId;if(!T)throw new e("not_initialized","This folder is not bound to a Hlix project. Run `hlix import .`, or pass --project <id>.");return{projectId:T,root:P?.root??j.cwd}}var Cn=(j,P)=>typeof j[P]==="string"?j[P]:void 0,As={name:"secrets list",summary:"Show every secret the project holds, masked, with its source file",usage:["Usage: hlix secrets list [--project <id>] [--json]","","One row per (key, source file). Values are masked to their last four","characters and there is no flag that unmasks them — `hlix secrets export`","is the one command that returns plaintext, and it is audited."].join(`
230
- `),supportsJson:!0,options:["project"],async run(j){let{projectId:P}=xn(j),O=await j.requireClient().secrets.listEntries(P);if(j.json)return j.stdout(re(se(As.name,O))),0;if(O.entries.length===0)j.stdout(`No secrets stored for this project.
231
- `);else j.stdout(`${Je(["key","source","format","value","updated"],O.entries.map((T)=>[T.key,T.source,T.format||"-",T.maskedValue,T.updatedAt?.slice(0,10)??"-"]))}
232
- `);for(let T of O.warnings)j.stderr(`warning: ${T}
233
- `);return 0}},Os={name:"secrets set",summary:"Create or replace one secret in the store",usage:["Usage: hlix secrets set <KEY> [value] [--from-stdin] [--source <file>] [--project <id>] [--json]",""," --from-stdin Read the value from stdin instead of the argument, so it"," never reaches shell history or `ps`. Use this for real"," credentials: `pbpaste | hlix secrets set API_KEY --from-stdin`."," --source The file the value belongs to, e.g. apps/api/.env.local."," Omitted means the project root .env.","","Exactly one trailing newline is stripped from stdin, so a piped value does","not acquire the shell's."].join(`
234
- `),supportsJson:!0,options:["from-stdin","source","project"],args:{min:1,max:2},async run(j){let{projectId:P}=xn(j),O=j.args[0],T=j.flags["from-stdin"]===!0;if(T&&j.args.length>1)throw new e("invalid_usage","Pass the value as an argument or with --from-stdin, not both.");if(!T&&j.args.length<2)throw new e("missing_argument","A value is required. Pass it as an argument, or pipe it with --from-stdin.");let F;if(T){if(!j.readStdin)throw new e("invalid_usage","--from-stdin is not available in this context.");F=(await j.readStdin()).replace(/\r?\n$/,"")}else F=j.args[1];let N=Cn(j.flags,"source"),M=await j.requireClient().secrets.upsertEntries(P,{entries:[{key:O,value:F,...N?{source:N}:{}}]});if(j.json)return j.stdout(re(se(Os.name,M))),M.written>0?0:1;if(M.written===0)throw new e("bad_request",`The store refused ${O}: --source must be a project-relative file path.`);return j.stdout(`${ye([["key",O],["source",N??".env"]])}
235
- `),0}},Ts={name:"secrets delete",summary:"Remove one secret from the store",usage:["Usage: hlix secrets delete <KEY> [--source <file>] [--project <id>] [--json]","","Without --source the key is removed from EVERY file that declares it,",'which is what "delete this secret" usually means. Removing nothing exits 1.'].join(`
236
- `),supportsJson:!0,options:["source","project"],args:{min:1,max:1},async run(j){let{projectId:P}=xn(j),O=j.args[0],T=Cn(j.flags,"source"),F=await j.requireClient().secrets.deleteEntry(P,O,T);if(j.json)return j.stdout(re(se(Ts.name,F))),F.removed>0?0:1;if(F.removed===0)return j.stderr(`No stored secret named ${O}${T?` in ${T}`:""}.
237
- `),1;return j.stdout(`Removed ${F.removed} entr${F.removed===1?"y":"ies"} for ${O}.
238
- `),0}},ur={name:"secrets import",summary:"Load this folder's secret files into the project secrets store",usage:["Usage: hlix secrets import [file...] [--project <id>] [--json]","","With no arguments, every secret file the project scanner detects. Naming","files narrows it to those; a named file the scanner does not consider a","secret is refused rather than uploaded.","","The files are uploaded as bytes and the server parses them, so every shape","it knows lands here: dotenv and .envrc, Terraform variables, Java","properties, Spring YAML, .NET appsettings, Azure Functions local settings,","npm credentials, Rails database.yml, wrangler/fly TOML and Serverless all","become readable entries under their own path. An opaque credential (a","private key, a keystore, a service-account JSON) is kept byte-exact","instead. A file whose plaintext this platform does not hold — SOPS,","Ansible Vault, git-crypt — and a .env.example are reported as skipped.","","A file that holds key/value pairs REPLACES what the store held for that","path: the file on this machine is the truth."].join(`
239
- `),supportsJson:!0,options:["project"],args:{min:0,max:64},async run(j){let{projectId:P,root:O}=xn(j),T=await He(O,{historyMode:"preserve",environment:j.env}),F=T.blocking.filter((z)=>!z.startsWith(as));if(F.length>0)throw new e("scan_blocked",`Project scan blocked the import:
240
- - ${F.join(`
241
- - `)}`);let N=T.protectedFiles.filter((z)=>z.kind==="dotenv"||z.kind==="credential"),M=await Vd(j.cwd),L=j.args.map((z)=>Qd(T.root,Wi(M,z)).split(eu).join("/")),H=L.filter((z)=>!N.some((W)=>W.path===z));if(H.length>0)throw new e("invalid_usage",`Not a secret file in this project: ${H.join(", ")}`);let U=L.length>0?N.filter((z)=>L.includes(z.path)):N;if(U.length===0)return j.stdout(j.json?re(se(ur.name,{imported:[],skipped:[],warnings:[],written:0,rejected:[]})):`No secret files found in this project.
242
- `),0;if(U.length>Bi)throw new e("invalid_usage",`${U.length} secret files exceeds the ${Bi} the store accepts in one request. Name the files to import, a batch at a time.`);let D=await j.requireClient().secrets.importFiles(P,U.map((z)=>({path:z.path,contentBase64:z.contentBase64})));if(j.json)return j.stdout(re(se(ur.name,D))),0;if(D.imported.length>0)j.stdout(`${Je(["source","format","stored"],D.imported.map((z)=>[z.path,z.format||"-",z.kind==="file"?"as file":`${z.entries} entr${z.entries===1?"y":"ies"}`]))}
243
- `);if(j.stdout(`${D.written} value${D.written===1?"":"s"} stored.
244
- `),D.imported.some((z)=>z.kind!=="file"))j.stdout(`Each imported file replaced what the store held under its path; keys the file no longer has are gone.
245
- `);for(let z of D.skipped)j.stderr(`skipped ${z.path}: ${z.reason}
246
- `);for(let z of D.warnings)j.stderr(`warning: ${z}
247
- `);for(let z of D.rejected)j.stderr(`rejected ${z}: the store refused its source path
248
- `);return 0}};function tu(j){return qd("git",["-C",Zd(j),"ls-files","--error-unmatch","--",Xd(j)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).status===0}var Ns={name:"secrets export",summary:"Render one source file back out of the store, values in clear",usage:["Usage: hlix secrets export [--source <file>] [--format <id>] [--out <path>] [--project <id>] [--json]",""," --source Which stored file to render. Omitted means the root .env."," --format Re-render it as a different shape (dotenv, tfvars, …)."," Omitted means the shape the values were parsed as."," --out Write it to this path, mode 0600, instead of stdout. A path"," git TRACKS is refused: an exported file carries plaintext and"," must not become a commit.","","This is the one command that returns secret values, and the server writes","an audit row for every call."].join(`
249
- `),supportsJson:!0,options:["source","format","out","project"],async run(j){let{projectId:P}=xn(j),O=Cn(j.flags,"source"),T=Cn(j.flags,"format"),F=Cn(j.flags,"out"),N=F===void 0?void 0:Wi(j.cwd,F);if(N!==void 0&&tu(N))throw new e("invalid_usage",`Refusing to overwrite a git-tracked file with secret values: ${N}`);let M=await j.requireClient().secrets.exportEntries(P,{...O?{source:O}:{},...T?{format:T}:{}});if(N!==void 0)await Yd(N,M,{mode:384}),await Kd(N,384);if(j.json)return j.stdout(re(se(Ns.name,{source:O??null,format:T??null,out:N??null,bytes:Buffer.byteLength(M),...N===void 0?{content:M}:{}}))),0;if(N===void 0)j.stdout(M);else j.stdout(`${ye([["wrote",N],["mode","0600"],["bytes",String(Buffer.byteLength(M))]])}
250
- `);return 0}};function Ms(j){let P=j.flags.project;if(typeof P==="string"&&P)return P;return t(j.cwd)?.config.projectId??void 0}function Fs(j,P){let O=j[P];if(typeof O!=="string"||O.trim()==="")throw new e("missing_argument",`--${P} is required.`);return O}var Hs={name:"cycles create",summary:"Propose a cycle, which starts the project working on it",usage:["Usage: hlix cycles create <project-id> --title <t> --description <d> [--json]","","This is the command that DISPATCHES work. The proposal enters the project's","own loop, which plans the cycle, creates its tasks and starts the coders —","using the project's harness (see `hlix harness get`).","","`adopted` is true when the loop took it on this call, false when it was","recorded and will be planned on the next pass. Neither is an error. The API","returns no cycle id: the roadmap owns cycles, so find it with `hlix tasks","list --project <id>` once planning has run."].join(`
251
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(j){let P=j.args[0],O=Fs(j.flags,"title"),T=Fs(j.flags,"description"),F=await j.requireClient().cycles.propose({projectId:P,title:O,description:T});if(j.json)return j.stdout(re(se(Hs.name,F))),0;return j.stdout(`${ye([["project",P],["title",O],["status",F.adopted?"adopted — the project is planning it now":"recorded — it will be planned on the next pass"]])}
252
- `),0}},Ls={name:"tasks create",summary:"Add a task to a project's board",usage:["Usage: hlix tasks create <project-id> --description <d> [--title <t>] [--json]","","Creates the task row. It does NOT start it: standalone task execution is","not implemented server-side and answers 501 by design. Work is dispatched","by its cycle — use `hlix cycles create` for that."].join(`
253
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(j){let P=j.args[0],O=Fs(j.flags,"description"),T=typeof j.flags.title==="string"?j.flags.title:void 0,F=await j.requireClient().tasks.create({projectId:P,description:O,...T?{title:T}:{}});if(j.json)return j.stdout(re(se(Ls.name,F))),0;return j.stdout(`${ye([["task",F.id],["project",P],["status",F.status??"queued"],["note","not started — dispatch with `hlix cycles create`"]])}
254
- `),0}},Us={name:"harness get",summary:"Show which coder runs, and which setting chose it",usage:["Usage: hlix harness get [project-id] [--project <id>] [--json]","","With a project id — or from a bound folder — what that project would run.","Otherwise the workspace-wide answer. `source` names the setting that","decided: a project preference, the workspace preference, or the system","default."].join(`
255
- `),supportsJson:!0,options:["project"],args:{min:0,max:1},async run(j){let P=j.args[0]??Ms(j),O=j.requireClient(),T=P?await O.modelConfig.resolvedProjectHarness(P):await O.modelConfig.resolvedHarness();if(j.json)return j.stdout(re(se(Us.name,T))),0;return j.stdout(`${ye([["scope",P?`project ${P}`:"workspace"],["harness",T.harness],["source",T.source]])}
256
- `),0}},Ds={name:"harness set",summary:"Choose the coder a project or the workspace runs",usage:[`Usage: hlix harness set <${o.join("|")}> [project-id] [--org] [--json]`,"","With a project id, sets that project's preference. With --org, the","workspace-wide one that projects fall back to. This is a PERSISTENT server","setting that every future run on that scope uses, and it is audited.","","It is not the same thing as the local `harness` config key, which only","picks the coder Hlix Code spawns on this machine."].join(`
257
- `),supportsJson:!0,options:["org"],args:{min:1,max:2},async run(j){let P=j.args[0];if(!o.includes(P))throw new e("invalid_usage",`harness must be one of ${o.join(", ")}; got "${P}".`);let O=j.flags.org===!0,T=j.args[1]??(O?void 0:Ms(j));if(T&&O)throw new e("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!T&&!O)throw new e("invalid_usage","Name the project to set, or pass --org for the whole workspace.");let F=j.requireClient(),N=T?await F.modelConfig.setProjectHarness(T,P):await F.modelConfig.setHarness(P);if(j.json)return j.stdout(re(se(Ds.name,N))),0;return j.stdout(`${ye([["scope",T?`project ${T}`:"workspace"],["harness",P]])}
258
- `),0}},zs={name:"harness clear",summary:"Remove a harness preference so the scope below it decides",usage:["Usage: hlix harness clear [project-id] [--org] [--json]","","With a project id, drops that project's preference so it inherits the","workspace's answer (or the system default). With --org, drops the","workspace-wide one. Audited, like every write on this setting.","","Answers `not_found` when that scope had no preference to clear — the","setting is already off, and saying so beats reporting a change that was","never made. Check the result with `hlix harness get`."].join(`
259
- `),supportsJson:!0,options:["org"],args:{min:0,max:1},async run(j){let P=j.flags.org===!0,O=j.args[0]??(P?void 0:Ms(j));if(O&&P)throw new e("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!O&&!P)throw new e("invalid_usage","Name the project to clear, or pass --org for the whole workspace.");let T=j.requireClient(),F=O?await T.modelConfig.clearProjectHarness(O):await T.modelConfig.clearHarness();if(j.json)return j.stdout(re(se(zs.name,F))),0;return j.stdout(`${ye([["scope",O?`project ${O}`:"workspace"],["harness","cleared — the scope below decides now"]])}
260
- `),0}};var d=[Lr,Ur,Lt,vs,bs,ws,ys,Dr,zr,Br,ls,dt,ar,ir,$n,In,xs,Rs,_s,As,Os,Ts,ur,Ns,Wr,Jr,Gr,Kr,Vr,Yr,Xr,Ls,Hs,Us,Ds,zs];
261
- export{e,R,s,u,t,r,n,a,p,l,o,m,g,S,h,c,i,E,f,y,I,w,b,C,_,A,x,v,k,d};