@hlix/cli 0.6.0 → 0.7.1

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,233 +0,0 @@
1
- #!/usr/bin/env node
2
- class e extends Error{code;details;constructor(j,P,I){super(P);if(this.name="CliError",this.code=j,I!==void 0)this.details=I}}var C=1,V=(j,P)=>({schemaVersion:1,command:j,data:P}),dt=(j,P)=>({schemaVersion:1,command:j,error:P});function q(j){return`${JSON.stringify(j,null,2)}
3
- `}function ce(j){let P=Math.max(0,...j.map(([I])=>I.length));return j.map(([I,R])=>`${I.padEnd(P)} ${R}`).join(`
4
- `)}function Ee(j,P){let I=j.map((O,_)=>Math.max(O.length,...P.map((T)=>(T[_]??"").length))),R=(O)=>O.map((_,T)=>_.padEnd(I[T])).join(" ").trimEnd();return[R(j),R(I.map((O)=>"-".repeat(O))),...P.map(R)].join(`
5
- `)}import{statSync as ii}from"node:fs";import{dirname as ai,resolve as ci}from"node:path";import{closeSync as En,constants as ut,existsSync as Gt,fsyncSync as ss,lstatSync as $n,mkdirSync as qo,openSync as os,readFileSync as is,renameSync as Vo,statSync as as,unlinkSync as cs,writeFileSync as Xo}from"node:fs";import{homedir as Yo}from"node:os";import{dirname as Zo,join as Pn}from"node:path";function Ke(j=process.env){let P=j.HLIX_CONFIG_HOME??j.XDG_CONFIG_HOME??Pn(Yo(),".config");return Pn(P,"hlix","credentials.json")}function ls(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 I=JSON.parse(is(Ke(j),"utf8"));return I.apiKey&&I.baseUrl?I:null}catch{return null}}function ds(j=process.env){let P=Ke(j);return Gt(P)?P:null}function Cn(j=process.env){let P=Ke(j);if(!Gt(P))return{path:P,removed:!1,reason:"absent"};let I=$n(P);if(I.isSymbolicLink()||!I.isFile())throw Error("Refusing to remove a credential path that is not a regular file.");let R=process.getuid?.();if(R!==void 0&&as(P).uid!==R)throw Error("Refusing to remove a credential file owned by another user.");let O;try{O=JSON.parse(is(P,"utf8"))}catch{O=null}let _=O;if(!_||typeof _.apiKey!=="string"||typeof _.baseUrl!=="string")throw Error(`Refusing to remove ${P}: it is not a credential written by this CLI.`);return cs(P),{path:P,removed:!0,reason:"removed"}}function us(j,P=process.env){let I=Ke(P),R=Zo(I);if(qo(R,{recursive:!0,mode:448}),$n(R).isSymbolicLink())throw Error("Refusing to write credentials through a symlinked directory.");if(Gt(I)){let T=$n(I);if(T.isSymbolicLink()||!T.isFile())throw Error("Refusing to replace a credential path that is not a regular file.");let A=process.getuid?.();if(A!==void 0&&as(I).uid!==A)throw Error("Refusing to replace a credential file owned by another user.")}let O=Pn(R,`.credentials.${process.pid}.${crypto.randomUUID()}.tmp`),_;try{_=os(O,ut.O_WRONLY|ut.O_CREAT|ut.O_EXCL|ut.O_NOFOLLOW,384),Xo(_,`${JSON.stringify(j,null,2)}
6
- `,"utf8"),ss(_),En(_),_=void 0,Vo(O,I);let T=os(R,ut.O_RDONLY);try{try{ss(T)}catch(A){let N=A.code;if(N!=="EINVAL"&&N!=="ENOTSUP")throw A}}finally{En(T)}}catch(T){if(_!==void 0)En(_);if(Gt(O))cs(O);throw T}return I}import{constants as Wt,existsSync as qt,lstatSync as ms,mkdirSync as Qo,openSync as ei,closeSync as ps,fsyncSync as ti,readFileSync as fs,renameSync as ni,unlinkSync as ri,writeFileSync as In}from"node:fs";import{dirname as si,join as pt,resolve as Vt}from"node:path";function oi(j){if(!qt(j))return;let P=ms(j);if(P.isSymbolicLink()||!P.isFile())throw Error(`Refusing to replace a non-regular Hlix file: ${j}`)}function mt(j,P){let I=si(j);if(Qo(I,{recursive:!0,mode:448}),ms(I).isSymbolicLink())throw Error(`Refusing to write through a symlinked Hlix directory: ${I}`);oi(j);let R=pt(I,`.hlix-${process.pid}-${crypto.randomUUID()}.tmp`),O;try{O=ei(R,Wt.O_WRONLY|Wt.O_CREAT|Wt.O_EXCL|Wt.O_NOFOLLOW,384),In(O,`${JSON.stringify(P,null,2)}
7
- `,"utf8"),ti(O),ps(O),O=void 0,ni(R,j)}catch(_){if(O!==void 0)ps(O);if(qt(R))ri(R);throw _}}function ft(j){return pt(Vt(j),".hlix","config.json")}function gs(j){return pt(Vt(j),".hlix","state.json")}function Je(j){try{let P=JSON.parse(fs(ft(j),"utf8"));return P.schemaVersion===1&&P.workspaceId&&P.apiUrl?P:null}catch{return null}}function Ge(j,P){mt(ft(j),P);let I=pt(Vt(j),".hlix",".gitignore");if(!qt(I))In(I,`state.json
8
- `,{mode:420,flag:"wx"});let R=pt(Vt(j),".hlixignore");if(!qt(R))In(R,`# Additional project-local paths to exclude from Hlix snapshots.
9
- `,{mode:420,flag:"wx"})}function Fe(j,P){mt(gs(j),P)}function Te(j){try{let P=JSON.parse(fs(gs(j),"utf8"));return P.schemaVersion===1&&P.revisionId&&P.generation>0?P:null}catch{return null}}var xn="https://server.hlix.ai";function Yt(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=ci(j);for(;;){let I=Je(P);if(I)return{root:P,config:I};let R=ai(P);if(R===P)return null;P=R}}function ys(j){try{return ii(j).isDirectory()}catch{return!1}}function Xt(j){if(typeof j!=="string")return;let P=j.trim();return P?P:void 0}var hs=(j,P)=>j.replace(/\/+$/,"")===P.replace(/\/+$/,"");function r(j){let{env:P,flags:I,cwd:R}=j,O=t(R),_=ls(P),T=_?P.HLIX_API_KEY?"env":P.HLIX_SESSION_TOKEN?"session":"file":null,A=T==="file"?_:null,N=Xt(I["base-url"]),F=Xt(P.HLIX_BASE_URL),H=Xt(I.workspace),L=Xt(P.HLIX_WORKSPACE_ID),D=N??F??O?.config.apiUrl??A?.baseUrl??xn,K=N?"flag":F?"env":O?.config.apiUrl?"project":A?.baseUrl?"credential":"default",z=H??L??O?.config.workspaceId??A?.organizationId??null,M=H?"flag":L?"env":O?.config.workspaceId?"project":A?.organizationId?"credential":null;return{baseUrl:D,baseUrlSource:K,workspaceId:z,workspaceSource:M,credential:_,credentialSource:T,credentialPath:Ke(P),binding:O,conflict:li(O,{flagBaseUrl:N,envBaseUrl:F,flagWorkspace:H,envWorkspace:L})}}function li(j,P){if(!j)return null;let I=`${j.root} is bound to`,R="Drop the override, or point --cwd at a folder bound to it.";if(P.flagWorkspace&&P.flagWorkspace!==j.config.workspaceId)return`${I} workspace ${j.config.workspaceId}, but --workspace names ${P.flagWorkspace}. ${R}`;if(P.envWorkspace&&P.envWorkspace!==j.config.workspaceId)return`${I} workspace ${j.config.workspaceId}, but HLIX_WORKSPACE_ID names ${P.envWorkspace}. ${R}`;if(P.flagBaseUrl&&!hs(P.flagBaseUrl,j.config.apiUrl))return`${I} ${j.config.apiUrl}, but --base-url names ${P.flagBaseUrl}. ${R}`;if(P.envBaseUrl&&!hs(P.envBaseUrl,j.config.apiUrl))return`${I} ${j.config.apiUrl}, but HLIX_BASE_URL names ${P.envBaseUrl}. ${R}`;return null}import{resolve as ki}from"node:path";import{parseArgs as ji}from"node:util";import di from"openapi-fetch";function Rn(j){return di({baseUrl:j.baseUrl,headers:j.headers,fetch:j.fetch})}var We=(j)=>({kind:"apiKey",apiKey:j});var _n=(j)=>({kind:"bearer",token:j});function ui(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 pi(j){return j?{"X-Organization-Id":j}:{}}function ws(j,P){return{...ui(j),...pi(P)}}function mi(j){if(typeof j!=="object"||j===null)return null;let{error:P}=j;return typeof P==="string"?P:null}class ue 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 qe extends ue{issues;constructor(j,P,I){super(j,P);this.issues=I}}class gt extends ue{}class ht extends ue{}class yt extends ue{}class $e extends ue{}class wt extends ue{}class vt extends ue{retryAfter;constructor(j,P,I){super(j,P);this.retryAfter=I}}class bt extends ue{}class St extends ue{}class Ve extends Error{method;url;constructor(j,P){super(j,{cause:P.cause});this.name="HlixTransportError",this.method=P.method,this.url=P.url}}function fi(j){if(typeof j!=="object"||j===null)return null;let P=j;if(P.success!==!1)return null;let I=P.error?.message;if(typeof I!=="string")return null;try{let R=JSON.parse(I);return Array.isArray(R)?R:[]}catch{return[]}}function gi(j){let P=j.get("retry-after");if(!P)return null;let I=Number(P);return Number.isFinite(I)&&I>=0?I:null}function Xe(j,P,I){let R={status:j.status,body:P,requestId:j.headers.get("x-request-id"),method:I.method,url:I.url},O=mi(P),_=`${I.method} ${I.url} failed with ${j.status}`,T=fi(P);if(T)return new qe(`${I.method} ${I.url}: request body failed validation`,R,T);let A=O??_;switch(j.status){case 400:return new gt(A,R);case 401:return new ht(A,R);case 403:return new yt(A,R);case 404:return new $e(A,R);case 409:return new wt(A,R);case 429:return new vt(A,R,gi(j.headers));case 501:return new bt(A,R);default:return j.status>=500?new St(A,R):new ue(A,R)}}var vs=new Set(["GET","HEAD","PUT","DELETE","OPTIONS","TRACE"]);function Zt(j){return vs.has(j.toUpperCase())}var hi=new Set([429,500,502,503,504]);function yi(j){return hi.has(j)}var On={attempts:3,baseDelayMs:200,maxDelayMs:5000};function Tn(j,P,I,R=Math.random){if(I!==null)return Math.min(I*1000,P.maxDelayMs);let O=Math.min(P.baseDelayMs*2**j,P.maxDelayMs);return Math.round(R()*O)}function An(j){if(!Zt(j.method))return!1;if(j.attempt+1>=j.policy.attempts)return!1;return j.status===null||yi(j.status)}var wi=(j)=>new Promise((P)=>setTimeout(P,j));function vi(j){let P=j.headers.get("retry-after");if(!P)return null;let I=Number(P);return Number.isFinite(I)&&I>=0?I:null}function bs(j){let{base:P,policy:I}=j,R=j.sleep??wi,O=j.random??Math.random;return async(_)=>{let T=_.method.toUpperCase(),A=Zt(T)?_.clone():null;for(let N=0;;N+=1){let F=N===0?_:A.clone(),H;try{H=await P(F)}catch(L){if(!A||!An({method:T,attempt:N,policy:I,status:null}))throw new Ve(`${T} ${_.url}: ${L instanceof Error?L.message:String(L)}`,{method:T,url:_.url,cause:L});await R(Tn(N,I,null,O));continue}if(!An({method:T,attempt:N,policy:I,status:H.status}))return H;if(!A)return H;await R(Tn(N,I,vi(H),O))}}}function X(j,P){if(j.response.ok)return j.data;throw Xe(j.response,j.error??j.data,P)}var kt=(j)=>typeof j==="string"?j:"";function Nn(j){let P;try{P=JSON.parse(j)}catch{return null}if(typeof P!=="object"||P===null)return null;let I=P;switch(I.type){case"idle":return{type:"idle"};case"done":return{type:"done"};case"active":return typeof I.runId==="string"?{type:"active",runId:I.runId}:{type:"active"};case"on_chat_model_stream":return{type:"on_chat_model_stream",delta:kt(I.delta)};case"reasoning":return{type:"reasoning",delta:kt(I.delta)};case"on_tool_start":return{type:"on_tool_start",name:kt(I.name),input:I.input};case"on_tool_end":return{type:"on_tool_end",name:kt(I.name),output:I.output};case"error":return{type:"error",message:kt(I.message)};default:return null}}var Fn=(j)=>j.type==="done"||j.type==="idle"||j.type==="error";var bi=()=>({event:null,data:[],id:null,retry:null});function Ss(j,P,I){switch(P){case"event":j.event=I;return;case"data":j.data.push(I);return;case"id":if(!I.includes("\x00"))j.id=I;return;case"retry":{if(/^\d+$/.test(I))j.retry=Number(I);return}default:return}}function js(j){let P=j.data.join(`
10
- `),{event:I,id:R}=j;if(j.data=[],j.event=null,P==="")return null;return{event:I,data:P,id:R,retry:j.retry}}function ks(j,P){if(P==="")return js(j);if(P.startsWith(":"))return null;let I=P.indexOf(":");if(I===-1)return Ss(j,P,""),null;let R=P.slice(0,I),O=P.slice(I+1);if(O.startsWith(" "))O=O.slice(1);return Ss(j,R,O),null}function Si(j){let P=[],I=0;for(let R=0;R<j.length;R+=1){let O=j[R];if(O!==`
11
- `&&O!=="\r")continue;if(P.push(j.slice(I,R)),O==="\r"&&j[R+1]===`
12
- `)R+=1;I=R+1}return{lines:P,rest:j.slice(I)}}async function*Hn(j,P){let I=j.getReader(),R=new TextDecoder,O=bi(),_="",T=()=>void I.cancel().catch(()=>{});P?.addEventListener("abort",T,{once:!0});try{for(;;){let{done:N,value:F}=await I.read();if(N)break;_+=R.decode(F,{stream:!0});let{lines:H,rest:L}=Si(_);_=L;for(let D of H){let K=ks(O,D);if(K)yield K}if(P?.aborted)return}if(_+=R.decode(),_!==""){let N=ks(O,_);if(N)yield N}let A=js(O);if(A)yield A}finally{P?.removeEventListener("abort",T),I.releaseLock()}}function Ln(j){let P;try{P=JSON.parse(j)}catch{return null}if(typeof P!=="object"||P===null)return null;let I=P;if(I.kind==="ready")return{kind:"ready"};if(I.kind==="workspace")return{kind:"workspace"};if(I.kind==="head"&&typeof I.revisionId==="string"&&typeof I.generation==="number")return{kind:"head",revisionId:I.revisionId,generation:I.generation};return null}function Es(j){return j instanceof ue&&j.status>=400&&j.status<500&&j.status!==408&&j.status!==429}var Qt={firstDelayMs:1000,maxDelayMs:30000};function jt(j,P){return new Promise((I)=>{if(P?.aborted)return I();let R=setTimeout(O,j);function O(){clearTimeout(R),P?.removeEventListener("abort",O),I()}P?.addEventListener("abort",O,{once:!0})})}class Ye{raw;baseUrl;headers;fetcher;constructor(j){this.baseUrl=j.baseUrl.replace(/\/+$/,""),this.headers=ws(j.credential,j.organizationId);let P={...On,...j.retry},I=j.fetch??((R)=>globalThis.fetch(R));this.fetcher=bs({base:I,policy:P}),this.raw=Rn({baseUrl:this.baseUrl,headers:this.headers,fetch:this.fetcher})}at(j,P){return{method:j,url:`${this.baseUrl}${P}`}}workspaces={list:async()=>X(await this.raw.GET("/v1/api/workspaces"),this.at("GET","/v1/api/workspaces"))};projects={list:async()=>X(await this.raw.GET("/v1/api/projects"),this.at("GET","/v1/api/projects")),get:async(j)=>X(await this.raw.GET("/v1/api/projects/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}`)),create:async(j)=>X(await this.raw.POST("/v1/api/projects",{body:j}),this.at("POST","/v1/api/projects")),delete:async(j)=>X(await this.raw.DELETE("/v1/api/projects/{id}",{params:{path:{id:j}}}),this.at("DELETE",`/v1/api/projects/${j}`)),start:async(j,P)=>X(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)=>X(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 I=await this.raw.POST("/v1/api/projects/{id}/repos/connect",{params:{path:{id:j}},body:P});return X(I,this.at("POST",`/v1/api/projects/${j}/repos/connect`))},terminal:async(j)=>X(await this.raw.GET("/v1/api/projects/{id}/terminal",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/terminal`)),observeAgent:(j,P,I)=>this.observeAgent(j,P,I),workspace:(j)=>({environment:async()=>X(await this.raw.GET("/v1/api/projects/{id}/environment",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/environment`)),fs:async(P)=>X(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)=>X(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)=>X(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)=>X(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)=>X(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,I)=>X(await this.raw.DELETE("/v1/api/secrets/project/{projectId}/entries/{key}",{params:{path:{projectId:j,key:P},...I===void 0?{}:{query:{source:I}}}}),this.at("DELETE",`/v1/api/secrets/project/${j}/entries/${encodeURIComponent(P)}`)),exportEntries:async(j,P={})=>{let I=`/v1/api/secrets/project/${j}/export`,R=`${this.baseUrl}${I}`,O=await this.fetcher(new Request(R,{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(!O.ok)throw Xe(O,await O.json().catch(()=>{return}),{method:"POST",url:R});return O.text()}};imports={create:async(j)=>{let P=await this.raw.POST("/v1/api/imports",{body:j});return X(P,this.at("POST","/v1/api/imports"))},get:async(j)=>X(await this.raw.GET("/v1/api/imports/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/imports/${j}`)),finalize:async(j,P)=>{let I=await this.raw.POST("/v1/api/imports/{id}/finalize",{params:{path:{id:j}},body:P});return X(I,this.at("POST",`/v1/api/imports/${j}/finalize`))},uploadBundle:async(j,P,I={})=>{let R=I.chunkSize??8388608;if(R<=0||R%262144!==0)throw Error("Import upload chunkSize must be a positive multiple of 256 KiB");let O=j.url.startsWith("/")?`${this.baseUrl}${j.url}`:j.url;if(j.kind==="hlix-stream"){let T=new Request(O,{method:"PUT",headers:{...this.headers,"content-type":"application/x-git-bundle","content-length":String(P.size)},body:P,signal:I.signal}),A=await this.fetcher(T);if(!A.ok)await this.throwUploadError(A,O);I.onProgress?.(P.size,P.size);return}let _=0;while(_<P.size){let T=Math.min(_+R,P.size),A=new Request(O,{method:"PUT",headers:{"content-type":"application/x-git-bundle","content-length":String(T-_),"content-range":`bytes ${_}-${T-1}/${P.size}`},body:P.slice(_,T),signal:I.signal}),N=await this.fetcher(A);if(N.status!==308&&!N.ok)await this.throwUploadError(N,O);let F=N.headers.get("range")?.match(/bytes=0-(\d+)/)?.[1];if(_=F?Number(F)+1:T,!Number.isSafeInteger(_)||_<T||_>P.size)throw Error("Import upload server returned an invalid acknowledged range");I.onProgress?.(_,P.size)}}};revisions={head:async(j)=>X(await this.raw.GET("/v1/api/projects/{id}/revisions/head",{params:{path:{id:j}}}),this.at("GET",`/v1/api/projects/${j}/revisions/head`)),protectedFiles:async(j)=>X(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 I=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads",{params:{path:{id:j}},body:P});return X(I,this.at("POST",`/v1/api/projects/${j}/revisions/uploads`))},finalize:async(j,P,I)=>{let R=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads/{uploadId}/finalize",{params:{path:{id:j,uploadId:P}},body:I});return X(R,this.at("POST",`/v1/api/projects/${j}/revisions/uploads/${P}/finalize`))},uploadBundle:async(j,P,I={})=>this.imports.uploadBundle(j,P,I),watch:(j,P)=>this.watchRevisions(j,P),downloadBundle:async(j,P)=>{let I=`/v1/api/projects/${j}/revisions/${P}/bundle`,R=new Request(`${this.baseUrl}${I}`,{method:"GET",headers:this.headers}),O=await this.fetcher(R);if(!O.ok)await this.throwUploadError(O,`${this.baseUrl}${I}`);return O.blob()}};resources={importSkill:async(j,P)=>X(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)=>X(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)=>X(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 I=null;try{I=await j.json()}catch{I=await j.text().catch(()=>null)}throw Xe(j,I,{method:"PUT",url:P})}tasks={list:async(j)=>X(await this.raw.GET("/v1/api/tasks",{params:{query:j??{}}}),this.at("GET","/v1/api/tasks")),get:async(j)=>X(await this.raw.GET("/v1/api/tasks/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/tasks/${j}`)),create:async(j)=>X(await this.raw.POST("/v1/api/tasks",{body:j}),this.at("POST","/v1/api/tasks")),update:async(j,P)=>X(await this.raw.PATCH("/v1/api/tasks/{id}",{params:{path:{id:j}},body:P}),this.at("PATCH",`/v1/api/tasks/${j}`)),listComments:async(j)=>X(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)=>X(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)=>X(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)=>X(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)=>X(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)=>X(await this.raw.PUT("/v1/api/model-config/harness",{body:{harness:j}}),this.at("PUT","/v1/api/model-config/harness")),clearHarness:async()=>X(await this.raw.DELETE("/v1/api/model-config/harness"),this.at("DELETE","/v1/api/model-config/harness")),resolvedHarness:async()=>X(await this.raw.GET("/v1/api/model-config/harness/resolved"),this.at("GET","/v1/api/model-config/harness/resolved")),resolvedProjectHarness:async(j)=>X(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)=>X(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)=>X(await this.raw.GET("/v1/api/cycles",{params:{query:j??{}}}),this.at("GET","/v1/api/cycles")),get:async(j)=>X(await this.raw.GET("/v1/api/cycles/{id}",{params:{path:{id:j}}}),this.at("GET",`/v1/api/cycles/${j}`)),propose:async(j)=>X(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)=>X(await this.raw.GET("/v1/api/client-billing/invoices",{params:{query:j??{}}}),this.at("GET","/v1/api/client-billing/invoices")),get:async(j)=>X(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)=>X(await this.raw.POST("/v1/api/client-billing/invoices",{body:j}),this.at("POST","/v1/api/client-billing/invoices")),issue:async(j)=>X(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)=>X(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)=>X(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={})=>X(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,I){let R=`/v1/api/projects/${j}/agents/${P}/observe`;for await(let O of this.stream(R,I)){let _=Nn(O.data);if(!_)continue;if(yield _,Fn(_))return}}async*watchRevisions(j,P){let I=`/v1/api/projects/${j}/revisions/watch`,R=P?.signal,O=Qt.firstDelayMs;while(!R?.aborted){try{for await(let _ of this.stream(I,P)){let T=Ln(_.data);if(!T)continue;if(T.kind==="ready")O=Qt.firstDelayMs;yield T}}catch(_){if(R?.aborted)return;if(Es(_))throw _}await jt(O,R),O=Math.min(O*2,Qt.maxDelayMs)}}async*stream(j,P){let I=`${this.baseUrl}${j}`,R=new Request(I,{headers:{...this.headers,accept:"text/event-stream"},signal:P?.signal}),O=await globalThis.fetch(R);if(!O.ok||!O.body){let _=null;try{_=await O.json()}catch{_=null}throw Xe(O,_,{method:"GET",url:I})}yield*Hn(O.body,P?.signal)}}function Mn(j){if(j instanceof e)return{code:j.code,status:null};if(j instanceof qe)return{code:"invalid_request",status:400};if(j instanceof gt)return{code:"bad_request",status:400};if(j instanceof ht)return{code:"unauthenticated",status:401};if(j instanceof yt)return{code:"forbidden",status:403};if(j instanceof $e)return{code:"not_found",status:404};if(j instanceof wt)return{code:"conflict",status:409};if(j instanceof vt)return{code:"rate_limited",status:429};if(j instanceof bt)return{code:"not_implemented",status:501};if(j instanceof St)return{code:"server_error",status:j.status};if(j instanceof Ve)return{code:"unreachable",status:null};return{code:"unknown",status:null}}var en=(j)=>{if(j instanceof qe&&j.issues.length>0){let P=j.issues.slice(0,5).map((R)=>{let O=R;return` - ${Array.isArray(O.path)&&O.path.length>0?`${O.path.join(".")}: `:""}${typeof O.message==="string"?O.message:JSON.stringify(R)}`}),I=j.issues.length-P.length;return`${j.message}
13
- ${P.join(`
14
- `)}${I>0?`
15
- … ${I} more`:""}`}return j instanceof Error?j.message:String(j)};function n(j,P){let I=r({env:j,flags:P.flags,cwd:P.cwd});if(I.conflict)throw new e("workspace_mismatch",I.conflict);if(!I.credential)throw new e("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");return new Ye({baseUrl:I.baseUrl,credential:I.credential.sessionToken?_n(I.credential.sessionToken):We(I.credential.apiKey),...I.workspaceId?{organizationId:I.workspaceId}:{}})}function $s(j){let P=Math.max(...j.map((R)=>R.name.length));return`hlix — the hlix control-plane CLI
16
-
17
- Usage:
18
- hlix <command> [options]
19
-
20
- Commands:
21
- ${[` hlix ${"".padEnd(P)} Open Hlix Code (interactive)`,...j.map((R)=>` hlix ${R.name.padEnd(P)} ${R.summary}`)].join(`
22
- `)}
23
-
24
- Options:
25
- --json Machine-readable output (a versioned, stable contract)
26
- --cwd <dir> Operate on another directory instead of the current one
27
- --workspace <id> Workspace to act in, overriding the folder's binding
28
- --base-url <url> API to talk to, overriding the folder's binding
29
- --help Show this help
30
- --version Show the installed CLI version
31
-
32
- Hlix Code (hlix with no command):
33
- --sandbox <choice> cloud, docker or local; --local is short for local
34
- --docker-image <r> image the docker sandbox runs in
35
- --harness <name> which coder does the work
36
- --project <id> project to act in, when this folder is not bound
37
- -p "<prompt>" one turn, print the answer, exit
38
- --json with -p: one JSON object per event instead of prose
39
- --allow-writes with -p: let the turn change files and run commands
40
- --yolo approve every tool call for the whole session
41
-
42
- A command targets the workspace named by, in order: an explicit flag, the
43
- HLIX_* environment, the nearest .hlix/config.json, then the stored credential.
44
- Run \`hlix status\` to see which one applied.
45
- `}function Cs(j,P){let I=[...Array(P.length+1).keys()];for(let R=1;R<=j.length;R+=1){let O=[R];for(let _=1;_<=P.length;_+=1)O[_]=Math.min(I[_]+1,O[_-1]+1,I[_-1]+(j[R-1]===P[_-1]?0:1));I=O}return I[P.length]}function Ei(j,P,I){let R=/Unknown option '--([^'=]+)/.exec(I)?.[1];if(!R)return I;let O=P.findIndex((N)=>N.startsWith("-")),_=O===-1?P:P.slice(0,O),T=new Set(["json","help","version","cwd","workspace","base-url",...tn(j,_)?.command.options??[]]),A=null;for(let N of T){let F=Cs(R,N);if(F<=2&&(!A||F<A.distance))A={name:N,distance:F}}return A?`${I}
46
- Did you mean --${A.name}?`:I}function Ps(j,P){let I=new Set;for(let _ of j)I.add(_.name),I.add(_.name.split(" ")[0]);let R=null;for(let _ of I){let T=Cs(P,_);if(T<=2&&(!R||T<R.distance))R={name:_,distance:T}}if(!R)return null;if(j.some((_)=>_.name===R.name))return R.name;let O=j.filter((_)=>_.name.startsWith(`${R.name} `)).sort((_,T)=>_.name.length-T.name.length)[0];return O?O.name:R.name}function tn(j,P){for(let I of[...j].sort((R,O)=>O.name.length-R.name.length)){let R=I.name.split(" ");if(R.every((O,_)=>P[_]===O))return{command:I,rest:P.slice(R.length)}}return null}function $i(j,P,I){let R=Ei(j,P,I);if(!/^Unknown option '/.test(I))return R;let O=R.replace(/\. To specify a positional argument[\s\S]*?after '--'[^\n]*/,"."),_=tn(j,P.filter((T)=>!T.startsWith("-")));return _?`${O}
47
-
48
- ${_.command.usage}`:O}async function s(j,P,I){if(P.some((J)=>J==="--api-key"||J.startsWith("--api-key=")))return I.stderr("error: API keys are never accepted as command-line arguments. Run `hlix auth login` and use the hidden prompt.\n"),2;let R;try{R=ji({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"},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(J){let ne=P.includes("--json"),ae=$i(j,P,en(J));if(I.onFailure?.({code:"invalid_usage",message:ae,status:null}),ne)I.stdout(q(dt("cli",{code:"invalid_usage",message:ae,status:null})));else I.stderr(`${ae}
49
- `);return 2}let O=R.values.json===!0,_=R.positionals;if(R.values.version===!0){let{version:J}=await import("./package-cxk3dvbh.js");return I.stdout(`${J}
50
- `),0}if(_.length===0||R.values.help===!0){let J=tn(j,_);return I.stdout(J?`${J.command.usage}
51
- `:$s(j)),_.length===0&&R.values.help!==!0?1:0}let T=tn(j,_);if(!T){let J=_.join(" "),ne=Ps(j,J)??Ps(j,_[0]),ae=ne?`Unknown command: ${J}
52
- Did you mean \`hlix ${ne}\`?`:`Unknown command: ${J}`;if(I.onFailure?.({code:"unknown_command",message:ae,status:null}),O)I.stdout(q(dt(J,{code:"unknown_command",message:ae,status:null})));else I.stderr(`${ae}
53
-
54
- ${$s(j)}`);return 2}let A=new Set(["json","help","version","cwd","workspace","base-url"]),N=new Set(T.command.options??[]),F=Object.entries(R.values).filter(([J,ne])=>ne!==void 0&&!A.has(J)&&!N.has(J)).map(([J])=>`--${J}`),H=T.command.args??{min:0,max:0},L=T.rest.length<H.min?{code:"missing_argument",message:T.command.usage.split(`
55
- `)[0]}:T.rest.length>H.max?{code:"invalid_usage",message:T.command.usage.split(`
56
- `)[0]}:null,D=typeof R.values.cwd==="string"?R.values.cwd:void 0,K=ki(D??"."),z=D!==void 0&&!ys(K)?{code:"invalid_usage",message:`--cwd is not a directory: ${K}`}:null,M=F.length>0?{code:"invalid_usage",message:`Unsupported option for ${T.command.name}: ${F.join(", ")}`}:z??L;if(M){if(I.onFailure?.({...M,status:null}),O)I.stdout(q(dt(T.command.name,{...M,status:null})));else{let J=T.command.usage.startsWith(M.message)?T.command.usage:`${M.message}
57
-
58
- ${T.command.usage}`;I.stderr(`error: ${J}
59
- `)}return 2}let U=R.values,B={...I,args:T.rest,json:O,flags:U,cwd:K,requireClient:(J)=>n(I.env,{cwd:J??K,flags:U})};try{return await T.command.run(B)}catch(J){let{code:ne,status:ae}=Mn(J);if(I.onFailure?.({code:ne,message:en(J),status:ae,...J instanceof e&&J.details!==void 0?{details:J.details}:{}}),O)I.stdout(q(dt(T.command.name,{code:ne,message:en(J),status:ae})));else if(I.stderr(`error: ${en(J)}
60
- `),process.env.HLIX_DEBUG&&J instanceof Error&&J.stack)I.stderr(`${J.stack}
61
- `);return ne==="unauthenticated"||ne==="forbidden"?3:1}}import{readFileSync as Pi}from"node:fs";import{homedir as Ci}from"node:os";import{join as Ii}from"node:path";var Is=20000;function l(j){if(j===void 0)return;let P=typeof j==="number"?j:Number(j.trim());return Number.isInteger(P)&&P>=Is?P:void 0}var i=["cloud","docker","local"],o=["claude-code","codex","cursor-agent","hlix"],y="hlix",xs={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"},Ze=["dockerImage","harness","memoryTokens","model","sandbox","yolo"],Un=["projectId","workspaceId","apiUrl"];function Dn(j=process.env){return Ii(j.HLIX_CONFIG_HOME??Ci(),".hlix","config.json")}function Rs(j=process.env){try{let P=JSON.parse(Pi(Dn(j),"utf8"));return P.schemaVersion===1?P:null}catch{return null}}function d(j,P=process.env){let I=Rs(P),R=t(j),O=R?.root??null,_=R?.config??null,T={},A={},N=(F)=>{let H=_?.[F],L=I?.[F];if(H!==void 0)T[F]=H,A[F]="project";else if(L!==void 0)T[F]=L,A[F]="global"};for(let F of Ze)N(F);for(let F of Un){let H=_?.[F];if(H!==void 0)T[F]=H,A[F]="project"}return{merged:T,sources:A,global:I,project:_,paths:{global:Dn(P),project:O?ft(O):null}}}function _s(j){return[...Ze,...Un].map((I)=>({key:I,value:j.merged[I]??null,source:j.sources[I]??"default"}))}function xi(j,P){if(j==="sandbox"&&!i.includes(P))return`sandbox must be one of ${i.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"&&l(P)===void 0)return`memoryTokens must be a whole number of tokens, at least ${Is}; got "${P}".`;if(j==="dockerImage"&&P.trim()==="")return"dockerImage must not be empty.";if(j==="yolo"&&w(P)===void 0)return`yolo must be true or false; got "${P}".`;return null}function w(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 zn(j){if(Ze.includes(j))return j;let P=Un.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: ${Ze.join(", ")}.`)}function Os(j,P){let I=xi(j,P);if(I)throw new e("invalid_usage",I);return P}function u(j){if(j.scope==="global"){let R=Dn(j.env),O=Rs(j.env)??{schemaVersion:1};return mt(R,{...O,[j.key]:j.value}),R}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 I=ft(P.root);return mt(I,{...P.config,[j.key]:j.value}),I}import{createHash as Ri}from"node:crypto";import{mkdirSync as _i,readdirSync as Ls,readFileSync as Oi,rmSync as Ti,statSync as Ms,writeFileSync as Ai}from"node:fs";import{homedir as Ni,tmpdir as Fi}from"node:os";import{basename as Us,isAbsolute as Hi,join as ee,relative as Li}from"node:path";var c=(j=process.env)=>j.HOME??j.USERPROFILE??Ni();function me(j){try{if(!Ms(j).isFile())return null;return Oi(j,"utf8")}catch{return null}}function Mi(j){try{return Ms(j).isDirectory()}catch{return!1}}function Qe(j,P){try{return Ls(j,{withFileTypes:!0}).filter((I)=>I.isFile()&&I.name.endsWith(P)).map((I)=>ee(j,I.name)).sort()}catch{return[]}}function Ui(j){try{return Ls(j,{withFileTypes:!0}).filter((P)=>P.isDirectory()||P.isSymbolicLink()).map((P)=>ee(j,P.name)).sort()}catch{return[]}}function Kn(j){let P=j.replace(/^\uFEFF/,""),I=P.indexOf(`
62
- `);if(!P.startsWith("---")||I===-1)return{fields:{},body:P.trim()};let R=P.indexOf(`
63
- ---`,I);if(R===-1)return{fields:{},body:P.trim()};let O={};for(let T of P.slice(I+1,R).split(`
64
- `)){let A=/^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(T);if(!A)continue;O[A[1]]=A[2].trim().replace(/^["']|["']$/g,"")}let _=P.indexOf(`
65
- `,R+1);return{fields:O,body:_===-1?"":P.slice(_+1).trim()}}function Di(j){let P=j.trimStart(),I=/^"((?:[^"\\]|\\.)*)"/.exec(P)??/^'([^']*)'/.exec(P);if(I)return I[1].replace(/\\"/g,'"').replace(/\\n/g,`
66
- `);if(P.startsWith("["))return[...P.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'/g)].map((O)=>O[1]??O[2]??"");if(P.startsWith("{")){let O={};for(let _ of P.matchAll(/([A-Za-z0-9_.-]+)\s*=\s*"((?:[^"\\]|\\.)*)"/g))O[_[1]]=_[2].replace(/\\"/g,'"');return O}let R=/^[^\s#]+/.exec(P)?.[0];if(R===void 0)return;if(R==="true"||R==="false")return R==="true";if(/^-?\d+(\.\d+)?$/.test(R))return Number(R);return R}function Ds(j){let P={"":{}},I="",R=j.split(`
67
- `);for(let O=0;O<R.length;O+=1){let T=R[O].trim();if(!T||T.startsWith("#"))continue;let A=/^\[\[?([^\]]+)\]\]?$/.exec(T);if(A){I=A[1].trim(),P[I]??={};continue}let N=/^([A-Za-z0-9_.-]+|"[^"]+")\s*=\s*(.*)$/.exec(T);if(!N)continue;let F=N[1].replace(/^"|"$/g,""),H=N[2];if(H.startsWith('"""')){let D=[],K=H.slice(3);if(K.includes('"""'))D.push(K.slice(0,K.indexOf('"""')));else{if(K)D.push(K);while(O+1<R.length){O+=1;let z=R[O],M=z.indexOf('"""');if(M===-1){D.push(z);continue}D.push(z.slice(0,M));break}}P[I][F]=D.join(`
68
- `).replace(/^\n/,"");continue}let L=Di(H);if(L!==void 0)P[I][F]=L}return P}function Bn(j,P){return j.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g,(I,R,O)=>{let _=P[R];return _!==void 0&&_!==""?_:O??""})}var Ts=(j,P)=>{let I={};for(let[R,O]of Object.entries(j))if(typeof O==="string")I[R]=Bn(O,P);return I},zi=[{relative:"GEMINI.md",source:"gemini"},{relative:ee(".gemini","GEMINI.md"),source:"gemini"},{relative:".cursorrules",source:"cursor"},{relative:".windsurfrules",source:"windsurf"},{relative:ee(".github","copilot-instructions.md"),source:"copilot"}],Bi=[{relative:ee(".gemini","GEMINI.md"),source:"gemini"}],Ki=[{relative:ee(".cursor","rules"),source:"cursor",extension:".mdc"},{relative:ee(".windsurf","rules"),source:"windsurf",extension:".md"}];function Ji(j,P){let I=ee(j,".clinerules"),R=Mi(I)?Qe(I,".md"):[I],O=[];for(let _ of R){let T=me(_)?.trim();if(T)O.push({path:_,source:"cline",scope:P,content:T})}return O}function Gi(j,P,I){let{fields:R,body:O}=Kn(P);if(R.alwaysApply==="false")return{path:j,source:"cursor",scope:I,reason:"alwaysApply: false"};if(!O)return{path:j,source:"cursor",scope:I,reason:"no rule body"};let _=R.globs?.replace(/^\[|\]$/g,"").trim();return{path:j,source:"cursor",scope:I,content:O,..._?{note:`Applies to: ${_}`}:{}}}var Wi=["AGENTS.md","CLAUDE.md"],zs=["",".claude"],b=["commands"];function qi(j,P){let I=[],R=new Set;for(let O of[...zs,P])for(let _ of Wi){let T=ee(j,O,_),A=me(T)?.trim();if(!A||R.has(A))continue;R.add(A),I.push({path:T,content:A})}return I}function As(j,P){return qi(j,P).map((I)=>I.content)}var p=["AGENTS.md","CLAUDE.md","GEMINI.md"];function Jn(j,P){for(let I of p)for(let R of[...zs,P]){let O=ee(j,R,I),_=me(O)?.trim();if(_)return{path:O,content:_}}return null}var Gn=(j=process.env)=>ee(j.HLIX_CONFIG_HOME??ee(c(j),".hlix"),"AGENTS.md");function m(j){let P=j.env??process.env,I=Gn(P),R=me(I)?.trim();return{global:R?{path:I,content:R}:null,project:Jn(j.cwd,j.configDir)}}var Ns=(j)=>{let P=Math.round(j.length/4);return P>=1000?`${(P/1000).toFixed(1)}k tokens`:`${P} tokens`};function S(j,P,I=process.env){let R=[...j.global?[Ks(j.global.path,I)]:[],...j.project?[$t(j.project.path,P)]:[]];return R.length===0?"":`rules: ${R.join(" + ")}`}function g(j,P,I=process.env,R=[]){let O=(_,T,A)=>T?`${_.padEnd(8)} ${A(T.path)} (${Ns(T.content)})`:`${_.padEnd(8)} none`;return[O("user",j.global,(_)=>Ks(_,I)),O("project",j.project,(_)=>$t(_,P)),...R.map((_)=>`${"nested".padEnd(8)} ${$t(_.path,P)} (${Ns(_.content)})`),"","User rules go first, the project's after, so the project wins a conflict.",R.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(`
69
- `)}var Fs=[{dir:".claude",source:"claude",harnessReads:!0},{dir:".agents",source:"agents",harnessReads:!0},{dir:".hlix",source:"hlix",harnessReads:!0},{dir:".codex",source:"codex",harnessReads:!1}],Vi=[{relative:ee(".cursor","commands"),source:"cursor"},{relative:ee(".codex","prompts"),source:"codex"}],Xi=[{relative:ee(".cursor","mcp.json"),source:"cursor",key:"mcpServers",format:"json"},{relative:ee(".windsurf","mcp.json"),source:"windsurf",key:"mcpServers",format:"json"},{relative:ee(".gemini","settings.json"),source:"gemini",key:"mcpServers",format:"json"},{relative:ee(".vscode","mcp.json"),source:"vscode",key:"servers",format:"json"},{relative:ee(".codex","config.toml"),source:"codex",key:"mcp_servers",format:"toml"},{relative:".mcp.json",source:"claude",key:"mcpServers",format:"json"}];function Bs(j){return[...Xi,{relative:ee(j,"mcp.json"),source:"hlix",key:"mcpServers",format:"json"}]}var Yi="found, not loaded (machine-wide; enable per project by copying into .hlix/mcp.json)",Zi=(j)=>Bs(j).filter((P)=>P.source!=="vscode");function Qi(j,P){if(!j||typeof j!=="object"||Array.isArray(j))return{reason:"not an object"};let I=j;if(I.enabled===!1||I.disabled===!0)return{reason:"disabled"};let R=typeof I.command==="string"&&I.command!=="",O=typeof I.url==="string"&&I.url!=="";if(R&&O)return{reason:'has both "command" and "url"'};if(R){let N=Array.isArray(I.args)?I.args.filter((H)=>typeof H==="string"):void 0,F=I.env&&typeof I.env==="object"&&!Array.isArray(I.env)?Ts(I.env,P):void 0;return{config:{command:I.command,...N&&N.length>0?{args:N}:{},...F&&Object.keys(F).length>0?{env:F}:{}}}}if(!O)return{reason:'missing "command" or "url"'};let _=I.headers??I.http_headers,T=_&&typeof _==="object"&&!Array.isArray(_)?Ts(_,P):{},A=I.bearer_token_env_var;if(typeof A==="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(A)&&!Object.keys(T).some((N)=>N.toLowerCase()==="authorization"))T.Authorization=`Bearer ${Bn(`\${${A}}`,P)}`;return{config:{url:Bn(I.url,P),...Object.keys(T).length>0?{headers:T}:{}}}}function Hs(j,P,I,R){let O=me(j),_=[],T=[];if(O===null)return{servers:_,skipped:T};let A=[];if(P.format==="toml"){let N=Ds(O);A=Object.entries(N).filter(([F])=>F.startsWith(`${P.key}.`)).map(([F,H])=>[F.slice(P.key.length+1),H])}else try{let F=JSON.parse(O)?.[P.key];if(F&&typeof F==="object"&&!Array.isArray(F))A=Object.entries(F)}catch{return T.push({path:j,source:P.source,scope:I,reason:"not valid JSON"}),{servers:_,skipped:T}}for(let[N,F]of A){let H=Qi(F,R);if("reason"in H){T.push({path:j,source:P.source,scope:I,reason:`${N}: ${H.reason}`});continue}_.push({path:j,source:P.source,scope:I,name:N,config:H.config})}return{servers:_,skipped:T}}function ea(j,P,I){let{fields:R,body:O}=Kn(P);if(!O)return{path:j,source:"claude",scope:I,reason:"no instructions"};let _=R.tools?.replace(/^\[|\]$/g,"").split(",").map((T)=>T.trim()).filter(Boolean);return{path:j,source:"claude",scope:I,name:R.name||Us(j,".md"),description:R.description??"",instructions:O,..._&&_.length>0&&_[0]!=="*"?{tools:_}:{},...R.model?{model:R.model}:{}}}function ta(j){let P=Ds(j)[""]??{},I=typeof P.prompt==="string"?P.prompt.trim():"";if(!I)return null;return{description:typeof P.description==="string"?P.description:"",body:I}}function f(j,P,I={}){let R=I.configDir??".hlix",O=I.env??process.env,_={instructions:[],skills:[],commands:[],generatedCommands:[],mcpServers:[],subagents:[],skipped:[]},T=(z)=>{if("reason"in z)_.skipped.push(z);else _.instructions.push(z)};for(let z of zi){let M=ee(j,z.relative),U=me(M)?.trim();if(U)_.instructions.push({path:M,source:z.source,scope:"project",content:U})}for(let z of Ki)for(let M of Qe(ee(j,z.relative),z.extension)){let U=me(M);if(U===null)continue;if(z.source==="cursor"){T(Gi(M,U,"project"));continue}let{body:B}=Kn(U);if(B)_.instructions.push({path:M,source:z.source,scope:"project",content:B})}for(let z of Ji(j,"project"))T(z);let A=As(j,R),N=ee(j,".codex","AGENTS.md"),F=me(N)?.trim();if(F&&A.includes(F))_.skipped.push({path:N,source:"codex",scope:"project",reason:"same content as the project's AGENTS.md"});else if(F)_.instructions.push({path:N,source:"codex",scope:"project",content:F});for(let z of Bi){let M=ee(P,z.relative),U=me(M)?.trim();if(U)_.instructions.push({path:M,source:z.source,scope:"global",content:U})}let H=ee(P,".codex","AGENTS.md"),L=me(H)?.trim(),D=As(P,R);if(L&&D.includes(L))_.skipped.push({path:H,source:"codex",scope:"global",reason:"same content as the machine's AGENTS.md"});else if(L)_.instructions.push({path:H,source:"codex",scope:"global",content:L});for(let[z,M]of[[j,"project"],[P,"global"]])for(let U of Fs){let B=ee(z,U.dir===".hlix"?R:U.dir,"skills");if(!Ui(B).some((ne)=>me(ee(ne,"SKILL.md"))!==null))continue;_.skills.push({path:B,source:U.source,scope:M,harnessReads:U.harnessReads})}for(let[z,M]of[[j,"project"],[P,"global"]]){for(let U of Fs){if(!U.harnessReads)continue;let B=ee(z,U.dir,"commands");if(Qe(B,".md").length===0)continue;_.commands.push({path:B,source:U.source,scope:M,harnessReads:!0})}for(let U of Vi){let B=ee(z,U.relative);if(Qe(B,".md").length===0)continue;_.commands.push({path:B,source:U.source,scope:M})}for(let U of Qe(ee(z,".gemini","commands"),".toml")){let B=me(U),J=B===null?null:ta(B);if(!J){_.skipped.push({path:U,source:"gemini",scope:M,reason:"no prompt field"});continue}_.generatedCommands.push({path:U,source:"gemini",scope:M,name:Us(U,".toml"),body:`---
70
- description: ${J.description}
71
- ---
72
-
73
- ${J.body}
74
- `})}}for(let z of Bs(R)){let M=Hs(ee(j,z.relative),z,"project",O);_.skipped.push(...M.skipped);for(let U of M.servers){let B=_.mcpServers.findIndex((J)=>J.name===U.name);if(B===-1)_.mcpServers.push(U);else _.mcpServers[B]=U}}for(let z of Zi(R)){let M=Hs(ee(P,z.relative),z,"global",O);for(let U of M.servers)_.skipped.push({path:U.path,source:U.source,scope:"global",reason:`${U.name}: ${Yi}`})}let K=[{dir:ee(".claude","agents"),source:"claude"},{dir:ee(R,"agents"),source:"hlix"}];for(let[z,M]of[[j,"project"],[P,"global"]])for(let U of K.flatMap((B)=>Qe(ee(z,B.dir),".md"))){let B=me(U);if(B===null)continue;let J=ea(U,B,M);if("reason"in J)_.skipped.push(J);else if(_.subagents.some((ne)=>ne.name===J.name))_.skipped.push({path:U,source:"claude",scope:M,reason:`a project agent already claims the name ${J.name}`});else _.subagents.push(J)}return _}function x(j,P){if(j.length===0)return null;let I=ee(Fi(),"hlix-standards-commands",Ri("sha256").update(P).digest("hex").slice(0,16));try{Ti(I,{recursive:!0,force:!0}),_i(I,{recursive:!0});for(let R of j)Ai(ee(I,`${R.name}.md`),R.body,"utf8");return I}catch{return null}}var na=60000,$t=(j,P)=>{let I=Li(P,j);return!I||I.startsWith("..")||Hi(I)?j:I},Ks=(j,P=process.env)=>{let I=P.HLIX_CONFIG_HOME;if(I&&j.startsWith(`${I}/`))return`~/.hlix/${j.slice(I.length+1)}`;let R=c(P);return R&&j.startsWith(`${R}/`)?`~/${j.slice(R.length+1)}`:j};function k(j,P,I=na){if(j.length===0)return"";let R=["# 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(`
75
- `),O=[],_=R.length,T=!1;for(let N of j){let F=`# From ${$t(N.path,P)} (${N.source})`,H=N.note?`${F}
76
- ${N.note}`:F,L=I-_-H.length-4;if(L<=0){T=!0;break}let D=N.content.length<=L?N.content:`${N.content.slice(0,L)}
77
- [truncated]`;if(D.length<N.content.length)T=!0;O.push(`${H}
78
-
79
- ${D}`),_+=H.length+D.length+4}let A=T?`
80
-
81
- [The standards block reached its ${I}-character cap; some rules above are cut short or omitted.]`:"";return`${R}
82
-
83
- ${O.join(`
84
-
85
- `)}${A}`}var Et=(j,P,I)=>`${j} ${j===1?P:I}`;function E(j){let P=[];if(j.instructions.length>0)P.push(Et(j.instructions.length,"instruction file","instruction files"));if(j.skills.length>0)P.push(Et(j.skills.length,"skill directory","skill directories"));let I=j.commands.length+j.generatedCommands.length;if(I>0)P.push(Et(I,"command source","command sources"));if(j.mcpServers.length>0)P.push(Et(j.mcpServers.length,"mcp server","mcp servers"));if(j.subagents.length>0)P.push(Et(j.subagents.length,"subagent","subagents"));if(P.length===0)return"";let R=[...new Set([...j.instructions,...j.skills,...j.commands,...j.generatedCommands,...j.mcpServers,...j.subagents].map((O)=>O.source))].sort();return`standards: ${P.join(" · ")} (${R.join(", ")})`}function Js(j,P){let I=[],R=(_,T)=>{if(T.length===0)return;I.push(_,...T.map((A)=>` ${A}`),"")},O=(_)=>`${_.source}${_.scope==="global"?" (global)":""} ${$t(_.path,P)}`;if(R("Instructions",j.instructions.map((_)=>`${O(_)}${_.note?` — ${_.note}`:""}`)),R("Skills",j.skills.map((_)=>`${O(_)}${_.harnessReads?" — already read by the harness":""}`)),R("Commands",[...j.commands.map((_)=>`${O(_)}${_.harnessReads?" — already read by the harness":""}`),...j.generatedCommands.map((_)=>`${O(_)} → /${_.name}`)]),R("MCP servers",j.mcpServers.map((_)=>`${O(_)} → ${_.name} (${"command"in _.config?"stdio":"http"})`)),R("Subagents",j.subagents.map((_)=>`${O(_)} → ${_.name}`)),R("Skipped",j.skipped.map((_)=>`${O(_)} — ${_.reason}`)),I.length===0)return`No standards from other agent tools were found in this folder.
86
- `;return`${I.join(`
87
- `).trimEnd()}
88
- `}async function ra(j,P,I){let R=P.map((A)=>A.id);if(I){if(!R.includes(I))throw new e("workspace_mismatch",P.length===0?`This key belongs to a user who is not a member of any workspace, including ${I}.`:`This key cannot act in workspace ${I}. Available: ${R.join(", ")}.`);return I}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 O=P[0];if(O&&P.length===1)return j.stderr(`Using your only workspace: ${O.name} (${O.id})
89
- `),O.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: ${R.join(", ")}.`);let _=Math.max(...P.map((A)=>A.name.length));j.stderr(`${P.map((A,N)=>` ${N+1}) ${A.name.padEnd(_)} ${A.slug} ${A.role} ${A.id}`).join(`
90
- `)}
91
- `);let T=await j.promptChoice(`Workspace [1-${P.length}]: `,P.length);return R[T]}var Wn={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(`
92
- `),supportsJson:!0,options:["base-url","workspace"],async run(j){let P=typeof j.flags.workspace==="string"?j.flags.workspace:j.env.HLIX_WORKSPACE_ID,I=j.env.HLIX_API_KEY??await j.readSecret?.("Hlix API key: ")??"";if(!I)throw new e("missing_credential","No API key entered. Run from a terminal or set HLIX_API_KEY for CI.");let R=typeof j.flags["base-url"]==="string"?j.flags["base-url"]:j.env.HLIX_BASE_URL??xn,O=new URL(R),_=O.hostname==="localhost"||O.hostname==="127.0.0.1"||O.hostname==="::1";if(O.protocol!=="https:"&&!(O.protocol==="http:"&&_))throw new e("invalid_base_url","--base-url must use HTTPS (HTTP is allowed only for localhost).");let T=new Ye({baseUrl:R,credential:We(I),retry:{attempts:1}}),A=await ra(j,await T.workspaces.list(),P);await new Ye({baseUrl:R,credential:We(I),organizationId:A,retry:{attempts:1}}).projects.list();let F=us({baseUrl:R,apiKey:I,organizationId:A},j.env);if(j.json)j.stdout(q(V(Wn.name,{baseUrl:R,organizationId:A,credentialPath:F})));else j.stdout(`Signed in to ${R}
93
- Credential stored at ${F}
94
- `);return 0}},qn={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(`
95
- `),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(R){throw j.stderr(`credential from ${P.credentialSource}, workspace ${P.workspaceId??"none"}, api ${P.baseUrl}
96
- `),R}let I={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(q(V(qn.name,I))),0;return j.stdout(`${ce([["credential",Yt(P)??"none"],["api",`${P.baseUrl} (from ${P.baseUrlSource})`],["workspace",P.workspaceId?`${P.workspaceId} (from ${P.workspaceSource})`:"none"],["status","valid"]])}
97
- `),0}},et={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(`
98
- `),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 R=P.credentialSource==="session",O=R?"session":"environment",_=R?"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.",T=ds(j.env);if(!T){let N={removed:!1,reason:O,path:null};if(j.json)j.stdout(q(V(et.name,N)));else j.stdout(`${_}
99
- `);return 0}if(j.flags.yes!==!0){let N={removed:!1,reason:O,path:T};if(j.json)j.stdout(q(V(et.name,N)));else j.stdout(`${_}
100
- A stored credential also exists at ${T} — repeat with --yes to remove it.
101
- `);return 0}let A=Cn(j.env);if(j.json)j.stdout(q(V(et.name,A)));else j.stdout(`Removed ${A.path}
102
- ${R?"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."}
103
- `);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 I=Cn(j.env);if(j.json)j.stdout(q(V(et.name,I)));else j.stdout(I.removed?`Removed ${I.path}
104
- `:`No stored credential at ${I.path}
105
- `);return 0}};var Gs=Ze.join(" | "),Vn={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(`
106
- `),supportsJson:!0,async run(j){let P=d(j.cwd,j.env),I=_s(P);if(j.json)return j.stdout(q(V(Vn.name,{settings:I,paths:P.paths}))),0;return j.stdout(`${Ee(["setting","value","source","applies to"],I.map((R)=>[R.key,R.value??"-",R.source,xs[R.key]??"this folder's binding"]))}
107
- `),j.stdout(`
108
- global ${P.paths.global}
109
- `),j.stdout(`project ${P.paths.project??"- (this folder is not bound to hlix)"}
110
- `),0}},Xn={name:"config get",summary:"Print one setting's effective value",usage:[`Usage: hlix config get <${Gs}> [--cwd <dir>] [--json]`,"","Prints the value the cascade resolves for one key, or exits 1 when no","file names it."].join(`
111
- `),supportsJson:!0,args:{min:1,max:1},async run(j){let P=zn(j.args[0]),I=d(j.cwd,j.env),R=I.merged[P]??null,O=I.sources[P]??"default";if(j.json)return j.stdout(q(V(Xn.name,{key:P,value:R,source:O}))),R===null?1:0;if(R===null)return j.stderr(`${P} is not set. Set it with \`hlix config set ${P} <value>\`.
112
- `),1;return j.stdout(`${R}
113
- `),0}},Yn={name:"config set",summary:"Set one setting for this folder, or for the machine with --global",usage:[`Usage: hlix config set <${Gs}> <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(`
114
- `),supportsJson:!0,options:["global"],args:{min:2,max:2},async run(j){let P=zn(j.args[0]),I=Os(P,j.args[1]),R=j.flags.global===!0?"global":"project",O=u({key:P,value:I,scope:R,cwd:j.cwd,env:j.env});if(j.json)return j.stdout(q(V(Yn.name,{key:P,value:I,scope:R,path:O}))),0;return j.stdout(`${P} = ${I} (${R}: ${O})
115
- `),0}};function He(j,P){if(typeof j!=="object"||j===null)return"";let I=j[P];return I===null||I===void 0?"":String(I)}var Zn={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(q(V(Zn.name,P))),0;let I=Array.isArray(P)?P:[];if(I.length===0)return j.stdout(`No projects.
116
- `),0;return j.stdout(`${Ee(["ID","NAME","STACK"],I.map((R)=>[He(R,"id"),He(R,"name"),He(R,"stack")]))}
117
- `),0}},Qn={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(`
118
- `),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 I=await j.requireClient().projects.get(P);if(j.json)return j.stdout(q(V(Qn.name,I))),0;let R=I.repos;return j.stdout(`${ce([["id",He(I,"id")],["name",He(I,"name")],["stack",He(I,"stack")],["status",He(I,"status")],["repos",Array.isArray(R)?String(R.length):""]].filter(([,O])=>O!==""))}
119
- `),0}};function er(j,P){let I=j.args[0];if(!I)throw new e("missing_argument",`A ${P} id is required.`);return I}function Ws(j,P){let I=j.flags[P];return typeof I==="string"&&I.trim()?I.trim():void 0}function ye(j,P){if(typeof j!=="object"||j===null)return"";let I=j[P];return I===null||I===void 0?"":String(I)}var tr={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(`
120
- `),supportsJson:!0,options:["project","status"],async run(j){let P=Ws(j,"project")??t(j.cwd)?.config.projectId,I=Ws(j,"status"),R=await j.requireClient().tasks.list({...P?{projectId:P}:{},...I?{status:I}:{}});if(j.json)return j.stdout(q(V(tr.name,R))),0;let O=Array.isArray(R)?R:[];if(O.length===0)return j.stdout(`No tasks.
121
- `),0;return j.stdout(`${Ee(["ID","STATUS","TITLE"],O.map((_)=>[ye(_,"id"),ye(_,"status"),ye(_,"title")||ye(_,"description").split(`
122
- `)[0]||""]))}
123
- `),0}},nr={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=er(j,"task"),I=await j.requireClient().tasks.get(P);if(j.json)return j.stdout(q(V(nr.name,I))),0;return j.stdout(`${ce([["id",ye(I,"id")],["status",ye(I,"status")],["title",ye(I,"title")],["project",ye(I,"projectId")],["description",ye(I,"description")]])}
124
- `),0}},rr={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=er(j,"task"),I=await j.requireClient().tasks.review(P);if(j.json)return j.stdout(q(V(rr.name,I))),0;return j.stdout(`${JSON.stringify(I,null,2)}
125
- `),0}},sr={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(`
126
- `),supportsJson:!0,args:{min:1,max:1},async run(j){let P=er(j,"task"),I=j.requireClient();for await(let R of I.tasks.stream(P)){let O;try{O=JSON.parse(R.data)}catch{O=R.data}if(j.json)j.stdout(`${JSON.stringify(V(sr.name,O))}
127
- `);else{let _=ye(O,"status"),T=ye(O,"error");j.stdout(T?`error: ${T}
128
- `:`${_||R.data}
129
- `)}}return 0}};import{realpath as ac}from"node:fs/promises";import{resolve as cc}from"node:path";import{createHash as Rt}from"node:crypto";import{createReadStream as la}from"node:fs";import{lstat as co,mkdir as da,readFile as It,readdir as ua,readlink as pa,realpath as lo,stat as ma,writeFile as fa}from"node:fs/promises";import{basename as Me,dirname as ga,join as rn,relative as Qs,resolve as eo,sep as ha}from"node:path";import{execFile as ya,spawnSync as wa}from"node:child_process";import to from"ignore";import{readFile as oa}from"node:fs/promises";import{join as ia}from"node:path";function sa(j){let P=j.trim();if(!P||/^[|>[{]/.test(P))return null;let I=P.match(/^(["'])([\s\S]*)\1$/);if(!I&&/^["']/.test(P))return null;return(I?I[2].trim():P.replace(/(?:^|\s)#.*$/,"").trim())||null}function qs(j){let P=j.split(/\r?\n/),I=P.findIndex((T)=>/^tasks:\s*(?:#.*)?$/.test(T));if(I===-1)return{tasks:[],partial:/^tasks:\s*\S/m.test(j)};let R=[],O=!1,_=-1;for(let T of P.slice(I+1)){if(!T.trim()||/^\s*#/.test(T))continue;let A=T.length-T.trimStart().length,N=T.match(/^(\s*-(?:\s+|$))(.*)$/);if(N){if(_!==-1&&A>=_)continue;if(R.push({}),_=N[2]?N[1].length:-1,!N[2])continue}else if(A===0)break;else if(R.length===0)continue;else if(_===-1)_=A;else if(A!==_)continue;let F=(N?N[2]:T.trim()).match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);if(!F)continue;let H=F[1];if(H!=="name"&&H!=="before"&&H!=="init"&&H!=="command")continue;let L=sa(F[2]);if(L===null)O=!0;else R[R.length-1][H]=L}return{tasks:R,partial:O}}async function Le(j,P){try{return await oa(ia(j,...P.split("/")),"utf8")}catch(I){if(I.code==="ENOENT")return null;throw I}}function Vs(j){try{let P=j.replace(/(^|[^:\\])\/\/.*$/gm,"$1").replace(/\/\*[\s\S]*?\*\//g,"").replace(/,\s*([}\]])/g,"$1");return JSON.parse(P)}catch{return null}}function Ae(j){if(typeof j==="string"&&j.trim())return[j.trim()];if(Array.isArray(j))return j.flatMap(Ae);if(j&&typeof j==="object")return Object.values(j).flatMap(Ae);return[]}function or(j){if(!j||typeof j!=="object")return[];return Object.keys(j).filter((P)=>/^[A-Za-z_][A-Za-z0-9_]*$/.test(P))}function aa(j,P){let I=new Set,R=[/\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)R.push(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}/g);for(let O of R)for(let _ of j.matchAll(O))I.add(_[1]);return[...I]}function ca(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 Xs(j){let P=typeof j==="number"?j:Number(j);return Number.isInteger(P)&&P>0&&P<=65535?P:null}function ge(j,P,I){if(!j.some((R)=>R.path===P&&R.kind===I))j.push({path:P,kind:I})}async function Ys(j,P,I){let R=[],O=[],_=[],T=[],A=new Map,N=new Set,F=new Set,H=[],L={},D=null,K=0,z=await Le(j,".cursor/environment.json");if(z){ge(R,".cursor/environment.json","cursor");let G=Vs(z);if(!G)H.push("Could not parse .cursor/environment.json; it remains quarantined.");else{O.push(...Ae(G.install));let te=Ae(G.start);if(te[0])D=te[0];if(Array.isArray(G.terminals))for(let Z of G.terminals){if(!Z||typeof Z!=="object")continue;let se=Z;if(typeof se.command!=="string"||!se.command.trim())continue;T.push({name:typeof se.name==="string"&&se.name.trim()?se.name.trim():"Terminal",command:se.command.trim(),...typeof se.cwd==="string"&&se.cwd.trim()?{cwd:se.cwd.trim()}:{}})}}}let M=P.has(".devcontainer/devcontainer.json")?".devcontainer/devcontainer.json":P.has("devcontainer.json")?"devcontainer.json":null;if(M){ge(R,M,"devcontainer");let G=Vs(I.get(M)??await Le(j,M)??"");if(!G)H.push(`Could not parse ${M}; it remains quarantined.`);else{O.push(...Ae(G.onCreateCommand),...Ae(G.updateContentCommand),...Ae(G.postCreateCommand));let te=Ae(G.postStartCommand);if(!D&&te[0])D=te[0];for(let Z of or(G.secrets))N.add(Z);for(let Z of[...or(G.containerEnv),...or(G.remoteEnv)])N.add(Z);if(Array.isArray(G.forwardPorts))for(let Z of G.forwardPorts){let se=Xs(Z);if(se)A.set(se,{port:se,visibility:"private"})}}}if(P.has(".gitpod.yml")){ge(R,".gitpod.yml","gitpod");let G=I.get(".gitpod.yml")??await Le(j,".gitpod.yml");if(G===null)H.push("Could not read .gitpod.yml; its task commands were not imported.");else{let te=qs(G);K=te.tasks.filter((Z)=>Z.before).length;for(let Z of te.tasks){if(Z.before)O.push(Z.before);if(Z.init)O.push(Z.init);if(!Z.command)continue;if(!D)D=Z.command;else T.push({name:Z.name??"Terminal",command:Z.command})}if(te.partial)H.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 G of["Dockerfile","docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"])if(P.has(G))ge(R,G,"docker");for(let G of["project.toml","nixpacks.toml","railpack.json","Aptfile"])if(P.has(G))ge(R,G,"buildpack");for(let G of["fly.toml","railway.json","render.yaml","vercel.json","netlify.toml"])if(P.has(G))ge(R,G,"platform");let U=I.get("package.json")??await Le(j,"package.json");if(U){ge(R,"package.json","package");try{let G=JSON.parse(U);if(G.engines?.node)L.node=G.engines.node;let te=ca(P,G.packageManager);if(te&&O.length===K)O.push(te);if(G.scripts?.build&&_.length===0)_.push(`${G.packageManager?.split("@")[0]??(P.has("bun.lock")?"bun":"npm")} run build`);let Z=G.scripts?.dev?`${P.has("bun.lock")?"bun":"npm"} run dev`:null,se=G.scripts?.start?`${P.has("bun.lock")?"bun":"npm"} run start`:Z;if(!D&&se)D=se}catch{H.push("Could not parse package.json for environment discovery.")}}if(P.has("uv.lock"))O.push("uv sync --frozen");else if(P.has("poetry.lock"))O.push("poetry install --no-interaction");else if(P.has("requirements.txt"))O.push("python -m pip install -r requirements.txt");if(P.has("go.mod"))O.push("go mod download");if(P.has("Procfile")){ge(R,"Procfile","procfile");let te=(I.get("Procfile")??"").split(/\r?\n/).find((Z)=>/^web\s*:/.test(Z));if(te)D=te.replace(/^web\s*:\s*/,"").trim()||D}let B=[[".node-version","node"],[".nvmrc","node"],[".python-version","python"]];for(let[G,te]of B){let Z=(I.get(G)??await Le(j,G))?.trim();if(Z)L[te]=Z,ge(R,G,"tool-version")}let J=I.get(".tool-versions")??await Le(j,".tool-versions");if(J){ge(R,".tool-versions","tool-version");for(let G of J.split(/\r?\n/)){let[te,Z]=G.trim().split(/\s+/,2);if(!Z)continue;if(te==="nodejs")L.node=Z;else if(te==="python")L.python=Z;else if(te==="bun")L.bun=Z}}let ne=I.get("mise.toml")??await Le(j,"mise.toml");if(ne){ge(R,"mise.toml","tool-version");for(let G of ne.matchAll(/^\s*(node|python|bun)\s*=\s*["']([^"']+)["']/gm))L[G[1]]=G[2]}for(let[G,te]of I){let Z=/(?:^|\/)(?:Dockerfile|Procfile)$/i.test(G)||/\.(?:jsonc?|ya?ml|toml|ini|conf|config|env|sh|bash|zsh|fish)$/i.test(G);for(let se of aa(te,Z))F.add(se);for(let se of te.matchAll(/(?:--port(?:=|\s+)|PORT\s*=\s*)(\d{2,5})/g)){let Re=Xs(se[1]);if(Re)A.set(Re,{port:Re,visibility:"private"})}}if(R.length===0&&P.size>0)ge(R,"repository","detected");let ae=(G)=>[...new Set(G.filter(Boolean))],re=R.length+O.length+(D?1:0);return{sources:R.sort((G,te)=>G.path.localeCompare(te.path)),toolchain:L,install:ae(O),build:ae(_),start:D,terminals:T,ports:[...A.values()].sort((G,te)=>G.port-te.port),requiredSecretKeys:[...N].sort(),observedSecretKeys:[...F].sort(),confidence:re>=4?"high":re>=2?"medium":"low",warnings:H}}var Zs=2;var uo=300000,va=25000,ba=52428800,Sa=524288000,xt=1e4,dr="Potential secrets exist in Git history",nn=1048576,Pt=20971520,no=[".git/",".hlix/","node_modules/",".next/",".turbo/",".cache/","dist/","build/","coverage/","__pycache__/",".venv/","venv/","target/",".DS_Store"],ur="Required project environment value was not found locally: ",ka=/(^|\/)\.env\.(example|sample|template)$/i,ja=/(^|\/)\.env(?:\.[^/]+)?$/i,Ea=/(^|\/)(?:\.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,$a=/\.(?:example|sample|template)$/i,Pa=/(^|\/)\.(?:npmrc|yarnrc(?:\.yml)?|pypirc)$/i,Ca=/(?:^|\/)(?:__tests__|tests?|fixtures)\/|\.(?:test|spec)\.[^/]+$|\.snap$/i,Ia=/\.(?:md|mdx|txt|rst)$/i,xa=/fake|dummy|example|placeholder|unused|changeme|xxxx|redacted|your[_-]|<[^>]*>/i,Ra=/^(.)\1+$/,_a=/RegExp\(/,pr="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,}",Oa=new RegExp(pr,"g"),Ta=/(^|\/)(?:\.mcp\.json|mcp\.json|claude_desktop_config\.json)$/i,Aa=/(^|\/)(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.github\/copilot-instructions\.md)$/i,Na=/(^|\/)(?:\.agents|\.claude)\/skills\//i,po=/-----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,}/,_u=new RegExp(po.source,"g"),Fa=/\.(?:json|ya?ml|toml|ini|conf|config)$/i,Ha=/(?:^|[,{\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,Ct=new Set(["HLIX_AGENT_RUN_ID","HLIX_API_KEY","HLIX_API_URL","HLIX_BASE_URL","HLIX_PROJECT_ID","HLIX_SESSION_TOKEN","HLIX_WORKSPACE_ID"]),ir="Your hlix credentials were left out of the project's secrets — the platform provides them.",ar=new Set(["CI","HOME","LANG","LOGNAME","NODE_ENV","OLDPWD","PATH","PORT","PWD","SHELL","SHLVL","TERM","TMPDIR","USER","_"]),La=100,ro=12;function Ma(j){let P=j.slice(0,ro).join(", "),I=j.length-ro;return j.length===1?`Observed environment reference has no local value: ${j[0]}`:`${j.length} observed environment references have no local value: ${P}${I>0?`, +${I} more`:""}`}var Ua=250;function tt(j){return j.split(ha).join("/")}function we(j){if(j>=1048576)return`${(j/1048576).toFixed(1)} MB`;if(j>=1024)return`${(j/1024).toFixed(1)} KB`;return`${j} bytes`}function cr(j,P=5){return[...j].sort((I,R)=>R.size-I.size||I.path.localeCompare(R.path)).slice(0,P).map((I)=>`${I.path} (${we(I.size)})`).join(", ")}function lr(j,P=5){let I=new Map;for(let R of j){let O=R.indexOf("/"),_=O===-1?".":R.slice(0,O);I.set(_,(I.get(_)??0)+1)}return[...I].sort((R,O)=>O[1]-R[1]||R[0].localeCompare(O[0])).slice(0,P).map(([R,O])=>`${R}/ (${O} files)`).join(", ")}function ve(j,P,I=10485760){return wa("git",["-C",j,...P],{encoding:"utf8",timeout:uo,maxBuffer:I,stdio:["ignore","pipe","pipe"]})}function sn(j,P,I={}){return new Promise((R)=>{ya("git",["-C",j,...P],{encoding:"utf8",timeout:uo,maxBuffer:I.maxBuffer??10485760,...I.signal?{signal:I.signal}:{}},(O,_)=>{let T=O?.code;R({status:O===null?0:typeof T==="number"?T:1,stdout:typeof _==="string"?_:""})})})}async function Da(j){let P=Rt("sha256");for await(let I of la(j))P.update(I);return P.digest("hex")}function _t(j){if(Array.isArray(j))return`[${j.map(_t).join(",")}]`;if(j&&typeof j==="object")return`{${Object.entries(j).sort(([P],[I])=>P.localeCompare(I)).map(([P,I])=>`${JSON.stringify(P)}:${_t(I)}`).join(",")}}`;return JSON.stringify(j)}function mo(j){let P={};for(let[I,R]of String(j).replace(/^\uFEFF/,"").split(/\r?\n/).entries()){let O=R.trim();if(!O||O.startsWith("#"))continue;let T=(O.startsWith("export ")?O.slice(7).trimStart():O).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!T)throw Error(`Invalid dotenv assignment on line ${I+1}`);let A=T[2]??"";if(A.startsWith('"')){if(!A.endsWith('"'))throw Error(`Unclosed dotenv quote on line ${I+1}`);A=A.slice(1,-1).replace(/\\n/g,`
130
- `).replace(/\\r/g,"\r")}else if(A.startsWith("'")){if(!A.endsWith("'"))throw Error(`Unclosed dotenv quote on line ${I+1}`);A=A.slice(1,-1)}else A=A.replace(/\s+#.*$/,"").trimEnd();P[T[1]]=A}return P}function za(j,P){return j.split(/(?<=\n)/).filter((I)=>{let R=I.trim(),_=(R.startsWith("export ")?R.slice(7).trimStart():R).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=/)?.[1];return _===void 0||!P.has(_)}).join("")}function Ba(j){let P=null;for(let I=0;I<j.length;I+=1){let R=j[I];if(R==="\\"&&P!=="single"){if(j[I+1]!=="$")return!0;I+=1;continue}if(R==="'"&&P!=="double"){P=P==="single"?null:"single";continue}if(R==='"'&&P!=="single"){P=P==="double"?null:"double";continue}if(P!=="single"&&(R==="$"||R==="`"))return!0;if(P===null&&(R==="<"||R===">")&&j[I+1]==="(")return!0}return P!==null}function Ka(j){let P={},I=new Set,R=new Set;for(let O of String(j).replace(/^\uFEFF/,"").split(/\r?\n/)){let _=O.trim();if(!_||_.startsWith("#"))continue;let A=(_.startsWith("export ")?_.slice(7).trimStart():_).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!A)continue;let N=A[1],F=A[2]??"";if(I.add(N),Ba(F)){delete P[N],R.add(N);continue}try{let L=mo(`${N}=${F}`)[N];if(L===void 0)throw Error("missing literal");P[N]=F.trimStart().startsWith("'")?L:L.replace(/\\\$/g,"$"),R.delete(N)}catch{delete P[N],R.add(N)}}return{values:P,keys:[...I].sort(),dynamicKeys:[...R].sort()}}async function Ja(j){let P=ve(j,["rev-parse","--show-toplevel"]);if(P.status!==0)return!1;try{return await lo(P.stdout.trim())===j}catch{return!1}}function Ga(j,P){if(!P)return new Set;let I=ve(j,["ls-files","-z"]);if(I.status!==0)throw Error("Could not enumerate tracked files.");return new Set(I.stdout.split("\x00").filter(Boolean).map(tt))}function Wa(j,P){if(!P)return[];let I=ve(j,["config","--get-regexp","^remote\\..*\\.url$"]);if(I.status!==0)return[];let R=[];for(let O of I.stdout.split(`
131
- `)){let _=O.trim();if(!_)continue;let T=/^remote\.(.*)\.url (.+)$/.exec(_);if(T)R.push({name:T[1],url:T[2]})}return R}function qa(j,P){if(!P)return{files:new Set,directories:[]};let I=ve(j,["ls-files","-z","--others","--ignored","--exclude-standard","--directory"]);if(I.status!==0)throw Error("Could not enumerate ignored files.");let R=new Set,O=[];for(let _ of I.stdout.split("\x00").filter(Boolean)){let T=tt(_);if(T.endsWith("/"))O.push(T);else R.add(T)}return{files:R,directories:O}}async function Va(j){let P=to().add(no),I=to().add(no),R=[];for(let O of[".gitignore",".hlixignore"])try{let _=rn(j,O),T=await co(_);if(T.isFile())I.add(await It(_,"utf8"));else if(T.isSymbolicLink())R.push(O)}catch(_){if(_.code!=="ENOENT")throw _}return{hardMatcher:P,matcher:I,symlinked:R}}function so(j){if(Ta.test(j))return"mcp";if(Na.test(j))return"skill";if(Aa.test(j))return"agent";return null}function oo(j){if(ja.test(j)&&!ka.test(j))return"dotenv";if(Ea.test(j))return"credential";return null}function Xa(j){if(j.has("package.json"))return"typescript";if(j.has("pyproject.toml")||j.has("requirements.txt"))return"python";if(j.has("go.mod"))return"go";if(j.has("Cargo.toml"))return"rust";if(j.has("composer.json"))return"php";if(j.has("Gemfile"))return"ruby";return"other"}function Ya(j,P){if(P)return[tt(P)];let I=new Map([[".env",0],[".env.development",1],[".env.local",2],[".env.development.local",3]]),R=j.filter((O)=>I.has(Me(O).toLocaleLowerCase("en-US"))).sort((O,_)=>O.slice(0,-Me(O).length).localeCompare(_.slice(0,-Me(_).length))||I.get(Me(O).toLocaleLowerCase("en-US"))-I.get(Me(_).toLocaleLowerCase("en-US")));return R.length>0?R:j.length===1?[...j]:[]}function Za(j,P){try{let I=JSON.parse(P);if(!I.mcpServers||typeof I.mcpServers!=="object")return[];return Object.entries(I.mcpServers).map(([R,O])=>{let _=O&&typeof O==="object"?O:{},T=_.type==="http"||_.type==="sse"||_.type==="stdio"?_.type:typeof _.command==="string"?"stdio":typeof _.url==="string"?"http":"unknown",A=_.env&&typeof _.env==="object"?_.env:{};return{sourcePath:j,name:R,transport:T,...typeof _.command==="string"?{command:_.command}:{},...Array.isArray(_.args)&&_.args.every((N)=>typeof N==="string")?{args:_.args}:{},...typeof _.url==="string"?{url:_.url}:{},envKeys:Object.keys(A).sort(),enabled:!1}})}catch{return[]}}function Qa(j){let P=!1,I=!1;for(let R of j.split(/\r?\n/)){let O=R.trim();if(!O||O.startsWith("#")||O.startsWith(";")||O.startsWith("["))continue;let _=O.indexOf("=");if(_===-1)continue;let T=O.slice(0,_).trim().toLowerCase(),A=O.slice(_+1).trim().replace(/^["']|["']$/g,"");if(!A||/^\$(?:\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*)$/.test(A))continue;if(T.endsWith("_authtoken")||T.endsWith("_password"))return!0;if(T.endsWith("password"))I=!0;else if(T.endsWith("username"))P=!0}return P&&I}async function ec(j,P,I,R){if($a.test(I))return!1;if(!Pa.test(I))return!0;let O=await sn(j,["show",`${P}:${I}`],{...R?{signal:R}:{}});return O.status===0&&Qa(O.stdout)}function tc(j,P,I){let R=j.lastIndexOf("/",P),O=j.indexOf("/",I);return R!==-1&&O!==-1&&!/\s/.test(j.slice(R,P)+j.slice(I,O))}function nc(j){if(Ca.test(j))return"test fixture";if(Ia.test(j))return"documentation or pattern definition";return null}function rc(j,P){let I=null;for(let R of j.split(/\r?\n/))for(let O of R.matchAll(P)){let _=O[0],T=O.index??0,A=_a.test(R)||tc(R,T,T+_.length)?"documentation or pattern definition":xa.test(_)||Ra.test(_)?"placeholder value":null;if(A===null)return null;I??=A}return I}async function sc(j,P,I,R){let O=nc(I);if(O!==null)return O;let _=await sn(j,["show",`${P}:${I}`],{...R?{signal:R}:{}});return _.status===0?rc(_.stdout,Oa):null}async function io(j,P,I){let R=[],O="unknown";for(let _ of j.split(/\r?\n/)){if(_.startsWith("@@"))O=_.slice(2);else if(_.trim()){let T=tt(_.trim());if(await I(O,T))R.push({commit:O,path:T,reason:P})}if(R.length>=100)break}return R}async function ao(j,P,I={}){if(!P)return{head:null,branch:null,refs:[],commitCount:0,complete:!0,findings:[],blockingFindings:[],waivedReasons:[]};let R=ve(j,["rev-parse","HEAD"]).stdout.trim()||null,O=ve(j,["symbolic-ref","--short","-q","HEAD"]),_=O.status===0?O.stdout.trim()||null:null,T=Number.parseInt(ve(j,["rev-list","--count","--all"]).stdout.trim(),10)||0,A=ve(j,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]),N=A.stdout.split(`
132
- `).filter(Boolean).map((B)=>{let[J,ne]=B.split("\x00");return{name:J,oid:ne}}).filter(({name:B,oid:J})=>/^refs\/(?:heads|tags)\/.+/.test(B)&&/^[0-9a-f]{40,64}$/.test(J)).sort((B,J)=>B.name.localeCompare(J.name)),F=I.signal,H=F?{signal:F}:{};I.onProgress?.(`history: ${T} commit${T===1?"":"s"}…`);let L=["log","--all",`--max-count=${xt}`,"--pretty=format:@@%H","--name-only"],D=await sn(j,[...L,"--",".env",".env.*","*.pem","*.key",".npmrc","*.tfvars"],H),K=await sn(j,["log","--all",`--max-count=${xt}`,"-G",pr,"--pretty=format:@@%H","--name-only"],H);F?.throwIfAborted();let z=new Map;for(let B of[...await io(D.stdout,"sensitive-path",(J,ne)=>ec(j,J,ne,F)),...await io(K.stdout,"secret-pattern",async()=>!0)])z.set(`${B.commit}:${B.path}:${B.reason}`,B);let M=[...z.values()].slice(0,100),U=new Map;for(let B of M){if(B.reason!=="secret-pattern")continue;let J=await sc(j,B.commit,B.path,F);if(J!==null)U.set(B,J)}return I.onProgress?.(`history: ${T} commit${T===1?"":"s"} scanned`),{head:R,branch:_,refs:N,commitCount:T,complete:T<=xt&&N.length<=1000&&A.status===0&&D.status===0&&K.status===0,findings:M,blockingFindings:M.filter((B)=>!U.has(B)),waivedReasons:[...U.values()]}}function oc(j,P){let I=P?.XDG_CACHE_HOME??(P?.HOME?rn(P.HOME,".cache"):null);if(!I)return null;return rn(I,"hlix","history",`${Rt("sha256").update(j).digest("hex")}.json`)}async function ic(j,P,I){let R=P?oc(j,I.environment):null;if(!R)return ao(j,P,I);let O=Rt("sha256").update([ve(j,["for-each-ref","--format=%(refname)%00%(objectname)"]).stdout,ve(j,["rev-parse","HEAD"]).stdout,ve(j,["symbolic-ref","--short","-q","HEAD"]).stdout,pr,String(xt)].join("\x00")).digest("hex");try{let T=JSON.parse(await It(R,"utf8"));if(T.key===O&&T.history)return I.onProgress?.(`history: ${T.history.commitCount} commits, unchanged since the last scan`),T.history}catch{}let _=await ao(j,P,I);if(_.complete)try{await da(ga(R),{recursive:!0,mode:448}),await fa(R,JSON.stringify({key:O,history:_}),{mode:384})}catch{}return _}async function Se(j,P={}){let I=await lo(eo(j));if(!(await ma(I)).isDirectory())throw Error("Import target must be a directory.");let R=await Ja(I),O=Wa(I,R),_=Ga(I,R),T=qa(I,R),{hardMatcher:A,matcher:N,symlinked:F}=await Va(I),H=[],L=[],D=[],K=[],z=[],M=[],U=[],B=[],J=P.envFile?tt(Qs(I,eo(I,P.envFile))):void 0,ne=J!==void 0&&J!==""&&J!==".."&&!J.startsWith("../");if(P.envFile&&!ne)B.push(`Selected environment file must stay inside the project: ${P.envFile}`);let ae=new Map,re=new Map,G=new Map,te=new Map,Z=[],se=[],Re=[],qr=new Map,Dt=P.maxFiles??va,Vr=P.maxFileBytes??ba,Xr=P.maxTotalBytes??Sa,wn=0,_e=0,Yr=()=>H.length+L.length+K.length+z.length,Zr=0,Qr=async(W)=>{let Y=await ua(W,{withFileTypes:!0});Y.sort((ie,le)=>ie.name.localeCompare(le.name));for(let ie of Y){if(P.signal?.throwIfAborted(),Zr+=1,Zr%Ua===0)P.onProgress?.(`scanning … ${H.length} files`);let le=rn(W,ie.name),Q=tt(Qs(I,le));if(ie.name===".git"){if(Q!==".git")B.push(`Nested Git repository is not supported: ${Q}`);continue}let de=await co(le),kn=ie.isDirectory()?`${Q}/`:Q,jn=_.has(Q),rs=!jn&&(N.ignores(kn)||T.files.has(Q)||T.directories.some((oe)=>kn.startsWith(oe))),Go=!jn&&A.ignores(kn);if(de.isSymbolicLink()){if(rs)continue;if(Yr()>=Dt){B.push(`Project exceeds the ${Dt} file limit, reached at ${Q}. Largest folders: ${lr(H.map((oe)=>oe.path))}. Exclude generated folders with .hlixignore.`);return}if(L.push({path:Q,target:await pa(le)}),so(Q)||oo(Q))D.push(Q);continue}if(ie.isDirectory()){if(Go)continue;await Qr(le);continue}let at=so(Q),ct=oo(Q);if(rs&&!at&&!ct)continue;if(!ie.isFile()){U.push({path:Q,reason:"non-regular-file"});continue}if(Yr()>=Dt){B.push(`Project exceeds the ${Dt} file limit, reached at ${Q}. Largest folders: ${lr(H.map((oe)=>oe.path))}. Exclude generated folders with .hlixignore.`);return}if(de.size>Vr){B.push(`File ${Q} is ${we(de.size)}, over the ${we(Vr)} per-file limit. Exclude it with .hlixignore.`);continue}if(wn+=de.size,wn>Xr){B.push(`Project files total at least ${we(wn)}, over the ${we(Xr)} limit. Largest so far: ${cr([...H,{path:Q,size:de.size}])}. Exclude large files with .hlixignore.`);return}let lt=await Da(le);if(at){if(de.size>nn){B.push(`Protected configuration ${Q} is ${we(de.size)}, over the ${we(nn)} per-file limit. Move the large content out of it, or exclude it with .hlixignore.`);continue}let oe=await It(le);if(_e+=oe.byteLength,Re.push({path:Q,size:oe.byteLength}),_e>Pt)continue;if(z.push({path:Q,kind:at,size:de.size,sha256:lt}),se.push({path:Q,kind:at,contentBase64:oe.toString("base64")}),at==="mcp")M.push(...Za(Q,oe.toString("utf8")));continue}if(ct){if(de.size>nn){B.push(`Protected file ${Q} is ${we(de.size)}, over the ${we(nn)} per-file limit. Move the large content out of it, or exclude it with .hlixignore.`);continue}let oe=await It(le);if(_e+=oe.byteLength,Re.push({path:Q,size:oe.byteLength}),_e>Pt)continue;let Ne=[],De=new Set;if(ct==="dotenv")try{let Jt=mo(oe),ze={};for(let[Oe,Be]of Object.entries(Jt)){if(Ct.has(Oe)){De.add(Oe);continue}ze[Oe]=Be}ae.set(Q,ze),Ne=Object.keys(ze).sort()}catch{B.push(`Could not parse environment file: ${Q}`)}else if(Me(Q)===".envrc"){let Jt=Ka(oe),ze={},Oe=new Set,Be=[];for(let[pe,Wo]of Object.entries(Jt.values)){if(Ct.has(pe)){De.add(pe);continue}if(ar.has(pe)){Z.push(`Ignored ambient runtime assignment in ${Q}: ${pe}`);continue}Oe.add(pe),ze[pe]=Wo}re.set(Q,ze);for(let pe of Jt.dynamicKeys){if(Ct.has(pe)){De.add(pe);continue}if(ar.has(pe)){Z.push(`Ignored ambient runtime assignment in ${Q}: ${pe}`);continue}Oe.add(pe),Be.push(pe)}if(G.set(Q,[...Oe].sort()),te.set(Q,Be.sort()),Ne=[...Oe].sort(),Be.length>0)Z.push(`Did not execute dynamic .envrc assignments; collect their resolved local values when available: ${Be.join(", ")}`)}if(De.size>0)Z.push(ir),oe=Buffer.from(za(oe.toString("utf8"),De),"utf8"),lt=Rt("sha256").update(oe).digest("hex");K.push({path:Q,kind:ct,keys:Ne,size:oe.byteLength,sha256:lt}),se.push({path:Q,kind:ct,contentBase64:oe.toString("base64")});continue}if(de.size<=1048576){let oe=await It(le),Ne=oe.toString("utf8");if(qr.set(Q,Ne),po.test(Ne)||Fa.test(Q)&&Ha.test(Ne)){if(_e+=oe.byteLength,Re.push({path:Q,size:oe.byteLength}),_e>Pt)continue;K.push({path:Q,kind:"detected-content",keys:[],size:de.size,sha256:lt}),se.push({path:Q,kind:"detected-content",contentBase64:oe.toString("base64")});continue}}H.push({path:Q,size:de.size,sha256:lt,tracked:jn,executable:(de.mode&73)!==0})}};if(await Qr(I),P.onProgress?.(`scanning … ${H.length} files`),P.onProgress?.(`secrets: ${K.length+z.length} files`),P.signal?.throwIfAborted(),D.length>0){let W=D.slice(0,5).join(", "),Y=D.length-5;Z.push(`Imported as symlinks, so no content was read or uploaded for them and the cloud recreates the link: ${W}${Y>0?`, +${Y} more`:""}`)}for(let W of F)B.push(`Ignore file ${W} is a symlink, so its rules were not applied. Replace it with a regular file inside the project.`);if(_e>Pt)B.push(`Protected project files total ${we(_e)}, over the ${we(Pt)} limit. Largest: ${cr(Re)}. Move large assets out of skill and config folders, or add them to .hlixignore.`);if(K.length>2000)B.push(`Project has ${K.length} environment and credential files, over the 2000 limit. Largest: ${cr(K)}. Exclude the ones the cloud project does not need with .hlixignore.`);if(z.length>5000)B.push(`Project has ${z.length} agent, skill and MCP files, over the 5000 limit. Largest folders: ${lr(z.map((W)=>W.path))}. Exclude the ones the cloud project does not need with .hlixignore.`);H.sort((W,Y)=>W.path.localeCompare(Y.path)),L.sort((W,Y)=>W.path.localeCompare(Y.path)),K.sort((W,Y)=>W.path.localeCompare(Y.path)),z.sort((W,Y)=>W.path.localeCompare(Y.path)),M.sort((W,Y)=>`${W.sourcePath}:${W.name}`.localeCompare(`${Y.sourcePath}:${Y.name}`));let vn=Ya([...ae.keys()].sort(),ne?J:void 0);if(P.envFile&&ne&&!ae.has(vn[0]))B.push(`Selected environment file was not found or is not a dotenv file: ${P.envFile}`);let it=new Map;for(let[W,Y]of ae)for(let ie of Object.keys(Y))it.set(ie,[...it.get(ie)??[],W]);for(let[W,Y]of G)for(let ie of Y)it.set(ie,[...it.get(ie)??[],W]);let Do=[...it].filter(([,W])=>W.length>1).map(([W,Y])=>({key:W,paths:Y.sort()})).sort((W,Y)=>W.key.localeCompare(Y.key)),je={};for(let W of vn)Object.assign(je,ae.get(W)??{});let zo=[...re.keys()].sort((W,Y)=>{if(W===".envrc")return 1;if(Y===".envrc")return-1;return W.localeCompare(Y)}),bn=new Set;for(let W of zo){let Y=new Set(te.get(W)??[]);for(let ie of G.get(W)??[]){if(Y.has(ie)){delete je[ie],bn.add(ie);continue}let le=re.get(W)?.[ie];if(le!==void 0)je[ie]=le;bn.delete(ie)}}let zt=P.historyMode??"abort_on_findings",fe=await ic(I,R,P);if(!fe.complete&&zt!=="preserve")B.push(`Git history scan exceeded ${xt} commits or failed; import requires explicit --history preserve.`);let Bt=fe.waivedReasons;for(let W of[...new Set(Bt)].sort()){let Y=Bt.filter((le)=>le===W).length,ie=Y===1;Z.push(`${Y} Git history finding${ie?"":"s"} did not block this import — ${W}, not ${ie?"a real credential":"real credentials"}; --history preserve is not needed for ${ie?"it":"them"}.`)}if(fe.blockingFindings.length>0&&zt==="abort_on_findings"){let W=fe.blockingFindings.length;B.push([`${dr} (${W} finding${W===1?"":"s"}${W>10?", first 10 shown":""}):`,...fe.blockingFindings.slice(0,10).map((Y)=>` ${Y.commit.slice(0,7)} ${Y.path} — ${Y.reason}`),...Bt.length>0?[` ${Bt.length} more look like test fixtures, placeholders or documentation (not blocking)`]:[]," Sanitize the repository, or re-run with --history preserve to import it as it is."].join(`
133
- `))}let es=new Set(H.map((W)=>W.path)),Bo=await Ys(I,es,qr),{observedSecretKeys:Ko,...be}=Bo;be.warnings.push(...Z);let Kt=new Set(be.requiredSecretKeys);for(let W of bn)Kt.add(W);for(let W of M)for(let Y of W.envKeys)Kt.add(Y);for(let W of Ct)if(Kt.delete(W))be.warnings.push(ir);be.requiredSecretKeys=[...Kt].sort();for(let W of be.requiredSecretKeys){if(je[W]!==void 0)continue;let Y=P.environment?.[W];if(Y===void 0){B.push(`${ur}${W}`);continue}je[W]=Y}let Sn=[];for(let W of Ko){if(Ct.has(W)){be.warnings.push(ir);continue}if(ar.has(W))continue;if(je[W]!==void 0)continue;let Y=P.environment?.[W];if(Y===void 0){Sn.push(W);continue}je[W]=Y}if(Sn.length>0)be.warnings.push(Ma(Sn.sort()));be.warnings=[...new Set(be.warnings)].sort().slice(0,La);let ts={schemaVersion:Zs,rootName:P.rootName??Me(I),stack:Xa(es),git:{detected:R,head:fe.head,branch:fe.branch,refs:fe.refs,commitCount:fe.commitCount,historyScanComplete:fe.complete,historyMode:zt},files:H,symlinks:L,secretFiles:K,activeEnvFiles:vn,secretKeys:Object.keys(je).sort(),envCollisions:Do,quarantinedResources:z,mcpServers:M,historicalSecretFindings:fe.blockingFindings,skipped:U,environment:be,totals:{files:H.length,bytes:H.reduce((W,Y)=>W+Y.size,0)}},ns=_t(ts),Jo=Rt("sha256").update(ns).digest("hex");return{root:I,manifest:ts,manifestJson:ns,manifestSha256:Jo,secretValues:je,protectedFiles:se.sort((W,Y)=>W.path.localeCompare(Y.path)),blocking:[...new Set(B)],blockingHistoryFindings:zt==="abort_on_findings"?fe.blockingFindings:[],gitRemotes:O}}var mr={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(`
134
- `),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 ac(cc(j.cwd,j.args[0]??".")),I=r({env:j.env,flags:j.flags,cwd:P});if(I.conflict)throw new e("workspace_mismatch",I.conflict);if(!I.workspaceId)throw Error("No workspace selected. Run `hlix auth login --workspace <id>` first.");let R=j.requireClient(P);await R.projects.list();let O=Je(P),_=typeof j.flags.project==="string"?j.flags.project:void 0;if(_&&O?.projectId&&O.projectId!==_)throw new e("workspace_mismatch",`This folder is bound to project ${O.projectId}; refusing to rebind it to ${_}.`);if(_)await R.projects.get(_);let T={...O??{schemaVersion:1,workspaceId:I.workspaceId,apiUrl:I.baseUrl},..._?{projectId:_}:{}};Ge(P,T);let A=await Se(P,{environment:j.env}),N={root:P,config:T,scan:{files:A.manifest.totals.files,bytes:A.manifest.totals.bytes,secretFiles:A.manifest.secretFiles.map((F)=>F.path),quarantinedResources:A.manifest.quarantinedResources.map((F)=>F.path),blocking:A.blocking}};if(j.json)j.stdout(q(V(mr.name,N)));else if(j.stdout(`Initialized ${P}
135
- Project: ${T.projectId??"not imported yet"}
136
- Workspace: ${T.workspaceId}
137
- `),A.blocking.length)j.stdout(`
138
- Review before import:
139
- ${A.blocking.map((F)=>`- ${F}`).join(`
140
- `)}
141
- `);return 0}};import{createHash as Fc}from"node:crypto";import{existsSync as Hc,rmSync as Lc,rmdirSync as Mc}from"node:fs";import{readFile as Uc,realpath as Dc}from"node:fs/promises";import{basename as zc,join as dn,resolve as Bc}from"node:path";import{createHash as lc}from"node:crypto";import{constants as on}from"node:fs";import{chmod as fo,copyFile as dc,lstat as fr,mkdir as uc,mkdtemp as pc,open as mc,realpath as fc,rename as gc,rm as Ue,symlink as hc,writeFile as yc}from"node:fs/promises";import{tmpdir as wc}from"node:os";import{dirname as wo,join as Pe,relative as vc,resolve as bc,sep as go}from"node:path";import{spawnSync as Sc}from"node:child_process";var kc=300000;function an(j){let P=j;if(typeof P==="string")try{P=JSON.parse(P)}catch{return{}}if(!P||typeof P!=="object")return{};let I=P,R=I.git&&typeof I.git==="object"?I.git:{},O=R.historyMode==="preserve"||R.historyMode==="abort_on_findings"?R.historyMode:void 0,_=typeof I.rootName==="string"&&I.rootName.trim()?I.rootName:void 0;return{historyMode:O,rootName:_}}function vo(j,P){let I=j;if(typeof I==="string")try{I=JSON.parse(I)}catch{return[]}if(!I||typeof I!=="object")return[];let R=I[P];if(!Array.isArray(R))return[];return R.filter((O)=>!!O&&typeof O==="object")}function bo(j){return vo(j,"files").flatMap((P)=>typeof P.path==="string"&&typeof P.sha256==="string"?[{path:P.path,sha256:P.sha256}]:[])}function gr(j){return vo(j,"symlinks").flatMap((P)=>typeof P.path==="string"&&typeof P.target==="string"?[{path:P.path,target:P.target}]:[])}function Ot(j,P){let I=Sc("git",["-C",j,...P],{encoding:"utf8",timeout:kc,maxBuffer:52428800,stdio:["ignore","pipe","pipe"]});if(I.status!==0)throw Error(I.stderr.trim().split(`
142
- `).at(-1)??"Git command failed");return I.stdout.trim()}function ho(j){return lc("sha256").update(j).digest("hex")}async function nt(j,P,I){let R=await fc(j),O=bc(R,...P.split("/"));if(O!==R&&!O.startsWith(R+go))throw Error(`Protected path escapes the project: ${P}`);let _=vc(R,wo(O)),T=R;for(let A of _.split(go).filter(Boolean)){T=Pe(T,A);try{let N=await fr(T);if(N.isSymbolicLink()&&I){I.push(T);break}if(!N.isDirectory()||N.isSymbolicLink())throw Error(`Protected path crosses a non-directory: ${P}`)}catch(N){if(N.code!=="ENOENT")throw N;if(!I)await uc(T,{mode:448})}}return O}async function yo(j,P,I){let R=await nt(j,P);try{let T=await fr(R);if(!T.isFile()||T.isSymbolicLink())throw Error(`Refusing to replace non-regular protected file: ${P}`)}catch(T){if(T.code!=="ENOENT")throw T}let O=Pe(wo(R),`.hlix-pull-${crypto.randomUUID()}.tmp`),_=await mc(O,on.O_WRONLY|on.O_CREAT|on.O_EXCL|on.O_NOFOLLOW,384);try{await _.writeFile(I),await _.sync()}finally{await _.close()}try{await gc(O,R)}catch(T){throw await Ue(O,{force:!0}),T}}async function jc(j,P,I){let R=I.length,O=await nt(j,P,I);if(I.length>R)return;try{let _=await fr(O);if(_.isSymbolicLink()){I.push(O);return}if(!_.isFile())throw Error(`Refusing to replace non-regular project file: ${P}`)}catch(_){if(_.code!=="ENOENT")throw _}}async function cn(j,P,I,R,O){let _=await pc(Pe(wc(),"hlix-pull-"));await fo(_,448);let T=Pe(_,"project.bundle"),A=Pe(_,"checkout");try{let N=Buffer.from(await R.arrayBuffer());if(N.byteLength!==I.bundleSize||ho(N)!==I.bundleSha256)throw Error("Downloaded revision bundle failed integrity verification.");if(await yc(T,N,{mode:384}),Ot(_,["clone","--no-hardlinks","--branch","main",T,A]),Ot(A,["bundle","verify",T]),Ot(A,["rev-parse","HEAD"])!==I.commitSha)throw Error("Downloaded revision bundle does not match the cloud commit.");let F=I.manifest,H=new Map;for(let M of[...F.secretFiles,...F.quarantinedResources])H.set(M.path,M);if(O&&O.files.length!==H.size)throw Error("Cloud protected files do not match the revision manifest.");let L=new Map;for(let M of O?.files??[]){let U=H.get(M.path),B=Buffer.from(M.contentBase64,"base64");if(B.toString("base64").replace(/=+$/,"")!==M.contentBase64.replace(/=+$/,"")||!U||U.kind!==M.kind||B.byteLength!==U.size||ho(B)!==U.sha256)throw Error(`Cloud protected file failed integrity verification: ${M.path}`);L.set(M.path,B)}let D=gr(I.manifest),K=new Set([...F.files.map((M)=>M.path),...D.map((M)=>M.path),...P.manifest.secretFiles.map((M)=>M.path),...P.manifest.quarantinedResources.map((M)=>M.path),...L.keys()]),z=[];for(let M of[...K].sort())await jc(j,M,z);for(let[M,U]of L)await yo(A,M,U);for(let M of[...new Set(z)].sort())await Ue(M,{force:!0});if(P.manifest.git.detected){Ot(j,["fetch",T,"refs/heads/main"]),Ot(j,["reset","--hard","FETCH_HEAD"]);let M=new Set([...F.files.map((U)=>U.path),...D.map((U)=>U.path)]);for(let U of[...P.manifest.files,...P.manifest.symlinks])if(!M.has(U.path))await Ue(Pe(j,...U.path.split("/")),{force:!0})}else{for(let M of[...P.manifest.files,...P.manifest.symlinks])await Ue(Pe(j,...M.path.split("/")),{force:!0});for(let M of F.files){let U=await nt(j,M.path);await dc(Pe(A,...M.path.split("/")),U),await fo(U,M.executable?493:420)}for(let M of D){let U=await nt(j,M.path);await Ue(U,{force:!0}),await hc(M.target,U)}}if(O){for(let M of[...P.manifest.secretFiles,...P.manifest.quarantinedResources])if(!L.has(M.path))await Ue(Pe(j,...M.path.split("/")),{force:!0})}for(let[M,U]of L)await yo(j,M,U)}finally{await Ue(_,{recursive:!0,force:!0})}}function he(j){return new Map([...bo(j).map((P)=>[P.path,`blob:${P.sha256}`]),...gr(j).map((P)=>[P.path,`link:${P.target}`])])}function rt(j,P,I){let R=he(I.manifest),O=he(j.manifest),_=0,T=0;for(let[N,F]of O){let H=R.get(N);if(H===void 0)_+=1;else if(H!==F)T+=1}let A=0;for(let N of R.keys())if(!O.has(N))A+=1;return{localChanged:!P.manifestSha256||j.manifestSha256!==P.manifestSha256,cloudChanged:I.id!==P.revisionId||I.generation!==P.generation,local:{revisionId:P.revisionId,generation:P.generation},cloud:{revisionId:I.id,generation:I.generation,commitSha:I.commitSha},files:{local:O.size,cloud:R.size,localOnly:_,cloudOnly:A,differing:T}}}function hr(j,P,I){let{localChanged:R,cloudChanged:O}=P;if(j==="push")return O?"conflict":R?"push":"none";if(j==="pull"){if(!O)return"none";return R&&!I?"conflict":"pull"}if(R&&O)return"conflict";return R?"push":O?"pull":"none"}function yr(j,P,I){return j==="pull"&&P.localChanged&&!I}var Ec={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 $c(j,P,I){if(P==="push"&&I.cloud.generation===0)return`Would push ${I.files.local} files as revision 1 — this project has no cloud revision yet.`;return Ec[j][P]}function So(j,P,I,R){let O=I.files;return[`${j} --dry-run: ${$c(j,P,I)}`,...R?["Requires --yes (or interactive approval) to execute."]:[],"",ce([["local",`generation ${I.local.generation} (${I.local.revisionId})${I.localChanged?" — modified":""}`],["cloud",`generation ${I.cloud.generation} (${I.cloud.revisionId})${I.cloudChanged?" — ahead":""}`],["files",`${O.local} local, ${O.cloud} cloud — ${O.localOnly} local-only, ${O.cloudOnly} cloud-only, ${O.differing} differing`]])].join(`
143
- `)}var Pc=new Set(["https:","http:","ssh:","git:"]);function ko(j,P){if(!j.trim())return null;let R=P.replace(/^\/+/,"").replace(/\/+$/,"").replace(/\.git$/i,"").split("/").filter(Boolean);if(R.length!==2)return null;let[O,_]=R;return{host:j.toLowerCase(),owner:O,name:_}}function jo(j){let P=j.trim();if(!P)return null;if(!/^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(P)){let R=/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/.exec(P);return R?ko(R[1],R[2]):null}let I;try{I=new URL(P)}catch{return null}if(!Pc.has(I.protocol))return null;return ko(I.hostname,I.pathname)}function Eo(j){return j.host==="github.com"}function $o(j){let P=j.find((I)=>I.name==="origin");if(P)return P;return j.length===1?j[0]:void 0}import{createHash as Cc}from"node:crypto";import{createReadStream as Ic}from"node:fs";import{chmod as wr,copyFile as xc,lstat as Po,mkdir as vr,mkdtemp as Rc,readdir as _c,readlink as Oc,rm as br,symlink as Tc}from"node:fs/promises";import{tmpdir as Ac}from"node:os";import{dirname as Co,join as Ie}from"node:path";import{spawnSync as Tt}from"node:child_process";var At=300000;function Ce(j,P){let I=Tt("git",["-C",j,...P],{encoding:"utf8",timeout:At,maxBuffer:20971520,stdio:["ignore","pipe","pipe"]});if(I.status!==0){let R=I.stderr.trim().split(`
144
- `).at(-1)??"git command failed";throw Error(R)}return I.stdout.trim()}async function Io(j){let P=Cc("sha256");for await(let I of Ic(j))P.update(I);return P.digest("hex")}async function Nc(j){for(let P of await _c(j)){if(P===".git")continue;await br(Ie(j,P),{recursive:!0,force:!0})}}async function ln(j){if(j.blocking.length>0)throw Error(`Project scan has blocking findings:
145
- - ${j.blocking.join(`
146
- - `)}`);let P=await Rc(Ie(Ac(),"hlix-snapshot-"));await wr(P,448);let I=Ie(P,"repo"),R=Ie(P,"source.git"),O=Ie(P,"project.bundle");try{if(j.manifest.git.detected){let L=Tt("git",["clone","--mirror","--no-hardlinks",j.root,R],{encoding:"utf8",timeout:At,stdio:["ignore","pipe","pipe"]});if(L.status!==0)throw Error(L.stderr.trim()||"Could not mirror repository.");let D=new Map(Ce(R,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]).split(`
147
- `).filter(Boolean).map((z)=>z.split("\x00",2)));for(let z of j.manifest.git.refs)if(D.get(z.name)!==z.oid)throw Error(`Git ref changed after scan: ${z.name}`);let K=Tt("git",["clone","--no-hardlinks",R,I],{encoding:"utf8",timeout:At,stdio:["ignore","pipe","pipe"]});if(K.status!==0)throw Error(K.stderr.trim()||"Could not create snapshot clone.");if(!j.manifest.git.head)throw Error("Git repository has no HEAD commit.");Ce(I,["checkout","-B","main",j.manifest.git.head])}else await vr(I,{recursive:!0,mode:448}),Ce(I,["init","-b","main"]);await Nc(I);for(let L of j.manifest.files){let D=Ie(j.root,...L.path.split("/")),K=await Po(D);if(!K.isFile()||K.isSymbolicLink())throw Error(`Source changed after scan: ${L.path}`);if(K.size!==L.size||await Io(D)!==L.sha256)throw Error(`Source changed after scan: ${L.path}`);let z=Ie(I,...L.path.split("/"));await vr(Co(z),{recursive:!0,mode:493}),await xc(D,z),await wr(z,L.executable?493:420)}for(let L of j.manifest.symlinks){let D=Ie(j.root,...L.path.split("/"));if(await Oc(D).catch(()=>null)!==L.target)throw Error(`Source changed after scan: ${L.path}`);let K=Ie(I,...L.path.split("/"));await vr(Co(K),{recursive:!0,mode:493}),await Tc(L.target,K)}Ce(I,["config","user.name","Hlix Import"]),Ce(I,["config","user.email","import@hlix.ai"]),Ce(I,["add","-A"]),Ce(I,["commit","--allow-empty","-m","chore(hlix): import snapshot"]);let _=Ce(I,["rev-parse","HEAD"]),T=j.manifest.git.refs.filter((L)=>L.name!=="refs/heads/main");if(T.length>0){let L=Tt("git",["-C",I,"update-ref","--stdin"],{encoding:"utf8",timeout:At,input:T.map((D)=>`update ${D.name} ${D.oid}`).join(`
148
- `)+`
149
- `,stdio:["pipe","pipe","pipe"]});if(L.status!==0)throw Error(L.stderr.trim()||"Could not recreate the approved Git refs.")}let A=T.map((L)=>L.name),N=Tt("git",["-C",I,"bundle","create",O,"--stdin"],{encoding:"utf8",timeout:At,input:["refs/heads/main",...A].join(`
150
- `)+`
151
- `,stdio:["pipe","pipe","pipe"]});if(N.status!==0)throw Error(N.stderr.trim()||"Could not create the approved Git bundle.");Ce(I,["bundle","verify",O]),await wr(O,384);let F=(await Po(O)).size,H=await Io(O);return{bundlePath:O,bundleSha256:H,bundleSize:F,commitSha:_,dispose:()=>br(P,{recursive:!0,force:!0})}}catch(_){throw await br(P,{recursive:!0,force:!0}),_}}function Nt(j,P){let I=j[P];return typeof I==="string"&&I.trim()?I.trim():void 0}function Kc(j){return[dn(j,".hlix","config.json"),dn(j,".hlix",".gitignore"),dn(j,".hlixignore")].filter((P)=>!Hc(P))}function xo(j,P){for(let I of P)Lc(I,{force:!0});if(P.length===0)return;try{Mc(dn(j,".hlix"))}catch{}}var Jc=44,Ro=(j)=>`${j.padEnd(Jc)}\r`;function Gc(j,P){return Fc("sha256").update(`project-import-v1\x00${j}\x00${P}`).digest("hex")}async function Wc(j,P){let I=$o(P);if(!I)return{kind:"none"};let R=jo(I.url);if(!R)return{kind:"unresolved",remoteName:I.name,remoteUrl:I.url,reason:"could not be parsed as a repository URL"};if(!Eo(R))return{kind:"unresolved",remoteName:I.name,remoteUrl:I.url,reason:`not a GitHub repository (${R.host})`};let _=(await j.projects.list()).find((T)=>(T.repos??[]).some((A)=>A.owner.toLowerCase()===R.owner.toLowerCase()&&A.name.toLowerCase()===R.name.toLowerCase()));if(_)return{kind:"owned",owner:R.owner,name:R.name,projectId:_.id,projectName:_.name};return{kind:"connect",owner:R.owner,name:R.name}}function qc(j){let P=j.manifest.environment.install,I=j.manifest.secretFiles.length+j.manifest.quarantinedResources.length;if(P.length===0&&I===0&&j.manifest.secretKeys.length===0)return null;let R=["Hlix will upload this project and encrypted protected files to your selected workspace."];if(P.length>0)R.push("Detected cloud setup commands:",...P.map((O)=>`- ${O}`));if(j.manifest.secretKeys.length>0)R.push("Project secret keys available to cloud tasks:",...j.manifest.secretKeys.map((O)=>`- ${O}`));if(j.manifest.quarantinedResources.length>0)R.push("Quarantined resources (preserved but not activated):",...j.manifest.quarantinedResources.map((O)=>`- ${O.kind}: ${O.path}`));if(j.manifest.environment.warnings.length>0)R.push("Environment warnings:",...j.manifest.environment.warnings.map((O)=>`- ${O}`));return R.push("Setup runs inside the isolated Coding Workspace and may access project secrets."),R.join(`
152
- `)}var Ft={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> abort-on-findings (default) or preserve"," --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(`
153
- `),supportsJson:!0,options:["attach","dry-run","env-file","history","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 Dc(Bc(j.cwd,j.args[0]??".")),I=r({env:j.env,flags:j.flags,cwd:P});if(I.conflict)throw new e("workspace_mismatch",I.conflict);if(!I.workspaceId||!I.credential)throw new e("workspace_required","No workspace selected. Run `hlix auth login` first.");let R=Je(P);if(R?.projectId)throw new e("already_imported","This folder is already bound to an Hlix project. Use `hlix push`.");let O=Nt(j.flags,"history");if(O&&O!=="preserve"&&O!=="abort-on-findings")throw Error("--history must be `abort-on-findings` or `preserve`.");let _=[];if(!R&&j.flags["dry-run"]!==!0)_=Kc(P),Ge(P,{schemaVersion:1,workspaceId:I.workspaceId,apiUrl:I.baseUrl});try{return await Vc(j,{root:P,workspaceId:I.workspaceId,apiUrl:I.baseUrl,historyFlag:O})}catch(T){if(j.signal?.aborted)throw xo(P,_),new e("cancelled","Import cancelled.");if(T instanceof e&&T.code==="cancelled")xo(P,_);throw T}}};async function Vc(j,P){let{root:I,historyFlag:R}=P,O=j.json?void 0:(F)=>j.stderr(Ro(F)),_=await Se(I,{...Nt(j.flags,"env-file")?{envFile:Nt(j.flags,"env-file")}:{},environment:j.env,historyMode:R==="preserve"?"preserve":"abort_on_findings",...O?{onProgress:O}:{},...j.signal?{signal:j.signal}:{}});if(O)j.stderr(`
154
- `);if(j.signal?.throwIfAborted(),j.flags["dry-run"]!==!0&&_.blocking.length===0){let F=qc(_);if(F&&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(F))throw new e("cancelled","Import cancelled.")}}let T={kind:"none"};if(j.flags["dry-run"]!==!0&&_.blocking.length===0&&j.flags["no-connect-origin"]!==!0){if(T=await Wc(j.requireClient(I),_.gitRemotes),T.kind==="owned"){let F=j.flags.attach===!0;if(!F&&!j.json&&j.flags.yes!==!0&&j.confirm){let H=[`Repository ${T.owner}/${T.name} is already attached to project "${T.projectName}" in this workspace.`,"This folder looks like a worktree or branch of that project.",`Attach this folder's work to "${T.projectName}" instead of creating a new project?`].join(`
155
- `);if(F=await j.confirm(H),!F)j.stderr(`Continuing as a new, repo-less import.
156
- `)}else if(!F&&!j.json)j.stderr(`Repository ${T.owner}/${T.name} belongs to project "${T.projectName}"; rerun with --attach to bind this folder to it.
157
- `);if(F){Ge(I,{schemaVersion:1,projectId:T.projectId,workspaceId:P.workspaceId,apiUrl:P.apiUrl});let H={root:I,projectId:T.projectId,projectName:T.projectName};if(j.json)j.stdout(q(V(Ft.name,H)));else j.stdout(`Attached ${I}
158
- Project: ${T.projectName} (${T.projectId})
159
- Run \`hlix pull\` to sync this folder.
160
- `);return 0}}else if(T.kind==="connect"){if(!j.json)j.stderr(`Origin repository ${T.owner}/${T.name} detected — connecting it to this project.
161
- `)}else if(T.kind==="unresolved"&&!j.json)j.stderr(`Origin remote '${T.remoteName}' (${T.remoteUrl}) was not connected: ${T.reason}.
162
- `)}let A={root:I,name:Nt(j.flags,"name")??zc(I),stack:Nt(j.flags,"stack")??_.manifest.stack,files:_.manifest.totals.files,bytes:_.manifest.totals.bytes,symlinks:_.manifest.symlinks,activeEnvFiles:_.manifest.activeEnvFiles,secretKeys:_.manifest.secretKeys,protectedFiles:_.manifest.secretFiles.length+_.manifest.quarantinedResources.length,environment:_.manifest.environment,historicalSecretFindings:_.manifest.historicalSecretFindings,quarantinedResources:_.manifest.quarantinedResources,mcpServers:_.manifest.mcpServers,skipped:_.manifest.skipped,blocking:_.blocking,manifestSha256:_.manifestSha256};if(j.flags["dry-run"]===!0){if(j.json)j.stdout(q(V(Ft.name,A)));else{let F=[..._.manifest.secretFiles.map((H)=>`${H.kind}: ${H.path}`),..._.manifest.quarantinedResources.map((H)=>`${H.kind}: ${H.path}`)];j.stdout([`Project: ${A.name}`,`Stack: ${A.stack}`,`Files: ${A.files}`,`Bytes: ${A.bytes}`,`Environment confidence: ${A.environment.confidence}`,`History findings: ${A.historicalSecretFindings.length}`,"","Environment evidence:",...A.environment.sources.length?A.environment.sources.map((H)=>`- ${H.kind}: ${H.path}`):["- none detected"],"","Cloud setup commands:",...A.environment.install.length?A.environment.install.map((H)=>`- ${H}`):["- none detected"],"","Required secret keys:",...A.environment.requiredSecretKeys.length?A.environment.requiredSecretKeys.map((H)=>`- ${H}`):["- none detected"],"","Collected secret keys:",...A.secretKeys.length?A.secretKeys.map((H)=>`- ${H}`):["- none detected"],"","Protected and quarantined paths:",...F.length?F.map((H)=>`- ${H}`):["- none"],"","Environment warnings:",...A.environment.warnings.length?A.environment.warnings.map((H)=>`- ${H}`):["- none"],"","Symlinks (stored as links, targets never read):",...A.symlinks.length?A.symlinks.map((H)=>`- ${H.path} -> ${H.target}`):["- none"],"","Skipped paths:",...A.skipped.length?A.skipped.map((H)=>`- ${H.reason}: ${H.path}`):["- none"],...A.blocking.length?["","Blocking findings:",...A.blocking.map((H)=>`- ${H}`)]:[]].join(`
163
- `)+`
164
- `)}return _.blocking.length?1:0}if(_.blocking.length)throw new e("scan_blocked",`Project scan blocked import:
165
- - ${_.blocking.join(`
166
- - `)}`,{findings:_.blockingHistoryFindings,fixtureFindings:_.manifest.historicalSecretFindings.length-_.blockingHistoryFindings.length,blocking:_.blocking.filter((F)=>!F.startsWith(dr))});j.signal?.throwIfAborted();let N=await ln(_);try{j.signal?.throwIfAborted();let F=j.requireClient(I),H=await F.imports.create({idempotencyKey:Gc(_.manifestSha256,N.bundleSha256),name:A.name,stack:A.stack,defaultBranch:"main",historyMode:_.manifest.git.historyMode,manifest:_.manifest,manifestSha256:_.manifestSha256,bundleSha256:N.bundleSha256,bundleSize:N.bundleSize,commitSha:N.commitSha});if(H.import.status==="pending_upload"){if(!H.upload)throw Error(`Import ${H.import.id} is ${H.import.status} but has no upload target.`);await F.imports.uploadBundle(H.upload,new Blob([Uint8Array.from(await Uc(N.bundlePath))]),{onProgress:(M,U)=>{if(!j.json)j.stderr(Ro(`uploading ${M}/${U} bytes`))}})}let D=(H.import.status==="ready"?{import:H.import}:await F.imports.finalize(H.import.id,{secrets:_.secretValues,protectedFiles:_.protectedFiles})).import,K=D.projectId??D.requestedProjectId;if(!K||!D.revisionId||!D.generation)throw Error("Import completed without project revision metadata.");if(j.signal?.throwIfAborted(),T.kind==="connect")try{await F.projects.connectRepo(K,{owner:T.owner,name:T.name})}catch(M){if(!j.json){let U=M instanceof Error?M.message:String(M);j.stderr(`Origin repository ${T.owner}/${T.name} could not be connected: ${U}
167
- `)}}Ge(I,{schemaVersion:1,projectId:K,workspaceId:P.workspaceId,apiUrl:P.apiUrl}),Fe(I,{schemaVersion:1,revisionId:D.revisionId,generation:D.generation,commitSha:N.commitSha,manifestSha256:_.manifestSha256,historyMode:_.manifest.git.historyMode,rootName:_.manifest.rootName,files:Object.fromEntries(he(_.manifest))});let z={projectId:K,revisionId:D.revisionId,generation:D.generation,commitSha:N.commitSha,files:_.manifest.totals.files,bytes:_.manifest.totals.bytes};if(j.json)j.stdout(q(V(Ft.name,z)));else j.stderr(`
168
- `),j.stdout(`Imported ${A.name}
169
- Project ID: ${K}
170
- Revision: ${D.generation}
171
- `);return 0}finally{await N.dispose()}}import{spawnSync as Xc}from"node:child_process";import{existsSync as Yc,mkdirSync as Zc,writeFileSync as Qc}from"node:fs";import{dirname as el}from"node:path";function tl(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(`
172
- `):["# 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(`
173
- `)}function nl(j){return j.VISUAL?.trim()||j.EDITOR?.trim()||"vi"}var Sr={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 (${p.join(", then ")}).`].join(`
174
- `),supportsJson:!0,options:["edit","global"],async run(j){let P=m({cwd:j.cwd,configDir:".hlix",env:j.env}),I=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 R=I?Gn(j.env):Jn(j.cwd,".hlix")?.path??`${j.cwd}/AGENTS.md`;if(!Yc(R))Zc(el(R),{recursive:!0}),Qc(R,tl(I?"global":"project"),"utf8"),j.stdout(`Created ${R}.
175
- `);let O=nl(j.env),_=Xc(O,[R],{stdio:"inherit"});if(_.error)throw new e("invalid_usage",`Could not run ${O}: ${_.error.message}`);return _.status??0}if(j.json){let R=(O)=>O?{path:O.path,characters:O.content.length}:null;return j.stdout(q(V(Sr.name,{user:R(P.global),project:R(P.project)}))),0}return j.stdout(`${g(P,j.cwd)}
176
- `),0}};var kr={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(`
177
- `),supportsJson:!0,async run(j){let P=f(j.cwd,c(j.env),{env:j.env});if(j.json)return j.stdout(q(V(kr.name,{instructions:P.instructions.map((I)=>({path:I.path,source:I.source,scope:I.scope,characters:I.content.length,...I.note?{note:I.note}:{}})),skills:P.skills,commands:[...P.commands.map((I)=>({path:I.path,source:I.source,scope:I.scope})),...P.generatedCommands.map((I)=>({path:I.path,source:I.source,scope:I.scope,command:I.name}))],mcpServers:P.mcpServers.map((I)=>({path:I.path,source:I.source,scope:I.scope,name:I.name,transport:"command"in I.config?"stdio":"http"})),subagents:P.subagents.map((I)=>({path:I.path,source:I.source,scope:I.scope,name:I.name,description:I.description,...I.model?{model:I.model}:{}})),skipped:P.skipped}))),0;return j.stdout(Js(P,j.cwd)),0}};var Oo=(j)=>j instanceof Error?j.message:String(j),_o=(j)=>j.split(/\s*\n\s*/).join(" ").trim();async function rl(j,P,I,R,O){try{let _=await Se(P,{historyMode:I,environment:j.env,rootName:R});return{files:_.manifest.totals.files,manifestSha256:_.manifestSha256,changed:O?_.manifestSha256!==O:null,blocking:_.blocking,error:null}}catch(_){return{files:null,manifestSha256:null,changed:null,blocking:[],error:Oo(_)}}}var jr={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(`
178
- `),supportsJson:!0,async run(j){let P=r({env:j.env,flags:j.flags,cwd:j.cwd}),I=P.binding,R=I?Te(I.root):null,O=I?await rl(j,I.root,R?.historyMode??"preserve",R?.rootName,R?.manifestSha256):null,_=null;if(I?.config.projectId&&P.credential&&!P.conflict)try{let N=(await j.requireClient().revisions.head(I.config.projectId)).revision;_={revisionId:N.id,generation:N.generation,changed:R?N.id!==R.revisionId||N.generation!==R.generation:null,error:null,errorMessage:null}}catch(N){_={revisionId:"",generation:0,changed:null,error:Mn(N).code,errorMessage:N instanceof $e?"no cloud revision yet — `hlix push` uploads this folder as revision 1":Oo(N)}}let T={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:I?{root:I.root,projectId:I.config.projectId??null,workspaceId:I.config.workspaceId,apiUrl:I.config.apiUrl}:null,revision:R?{id:R.revisionId,generation:R.generation,commitSha:R.commitSha}:null,local:O,cloud:_};if(j.json)return j.stdout(q(V(jr.name,T))),0;let A=[["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",Yt(P)??"none — run `hlix auth login`"],["project",I?I.config.projectId??`initialized at ${I.root}, not imported yet`:"none — run `hlix import .` to bind this folder"]];if(R)A.push(["revision",`generation ${R.generation} (${R.revisionId})`]);if(O){if(A.push(["local",O.error?`could not scan: ${O.error}`:O.changed===null?`${O.files} files, no synced base revision`:O.changed?`${O.files} files, modified since the last sync`:`${O.files} files, matches the last sync`]),O.blocking.length>0)A.push(["blocking",O.blocking.join("; ")])}if(_)A.push(["cloud",_.error==="not_found"?_o(_.errorMessage??_.error):_.error?`not checked — ${_o(_.errorMessage??_.error)}`:_.changed?`generation ${_.generation} available — run \`hlix pull\``:`generation ${_.generation}, up to date`]);if(P.conflict)A.push(["conflict",P.conflict]);return j.stdout(`${ce(A)}
179
- `),0}};import{spawnSync as To}from"node:child_process";var Er={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(`
180
- `),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 I=await j.requireClient().projects.terminal(P);if(j.json)return j.stdout(q(V(Er.name,I))),I.available?0:1;if(!I.available){let T=I.environmentState?` (environment: ${I.environmentState})`:"";throw new e("not_found",`${I.reason??"Terminal unavailable"}${T}`)}let R=j.flags.print===!0,O=j.flags.web===!0;if(R||O&&!I.webTerminalUrl||!O&&!I.sshCommand)return j.stdout(`${ce([["ssh",I.sshCommand??"not available"],["browser",I.webTerminalUrl??"not available"]])}
181
- `),0;if(O){if(To(process.platform==="darwin"?"open":"xdg-open",[I.webTerminalUrl],{stdio:"ignore"}).status!==0)j.stdout(`${I.webTerminalUrl}
182
- `);return 0}return To("sh",["-c",I.sshCommand],{stdio:"inherit"}).status??1}};import{createHash as Ao}from"node:crypto";import{readFile as sl,realpath as ol}from"node:fs/promises";function il(j,P,I){return Ao("sha256").update(`project-push-v1\x00${j}\x00${P}\x00${I}`).digest("hex")}var al={schemaVersion:1,revisionId:"",generation:0,commitSha:""},Ht={id:"",generation:0,commitSha:"",manifest:{}};async function st(j,P){try{return await j.revisions.head(P)}catch(I){if(I instanceof $e)return null;throw I}}async function No(j,P){let I=await st(j,P);if(I)return I;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 ke(j,{allowUnsynced:P=!1}={}){let I=t(j);if(!I?.config.projectId)throw new e("not_initialized","This folder is not bound to an imported Hlix project. Run `hlix import .` first.");let R=Te(I.root)??(P?al:null);if(!R)throw new e("not_initialized","This folder is bound to a project but has never been pulled. Run `hlix pull` first.");return{root:await ol(I.root),config:I.config,state:R}}async function xe(j,P,I,R){let O=await Se(j,{historyMode:I,environment:P,rootName:R});if(O.blocking.length>0)throw new e("scan_blocked",`Project scan blocked sync:
183
- - ${O.blocking.join(`
184
- - `)}`);return O}async function $r(j,P,I,R){let{state:O,config:_}=await ke(R,{allowUnsynced:!0}),T=j.requireClient(),[A,N]=await Promise.all([xe(R,j.env,O.historyMode??"preserve",O.rootName),I==="pull"?No(T,_.projectId):st(T,_.projectId)]),F=rt(A,O,N?.revision??Ht),H=hr(I,F,j.flags.force===!0),L=yr(H,F,j.flags.yes===!0);if(j.json)j.stdout(q(V(P,{dryRun:!0,action:H,approvalRequired:L,...F})));else j.stdout(`${So(I,H,F,L)}
185
- `);return H==="conflict"?1:0}async function cl(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 I=[`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(`
186
- `);if(!await j.confirm(I))throw new e("cancelled","Pull cancelled.")}function ll(j,P){let I=P??{},R={...j.manifest,secretFiles:I.secretFiles??[],activeEnvFiles:I.activeEnvFiles??[],secretKeys:I.secretKeys??[],envCollisions:I.envCollisions??[],quarantinedResources:I.quarantinedResources??[],mcpServers:I.mcpServers??[]};return{manifest:R,manifestSha256:Ao("sha256").update(_t(R)).digest("hex")}}async function fn(j,P,I,R,{inheritProtected:O=!1}={}){let{state:_,config:T}=await ke(j,{allowUnsynced:!0}),A=P.requireClient(),N=_.historyMode??"preserve",F=I??await xe(j,P.env,N,_.rootName),H=R??(await st(A,T.projectId))?.revision??Ht;if(H.id!==_.revisionId||H.generation!==_.generation)throw new e("conflict","Cloud changed since the local base. Run `hlix pull` or resolve with `hlix sync`.");if(_.manifestSha256&&F.manifestSha256===_.manifestSha256)return{action:"none",revisionId:_.revisionId,generation:_.generation};let L=O?ll(F,H.manifest):{manifest:F.manifest,manifestSha256:F.manifestSha256},D=await ln(F);try{let K=await A.revisions.createUpload(T.projectId,{idempotencyKey:il(_.revisionId,L.manifestSha256,D.bundleSha256),expectedRevisionId:_.revisionId||null,expectedGeneration:_.generation,manifest:L.manifest,manifestSha256:L.manifestSha256,bundleSha256:D.bundleSha256,bundleSize:D.bundleSize,commitSha:D.commitSha});if(K.revisionUpload.status==="pending_upload"){if(!K.upload)throw Error("Revision upload has no bundle target.");await A.revisions.uploadBundle(K.upload,new Blob([Uint8Array.from(await sl(D.bundlePath))]),{onProgress:(M,U)=>{if(!P.json)P.stderr(`Uploading ${M}/${U} bytes\r`)}})}let z=await A.revisions.finalize(T.projectId,K.revisionUpload.id,O?{secrets:{},protectedFiles:[],inheritProtected:!0}:{secrets:F.secretValues,protectedFiles:F.protectedFiles});if(!z.revision)throw Error("Revision finalized without head metadata.");return Fe(j,{schemaVersion:1,revisionId:z.revision.id,generation:z.revision.generation,commitSha:z.revision.commitSha,manifestSha256:O?F.manifestSha256:z.revision.manifestSha256,historyMode:N,rootName:_.rootName??F.manifest.rootName,files:Object.fromEntries(he(F.manifest))}),{action:"push",...z.revision}}finally{await D.dispose()}}async function Fo(j,P,I,R,O){let{state:_,config:T}=await ke(j,{allowUnsynced:!0}),A=P.requireClient(),N=_.historyMode??"preserve",F=R??await xe(j,P.env,N,_.rootName),H=O??(await No(A,T.projectId)).revision;if(H.id===_.revisionId&&H.generation===_.generation)return{action:"none",revisionId:_.revisionId,generation:_.generation};let L=_.manifestSha256?F.manifestSha256!==_.manifestSha256:(()=>{let{files:J}=rt(F,_,H);return J.localOnly+J.differing>0})();if(L&&!I)throw new e("conflict","Local files changed since the last sync. Push them, or use `hlix pull --force` to replace them.");if(L)await cl(P,rt(F,_,H));let[D,K]=await Promise.all([A.revisions.downloadBundle(T.projectId,H.id),A.revisions.protectedFiles(T.projectId)]);await cn(j,F,H,D,K);let z=an(H.manifest),M=z.historyMode??N,U=z.rootName??_.rootName??F.manifest.rootName,B=await xe(j,P.env,M,U);return Fe(j,{schemaVersion:1,revisionId:H.id,generation:H.generation,commitSha:H.commitSha,manifestSha256:B.manifestSha256,historyMode:M,rootName:U,files:Object.fromEntries(he(B.manifest))}),{action:"pull",revisionId:H.id,generation:H.generation,commitSha:H.commitSha}}function Pr(j,P,I){if(j.json)j.stdout(q(V(P,I)));else if("action"in I&&I.action==="none")j.stdout(`Already in sync.
187
- `);else j.stdout(`${String("action"in I?I.action:"sync")} complete.
188
- `)}var un={name:"push",summary:"Push local changes as an immutable cloud revision",usage:["Usage: hlix push [--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(`
189
- `),supportsJson:!0,options:["dry-run"],async run(j){if(j.args.length)throw Error("push accepts no positional arguments.");let{root:P}=await ke(j.cwd,{allowUnsynced:!0});if(j.flags["dry-run"]===!0)return $r(j,un.name,"push",P);return Pr(j,un.name,await fn(P,j)),0}},pn={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(`
190
- `),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 ke(j.cwd,{allowUnsynced:!0});if(j.flags["dry-run"]===!0)return $r(j,pn.name,"pull",P);return Pr(j,pn.name,await Fo(P,j,j.flags.force===!0)),0}},mn={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:I,config:R}=await ke(j.cwd,{allowUnsynced:!0});if(j.flags["dry-run"]===!0)return $r(j,mn.name,"sync",P);let O=j.requireClient(),[_,T]=await Promise.all([xe(P,j.env,I.historyMode??"preserve",I.rootName),st(O,R.projectId)]),A=T?.revision??Ht,N=rt(_,I,A);if(N.localChanged&&N.cloudChanged)throw new e("conflict","Both local and cloud changed since the last sync. Pull or push explicitly after reviewing the conflict.");let F=N.localChanged?await fn(P,j,_,A):N.cloudChanged?await Fo(P,j,!1,_,T?.revision):{action:"none",revisionId:I.revisionId,generation:I.generation};return Pr(j,mn.name,F),0}};import{lstat as dl,readFile as ul,readlink as pl,rm as Ho,symlink as ml,writeFile as fl,chmod as gl}from"node:fs/promises";import{watch as hl}from"node:fs";function h(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 yl(j,P){let I=new Map;for(let R of P){let O=`${j}/${R}`;try{let _=await dl(O);if(_.isSymbolicLink())I.set(R,{kind:"link",target:await pl(O)});else if(_.isFile())I.set(R,{kind:"file",bytes:await ul(O),mode:_.mode&511})}catch(_){if(_.code!=="ENOENT")throw _}}return I}async function Cr(j,P,I){let R=await nt(j,P);if(await Ho(R,{force:!0}),I.kind==="link"){await ml(I.target,R);return}await fl(R,I.bytes,{mode:I.mode}),await gl(R,I.mode)}var wl=(j)=>j.toISOString().replace(/\.\d+Z$/,"Z").replace(/[-:]/g,"");async function vl(j,P,I,R,O,_){let T=new Map(Object.entries(O.files??{})),A=he(R.manifest),N=he(_.manifest),F=[],H=[],L=[];for(let re of new Set([...A.keys(),...N.keys()])){let G=A.get(re),te=N.get(re),Z=T.get(re);if(G===te||G===Z)continue;if(te===Z){if(G===void 0)H.push(re);else F.push(re);continue}if(G!==void 0)L.push(re)}let D=[...R.manifest.secretFiles,...R.manifest.quarantinedResources].map((re)=>re.path),K=await yl(j,[...F,...L,...D]),z=await P.client.revisions.downloadBundle(I,_.id);await cn(j,R,_,z,null);for(let re of D){let G=K.get(re);if(G)await Cr(j,re,G)}let M=an(_.manifest),U=M.historyMode??O.historyMode??"preserve",B=M.rootName??O.rootName??R.manifest.rootName,J=await xe(j,P.env,U,B);Fe(j,{schemaVersion:1,revisionId:_.id,generation:_.generation,commitSha:_.commitSha,manifestSha256:J.manifestSha256,historyMode:U,rootName:B,files:Object.fromEntries(he(J.manifest))});for(let re of F){let G=K.get(re);if(G)await Cr(j,re,G)}for(let re of H)await Ho(`${j}/${re}`,{force:!0});let ne=`.local-${wl((P.now??(()=>new Date))())}`,ae=[];for(let re of L){let G=K.get(re);if(!G)continue;await Cr(j,`${re}${ne}`,G),ae.push({path:re,savedAs:`${re}${ne}`})}return ae}function bl(j,P){if(!P)return!1;if(!P.files)return P.manifestSha256===j.manifestSha256;let I=Object.entries(P.files),R=he(j.manifest);return I.length===R.size&&I.every(([O,_])=>R.get(O)===_)}var Sl=(j)=>({requireClient:()=>j.client,env:j.env??{},json:!0,stderr:()=>{}});async function Ir(j,P,{cloud:I}){let{config:R,state:O}=await ke(j,{allowUnsynced:!0}),_=R.projectId,T={conflicts:[]},A=await xe(j,P.env,O.historyMode??"preserve",O.rootName),N;if(I){let F=(await st(P.client,_))?.revision;if(F&&(F.id!==O.revisionId||F.generation!==O.generation))T.conflicts=await vl(j,P,_,A,O,F),T.pulled=F.generation,A=await xe(j,P.env,O.historyMode??"preserve",O.rootName);N=F??Ht}if(bl(A,Te(j)))return T;try{let F=await fn(j,Sl(P),A,N,{inheritProtected:!0});if(F.action==="push")T.pushed=F.generation;return T}catch(F){if(!I&&F instanceof e&&F.code==="conflict")return Ir(j,P,{cloud:!0});throw F}}function kl(j){if(!j)return!1;let P=j.split("\\").join("/");return/^(\.git|\.hlix|node_modules)(\/|$)/.test(P)||/\/(\.git|node_modules)(\/|$)/.test(P)}var jl=300;async function v(j,P,I){let{config:R}=await ke(j,{allowUnsynced:!0}),O=I.signal,_=!1,T=!1,A=null,N=!1,F=async()=>{while(_||T){if(await jt(jl,O),O?.aborted)return;let D=_;_=!1,T=!1;try{let K=await Ir(j,P,{cloud:D});if(K.pulled!==void 0||K.pushed!==void 0||K.conflicts.length>0)I.onReport(K);if(D&&!N)N=!0,I.onCaughtUp?.()}catch(K){I.onError(K)}}},H=()=>{if(A||O?.aborted)return;A=F().finally(()=>{if(A=null,_||T)H()})},L=hl(j,{recursive:!0,...O?{signal:O}:{}},(D,K)=>{if(kl(typeof K==="string"?K:null))return;T=!0,H()});L.on("error",I.onError);try{for await(let D of P.client.revisions.watch(R.projectId,O?{signal:O}:{})){if(D.kind==="head"&&D.generation===Te(j)?.generation)continue;_=!0,H()}}finally{L.close(),await A}}function El(j,P){if(j.json)j.stdout(`${JSON.stringify(V(Lt.name,P))}
191
- `);else for(let I of h(P))j.stdout(`${I}
192
- `)}var Lt={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(`
193
- `),supportsJson:!0,options:["once"],agentTool:!1,async run(j){if(j.args.length)throw Error("mirror accepts no positional arguments.");let{root:P,config:I}=await ke(j.cwd,{allowUnsynced:!0}),R={client:j.requireClient(),env:j.env};if(j.flags.once===!0){let O=await Ir(P,R,{cloud:!0});if(j.json)j.stdout(q(V(Lt.name,O)));else{let _=h(O);j.stdout(_.length?`${_.join(`
194
- `)}
195
- `:`Already in sync.
196
- `)}return 0}if(!j.json)j.stdout(`Mirroring ${P} with project ${I.projectId}. Ctrl-C stops.
197
- `);return await v(P,R,{...j.signal?{signal:j.signal}:{},onCaughtUp:()=>{let O=Te(P)?.generation??0;if(j.json)j.stdout(`${JSON.stringify(V(Lt.name,{caughtUp:!0,generation:O}))}
198
- `);else j.stdout(`Caught up at revision ${O}; following the cloud.
199
- `)},onReport:(O)=>El(j,O),onError:(O)=>j.stderr(`mirror: ${O instanceof Error?O.message:String(O)}
200
- `)}),0}};import{lstat as Rr,readFile as $l,realpath as Pl}from"node:fs/promises";import{basename as xr,dirname as Cl,extname as Il,join as gn,parse as Lo,resolve as hn}from"node:path";function ot(j,P){let I=j.flags[P];return typeof I==="string"&&I.trim()?I.trim():void 0}function _r(j){let P=ot(j,"project");if(P)return{root:j.cwd,projectId:P};return xl(j.cwd)}function xl(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 Or(j,P){let I=await Rr(j);if(I.isSymbolicLink()||!I.isFile())throw Error(`Refusing to import a non-regular file: ${j}`);if(I.size>P)throw Error(`Import file exceeds ${P} bytes: ${j}`);return{path:await Pl(j),content:await $l(j,"utf8")}}function Tr(j,P,I,R){if(j.json)j.stdout(q(V(P,I)));else j.stdout(`${R}
201
- `)}function Rl(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 _l=[gn(".claude","skills"),gn(".agents","skills"),gn(".hlix","skills")];async function Ol(j,P){let I=[hn(j,P),..._l.map((R)=>hn(j,R,P))];for(let R of I)if(await Rr(R).then(()=>!0,()=>!1))return R;throw new e("not_found",`No skill at ${P}. Pass the SKILL.md or its folder, for example .claude/skills/${P}.`)}var Ar={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=_r(j),I=await Ol(j.cwd,j.args[0]),R=await Rr(I);if(R.isSymbolicLink())throw Error(`Refusing to import a symlink: ${I}`);let O=R.isDirectory()?gn(I,"SKILL.md"):I,_=await Or(O,200000),T=R.isDirectory()?xr(I):xr(O)==="SKILL.md"?xr(Cl(O)):Lo(O).name,A=ot(j,"name")??T;if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(A))throw Error("Skill name must be a lowercase kebab-case slug.");let N=await j.requireClient().resources.importSkill(P.projectId,{slug:A,content:_.content});return Tr(j,Ar.name,N.skill,`Imported skill ${A}`),0}},Nr={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=_r(j),I=hn(j.cwd,j.args[0]);if(![".md",".mdx"].includes(Il(I).toLowerCase()))throw Error("Agent imports must be Markdown files.");let R=await Or(I,20000),O=ot(j,"runtime")??"hlix";if(!["claude-code","codex","cursor-agent","hlix"].includes(O))throw Error("--runtime must be claude-code, codex, cursor-agent, or hlix.");let _=ot(j,"duty")??"executor";if(_!=="executor"&&_!=="intake")throw Error("--duty must be executor or intake.");let T=ot(j,"name")??Rl(R.content)??Lo(I).name.replace(/[-_]+/g," "),A=await j.requireClient().resources.importAgent(P.projectId,{name:T,instructions:R.content,runtimeKind:O,duty:_});return Tr(j,Nr.name,A.agent,A.agent.duty==="intake"?`Imported agent ${A.agent.name} as this project's intake agent`:`Imported agent ${A.agent.name}`),0}},Fr={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=_r(j),I=await Or(hn(j.cwd,j.args[0]),200000),R;try{R=JSON.parse(I.content)}catch{throw Error("MCP config is not valid JSON.")}let O=Object.entries(R.mcpServers??{});if(O.length===0)throw Error("MCP config contains no servers.");let _=ot(j,"server");if(!_&&O.length>1)throw Error("MCP config contains multiple servers; select one with --server <name>.");let T=_?O.find(([M])=>M===_):O[0];if(!T)throw Error(`MCP server not found: ${_}`);let[A,N]=T,F=N.type==="http"||N.type==="sse"?N.type:typeof N.command==="string"?"stdio":typeof N.url==="string"?"http":null;if(!F)throw Error(`MCP server ${A} has no supported transport.`);if(F==="stdio"&&j.flags["allow-stdio"]!==!0)throw Error("Stdio MCP servers execute a local command in the cloud; repeat with --allow-stdio.");let H=N.env&&typeof N.env==="object"&&!Array.isArray(N.env)?N.env:{},L=N.headers&&typeof N.headers==="object"&&!Array.isArray(N.headers)?N.headers:{};if(Object.values(L).some((M)=>typeof M!=="string"))throw Error(`MCP server ${A} headers must be strings.`);for(let[M,U]of Object.entries(H)){if(typeof U!=="string")continue;let B=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(U)?.[1];if(B&&B!==M)throw new e("invalid_usage",`MCP server ${A}: env ${M} references \${${B}}, but a placeholder must be the variable's own name — write "${M}": "\${${M}}" and store the secret as ${M}.`)}let D=Object.values(L).flatMap((M)=>[...M.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)].map((U)=>U[1]));if(Object.keys(L).length>0&&D.length===0)throw Error("MCP remote headers must use ${KEY} placeholders; literal credentials are refused.");let K=/^(?:(?:Bearer|Basic|Token) )?\$\{[A-Za-z_][A-Za-z0-9_]*\}$/i;if(Object.values(L).some((M)=>!K.test(M)))throw Error("MCP remote headers must be ${KEY} or an approved auth scheme followed by ${KEY}.");let z=await j.requireClient().resources.importMcp(P.projectId,{name:A,transport:F,...typeof N.command==="string"?{command:N.command}:{},...Array.isArray(N.args)&&N.args.every((M)=>typeof M==="string")?{args:N.args}:{},...typeof N.url==="string"?{url:N.url}:{},...Object.keys(L).length>0?{headers:L}:{},envKeys:[...new Set([...Object.keys(H),...D])].sort()});return Tr(j,Fr.name,z.mcpServer,`Imported MCP server ${A}`),0}};import{spawnSync as Tl}from"node:child_process";import{chmod as Al,realpath as Nl,writeFile as Fl}from"node:fs/promises";import{basename as Hl,dirname as Ll,relative as Ml,resolve as Uo,sep as Ul}from"node:path";var Mo=64;function Ut(j){let P=t(j.cwd),R=(typeof j.flags.project==="string"?j.flags.project:void 0)??P?.config.projectId;if(!R)throw new e("not_initialized","This folder is not bound to a Hlix project. Run `hlix import .`, or pass --project <id>.");return{projectId:R,root:P?.root??j.cwd}}var Mt=(j,P)=>typeof j[P]==="string"?j[P]:void 0,Hr={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(`
202
- `),supportsJson:!0,options:["project"],async run(j){let{projectId:P}=Ut(j),I=await j.requireClient().secrets.listEntries(P);if(j.json)return j.stdout(q(V(Hr.name,I))),0;if(I.entries.length===0)j.stdout(`No secrets stored for this project.
203
- `);else j.stdout(`${Ee(["key","source","format","value","updated"],I.entries.map((R)=>[R.key,R.source,R.format||"-",R.maskedValue,R.updatedAt?.slice(0,10)??"-"]))}
204
- `);for(let R of I.warnings)j.stderr(`warning: ${R}
205
- `);return 0}},Lr={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(`
206
- `),supportsJson:!0,options:["from-stdin","source","project"],args:{min:1,max:2},async run(j){let{projectId:P}=Ut(j),I=j.args[0],R=j.flags["from-stdin"]===!0;if(R&&j.args.length>1)throw new e("invalid_usage","Pass the value as an argument or with --from-stdin, not both.");if(!R&&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 O;if(R){if(!j.readStdin)throw new e("invalid_usage","--from-stdin is not available in this context.");O=(await j.readStdin()).replace(/\r?\n$/,"")}else O=j.args[1];let _=Mt(j.flags,"source"),T=await j.requireClient().secrets.upsertEntries(P,{entries:[{key:I,value:O,..._?{source:_}:{}}]});if(j.json)return j.stdout(q(V(Lr.name,T))),T.written>0?0:1;if(T.written===0)throw new e("bad_request",`The store refused ${I}: --source must be a project-relative file path.`);return j.stdout(`${ce([["key",I],["source",_??".env"]])}
207
- `),0}},Mr={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(`
208
- `),supportsJson:!0,options:["source","project"],args:{min:1,max:1},async run(j){let{projectId:P}=Ut(j),I=j.args[0],R=Mt(j.flags,"source"),O=await j.requireClient().secrets.deleteEntry(P,I,R);if(j.json)return j.stdout(q(V(Mr.name,O))),O.removed>0?0:1;if(O.removed===0)return j.stderr(`No stored secret named ${I}${R?` in ${R}`:""}.
209
- `),1;return j.stdout(`Removed ${O.removed} entr${O.removed===1?"y":"ies"} for ${I}.
210
- `),0}},yn={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(`
211
- `),supportsJson:!0,options:["project"],args:{min:0,max:64},async run(j){let{projectId:P,root:I}=Ut(j),R=await Se(I,{historyMode:"preserve",environment:j.env}),O=R.blocking.filter((L)=>!L.startsWith(ur));if(O.length>0)throw new e("scan_blocked",`Project scan blocked the import:
212
- - ${O.join(`
213
- - `)}`);let _=R.protectedFiles.filter((L)=>L.kind==="dotenv"||L.kind==="credential"),T=await Nl(j.cwd),A=j.args.map((L)=>Ml(R.root,Uo(T,L)).split(Ul).join("/")),N=A.filter((L)=>!_.some((D)=>D.path===L));if(N.length>0)throw new e("invalid_usage",`Not a secret file in this project: ${N.join(", ")}`);let F=A.length>0?_.filter((L)=>A.includes(L.path)):_;if(F.length===0)return j.stdout(j.json?q(V(yn.name,{imported:[],skipped:[],warnings:[],written:0,rejected:[]})):`No secret files found in this project.
214
- `),0;if(F.length>Mo)throw new e("invalid_usage",`${F.length} secret files exceeds the ${Mo} the store accepts in one request. Name the files to import, a batch at a time.`);let H=await j.requireClient().secrets.importFiles(P,F.map((L)=>({path:L.path,contentBase64:L.contentBase64})));if(j.json)return j.stdout(q(V(yn.name,H))),0;if(H.imported.length>0)j.stdout(`${Ee(["source","format","stored"],H.imported.map((L)=>[L.path,L.format||"-",L.kind==="file"?"as file":`${L.entries} entr${L.entries===1?"y":"ies"}`]))}
215
- `);if(j.stdout(`${H.written} value${H.written===1?"":"s"} stored.
216
- `),H.imported.some((L)=>L.kind!=="file"))j.stdout(`Each imported file replaced what the store held under its path; keys the file no longer has are gone.
217
- `);for(let L of H.skipped)j.stderr(`skipped ${L.path}: ${L.reason}
218
- `);for(let L of H.warnings)j.stderr(`warning: ${L}
219
- `);for(let L of H.rejected)j.stderr(`rejected ${L}: the store refused its source path
220
- `);return 0}};function Dl(j){return Tl("git",["-C",Ll(j),"ls-files","--error-unmatch","--",Hl(j)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).status===0}var Ur={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(`
221
- `),supportsJson:!0,options:["source","format","out","project"],async run(j){let{projectId:P}=Ut(j),I=Mt(j.flags,"source"),R=Mt(j.flags,"format"),O=Mt(j.flags,"out"),_=O===void 0?void 0:Uo(j.cwd,O);if(_!==void 0&&Dl(_))throw new e("invalid_usage",`Refusing to overwrite a git-tracked file with secret values: ${_}`);let T=await j.requireClient().secrets.exportEntries(P,{...I?{source:I}:{},...R?{format:R}:{}});if(_!==void 0)await Fl(_,T,{mode:384}),await Al(_,384);if(j.json)return j.stdout(q(V(Ur.name,{source:I??null,format:R??null,out:_??null,bytes:Buffer.byteLength(T),..._===void 0?{content:T}:{}}))),0;if(_===void 0)j.stdout(T);else j.stdout(`${ce([["wrote",_],["mode","0600"],["bytes",String(Buffer.byteLength(T))]])}
222
- `);return 0}};function zr(j){let P=j.flags.project;if(typeof P==="string"&&P)return P;return t(j.cwd)?.config.projectId??void 0}function Dr(j,P){let I=j[P];if(typeof I!=="string"||I.trim()==="")throw new e("missing_argument",`--${P} is required.`);return I}var Br={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(`
223
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(j){let P=j.args[0],I=Dr(j.flags,"title"),R=Dr(j.flags,"description"),O=await j.requireClient().cycles.propose({projectId:P,title:I,description:R});if(j.json)return j.stdout(q(V(Br.name,O))),0;return j.stdout(`${ce([["project",P],["title",I],["status",O.adopted?"adopted — the project is planning it now":"recorded — it will be planned on the next pass"]])}
224
- `),0}},Kr={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(`
225
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(j){let P=j.args[0],I=Dr(j.flags,"description"),R=typeof j.flags.title==="string"?j.flags.title:void 0,O=await j.requireClient().tasks.create({projectId:P,description:I,...R?{title:R}:{}});if(j.json)return j.stdout(q(V(Kr.name,O))),0;return j.stdout(`${ce([["task",O.id],["project",P],["status",O.status??"queued"],["note","not started — dispatch with `hlix cycles create`"]])}
226
- `),0}},Jr={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(`
227
- `),supportsJson:!0,options:["project"],args:{min:0,max:1},async run(j){let P=j.args[0]??zr(j),I=j.requireClient(),R=P?await I.modelConfig.resolvedProjectHarness(P):await I.modelConfig.resolvedHarness();if(j.json)return j.stdout(q(V(Jr.name,R))),0;return j.stdout(`${ce([["scope",P?`project ${P}`:"workspace"],["harness",R.harness],["source",R.source]])}
228
- `),0}},Gr={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(`
229
- `),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 I=j.flags.org===!0,R=j.args[1]??(I?void 0:zr(j));if(R&&I)throw new e("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!R&&!I)throw new e("invalid_usage","Name the project to set, or pass --org for the whole workspace.");let O=j.requireClient(),_=R?await O.modelConfig.setProjectHarness(R,P):await O.modelConfig.setHarness(P);if(j.json)return j.stdout(q(V(Gr.name,_))),0;return j.stdout(`${ce([["scope",R?`project ${R}`:"workspace"],["harness",P]])}
230
- `),0}},Wr={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(`
231
- `),supportsJson:!0,options:["org"],args:{min:0,max:1},async run(j){let P=j.flags.org===!0,I=j.args[0]??(P?void 0:zr(j));if(I&&P)throw new e("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!I&&!P)throw new e("invalid_usage","Name the project to clear, or pass --org for the whole workspace.");let R=j.requireClient(),O=I?await R.modelConfig.clearProjectHarness(I):await R.modelConfig.clearHarness();if(j.json)return j.stdout(q(V(Wr.name,O))),0;return j.stdout(`${ce([["scope",I?`project ${I}`:"workspace"],["harness","cleared — the scope below decides now"]])}
232
- `),0}};var a=[Wn,qn,et,jr,Er,kr,Sr,Vn,Xn,Yn,mr,Ft,mn,pn,un,Lt,Ar,Nr,Fr,Hr,Lr,Mr,yn,Ur,Zn,Qn,tr,nr,rr,sr,Kr,Br,Jr,Gr,Wr];
233
- export{e,C,t,r,n,s,l,i,o,y,d,w,u,c,b,p,m,S,g,f,x,k,E,h,v,a};