@hlix/cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,8 +33,8 @@ For CI, and for anything else that must not change underneath you, pin the
33
33
  version instead of floating to `latest`:
34
34
 
35
35
  ```bash
36
- npm install --global @hlix/cli@0.3.0
37
- npx @hlix/cli@0.3.0 status --json
36
+ npm install --global @hlix/cli@0.4.0
37
+ npx @hlix/cli@0.4.0 status --json
38
38
  ```
39
39
 
40
40
  ## Authenticate
@@ -85,6 +85,7 @@ result with the source that decided each value.
85
85
  ```bash
86
86
  hlix status [--json]
87
87
  hlix init [folder] [--project <id>] [--json]
88
+ hlix terminal [project-id] [--print] [--web] [--json]
88
89
  hlix import [folder] [--dry-run] [--env-file <path>] [--history preserve] [--yes]
89
90
  hlix push [--dry-run] | hlix pull [--force] [--yes] [--dry-run] | hlix sync [--dry-run]
90
91
  hlix projects list [--json]
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ import{q as Xs}from"./index-syeavftx.js";class h extends Error{code;constructor(e,t){super(t);this.name="CliError",this.code=e}}var la=1,b=(e,t)=>({schemaVersion:1,command:e,data:t}),Ee=(e,t)=>({schemaVersion:1,command:e,error:t});function w(e){return`${JSON.stringify(e,null,2)}
3
+ `}function O(e){let t=Math.max(0,...e.map(([n])=>n.length));return e.map(([n,r])=>`${n.padEnd(t)} ${r}`).join(`
4
+ `)}function X(e,t){let n=e.map((s,o)=>Math.max(s.length,...t.map((i)=>(i[o]??"").length))),r=(s)=>s.map((o,i)=>o.padEnd(n[i])).join(" ").trimEnd();return[r(e),r(n.map((s)=>"-".repeat(s))),...t.map(r)].join(`
5
+ `)}import{statSync as As}from"node:fs";import{dirname as Fs,resolve as Ns}from"node:path";import{closeSync as Pt,constants as Pe,existsSync as rt,fsyncSync as Gn,lstatSync as Ct,mkdirSync as ks,openSync as Wn,readFileSync as Vn,renameSync as js,statSync as Xn,unlinkSync as Zn,writeFileSync as Es}from"node:fs";import{homedir as Ps}from"node:os";import{dirname as Cs,join as $t}from"node:path";function de(e=process.env){let t=e.HLIX_CONFIG_HOME??e.XDG_CONFIG_HOME??$t(Ps(),".config");return $t(t,"hlix","credentials.json")}function Yn(e=process.env){let t=e.HLIX_API_KEY;if(!t&&e.HLIX_SESSION_TOKEN)return{baseUrl:e.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:"",sessionToken:e.HLIX_SESSION_TOKEN,...e.HLIX_WORKSPACE_ID?{organizationId:e.HLIX_WORKSPACE_ID}:{}};if(t)return{baseUrl:e.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:t,...e.HLIX_WORKSPACE_ID?{organizationId:e.HLIX_WORKSPACE_ID}:{}};try{let n=JSON.parse(Vn(de(e),"utf8"));return n.apiKey&&n.baseUrl?n:null}catch{return null}}function Qn(e=process.env){let t=de(e);return rt(t)?t:null}function It(e=process.env){let t=de(e);if(!rt(t))return{path:t,removed:!1,reason:"absent"};let n=Ct(t);if(n.isSymbolicLink()||!n.isFile())throw Error("Refusing to remove a credential path that is not a regular file.");let r=process.getuid?.();if(r!==void 0&&Xn(t).uid!==r)throw Error("Refusing to remove a credential file owned by another user.");let s;try{s=JSON.parse(Vn(t,"utf8"))}catch{s=null}let o=s;if(!o||typeof o.apiKey!=="string"||typeof o.baseUrl!=="string")throw Error(`Refusing to remove ${t}: it is not a credential written by this CLI.`);return Zn(t),{path:t,removed:!0,reason:"removed"}}function er(e,t=process.env){let n=de(t),r=Cs(n);if(ks(r,{recursive:!0,mode:448}),Ct(r).isSymbolicLink())throw Error("Refusing to write credentials through a symlinked directory.");if(rt(n)){let i=Ct(n);if(i.isSymbolicLink()||!i.isFile())throw Error("Refusing to replace a credential path that is not a regular file.");let a=process.getuid?.();if(a!==void 0&&Xn(n).uid!==a)throw Error("Refusing to replace a credential file owned by another user.")}let s=$t(r,`.credentials.${process.pid}.${crypto.randomUUID()}.tmp`),o;try{o=Wn(s,Pe.O_WRONLY|Pe.O_CREAT|Pe.O_EXCL|Pe.O_NOFOLLOW,384),Es(o,`${JSON.stringify(e,null,2)}
6
+ `,"utf8"),Gn(o),Pt(o),o=void 0,js(s,n);let i=Wn(r,Pe.O_RDONLY);try{try{Gn(i)}catch(a){let c=a.code;if(c!=="EINVAL"&&c!=="ENOTSUP")throw a}}finally{Pt(i)}}catch(i){if(o!==void 0)Pt(o);if(rt(s))Zn(s);throw i}return n}import{constants as st,existsSync as ot,lstatSync as nr,mkdirSync as $s,openSync as Is,closeSync as tr,fsyncSync as xs,readFileSync as rr,renameSync as Rs,unlinkSync as _s,writeFileSync as xt}from"node:fs";import{dirname as Ts,join as Ce,resolve as it}from"node:path";function Os(e){if(!ot(e))return;let t=nr(e);if(t.isSymbolicLink()||!t.isFile())throw Error(`Refusing to replace a non-regular Hlix file: ${e}`)}function $e(e,t){let n=Ts(e);if($s(n,{recursive:!0,mode:448}),nr(n).isSymbolicLink())throw Error(`Refusing to write through a symlinked Hlix directory: ${n}`);Os(e);let r=Ce(n,`.hlix-${process.pid}-${crypto.randomUUID()}.tmp`),s;try{s=Is(r,st.O_WRONLY|st.O_CREAT|st.O_EXCL|st.O_NOFOLLOW,384),xt(s,`${JSON.stringify(t,null,2)}
7
+ `,"utf8"),xs(s),tr(s),s=void 0,Rs(r,e)}catch(o){if(s!==void 0)tr(s);if(ot(r))_s(r);throw o}}function Ie(e){return Ce(it(e),".hlix","config.json")}function sr(e){return Ce(it(e),".hlix","state.json")}function pe(e){try{let t=JSON.parse(rr(Ie(e),"utf8"));return t.schemaVersion===1&&t.workspaceId&&t.apiUrl?t:null}catch{return null}}function xe(e,t){$e(Ie(e),t);let n=Ce(it(e),".hlix",".gitignore");if(!ot(n))xt(n,`state.json
8
+ `,{mode:420,flag:"wx"});let r=Ce(it(e),".hlixignore");if(!ot(r))xt(r,`# Additional project-local paths to exclude from Hlix snapshots.
9
+ `,{mode:420,flag:"wx"})}function Re(e,t){$e(sr(e),t)}function at(e){try{let t=JSON.parse(rr(sr(e),"utf8"));return t.schemaVersion===1&&t.revisionId&&t.generation>0?t:null}catch{return null}}var Rt="https://server.hlix.ai";function A(e){let t=Ns(e);for(;;){let n=pe(t);if(n)return{root:t,config:n};let r=Fs(t);if(r===t)return null;t=r}}function ir(e){try{return As(e).isDirectory()}catch{return!1}}function ct(e){if(typeof e!=="string")return;let t=e.trim();return t?t:void 0}var or=(e,t)=>e.replace(/\/+$/,"")===t.replace(/\/+$/,"");function D(e){let{env:t,flags:n,cwd:r}=e,s=A(r),o=Yn(t),i=o?t.HLIX_API_KEY||t.HLIX_SESSION_TOKEN?"env":"file":null,a=i==="file"?o:null,c=ct(n["base-url"]),l=ct(t.HLIX_BASE_URL),p=ct(n.workspace),u=ct(t.HLIX_WORKSPACE_ID),f=c??l??s?.config.apiUrl??a?.baseUrl??Rt,d=c?"flag":l?"env":s?.config.apiUrl?"project":a?.baseUrl?"credential":"default",g=p??u??s?.config.workspaceId??a?.organizationId??null,m=p?"flag":u?"env":s?.config.workspaceId?"project":a?.organizationId?"credential":null;return{baseUrl:f,baseUrlSource:d,workspaceId:g,workspaceSource:m,credential:o,credentialSource:i,credentialPath:de(t),binding:s,conflict:Hs(s,{flagBaseUrl:c,envBaseUrl:l,flagWorkspace:p,envWorkspace:u})}}function Hs(e,t){if(!e)return null;let n=`${e.root} is bound to`,r="Drop the override, or point --cwd at a folder bound to it.";if(t.flagWorkspace&&t.flagWorkspace!==e.config.workspaceId)return`${n} workspace ${e.config.workspaceId}, but --workspace names ${t.flagWorkspace}. ${r}`;if(t.envWorkspace&&t.envWorkspace!==e.config.workspaceId)return`${n} workspace ${e.config.workspaceId}, but HLIX_WORKSPACE_ID names ${t.envWorkspace}. ${r}`;if(t.flagBaseUrl&&!or(t.flagBaseUrl,e.config.apiUrl))return`${n} ${e.config.apiUrl}, but --base-url names ${t.flagBaseUrl}. ${r}`;if(t.envBaseUrl&&!or(t.envBaseUrl,e.config.apiUrl))return`${n} ${e.config.apiUrl}, but HLIX_BASE_URL names ${t.envBaseUrl}. ${r}`;return null}import{resolve as Zs}from"node:path";import{parseArgs as Ys}from"node:util";import Ls from"openapi-fetch";function _t(e){return Ls({baseUrl:e.baseUrl,headers:e.headers,fetch:e.fetch})}var _e=(e)=>({kind:"apiKey",apiKey:e});var Tt=(e)=>({kind:"bearer",token:e});function Us(e){switch(e.kind){case"apiKey":return{"x-api-key":e.apiKey};case"session":return{cookie:e.cookie};case"bearer":return{authorization:`Bearer ${e.token}`}}}function Ms(e){return e?{"X-Organization-Id":e}:{}}function ar(e,t){return{...Us(e),...Ms(t)}}function Bs(e){if(typeof e!=="object"||e===null)return null;let{error:t}=e;return typeof t==="string"?t:null}class M extends Error{status;body;requestId;method;url;constructor(e,t){super(e);this.name=new.target.name,this.status=t.status,this.body=t.body,this.requestId=t.requestId??null,this.method=t.method,this.url=t.url}}class Te extends M{issues;constructor(e,t,n){super(e,t);this.issues=n}}class Oe extends M{}class Ae extends M{}class Fe extends M{}class Ne extends M{}class He extends M{}class Le extends M{retryAfter;constructor(e,t,n){super(e,t);this.retryAfter=n}}class Ue extends M{}class Me extends M{}class ue extends Error{method;url;constructor(e,t){super(e,{cause:t.cause});this.name="HlixTransportError",this.method=t.method,this.url=t.url}}function zs(e){if(typeof e!=="object"||e===null)return null;let t=e;if(t.success!==!1)return null;let n=t.error?.message;if(typeof n!=="string")return null;try{let r=JSON.parse(n);return Array.isArray(r)?r:[]}catch{return[]}}function Ds(e){let t=e.get("retry-after");if(!t)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function me(e,t,n){let r={status:e.status,body:t,requestId:e.headers.get("x-request-id"),method:n.method,url:n.url},s=Bs(t),o=`${n.method} ${n.url} failed with ${e.status}`,i=zs(t);if(i)return new Te(`${n.method} ${n.url}: request body failed validation`,r,i);let a=s??o;switch(e.status){case 400:return new Oe(a,r);case 401:return new Ae(a,r);case 403:return new Fe(a,r);case 404:return new Ne(a,r);case 409:return new He(a,r);case 429:return new Le(a,r,Ds(e.headers));case 501:return new Ue(a,r);default:return e.status>=500?new Me(a,r):new M(a,r)}}var cr=new Set(["GET","HEAD","PUT","DELETE","OPTIONS","TRACE"]);function lt(e){return cr.has(e.toUpperCase())}var Ks=new Set([429,500,502,503,504]);function Js(e){return Ks.has(e)}var Ot={attempts:3,baseDelayMs:200,maxDelayMs:5000};function At(e,t,n,r=Math.random){if(n!==null)return Math.min(n*1000,t.maxDelayMs);let s=Math.min(t.baseDelayMs*2**e,t.maxDelayMs);return Math.round(r()*s)}function Ft(e){if(!lt(e.method))return!1;if(e.attempt+1>=e.policy.attempts)return!1;return e.status===null||Js(e.status)}var qs=(e)=>new Promise((t)=>setTimeout(t,e));function Gs(e){let t=e.headers.get("retry-after");if(!t)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function lr(e){let{base:t,policy:n}=e,r=e.sleep??qs,s=e.random??Math.random;return async(o)=>{let i=o.method.toUpperCase(),a=lt(i)?o.clone():null;for(let c=0;;c+=1){let l=c===0?o:a.clone(),p;try{p=await t(l)}catch(u){if(!a||!Ft({method:i,attempt:c,policy:n,status:null}))throw new ue(`${i} ${o.url}: ${u instanceof Error?u.message:String(u)}`,{method:i,url:o.url,cause:u});await r(At(c,n,null,s));continue}if(!Ft({method:i,attempt:c,policy:n,status:p.status}))return p;if(!a)return p;await r(At(c,n,Gs(p),s))}}}function S(e,t){if(e.response.ok)return e.data;throw me(e.response,e.error??e.data,t)}var Be=(e)=>typeof e==="string"?e:"";function Nt(e){let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=="object"||t===null)return null;let n=t;switch(n.type){case"idle":return{type:"idle"};case"done":return{type:"done"};case"active":return typeof n.runId==="string"?{type:"active",runId:n.runId}:{type:"active"};case"on_chat_model_stream":return{type:"on_chat_model_stream",delta:Be(n.delta)};case"reasoning":return{type:"reasoning",delta:Be(n.delta)};case"on_tool_start":return{type:"on_tool_start",name:Be(n.name),input:n.input};case"on_tool_end":return{type:"on_tool_end",name:Be(n.name),output:n.output};case"error":return{type:"error",message:Be(n.message)};default:return null}}var Ht=(e)=>e.type==="done"||e.type==="idle"||e.type==="error";var Ws=()=>({event:null,data:[],id:null,retry:null});function dr(e,t,n){switch(t){case"event":e.event=n;return;case"data":e.data.push(n);return;case"id":if(!n.includes("\x00"))e.id=n;return;case"retry":{if(/^\d+$/.test(n))e.retry=Number(n);return}default:return}}function ur(e){let t=e.data.join(`
10
+ `),n=e.event,r=e.id;if(e.data=[],e.event=null,t==="")return null;return{event:n,data:t,id:r,retry:e.retry}}function pr(e,t){if(t==="")return ur(e);if(t.startsWith(":"))return null;let n=t.indexOf(":");if(n===-1)return dr(e,t,""),null;let r=t.slice(0,n),s=t.slice(n+1);if(s.startsWith(" "))s=s.slice(1);return dr(e,r,s),null}function Vs(e){let t=[],n=0;for(let r=0;r<e.length;r+=1){let s=e[r];if(s!==`
11
+ `&&s!=="\r")continue;if(t.push(e.slice(n,r)),s==="\r"&&e[r+1]===`
12
+ `)r+=1;n=r+1}return{lines:t,rest:e.slice(n)}}async function*Lt(e,t){let n=e.getReader(),r=new TextDecoder,s=Ws(),o="",i=()=>void n.cancel().catch(()=>{});t?.addEventListener("abort",i,{once:!0});try{for(;;){let{done:c,value:l}=await n.read();if(c)break;o+=r.decode(l,{stream:!0});let{lines:p,rest:u}=Vs(o);o=u;for(let f of p){let d=pr(s,f);if(d)yield d}if(t?.aborted)return}if(o+=r.decode(),o!==""){let c=pr(s,o);if(c)yield c}let a=ur(s);if(a)yield a}finally{t?.removeEventListener("abort",i),n.releaseLock()}}class ze{raw;baseUrl;headers;fetcher;constructor(e){this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.headers=ar(e.credential,e.organizationId);let t={...Ot,...e.retry},n=e.fetch??((r)=>globalThis.fetch(r));this.fetcher=lr({base:n,policy:t}),this.raw=_t({baseUrl:this.baseUrl,headers:this.headers,fetch:this.fetcher})}at(e,t){return{method:e,url:`${this.baseUrl}${t}`}}projects={list:async()=>S(await this.raw.GET("/v1/api/projects"),this.at("GET","/v1/api/projects")),get:async(e)=>S(await this.raw.GET("/v1/api/projects/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}`)),create:async(e)=>S(await this.raw.POST("/v1/api/projects",{body:e}),this.at("POST","/v1/api/projects")),delete:async(e)=>S(await this.raw.DELETE("/v1/api/projects/{id}",{params:{path:{id:e}}}),this.at("DELETE",`/v1/api/projects/${e}`)),start:async(e,t)=>S(await this.raw.POST("/v1/api/projects/{id}/start",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/start`)),refreshPreview:async(e)=>S(await this.raw.POST("/v1/api/projects/{id}/preview/refresh",{params:{path:{id:e}}}),this.at("POST",`/v1/api/projects/${e}/preview/refresh`)),terminal:async(e)=>S(await this.raw.GET("/v1/api/projects/{id}/terminal",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}/terminal`)),observeAgent:(e,t,n)=>this.observeAgent(e,t,n),workspace:(e)=>({fs:async(t)=>S(await this.raw.POST("/v1/api/projects/{id}/workspace/fs",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/workspace/fs`)),exec:async(t)=>S(await this.raw.POST("/v1/api/projects/{id}/workspace/exec",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/workspace/exec`))})};secrets={listEntries:async(e)=>S(await this.raw.GET("/v1/api/secrets/project/{projectId}/entries",{params:{path:{projectId:e}}}),this.at("GET",`/v1/api/secrets/project/${e}/entries`)),upsertEntries:async(e,t)=>S(await this.raw.PUT("/v1/api/secrets/project/{projectId}/entries",{params:{path:{projectId:e}},body:t}),this.at("PUT",`/v1/api/secrets/project/${e}/entries`)),deleteEntry:async(e,t,n)=>S(await this.raw.DELETE("/v1/api/secrets/project/{projectId}/entries/{key}",{params:{path:{projectId:e,key:t},...n===void 0?{}:{query:{source:n}}}}),this.at("DELETE",`/v1/api/secrets/project/${e}/entries/${encodeURIComponent(t)}`)),exportEntries:async(e,t={})=>{let n=`/v1/api/secrets/project/${e}/export`,r=`${this.baseUrl}${n}`,s=await this.fetcher(new Request(r,{method:"POST",headers:{...this.headers,"content-type":"application/json"},body:JSON.stringify({...t.source===void 0?{}:{source:t.source},...t.format===void 0?{}:{format:t.format}})}));if(!s.ok)throw me(s,await s.json().catch(()=>{return}),{method:"POST",url:r});return s.text()}};imports={create:async(e)=>{let t=await this.raw.POST("/v1/api/imports",{body:e});return S(t,this.at("POST","/v1/api/imports"))},get:async(e)=>S(await this.raw.GET("/v1/api/imports/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/imports/${e}`)),finalize:async(e,t)=>{let n=await this.raw.POST("/v1/api/imports/{id}/finalize",{params:{path:{id:e}},body:t});return S(n,this.at("POST",`/v1/api/imports/${e}/finalize`))},uploadBundle:async(e,t,n={})=>{let r=n.chunkSize??8388608;if(r<=0||r%262144!==0)throw Error("Import upload chunkSize must be a positive multiple of 256 KiB");let s=e.url.startsWith("/")?`${this.baseUrl}${e.url}`:e.url;if(e.kind==="hlix-stream"){let i=new Request(s,{method:"PUT",headers:{...this.headers,"content-type":"application/x-git-bundle","content-length":String(t.size)},body:t,signal:n.signal}),a=await this.fetcher(i);if(!a.ok)await this.throwUploadError(a,s);n.onProgress?.(t.size,t.size);return}let o=0;while(o<t.size){let i=Math.min(o+r,t.size),a=new Request(s,{method:"PUT",headers:{"content-type":"application/x-git-bundle","content-length":String(i-o),"content-range":`bytes ${o}-${i-1}/${t.size}`},body:t.slice(o,i),signal:n.signal}),c=await this.fetcher(a);if(c.status!==308&&!c.ok)await this.throwUploadError(c,s);let l=c.headers.get("range")?.match(/bytes=0-(\d+)/)?.[1];if(o=l?Number(l)+1:i,!Number.isSafeInteger(o)||o<i||o>t.size)throw Error("Import upload server returned an invalid acknowledged range");n.onProgress?.(o,t.size)}}};revisions={head:async(e)=>S(await this.raw.GET("/v1/api/projects/{id}/revisions/head",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}/revisions/head`)),protectedFiles:async(e)=>S(await this.raw.GET("/v1/api/projects/{id}/protected-files",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}/protected-files`)),createUpload:async(e,t)=>{let n=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads",{params:{path:{id:e}},body:t});return S(n,this.at("POST",`/v1/api/projects/${e}/revisions/uploads`))},finalize:async(e,t,n)=>{let r=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads/{uploadId}/finalize",{params:{path:{id:e,uploadId:t}},body:n});return S(r,this.at("POST",`/v1/api/projects/${e}/revisions/uploads/${t}/finalize`))},uploadBundle:async(e,t,n={})=>this.imports.uploadBundle(e,t,n),downloadBundle:async(e,t)=>{let n=`/v1/api/projects/${e}/revisions/${t}/bundle`,r=new Request(`${this.baseUrl}${n}`,{method:"GET",headers:this.headers}),s=await this.fetcher(r);if(!s.ok)await this.throwUploadError(s,`${this.baseUrl}${n}`);return s.blob()}};resources={importSkill:async(e,t)=>S(await this.raw.POST("/v1/api/projects/{id}/resources/skill",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/skill`)),importAgent:async(e,t)=>S(await this.raw.POST("/v1/api/projects/{id}/resources/agent",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/agent`)),importMcp:async(e,t)=>S(await this.raw.POST("/v1/api/projects/{id}/resources/mcp",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/mcp`))};async throwUploadError(e,t){let n=null;try{n=await e.json()}catch{n=await e.text().catch(()=>null)}throw me(e,n,{method:"PUT",url:t})}tasks={list:async(e)=>S(await this.raw.GET("/v1/api/tasks",{params:{query:e??{}}}),this.at("GET","/v1/api/tasks")),get:async(e)=>S(await this.raw.GET("/v1/api/tasks/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}`)),create:async(e)=>S(await this.raw.POST("/v1/api/tasks",{body:e}),this.at("POST","/v1/api/tasks")),update:async(e,t)=>S(await this.raw.PATCH("/v1/api/tasks/{id}",{params:{path:{id:e}},body:t}),this.at("PATCH",`/v1/api/tasks/${e}`)),listComments:async(e)=>S(await this.raw.GET("/v1/api/tasks/{id}/comments",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}/comments`)),addComment:async(e,t)=>S(await this.raw.POST("/v1/api/tasks/{id}/comments",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/tasks/${e}/comments`)),review:async(e)=>S(await this.raw.GET("/v1/api/tasks/{id}/review",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}/review`)),stream:(e,t)=>this.stream(`/v1/api/tasks/${e}/stream`,t)};modelConfig={setProjectHarness:async(e,t)=>S(await this.raw.PUT("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:e}},body:{harness:t}}),this.at("PUT",`/v1/api/model-config/harness/${e}`)),clearProjectHarness:async(e)=>S(await this.raw.DELETE("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:e}}}),this.at("DELETE",`/v1/api/model-config/harness/${e}`)),setHarness:async(e)=>S(await this.raw.PUT("/v1/api/model-config/harness",{body:{harness:e}}),this.at("PUT","/v1/api/model-config/harness")),clearHarness:async()=>S(await this.raw.DELETE("/v1/api/model-config/harness"),this.at("DELETE","/v1/api/model-config/harness")),resolvedHarness:async()=>S(await this.raw.GET("/v1/api/model-config/harness/resolved"),this.at("GET","/v1/api/model-config/harness/resolved")),resolvedProjectHarness:async(e)=>S(await this.raw.GET("/v1/api/model-config/harness/{projectId}/resolved",{params:{path:{projectId:e}}}),this.at("GET",`/v1/api/model-config/harness/${e}/resolved`))};cycles={list:async(e)=>S(await this.raw.GET("/v1/api/cycles",{params:{query:e??{}}}),this.at("GET","/v1/api/cycles")),get:async(e)=>S(await this.raw.GET("/v1/api/cycles/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/cycles/${e}`)),propose:async(e)=>S(await this.raw.POST("/v1/api/cycles",{body:e}),this.at("POST","/v1/api/cycles")),stream:(e,t)=>this.stream(`/v1/api/cycles/${e}/stream`,t)};clientInvoices={list:async(e)=>S(await this.raw.GET("/v1/api/client-billing/invoices",{params:{query:e??{}}}),this.at("GET","/v1/api/client-billing/invoices")),get:async(e)=>S(await this.raw.GET("/v1/api/client-billing/invoices/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/client-billing/invoices/${e}`)),createDraft:async(e)=>S(await this.raw.POST("/v1/api/client-billing/invoices",{body:e}),this.at("POST","/v1/api/client-billing/invoices")),issue:async(e)=>S(await this.raw.POST("/v1/api/client-billing/invoices/{id}/issue",{params:{path:{id:e}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/issue`)),void:async(e,t)=>S(await this.raw.POST("/v1/api/client-billing/invoices/{id}/void",{params:{path:{id:e}},body:{reason:t}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/void`)),pay:async(e)=>S(await this.raw.POST("/v1/api/client-billing/invoices/{id}/pay",{params:{path:{id:e}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/pay`)),paymentLink:async(e,t={})=>S(await this.raw.POST("/v1/api/client-billing/invoices/{id}/payment-link",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/client-billing/invoices/${e}/payment-link`))};async*observeAgent(e,t,n){let r=`/v1/api/projects/${e}/agents/${t}/observe`;for await(let s of this.stream(r,n)){let o=Nt(s.data);if(!o)continue;if(yield o,Ht(o))return}}async*stream(e,t){let n=`${this.baseUrl}${e}`,r=new Request(n,{headers:{...this.headers,accept:"text/event-stream"},signal:t?.signal}),s=await globalThis.fetch(r);if(!s.ok||!s.body){let o=null;try{o=await s.json()}catch{o=null}throw me(s,o,{method:"GET",url:n})}yield*Lt(s.body,t?.signal)}}function Mt(e){if(e instanceof h)return{code:e.code,status:null};if(e instanceof Te)return{code:"invalid_request",status:400};if(e instanceof Oe)return{code:"bad_request",status:400};if(e instanceof Ae)return{code:"unauthenticated",status:401};if(e instanceof Fe)return{code:"forbidden",status:403};if(e instanceof Ne)return{code:"not_found",status:404};if(e instanceof He)return{code:"conflict",status:409};if(e instanceof Le)return{code:"rate_limited",status:429};if(e instanceof Ue)return{code:"not_implemented",status:501};if(e instanceof Me)return{code:"server_error",status:e.status};if(e instanceof ue)return{code:"unreachable",status:null};return{code:"unknown",status:null}}var Ut=(e)=>e instanceof Error?e.message:String(e);function Qs(e,t){let n=D({env:e,flags:t.flags,cwd:t.cwd});if(n.conflict)throw new h("workspace_mismatch",n.conflict);if(!n.credential)throw new h("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");return new ze({baseUrl:n.baseUrl,credential:n.credential.sessionToken?Tt(n.credential.sessionToken):_e(n.credential.apiKey),...n.workspaceId?{organizationId:n.workspaceId}:{}})}function mr(e){let t=Math.max(...e.map((r)=>r.name.length));return`hlix — the hlix control-plane CLI
13
+
14
+ Usage:
15
+ hlix <command> [options]
16
+
17
+ Commands:
18
+ ${[` hlix ${"".padEnd(t)} Open Hlix Code (interactive)`,...e.map((r)=>` hlix ${r.name.padEnd(t)} ${r.summary}`)].join(`
19
+ `)}
20
+
21
+ Options:
22
+ --json Machine-readable output (a versioned, stable contract)
23
+ --cwd <dir> Operate on another directory instead of the current one
24
+ --workspace <id> Workspace to act in, overriding the folder's binding
25
+ --base-url <url> API to talk to, overriding the folder's binding
26
+ --help Show this help
27
+ --version Show the installed CLI version
28
+
29
+ A command targets the workspace named by, in order: an explicit flag, the
30
+ HLIX_* environment, the nearest .hlix/config.json, then the stored credential.
31
+ Run \`hlix status\` to see which one applied.
32
+ `}function fr(e,t){for(let n of[...e].sort((r,s)=>s.name.length-r.name.length)){let r=n.name.split(" ");if(r.every((s,o)=>t[o]===s))return{command:n,rest:t.slice(r.length)}}return null}async function nc(e,t,n){if(t.some((j)=>j==="--api-key"||j.startsWith("--api-key=")))return n.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=Ys({args:t,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"},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"}}})}catch(j){let F=t.includes("--json"),H=Ut(j);if(F)n.stdout(w(Ee("cli",{code:"invalid_usage",message:H,status:null})));else n.stderr(`${H}
33
+ `);return 2}let s=r.values.json===!0,o=r.positionals;if(r.values.version===!0){let{version:j}=await import("./package-w9c40vfc.js");return n.stdout(`${j}
34
+ `),0}if(o.length===0||r.values.help===!0){let j=fr(e,o);return n.stdout(j?`${j.command.usage}
35
+ `:mr(e)),o.length===0&&r.values.help!==!0?1:0}let i=fr(e,o);if(!i){let j=o.join(" ");if(s)n.stdout(w(Ee(j,{code:"unknown_command",message:`Unknown command: ${j}`,status:null})));else n.stderr(`Unknown command: ${j}
36
+
37
+ ${mr(e)}`);return 2}let a=new Set(["json","help","version","cwd","workspace","base-url"]),c=new Set(i.command.options??[]),l=Object.entries(r.values).filter(([j,F])=>F!==void 0&&!a.has(j)&&!c.has(j)).map(([j])=>`--${j}`),p=i.command.args??{min:0,max:0},u=i.rest.length<p.min?{code:"missing_argument",message:i.command.usage.split(`
38
+ `)[0]}:i.rest.length>p.max?{code:"invalid_usage",message:i.command.usage.split(`
39
+ `)[0]}:null,f=typeof r.values.cwd==="string"?r.values.cwd:void 0,d=Zs(f??"."),g=f!==void 0&&!ir(d)?{code:"invalid_usage",message:`--cwd is not a directory: ${d}`}:null,m=l.length>0?{code:"invalid_usage",message:`Unsupported option for ${i.command.name}: ${l.join(", ")}`}:g??u;if(m){if(s)n.stdout(w(Ee(i.command.name,{...m,status:null})));else n.stderr(`error: ${m.message}
40
+
41
+ ${i.command.usage}
42
+ `);return 2}let k=r.values,R={...n,args:i.rest,json:s,flags:k,cwd:d,requireClient:(j)=>Qs(n.env,{cwd:j??d,flags:k})};try{return await i.command.run(R)}catch(j){let{code:F,status:H}=Mt(j);if(s)n.stdout(w(Ee(i.command.name,{code:F,message:Ut(j),status:H})));else n.stderr(`error: ${Ut(j)}
43
+ `);return F==="unauthenticated"||F==="forbidden"?3:1}}import{readFileSync as eo}from"node:fs";import{homedir as to}from"node:os";import{join as no}from"node:path";var gr=["cloud","docker","local"],fe=["claude-code","codex","cursor-agent","hlix"],uc="hlix",hr={harness:"local and docker sandboxes only",model:"all sandboxes",sandbox:"all sandboxes"},ge=["harness","model","sandbox"],Bt=["projectId","workspaceId","apiUrl"];function zt(e=process.env){return no(e.HLIX_CONFIG_HOME??to(),".hlix","config.json")}function yr(e=process.env){try{let t=JSON.parse(eo(zt(e),"utf8"));return t.schemaVersion===1?t:null}catch{return null}}function Dt(e,t=process.env){let n=yr(t),r=A(e),s=r?.root??null,o=r?.config??null,i={},a={},c=(l)=>{let p=o?.[l],u=n?.[l];if(p!==void 0)i[l]=p,a[l]="project";else if(u!==void 0)i[l]=u,a[l]="global"};for(let l of ge)c(l);for(let l of Bt){let p=o?.[l];if(p!==void 0)i[l]=p,a[l]="project"}return{merged:i,sources:a,global:n,project:o,paths:{global:zt(t),project:s?Ie(s):null}}}function vr(e){return[...ge,...Bt].map((n)=>({key:n,value:e.merged[n]??null,source:e.sources[n]??"default"}))}function ro(e,t){if(e==="sandbox"&&!gr.includes(t))return`sandbox must be one of ${gr.join(", ")}; got "${t}".`;if(e==="harness"&&!fe.includes(t))return`harness must be one of ${fe.join(", ")}; got "${t}".`;if(e==="model"&&t.trim()==="")return"model must not be empty.";return null}function Kt(e){if(ge.includes(e))return e;let t=Bt.includes(e);throw new h("invalid_usage",t?`${e} is written by \`hlix init\` and \`hlix import\`, not by \`hlix config set\`.`:`Unknown setting: ${e}. Known settings: ${ge.join(", ")}.`)}function wr(e,t){let n=ro(e,t);if(n)throw new h("invalid_usage",n);return t}function br(e){if(e.scope==="global"){let r=zt(e.env),s=yr(e.env)??{schemaVersion:1};return $e(r,{...s,[e.key]:e.value}),r}let t=A(e.cwd);if(!t)throw new h("not_initialized","This folder is not bound to hlix. Run `hlix init` here, or set it machine-wide with --global.");let n=Ie(t.root);return $e(n,{...t.config,[e.key]:e.value}),n}import{createHash as so}from"node:crypto";import{mkdirSync as oo,readdirSync as Er,readFileSync as io,rmSync as ao,statSync as Pr,writeFileSync as co}from"node:fs";import{homedir as lo,tmpdir as po}from"node:os";import{basename as Cr,isAbsolute as uo,join as x,relative as mo}from"node:path";var $r=(e=process.env)=>e.HOME??e.USERPROFILE??lo();function K(e){try{if(!Pr(e).isFile())return null;return io(e,"utf8")}catch{return null}}function fo(e){try{return Pr(e).isDirectory()}catch{return!1}}function Ke(e,t){try{return Er(e,{withFileTypes:!0}).filter((n)=>n.isFile()&&n.name.endsWith(t)).map((n)=>x(e,n.name)).sort()}catch{return[]}}function go(e){try{return Er(e,{withFileTypes:!0}).filter((t)=>t.isDirectory()||t.isSymbolicLink()).map((t)=>x(e,t.name)).sort()}catch{return[]}}function qt(e){let t=e.replace(/^\uFEFF/,""),n=t.indexOf(`
44
+ `);if(!t.startsWith("---")||n===-1)return{fields:{},body:t.trim()};let r=t.indexOf(`
45
+ ---`,n);if(r===-1)return{fields:{},body:t.trim()};let s={};for(let i of t.slice(n+1,r).split(`
46
+ `)){let a=/^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(i);if(!a)continue;s[a[1]]=a[2].trim().replace(/^["']|["']$/g,"")}let o=t.indexOf(`
47
+ `,r+1);return{fields:s,body:o===-1?"":t.slice(o+1).trim()}}function ho(e){let t=e.trimStart(),n=/^"((?:[^"\\]|\\.)*)"/.exec(t)??/^'([^']*)'/.exec(t);if(n)return n[1].replace(/\\"/g,'"').replace(/\\n/g,`
48
+ `);if(t.startsWith("["))return[...t.matchAll(/"((?:[^"\\]|\\.)*)"|'([^']*)'/g)].map((s)=>s[1]??s[2]??"");if(t.startsWith("{")){let s={};for(let o of t.matchAll(/([A-Za-z0-9_.-]+)\s*=\s*"((?:[^"\\]|\\.)*)"/g))s[o[1]]=o[2].replace(/\\"/g,'"');return s}let r=/^[^\s#]+/.exec(t)?.[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 Ir(e){let t={"":{}},n="",r=e.split(`
49
+ `);for(let s=0;s<r.length;s+=1){let i=r[s].trim();if(!i||i.startsWith("#"))continue;let a=/^\[\[?([^\]]+)\]\]?$/.exec(i);if(a){n=a[1].trim(),t[n]??={};continue}let c=/^([A-Za-z0-9_.-]+|"[^"]+")\s*=\s*(.*)$/.exec(i);if(!c)continue;let l=c[1].replace(/^"|"$/g,""),p=c[2];if(p.startsWith('"""')){let f=[],d=p.slice(3);if(d.includes('"""'))f.push(d.slice(0,d.indexOf('"""')));else{if(d)f.push(d);while(s+1<r.length){s+=1;let g=r[s],m=g.indexOf('"""');if(m===-1){f.push(g);continue}f.push(g.slice(0,m));break}}t[n][l]=f.join(`
50
+ `).replace(/^\n/,"");continue}let u=ho(p);if(u!==void 0)t[n][l]=u}return t}function Jt(e,t){return e.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g,(n,r,s)=>{let o=t[r];return o!==void 0&&o!==""?o:s??""})}var Sr=(e,t)=>{let n={};for(let[r,s]of Object.entries(e))if(typeof s==="string")n[r]=Jt(s,t);return n},yo=[{relative:"GEMINI.md",source:"gemini"},{relative:x(".gemini","GEMINI.md"),source:"gemini"},{relative:".cursorrules",source:"cursor"},{relative:".windsurfrules",source:"windsurf"},{relative:x(".github","copilot-instructions.md"),source:"copilot"}],vo=[{relative:x(".gemini","GEMINI.md"),source:"gemini"}],wo=[{relative:x(".cursor","rules"),source:"cursor",extension:".mdc"},{relative:x(".windsurf","rules"),source:"windsurf",extension:".md"}];function bo(e,t){let n=x(e,".clinerules"),r=fo(n)?Ke(n,".md"):[n],s=[];for(let o of r){let i=K(o)?.trim();if(i)s.push({path:o,source:"cline",scope:t,content:i})}return s}function So(e,t,n){let{fields:r,body:s}=qt(t);if(r.alwaysApply==="false")return{path:e,source:"cursor",scope:n,reason:"alwaysApply: false"};if(!s)return{path:e,source:"cursor",scope:n,reason:"no rule body"};let o=r.globs?.replace(/^\[|\]$/g,"").trim();return{path:e,source:"cursor",scope:n,content:s,...o?{note:`Applies to: ${o}`}:{}}}function kr(e,t){let n=[];for(let r of["",".claude",t])for(let s of["AGENTS.md","CLAUDE.md"]){let o=K(x(e,r,s))?.trim();if(o)n.push(o)}return n}var ko=[{dir:".claude",source:"claude",harnessReads:!0},{dir:".agents",source:"agents",harnessReads:!0},{dir:".hlix",source:"hlix",harnessReads:!0},{dir:".codex",source:"codex",harnessReads:!1}],jo=[{relative:x(".cursor","commands"),source:"cursor"},{relative:x(".codex","prompts"),source:"codex"}],xr=[{relative:x(".cursor","mcp.json"),source:"cursor",key:"mcpServers",format:"json"},{relative:x(".windsurf","mcp.json"),source:"windsurf",key:"mcpServers",format:"json"},{relative:x(".gemini","settings.json"),source:"gemini",key:"mcpServers",format:"json"},{relative:x(".vscode","mcp.json"),source:"vscode",key:"servers",format:"json"},{relative:x(".codex","config.toml"),source:"codex",key:"mcp_servers",format:"toml"}],Eo="found, not loaded (machine-wide; enable per project by copying into .hlix/mcp.json)",Po=xr.filter((e)=>e.source!=="vscode");function Co(e,t){if(!e||typeof e!=="object"||Array.isArray(e))return{reason:"not an object"};let n=e;if(n.enabled===!1||n.disabled===!0)return{reason:"disabled"};let r=typeof n.command==="string"&&n.command!=="",s=typeof n.url==="string"&&n.url!=="";if(r&&s)return{reason:'has both "command" and "url"'};if(r){let c=Array.isArray(n.args)?n.args.filter((p)=>typeof p==="string"):void 0,l=n.env&&typeof n.env==="object"&&!Array.isArray(n.env)?Sr(n.env,t):void 0;return{config:{command:n.command,...c&&c.length>0?{args:c}:{},...l&&Object.keys(l).length>0?{env:l}:{}}}}if(!s)return{reason:'missing "command" or "url"'};let o=n.headers??n.http_headers,i=o&&typeof o==="object"&&!Array.isArray(o)?Sr(o,t):{},a=n.bearer_token_env_var;if(typeof a==="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&!Object.keys(i).some((c)=>c.toLowerCase()==="authorization"))i.Authorization=`Bearer ${Jt(`\${${a}}`,t)}`;return{config:{url:Jt(n.url,t),...Object.keys(i).length>0?{headers:i}:{}}}}function jr(e,t,n,r){let s=K(e),o=[],i=[];if(s===null)return{servers:o,skipped:i};let a=[];if(t.format==="toml"){let c=Ir(s);a=Object.entries(c).filter(([l])=>l.startsWith(`${t.key}.`)).map(([l,p])=>[l.slice(t.key.length+1),p])}else try{let l=JSON.parse(s)?.[t.key];if(l&&typeof l==="object"&&!Array.isArray(l))a=Object.entries(l)}catch{return i.push({path:e,source:t.source,scope:n,reason:"not valid JSON"}),{servers:o,skipped:i}}for(let[c,l]of a){let p=Co(l,r);if("reason"in p){i.push({path:e,source:t.source,scope:n,reason:`${c}: ${p.reason}`});continue}o.push({path:e,source:t.source,scope:n,name:c,config:p.config})}return{servers:o,skipped:i}}function $o(e,t,n){let{fields:r,body:s}=qt(t);if(!s)return{path:e,source:"claude",scope:n,reason:"no instructions"};let o=r.tools?.replace(/^\[|\]$/g,"").split(",").map((i)=>i.trim()).filter(Boolean);return{path:e,source:"claude",scope:n,name:r.name||Cr(e,".md"),description:r.description??"",instructions:s,...o&&o.length>0&&o[0]!=="*"?{tools:o}:{},...r.model?{model:r.model}:{}}}function Io(e){let t=Ir(e)[""]??{},n=typeof t.prompt==="string"?t.prompt.trim():"";if(!n)return null;return{description:typeof t.description==="string"?t.description:"",body:n}}function Rr(e,t,n={}){let r=n.configDir??".hlix",s=n.env??process.env,o={instructions:[],skills:[],commands:[],generatedCommands:[],mcpServers:[],subagents:[],skipped:[]},i=(d)=>{if("reason"in d)o.skipped.push(d);else o.instructions.push(d)};for(let d of yo){let g=x(e,d.relative),m=K(g)?.trim();if(m)o.instructions.push({path:g,source:d.source,scope:"project",content:m})}for(let d of wo)for(let g of Ke(x(e,d.relative),d.extension)){let m=K(g);if(m===null)continue;if(d.source==="cursor"){i(So(g,m,"project"));continue}let{body:k}=qt(m);if(k)o.instructions.push({path:g,source:d.source,scope:"project",content:k})}for(let d of bo(e,"project"))i(d);let a=kr(e,r),c=x(e,".codex","AGENTS.md"),l=K(c)?.trim();if(l&&a.includes(l))o.skipped.push({path:c,source:"codex",scope:"project",reason:"same content as the project's AGENTS.md"});else if(l)o.instructions.push({path:c,source:"codex",scope:"project",content:l});for(let d of vo){let g=x(t,d.relative),m=K(g)?.trim();if(m)o.instructions.push({path:g,source:d.source,scope:"global",content:m})}let p=x(t,".codex","AGENTS.md"),u=K(p)?.trim(),f=kr(t,r);if(u&&f.includes(u))o.skipped.push({path:p,source:"codex",scope:"global",reason:"same content as the machine's AGENTS.md"});else if(u)o.instructions.push({path:p,source:"codex",scope:"global",content:u});for(let[d,g]of[[e,"project"],[t,"global"]])for(let m of ko){let k=x(d,m.dir===".hlix"?r:m.dir,"skills");if(!go(k).some((j)=>K(x(j,"SKILL.md"))!==null))continue;o.skills.push({path:k,source:m.source,scope:g,harnessReads:m.harnessReads})}for(let[d,g]of[[e,"project"],[t,"global"]]){for(let m of jo){let k=x(d,m.relative);if(Ke(k,".md").length===0)continue;o.commands.push({path:k,source:m.source,scope:g})}for(let m of Ke(x(d,".gemini","commands"),".toml")){let k=K(m),R=k===null?null:Io(k);if(!R){o.skipped.push({path:m,source:"gemini",scope:g,reason:"no prompt field"});continue}o.generatedCommands.push({path:m,source:"gemini",scope:g,name:Cr(m,".toml"),body:`---
51
+ description: ${R.description}
52
+ ---
53
+
54
+ ${R.body}
55
+ `})}}for(let d of xr){let g=jr(x(e,d.relative),d,"project",s);o.skipped.push(...g.skipped);for(let m of g.servers){let k=o.mcpServers.findIndex((R)=>R.name===m.name);if(k===-1)o.mcpServers.push(m);else o.mcpServers[k]=m}}for(let d of Po){let g=jr(x(t,d.relative),d,"global",s);for(let m of g.servers)o.skipped.push({path:m.path,source:m.source,scope:"global",reason:`${m.name}: ${Eo}`})}for(let[d,g]of[[e,"project"],[t,"global"]])for(let m of Ke(x(d,".claude","agents"),".md")){let k=K(m);if(k===null)continue;let R=$o(m,k,g);if("reason"in R)o.skipped.push(R);else if(o.subagents.some((j)=>j.name===R.name))o.skipped.push({path:m,source:"claude",scope:g,reason:`a project agent already claims the name ${R.name}`});else o.subagents.push(R)}return o}function vc(e,t){if(e.length===0)return null;let n=x(po(),"hlix-standards-commands",so("sha256").update(t).digest("hex").slice(0,16));try{ao(n,{recursive:!0,force:!0}),oo(n,{recursive:!0});for(let r of e)co(x(n,`${r.name}.md`),r.body,"utf8");return n}catch{return null}}var xo=60000,_r=(e,t)=>{let n=mo(t,e);return!n||n.startsWith("..")||uo(n)?e:n};function wc(e,t,n=xo){if(e.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(`
56
+ `),s=[],o=r.length,i=!1;for(let c of e){let l=`# From ${_r(c.path,t)} (${c.source})`,p=c.note?`${l}
57
+ ${c.note}`:l,u=n-o-p.length-4;if(u<=0){i=!0;break}let f=c.content.length<=u?c.content:`${c.content.slice(0,u)}
58
+ [truncated]`;if(f.length<c.content.length)i=!0;s.push(`${p}
59
+
60
+ ${f}`),o+=p.length+f.length+4}let a=i?`
61
+
62
+ [The standards block reached its ${n}-character cap; some rules above are cut short or omitted.]`:"";return`${r}
63
+
64
+ ${s.join(`
65
+
66
+ `)}${a}`}var De=(e,t,n)=>`${e} ${e===1?t:n}`;function bc(e){let t=[];if(e.instructions.length>0)t.push(De(e.instructions.length,"instruction file","instruction files"));if(e.skills.length>0)t.push(De(e.skills.length,"skill directory","skill directories"));let n=e.commands.length+e.generatedCommands.length;if(n>0)t.push(De(n,"command source","command sources"));if(e.mcpServers.length>0)t.push(De(e.mcpServers.length,"mcp server","mcp servers"));if(e.subagents.length>0)t.push(De(e.subagents.length,"subagent","subagents"));if(t.length===0)return"";let r=[...new Set([...e.instructions,...e.skills,...e.commands,...e.generatedCommands,...e.mcpServers,...e.subagents].map((s)=>s.source))].sort();return`standards: ${t.join(" · ")} (${r.join(", ")})`}function Tr(e,t){let n=[],r=(o,i)=>{if(i.length===0)return;n.push(o,...i.map((a)=>` ${a}`),"")},s=(o)=>`${o.source}${o.scope==="global"?" (global)":""} ${_r(o.path,t)}`;if(r("Instructions",e.instructions.map((o)=>`${s(o)}${o.note?` — ${o.note}`:""}`)),r("Skills",e.skills.map((o)=>`${s(o)}${o.harnessReads?" — already read by the harness":""}`)),r("Commands",[...e.commands.map(s),...e.generatedCommands.map((o)=>`${s(o)} → /${o.name}`)]),r("MCP servers",e.mcpServers.map((o)=>`${s(o)} → ${o.name} (${"command"in o.config?"stdio":"http"})`)),r("Subagents",e.subagents.map((o)=>`${s(o)} → ${o.name}`)),r("Skipped",e.skipped.map((o)=>`${s(o)} — ${o.reason}`)),n.length===0)return`No standards from other agent tools were found in this folder.
67
+ `;return`${n.join(`
68
+ `).trimEnd()}
69
+ `}var Gt={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 Required. Workspace (organization) id to act in","","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(`
70
+ `),supportsJson:!0,options:["base-url","workspace"],async run(e){let t=typeof e.flags.workspace==="string"?e.flags.workspace:e.env.HLIX_WORKSPACE_ID;if(!t)throw new h("missing_argument","--workspace is required.");let n=e.env.HLIX_API_KEY??await e.readSecret?.("Hlix API key: ")??"";if(!n)throw new h("missing_credential","No API key entered. Run from a terminal or set HLIX_API_KEY for CI.");let r=typeof e.flags["base-url"]==="string"?e.flags["base-url"]:e.env.HLIX_BASE_URL??Rt,s=new URL(r),o=s.hostname==="localhost"||s.hostname==="127.0.0.1"||s.hostname==="::1";if(s.protocol!=="https:"&&!(s.protocol==="http:"&&o))throw new h("invalid_base_url","--base-url must use HTTPS (HTTP is allowed only for localhost).");await new ze({baseUrl:r,credential:_e(n),organizationId:t,retry:{attempts:1}}).projects.list();let a=er({baseUrl:r,apiKey:n,organizationId:t},e.env);if(e.json)e.stdout(w(b(Gt.name,{baseUrl:r,organizationId:t,credentialPath:a})));else e.stdout(`Signed in to ${r}
71
+ Credential stored at ${a}
72
+ `);return 0}},Wt={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 environment or the stored file —","and verifies it against the API. The key itself is never printed, not even","a prefix: machine output gets piped into logs."].join(`
73
+ `),supportsJson:!0,async run(e){let t=D({env:e.env,flags:e.flags,cwd:e.cwd});if(t.conflict)throw new h("workspace_mismatch",t.conflict);if(!t.credential)throw new h("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");try{await e.requireClient().projects.list()}catch(r){throw e.stderr(`credential from ${t.credentialSource}, workspace ${t.workspaceId??"none"}, api ${t.baseUrl}
74
+ `),r}let n={credentialSource:t.credentialSource,credentialPath:t.credentialSource==="file"?t.credentialPath:null,baseUrl:t.baseUrl,baseUrlSource:t.baseUrlSource,workspaceId:t.workspaceId,workspaceSource:t.workspaceSource,valid:!0};if(e.json)return e.stdout(w(b(Wt.name,n))),0;return e.stdout(`${O([["credential",t.credentialSource==="env"?`environment (${t.credential?.sessionToken?"HLIX_SESSION_TOKEN":"HLIX_API_KEY"})`:`file (${t.credentialPath})`],["api",`${t.baseUrl} (from ${t.baseUrlSource})`],["workspace",t.workspaceId?`${t.workspaceId} (from ${t.workspaceSource})`:"none"],["status","valid"]])}
75
+ `),0}},he={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."].join(`
76
+ `),supportsJson:!0,options:["yes"],async run(e){let t=D({env:e.env,flags:e.flags,cwd:e.cwd});if(t.credentialSource==="env"){let r=Qn(e.env);if(!r){let o={removed:!1,reason:"environment",path:null};if(e.json)e.stdout(w(b(he.name,o)));else e.stdout(`HLIX_API_KEY is set in this environment; unset it there to sign out.
77
+ `);return 0}if(e.flags.yes!==!0){let o={removed:!1,reason:"environment",path:r};if(e.json)e.stdout(w(b(he.name,o)));else e.stdout(`HLIX_API_KEY is set in this environment; unset it there to sign out.
78
+ A stored credential also exists at ${r} — repeat with --yes to remove it.
79
+ `);return 0}let s=It(e.env);if(e.json)e.stdout(w(b(he.name,s)));else e.stdout(`Removed ${s.path}
80
+ HLIX_API_KEY is still set in this environment; unset it there to finish signing out.
81
+ `);return 0}if(e.flags.yes!==!0&&t.credential){if(e.json||!e.confirm)throw new h("approval_required","Removing the stored credential needs approval. Repeat with `--yes`.");if(!await e.confirm(`Remove the stored credential at ${t.credentialPath}? Signing back in needs the API key again.`))throw new h("cancelled","Logout cancelled.")}let n=It(e.env);if(e.json)e.stdout(w(b(he.name,n)));else e.stdout(n.removed?`Removed ${n.path}
82
+ `:`No stored credential at ${n.path}
83
+ `);return 0}};var Or=ge.join(" | "),Vt={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(`
84
+ `),supportsJson:!0,async run(e){let t=Dt(e.cwd,e.env),n=vr(t);if(e.json)return e.stdout(w(b(Vt.name,{settings:n,paths:t.paths}))),0;return e.stdout(`${X(["setting","value","source","applies to"],n.map((r)=>[r.key,r.value??"-",r.source,hr[r.key]??"this folder's binding"]))}
85
+ `),e.stdout(`
86
+ global ${t.paths.global}
87
+ `),e.stdout(`project ${t.paths.project??"- (this folder is not bound to hlix)"}
88
+ `),0}},Xt={name:"config get",summary:"Print one setting's effective value",usage:[`Usage: hlix config get <${Or}> [--cwd <dir>] [--json]`,"","Prints the value the cascade resolves for one key, or exits 1 when no","file names it."].join(`
89
+ `),supportsJson:!0,args:{min:1,max:1},async run(e){let t=Kt(e.args[0]),n=Dt(e.cwd,e.env),r=n.merged[t]??null,s=n.sources[t]??"default";if(e.json)return e.stdout(w(b(Xt.name,{key:t,value:r,source:s}))),r===null?1:0;if(r===null)return e.stderr(`${t} is not set. Set it with \`hlix config set ${t} <value>\`.
90
+ `),1;return e.stdout(`${r}
91
+ `),0}},Zt={name:"config set",summary:"Set one setting for this folder, or for the machine with --global",usage:[`Usage: hlix config set <${Or}> <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(`
92
+ `),supportsJson:!0,options:["global"],args:{min:2,max:2},async run(e){let t=Kt(e.args[0]),n=wr(t,e.args[1]),r=e.flags.global===!0?"global":"project",s=br({key:t,value:n,scope:r,cwd:e.cwd,env:e.env});if(e.json)return e.stdout(w(b(Zt.name,{key:t,value:n,scope:r,path:s}))),0;return e.stdout(`${t} = ${n} (${r}: ${s})
93
+ `),0}};function se(e,t){if(typeof e!=="object"||e===null)return"";let n=e[t];return n===null||n===void 0?"":String(n)}var Yt={name:"projects list",summary:"List the projects in your workspace",usage:"Usage: hlix projects list [--json]",supportsJson:!0,async run(e){let t=await e.requireClient().projects.list();if(e.json)return e.stdout(w(b(Yt.name,t))),0;let n=Array.isArray(t)?t:[];if(n.length===0)return e.stdout(`No projects.
94
+ `),0;return e.stdout(`${X(["ID","NAME","STACK"],n.map((r)=>[se(r,"id"),se(r,"name"),se(r,"stack")]))}
95
+ `),0}},Qt={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(`
96
+ `),supportsJson:!0,args:{min:0,max:1},async run(e){let t=e.args[0]??A(e.cwd)?.config.projectId;if(!t)throw new h("missing_argument","A project id is required, or run this inside a folder bound to a project.");let n=await e.requireClient().projects.get(t);if(e.json)return e.stdout(w(b(Qt.name,n))),0;let r=n.repos;return e.stdout(`${O([["id",se(n,"id")],["name",se(n,"name")],["stack",se(n,"stack")],["status",se(n,"status")],["repos",Array.isArray(r)?String(r.length):""]].filter(([,s])=>s!==""))}
97
+ `),0}};function en(e,t){let n=e.args[0];if(!n)throw new h("missing_argument",`A ${t} id is required.`);return n}function Ar(e,t){let n=e.flags[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function J(e,t){if(typeof e!=="object"||e===null)return"";let n=e[t];return n===null||n===void 0?"":String(n)}var tn={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(`
98
+ `),supportsJson:!0,options:["project","status"],async run(e){let t=Ar(e,"project")??A(e.cwd)?.config.projectId,n=Ar(e,"status"),r=await e.requireClient().tasks.list({...t?{projectId:t}:{},...n?{status:n}:{}});if(e.json)return e.stdout(w(b(tn.name,r))),0;let s=Array.isArray(r)?r:[];if(s.length===0)return e.stdout(`No tasks.
99
+ `),0;return e.stdout(`${X(["ID","STATUS","TITLE"],s.map((o)=>[J(o,"id"),J(o,"status"),J(o,"title")||J(o,"description").split(`
100
+ `)[0]||""]))}
101
+ `),0}},nn={name:"tasks get",summary:"Show one task",usage:"Usage: hlix tasks get <task-id> [--json]",supportsJson:!0,args:{min:1,max:1},async run(e){let t=en(e,"task"),n=await e.requireClient().tasks.get(t);if(e.json)return e.stdout(w(b(nn.name,n))),0;return e.stdout(`${O([["id",J(n,"id")],["status",J(n,"status")],["title",J(n,"title")],["project",J(n,"projectId")],["description",J(n,"description")]])}
102
+ `),0}},rn={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(e){let t=en(e,"task"),n=await e.requireClient().tasks.review(t);if(e.json)return e.stdout(w(b(rn.name,n))),0;return e.stdout(`${JSON.stringify(n,null,2)}
103
+ `),0}},sn={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(`
104
+ `),supportsJson:!0,args:{min:1,max:1},async run(e){let t=en(e,"task"),n=e.requireClient();for await(let r of n.tasks.stream(t)){let s;try{s=JSON.parse(r.data)}catch{s=r.data}if(e.json)e.stdout(`${JSON.stringify(b(sn.name,s))}
105
+ `);else{let o=J(s,"status"),i=J(s,"error");e.stdout(i?`error: ${i}
106
+ `:`${o||r.data}
107
+ `)}}return 0}};import{realpath as li}from"node:fs/promises";import{resolve as di}from"node:path";import{createHash as Jr}from"node:crypto";import{createReadStream as Fo}from"node:fs";import{lstat as qr,readFile as pt,readdir as No,realpath as Gr,stat as Ho}from"node:fs/promises";import{basename as ie,join as Wr,relative as Mr,resolve as Br,sep as Lo}from"node:path";import{spawnSync as Uo}from"node:child_process";import zr from"ignore";import{readFile as _o}from"node:fs/promises";import{join as To}from"node:path";function Ro(e){let t=e.trim();if(!t||/^[|>[{]/.test(t))return null;let n=t.match(/^(["'])([\s\S]*)\1$/);if(!n&&/^["']/.test(t))return null;return(n?n[2].trim():t.replace(/(?:^|\s)#.*$/,"").trim())||null}function Fr(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>/^tasks:\s*(?:#.*)?$/.test(i));if(n===-1)return{tasks:[],partial:/^tasks:\s*\S/m.test(e)};let r=[],s=!1,o=-1;for(let i of t.slice(n+1)){if(!i.trim()||/^\s*#/.test(i))continue;let a=i.length-i.trimStart().length,c=i.match(/^(\s*-(?:\s+|$))(.*)$/);if(c){if(o!==-1&&a>=o)continue;if(r.push({}),o=c[2]?c[1].length:-1,!c[2])continue}else if(a===0)break;else if(r.length===0)continue;else if(o===-1)o=a;else if(a!==o)continue;let l=(c?c[2]:i.trim()).match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);if(!l)continue;let p=l[1];if(p!=="name"&&p!=="before"&&p!=="init"&&p!=="command")continue;let u=Ro(l[2]);if(u===null)s=!0;else r[r.length-1][p]=u}return{tasks:r,partial:s}}async function oe(e,t){try{return await _o(To(e,...t.split("/")),"utf8")}catch(n){if(n.code==="ENOENT")return null;throw n}}function Nr(e){try{let t=e.replace(/(^|[^:\\])\/\/.*$/gm,"$1").replace(/\/\*[\s\S]*?\*\//g,"").replace(/,\s*([}\]])/g,"$1");return JSON.parse(t)}catch{return null}}function te(e){if(typeof e==="string"&&e.trim())return[e.trim()];if(Array.isArray(e))return e.flatMap(te);if(e&&typeof e==="object")return Object.values(e).flatMap(te);return[]}function on(e){if(!e||typeof e!=="object")return[];return Object.keys(e).filter((t)=>/^[A-Za-z_][A-Za-z0-9_]*$/.test(t))}function Oo(e,t){let n=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(t)r.push(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}/g);for(let s of r)for(let o of e.matchAll(s))n.add(o[1]);return[...n]}function Ao(e,t){if(e.has("bun.lock")||e.has("bun.lockb")||t?.startsWith("bun@"))return"bun install --frozen-lockfile";if(e.has("pnpm-lock.yaml")||t?.startsWith("pnpm@"))return"pnpm install --frozen-lockfile";if(e.has("yarn.lock")||t?.startsWith("yarn@"))return"yarn install --immutable";if(e.has("package-lock.json")||e.has("npm-shrinkwrap.json"))return"npm ci";if(e.has("package.json"))return"npm install";return null}function Hr(e){let t=typeof e==="number"?e:Number(e);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function B(e,t,n){if(!e.some((r)=>r.path===t&&r.kind===n))e.push({path:t,kind:n})}async function Lr(e,t,n){let r=[],s=[],o=[],i=[],a=new Map,c=new Set,l=new Set,p=[],u={},f=null,d=0,g=await oe(e,".cursor/environment.json");if(g){B(r,".cursor/environment.json","cursor");let y=Nr(g);if(!y)p.push("Could not parse .cursor/environment.json; it remains quarantined.");else{s.push(...te(y.install));let C=te(y.start);if(C[0])f=C[0];if(Array.isArray(y.terminals))for(let E of y.terminals){if(!E||typeof E!=="object")continue;let _=E;if(typeof _.command!=="string"||!_.command.trim())continue;i.push({name:typeof _.name==="string"&&_.name.trim()?_.name.trim():"Terminal",command:_.command.trim(),...typeof _.cwd==="string"&&_.cwd.trim()?{cwd:_.cwd.trim()}:{}})}}}let m=t.has(".devcontainer/devcontainer.json")?".devcontainer/devcontainer.json":t.has("devcontainer.json")?"devcontainer.json":null;if(m){B(r,m,"devcontainer");let y=Nr(n.get(m)??await oe(e,m)??"");if(!y)p.push(`Could not parse ${m}; it remains quarantined.`);else{s.push(...te(y.onCreateCommand),...te(y.updateContentCommand),...te(y.postCreateCommand));let C=te(y.postStartCommand);if(!f&&C[0])f=C[0];for(let E of on(y.secrets))c.add(E);for(let E of[...on(y.containerEnv),...on(y.remoteEnv)])c.add(E);if(Array.isArray(y.forwardPorts))for(let E of y.forwardPorts){let _=Hr(E);if(_)a.set(_,{port:_,visibility:"private"})}}}if(t.has(".gitpod.yml")){B(r,".gitpod.yml","gitpod");let y=n.get(".gitpod.yml")??await oe(e,".gitpod.yml");if(y===null)p.push("Could not read .gitpod.yml; its task commands were not imported.");else{let C=Fr(y);d=C.tasks.filter((E)=>E.before).length;for(let E of C.tasks){if(E.before)s.push(E.before);if(E.init)s.push(E.init);if(!E.command)continue;if(!f)f=E.command;else i.push({name:E.name??"Terminal",command:E.command})}if(C.partial)p.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 y of["Dockerfile","docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"])if(t.has(y))B(r,y,"docker");for(let y of["project.toml","nixpacks.toml","railpack.json","Aptfile"])if(t.has(y))B(r,y,"buildpack");for(let y of["fly.toml","railway.json","render.yaml","vercel.json","netlify.toml"])if(t.has(y))B(r,y,"platform");let k=n.get("package.json")??await oe(e,"package.json");if(k){B(r,"package.json","package");try{let y=JSON.parse(k);if(y.engines?.node)u.node=y.engines.node;let C=Ao(t,y.packageManager);if(C&&s.length===d)s.push(C);if(y.scripts?.build&&o.length===0)o.push(`${y.packageManager?.split("@")[0]??(t.has("bun.lock")?"bun":"npm")} run build`);let E=y.scripts?.dev?`${t.has("bun.lock")?"bun":"npm"} run dev`:null,_=y.scripts?.start?`${t.has("bun.lock")?"bun":"npm"} run start`:E;if(!f&&_)f=_}catch{p.push("Could not parse package.json for environment discovery.")}}if(t.has("uv.lock"))s.push("uv sync --frozen");else if(t.has("poetry.lock"))s.push("poetry install --no-interaction");else if(t.has("requirements.txt"))s.push("python -m pip install -r requirements.txt");if(t.has("go.mod"))s.push("go mod download");if(t.has("Procfile")){B(r,"Procfile","procfile");let C=(n.get("Procfile")??"").split(/\r?\n/).find((E)=>/^web\s*:/.test(E));if(C)f=C.replace(/^web\s*:\s*/,"").trim()||f}let R=[[".node-version","node"],[".nvmrc","node"],[".python-version","python"]];for(let[y,C]of R){let E=(n.get(y)??await oe(e,y))?.trim();if(E)u[C]=E,B(r,y,"tool-version")}let j=n.get(".tool-versions")??await oe(e,".tool-versions");if(j){B(r,".tool-versions","tool-version");for(let y of j.split(/\r?\n/)){let[C,E]=y.trim().split(/\s+/,2);if(!E)continue;if(C==="nodejs")u.node=E;else if(C==="python")u.python=E;else if(C==="bun")u.bun=E}}let F=n.get("mise.toml")??await oe(e,"mise.toml");if(F){B(r,"mise.toml","tool-version");for(let y of F.matchAll(/^\s*(node|python|bun)\s*=\s*["']([^"']+)["']/gm))u[y[1]]=y[2]}for(let[y,C]of n){let E=/(?:^|\/)(?:Dockerfile|Procfile)$/i.test(y)||/\.(?:jsonc?|ya?ml|toml|ini|conf|config|env|sh|bash|zsh|fish)$/i.test(y);for(let _ of Oo(C,E))l.add(_);for(let _ of C.matchAll(/(?:--port(?:=|\s+)|PORT\s*=\s*)(\d{2,5})/g)){let q=Hr(_[1]);if(q)a.set(q,{port:q,visibility:"private"})}}if(r.length===0&&t.size>0)B(r,"repository","detected");let H=(y)=>[...new Set(y.filter(Boolean))],be=r.length+s.length+(f?1:0);return{sources:r.sort((y,C)=>y.path.localeCompare(C.path)),toolchain:u,install:H(s),build:H(o),start:f,terminals:i,ports:[...a.values()].sort((y,C)=>y.port-C.port),requiredSecretKeys:[...c].sort(),observedSecretKeys:[...l].sort(),confidence:be>=4?"high":be>=2?"medium":"low",warnings:p}}var Ur=2;var Mo=25000,Bo=52428800,zo=524288000,ut=1e4,dt=1048576,ye=10485760,Dr=[".git/",".hlix/","node_modules/",".next/",".turbo/",".cache/","dist/","build/","coverage/","__pycache__/",".venv/","venv/","target/",".DS_Store"],ln="Required project environment value was not found locally: ",Do=/(^|\/)\.env\.(example|sample|template)$/i,Ko=/(^|\/)\.env(?:\.[^/]+)?$/i,Jo=/(^|\/)(?:\.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)|terraform\.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,qo=/(^|\/)(?:\.mcp\.json|mcp\.json|claude_desktop_config\.json)$/i,Go=/(^|\/)(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.github\/copilot-instructions\.md)$/i,Wo=/(^|\/)(?:\.agents|\.claude)\/skills\//i,Vo=/-----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,}/,Xo=/\.(?:json|ya?ml|toml|ini|conf|config)$/i,Zo=/(?:^|[,{\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,Je=/^HLIX_[A-Za-z0-9_]*$/,an=new Set(["CI","HOME","LANG","LOGNAME","NODE_ENV","OLDPWD","PATH","PORT","PWD","SHELL","SHLVL","TERM","TMPDIR","USER","_"]);function qe(e){return e.split(Lo).join("/")}function ne(e,t,n=10485760){return Uo("git",["-C",e,...t],{encoding:"utf8",maxBuffer:n,stdio:["ignore","pipe","pipe"]})}async function Yo(e){let t=Jr("sha256");for await(let n of Fo(e))t.update(n);return t.digest("hex")}function cn(e){if(Array.isArray(e))return`[${e.map(cn).join(",")}]`;if(e&&typeof e==="object")return`{${Object.entries(e).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>`${JSON.stringify(t)}:${cn(n)}`).join(",")}}`;return JSON.stringify(e)}function mt(e){let t={};for(let[n,r]of String(e).replace(/^\uFEFF/,"").split(/\r?\n/).entries()){let s=r.trim();if(!s||s.startsWith("#"))continue;let i=(s.startsWith("export ")?s.slice(7).trimStart():s).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!i)throw Error(`Invalid dotenv assignment on line ${n+1}`);let a=i[2]??"";if(a.startsWith('"')){if(!a.endsWith('"'))throw Error(`Unclosed dotenv quote on line ${n+1}`);a=a.slice(1,-1).replace(/\\n/g,`
108
+ `).replace(/\\r/g,"\r")}else if(a.startsWith("'")){if(!a.endsWith("'"))throw Error(`Unclosed dotenv quote on line ${n+1}`);a=a.slice(1,-1)}else a=a.replace(/\s+#.*$/,"").trimEnd();t[i[1]]=a}return t}function Qo(e){let t=null;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&t!=="single"){if(e[n+1]!=="$")return!0;n+=1;continue}if(r==="'"&&t!=="double"){t=t==="single"?null:"single";continue}if(r==='"'&&t!=="single"){t=t==="double"?null:"double";continue}if(t!=="single"&&(r==="$"||r==="`"))return!0;if(t===null&&(r==="<"||r===">")&&e[n+1]==="(")return!0}return t!==null}function dn(e){let t={},n=new Set,r=new Set;for(let s of String(e).replace(/^\uFEFF/,"").split(/\r?\n/)){let o=s.trim();if(!o||o.startsWith("#"))continue;let a=(o.startsWith("export ")?o.slice(7).trimStart():o).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!a)continue;let c=a[1],l=a[2]??"";if(n.add(c),Qo(l)){delete t[c],r.add(c);continue}try{let u=mt(`${c}=${l}`)[c];if(u===void 0)throw Error("missing literal");t[c]=l.trimStart().startsWith("'")?u:u.replace(/\\\$/g,"$"),r.delete(c)}catch{delete t[c],r.add(c)}}return{values:t,keys:[...n].sort(),dynamicKeys:[...r].sort()}}async function ei(e){let t=ne(e,["rev-parse","--show-toplevel"]);if(t.status!==0)return!1;try{return await Gr(t.stdout.trim())===e}catch{return!1}}function ti(e,t){if(!t)return new Set;let n=ne(e,["ls-files","-z"]);if(n.status!==0)throw Error("Could not enumerate tracked files.");return new Set(n.stdout.split("\x00").filter(Boolean).map(qe))}async function ni(e){let t=zr().add(Dr),n=zr().add(Dr);for(let r of[".gitignore",".hlixignore"])try{let s=Wr(e,r);if((await qr(s)).isFile())n.add(await pt(s,"utf8"))}catch(s){if(s.code!=="ENOENT")throw s}return{hardMatcher:t,matcher:n}}function ri(e){if(qo.test(e))return"mcp";if(Wo.test(e))return"skill";if(Go.test(e))return"agent";return null}function si(e){if(Ko.test(e)&&!Do.test(e))return"dotenv";if(Jo.test(e))return"credential";return null}function oi(e){if(e.has("package.json"))return"typescript";if(e.has("pyproject.toml")||e.has("requirements.txt"))return"python";if(e.has("go.mod"))return"go";if(e.has("Cargo.toml"))return"rust";if(e.has("composer.json"))return"php";if(e.has("Gemfile"))return"ruby";return"other"}function ii(e,t){if(t)return[qe(t)];let n=new Map([[".env",0],[".env.development",1],[".env.local",2],[".env.development.local",3]]),r=e.filter((s)=>n.has(ie(s).toLocaleLowerCase("en-US"))).sort((s,o)=>s.slice(0,-ie(s).length).localeCompare(o.slice(0,-ie(o).length))||n.get(ie(s).toLocaleLowerCase("en-US"))-n.get(ie(o).toLocaleLowerCase("en-US")));return r.length>0?r:e.length===1?[...e]:[]}function ai(e,t){try{let n=JSON.parse(t);if(!n.mcpServers||typeof n.mcpServers!=="object")return[];return Object.entries(n.mcpServers).map(([r,s])=>{let o=s&&typeof s==="object"?s:{},i=o.type==="http"||o.type==="sse"||o.type==="stdio"?o.type:typeof o.command==="string"?"stdio":typeof o.url==="string"?"http":"unknown",a=o.env&&typeof o.env==="object"?o.env:{};return{sourcePath:e,name:r,transport:i,...typeof o.command==="string"?{command:o.command}:{},...Array.isArray(o.args)&&o.args.every((c)=>typeof c==="string")?{args:o.args}:{},...typeof o.url==="string"?{url:o.url}:{},envKeys:Object.keys(a).sort(),enabled:!1}})}catch{return[]}}function Kr(e,t){let n=[],r="unknown";for(let s of e.split(/\r?\n/)){if(s.startsWith("@@"))r=s.slice(2);else if(s.trim())n.push({commit:r,path:qe(s.trim()),reason:t});if(n.length>=100)break}return n}function ci(e,t){if(!t)return{head:null,branch:null,refs:[],commitCount:0,complete:!0,findings:[]};let n=ne(e,["rev-parse","HEAD"]).stdout.trim()||null,r=ne(e,["symbolic-ref","--short","-q","HEAD"]),s=r.status===0?r.stdout.trim()||null:null,o=Number.parseInt(ne(e,["rev-list","--count","--all"]).stdout.trim(),10)||0,i=ne(e,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]),a=i.stdout.split(`
109
+ `).filter(Boolean).map((f)=>{let[d,g]=f.split("\x00");return{name:d,oid:g}}).filter(({name:f,oid:d})=>/^refs\/(?:heads|tags)\/.+/.test(f)&&/^[0-9a-f]{40,64}$/.test(d)).sort((f,d)=>f.name.localeCompare(d.name)),c=["log","--all",`--max-count=${ut}`,"--pretty=format:@@%H","--name-only"],l=ne(e,[...c,"--",".env",".env.*","*.pem","*.key",".npmrc","*.tfvars"]),p=ne(e,["log","--all",`--max-count=${ut}`,"-G","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,}","--pretty=format:@@%H","--name-only"]),u=new Map;for(let f of[...Kr(l.stdout,"sensitive-path"),...Kr(p.stdout,"secret-pattern")])u.set(`${f.commit}:${f.path}:${f.reason}`,f);return{head:n,branch:s,refs:a,commitCount:o,complete:o<=ut&&a.length<=1000&&i.status===0&&l.status===0&&p.status===0,findings:[...u.values()].slice(0,100)}}async function G(e,t={}){let n=await Gr(Br(e));if(!(await Ho(n)).isDirectory())throw Error("Import target must be a directory.");let r=await ei(n),s=ti(n,r),{hardMatcher:o,matcher:i}=await ni(n),a=[],c=[],l=[],p=[],u=[],f=[],d=t.envFile?qe(Mr(n,Br(n,t.envFile))):void 0,g=d!==void 0&&d!==""&&d!==".."&&!d.startsWith("../");if(t.envFile&&!g)f.push(`Selected environment file must stay inside the project: ${t.envFile}`);let m=new Map,k=new Map,R=new Map,j=new Map,F=[],H=[],be=new Map,y=t.maxFiles??Mo,C=t.maxFileBytes??Bo,E=t.maxTotalBytes??zo,_=0,q=0,Bn=async(v)=>{let P=await No(v,{withFileTypes:!0});P.sort((T,L)=>T.name.localeCompare(L.name));for(let T of P){let L=Wr(v,T.name),I=qe(Mr(n,L));if(T.name===".git"){if(I!==".git")f.push(`Nested Git repository is not supported: ${I}`);continue}let z=await qr(L),Jn=T.isDirectory()?`${I}/`:I,Et=s.has(I),qn=!Et&&i.ignores(Jn),bs=!Et&&o.ignores(Jn);if(z.isSymbolicLink()){if(u.push({path:I,reason:"symlink"}),!qn)f.push(`Symlinks are not imported in this release: ${I}`);continue}if(T.isDirectory()){if(bs)continue;await Bn(L);continue}let ke=ri(I),je=si(I);if(qn&&!ke&&!je)continue;if(!T.isFile()){u.push({path:I,reason:"non-regular-file"});continue}if(a.length+c.length+l.length>=y){f.push(`Project exceeds the ${y} file limit.`);return}if(z.size>C){f.push(`File exceeds the ${C} byte limit: ${I}`);continue}if(_+=z.size,_>E){f.push(`Project exceeds the ${E} byte total limit.`);return}let tt=await Yo(L);if(ke){if(z.size>dt){f.push(`Protected configuration exceeds the ${dt} byte limit: ${I}`);continue}let U=await pt(L);if(q+=U.byteLength,q>ye){f.push(`Protected project files exceed the ${ye} byte total limit.`);continue}if(l.push({path:I,kind:ke,size:z.size,sha256:tt}),H.push({path:I,kind:ke,contentBase64:U.toString("base64")}),ke==="mcp")p.push(...ai(I,U.toString("utf8")));continue}if(je){if(z.size>dt){f.push(`Protected file exceeds the ${dt} byte limit: ${I}`);continue}let U=await pt(L);if(q+=U.byteLength,q>ye){f.push(`Protected project files exceed the ${ye} byte total limit.`);continue}let re=[];if(je==="dotenv")try{let nt=mt(U),ce={};for(let[ee,le]of Object.entries(nt)){if(Je.test(ee)){f.push(`Hlix control-plane environment keys cannot be imported into a project: ${ee}`);continue}ce[ee]=le}m.set(I,ce),re=Object.keys(ce).sort()}catch{f.push(`Could not parse environment file: ${I}`)}else if(ie(I)===".envrc"){let nt=dn(U),ce={},ee=new Set,le=[];for(let[N,Ss]of Object.entries(nt.values)){if(Je.test(N)){f.push(`Hlix control-plane environment keys cannot be imported into a project: ${N}`);continue}if(an.has(N)){F.push(`Ignored ambient runtime assignment in ${I}: ${N}`);continue}ee.add(N),ce[N]=Ss}k.set(I,ce);for(let N of nt.dynamicKeys){if(Je.test(N)){f.push(`Hlix control-plane environment keys cannot be imported into a project: ${N}`);continue}if(an.has(N)){F.push(`Ignored ambient runtime assignment in ${I}: ${N}`);continue}ee.add(N),le.push(N)}if(R.set(I,[...ee].sort()),j.set(I,le.sort()),re=[...ee].sort(),le.length>0)F.push(`Did not execute dynamic .envrc assignments; collect their resolved local values when available: ${le.join(", ")}`)}c.push({path:I,kind:je,keys:re,size:z.size,sha256:tt}),H.push({path:I,kind:je,contentBase64:U.toString("base64")});continue}if(z.size<=1048576){let U=await pt(L),re=U.toString("utf8");if(be.set(I,re),Vo.test(re)||Xo.test(I)&&Zo.test(re)){if(q+=U.byteLength,q>ye){f.push(`Protected project files exceed the ${ye} byte total limit.`);continue}c.push({path:I,kind:"detected-content",keys:[],size:z.size,sha256:tt}),H.push({path:I,kind:"detected-content",contentBase64:U.toString("base64")});continue}}a.push({path:I,size:z.size,sha256:tt,tracked:Et,executable:(z.mode&73)!==0})}};await Bn(n),a.sort((v,P)=>v.path.localeCompare(P.path)),c.sort((v,P)=>v.path.localeCompare(P.path)),l.sort((v,P)=>v.path.localeCompare(P.path)),p.sort((v,P)=>`${v.sourcePath}:${v.name}`.localeCompare(`${P.sourcePath}:${P.name}`));let bt=ii([...m.keys()].sort(),g?d:void 0);if(t.envFile&&g&&!m.has(bt[0]))f.push(`Selected environment file was not found or is not a dotenv file: ${t.envFile}`);let Se=new Map;for(let[v,P]of m)for(let T of Object.keys(P))Se.set(T,[...Se.get(T)??[],v]);for(let[v,P]of R)for(let T of P)Se.set(T,[...Se.get(T)??[],v]);let gs=[...Se].filter(([,v])=>v.length>1).map(([v,P])=>({key:v,paths:P.sort()})).sort((v,P)=>v.key.localeCompare(P.key)),W={};for(let v of bt)Object.assign(W,m.get(v)??{});let hs=[...k.keys()].sort((v,P)=>{if(v===".envrc")return 1;if(P===".envrc")return-1;return v.localeCompare(P)}),St=new Set;for(let v of hs){let P=new Set(j.get(v)??[]);for(let T of R.get(v)??[]){if(P.has(T)){delete W[T],St.add(T);continue}let L=k.get(v)?.[T];if(L!==void 0)W[T]=L;St.delete(T)}}let kt=t.historyMode??"abort_on_findings",Q=ci(n,r);if(!Q.complete&&kt!=="preserve")f.push(`Git history scan exceeded ${ut} commits or failed; import requires explicit --history preserve.`);if(Q.findings.length>0&&kt==="abort_on_findings")f.push("Potential secrets exist in Git history. Abort, sanitize the repository, or explicitly use --history preserve.");let zn=new Set(a.map((v)=>v.path)),ys=await Lr(n,zn,be),{observedSecretKeys:vs,...V}=ys;V.warnings.push(...F);let jt=new Set(V.requiredSecretKeys);for(let v of St)jt.add(v);for(let v of p)for(let P of v.envKeys)jt.add(P);V.requiredSecretKeys=[...jt].sort();for(let v of V.requiredSecretKeys){if(Je.test(v)){f.push(`Hlix control-plane environment keys cannot be imported into a project: ${v}`);continue}if(W[v]!==void 0)continue;let P=t.environment?.[v];if(P===void 0){f.push(`${ln}${v}`);continue}W[v]=P}for(let v of vs){if(Je.test(v)){V.warnings.push(`Ignored reserved Hlix control-plane environment reference: ${v}`);continue}if(an.has(v))continue;if(W[v]!==void 0)continue;let P=t.environment?.[v];if(P===void 0){V.warnings.push(`Observed environment reference has no local value: ${v}`);continue}W[v]=P}V.warnings=[...new Set(V.warnings)].sort();let Dn={schemaVersion:Ur,rootName:t.rootName??ie(n),stack:oi(zn),git:{detected:r,head:Q.head,branch:Q.branch,refs:Q.refs,commitCount:Q.commitCount,historyScanComplete:Q.complete,historyMode:kt},files:a,secretFiles:c,activeEnvFiles:bt,secretKeys:Object.keys(W).sort(),envCollisions:gs,quarantinedResources:l,mcpServers:p,historicalSecretFindings:Q.findings,skipped:u,environment:V,totals:{files:a.length,bytes:a.reduce((v,P)=>v+P.size,0)}},Kn=cn(Dn),ws=Jr("sha256").update(Kn).digest("hex");return{root:n,manifest:Dn,manifestJson:Kn,manifestSha256:ws,secretValues:W,protectedFiles:H.sort((v,P)=>v.path.localeCompare(P.path)),blocking:[...new Set(f)]}}var pn={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`)"].join(`
110
+ `),supportsJson:!0,options:["project"],args:{min:0,max:1},async run(e){if(e.args.length>1)throw Error("init accepts at most one folder.");let t=await li(di(e.cwd,e.args[0]??".")),n=D({env:e.env,flags:e.flags,cwd:t});if(n.conflict)throw new h("workspace_mismatch",n.conflict);if(!n.workspaceId)throw Error("No workspace selected. Run `hlix auth login --workspace <id>` first.");let r=e.requireClient(t);await r.projects.list();let s=pe(t),o=typeof e.flags.project==="string"?e.flags.project:void 0;if(o&&s?.projectId&&s.projectId!==o)throw new h("workspace_mismatch",`This folder is bound to project ${s.projectId}; refusing to rebind it to ${o}.`);if(o)await r.projects.get(o);let i={...s??{schemaVersion:1,workspaceId:n.workspaceId,apiUrl:n.baseUrl},...o?{projectId:o}:{}};xe(t,i);let a=await G(t,{environment:e.env}),c={root:t,config:i,scan:{files:a.manifest.totals.files,bytes:a.manifest.totals.bytes,secretFiles:a.manifest.secretFiles.map((l)=>l.path),quarantinedResources:a.manifest.quarantinedResources.map((l)=>l.path),blocking:a.blocking}};if(e.json)e.stdout(w(b(pn.name,c)));else if(e.stdout(`Initialized ${t}
111
+ Project: ${i.projectId??"not imported yet"}
112
+ Workspace: ${i.workspaceId}
113
+ `),a.blocking.length)e.stdout(`
114
+ Review before import:
115
+ ${a.blocking.map((l)=>`- ${l}`).join(`
116
+ `)}
117
+ `);return 0}};import{createHash as wi}from"node:crypto";import{readFile as bi,realpath as Si}from"node:fs/promises";import{basename as ki,resolve as ji}from"node:path";import{createHash as pi}from"node:crypto";import{createReadStream as ui}from"node:fs";import{chmod as un,copyFile as mi,lstat as Vr,mkdir as Xr,mkdtemp as fi,readdir as gi,rm as mn}from"node:fs/promises";import{tmpdir as hi}from"node:os";import{dirname as yi,join as ae}from"node:path";import{spawnSync as Ge}from"node:child_process";function Z(e,t){let n=Ge("git",["-C",e,...t],{encoding:"utf8",maxBuffer:20971520,stdio:["ignore","pipe","pipe"]});if(n.status!==0){let r=n.stderr.trim().split(`
118
+ `).at(-1)??"git command failed";throw Error(r)}return n.stdout.trim()}async function Zr(e){let t=pi("sha256");for await(let n of ui(e))t.update(n);return t.digest("hex")}async function vi(e){for(let t of await gi(e)){if(t===".git")continue;await mn(ae(e,t),{recursive:!0,force:!0})}}async function ft(e){if(e.blocking.length>0)throw Error(`Project scan has blocking findings:
119
+ - ${e.blocking.join(`
120
+ - `)}`);let t=await fi(ae(hi(),"hlix-snapshot-"));await un(t,448);let n=ae(t,"repo"),r=ae(t,"source.git"),s=ae(t,"project.bundle");try{if(e.manifest.git.detected){let u=Ge("git",["clone","--mirror","--no-hardlinks",e.root,r],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(u.status!==0)throw Error(u.stderr.trim()||"Could not mirror repository.");let f=new Map(Z(r,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]).split(`
121
+ `).filter(Boolean).map((g)=>g.split("\x00",2)));for(let g of e.manifest.git.refs)if(f.get(g.name)!==g.oid)throw Error(`Git ref changed after scan: ${g.name}`);let d=Ge("git",["clone","--no-hardlinks",r,n],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(d.status!==0)throw Error(d.stderr.trim()||"Could not create snapshot clone.");if(!e.manifest.git.head)throw Error("Git repository has no HEAD commit.");Z(n,["checkout","-B","main",e.manifest.git.head])}else await Xr(n,{recursive:!0,mode:448}),Z(n,["init","-b","main"]);await vi(n);for(let u of e.manifest.files){let f=ae(e.root,...u.path.split("/")),d=await Vr(f);if(!d.isFile()||d.isSymbolicLink())throw Error(`Source changed after scan: ${u.path}`);if(d.size!==u.size||await Zr(f)!==u.sha256)throw Error(`Source changed after scan: ${u.path}`);let g=ae(n,...u.path.split("/"));await Xr(yi(g),{recursive:!0,mode:493}),await mi(f,g),await un(g,u.executable?493:420)}Z(n,["config","user.name","Hlix Import"]),Z(n,["config","user.email","import@hlix.ai"]),Z(n,["add","-A"]),Z(n,["commit","--allow-empty","-m","chore(hlix): import snapshot"]);let o=Z(n,["rev-parse","HEAD"]),i=e.manifest.git.refs.filter((u)=>u.name!=="refs/heads/main");if(i.length>0){let u=Ge("git",["-C",n,"update-ref","--stdin"],{encoding:"utf8",input:i.map((f)=>`update ${f.name} ${f.oid}`).join(`
122
+ `)+`
123
+ `,stdio:["pipe","pipe","pipe"]});if(u.status!==0)throw Error(u.stderr.trim()||"Could not recreate the approved Git refs.")}let a=i.map((u)=>u.name),c=Ge("git",["-C",n,"bundle","create",s,"--stdin"],{encoding:"utf8",input:["refs/heads/main",...a].join(`
124
+ `)+`
125
+ `,stdio:["pipe","pipe","pipe"]});if(c.status!==0)throw Error(c.stderr.trim()||"Could not create the approved Git bundle.");Z(n,["bundle","verify",s]),await un(s,384);let l=(await Vr(s)).size,p=await Zr(s);return{bundlePath:s,bundleSha256:p,bundleSize:l,commitSha:o,dispose:()=>mn(t,{recursive:!0,force:!0})}}catch(o){throw await mn(t,{recursive:!0,force:!0}),o}}function We(e,t){let n=e[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function Ei(e,t){return wi("sha256").update(`project-import-v1\x00${e}\x00${t}`).digest("hex")}function Pi(e){let t=e.manifest.environment.install,n=e.manifest.secretFiles.length+e.manifest.quarantinedResources.length;if(t.length===0&&n===0&&e.manifest.secretKeys.length===0)return null;let r=["Hlix will upload this project and encrypted protected files to your selected workspace."];if(t.length>0)r.push("Detected cloud setup commands:",...t.map((s)=>`- ${s}`));if(e.manifest.secretKeys.length>0)r.push("Project secret keys available to cloud tasks:",...e.manifest.secretKeys.map((s)=>`- ${s}`));if(e.manifest.quarantinedResources.length>0)r.push("Quarantined resources (preserved but not activated):",...e.manifest.quarantinedResources.map((s)=>`- ${s.kind}: ${s.path}`));if(e.manifest.environment.warnings.length>0)r.push("Environment warnings:",...e.manifest.environment.warnings.map((s)=>`- ${s}`));return r.push("Setup runs inside the isolated Coding Workspace and may access project secrets."),r.join(`
126
+ `)}var gt={name:"import",summary:"Import a local project into your Hlix workspace",usage:["Usage: hlix import [folder] [options]","","Options:"," --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)"," --stack <stack> Override detected stack"," --yes Approve the reviewed upload and cloud setup"," --json Machine-readable output (never contains secret values)"].join(`
127
+ `),supportsJson:!0,options:["dry-run","env-file","history","name","stack","yes"],args:{min:0,max:1},async run(e){if(e.args.length>1)throw Error("import accepts at most one folder.");let t=await Si(ji(e.cwd,e.args[0]??".")),n=D({env:e.env,flags:e.flags,cwd:t});if(n.conflict)throw new h("workspace_mismatch",n.conflict);if(!n.workspaceId||!n.credential)throw new h("workspace_required","No workspace selected. Run `hlix auth login --workspace <id>` first.");let r=pe(t);if(r?.projectId)throw new h("already_imported","This folder is already bound to an Hlix project. Use `hlix push`.");let s=We(e.flags,"history");if(s&&s!=="preserve"&&s!=="abort-on-findings")throw Error("--history must be `abort-on-findings` or `preserve`.");if(!r&&e.flags["dry-run"]!==!0)xe(t,{schemaVersion:1,workspaceId:n.workspaceId,apiUrl:n.baseUrl});let o=await G(t,{...We(e.flags,"env-file")?{envFile:We(e.flags,"env-file")}:{},environment:e.env,historyMode:s==="preserve"?"preserve":"abort_on_findings"});if(e.flags["dry-run"]!==!0&&o.blocking.length===0){let c=Pi(o);if(c&&e.flags.yes!==!0){if(e.json||!e.confirm)throw new h("approval_required","Import needs approval for protected files or cloud setup. Review with `hlix import --dry-run`, then repeat with `--yes`.");if(!await e.confirm(c))throw new h("cancelled","Import cancelled.")}}let i={root:t,name:We(e.flags,"name")??ki(t),stack:We(e.flags,"stack")??o.manifest.stack,files:o.manifest.totals.files,bytes:o.manifest.totals.bytes,activeEnvFiles:o.manifest.activeEnvFiles,secretKeys:o.manifest.secretKeys,protectedFiles:o.manifest.secretFiles.length+o.manifest.quarantinedResources.length,environment:o.manifest.environment,historicalSecretFindings:o.manifest.historicalSecretFindings,quarantinedResources:o.manifest.quarantinedResources,mcpServers:o.manifest.mcpServers,skipped:o.manifest.skipped,blocking:o.blocking,manifestSha256:o.manifestSha256};if(e.flags["dry-run"]===!0){if(e.json)e.stdout(w(b(gt.name,i)));else{let c=[...o.manifest.secretFiles.map((l)=>`${l.kind}: ${l.path}`),...o.manifest.quarantinedResources.map((l)=>`${l.kind}: ${l.path}`)];e.stdout([`Project: ${i.name}`,`Stack: ${i.stack}`,`Files: ${i.files}`,`Bytes: ${i.bytes}`,`Environment confidence: ${i.environment.confidence}`,`History findings: ${i.historicalSecretFindings.length}`,"","Environment evidence:",...i.environment.sources.length?i.environment.sources.map((l)=>`- ${l.kind}: ${l.path}`):["- none detected"],"","Cloud setup commands:",...i.environment.install.length?i.environment.install.map((l)=>`- ${l}`):["- none detected"],"","Required secret keys:",...i.environment.requiredSecretKeys.length?i.environment.requiredSecretKeys.map((l)=>`- ${l}`):["- none detected"],"","Collected secret keys:",...i.secretKeys.length?i.secretKeys.map((l)=>`- ${l}`):["- none detected"],"","Protected and quarantined paths:",...c.length?c.map((l)=>`- ${l}`):["- none"],"","Environment warnings:",...i.environment.warnings.length?i.environment.warnings.map((l)=>`- ${l}`):["- none"],...i.blocking.length?["","Blocking findings:",...i.blocking.map((l)=>`- ${l}`)]:[]].join(`
128
+ `)+`
129
+ `)}return o.blocking.length?1:0}if(o.blocking.length)throw new h("scan_blocked",`Project scan blocked import:
130
+ - ${o.blocking.join(`
131
+ - `)}`);let a=await ft(o);try{let c=e.requireClient(t),l=await c.imports.create({idempotencyKey:Ei(o.manifestSha256,a.bundleSha256),name:i.name,stack:i.stack,defaultBranch:"main",historyMode:o.manifest.git.historyMode,manifest:o.manifest,manifestSha256:o.manifestSha256,bundleSha256:a.bundleSha256,bundleSize:a.bundleSize,commitSha:a.commitSha});if(l.import.status==="pending_upload"){if(!l.upload)throw Error(`Import ${l.import.id} is ${l.import.status} but has no upload target.`);await c.imports.uploadBundle(l.upload,new Blob([Uint8Array.from(await bi(a.bundlePath))]),{onProgress:(g,m)=>{if(!e.json)e.stderr(`Uploading ${g}/${m} bytes\r`)}})}let u=(l.import.status==="ready"?{import:l.import}:await c.imports.finalize(l.import.id,{secrets:o.secretValues,protectedFiles:o.protectedFiles})).import,f=u.projectId??u.requestedProjectId;if(!f||!u.revisionId||!u.generation)throw Error("Import completed without project revision metadata.");xe(t,{schemaVersion:1,projectId:f,workspaceId:n.workspaceId,apiUrl:n.baseUrl}),Re(t,{schemaVersion:1,revisionId:u.revisionId,generation:u.generation,commitSha:a.commitSha,manifestSha256:o.manifestSha256,historyMode:o.manifest.git.historyMode,rootName:o.manifest.rootName});let d={projectId:f,revisionId:u.revisionId,generation:u.generation,commitSha:a.commitSha,files:o.manifest.totals.files,bytes:o.manifest.totals.bytes};if(e.json)e.stdout(w(b(gt.name,d)));else e.stderr(`
132
+ `),e.stdout(`Imported ${i.name}
133
+ Project ID: ${f}
134
+ Revision: ${u.generation}
135
+ `);return 0}finally{await a.dispose()}}};var fn={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(`
136
+ `),supportsJson:!0,async run(e){let t=Rr(e.cwd,$r(e.env),{env:e.env});if(e.json)return e.stdout(w(b(fn.name,{instructions:t.instructions.map((n)=>({path:n.path,source:n.source,scope:n.scope,characters:n.content.length,...n.note?{note:n.note}:{}})),skills:t.skills,commands:[...t.commands.map((n)=>({path:n.path,source:n.source,scope:n.scope})),...t.generatedCommands.map((n)=>({path:n.path,source:n.source,scope:n.scope,command:n.name}))],mcpServers:t.mcpServers.map((n)=>({path:n.path,source:n.source,scope:n.scope,name:n.name,transport:"command"in n.config?"stdio":"http"})),subagents:t.subagents.map((n)=>({path:n.path,source:n.source,scope:n.scope,name:n.name,description:n.description,...n.model?{model:n.model}:{}})),skipped:t.skipped}))),0;return e.stdout(Tr(t,e.cwd)),0}};var Ci=(e)=>e instanceof Error?e.message:String(e);async function $i(e,t,n,r,s){try{let o=await G(t,{historyMode:n,environment:e.env,rootName:r});return{files:o.manifest.totals.files,manifestSha256:o.manifestSha256,changed:s?o.manifestSha256!==s:null,blocking:o.blocking,error:null}}catch(o){return{files:null,manifestSha256:null,changed:null,blocking:[],error:Ci(o)}}}var gn={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(`
137
+ `),supportsJson:!0,async run(e){let t=D({env:e.env,flags:e.flags,cwd:e.cwd}),n=t.binding,r=n?at(n.root):null,s=n?await $i(e,n.root,r?.historyMode??"preserve",r?.rootName,r?.manifestSha256):null,o=null;if(n?.config.projectId&&t.credential&&!t.conflict)try{let c=(await e.requireClient().revisions.head(n.config.projectId)).revision;o={revisionId:c.id,generation:c.generation,changed:r?c.id!==r.revisionId||c.generation!==r.generation:null,error:null}}catch(c){o={revisionId:"",generation:0,changed:null,error:Mt(c).code}}let i={cwd:e.cwd,workspace:{id:t.workspaceId,source:t.workspaceSource},api:{baseUrl:t.baseUrl,source:t.baseUrlSource},credential:{present:t.credential!==null,source:t.credentialSource,path:t.credentialPath},conflict:t.conflict,project:n?{root:n.root,projectId:n.config.projectId??null,workspaceId:n.config.workspaceId,apiUrl:n.config.apiUrl}:null,revision:r?{id:r.revisionId,generation:r.generation,commitSha:r.commitSha}:null,local:s,cloud:o};if(e.json)return e.stdout(w(b(gn.name,i))),0;let a=[["folder",e.cwd],["workspace",t.workspaceId?`${t.workspaceId} (from ${t.workspaceSource})`:"none — run `hlix auth login --workspace <id>`"],["api",`${t.baseUrl} (from ${t.baseUrlSource})`],["credential",t.credential?t.credentialSource==="env"?`environment (${t.credential?.sessionToken?"HLIX_SESSION_TOKEN":"HLIX_API_KEY"})`:`file (${t.credentialPath})`:"none — run `hlix auth login`"],["project",n?n.config.projectId??`initialized at ${n.root}, not imported yet`:"none — run `hlix import .` to bind this folder"]];if(r)a.push(["revision",`generation ${r.generation} (${r.revisionId})`]);if(s){if(a.push(["local",s.error?`could not scan: ${s.error}`:s.changed===null?`${s.files} files, no synced base revision`:s.changed?`${s.files} files, modified since the last sync`:`${s.files} files, matches the last sync`]),s.blocking.length>0)a.push(["blocking",s.blocking.join("; ")])}if(o)a.push(["cloud",o.error?`not checked: ${o.error}`:o.changed?`generation ${o.generation} available — run \`hlix pull\``:`generation ${o.generation}, up to date`]);if(t.conflict)a.push(["conflict",t.conflict]);return e.stdout(`${O(a)}
138
+ `),0}};import{spawnSync as Yr}from"node:child_process";var hn={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(`
139
+ `),supportsJson:!0,options:["print","web"],args:{min:0,max:1},async run(e){let t=e.args[0]??A(e.cwd)?.config.projectId;if(!t)throw new h("missing_argument","A project id is required, or run this inside a folder bound to a project.");let n=await e.requireClient().projects.terminal(t);if(e.json)return e.stdout(w(b(hn.name,n))),n.available?0:1;if(!n.available){let i=n.environmentState?` (environment: ${n.environmentState})`:"";throw new h("not_found",`${n.reason??"Terminal unavailable"}${i}`)}let r=e.flags.print===!0,s=e.flags.web===!0;if(r||s&&!n.webTerminalUrl||!s&&!n.sshCommand)return e.stdout(`${O([["ssh",n.sshCommand??"not available"],["browser",n.webTerminalUrl??"not available"]])}
140
+ `),0;if(s){if(Yr(process.platform==="darwin"?"open":"xdg-open",[n.webTerminalUrl],{stdio:"ignore"}).status!==0)e.stdout(`${n.webTerminalUrl}
141
+ `);return 0}return Yr("sh",["-c",n.sshCommand],{stdio:"inherit"}).status??1}};import{createHash as zi}from"node:crypto";import{readFile as Di,realpath as Ki}from"node:fs/promises";import{createHash as Ii}from"node:crypto";import{constants as ht}from"node:fs";import{chmod as Qr,copyFile as xi,lstat as yn,mkdir as Ri,mkdtemp as _i,open as Ti,realpath as Oi,rename as Ai,rm as Xe,writeFile as Fi}from"node:fs/promises";import{tmpdir as Ni}from"node:os";import{dirname as rs,join as Y,relative as Hi,resolve as Li,sep as es}from"node:path";import{spawnSync as Ui}from"node:child_process";function ss(e){let t=e;if(typeof t==="string")try{t=JSON.parse(t)}catch{return{}}if(!t||typeof t!=="object")return{};let n=t,r=n.git&&typeof n.git==="object"?n.git:{},s=r.historyMode==="preserve"||r.historyMode==="abort_on_findings"?r.historyMode:void 0,o=typeof n.rootName==="string"&&n.rootName.trim()?n.rootName:void 0;return{historyMode:s,rootName:o}}function os(e){let t=e;if(typeof t==="string")try{t=JSON.parse(t)}catch{return[]}if(!t||typeof t!=="object")return[];let n=t.files;if(!Array.isArray(n))return[];return n.flatMap((r)=>{if(!r||typeof r!=="object")return[];let s=r;return typeof s.path==="string"&&typeof s.sha256==="string"?[{path:s.path,sha256:s.sha256}]:[]})}function Ve(e,t){let n=Ui("git",["-C",e,...t],{encoding:"utf8",maxBuffer:52428800,stdio:["ignore","pipe","pipe"]});if(n.status!==0)throw Error(n.stderr.trim().split(`
142
+ `).at(-1)??"Git command failed");return n.stdout.trim()}function ts(e){return Ii("sha256").update(e).digest("hex")}async function vn(e,t){let n=await Oi(e),r=Li(n,...t.split("/"));if(r!==n&&!r.startsWith(n+es))throw Error(`Protected path escapes the project: ${t}`);let s=Hi(n,rs(r)),o=n;for(let i of s.split(es).filter(Boolean)){o=Y(o,i);try{let a=await yn(o);if(!a.isDirectory()||a.isSymbolicLink())throw Error(`Protected path crosses a non-directory: ${t}`)}catch(a){if(a.code!=="ENOENT")throw a;await Ri(o,{mode:448})}}return r}async function ns(e,t,n){let r=await vn(e,t);try{let i=await yn(r);if(!i.isFile()||i.isSymbolicLink())throw Error(`Refusing to replace non-regular protected file: ${t}`)}catch(i){if(i.code!=="ENOENT")throw i}let s=Y(rs(r),`.hlix-pull-${crypto.randomUUID()}.tmp`),o=await Ti(s,ht.O_WRONLY|ht.O_CREAT|ht.O_EXCL|ht.O_NOFOLLOW,384);try{await o.writeFile(n),await o.sync()}finally{await o.close()}try{await Ai(s,r)}catch(i){throw await Xe(s,{force:!0}),i}}async function Mi(e,t){let n=await vn(e,t);try{let r=await yn(n);if(!r.isFile()||r.isSymbolicLink())throw Error(`Refusing to replace non-regular project file: ${t}`)}catch(r){if(r.code!=="ENOENT")throw r}}async function is(e,t,n,r,s){let o=await _i(Y(Ni(),"hlix-pull-"));await Qr(o,448);let i=Y(o,"project.bundle"),a=Y(o,"checkout");try{let c=Buffer.from(await r.arrayBuffer());if(c.byteLength!==n.bundleSize||ts(c)!==n.bundleSha256)throw Error("Downloaded revision bundle failed integrity verification.");if(await Fi(i,c,{mode:384}),Ve(o,["clone","--no-hardlinks","--branch","main",i,a]),Ve(a,["bundle","verify",i]),Ve(a,["rev-parse","HEAD"])!==n.commitSha)throw Error("Downloaded revision bundle does not match the cloud commit.");let l=n.manifest,p=new Map;for(let d of[...l.secretFiles,...l.quarantinedResources])p.set(d.path,d);if(s.files.length!==p.size)throw Error("Cloud protected files do not match the revision manifest.");let u=new Map;for(let d of s.files){let g=p.get(d.path),m=Buffer.from(d.contentBase64,"base64");if(m.toString("base64").replace(/=+$/,"")!==d.contentBase64.replace(/=+$/,"")||!g||g.kind!==d.kind||m.byteLength!==g.size||ts(m)!==g.sha256)throw Error(`Cloud protected file failed integrity verification: ${d.path}`);u.set(d.path,m)}let f=new Set([...l.files.map((d)=>d.path),...t.manifest.secretFiles.map((d)=>d.path),...t.manifest.quarantinedResources.map((d)=>d.path),...u.keys()]);for(let d of[...f].sort())await Mi(e,d);for(let[d,g]of u)await ns(a,d,g);if(t.manifest.git.detected){Ve(e,["fetch",i,"refs/heads/main"]),Ve(e,["reset","--hard","FETCH_HEAD"]);let d=new Set(l.files.map((g)=>g.path));for(let g of t.manifest.files)if(!d.has(g.path))await Xe(Y(e,...g.path.split("/")),{force:!0})}else{for(let d of t.manifest.files)await Xe(Y(e,...d.path.split("/")),{force:!0});for(let d of l.files){let g=await vn(e,d.path);await xi(Y(a,...d.path.split("/")),g),await Qr(g,d.executable?493:420)}}for(let d of[...t.manifest.secretFiles,...t.manifest.quarantinedResources])if(!u.has(d.path))await Xe(Y(e,...d.path.split("/")),{force:!0});for(let[d,g]of u)await ns(e,d,g)}finally{await Xe(o,{recursive:!0,force:!0})}}function ve(e,t,n){let r=new Map(os(n.manifest).map((c)=>[c.path,c.sha256])),s=new Map(e.manifest.files.map((c)=>[c.path,c.sha256])),o=0,i=0;for(let[c,l]of s){let p=r.get(c);if(p===void 0)o+=1;else if(p!==l)i+=1}let a=0;for(let c of r.keys())if(!s.has(c))a+=1;return{localChanged:!t.manifestSha256||e.manifestSha256!==t.manifestSha256,cloudChanged:n.id!==t.revisionId||n.generation!==t.generation,local:{revisionId:t.revisionId,generation:t.generation},cloud:{revisionId:n.id,generation:n.generation,commitSha:n.commitSha},files:{local:s.size,cloud:r.size,localOnly:o,cloudOnly:a,differing:i}}}function wn(e,t,n){let{localChanged:r,cloudChanged:s}=t;if(e==="push")return s?"conflict":r?"push":"none";if(e==="pull"){if(!s)return"none";return r&&!n?"conflict":"pull"}if(r&&s)return"conflict";return r?"push":s?"pull":"none"}function bn(e,t,n){return e==="pull"&&t.localChanged&&!n}var Bi={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 as(e,t,n,r){let s=n.files;return[`${e} --dry-run: ${Bi[e][t]}`,...r?["Requires --yes (or interactive approval) to execute."]:[],"",O([["local",`generation ${n.local.generation} (${n.local.revisionId})${n.localChanged?" — modified":""}`],["cloud",`generation ${n.cloud.generation} (${n.cloud.revisionId})${n.cloudChanged?" — ahead":""}`],["files",`${s.local} local, ${s.cloud} cloud — ${s.localOnly} local-only, ${s.cloudOnly} cloud-only, ${s.differing} differing`]])].join(`
143
+ `)}function Ji(e,t,n){return zi("sha256").update(`project-push-v1\x00${e}\x00${t}\x00${n}`).digest("hex")}var qi={schemaVersion:1,revisionId:"",generation:0,commitSha:""};async function we(e,{allowUnsynced:t=!1}={}){let n=A(e);if(!n?.config.projectId)throw new h("not_initialized","This folder is not bound to an imported Hlix project. Run `hlix import .` first.");let r=at(n.root)??(t?qi:null);if(!r)throw new h("not_initialized","This folder is bound to a project but has never been pulled. Run `hlix pull` first.");return{root:await Ki(n.root),config:n.config,state:r}}async function Ze(e,t,n,r){let s=await G(e,{historyMode:n,environment:t,rootName:r});if(s.blocking.length>0)throw new h("scan_blocked",`Project scan blocked sync:
144
+ - ${s.blocking.join(`
145
+ - `)}`);return s}async function Sn(e,t,n,r){let{state:s,config:o}=await we(r,{allowUnsynced:n==="pull"}),i=e.requireClient(),[a,c]=await Promise.all([Ze(r,e.env,s.historyMode??"preserve",s.rootName),i.revisions.head(o.projectId)]),l=ve(a,s,c.revision),p=wn(n,l,e.flags.force===!0),u=bn(p,l,e.flags.yes===!0);if(e.json)e.stdout(w(b(t,{dryRun:!0,action:p,approvalRequired:u,...l})));else e.stdout(`${as(n,p,l,u)}
146
+ `);return p==="conflict"?1:0}async function Gi(e,t){if(e.flags.yes===!0)return;if(e.json||!e.confirm)throw new h("approval_required","`pull --force` replaces local files. Review with `hlix pull --dry-run`, then repeat with `--yes`.");let n=[`hlix pull --force will replace this folder with cloud revision ${t.cloud.generation}.`,`Local-only files to delete: ${t.files.localOnly}`,`Files to replace with the cloud copy: ${t.files.differing}`,"Local changes that were never pushed cannot be recovered by Hlix."].join(`
147
+ `);if(!await e.confirm(n))throw new h("cancelled","Pull cancelled.")}async function cs(e,t,n,r){let{state:s,config:o}=await we(e),i=t.requireClient(),a=s.historyMode??"preserve",c=n??await Ze(e,t.env,a,s.rootName),l=r??(await i.revisions.head(o.projectId)).revision;if(l.id!==s.revisionId||l.generation!==s.generation)throw new h("conflict","Cloud changed since the local base. Run `hlix pull` or resolve with `hlix sync`.");if(s.manifestSha256&&c.manifestSha256===s.manifestSha256)return{action:"none",revisionId:s.revisionId,generation:s.generation};let p=await ft(c);try{let u=await i.revisions.createUpload(o.projectId,{idempotencyKey:Ji(s.revisionId,c.manifestSha256,p.bundleSha256),expectedRevisionId:s.revisionId,expectedGeneration:s.generation,manifest:c.manifest,manifestSha256:c.manifestSha256,bundleSha256:p.bundleSha256,bundleSize:p.bundleSize,commitSha:p.commitSha});if(u.revisionUpload.status==="pending_upload"){if(!u.upload)throw Error("Revision upload has no bundle target.");await i.revisions.uploadBundle(u.upload,new Blob([Uint8Array.from(await Di(p.bundlePath))]),{onProgress:(d,g)=>{if(!t.json)t.stderr(`Uploading ${d}/${g} bytes\r`)}})}let f=await i.revisions.finalize(o.projectId,u.revisionUpload.id,{secrets:c.secretValues,protectedFiles:c.protectedFiles});if(!f.revision)throw Error("Revision finalized without head metadata.");return Re(e,{schemaVersion:1,revisionId:f.revision.id,generation:f.revision.generation,commitSha:f.revision.commitSha,manifestSha256:f.revision.manifestSha256,historyMode:a,rootName:s.rootName??c.manifest.rootName}),{action:"push",...f.revision}}finally{await p.dispose()}}async function ls(e,t,n,r,s){let{state:o,config:i}=await we(e,{allowUnsynced:!0}),a=t.requireClient(),c=o.historyMode??"preserve",l=r??await Ze(e,t.env,c,o.rootName),p=s??(await a.revisions.head(i.projectId)).revision;if(p.id===o.revisionId&&p.generation===o.generation)return{action:"none",revisionId:o.revisionId,generation:o.generation};let u=o.manifestSha256?l.manifestSha256!==o.manifestSha256:(()=>{let{files:j}=ve(l,o,p);return j.localOnly+j.differing>0})();if(u&&!n)throw new h("conflict","Local files changed since the last sync. Push them, or use `hlix pull --force` to replace them.");if(u)await Gi(t,ve(l,o,p));let[f,d]=await Promise.all([a.revisions.downloadBundle(i.projectId,p.id),a.revisions.protectedFiles(i.projectId)]);await is(e,l,p,f,d);let g=ss(p.manifest),m=g.historyMode??c,k=g.rootName??o.rootName??l.manifest.rootName,R=await Ze(e,t.env,m,k);return Re(e,{schemaVersion:1,revisionId:p.id,generation:p.generation,commitSha:p.commitSha,manifestSha256:R.manifestSha256,historyMode:m,rootName:k}),{action:"pull",revisionId:p.id,generation:p.generation,commitSha:p.commitSha}}function kn(e,t,n){if(e.json)e.stdout(w(b(t,n)));else if("action"in n&&n.action==="none")e.stdout(`Already in sync.
148
+ `);else e.stdout(`${String("action"in n?n.action:"sync")} complete.
149
+ `)}var yt={name:"push",summary:"Push local changes as an immutable cloud revision",usage:"Usage: hlix push [--dry-run] [--json]",supportsJson:!0,options:["dry-run"],async run(e){if(e.args.length)throw Error("push accepts no positional arguments.");let{root:t}=await we(e.cwd);if(e.flags["dry-run"]===!0)return Sn(e,yt.name,"push",t);return kn(e,yt.name,await cs(t,e)),0}},vt={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(`
150
+ `),supportsJson:!0,options:["force","yes","dry-run"],async run(e){if(e.args.length)throw Error("pull accepts no positional arguments.");let{root:t}=await we(e.cwd,{allowUnsynced:!0});if(e.flags["dry-run"]===!0)return Sn(e,vt.name,"pull",t);return kn(e,vt.name,await ls(t,e,e.flags.force===!0)),0}},wt={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(e){if(e.args.length)throw Error("sync accepts no positional arguments.");let{root:t,state:n,config:r}=await we(e.cwd);if(e.flags["dry-run"]===!0)return Sn(e,wt.name,"sync",t);let s=e.requireClient(),[o,i]=await Promise.all([Ze(t,e.env,n.historyMode??"preserve",n.rootName),s.revisions.head(r.projectId)]),a=i.revision,c=ve(o,n,a);if(c.localChanged&&c.cloudChanged)throw new h("conflict","Both local and cloud changed since the last sync. Pull or push explicitly after reviewing the conflict.");let l=c.localChanged?await cs(t,e,o,a):c.cloudChanged?await ls(t,e,!1,o,a):{action:"none",revisionId:n.revisionId,generation:n.generation};return kn(e,wt.name,l),0}};import{lstat as ds,readFile as Wi,realpath as Vi}from"node:fs/promises";import{basename as jn,dirname as Xi,extname as Zi,join as Yi,parse as ps,resolve as En}from"node:path";function Ye(e,t){let n=e.flags[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function Pn(e){let t=A(e);if(!t?.config.projectId)throw new h("not_initialized","This folder is not bound to an Hlix project. Run `hlix import .` first.");return{root:t.root,projectId:t.config.projectId}}async function Cn(e,t){let n=await ds(e);if(n.isSymbolicLink()||!n.isFile())throw Error(`Refusing to import a non-regular file: ${e}`);if(n.size>t)throw Error(`Import file exceeds ${t} bytes: ${e}`);return{path:await Vi(e),content:await Wi(e,"utf8")}}function $n(e,t,n,r){if(e.json)e.stdout(w(b(t,n)));else e.stdout(`${r}
151
+ `)}var In={name:"skill import",summary:"Activate a local skill for the bound cloud project",usage:"Usage: hlix skill import <SKILL.md|folder> [--name <slug>] [--json]",supportsJson:!0,options:["name"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("skill import requires one file or folder.");let t=Pn(e.cwd),n=En(e.cwd,e.args[0]),r=await ds(n);if(r.isSymbolicLink())throw Error(`Refusing to import a symlink: ${n}`);let s=r.isDirectory()?Yi(n,"SKILL.md"):n,o=await Cn(s,200000),i=r.isDirectory()?jn(n):jn(s)==="SKILL.md"?jn(Xi(s)):ps(s).name,a=Ye(e,"name")??i;if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(a))throw Error("Skill name must be a lowercase kebab-case slug.");let c=await e.requireClient().resources.importSkill(t.projectId,{slug:a,content:o.content});return $n(e,In.name,c.skill,`Imported skill ${a}`),0}},xn={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>] [--json]",supportsJson:!0,options:["name","runtime","duty","profile"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("agent import requires one Markdown file.");let t=Pn(e.cwd),n=En(e.cwd,e.args[0]);if(![".md",".mdx"].includes(Zi(n).toLowerCase()))throw Error("Agent imports must be Markdown files.");let r=await Cn(n,20000),s=Ye(e,"runtime")??"hlix";if(!["claude-code","codex","cursor-agent","hlix"].includes(s))throw Error("--runtime must be claude-code, codex, cursor-agent, or hlix.");let o=Ye(e,"duty")??"executor";if(o!=="executor"&&o!=="intake")throw Error("--duty must be executor or intake.");let i=Ye(e,"name")??ps(n).name.replace(/[-_]+/g," "),a=await e.requireClient().resources.importAgent(t.projectId,{name:i,instructions:r.content,runtimeKind:s,duty:o});return $n(e,xn.name,a.agent,a.agent.duty==="intake"?`Imported agent ${a.agent.name} as this project's intake agent`:`Imported agent ${a.agent.name}`),0}},Rn={name:"mcp import",summary:"Explicitly activate one validated local MCP server",usage:"Usage: hlix mcp import <.mcp.json> [--server <name>] [--allow-stdio] [--json]",supportsJson:!0,options:["server","allow-stdio"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("mcp import requires one MCP JSON file.");let t=Pn(e.cwd),n=await Cn(En(e.cwd,e.args[0]),200000),r;try{r=JSON.parse(n.content)}catch{throw Error("MCP config is not valid JSON.")}let s=Object.entries(r.mcpServers??{});if(s.length===0)throw Error("MCP config contains no servers.");let o=Ye(e,"server");if(!o&&s.length>1)throw Error("MCP config contains multiple servers; select one with --server <name>.");let i=o?s.find(([m])=>m===o):s[0];if(!i)throw Error(`MCP server not found: ${o}`);let[a,c]=i,l=c.type==="http"||c.type==="sse"?c.type:typeof c.command==="string"?"stdio":typeof c.url==="string"?"http":null;if(!l)throw Error(`MCP server ${a} has no supported transport.`);if(l==="stdio"&&e.flags["allow-stdio"]!==!0)throw Error("Stdio MCP servers execute a local command in the cloud; repeat with --allow-stdio.");let p=c.env&&typeof c.env==="object"&&!Array.isArray(c.env)?c.env:{},u=c.headers&&typeof c.headers==="object"&&!Array.isArray(c.headers)?c.headers:{};if(Object.values(u).some((m)=>typeof m!=="string"))throw Error(`MCP server ${a} headers must be strings.`);let f=Object.values(u).flatMap((m)=>[...m.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)].map((k)=>k[1]));if(Object.keys(u).length>0&&f.length===0)throw Error("MCP remote headers must use ${KEY} placeholders; literal credentials are refused.");let d=/^(?:(?:Bearer|Basic|Token) )?\$\{[A-Za-z_][A-Za-z0-9_]*\}$/i;if(Object.values(u).some((m)=>!d.test(m)))throw Error("MCP remote headers must be ${KEY} or an approved auth scheme followed by ${KEY}.");let g=await e.requireClient().resources.importMcp(t.projectId,{name:a,transport:l,...typeof c.command==="string"?{command:c.command}:{},...Array.isArray(c.args)&&c.args.every((m)=>typeof m==="string")?{args:c.args}:{},...typeof c.url==="string"?{url:c.url}:{},...Object.keys(u).length>0?{headers:u}:{},envKeys:[...new Set([...Object.keys(p),...f])].sort()});return $n(e,Rn.name,g.mcpServer,`Imported MCP server ${a}`),0}};import{spawnSync as Qi}from"node:child_process";import{chmod as ea,realpath as ta,writeFile as na}from"node:fs/promises";import{basename as ms,dirname as ra,relative as sa,resolve as fs,sep as oa}from"node:path";var us=500;function et(e){let t=A(e.cwd),r=(typeof e.flags.project==="string"?e.flags.project:void 0)??t?.config.projectId;if(!r)throw new h("not_initialized","This folder is not bound to a Hlix project. Run `hlix import .`, or pass --project <id>.");return{projectId:r,root:t?.root??e.cwd}}var Qe=(e,t)=>typeof e[t]==="string"?e[t]:void 0,_n={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(`
152
+ `),supportsJson:!0,options:["project"],async run(e){let{projectId:t}=et(e),n=await e.requireClient().secrets.listEntries(t);if(e.json)return e.stdout(w(b(_n.name,n))),0;if(n.entries.length===0)e.stdout(`No secrets stored for this project.
153
+ `);else e.stdout(`${X(["key","source","format","value","updated"],n.entries.map((r)=>[r.key,r.source,r.format||"-",r.maskedValue,r.updatedAt?.slice(0,10)??"-"]))}
154
+ `);for(let r of n.warnings)e.stderr(`warning: ${r}
155
+ `);return 0}},Tn={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(`
156
+ `),supportsJson:!0,options:["from-stdin","source","project"],args:{min:1,max:2},async run(e){let{projectId:t}=et(e),n=e.args[0],r=e.flags["from-stdin"]===!0;if(r&&e.args.length>1)throw new h("invalid_usage","Pass the value as an argument or with --from-stdin, not both.");if(!r&&e.args.length<2)throw new h("missing_argument","A value is required. Pass it as an argument, or pipe it with --from-stdin.");let s;if(r){if(!e.readStdin)throw new h("invalid_usage","--from-stdin is not available in this context.");s=(await e.readStdin()).replace(/\r?\n$/,"")}else s=e.args[1];let o=Qe(e.flags,"source"),i=await e.requireClient().secrets.upsertEntries(t,{entries:[{key:n,value:s,...o?{source:o}:{}}]});if(e.json)return e.stdout(w(b(Tn.name,i))),i.written>0?0:1;if(i.written===0)throw new h("bad_request",`The store refused ${n}: --source must be a project-relative file path.`);return e.stdout(`${O([["key",n],["source",o??".env"]])}
157
+ `),0}},On={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(`
158
+ `),supportsJson:!0,options:["source","project"],args:{min:1,max:1},async run(e){let{projectId:t}=et(e),n=e.args[0],r=Qe(e.flags,"source"),s=await e.requireClient().secrets.deleteEntry(t,n,r);if(e.json)return e.stdout(w(b(On.name,s))),s.removed>0?0:1;if(s.removed===0)return e.stderr(`No stored secret named ${n}${r?` in ${r}`:""}.
159
+ `),1;return e.stdout(`Removed ${s.removed} entr${s.removed===1?"y":"ies"} for ${n}.
160
+ `),0}};function ia(e,t){let n=(r)=>Object.entries(r).map(([s,o])=>({key:s,value:o}));if(ms(e.path)===".envrc")return{entries:n(dn(t).values)};if(e.kind!=="dotenv")return{skip:"not a dotenv grammar — deliver it with `hlix import` / `hlix push`"};try{return{entries:n(mt(t))}}catch(r){return{skip:r instanceof Error?r.message:"could not be parsed"}}}var An={name:"secrets import",summary:"Load this folder's dotenv 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.","","Only the grammars this CLI owns are read here — dotenv (.env and its","variants) and literal .envrc assignments — because the store's write API","takes parsed values, not file bytes. Every other detected secret file is","listed as skipped: `hlix import` / `hlix push` ship the file itself and","the backend parses it (Terraform, appsettings, properties, wrangler, fly,","serverless, database.yml, and the opaque credentials)."].join(`
161
+ `),supportsJson:!0,options:["project"],args:{min:0,max:64},async run(e){let{projectId:t,root:n}=et(e),r=await G(n,{historyMode:"preserve",environment:e.env}),s=r.blocking.filter((m)=>!m.startsWith(ln));if(s.length>0)throw new h("scan_blocked",`Project scan blocked the import:
162
+ - ${s.join(`
163
+ - `)}`);let o=r.protectedFiles.filter((m)=>m.kind==="dotenv"||m.kind==="credential"),i=await ta(e.cwd),a=e.args.map((m)=>sa(r.root,fs(i,m)).split(oa).join("/")),c=a.filter((m)=>!o.some((k)=>k.path===m));if(c.length>0)throw new h("invalid_usage",`Not a secret file in this project: ${c.join(", ")}`);let l=a.length>0?o.filter((m)=>a.includes(m.path)):o,p=[],u=[],f=[];for(let m of l){let k=ia(m,Buffer.from(m.contentBase64,"base64"));if("skip"in k){f.push({source:m.path,reason:k.skip});continue}for(let R of k.entries)p.push({...R,source:m.path});u.push({source:m.path,keys:k.entries.length})}if(p.length>us)throw new h("invalid_usage",`${p.length} values exceeds the ${us} the store accepts in one write. Import fewer files at a time.`);let d=p.length>0?await e.requireClient().secrets.upsertEntries(t,{entries:p}):{written:0,rejected:[]},g={imported:u,skipped:f,written:d.written,rejected:d.rejected};if(e.json)return e.stdout(w(b(An.name,g))),0;if(u.length>0)e.stdout(`${X(["source","keys"],u.map((m)=>[m.source,String(m.keys)]))}
164
+ `);e.stdout(`${d.written} value${d.written===1?"":"s"} stored.
165
+ `);for(let m of f)e.stderr(`skipped ${m.source}: ${m.reason}
166
+ `);for(let m of d.rejected)e.stderr(`rejected ${m}: the store refused its source path
167
+ `);return 0}};function aa(e){return Qi("git",["-C",ra(e),"ls-files","--error-unmatch","--",ms(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).status===0}var Fn={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(`
168
+ `),supportsJson:!0,options:["source","format","out","project"],async run(e){let{projectId:t}=et(e),n=Qe(e.flags,"source"),r=Qe(e.flags,"format"),s=Qe(e.flags,"out"),o=s===void 0?void 0:fs(e.cwd,s);if(o!==void 0&&aa(o))throw new h("invalid_usage",`Refusing to overwrite a git-tracked file with secret values: ${o}`);let i=await e.requireClient().secrets.exportEntries(t,{...n?{source:n}:{},...r?{format:r}:{}});if(o!==void 0)await na(o,i,{mode:384}),await ea(o,384);if(e.json)return e.stdout(w(b(Fn.name,{source:n??null,format:r??null,out:o??null,bytes:Buffer.byteLength(i),...o===void 0?{content:i}:{}}))),0;if(o===void 0)e.stdout(i);else e.stdout(`${O([["wrote",o],["mode","0600"],["bytes",String(Buffer.byteLength(i))]])}
169
+ `);return 0}};function Nn(e,t){let n=e[t];if(typeof n!=="string"||n.trim()==="")throw new h("missing_argument",`--${t} is required.`);return n}var Hn={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(`
170
+ `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(e){let t=e.args[0],n=Nn(e.flags,"title"),r=Nn(e.flags,"description"),s=await e.requireClient().cycles.propose({projectId:t,title:n,description:r});if(e.json)return e.stdout(w(b(Hn.name,s))),0;return e.stdout(`${O([["project",t],["title",n],["status",s.adopted?"adopted — the project is planning it now":"recorded — it will be planned on the next pass"]])}
171
+ `),0}},Ln={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(`
172
+ `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(e){let t=e.args[0],n=Nn(e.flags,"description"),r=typeof e.flags.title==="string"?e.flags.title:void 0,s=await e.requireClient().tasks.create({projectId:t,description:n,...r?{title:r}:{}});if(e.json)return e.stdout(w(b(Ln.name,s))),0;return e.stdout(`${O([["task",s.id],["project",t],["status",s.status??"queued"],["note","not started — dispatch with `hlix cycles create`"]])}
173
+ `),0}},Un={name:"harness get",summary:"Show which coder runs, and which setting chose it",usage:["Usage: hlix harness get [project-id] [--json]","","With a project id, what that project would run. Without one, the","workspace-wide answer. `source` names the setting that decided: a project","preference, the workspace preference, or the system default."].join(`
174
+ `),supportsJson:!0,args:{min:0,max:1},async run(e){let t=e.args[0],n=e.requireClient(),r=t?await n.modelConfig.resolvedProjectHarness(t):await n.modelConfig.resolvedHarness();if(e.json)return e.stdout(w(b(Un.name,r))),0;return e.stdout(`${O([["scope",t?`project ${t}`:"workspace"],["harness",r.harness],["source",r.source]])}
175
+ `),0}},Mn={name:"harness set",summary:"Choose the coder a project or the workspace runs",usage:[`Usage: hlix harness set <${fe.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(`
176
+ `),supportsJson:!0,options:["org"],args:{min:1,max:2},async run(e){let t=e.args[0];if(!fe.includes(t))throw new h("invalid_usage",`harness must be one of ${fe.join(", ")}; got "${t}".`);let n=e.args[1],r=e.flags.org===!0;if(n&&r)throw new h("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!n&&!r)throw new h("invalid_usage","Name the project to set, or pass --org for the whole workspace.");let s=e.requireClient(),o=n?await s.modelConfig.setProjectHarness(n,t):await s.modelConfig.setHarness(t);if(e.json)return e.stdout(w(b(Mn.name,o))),0;return e.stdout(`${O([["scope",n?`project ${n}`:"workspace"],["harness",t]])}
177
+ `),0}};var Ld=[Gt,Wt,he,gn,hn,fn,Vt,Xt,Zt,pn,gt,wt,vt,yt,In,xn,Rn,_n,Tn,On,An,Fn,Yt,Qt,tn,nn,rn,sn,Ln,Hn,Un,Mn];
178
+ export{h as a,la as b,A as c,D as d,Qs as e,nc as f,gr as g,fe as h,uc as i,Dt as j,$r as k,Rr as l,vc as m,wc as n,bc as o,Ld as p};
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  import{createRequire as a}from"node:module";var c=a(import.meta.url);
3
- export{c as l};
3
+ export{c as q};
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{b as g,c as y,e as v,f as c,k as o}from"./index-619ayaee.js";import{l as i}from"./index-vfqh17y6.js";import{emitKeypressEvents as w}from"node:readline";import{createInterface as C}from"node:readline/promises";async function u(r){if(!process.stdin.isTTY||!process.stdin.setRawMode)throw Error("Interactive login requires a terminal. Set HLIX_API_KEY for CI.");return process.stderr.write(r),w(process.stdin),process.stdin.setRawMode(!0),process.stdin.resume(),new Promise((e,t)=>{let s="",p=()=>{process.stdin.off("keypress",a),process.stdin.setRawMode(!1),process.stdin.pause(),process.stderr.write(`
3
- `)},a=(m,n)=>{if(n.ctrl&&n.name==="c"||n.name==="escape"){p(),t(Error("Login cancelled."));return}if(n.name==="return"||n.name==="enter"){p(),e(s);return}if(n.name==="backspace"){s=s.slice(0,-1);return}if(m&&!n.ctrl)s+=m};process.stdin.on("keypress",a)})}async function f(r){if(!process.stdin.isTTY||!process.stderr.isTTY)throw Error("Interactive approval requires a terminal. Review with --dry-run, then pass --yes.");let e=C({input:process.stdin,output:process.stderr});try{let t=(await e.question(`${r}
4
- Continue? [y/N] `)).trim().toLowerCase();return t==="y"||t==="yes"}finally{e.close()}}import{realpathSync as l}from"node:fs";import{fileURLToPath as x}from"node:url";function h(){if(i.main==i.module===!0)return!0;let r=process.argv[1];if(!r)return!1;try{return l(r)===l(x(import.meta.url))}catch{return!1}}var d={"-h":"--help","-v":"--version"};function M(r){return r.map((e)=>d[e]??e)}function S(r,e=o){let t=r[0];if(t===void 0)return!1;if(t in d||t==="--help"||t==="--version")return!0;return e.some((s)=>s.name.split(" ")[0]===t)}function P(r,e){if(S(r))return e.cli(M(r));return e.code(r[0]==="code"?r.slice(1):r)}if(h()){let r=await P(process.argv.slice(2),{cli:(e)=>c(o,e,{stdout:(t)=>process.stdout.write(t),stderr:(t)=>process.stderr.write(t),env:process.env,readSecret:u,confirm:f}),code:async(e)=>(await import("./main-ct6p55pt.js")).runHlixCode(e)});process.exit(r)}export{o as COMMANDS,g as JSON_SCHEMA_VERSION,v as clientFor,P as dispatch,y as findProjectBinding,S as isCliInvocation,M as normalizeCliArgv,c as runCli};
2
+ import{b as g,c as y,e as v,f as c,p as o}from"./index-qd7p5gqk.js";import{q as i}from"./index-syeavftx.js";import{emitKeypressEvents as w}from"node:readline";import{createInterface as C}from"node:readline/promises";async function u(r){if(!process.stdin.isTTY||!process.stdin.setRawMode)throw Error("Interactive login requires a terminal. Set HLIX_API_KEY for CI.");return process.stderr.write(r),w(process.stdin),process.stdin.setRawMode(!0),process.stdin.resume(),new Promise((e,t)=>{let s="",a=()=>{process.stdin.off("keypress",p),process.stdin.setRawMode(!1),process.stdin.pause(),process.stderr.write(`
3
+ `)},p=(m,n)=>{if(n.ctrl&&n.name==="c"||n.name==="escape"){a(),t(Error("Login cancelled."));return}if(n.name==="return"||n.name==="enter"){a(),e(s);return}if(n.name==="backspace"){s=s.slice(0,-1);return}if(m&&!n.ctrl)s+=m};process.stdin.on("keypress",p)})}async function d(r){if(!process.stdin.isTTY||!process.stderr.isTTY)throw Error("Interactive approval requires a terminal. Review with --dry-run, then pass --yes.");let e=C({input:process.stdin,output:process.stderr});try{let t=(await e.question(`${r}
4
+ Continue? [y/N] `)).trim().toLowerCase();return t==="y"||t==="yes"}finally{e.close()}}import{readFileSync as x,realpathSync as f}from"node:fs";import{fileURLToPath as S}from"node:url";function h(){if(i.main==i.module===!0)return!0;let r=process.argv[1];if(!r)return!1;try{return f(r)===f(S(import.meta.url))}catch{return!1}}var l={"-h":"--help","-v":"--version"};function M(r){return r.map((e)=>l[e]??e)}function P(r,e=o){let t=r[0];if(t===void 0)return!1;if(t in l||t==="--help"||t==="--version")return!0;return e.some((s)=>s.name.split(" ")[0]===t)}function I(r,e){if(P(r))return e.cli(M(r));return e.code(r[0]==="code"?r.slice(1):r)}if(h()){let r=await I(process.argv.slice(2),{cli:(e)=>c(o,e,{stdout:(t)=>process.stdout.write(t),stderr:(t)=>process.stderr.write(t),env:process.env,readSecret:u,confirm:d,readStdin:async()=>x(0,"utf8")}),code:async(e)=>(await import("./main-0t04w2by.js")).runHlixCode(e)});process.exit(r)}export{o as COMMANDS,g as JSON_SCHEMA_VERSION,v as clientFor,I as dispatch,y as findProjectBinding,P as isCliInvocation,M as normalizeCliArgv,c as runCli};
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import{a as w,d as te,e as h,f as D,g as C,h as f,i as v,j as fe,k as xe,l as we,m as ye,n as be,o as ke,p as y}from"./index-qd7p5gqk.js";import{q as ht}from"./index-syeavftx.js";import{relative as gt,resolve as ft}from"node:path";import{parseArgs as xt}from"node:util";import{createMastraCode as wt}from"mastracode";import{loadMcpConfig as yt}from"@mastra/code-sdk/mcp/config";import{executeSubagent as bt}from"@mastra/code-sdk/agents/subagents/execute";import{exploreSubagent as kt}from"@mastra/code-sdk/agents/subagents/explore";import{planSubagent as vt}from"@mastra/code-sdk/agents/subagents/plan";import{hasHeadlessFlag as St,parseHeadlessArgs as Ct,runMC as Ht}from"mastracode/headless";import{MastraTUI as jt}from"mastracode/tui";import{mkdirSync as Re,writeFileSync as Ae}from"node:fs";import{join as U}from"node:path";import{createTool as He}from"@mastra/core/tools";import{z as u}from"zod";var b=(e)=>`hlix_${e.split(" ").join("_")}`,je=u.object({args:u.array(u.string()).optional().describe("Positional arguments that follow the command name."),flags:u.record(u.string(),u.union([u.string(),u.boolean()])).optional().describe('Options without the leading dashes, e.g. { "yes": true, "name": "api" }.')}),Ie=u.object({exitCode:u.number(),stdout:u.string(),stderr:u.string()});function Pe(e,t,s){let r=e.name.split(" ").concat(t.args??[]);for(let[o,n]of Object.entries(t.flags??{})){if(n===!1)continue;if(r.push(`--${o}`),typeof n==="string")r.push(n)}if(!t.flags?.cwd)r.push("--cwd",s);if(e.supportsJson&&!t.flags?.json)r.push("--json");return r}async function _e(e,t,s,r=process.env){let o="",n="";return{exitCode:await D([e],Pe(e,t,s),{stdout:(c)=>{o+=c},stderr:(c)=>{n+=c},env:r}),stdout:o,stderr:n}}function B(e){let t={};for(let s of e.commands??y){let r=b(s.name);t[r]=He({id:r,description:`${s.summary}
3
+
4
+ ${s.usage}`,inputSchema:je,outputSchema:Ie,execute:async(o)=>_e(s,o,e.cwd,e.env)})}return t}var Me=(e)=>`${e.split(" ").join("-")}.md`;function $e(e){return["---",`description: ${e.summary}`,"---","",`Call the tool \`${b(e.name)}\` with the user's arguments: $ARGUMENTS.`,"Show the result.",""].join(`
5
+ `)}var Oe={"follow.md":["---","description: Watch a cloud task being coded, live","---","","Call the tool `hlix_tasks_follow` with `taskId` set to $ARGUMENTS. It streams the","coder's text and tool calls into this session. Summarise what it did.",""].join(`
6
+ `),"harness.md":["---","description: Show or change the harness — which coder does the work","---","","Call the tool `hlix_harness` with `harness` set to $ARGUMENTS when the user","named one, and with no argument when they did not. Show `message` verbatim.",""].join(`
7
+ `)};function q(e,t=y){let s=U(e,".hlix","commands");Re(s,{recursive:!0});let r=[],o=[...t.map((n)=>[Me(n.name),$e(n)]),...Object.entries(Oe)];for(let[n,i]of o){let c=U(s,n);try{Ae(c,i,{flag:"wx"}),r.push(c)}catch(a){if(a.code!=="EEXIST")throw a}}return r}import{execFileSync as Te}from"node:child_process";import{createACPTool as Ne}from"@mastra/acp";import{createTool as Ee}from"@mastra/core/tools";import{z as p}from"zod";var x={"claude-code":{harness:"claude-code",label:"Claude Code",command:"claude-agent-acp",args:[],authEnvVars:["ANTHROPIC_API_KEY"],install:"npm i -g @agentclientprotocol/claude-agent-acp"},codex:{harness:"codex",label:"Codex",command:"codex-acp",args:[],authEnvVars:["OPENAI_API_KEY"],env:{NO_BROWSER:"1"},install:"npm i -g @agentclientprotocol/codex-acp"},"cursor-agent":{harness:"cursor-agent",label:"Cursor Agent",command:"cursor-agent",args:["acp"],authEnvVars:["CURSOR_API_KEY"],install:"curl https://cursor.com/install -fsS | bash"}};function J(e){if(e.flag)return{harness:Fe(e.flag,"--harness"),source:"flag"};if(e.configured)return{harness:e.configured,source:e.configSource??"project"};return{harness:v,source:"default"}}function Fe(e,t){if(f.includes(e))return e;throw Error(`${t} must be one of ${f.join(", ")}; got "${e}".`)}var k="hlix_tasks_follow",We=(e)=>`hlix_coder_${e.split("-").join("_")}`;function V(e,t){let s=t.source==="default"?"":` (${t.source==="flag"?"--harness":t.source})`;return`${e} · harness: ${t.harness}${s}`}function X(e,t=3000){try{return Te("which",[e],{timeout:t,stdio:"ignore"}),!0}catch{return!1}}var S=(e)=>`harness ${e.harness} needs \`${e.command}\` on PATH. Install it with: ${e.install}`;function Le(e){let t=e.options??[],s=t.find((r)=>r.kind==="allow_once")??t.find((r)=>r.kind==="reject_once");if(!s)return{outcome:{outcome:"cancelled"}};return{outcome:{outcome:"selected",optionId:s.optionId}}}var K=["view","search_content","find_files","file_stat","lsp_inspect"],z=["ask_user","task_write","task_update","task_complete","task_check"],De=(e)=>[`harness ${e} runs in the project's Coding Workspace, not on this machine.`,"This session can follow and stream that work, but cannot start it:","which coder the platform uses comes from the project's harness preference,","and this CLI has no command that creates a task."].join(" "),Y=(e)=>[e==="unknown"?"This project's harness could not be read from the server. Do NOT guess which coder it runs — say so, and offer to check with the `hlix_harness` tool.":`This project's harness is ${e}: the platform runs ${e} for the coding work it executes, in the project's Coding Workspace.`,"Change it with the `hlix_harness` tool, which writes the project's setting.","","To do coding work here, dispatch it and then watch it:","1. `hlix_cycles_create` with the project id, a title and a description. That"," is what STARTS work — it enters the project's loop, which plans the cycle,"," creates its tasks and starts the coder. It returns no cycle id.","2. `hlix_tasks_list` with that project to find the tasks planning produced.",`3. \`${k}\` with a task id, which streams that coder's own text and`," tool calls into this session live. Report what it did.","","`hlix_tasks_create` only adds a board row; it does not start anything, and","there is no way to start a single task. Never claim otherwise."].join(`
8
+ `),Be=(e,t)=>[`The user chose the ${e.label} harness. Do not edit files or run commands`,`yourself. Hand the whole task to \`${t}\` as one natural-language brief,`,`then report what it did. ${e.label} reads and writes the same working`,"directory you are in.","",`It authenticates from ${e.authEnvVars.join(" or ")} in this shell's`,"environment. If it reports a credential problem, say so — do not retry."].join(`
9
+ `);function G(e){if(e.sandbox==="cloud"||e.active==="hlix")return[];let t=new Set(e.unavailable??[]),s=e.model?{defaultModelId:e.model}:{},r=[{id:"hlix",name:"Hlix",description:"The hlix agent codes here, with the full toolset.",...s}];for(let o of Object.values(x)){let n=e.active===o.harness,i=We(o.harness);r.push({id:o.harness,name:o.label,description:`${o.label} runs on this machine over ACP and edits ${e.cwd}.`,instructions:Be(o,i),availableTools:t.has(o.harness)?[...K,...z,k]:[i,...K,...z,k],...t.has(o.harness)?{}:{additionalTools:{[i]:Ne({id:i,description:`Run a coding task with ${o.label}. Give it one natural-language brief; it reads and writes the working directory and returns its final output.`,command:o.command,args:o.args,cwd:e.cwd,...o.env?{env:o.env}:{},...e.workspace?{workspace:e.workspace}:{},onPermissionRequest:async(c)=>Le(c)})}},...s,...n?{metadata:{default:!0}}:{}})}return r}function Ue(e){let t=[...e.available],s=(o,n="none")=>({harness:e.current,available:t,action:n,message:o});if(!e.requested)return s(`harness: ${e.current}. Available here: ${t.join(", ")}.`);if(!f.includes(e.requested))return s(`/harness must name one of ${f.join(", ")}; got "${e.requested}".`);let r=e.requested;if(e.sandbox==="cloud"){let o=`${e.sandboxLine} · harness: ${r} (project preference)`;return{harness:r,available:t,action:"preference",message:r==="hlix"?o:`${o}. ${De(r)}`}}if(!t.includes(r))return s(S(x[r]));if(!e.modesBuilt)return s(`This session runs the hlix coder, so there is no ${r} mode to switch to. Restart with \`hlix --harness ${r}\`, or make it the default with \`hlix config set harness ${r}\`.`,"restart");return{harness:r,available:t,action:"mode",message:`${e.sandboxLine} · harness: ${r}`}}function Q(e){return Ee({id:"hlix_harness",description:"Show or change the harness — which coder does the work. In a local or docker sandbox it switches this session's coder; in a cloud sandbox it writes the project's harness preference, which is what the platform runs. With no argument it reports the current harness.",inputSchema:p.object({harness:p.string().optional().describe(`One of ${f.join(", ")}. Omit to report the current one.`)}),outputSchema:p.object({harness:p.string(),available:p.array(p.string()),message:p.string()}),execute:async(t)=>{let s=e.session(),r=Ue({...t.harness?{requested:t.harness}:{},current:s?.mode.get()??v,available:e.available,sandbox:e.sandbox,sandboxLine:e.sandboxLine,modesBuilt:e.modesBuilt}),o={harness:r.harness,available:r.available,message:r.message};if(r.action==="mode"&&s)return await s.mode.switch({modeId:r.harness}),o;if(r.action==="preference"){if(!e.setProjectHarness)return{...o,message:"This folder is not bound to a hlix project, so there is no project preference to write. Run `hlix init` or pass --project <id>."};await e.setProjectHarness(r.harness)}return o}})}import{createTool as qe}from"@mastra/core/tools";import{writeToolProgress as Ke}from"mastracode/plugin";import{z as m}from"zod";function ze(e){switch(e.type){case"on_chat_model_stream":return e.delta?{event:"text",text:e.delta}:null;case"reasoning":return e.delta?{event:"text",text:e.delta}:null;case"on_tool_start":return{event:"tool_start",toolName:e.name,args:e.input};case"on_tool_end":return{event:"tool_end",toolName:e.name,result:e.output,isError:Je(e.output)};case"error":return{event:"finish",isError:!0,result:e.message};case"done":return{event:"finish",isError:!1};default:return null}}function Je(e){return typeof e==="object"&&e!==null&&e.status==="failed"}async function Ve(e,t){let s=[],r=[],o="streamed",n="The coder's turn ended.";for await(let i of e){if(i.type==="idle"){o="idle",n="Nothing is being coded right now. The task is not in build or test.";break}if(i.type==="error")o="error",n=i.message;if(i.type==="on_chat_model_stream")s.push(i.delta);if(i.type==="on_tool_start")r.push(i.name);let c=ze(i);if(c)await t(c)}return{status:o,text:s.join(""),tools:r,message:n}}function Z(e){return qe({id:"hlix_tasks_follow",description:"Watch a hlix task being coded in the cloud, live. Streams the coder's text and tool calls into this session as they happen, and returns what it did. Use it after a task starts building.",inputSchema:m.object({taskId:m.string().describe("The task to follow.")}),outputSchema:m.object({status:m.enum(["streamed","idle","error","unassigned"]),text:m.string(),tools:m.array(m.string()),message:m.string()}),execute:async(t,s)=>{let r=h(e.env??process.env,{cwd:e.cwd,flags:{}}),o=await r.tasks.get(t.taskId);if(!o.agentId)return{status:"unassigned",text:"",tools:[],message:"No agent has picked this task up yet, so there is no coder to watch. Check `hlix_tasks_get` again once it is building."};return Ve(r.projects.observeAgent(o.projectId,o.agentId),(n)=>Ke(s,n))}})}import{buildMode as Xe}from"@mastra/code-sdk/agents/modes/build";import{fastMode as Ye}from"@mastra/code-sdk/agents/modes/explore";import{planMode as Ge}from"@mastra/code-sdk/agents/modes/plan";import{setCustomProvidersSource as Qe}from"@mastra/code-sdk/agents/model";import{getCustomProviderId as ee,loadSettings as Ze}from"@mastra/code-sdk/onboarding/settings";var se="hlix",re="default",et=(e)=>`${se}/${e}`;function tt(e){return{name:se,url:`${e.baseUrl.replace(/\/+$/,"")}/v1/api/ai/w/${e.workspaceId}`,apiKey:e.apiKey,models:[...new Set([re,...e.models??[]])]}}function st(e){let t=[Xe,Ge,Ye];return e?t.map((s)=>({...s,defaultModelId:e})):t}function oe(e){let t=te({env:e.env,flags:{},cwd:e.cwd});if(t.conflict||!t.credential||!t.workspaceId)return null;let s=tt({baseUrl:t.baseUrl,workspaceId:t.workspaceId,apiKey:t.credential.apiKey,...e.models?{models:e.models}:{}}),r=ee(s.name);return Qe(()=>[...Ze().customProviders.filter((o)=>ee(o.name)!==r),s]),{provider:s,modelId:et(re)}}var ne=(e,t)=>e.length>0?[...e]:st(t);function ae(e){if(e.configured)return{id:e.configured,source:e.configuredSource??"config"};return e.wired?{id:e.wired.modelId,source:"workspace"}:null}var ie=(e,t)=>t?`${e} · model: ${t.id} (${t.source})`:e;import{execFileSync as lt}from"node:child_process";import{DockerSandbox as dt}from"@mastra/docker";import{LocalFilesystem as ut,Workspace as mt}from"@mastra/core/workspace";import{posix as ce}from"node:path";import{MastraFilesystem as rt,MastraSandbox as ot,Workspace as nt}from"@mastra/core/workspace";var at=600000,it=["recursive","overwrite","force","maxDepth","extension"];function g(e){let t=e??{},s={};for(let r of it)if(t[r]!==void 0)s[r]=t[r];return Object.keys(s).length>0?{options:s}:{}}var le=(e)=>e instanceof Date?e:new Date(typeof e==="string"||typeof e==="number"?e:0);class de extends rt{id;name="RemoteFilesystem";provider="hlix-coding-workspace";basePath;status="ready";client;constructor(e,t){super({name:"RemoteFilesystem"});this.client=e,this.basePath=t.root,this.id=t.id??`hlix-remote-fs:${t.root}`}getInfo(){return{id:this.id,name:this.name,provider:this.provider,status:this.status,metadata:{root:this.basePath}}}resolveAbsolutePath(e){return ce.isAbsolute(e)?e:ce.join(this.basePath,e)}async call(e){let{result:t}=await this.client.fs({...e,encoding:e.encoding??"utf8",path:this.resolveAbsolutePath(e.path)});return t}async readFile(e,t){let r=await this.call({op:"read",path:e,encoding:"base64"}),o=Buffer.from(r.content,r.encoding);return t?.encoding?o.toString(t.encoding):o}async writeFile(e,t,s){await this.call({op:"write",path:e,content:Buffer.from(t).toString("base64"),encoding:"base64",...g(s)})}async appendFile(e,t){await this.call({op:"append",path:e,content:Buffer.from(t).toString("base64"),encoding:"base64"})}async deleteFile(e,t){await this.call({op:"delete",path:e,...g(t)})}async copyFile(e,t,s){await this.call({op:"copy",path:e,dest:this.resolveAbsolutePath(t),...g(s)})}async moveFile(e,t,s){await this.call({op:"move",path:e,dest:this.resolveAbsolutePath(t),...g(s)})}async mkdir(e,t){await this.call({op:"mkdir",path:e,...g(t)})}async rmdir(e,t){await this.call({op:"rmdir",path:e,...g(t)})}async readdir(e,t){return await this.call({op:"readdir",path:e,...g(t)})??[]}async exists(e){return await this.call({op:"exists",path:e})===!0}async stat(e){let t=await this.call({op:"stat",path:e});return{...t,createdAt:le(t.createdAt),modifiedAt:le(t.modifiedAt)}}}var ct=(e)=>`'${e.split("'").join("'\\''")}'`;class ue extends ot{id;name="RemoteSandbox";provider="hlix-coding-workspace";status="ready";client;constructor(e,t){super({name:"RemoteSandbox"});if(this.client=e,this.id=`hlix-remote-sandbox:${t.projectId}`,t.root)this.setWorkingDirectory(t.root)}async start(){}getInfo(){return{id:this.id,name:this.name,provider:this.provider,status:this.status,createdAt:new Date(0)}}async executeCommand(e,t=[],s){let r=[e,...t.map(ct)].join(" "),o=Date.now(),n=s?.cwd??this.workingDirectory,i=await this.client.exec({command:r,...n?{cwd:n}:{},timeoutMs:s?.timeout??at});return{success:i.exitCode===0,exitCode:i.exitCode,stdout:i.stdout,stderr:i.stderr,executionTimeMs:Date.now()-o,command:e,args:t}}}function me(e,t){let s=t.root??"/workspace";return new nt({id:`hlix-project:${t.projectId}`,name:"Hlix Coding Workspace",filesystem:new de(e,{root:s}),sandbox:new ue(e,{projectId:t.projectId,root:s})})}function pt(e,t){if(C.includes(e))return e;throw new w("invalid_usage",`${t==="flag"?"--sandbox":"sandbox in .hlix/config.json"} must be one of ${C.join(", ")}; got "${e}".`)}function pe(e){if(e.flag){let t=e.flagSource??"flag";return{choice:pt(e.flag,t),reason:t==="flag"?`--sandbox ${e.flag}`:"config"}}if(e.projectId)return{choice:"cloud",reason:`project ${e.projectId}`};if(e.dockerAvailable())return{choice:"docker",reason:"auto"};return{choice:"local",reason:"auto"}}var he=(e)=>`sandbox: ${e.choice} (${e.reason})`;function ge(e=3000){try{return lt("docker",["info"],{timeout:e,stdio:"ignore"}),!0}catch{return!1}}function H(e,t){if(e.choice==="local")return;if(e.choice==="cloud"){if(!t.remote||!t.projectId)throw new w("invalid_usage","The cloud sandbox needs a hlix project. Run `hlix init`, pass --project <id>, or choose --sandbox docker|local.");return me(t.remote,{projectId:t.projectId})}let s="/workspace";return new mt({id:"hlix-code-docker",name:"Hlix Code (Docker)",filesystem:new ut({basePath:t.cwd}),...t.skills&&t.skills.length>0?{skills:t.skills}:{},sandbox:new dt({id:"hlix-code",volumes:{[t.cwd]:s},workingDirectory:s})})}var It=["You are running inside Hlix Code, the terminal harness for the hlix control plane.","Every `hlix` CLI command is available to you as a tool named `hlix_<command>`,","with spaces replaced by underscores — `hlix_status`, `hlix_tasks_list`, `hlix_push`.","Use those tools instead of running `hlix` through the shell: they resolve the","folder's workspace binding and credential the same way the CLI does, and they","return the CLI's machine-readable output.","Report a non-zero exit code and its stderr to the user verbatim. Never invent a","project, task or workspace id — read one with a tool first.","","This project's secrets live in the hlix secrets store, not in a file in this","folder: `hlix_secrets_list` shows them keyed by (key, source file) with every","value masked, and `hlix_secrets_set` changes one. When the user asks for a",'local env file, call `hlix_secrets_export` with `{ flags: { out: ".env" } }` —',"it writes the rendered file at mode 0600 and refuses a path git tracks. Do not","repeat an exported secret value back into the conversation."].join(`
10
+ `);function Pt(e){if(!e||e.entries.length===0)return"";let t=e.entries.length,s=new Set(e.entries.map((r)=>r.source)).size;return`secrets: ${t} ${t===1?"entry":"entries"} (${s} ${s===1?"source":"sources"})`}async function _t(e,t){try{return await h(process.env,{cwd:e,flags:{}}).secrets.listEntries(t)}catch{return null}}function Rt(e){let{values:t}=xt({args:e,allowPositionals:!0,strict:!1,options:{local:{type:"boolean"},sandbox:{type:"string"},harness:{type:"string"},project:{type:"string"},cwd:{type:"string"}}}),s=typeof t.sandbox==="string"?t.sandbox:t.local===!0?"local":void 0;return{...s?{sandbox:s,sandboxSource:"flag"}:{},...typeof t.harness==="string"?{harness:t.harness}:{},...typeof t.project==="string"?{project:t.project}:{},cwd:ft(typeof t.cwd==="string"?t.cwd:".")}}function At(e){let t=Object.keys(x),r=e.sandbox==="cloud"?t:t.filter((a)=>e.installed(a)),o=["hlix",...r],n=t.filter((a)=>!r.includes(a)),i=e.requested.harness;if(i==="hlix"||r.includes(i))return{harness:e.requested,available:o,unavailable:n,refusal:null,warning:null};let c=S(x[i]);if(e.requested.source==="flag")return{harness:e.requested,available:o,unavailable:n,refusal:c,warning:null};return{harness:{harness:"hlix",source:"default"},available:o,unavailable:n,refusal:null,warning:`${c} Falling back to harness hlix.`}}async function Mt(e,t){try{let r=await h(process.env,{cwd:e,flags:{}}).modelConfig.resolvedProjectHarness(t);return{harness:r.harness,source:r.source}}catch{return null}}function $t(e,t){let s=t.skills&&t.skills.length>0?{skills:t.skills}:{};if(e.choice!=="cloud")return H(e,{cwd:t.cwd,...s});if(!t.projectId)throw new w("invalid_usage","The cloud sandbox needs a hlix project. Run `hlix init`, pass --project <id>, or choose --sandbox docker|local.");let o=h(process.env,{cwd:t.cwd,flags:{}}).projects.workspace(t.projectId);return H(e,{cwd:t.cwd,projectId:t.projectId,remote:o})}var j=".hlix";function Ot(e){return e.skills.filter((t)=>!t.harnessReads).map((t)=>t.path)}function Tt(e,t){return e.skills.filter((s)=>s.scope==="project").map((s)=>gt(t,s.path)).filter((s)=>s!==""&&!s.startsWith(".."))}function Nt(e,t){if(e.length===0)return;let s={explore:"fast",plan:"plan",execute:"build"},r=t.find((a)=>a.metadata?.default===!0)?.id??t.find((a)=>a.id==="build")?.id??t[0]?.id,o=(a)=>t.find((d)=>d.id===s[a])?.defaultModelId??t.find((d)=>d.id===r)?.defaultModelId,n=[kt,vt,bt].map((a)=>{let d=o(a.id);return{...a,...d?{defaultModelId:d}:{}}}),i=new Set(n.map((a)=>a.id)),c=e.filter((a)=>!i.has(a.name)).map((a)=>{let d=a.model??o("execute");return{id:a.name,name:a.name,description:a.description||`Project subagent from ${a.path}`,instructions:a.instructions,...a.tools?{allowedControllerTools:a.tools}:{},...d?{defaultModelId:d}:{}}});return[...n,...c]}async function Et(e,t,s){if(St(t)){let r=Ct(t),n=await Ht({controller:e.controller,session:e.session,prompt:r.prompt??"",...r.model?{model:r.model}:{},...r.maxTurns?{maxTurns:r.maxTurns}:{}}).result;if(process.stdout.write(`${n.text}
11
+ `),n.error)process.stderr.write(`${n.error.message}
12
+ `);return n.exitCode}return await new jt({controller:e.controller,session:e.session,...e.hookManager?{hookManager:e.hookManager}:{},...e.mcpManager?{mcpManager:e.mcpManager}:{},...e.pluginManager?{pluginManager:e.pluginManager}:{},...e.knowledgeInspector?{knowledgeInspector:e.knowledgeInspector}:{},authStorage:e.authStorage,storageMaintenance:e.storageMaintenance,appName:"Hlix Code",version:s}).run(),0}async function Bs(e,t={boot:wt,present:Et}){let s=Rt(e),r=fe(s.cwd,process.env),o=s.project??r.merged.projectId,n=we(s.cwd,xe(process.env),{configDir:j}),i,c,a;try{if(c=pe({flag:s.sandbox??r.merged.sandbox,flagSource:s.sandbox?"flag":"config",projectId:o,dockerAvailable:()=>ge()}),a=At({requested:J({...s.harness?{flag:s.harness}:{},...r.merged.harness?{configured:r.merged.harness}:{},...r.sources.harness?{configSource:r.sources.harness}:{}}),sandbox:c.choice,installed:(l)=>X(x[l].command)}),a.refusal)throw new w("invalid_usage",a.refusal);i=$t(c,{cwd:s.cwd,projectId:o,...c.choice==="docker"?{skills:Tt(n,s.cwd)}:{}})}catch(l){return process.stderr.write(`error: ${l instanceof Error?l.message:String(l)}
13
+ `),2}if(a.warning)process.stderr.write(`warning: ${a.warning}
14
+ `);if(c.choice==="cloud"){let l=o?await Mt(s.cwd,o):null;if(l&&s.harness&&s.harness!==l.harness)process.stderr.write(`warning: this project runs ${l.harness}. Run \`/harness ${s.harness}\` to make ${s.harness} the project's setting.
15
+ `);a={...a,harness:l??{harness:"unknown",source:o?"the project's setting could not be read":"no project bound"}}}let d=ae({wired:oe({cwd:s.cwd,env:process.env}),...r.merged.model?{configured:r.merged.model}:{},...r.sources.model?{configuredSource:r.sources.model}:{}}),I=he(c);process.stdout.write(`${ie(V(I,a.harness),d)}
16
+ `);let P=ke(n);if(P)process.stdout.write(`${P}
17
+ `);let _=o?Pt(await _t(s.cwd,o)):"";if(_)process.stdout.write(`${_}
18
+ `);q(s.cwd);let R=null,ve=a.harness.harness==="unknown"?"hlix":a.harness.harness,A=G({sandbox:c.choice,cwd:s.cwd,active:ve,unavailable:a.unavailable,...i?{workspace:i}:{},...d?{model:d.id}:{}}),Se=new Set(Object.keys(yt(s.cwd,j).mcpServers??{})),M=Object.fromEntries(n.mcpServers.filter((l)=>!Se.has(l.name)).map((l)=>[l.name,l.config])),O=ye(n.generatedCommands,s.cwd),T=[...n.commands.map((l)=>l.path),...O?[O]:[]],N=Ot(n),E=ne(A,d?.id),F=Nt(n.subagents,E),W=be(n.instructions,s.cwd),{version:Ce}=await import("./package-w9c40vfc.js"),L=await t.boot({configDir:j,cwd:s.cwd,hostInstructions:[It,...c.choice==="cloud"?[Y(a.harness.harness)]:[],...W?[W]:[]].join(`
19
+
20
+ `),...Object.keys(M).length>0?{mcpServers:M}:{},...F?{subagents:F}:{},...T.length>0||N.length>0?{initialState:{pluginCommandPaths:T,pluginSkillPaths:N}}:{},extraTools:{...B({cwd:s.cwd}),hlix_tasks_follow:Z({cwd:s.cwd}),hlix_harness:Q({sandbox:c.choice,sandboxLine:I,available:a.available,modesBuilt:A.length>0,session:()=>R,...o?{setProjectHarness:async(l)=>{await h(process.env,{cwd:s.cwd,flags:{}}).modelConfig.setProjectHarness(o,l)}}:{}})},modes:E,...i?{workspace:i}:{}});return R=L.session,t.present(L,e,Ce)}export{Ot as extraSkillPaths,Rt as parseHlixCodeArgs,At as planHarness,Bs as runHlixCode,Pt as secretsStatusLine,Nt as standardsSubagents,Tt as workspaceSkillPaths};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import"./index-vfqh17y6.js";var s="@hlix/cli",i="0.3.0",n="SEE LICENSE IN LICENSE",a="Hlix Code and the hlix control-plane CLI.",r=["hlix","cli","agents"],d="https://hlix.ai",p="module",c="./dist/index.js",o={hlix:"./dist/index.js"},l=["dist","skills","LICENSE","THIRD_PARTY_NOTICES"],u={node:">=22.19.0"},b={access:"public"},h={build:"rm -rf dist && bun build src/index.ts --outdir dist --target node --format esm --splitting --packages external --minify --banner '#!/usr/bin/env node'",test:'bun test --isolate src --path-ignore-patterns "**/*.integration.test.ts" --timeout 20000',typecheck:"tsc --noEmit",prepublishOnly:"bun run typecheck && bun run build && bun run test","test:integration":"NODE_ENV=test bun run ../../apps/backend/scripts/with-aimock.ts -- bun run ../../apps/backend/scripts/with-test-db.ts -- bun test --isolate --preload ../../apps/backend/test/helpers/pool-lifecycle.ts --timeout 60000 .integration.test.ts"},m={"@mastra/acp":"^0.4.1","@mastra/code-sdk":"1.7.0","@mastra/core":"^1.65.0","@mastra/docker":"^0.7.0",ignore:"7.0.8",mastracode:"0.39.0","openapi-fetch":"^0.17.0",zod:"4.5.4"},g={"@hlix/sdk":"^0.2.0","@types/bun":"latest",typescript:"^7.0.2"},k={name:s,version:i,license:n,description:a,keywords:r,homepage:d,type:p,main:c,bin:o,files:l,engines:u,publishConfig:b,scripts:h,dependencies:m,devDependencies:g};export{o as bin,k as default,m as dependencies,a as description,g as devDependencies,u as engines,l as files,d as homepage,r as keywords,n as license,c as main,s as name,b as publishConfig,h as scripts,p as type,i as version};
2
+ import"./index-syeavftx.js";var s="@hlix/cli",i="0.4.0",n="SEE LICENSE IN LICENSE",a="Hlix Code and the hlix control-plane CLI.",r=["hlix","cli","agents"],d="https://hlix.ai",p="module",c="./dist/index.js",o={hlix:"./dist/index.js"},l=["dist","skills","LICENSE","THIRD_PARTY_NOTICES"],u={node:">=22.19.0"},b={access:"public"},h={build:"rm -rf dist && bun build src/index.ts --outdir dist --target node --format esm --splitting --packages external --minify --banner '#!/usr/bin/env node'",test:'bun test --isolate src --path-ignore-patterns "**/*.integration.test.ts" --timeout 20000',typecheck:"tsc --noEmit",prepublishOnly:"bun run typecheck && bun run build && bun run test","test:integration":"NODE_ENV=test bun run ../../apps/backend/scripts/with-aimock.ts -- bun run ../../apps/backend/scripts/with-test-db.ts -- bun test --isolate --preload ../../apps/backend/test/helpers/pool-lifecycle.ts --timeout 60000 .integration.test.ts"},m={"@mastra/acp":"^0.4.1","@mastra/code-sdk":"1.7.0","@mastra/core":"^1.65.0","@mastra/docker":"^0.7.0",ignore:"7.0.8",mastracode:"0.39.0","openapi-fetch":"^0.17.0",zod:"4.5.4"},g={"@hlix/sdk":"^0.2.0","@types/bun":"latest",typescript:"^7.0.2"},k={name:s,version:i,license:n,description:a,keywords:r,homepage:d,type:p,main:c,bin:o,files:l,engines:u,publishConfig:b,scripts:h,dependencies:m,devDependencies:g};export{o as bin,k as default,m as dependencies,a as description,g as devDependencies,u as engines,l as files,d as homepage,r as keywords,n as license,c as main,s as name,b as publishConfig,h as scripts,p as type,i as version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlix/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Hlix Code and the hlix control-plane CLI.",
6
6
  "keywords": [
@@ -82,6 +82,52 @@ shell live (`cloud`, `docker`, `local`). `config set` writes this folder unless
82
82
  refuses `projectId`, `workspaceId` and `apiUrl` — those bind a folder to a
83
83
  tenant and are written by `init` and `import`.
84
84
 
85
+ ## Project secrets
86
+
87
+ ```bash
88
+ hlix secrets list [--project <id>] [--json]
89
+ hlix secrets set <KEY> [value] [--from-stdin] [--source <file>] [--project <id>] [--json]
90
+ hlix secrets delete <KEY> [--source <file>] [--project <id>] [--json]
91
+ hlix secrets import [file...] [--project <id>] [--json]
92
+ hlix secrets export [--source <file>] [--format <id>] [--out <path>] [--project <id>] [--json]
93
+ ```
94
+
95
+ The store is the source of truth for a project's environment; files are
96
+ exports. Every value is keyed by `(key, source file)`, so `.env`,
97
+ `apps/api/.env.local` and `infra/terraform.tfvars` stay three files instead of
98
+ collapsing into one bag of variables. These commands act on the project this
99
+ folder is bound to unless `--project` names another one.
100
+
101
+ `secrets list` masks every value to its last four characters and **no flag
102
+ unmasks it**. Its `warnings` name files whose export is a normalized rebuild
103
+ (comments and untracked neighbouring settings are not reproduced).
104
+
105
+ `secrets set` takes the value as an argument or, better, from stdin:
106
+ `--from-stdin` keeps a real credential out of shell history and out of `ps`,
107
+ and strips exactly one trailing newline. `--source` names the file the value
108
+ belongs to; omitted, it is the project root `.env`.
109
+
110
+ `secrets delete` without `--source` removes the key from every file that
111
+ declares it. Removing nothing exits 1.
112
+
113
+ `secrets import` loads the local files into the store, detected by the same
114
+ scanner `hlix import` uses. It reads the grammars this CLI owns — dotenv and
115
+ literal `.envrc` assignments — and lists every other detected secret file as
116
+ **skipped**, because the store's write API takes parsed values rather than file
117
+ bytes. Those arrive through `hlix import` / `hlix push`, which ship the file
118
+ itself for the backend to parse: Terraform, .NET appsettings, Java properties,
119
+ Spring YAML, Azure Functions local settings, wrangler, fly, serverless, Rails
120
+ `config/database.yml`, and the opaque credentials.
121
+
122
+ `secrets export` is the one command that returns secret **values**, and the
123
+ server audits every call. Without `--out` it writes the rendered file to
124
+ stdout; with `--out` it writes it at mode 0600 and **refuses a path git
125
+ tracks**, because an exported file is plaintext and must not become a commit.
126
+ `--format` re-renders a source as another shape; omitted, it keeps the shape
127
+ the values were parsed as.
128
+
129
+ Secrets are agency-only on every route. A client collaborator gets `forbidden`.
130
+
85
131
  ## Dispatching work
86
132
 
87
133
  ```bash
@@ -111,9 +157,11 @@ key, which only picks the coder Hlix Code spawns on this machine.
111
157
 
112
158
  ```bash
113
159
  hlix status [--json] # workspace, binding, local and cloud drift
160
+ hlix standards [--json] # instruction files, skills, commands, MCP servers and subagents other agent tools left in this folder
114
161
  hlix projects list [--json] # projects in the workspace
115
162
  hlix projects get [project-id] [--json]
116
163
  hlix init [folder] [--project <id>] [--json] # create committed project configuration; --project binds an existing cloud project
164
+ hlix terminal [project-id] [--print] [--web] [--json] # shell into the project's Coding Workspace (ssh here, or the browser terminal)
117
165
  hlix import [folder] [--dry-run] [--env-file <path>] [--history preserve] [--yes] [--json]
118
166
  hlix sync [--dry-run] [--json] # push or pull when only one side changed
119
167
  hlix pull [--force] [--yes] [--dry-run] [--json]
@@ -1,130 +0,0 @@
1
- #!/usr/bin/env node
2
- import{l as wo}from"./index-vfqh17y6.js";class y extends Error{code;constructor(e,t){super(t);this.name="CliError",this.code=e}}var Ys=1,j=(e,t)=>({schemaVersion:1,command:e,data:t}),be=(e,t)=>({schemaVersion:1,command:e,error:t});function v(e){return`${JSON.stringify(e,null,2)}
3
- `}function R(e){let t=Math.max(0,...e.map(([n])=>n.length));return e.map(([n,r])=>`${n.padEnd(t)} ${r}`).join(`
4
- `)}function ae(e,t){let n=e.map((o,s)=>Math.max(o.length,...t.map((i)=>(i[s]??"").length))),r=(o)=>o.map((s,i)=>s.padEnd(n[i])).join(" ").trimEnd();return[r(e),r(n.map((o)=>"-".repeat(o))),...t.map(r)].join(`
5
- `)}import{statSync as to}from"node:fs";import{dirname as no,resolve as ro}from"node:path";import{closeSync as wt,constants as Se,existsSync as Ye,fsyncSync as In,lstatSync as vt,mkdirSync as zr,openSync as _n,readFileSync as On,renameSync as Dr,statSync as Rn,unlinkSync as Tn,writeFileSync as qr}from"node:fs";import{homedir as Jr}from"node:os";import{dirname as Gr,join as kt}from"node:path";function ce(e=process.env){let t=e.HLIX_CONFIG_HOME??e.XDG_CONFIG_HOME??kt(Jr(),".config");return kt(t,"hlix","credentials.json")}function An(e=process.env){let t=e.HLIX_API_KEY;if(!t&&e.HLIX_SESSION_TOKEN)return{baseUrl:e.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:"",sessionToken:e.HLIX_SESSION_TOKEN,...e.HLIX_WORKSPACE_ID?{organizationId:e.HLIX_WORKSPACE_ID}:{}};if(t)return{baseUrl:e.HLIX_BASE_URL??"https://server.hlix.ai",apiKey:t,...e.HLIX_WORKSPACE_ID?{organizationId:e.HLIX_WORKSPACE_ID}:{}};try{let n=JSON.parse(On(ce(e),"utf8"));return n.apiKey&&n.baseUrl?n:null}catch{return null}}function Hn(e=process.env){let t=ce(e);return Ye(t)?t:null}function bt(e=process.env){let t=ce(e);if(!Ye(t))return{path:t,removed:!1,reason:"absent"};let n=vt(t);if(n.isSymbolicLink()||!n.isFile())throw Error("Refusing to remove a credential path that is not a regular file.");let r=process.getuid?.();if(r!==void 0&&Rn(t).uid!==r)throw Error("Refusing to remove a credential file owned by another user.");let o;try{o=JSON.parse(On(t,"utf8"))}catch{o=null}let s=o;if(!s||typeof s.apiKey!=="string"||typeof s.baseUrl!=="string")throw Error(`Refusing to remove ${t}: it is not a credential written by this CLI.`);return Tn(t),{path:t,removed:!0,reason:"removed"}}function Fn(e,t=process.env){let n=ce(t),r=Gr(n);if(zr(r,{recursive:!0,mode:448}),vt(r).isSymbolicLink())throw Error("Refusing to write credentials through a symlinked directory.");if(Ye(n)){let i=vt(n);if(i.isSymbolicLink()||!i.isFile())throw Error("Refusing to replace a credential path that is not a regular file.");let a=process.getuid?.();if(a!==void 0&&Rn(n).uid!==a)throw Error("Refusing to replace a credential file owned by another user.")}let o=kt(r,`.credentials.${process.pid}.${crypto.randomUUID()}.tmp`),s;try{s=_n(o,Se.O_WRONLY|Se.O_CREAT|Se.O_EXCL|Se.O_NOFOLLOW,384),qr(s,`${JSON.stringify(e,null,2)}
6
- `,"utf8"),In(s),wt(s),s=void 0,Dr(o,n);let i=_n(r,Se.O_RDONLY);try{try{In(i)}catch(a){let c=a.code;if(c!=="EINVAL"&&c!=="ENOTSUP")throw a}}finally{wt(i)}}catch(i){if(s!==void 0)wt(s);if(Ye(o))Tn(o);throw i}return n}import{constants as Ze,existsSync as Qe,lstatSync as Ln,mkdirSync as Wr,openSync as Vr,closeSync as Nn,fsyncSync as Xr,readFileSync as Un,renameSync as Yr,unlinkSync as Zr,writeFileSync as St}from"node:fs";import{dirname as Qr,join as je,resolve as et}from"node:path";function eo(e){if(!Qe(e))return;let t=Ln(e);if(t.isSymbolicLink()||!t.isFile())throw Error(`Refusing to replace a non-regular Hlix file: ${e}`)}function Ee(e,t){let n=Qr(e);if(Wr(n,{recursive:!0,mode:448}),Ln(n).isSymbolicLink())throw Error(`Refusing to write through a symlinked Hlix directory: ${n}`);eo(e);let r=je(n,`.hlix-${process.pid}-${crypto.randomUUID()}.tmp`),o;try{o=Vr(r,Ze.O_WRONLY|Ze.O_CREAT|Ze.O_EXCL|Ze.O_NOFOLLOW,384),St(o,`${JSON.stringify(t,null,2)}
7
- `,"utf8"),Xr(o),Nn(o),o=void 0,Yr(r,e)}catch(s){if(o!==void 0)Nn(o);if(Qe(r))Zr(r);throw s}}function Pe(e){return je(et(e),".hlix","config.json")}function Mn(e){return je(et(e),".hlix","state.json")}function le(e){try{let t=JSON.parse(Un(Pe(e),"utf8"));return t.schemaVersion===1&&t.workspaceId&&t.apiUrl?t:null}catch{return null}}function Ce(e,t){Ee(Pe(e),t);let n=je(et(e),".hlix",".gitignore");if(!Qe(n))St(n,`state.json
8
- `,{mode:420,flag:"wx"});let r=je(et(e),".hlixignore");if(!Qe(r))St(r,`# Additional project-local paths to exclude from Hlix snapshots.
9
- `,{mode:420,flag:"wx"})}function $e(e,t){Ee(Mn(e),t)}function tt(e){try{let t=JSON.parse(Un(Mn(e),"utf8"));return t.schemaVersion===1&&t.revisionId&&t.generation>0?t:null}catch{return null}}var jt="https://server.hlix.ai";function N(e){let t=ro(e);for(;;){let n=le(t);if(n)return{root:t,config:n};let r=no(t);if(r===t)return null;t=r}}function Kn(e){try{return to(e).isDirectory()}catch{return!1}}function nt(e){if(typeof e!=="string")return;let t=e.trim();return t?t:void 0}var Bn=(e,t)=>e.replace(/\/+$/,"")===t.replace(/\/+$/,"");function B(e){let{env:t,flags:n,cwd:r}=e,o=N(r),s=An(t),i=s?t.HLIX_API_KEY||t.HLIX_SESSION_TOKEN?"env":"file":null,a=i==="file"?s:null,c=nt(n["base-url"]),l=nt(t.HLIX_BASE_URL),p=nt(n.workspace),d=nt(t.HLIX_WORKSPACE_ID),u=c??l??o?.config.apiUrl??a?.baseUrl??jt,m=c?"flag":l?"env":o?.config.apiUrl?"project":a?.baseUrl?"credential":"default",h=p??d??o?.config.workspaceId??a?.organizationId??null,k=p?"flag":d?"env":o?.config.workspaceId?"project":a?.organizationId?"credential":null;return{baseUrl:u,baseUrlSource:m,workspaceId:h,workspaceSource:k,credential:s,credentialSource:i,credentialPath:ce(t),binding:o,conflict:oo(o,{flagBaseUrl:c,envBaseUrl:l,flagWorkspace:p,envWorkspace:d})}}function oo(e,t){if(!e)return null;let n=`${e.root} is bound to`,r="Drop the override, or point --cwd at a folder bound to it.";if(t.flagWorkspace&&t.flagWorkspace!==e.config.workspaceId)return`${n} workspace ${e.config.workspaceId}, but --workspace names ${t.flagWorkspace}. ${r}`;if(t.envWorkspace&&t.envWorkspace!==e.config.workspaceId)return`${n} workspace ${e.config.workspaceId}, but HLIX_WORKSPACE_ID names ${t.envWorkspace}. ${r}`;if(t.flagBaseUrl&&!Bn(t.flagBaseUrl,e.config.apiUrl))return`${n} ${e.config.apiUrl}, but --base-url names ${t.flagBaseUrl}. ${r}`;if(t.envBaseUrl&&!Bn(t.envBaseUrl,e.config.apiUrl))return`${n} ${e.config.apiUrl}, but HLIX_BASE_URL names ${t.envBaseUrl}. ${r}`;return null}import{resolve as vo}from"node:path";import{parseArgs as ko}from"node:util";import so from"openapi-fetch";function Et(e){return so({baseUrl:e.baseUrl,headers:e.headers,fetch:e.fetch})}var xe=(e)=>({kind:"apiKey",apiKey:e});var Pt=(e)=>({kind:"bearer",token:e});function io(e){switch(e.kind){case"apiKey":return{"x-api-key":e.apiKey};case"session":return{cookie:e.cookie};case"bearer":return{authorization:`Bearer ${e.token}`}}}function ao(e){return e?{"X-Organization-Id":e}:{}}function zn(e,t){return{...io(e),...ao(t)}}function co(e){if(typeof e!=="object"||e===null)return null;let{error:t}=e;return typeof t==="string"?t:null}class L extends Error{status;body;requestId;method;url;constructor(e,t){super(e);this.name=new.target.name,this.status=t.status,this.body=t.body,this.requestId=t.requestId??null,this.method=t.method,this.url=t.url}}class Ie extends L{issues;constructor(e,t,n){super(e,t);this.issues=n}}class _e extends L{}class Oe extends L{}class Re extends L{}class Te extends L{}class Ae extends L{}class He extends L{retryAfter;constructor(e,t,n){super(e,t);this.retryAfter=n}}class Fe extends L{}class Ne extends L{}class de extends Error{method;url;constructor(e,t){super(e,{cause:t.cause});this.name="HlixTransportError",this.method=t.method,this.url=t.url}}function lo(e){if(typeof e!=="object"||e===null)return null;let t=e;if(t.success!==!1)return null;let n=t.error?.message;if(typeof n!=="string")return null;try{let r=JSON.parse(n);return Array.isArray(r)?r:[]}catch{return[]}}function po(e){let t=e.get("retry-after");if(!t)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function Le(e,t,n){let r={status:e.status,body:t,requestId:e.headers.get("x-request-id"),method:n.method,url:n.url},o=co(t),s=`${n.method} ${n.url} failed with ${e.status}`,i=lo(t);if(i)return new Ie(`${n.method} ${n.url}: request body failed validation`,r,i);let a=o??s;switch(e.status){case 400:return new _e(a,r);case 401:return new Oe(a,r);case 403:return new Re(a,r);case 404:return new Te(a,r);case 409:return new Ae(a,r);case 429:return new He(a,r,po(e.headers));case 501:return new Fe(a,r);default:return e.status>=500?new Ne(a,r):new L(a,r)}}var Dn=new Set(["GET","HEAD","PUT","DELETE","OPTIONS","TRACE"]);function rt(e){return Dn.has(e.toUpperCase())}var uo=new Set([429,500,502,503,504]);function mo(e){return uo.has(e)}var Ct={attempts:3,baseDelayMs:200,maxDelayMs:5000};function $t(e,t,n,r=Math.random){if(n!==null)return Math.min(n*1000,t.maxDelayMs);let o=Math.min(t.baseDelayMs*2**e,t.maxDelayMs);return Math.round(r()*o)}function xt(e){if(!rt(e.method))return!1;if(e.attempt+1>=e.policy.attempts)return!1;return e.status===null||mo(e.status)}var fo=(e)=>new Promise((t)=>setTimeout(t,e));function go(e){let t=e.headers.get("retry-after");if(!t)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function qn(e){let{base:t,policy:n}=e,r=e.sleep??fo,o=e.random??Math.random;return async(s)=>{let i=s.method.toUpperCase(),a=rt(i)?s.clone():null;for(let c=0;;c+=1){let l=c===0?s:a.clone(),p;try{p=await t(l)}catch(d){if(!a||!xt({method:i,attempt:c,policy:n,status:null}))throw new de(`${i} ${s.url}: ${d instanceof Error?d.message:String(d)}`,{method:i,url:s.url,cause:d});await r($t(c,n,null,o));continue}if(!xt({method:i,attempt:c,policy:n,status:p.status}))return p;if(!a)return p;await r($t(c,n,go(p),o))}}}function w(e,t){if(e.response.ok)return e.data;throw Le(e.response,e.error??e.data,t)}var Ue=(e)=>typeof e==="string"?e:"";function It(e){let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=="object"||t===null)return null;let n=t;switch(n.type){case"idle":return{type:"idle"};case"done":return{type:"done"};case"active":return typeof n.runId==="string"?{type:"active",runId:n.runId}:{type:"active"};case"on_chat_model_stream":return{type:"on_chat_model_stream",delta:Ue(n.delta)};case"reasoning":return{type:"reasoning",delta:Ue(n.delta)};case"on_tool_start":return{type:"on_tool_start",name:Ue(n.name),input:n.input};case"on_tool_end":return{type:"on_tool_end",name:Ue(n.name),output:n.output};case"error":return{type:"error",message:Ue(n.message)};default:return null}}var _t=(e)=>e.type==="done"||e.type==="idle"||e.type==="error";var ho=()=>({event:null,data:[],id:null,retry:null});function Jn(e,t,n){switch(t){case"event":e.event=n;return;case"data":e.data.push(n);return;case"id":if(!n.includes("\x00"))e.id=n;return;case"retry":{if(/^\d+$/.test(n))e.retry=Number(n);return}default:return}}function Wn(e){let t=e.data.join(`
10
- `),n=e.event,r=e.id;if(e.data=[],e.event=null,t==="")return null;return{event:n,data:t,id:r,retry:e.retry}}function Gn(e,t){if(t==="")return Wn(e);if(t.startsWith(":"))return null;let n=t.indexOf(":");if(n===-1)return Jn(e,t,""),null;let r=t.slice(0,n),o=t.slice(n+1);if(o.startsWith(" "))o=o.slice(1);return Jn(e,r,o),null}function yo(e){let t=[],n=0;for(let r=0;r<e.length;r+=1){let o=e[r];if(o!==`
11
- `&&o!=="\r")continue;if(t.push(e.slice(n,r)),o==="\r"&&e[r+1]===`
12
- `)r+=1;n=r+1}return{lines:t,rest:e.slice(n)}}async function*Ot(e,t){let n=e.getReader(),r=new TextDecoder,o=ho(),s="",i=()=>void n.cancel().catch(()=>{});t?.addEventListener("abort",i,{once:!0});try{for(;;){let{done:c,value:l}=await n.read();if(c)break;s+=r.decode(l,{stream:!0});let{lines:p,rest:d}=yo(s);s=d;for(let u of p){let m=Gn(o,u);if(m)yield m}if(t?.aborted)return}if(s+=r.decode(),s!==""){let c=Gn(o,s);if(c)yield c}let a=Wn(o);if(a)yield a}finally{t?.removeEventListener("abort",i),n.releaseLock()}}class Me{raw;baseUrl;headers;fetcher;constructor(e){this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.headers=zn(e.credential,e.organizationId);let t={...Ct,...e.retry},n=e.fetch??((r)=>globalThis.fetch(r));this.fetcher=qn({base:n,policy:t}),this.raw=Et({baseUrl:this.baseUrl,headers:this.headers,fetch:this.fetcher})}at(e,t){return{method:e,url:`${this.baseUrl}${t}`}}projects={list:async()=>w(await this.raw.GET("/v1/api/projects"),this.at("GET","/v1/api/projects")),get:async(e)=>w(await this.raw.GET("/v1/api/projects/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}`)),create:async(e)=>w(await this.raw.POST("/v1/api/projects",{body:e}),this.at("POST","/v1/api/projects")),delete:async(e)=>w(await this.raw.DELETE("/v1/api/projects/{id}",{params:{path:{id:e}}}),this.at("DELETE",`/v1/api/projects/${e}`)),start:async(e,t)=>w(await this.raw.POST("/v1/api/projects/{id}/start",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/start`)),observeAgent:(e,t,n)=>this.observeAgent(e,t,n),workspace:(e)=>({fs:async(t)=>w(await this.raw.POST("/v1/api/projects/{id}/workspace/fs",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/workspace/fs`)),exec:async(t)=>w(await this.raw.POST("/v1/api/projects/{id}/workspace/exec",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/workspace/exec`))})};imports={create:async(e)=>{let t=await this.raw.POST("/v1/api/imports",{body:e});return w(t,this.at("POST","/v1/api/imports"))},get:async(e)=>w(await this.raw.GET("/v1/api/imports/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/imports/${e}`)),finalize:async(e,t)=>{let n=await this.raw.POST("/v1/api/imports/{id}/finalize",{params:{path:{id:e}},body:t});return w(n,this.at("POST",`/v1/api/imports/${e}/finalize`))},uploadBundle:async(e,t,n={})=>{let r=n.chunkSize??8388608;if(r<=0||r%262144!==0)throw Error("Import upload chunkSize must be a positive multiple of 256 KiB");let o=e.url.startsWith("/")?`${this.baseUrl}${e.url}`:e.url;if(e.kind==="hlix-stream"){let i=new Request(o,{method:"PUT",headers:{...this.headers,"content-type":"application/x-git-bundle","content-length":String(t.size)},body:t,signal:n.signal}),a=await this.fetcher(i);if(!a.ok)await this.throwUploadError(a,o);n.onProgress?.(t.size,t.size);return}let s=0;while(s<t.size){let i=Math.min(s+r,t.size),a=new Request(o,{method:"PUT",headers:{"content-type":"application/x-git-bundle","content-length":String(i-s),"content-range":`bytes ${s}-${i-1}/${t.size}`},body:t.slice(s,i),signal:n.signal}),c=await this.fetcher(a);if(c.status!==308&&!c.ok)await this.throwUploadError(c,o);let l=c.headers.get("range")?.match(/bytes=0-(\d+)/)?.[1];if(s=l?Number(l)+1:i,!Number.isSafeInteger(s)||s<i||s>t.size)throw Error("Import upload server returned an invalid acknowledged range");n.onProgress?.(s,t.size)}}};revisions={head:async(e)=>w(await this.raw.GET("/v1/api/projects/{id}/revisions/head",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}/revisions/head`)),protectedFiles:async(e)=>w(await this.raw.GET("/v1/api/projects/{id}/protected-files",{params:{path:{id:e}}}),this.at("GET",`/v1/api/projects/${e}/protected-files`)),createUpload:async(e,t)=>{let n=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads",{params:{path:{id:e}},body:t});return w(n,this.at("POST",`/v1/api/projects/${e}/revisions/uploads`))},finalize:async(e,t,n)=>{let r=await this.raw.POST("/v1/api/projects/{id}/revisions/uploads/{uploadId}/finalize",{params:{path:{id:e,uploadId:t}},body:n});return w(r,this.at("POST",`/v1/api/projects/${e}/revisions/uploads/${t}/finalize`))},uploadBundle:async(e,t,n={})=>this.imports.uploadBundle(e,t,n),downloadBundle:async(e,t)=>{let n=`/v1/api/projects/${e}/revisions/${t}/bundle`,r=new Request(`${this.baseUrl}${n}`,{method:"GET",headers:this.headers}),o=await this.fetcher(r);if(!o.ok)await this.throwUploadError(o,`${this.baseUrl}${n}`);return o.blob()}};resources={importSkill:async(e,t)=>w(await this.raw.POST("/v1/api/projects/{id}/resources/skill",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/skill`)),importAgent:async(e,t)=>w(await this.raw.POST("/v1/api/projects/{id}/resources/agent",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/agent`)),importMcp:async(e,t)=>w(await this.raw.POST("/v1/api/projects/{id}/resources/mcp",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/projects/${e}/resources/mcp`))};async throwUploadError(e,t){let n=null;try{n=await e.json()}catch{n=await e.text().catch(()=>null)}throw Le(e,n,{method:"PUT",url:t})}tasks={list:async(e)=>w(await this.raw.GET("/v1/api/tasks",{params:{query:e??{}}}),this.at("GET","/v1/api/tasks")),get:async(e)=>w(await this.raw.GET("/v1/api/tasks/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}`)),create:async(e)=>w(await this.raw.POST("/v1/api/tasks",{body:e}),this.at("POST","/v1/api/tasks")),update:async(e,t)=>w(await this.raw.PATCH("/v1/api/tasks/{id}",{params:{path:{id:e}},body:t}),this.at("PATCH",`/v1/api/tasks/${e}`)),listComments:async(e)=>w(await this.raw.GET("/v1/api/tasks/{id}/comments",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}/comments`)),addComment:async(e,t)=>w(await this.raw.POST("/v1/api/tasks/{id}/comments",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/tasks/${e}/comments`)),review:async(e)=>w(await this.raw.GET("/v1/api/tasks/{id}/review",{params:{path:{id:e}}}),this.at("GET",`/v1/api/tasks/${e}/review`)),stream:(e,t)=>this.stream(`/v1/api/tasks/${e}/stream`,t)};modelConfig={setProjectHarness:async(e,t)=>w(await this.raw.PUT("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:e}},body:{harness:t}}),this.at("PUT",`/v1/api/model-config/harness/${e}`)),clearProjectHarness:async(e)=>w(await this.raw.DELETE("/v1/api/model-config/harness/{projectId}",{params:{path:{projectId:e}}}),this.at("DELETE",`/v1/api/model-config/harness/${e}`)),setHarness:async(e)=>w(await this.raw.PUT("/v1/api/model-config/harness",{body:{harness:e}}),this.at("PUT","/v1/api/model-config/harness")),clearHarness:async()=>w(await this.raw.DELETE("/v1/api/model-config/harness"),this.at("DELETE","/v1/api/model-config/harness")),resolvedHarness:async()=>w(await this.raw.GET("/v1/api/model-config/harness/resolved"),this.at("GET","/v1/api/model-config/harness/resolved")),resolvedProjectHarness:async(e)=>w(await this.raw.GET("/v1/api/model-config/harness/{projectId}/resolved",{params:{path:{projectId:e}}}),this.at("GET",`/v1/api/model-config/harness/${e}/resolved`))};cycles={list:async(e)=>w(await this.raw.GET("/v1/api/cycles",{params:{query:e??{}}}),this.at("GET","/v1/api/cycles")),get:async(e)=>w(await this.raw.GET("/v1/api/cycles/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/cycles/${e}`)),propose:async(e)=>w(await this.raw.POST("/v1/api/cycles",{body:e}),this.at("POST","/v1/api/cycles")),stream:(e,t)=>this.stream(`/v1/api/cycles/${e}/stream`,t)};clientInvoices={list:async(e)=>w(await this.raw.GET("/v1/api/client-billing/invoices",{params:{query:e??{}}}),this.at("GET","/v1/api/client-billing/invoices")),get:async(e)=>w(await this.raw.GET("/v1/api/client-billing/invoices/{id}",{params:{path:{id:e}}}),this.at("GET",`/v1/api/client-billing/invoices/${e}`)),createDraft:async(e)=>w(await this.raw.POST("/v1/api/client-billing/invoices",{body:e}),this.at("POST","/v1/api/client-billing/invoices")),issue:async(e)=>w(await this.raw.POST("/v1/api/client-billing/invoices/{id}/issue",{params:{path:{id:e}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/issue`)),void:async(e,t)=>w(await this.raw.POST("/v1/api/client-billing/invoices/{id}/void",{params:{path:{id:e}},body:{reason:t}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/void`)),pay:async(e)=>w(await this.raw.POST("/v1/api/client-billing/invoices/{id}/pay",{params:{path:{id:e}},body:{}}),this.at("POST",`/v1/api/client-billing/invoices/${e}/pay`)),paymentLink:async(e,t={})=>w(await this.raw.POST("/v1/api/client-billing/invoices/{id}/payment-link",{params:{path:{id:e}},body:t}),this.at("POST",`/v1/api/client-billing/invoices/${e}/payment-link`))};async*observeAgent(e,t,n){let r=`/v1/api/projects/${e}/agents/${t}/observe`;for await(let o of this.stream(r,n)){let s=It(o.data);if(!s)continue;if(yield s,_t(s))return}}async*stream(e,t){let n=`${this.baseUrl}${e}`,r=new Request(n,{headers:{...this.headers,accept:"text/event-stream"},signal:t?.signal}),o=await globalThis.fetch(r);if(!o.ok||!o.body){let s=null;try{s=await o.json()}catch{s=null}throw Le(o,s,{method:"GET",url:n})}yield*Ot(o.body,t?.signal)}}function Tt(e){if(e instanceof y)return{code:e.code,status:null};if(e instanceof Ie)return{code:"invalid_request",status:400};if(e instanceof _e)return{code:"bad_request",status:400};if(e instanceof Oe)return{code:"unauthenticated",status:401};if(e instanceof Re)return{code:"forbidden",status:403};if(e instanceof Te)return{code:"not_found",status:404};if(e instanceof Ae)return{code:"conflict",status:409};if(e instanceof He)return{code:"rate_limited",status:429};if(e instanceof Fe)return{code:"not_implemented",status:501};if(e instanceof Ne)return{code:"server_error",status:e.status};if(e instanceof de)return{code:"unreachable",status:null};return{code:"unknown",status:null}}var Rt=(e)=>e instanceof Error?e.message:String(e);function bo(e,t){let n=B({env:e,flags:t.flags,cwd:t.cwd});if(n.conflict)throw new y("workspace_mismatch",n.conflict);if(!n.credential)throw new y("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");return new Me({baseUrl:n.baseUrl,credential:n.credential.sessionToken?Pt(n.credential.sessionToken):xe(n.credential.apiKey),...n.workspaceId?{organizationId:n.workspaceId}:{}})}function Vn(e){let t=Math.max(...e.map((r)=>r.name.length));return`hlix — the hlix control-plane CLI
13
-
14
- Usage:
15
- hlix <command> [options]
16
-
17
- Commands:
18
- ${[` hlix ${"".padEnd(t)} Open Hlix Code (interactive)`,...e.map((r)=>` hlix ${r.name.padEnd(t)} ${r.summary}`)].join(`
19
- `)}
20
-
21
- Options:
22
- --json Machine-readable output (a versioned, stable contract)
23
- --cwd <dir> Operate on another directory instead of the current one
24
- --workspace <id> Workspace to act in, overriding the folder's binding
25
- --base-url <url> API to talk to, overriding the folder's binding
26
- --help Show this help
27
- --version Show the installed CLI version
28
-
29
- A command targets the workspace named by, in order: an explicit flag, the
30
- HLIX_* environment, the nearest .hlix/config.json, then the stored credential.
31
- Run \`hlix status\` to see which one applied.
32
- `}function Xn(e,t){for(let n of[...e].sort((r,o)=>o.name.length-r.name.length)){let r=n.name.split(" ");if(r.every((o,s)=>t[s]===o))return{command:n,rest:t.slice(r.length)}}return null}async function Di(e,t,n){if(t.some((E)=>E==="--api-key"||E.startsWith("--api-key=")))return n.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=ko({args:t,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"},"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"}}})}catch(E){let O=t.includes("--json"),A=Rt(E);if(O)n.stdout(v(be("cli",{code:"invalid_usage",message:A,status:null})));else n.stderr(`${A}
33
- `);return 2}let o=r.values.json===!0,s=r.positionals;if(r.values.version===!0){let{version:E}=await import("./package-12m4e2y1.js");return n.stdout(`${E}
34
- `),0}if(s.length===0||r.values.help===!0){let E=Xn(e,s);return n.stdout(E?`${E.command.usage}
35
- `:Vn(e)),s.length===0&&r.values.help!==!0?1:0}let i=Xn(e,s);if(!i){let E=s.join(" ");if(o)n.stdout(v(be(E,{code:"unknown_command",message:`Unknown command: ${E}`,status:null})));else n.stderr(`Unknown command: ${E}
36
-
37
- ${Vn(e)}`);return 2}let a=new Set(["json","help","version","cwd","workspace","base-url"]),c=new Set(i.command.options??[]),l=Object.entries(r.values).filter(([E,O])=>O!==void 0&&!a.has(E)&&!c.has(E)).map(([E])=>`--${E}`),p=i.command.args??{min:0,max:0},d=i.rest.length<p.min?{code:"missing_argument",message:i.command.usage.split(`
38
- `)[0]}:i.rest.length>p.max?{code:"invalid_usage",message:i.command.usage.split(`
39
- `)[0]}:null,u=typeof r.values.cwd==="string"?r.values.cwd:void 0,m=vo(u??"."),h=u!==void 0&&!Kn(m)?{code:"invalid_usage",message:`--cwd is not a directory: ${m}`}:null,k=l.length>0?{code:"invalid_usage",message:`Unsupported option for ${i.command.name}: ${l.join(", ")}`}:h??d;if(k){if(o)n.stdout(v(be(i.command.name,{...k,status:null})));else n.stderr(`error: ${k.message}
40
-
41
- ${i.command.usage}
42
- `);return 2}let _=r.values,D={...n,args:i.rest,json:o,flags:_,cwd:m,requireClient:(E)=>bo(n.env,{cwd:E??m,flags:_})};try{return await i.command.run(D)}catch(E){let{code:O,status:A}=Tt(E);if(o)n.stdout(v(be(i.command.name,{code:O,message:Rt(E),status:A})));else n.stderr(`error: ${Rt(E)}
43
- `);return O==="unauthenticated"||O==="forbidden"?3:1}}import{readFileSync as So}from"node:fs";import{homedir as jo}from"node:os";import{join as Eo}from"node:path";var Yn=["cloud","docker","local"],pe=["claude-code","codex","cursor-agent","hlix"],ea="hlix",Zn={harness:"local and docker sandboxes only",model:"all sandboxes",sandbox:"all sandboxes"},ue=["harness","model","sandbox"],At=["projectId","workspaceId","apiUrl"];function Ht(e=process.env){return Eo(e.HLIX_CONFIG_HOME??jo(),".hlix","config.json")}function Qn(e=process.env){try{let t=JSON.parse(So(Ht(e),"utf8"));return t.schemaVersion===1?t:null}catch{return null}}function Ft(e,t=process.env){let n=Qn(t),r=N(e),o=r?.root??null,s=r?.config??null,i={},a={},c=(l)=>{let p=s?.[l],d=n?.[l];if(p!==void 0)i[l]=p,a[l]="project";else if(d!==void 0)i[l]=d,a[l]="global"};for(let l of ue)c(l);for(let l of At){let p=s?.[l];if(p!==void 0)i[l]=p,a[l]="project"}return{merged:i,sources:a,global:n,project:s,paths:{global:Ht(t),project:o?Pe(o):null}}}function er(e){return[...ue,...At].map((n)=>({key:n,value:e.merged[n]??null,source:e.sources[n]??"default"}))}function Po(e,t){if(e==="sandbox"&&!Yn.includes(t))return`sandbox must be one of ${Yn.join(", ")}; got "${t}".`;if(e==="harness"&&!pe.includes(t))return`harness must be one of ${pe.join(", ")}; got "${t}".`;if(e==="model"&&t.trim()==="")return"model must not be empty.";return null}function Nt(e){if(ue.includes(e))return e;let t=At.includes(e);throw new y("invalid_usage",t?`${e} is written by \`hlix init\` and \`hlix import\`, not by \`hlix config set\`.`:`Unknown setting: ${e}. Known settings: ${ue.join(", ")}.`)}function tr(e,t){let n=Po(e,t);if(n)throw new y("invalid_usage",n);return t}function nr(e){if(e.scope==="global"){let r=Ht(e.env),o=Qn(e.env)??{schemaVersion:1};return Ee(r,{...o,[e.key]:e.value}),r}let t=N(e.cwd);if(!t)throw new y("not_initialized","This folder is not bound to hlix. Run `hlix init` here, or set it machine-wide with --global.");let n=Pe(t.root);return Ee(n,{...t.config,[e.key]:e.value}),n}var Lt={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 Required. Workspace (organization) id to act in","","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(`
44
- `),supportsJson:!0,options:["base-url","workspace"],async run(e){let t=typeof e.flags.workspace==="string"?e.flags.workspace:e.env.HLIX_WORKSPACE_ID;if(!t)throw new y("missing_argument","--workspace is required.");let n=e.env.HLIX_API_KEY??await e.readSecret?.("Hlix API key: ")??"";if(!n)throw new y("missing_credential","No API key entered. Run from a terminal or set HLIX_API_KEY for CI.");let r=typeof e.flags["base-url"]==="string"?e.flags["base-url"]:e.env.HLIX_BASE_URL??jt,o=new URL(r),s=o.hostname==="localhost"||o.hostname==="127.0.0.1"||o.hostname==="::1";if(o.protocol!=="https:"&&!(o.protocol==="http:"&&s))throw new y("invalid_base_url","--base-url must use HTTPS (HTTP is allowed only for localhost).");await new Me({baseUrl:r,credential:xe(n),organizationId:t,retry:{attempts:1}}).projects.list();let a=Fn({baseUrl:r,apiKey:n,organizationId:t},e.env);if(e.json)e.stdout(v(j(Lt.name,{baseUrl:r,organizationId:t,credentialPath:a})));else e.stdout(`Signed in to ${r}
45
- Credential stored at ${a}
46
- `);return 0}},Ut={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 environment or the stored file —","and verifies it against the API. The key itself is never printed, not even","a prefix: machine output gets piped into logs."].join(`
47
- `),supportsJson:!0,async run(e){let t=B({env:e.env,flags:e.flags,cwd:e.cwd});if(t.conflict)throw new y("workspace_mismatch",t.conflict);if(!t.credential)throw new y("unauthenticated","No credential. Run `hlix auth login`, or set HLIX_API_KEY for CI.");try{await e.requireClient().projects.list()}catch(r){throw e.stderr(`credential from ${t.credentialSource}, workspace ${t.workspaceId??"none"}, api ${t.baseUrl}
48
- `),r}let n={credentialSource:t.credentialSource,credentialPath:t.credentialSource==="file"?t.credentialPath:null,baseUrl:t.baseUrl,baseUrlSource:t.baseUrlSource,workspaceId:t.workspaceId,workspaceSource:t.workspaceSource,valid:!0};if(e.json)return e.stdout(v(j(Ut.name,n))),0;return e.stdout(`${R([["credential",t.credentialSource==="env"?`environment (${t.credential?.sessionToken?"HLIX_SESSION_TOKEN":"HLIX_API_KEY"})`:`file (${t.credentialPath})`],["api",`${t.baseUrl} (from ${t.baseUrlSource})`],["workspace",t.workspaceId?`${t.workspaceId} (from ${t.workspaceSource})`:"none"],["status","valid"]])}
49
- `),0}},me={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."].join(`
50
- `),supportsJson:!0,options:["yes"],async run(e){let t=B({env:e.env,flags:e.flags,cwd:e.cwd});if(t.credentialSource==="env"){let r=Hn(e.env);if(!r){let s={removed:!1,reason:"environment",path:null};if(e.json)e.stdout(v(j(me.name,s)));else e.stdout(`HLIX_API_KEY is set in this environment; unset it there to sign out.
51
- `);return 0}if(e.flags.yes!==!0){let s={removed:!1,reason:"environment",path:r};if(e.json)e.stdout(v(j(me.name,s)));else e.stdout(`HLIX_API_KEY is set in this environment; unset it there to sign out.
52
- A stored credential also exists at ${r} — repeat with --yes to remove it.
53
- `);return 0}let o=bt(e.env);if(e.json)e.stdout(v(j(me.name,o)));else e.stdout(`Removed ${o.path}
54
- HLIX_API_KEY is still set in this environment; unset it there to finish signing out.
55
- `);return 0}if(e.flags.yes!==!0&&t.credential){if(e.json||!e.confirm)throw new y("approval_required","Removing the stored credential needs approval. Repeat with `--yes`.");if(!await e.confirm(`Remove the stored credential at ${t.credentialPath}? Signing back in needs the API key again.`))throw new y("cancelled","Logout cancelled.")}let n=bt(e.env);if(e.json)e.stdout(v(j(me.name,n)));else e.stdout(n.removed?`Removed ${n.path}
56
- `:`No stored credential at ${n.path}
57
- `);return 0}};var rr=ue.join(" | "),Mt={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(`
58
- `),supportsJson:!0,async run(e){let t=Ft(e.cwd,e.env),n=er(t);if(e.json)return e.stdout(v(j(Mt.name,{settings:n,paths:t.paths}))),0;return e.stdout(`${ae(["setting","value","source","applies to"],n.map((r)=>[r.key,r.value??"-",r.source,Zn[r.key]??"this folder's binding"]))}
59
- `),e.stdout(`
60
- global ${t.paths.global}
61
- `),e.stdout(`project ${t.paths.project??"- (this folder is not bound to hlix)"}
62
- `),0}},Bt={name:"config get",summary:"Print one setting's effective value",usage:[`Usage: hlix config get <${rr}> [--cwd <dir>] [--json]`,"","Prints the value the cascade resolves for one key, or exits 1 when no","file names it."].join(`
63
- `),supportsJson:!0,args:{min:1,max:1},async run(e){let t=Nt(e.args[0]),n=Ft(e.cwd,e.env),r=n.merged[t]??null,o=n.sources[t]??"default";if(e.json)return e.stdout(v(j(Bt.name,{key:t,value:r,source:o}))),r===null?1:0;if(r===null)return e.stderr(`${t} is not set. Set it with \`hlix config set ${t} <value>\`.
64
- `),1;return e.stdout(`${r}
65
- `),0}},Kt={name:"config set",summary:"Set one setting for this folder, or for the machine with --global",usage:[`Usage: hlix config set <${rr}> <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(`
66
- `),supportsJson:!0,options:["global"],args:{min:2,max:2},async run(e){let t=Nt(e.args[0]),n=tr(t,e.args[1]),r=e.flags.global===!0?"global":"project",o=nr({key:t,value:n,scope:r,cwd:e.cwd,env:e.env});if(e.json)return e.stdout(v(j(Kt.name,{key:t,value:n,scope:r,path:o}))),0;return e.stdout(`${t} = ${n} (${r}: ${o})
67
- `),0}};function te(e,t){if(typeof e!=="object"||e===null)return"";let n=e[t];return n===null||n===void 0?"":String(n)}var zt={name:"projects list",summary:"List the projects in your workspace",usage:"Usage: hlix projects list [--json]",supportsJson:!0,async run(e){let t=await e.requireClient().projects.list();if(e.json)return e.stdout(v(j(zt.name,t))),0;let n=Array.isArray(t)?t:[];if(n.length===0)return e.stdout(`No projects.
68
- `),0;return e.stdout(`${ae(["ID","NAME","STACK"],n.map((r)=>[te(r,"id"),te(r,"name"),te(r,"stack")]))}
69
- `),0}},Dt={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(`
70
- `),supportsJson:!0,args:{min:0,max:1},async run(e){let t=e.args[0]??N(e.cwd)?.config.projectId;if(!t)throw new y("missing_argument","A project id is required, or run this inside a folder bound to a project.");let n=await e.requireClient().projects.get(t);if(e.json)return e.stdout(v(j(Dt.name,n))),0;let r=n.repos;return e.stdout(`${R([["id",te(n,"id")],["name",te(n,"name")],["stack",te(n,"stack")],["status",te(n,"status")],["repos",Array.isArray(r)?String(r.length):""]].filter(([,o])=>o!==""))}
71
- `),0}};function qt(e,t){let n=e.args[0];if(!n)throw new y("missing_argument",`A ${t} id is required.`);return n}function or(e,t){let n=e.flags[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function K(e,t){if(typeof e!=="object"||e===null)return"";let n=e[t];return n===null||n===void 0?"":String(n)}var Jt={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(`
72
- `),supportsJson:!0,options:["project","status"],async run(e){let t=or(e,"project")??N(e.cwd)?.config.projectId,n=or(e,"status"),r=await e.requireClient().tasks.list({...t?{projectId:t}:{},...n?{status:n}:{}});if(e.json)return e.stdout(v(j(Jt.name,r))),0;let o=Array.isArray(r)?r:[];if(o.length===0)return e.stdout(`No tasks.
73
- `),0;return e.stdout(`${ae(["ID","STATUS","TITLE"],o.map((s)=>[K(s,"id"),K(s,"status"),K(s,"title")||K(s,"description").split(`
74
- `)[0]||""]))}
75
- `),0}},Gt={name:"tasks get",summary:"Show one task",usage:"Usage: hlix tasks get <task-id> [--json]",supportsJson:!0,args:{min:1,max:1},async run(e){let t=qt(e,"task"),n=await e.requireClient().tasks.get(t);if(e.json)return e.stdout(v(j(Gt.name,n))),0;return e.stdout(`${R([["id",K(n,"id")],["status",K(n,"status")],["title",K(n,"title")],["project",K(n,"projectId")],["description",K(n,"description")]])}
76
- `),0}},Wt={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(e){let t=qt(e,"task"),n=await e.requireClient().tasks.review(t);if(e.json)return e.stdout(v(j(Wt.name,n))),0;return e.stdout(`${JSON.stringify(n,null,2)}
77
- `),0}},Vt={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(`
78
- `),supportsJson:!0,args:{min:1,max:1},async run(e){let t=qt(e,"task"),n=e.requireClient();for await(let r of n.tasks.stream(t)){let o;try{o=JSON.parse(r.data)}catch{o=r.data}if(e.json)e.stdout(`${JSON.stringify(j(Vt.name,o))}
79
- `);else{let s=K(o,"status"),i=K(o,"error");e.stdout(i?`error: ${i}
80
- `:`${s||r.data}
81
- `)}}return 0}};import{realpath as is}from"node:fs/promises";import{resolve as as}from"node:path";import{createHash as gr}from"node:crypto";import{createReadStream as Oo}from"node:fs";import{lstat as hr,readFile as st,readdir as Ro,realpath as yr,stat as To}from"node:fs/promises";import{basename as re,join as wr,relative as dr,resolve as pr,sep as Ao}from"node:path";import{spawnSync as Ho}from"node:child_process";import ur from"ignore";import{readFile as $o}from"node:fs/promises";import{join as xo}from"node:path";function Co(e){let t=e.trim();if(!t||/^[|>[{]/.test(t))return null;let n=t.match(/^(["'])([\s\S]*)\1$/);if(!n&&/^["']/.test(t))return null;return(n?n[2].trim():t.replace(/(?:^|\s)#.*$/,"").trim())||null}function sr(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>/^tasks:\s*(?:#.*)?$/.test(i));if(n===-1)return{tasks:[],partial:/^tasks:\s*\S/m.test(e)};let r=[],o=!1,s=-1;for(let i of t.slice(n+1)){if(!i.trim()||/^\s*#/.test(i))continue;let a=i.length-i.trimStart().length,c=i.match(/^(\s*-(?:\s+|$))(.*)$/);if(c){if(s!==-1&&a>=s)continue;if(r.push({}),s=c[2]?c[1].length:-1,!c[2])continue}else if(a===0)break;else if(r.length===0)continue;else if(s===-1)s=a;else if(a!==s)continue;let l=(c?c[2]:i.trim()).match(/^([A-Za-z_][A-Za-z0-9_-]*):\s*(.*)$/);if(!l)continue;let p=l[1];if(p!=="name"&&p!=="before"&&p!=="init"&&p!=="command")continue;let d=Co(l[2]);if(d===null)o=!0;else r[r.length-1][p]=d}return{tasks:r,partial:o}}async function ne(e,t){try{return await $o(xo(e,...t.split("/")),"utf8")}catch(n){if(n.code==="ENOENT")return null;throw n}}function ir(e){try{let t=e.replace(/(^|[^:\\])\/\/.*$/gm,"$1").replace(/\/\*[\s\S]*?\*\//g,"").replace(/,\s*([}\]])/g,"$1");return JSON.parse(t)}catch{return null}}function Y(e){if(typeof e==="string"&&e.trim())return[e.trim()];if(Array.isArray(e))return e.flatMap(Y);if(e&&typeof e==="object")return Object.values(e).flatMap(Y);return[]}function Xt(e){if(!e||typeof e!=="object")return[];return Object.keys(e).filter((t)=>/^[A-Za-z_][A-Za-z0-9_]*$/.test(t))}function Io(e,t){let n=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(t)r.push(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::[-?][^}]*)?\}/g);for(let o of r)for(let s of e.matchAll(o))n.add(s[1]);return[...n]}function _o(e,t){if(e.has("bun.lock")||e.has("bun.lockb")||t?.startsWith("bun@"))return"bun install --frozen-lockfile";if(e.has("pnpm-lock.yaml")||t?.startsWith("pnpm@"))return"pnpm install --frozen-lockfile";if(e.has("yarn.lock")||t?.startsWith("yarn@"))return"yarn install --immutable";if(e.has("package-lock.json")||e.has("npm-shrinkwrap.json"))return"npm ci";if(e.has("package.json"))return"npm install";return null}function ar(e){let t=typeof e==="number"?e:Number(e);return Number.isInteger(t)&&t>0&&t<=65535?t:null}function U(e,t,n){if(!e.some((r)=>r.path===t&&r.kind===n))e.push({path:t,kind:n})}async function cr(e,t,n){let r=[],o=[],s=[],i=[],a=new Map,c=new Set,l=new Set,p=[],d={},u=null,m=0,h=await ne(e,".cursor/environment.json");if(h){U(r,".cursor/environment.json","cursor");let f=ir(h);if(!f)p.push("Could not parse .cursor/environment.json; it remains quarantined.");else{o.push(...Y(f.install));let P=Y(f.start);if(P[0])u=P[0];if(Array.isArray(f.terminals))for(let b of f.terminals){if(!b||typeof b!=="object")continue;let x=b;if(typeof x.command!=="string"||!x.command.trim())continue;i.push({name:typeof x.name==="string"&&x.name.trim()?x.name.trim():"Terminal",command:x.command.trim(),...typeof x.cwd==="string"&&x.cwd.trim()?{cwd:x.cwd.trim()}:{}})}}}let k=t.has(".devcontainer/devcontainer.json")?".devcontainer/devcontainer.json":t.has("devcontainer.json")?"devcontainer.json":null;if(k){U(r,k,"devcontainer");let f=ir(n.get(k)??await ne(e,k)??"");if(!f)p.push(`Could not parse ${k}; it remains quarantined.`);else{o.push(...Y(f.onCreateCommand),...Y(f.updateContentCommand),...Y(f.postCreateCommand));let P=Y(f.postStartCommand);if(!u&&P[0])u=P[0];for(let b of Xt(f.secrets))c.add(b);for(let b of[...Xt(f.containerEnv),...Xt(f.remoteEnv)])c.add(b);if(Array.isArray(f.forwardPorts))for(let b of f.forwardPorts){let x=ar(b);if(x)a.set(x,{port:x,visibility:"private"})}}}if(t.has(".gitpod.yml")){U(r,".gitpod.yml","gitpod");let f=n.get(".gitpod.yml")??await ne(e,".gitpod.yml");if(f===null)p.push("Could not read .gitpod.yml; its task commands were not imported.");else{let P=sr(f);m=P.tasks.filter((b)=>b.before).length;for(let b of P.tasks){if(b.before)o.push(b.before);if(b.init)o.push(b.init);if(!b.command)continue;if(!u)u=b.command;else i.push({name:b.name??"Terminal",command:b.command})}if(P.partial)p.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 f of["Dockerfile","docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml"])if(t.has(f))U(r,f,"docker");for(let f of["project.toml","nixpacks.toml","railpack.json","Aptfile"])if(t.has(f))U(r,f,"buildpack");for(let f of["fly.toml","railway.json","render.yaml","vercel.json","netlify.toml"])if(t.has(f))U(r,f,"platform");let _=n.get("package.json")??await ne(e,"package.json");if(_){U(r,"package.json","package");try{let f=JSON.parse(_);if(f.engines?.node)d.node=f.engines.node;let P=_o(t,f.packageManager);if(P&&o.length===m)o.push(P);if(f.scripts?.build&&s.length===0)s.push(`${f.packageManager?.split("@")[0]??(t.has("bun.lock")?"bun":"npm")} run build`);let b=f.scripts?.dev?`${t.has("bun.lock")?"bun":"npm"} run dev`:null,x=f.scripts?.start?`${t.has("bun.lock")?"bun":"npm"} run start`:b;if(!u&&x)u=x}catch{p.push("Could not parse package.json for environment discovery.")}}if(t.has("uv.lock"))o.push("uv sync --frozen");else if(t.has("poetry.lock"))o.push("poetry install --no-interaction");else if(t.has("requirements.txt"))o.push("python -m pip install -r requirements.txt");if(t.has("go.mod"))o.push("go mod download");if(t.has("Procfile")){U(r,"Procfile","procfile");let P=(n.get("Procfile")??"").split(/\r?\n/).find((b)=>/^web\s*:/.test(b));if(P)u=P.replace(/^web\s*:\s*/,"").trim()||u}let D=[[".node-version","node"],[".nvmrc","node"],[".python-version","python"]];for(let[f,P]of D){let b=(n.get(f)??await ne(e,f))?.trim();if(b)d[P]=b,U(r,f,"tool-version")}let E=n.get(".tool-versions")??await ne(e,".tool-versions");if(E){U(r,".tool-versions","tool-version");for(let f of E.split(/\r?\n/)){let[P,b]=f.trim().split(/\s+/,2);if(!b)continue;if(P==="nodejs")d.node=b;else if(P==="python")d.python=b;else if(P==="bun")d.bun=b}}let O=n.get("mise.toml")??await ne(e,"mise.toml");if(O){U(r,"mise.toml","tool-version");for(let f of O.matchAll(/^\s*(node|python|bun)\s*=\s*["']([^"']+)["']/gm))d[f[1]]=f[2]}for(let[f,P]of n){let b=/(?:^|\/)(?:Dockerfile|Procfile)$/i.test(f)||/\.(?:jsonc?|ya?ml|toml|ini|conf|config|env|sh|bash|zsh|fish)$/i.test(f);for(let x of Io(P,b))l.add(x);for(let x of P.matchAll(/(?:--port(?:=|\s+)|PORT\s*=\s*)(\d{2,5})/g)){let z=ar(x[1]);if(z)a.set(z,{port:z,visibility:"private"})}}if(r.length===0&&t.size>0)U(r,"repository","detected");let A=(f)=>[...new Set(f.filter(Boolean))],ye=r.length+o.length+(u?1:0);return{sources:r.sort((f,P)=>f.path.localeCompare(P.path)),toolchain:d,install:A(o),build:A(s),start:u,terminals:i,ports:[...a.values()].sort((f,P)=>f.port-P.port),requiredSecretKeys:[...c].sort(),observedSecretKeys:[...l].sort(),confidence:ye>=4?"high":ye>=2?"medium":"low",warnings:p}}var lr=2;var Fo=25000,No=52428800,Lo=524288000,it=1e4,ot=1048576,fe=10485760,mr=[".git/",".hlix/","node_modules/",".next/",".turbo/",".cache/","dist/","build/","coverage/","__pycache__/",".venv/","venv/","target/",".DS_Store"],Uo=/(^|\/)\.env\.(example|sample|template)$/i,Mo=/(^|\/)\.env(?:\.[^/]+)?$/i,Bo=/(^|\/)(?:\.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)|terraform\.tfvars(?:\.json)?)$/i,Ko=/(^|\/)(?:\.mcp\.json|mcp\.json|claude_desktop_config\.json)$/i,zo=/(^|\/)(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.github\/copilot-instructions\.md)$/i,Do=/(^|\/)(?:\.agents|\.claude)\/skills\//i,qo=/-----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,}/,Jo=/\.(?:json|ya?ml|toml|ini|conf|config)$/i,Go=/(?:^|[,{\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,Be=/^HLIX_[A-Za-z0-9_]*$/,Yt=new Set(["CI","HOME","LANG","LOGNAME","NODE_ENV","OLDPWD","PATH","PORT","PWD","SHELL","SHLVL","TERM","TMPDIR","USER","_"]);function Ke(e){return e.split(Ao).join("/")}function Z(e,t,n=10485760){return Ho("git",["-C",e,...t],{encoding:"utf8",maxBuffer:n,stdio:["ignore","pipe","pipe"]})}async function Wo(e){let t=gr("sha256");for await(let n of Oo(e))t.update(n);return t.digest("hex")}function Zt(e){if(Array.isArray(e))return`[${e.map(Zt).join(",")}]`;if(e&&typeof e==="object")return`{${Object.entries(e).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>`${JSON.stringify(t)}:${Zt(n)}`).join(",")}}`;return JSON.stringify(e)}function vr(e){let t={};for(let[n,r]of String(e).replace(/^\uFEFF/,"").split(/\r?\n/).entries()){let o=r.trim();if(!o||o.startsWith("#"))continue;let i=(o.startsWith("export ")?o.slice(7).trimStart():o).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!i)throw Error(`Invalid dotenv assignment on line ${n+1}`);let a=i[2]??"";if(a.startsWith('"')){if(!a.endsWith('"'))throw Error(`Unclosed dotenv quote on line ${n+1}`);a=a.slice(1,-1).replace(/\\n/g,`
82
- `).replace(/\\r/g,"\r")}else if(a.startsWith("'")){if(!a.endsWith("'"))throw Error(`Unclosed dotenv quote on line ${n+1}`);a=a.slice(1,-1)}else a=a.replace(/\s+#.*$/,"").trimEnd();t[i[1]]=a}return t}function Vo(e){let t=null;for(let n=0;n<e.length;n+=1){let r=e[n];if(r==="\\"&&t!=="single"){if(e[n+1]!=="$")return!0;n+=1;continue}if(r==="'"&&t!=="double"){t=t==="single"?null:"single";continue}if(r==='"'&&t!=="single"){t=t==="double"?null:"double";continue}if(t!=="single"&&(r==="$"||r==="`"))return!0;if(t===null&&(r==="<"||r===">")&&e[n+1]==="(")return!0}return t!==null}function Xo(e){let t={},n=new Set,r=new Set;for(let o of String(e).replace(/^\uFEFF/,"").split(/\r?\n/)){let s=o.trim();if(!s||s.startsWith("#"))continue;let a=(s.startsWith("export ")?s.slice(7).trimStart():s).match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!a)continue;let c=a[1],l=a[2]??"";if(n.add(c),Vo(l)){delete t[c],r.add(c);continue}try{let d=vr(`${c}=${l}`)[c];if(d===void 0)throw Error("missing literal");t[c]=l.trimStart().startsWith("'")?d:d.replace(/\\\$/g,"$"),r.delete(c)}catch{delete t[c],r.add(c)}}return{values:t,keys:[...n].sort(),dynamicKeys:[...r].sort()}}async function Yo(e){let t=Z(e,["rev-parse","--show-toplevel"]);if(t.status!==0)return!1;try{return await yr(t.stdout.trim())===e}catch{return!1}}function Zo(e,t){if(!t)return new Set;let n=Z(e,["ls-files","-z"]);if(n.status!==0)throw Error("Could not enumerate tracked files.");return new Set(n.stdout.split("\x00").filter(Boolean).map(Ke))}async function Qo(e){let t=ur().add(mr),n=ur().add(mr);for(let r of[".gitignore",".hlixignore"])try{let o=wr(e,r);if((await hr(o)).isFile())n.add(await st(o,"utf8"))}catch(o){if(o.code!=="ENOENT")throw o}return{hardMatcher:t,matcher:n}}function es(e){if(Ko.test(e))return"mcp";if(Do.test(e))return"skill";if(zo.test(e))return"agent";return null}function ts(e){if(Mo.test(e)&&!Uo.test(e))return"dotenv";if(Bo.test(e))return"credential";return null}function ns(e){if(e.has("package.json"))return"typescript";if(e.has("pyproject.toml")||e.has("requirements.txt"))return"python";if(e.has("go.mod"))return"go";if(e.has("Cargo.toml"))return"rust";if(e.has("composer.json"))return"php";if(e.has("Gemfile"))return"ruby";return"other"}function rs(e,t){if(t)return[Ke(t)];let n=new Map([[".env",0],[".env.development",1],[".env.local",2],[".env.development.local",3]]),r=e.filter((o)=>n.has(re(o).toLocaleLowerCase("en-US"))).sort((o,s)=>o.slice(0,-re(o).length).localeCompare(s.slice(0,-re(s).length))||n.get(re(o).toLocaleLowerCase("en-US"))-n.get(re(s).toLocaleLowerCase("en-US")));return r.length>0?r:e.length===1?[...e]:[]}function os(e,t){try{let n=JSON.parse(t);if(!n.mcpServers||typeof n.mcpServers!=="object")return[];return Object.entries(n.mcpServers).map(([r,o])=>{let s=o&&typeof o==="object"?o:{},i=s.type==="http"||s.type==="sse"||s.type==="stdio"?s.type:typeof s.command==="string"?"stdio":typeof s.url==="string"?"http":"unknown",a=s.env&&typeof s.env==="object"?s.env:{};return{sourcePath:e,name:r,transport:i,...typeof s.command==="string"?{command:s.command}:{},...Array.isArray(s.args)&&s.args.every((c)=>typeof c==="string")?{args:s.args}:{},...typeof s.url==="string"?{url:s.url}:{},envKeys:Object.keys(a).sort(),enabled:!1}})}catch{return[]}}function fr(e,t){let n=[],r="unknown";for(let o of e.split(/\r?\n/)){if(o.startsWith("@@"))r=o.slice(2);else if(o.trim())n.push({commit:r,path:Ke(o.trim()),reason:t});if(n.length>=100)break}return n}function ss(e,t){if(!t)return{head:null,branch:null,refs:[],commitCount:0,complete:!0,findings:[]};let n=Z(e,["rev-parse","HEAD"]).stdout.trim()||null,r=Z(e,["symbolic-ref","--short","-q","HEAD"]),o=r.status===0?r.stdout.trim()||null:null,s=Number.parseInt(Z(e,["rev-list","--count","--all"]).stdout.trim(),10)||0,i=Z(e,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]),a=i.stdout.split(`
83
- `).filter(Boolean).map((u)=>{let[m,h]=u.split("\x00");return{name:m,oid:h}}).filter(({name:u,oid:m})=>/^refs\/(?:heads|tags)\/.+/.test(u)&&/^[0-9a-f]{40,64}$/.test(m)).sort((u,m)=>u.name.localeCompare(m.name)),c=["log","--all",`--max-count=${it}`,"--pretty=format:@@%H","--name-only"],l=Z(e,[...c,"--",".env",".env.*","*.pem","*.key",".npmrc","*.tfvars"]),p=Z(e,["log","--all",`--max-count=${it}`,"-G","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,}","--pretty=format:@@%H","--name-only"]),d=new Map;for(let u of[...fr(l.stdout,"sensitive-path"),...fr(p.stdout,"secret-pattern")])d.set(`${u.commit}:${u.path}:${u.reason}`,u);return{head:n,branch:o,refs:a,commitCount:s,complete:s<=it&&a.length<=1000&&i.status===0&&l.status===0&&p.status===0,findings:[...d.values()].slice(0,100)}}async function Q(e,t={}){let n=await yr(pr(e));if(!(await To(n)).isDirectory())throw Error("Import target must be a directory.");let r=await Yo(n),o=Zo(n,r),{hardMatcher:s,matcher:i}=await Qo(n),a=[],c=[],l=[],p=[],d=[],u=[],m=t.envFile?Ke(dr(n,pr(n,t.envFile))):void 0,h=m!==void 0&&m!==""&&m!==".."&&!m.startsWith("../");if(t.envFile&&!h)u.push(`Selected environment file must stay inside the project: ${t.envFile}`);let k=new Map,_=new Map,D=new Map,E=new Map,O=[],A=[],ye=new Map,f=t.maxFiles??Fo,P=t.maxFileBytes??No,b=t.maxTotalBytes??Lo,x=0,z=0,jn=async(g)=>{let S=await Ro(g,{withFileTypes:!0});S.sort((I,H)=>I.name.localeCompare(H.name));for(let I of S){let H=wr(g,I.name),C=Ke(dr(n,H));if(I.name===".git"){if(C!==".git")u.push(`Nested Git repository is not supported: ${C}`);continue}let M=await hr(H),$n=I.isDirectory()?`${C}/`:C,yt=o.has(C),xn=!yt&&i.ignores($n),Br=!yt&&s.ignores($n);if(M.isSymbolicLink()){if(d.push({path:C,reason:"symlink"}),!xn)u.push(`Symlinks are not imported in this release: ${C}`);continue}if(I.isDirectory()){if(Br)continue;await jn(H);continue}let ve=es(C),ke=ts(C);if(xn&&!ve&&!ke)continue;if(!I.isFile()){d.push({path:C,reason:"non-regular-file"});continue}if(a.length+c.length+l.length>=f){u.push(`Project exceeds the ${f} file limit.`);return}if(M.size>P){u.push(`File exceeds the ${P} byte limit: ${C}`);continue}if(x+=M.size,x>b){u.push(`Project exceeds the ${b} byte total limit.`);return}let Ve=await Wo(H);if(ve){if(M.size>ot){u.push(`Protected configuration exceeds the ${ot} byte limit: ${C}`);continue}let F=await st(H);if(z+=F.byteLength,z>fe){u.push(`Protected project files exceed the ${fe} byte total limit.`);continue}if(l.push({path:C,kind:ve,size:M.size,sha256:Ve}),A.push({path:C,kind:ve,contentBase64:F.toString("base64")}),ve==="mcp")p.push(...os(C,F.toString("utf8")));continue}if(ke){if(M.size>ot){u.push(`Protected file exceeds the ${ot} byte limit: ${C}`);continue}let F=await st(H);if(z+=F.byteLength,z>fe){u.push(`Protected project files exceed the ${fe} byte total limit.`);continue}let ee=[];if(ke==="dotenv")try{let Xe=vr(F),se={};for(let[X,ie]of Object.entries(Xe)){if(Be.test(X)){u.push(`Hlix control-plane environment keys cannot be imported into a project: ${X}`);continue}se[X]=ie}k.set(C,se),ee=Object.keys(se).sort()}catch{u.push(`Could not parse environment file: ${C}`)}else if(re(C)===".envrc"){let Xe=Xo(F),se={},X=new Set,ie=[];for(let[T,Kr]of Object.entries(Xe.values)){if(Be.test(T)){u.push(`Hlix control-plane environment keys cannot be imported into a project: ${T}`);continue}if(Yt.has(T)){O.push(`Ignored ambient runtime assignment in ${C}: ${T}`);continue}X.add(T),se[T]=Kr}_.set(C,se);for(let T of Xe.dynamicKeys){if(Be.test(T)){u.push(`Hlix control-plane environment keys cannot be imported into a project: ${T}`);continue}if(Yt.has(T)){O.push(`Ignored ambient runtime assignment in ${C}: ${T}`);continue}X.add(T),ie.push(T)}if(D.set(C,[...X].sort()),E.set(C,ie.sort()),ee=[...X].sort(),ie.length>0)O.push(`Did not execute dynamic .envrc assignments; collect their resolved local values when available: ${ie.join(", ")}`)}c.push({path:C,kind:ke,keys:ee,size:M.size,sha256:Ve}),A.push({path:C,kind:ke,contentBase64:F.toString("base64")});continue}if(M.size<=1048576){let F=await st(H),ee=F.toString("utf8");if(ye.set(C,ee),qo.test(ee)||Jo.test(C)&&Go.test(ee)){if(z+=F.byteLength,z>fe){u.push(`Protected project files exceed the ${fe} byte total limit.`);continue}c.push({path:C,kind:"detected-content",keys:[],size:M.size,sha256:Ve}),A.push({path:C,kind:"detected-content",contentBase64:F.toString("base64")});continue}}a.push({path:C,size:M.size,sha256:Ve,tracked:yt,executable:(M.mode&73)!==0})}};await jn(n),a.sort((g,S)=>g.path.localeCompare(S.path)),c.sort((g,S)=>g.path.localeCompare(S.path)),l.sort((g,S)=>g.path.localeCompare(S.path)),p.sort((g,S)=>`${g.sourcePath}:${g.name}`.localeCompare(`${S.sourcePath}:${S.name}`));let mt=rs([...k.keys()].sort(),h?m:void 0);if(t.envFile&&h&&!k.has(mt[0]))u.push(`Selected environment file was not found or is not a dotenv file: ${t.envFile}`);let we=new Map;for(let[g,S]of k)for(let I of Object.keys(S))we.set(I,[...we.get(I)??[],g]);for(let[g,S]of D)for(let I of S)we.set(I,[...we.get(I)??[],g]);let Fr=[...we].filter(([,g])=>g.length>1).map(([g,S])=>({key:g,paths:S.sort()})).sort((g,S)=>g.key.localeCompare(S.key)),q={};for(let g of mt)Object.assign(q,k.get(g)??{});let Nr=[..._.keys()].sort((g,S)=>{if(g===".envrc")return 1;if(S===".envrc")return-1;return g.localeCompare(S)}),ft=new Set;for(let g of Nr){let S=new Set(E.get(g)??[]);for(let I of D.get(g)??[]){if(S.has(I)){delete q[I],ft.add(I);continue}let H=_.get(g)?.[I];if(H!==void 0)q[I]=H;ft.delete(I)}}let gt=t.historyMode??"abort_on_findings",V=ss(n,r);if(!V.complete&&gt!=="preserve")u.push(`Git history scan exceeded ${it} commits or failed; import requires explicit --history preserve.`);if(V.findings.length>0&&gt==="abort_on_findings")u.push("Potential secrets exist in Git history. Abort, sanitize the repository, or explicitly use --history preserve.");let En=new Set(a.map((g)=>g.path)),Lr=await cr(n,En,ye),{observedSecretKeys:Ur,...J}=Lr;J.warnings.push(...O);let ht=new Set(J.requiredSecretKeys);for(let g of ft)ht.add(g);for(let g of p)for(let S of g.envKeys)ht.add(S);J.requiredSecretKeys=[...ht].sort();for(let g of J.requiredSecretKeys){if(Be.test(g)){u.push(`Hlix control-plane environment keys cannot be imported into a project: ${g}`);continue}if(q[g]!==void 0)continue;let S=t.environment?.[g];if(S===void 0){u.push(`Required project environment value was not found locally: ${g}`);continue}q[g]=S}for(let g of Ur){if(Be.test(g)){J.warnings.push(`Ignored reserved Hlix control-plane environment reference: ${g}`);continue}if(Yt.has(g))continue;if(q[g]!==void 0)continue;let S=t.environment?.[g];if(S===void 0){J.warnings.push(`Observed environment reference has no local value: ${g}`);continue}q[g]=S}J.warnings=[...new Set(J.warnings)].sort();let Pn={schemaVersion:lr,rootName:t.rootName??re(n),stack:ns(En),git:{detected:r,head:V.head,branch:V.branch,refs:V.refs,commitCount:V.commitCount,historyScanComplete:V.complete,historyMode:gt},files:a,secretFiles:c,activeEnvFiles:mt,secretKeys:Object.keys(q).sort(),envCollisions:Fr,quarantinedResources:l,mcpServers:p,historicalSecretFindings:V.findings,skipped:d,environment:J,totals:{files:a.length,bytes:a.reduce((g,S)=>g+S.size,0)}},Cn=Zt(Pn),Mr=gr("sha256").update(Cn).digest("hex");return{root:n,manifest:Pn,manifestJson:Cn,manifestSha256:Mr,secretValues:q,protectedFiles:A.sort((g,S)=>g.path.localeCompare(S.path)),blocking:[...new Set(u)]}}var Qt={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`)"].join(`
84
- `),supportsJson:!0,options:["project"],args:{min:0,max:1},async run(e){if(e.args.length>1)throw Error("init accepts at most one folder.");let t=await is(as(e.cwd,e.args[0]??".")),n=B({env:e.env,flags:e.flags,cwd:t});if(n.conflict)throw new y("workspace_mismatch",n.conflict);if(!n.workspaceId)throw Error("No workspace selected. Run `hlix auth login --workspace <id>` first.");let r=e.requireClient(t);await r.projects.list();let o=le(t),s=typeof e.flags.project==="string"?e.flags.project:void 0;if(s&&o?.projectId&&o.projectId!==s)throw new y("workspace_mismatch",`This folder is bound to project ${o.projectId}; refusing to rebind it to ${s}.`);if(s)await r.projects.get(s);let i={...o??{schemaVersion:1,workspaceId:n.workspaceId,apiUrl:n.baseUrl},...s?{projectId:s}:{}};Ce(t,i);let a=await Q(t,{environment:e.env}),c={root:t,config:i,scan:{files:a.manifest.totals.files,bytes:a.manifest.totals.bytes,secretFiles:a.manifest.secretFiles.map((l)=>l.path),quarantinedResources:a.manifest.quarantinedResources.map((l)=>l.path),blocking:a.blocking}};if(e.json)e.stdout(v(j(Qt.name,c)));else if(e.stdout(`Initialized ${t}
85
- Project: ${i.projectId??"not imported yet"}
86
- Workspace: ${i.workspaceId}
87
- `),a.blocking.length)e.stdout(`
88
- Review before import:
89
- ${a.blocking.map((l)=>`- ${l}`).join(`
90
- `)}
91
- `);return 0}};import{createHash as hs}from"node:crypto";import{readFile as ys,realpath as ws}from"node:fs/promises";import{basename as vs,resolve as ks}from"node:path";import{createHash as cs}from"node:crypto";import{createReadStream as ls}from"node:fs";import{chmod as en,copyFile as ds,lstat as kr,mkdir as br,mkdtemp as ps,readdir as us,rm as tn}from"node:fs/promises";import{tmpdir as ms}from"node:os";import{dirname as fs,join as oe}from"node:path";import{spawnSync as ze}from"node:child_process";function G(e,t){let n=ze("git",["-C",e,...t],{encoding:"utf8",maxBuffer:20971520,stdio:["ignore","pipe","pipe"]});if(n.status!==0){let r=n.stderr.trim().split(`
92
- `).at(-1)??"git command failed";throw Error(r)}return n.stdout.trim()}async function Sr(e){let t=cs("sha256");for await(let n of ls(e))t.update(n);return t.digest("hex")}async function gs(e){for(let t of await us(e)){if(t===".git")continue;await tn(oe(e,t),{recursive:!0,force:!0})}}async function at(e){if(e.blocking.length>0)throw Error(`Project scan has blocking findings:
93
- - ${e.blocking.join(`
94
- - `)}`);let t=await ps(oe(ms(),"hlix-snapshot-"));await en(t,448);let n=oe(t,"repo"),r=oe(t,"source.git"),o=oe(t,"project.bundle");try{if(e.manifest.git.detected){let d=ze("git",["clone","--mirror","--no-hardlinks",e.root,r],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(d.status!==0)throw Error(d.stderr.trim()||"Could not mirror repository.");let u=new Map(G(r,["for-each-ref","--format=%(refname)%00%(objectname)","refs/heads","refs/tags"]).split(`
95
- `).filter(Boolean).map((h)=>h.split("\x00",2)));for(let h of e.manifest.git.refs)if(u.get(h.name)!==h.oid)throw Error(`Git ref changed after scan: ${h.name}`);let m=ze("git",["clone","--no-hardlinks",r,n],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(m.status!==0)throw Error(m.stderr.trim()||"Could not create snapshot clone.");if(!e.manifest.git.head)throw Error("Git repository has no HEAD commit.");G(n,["checkout","-B","main",e.manifest.git.head])}else await br(n,{recursive:!0,mode:448}),G(n,["init","-b","main"]);await gs(n);for(let d of e.manifest.files){let u=oe(e.root,...d.path.split("/")),m=await kr(u);if(!m.isFile()||m.isSymbolicLink())throw Error(`Source changed after scan: ${d.path}`);if(m.size!==d.size||await Sr(u)!==d.sha256)throw Error(`Source changed after scan: ${d.path}`);let h=oe(n,...d.path.split("/"));await br(fs(h),{recursive:!0,mode:493}),await ds(u,h),await en(h,d.executable?493:420)}G(n,["config","user.name","Hlix Import"]),G(n,["config","user.email","import@hlix.ai"]),G(n,["add","-A"]),G(n,["commit","--allow-empty","-m","chore(hlix): import snapshot"]);let s=G(n,["rev-parse","HEAD"]),i=e.manifest.git.refs.filter((d)=>d.name!=="refs/heads/main");if(i.length>0){let d=ze("git",["-C",n,"update-ref","--stdin"],{encoding:"utf8",input:i.map((u)=>`update ${u.name} ${u.oid}`).join(`
96
- `)+`
97
- `,stdio:["pipe","pipe","pipe"]});if(d.status!==0)throw Error(d.stderr.trim()||"Could not recreate the approved Git refs.")}let a=i.map((d)=>d.name),c=ze("git",["-C",n,"bundle","create",o,"--stdin"],{encoding:"utf8",input:["refs/heads/main",...a].join(`
98
- `)+`
99
- `,stdio:["pipe","pipe","pipe"]});if(c.status!==0)throw Error(c.stderr.trim()||"Could not create the approved Git bundle.");G(n,["bundle","verify",o]),await en(o,384);let l=(await kr(o)).size,p=await Sr(o);return{bundlePath:o,bundleSha256:p,bundleSize:l,commitSha:s,dispose:()=>tn(t,{recursive:!0,force:!0})}}catch(s){throw await tn(t,{recursive:!0,force:!0}),s}}function De(e,t){let n=e[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function bs(e,t){return hs("sha256").update(`project-import-v1\x00${e}\x00${t}`).digest("hex")}function Ss(e){let t=e.manifest.environment.install,n=e.manifest.secretFiles.length+e.manifest.quarantinedResources.length;if(t.length===0&&n===0&&e.manifest.secretKeys.length===0)return null;let r=["Hlix will upload this project and encrypted protected files to your selected workspace."];if(t.length>0)r.push("Detected cloud setup commands:",...t.map((o)=>`- ${o}`));if(e.manifest.secretKeys.length>0)r.push("Project secret keys available to cloud tasks:",...e.manifest.secretKeys.map((o)=>`- ${o}`));if(e.manifest.quarantinedResources.length>0)r.push("Quarantined resources (preserved but not activated):",...e.manifest.quarantinedResources.map((o)=>`- ${o.kind}: ${o.path}`));if(e.manifest.environment.warnings.length>0)r.push("Environment warnings:",...e.manifest.environment.warnings.map((o)=>`- ${o}`));return r.push("Setup runs inside the isolated Coding Workspace and may access project secrets."),r.join(`
100
- `)}var ct={name:"import",summary:"Import a local project into your Hlix workspace",usage:["Usage: hlix import [folder] [options]","","Options:"," --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)"," --stack <stack> Override detected stack"," --yes Approve the reviewed upload and cloud setup"," --json Machine-readable output (never contains secret values)"].join(`
101
- `),supportsJson:!0,options:["dry-run","env-file","history","name","stack","yes"],args:{min:0,max:1},async run(e){if(e.args.length>1)throw Error("import accepts at most one folder.");let t=await ws(ks(e.cwd,e.args[0]??".")),n=B({env:e.env,flags:e.flags,cwd:t});if(n.conflict)throw new y("workspace_mismatch",n.conflict);if(!n.workspaceId||!n.credential)throw new y("workspace_required","No workspace selected. Run `hlix auth login --workspace <id>` first.");let r=le(t);if(r?.projectId)throw new y("already_imported","This folder is already bound to an Hlix project. Use `hlix push`.");let o=De(e.flags,"history");if(o&&o!=="preserve"&&o!=="abort-on-findings")throw Error("--history must be `abort-on-findings` or `preserve`.");if(!r&&e.flags["dry-run"]!==!0)Ce(t,{schemaVersion:1,workspaceId:n.workspaceId,apiUrl:n.baseUrl});let s=await Q(t,{...De(e.flags,"env-file")?{envFile:De(e.flags,"env-file")}:{},environment:e.env,historyMode:o==="preserve"?"preserve":"abort_on_findings"});if(e.flags["dry-run"]!==!0&&s.blocking.length===0){let c=Ss(s);if(c&&e.flags.yes!==!0){if(e.json||!e.confirm)throw new y("approval_required","Import needs approval for protected files or cloud setup. Review with `hlix import --dry-run`, then repeat with `--yes`.");if(!await e.confirm(c))throw new y("cancelled","Import cancelled.")}}let i={root:t,name:De(e.flags,"name")??vs(t),stack:De(e.flags,"stack")??s.manifest.stack,files:s.manifest.totals.files,bytes:s.manifest.totals.bytes,activeEnvFiles:s.manifest.activeEnvFiles,secretKeys:s.manifest.secretKeys,protectedFiles:s.manifest.secretFiles.length+s.manifest.quarantinedResources.length,environment:s.manifest.environment,historicalSecretFindings:s.manifest.historicalSecretFindings,quarantinedResources:s.manifest.quarantinedResources,mcpServers:s.manifest.mcpServers,skipped:s.manifest.skipped,blocking:s.blocking,manifestSha256:s.manifestSha256};if(e.flags["dry-run"]===!0){if(e.json)e.stdout(v(j(ct.name,i)));else{let c=[...s.manifest.secretFiles.map((l)=>`${l.kind}: ${l.path}`),...s.manifest.quarantinedResources.map((l)=>`${l.kind}: ${l.path}`)];e.stdout([`Project: ${i.name}`,`Stack: ${i.stack}`,`Files: ${i.files}`,`Bytes: ${i.bytes}`,`Environment confidence: ${i.environment.confidence}`,`History findings: ${i.historicalSecretFindings.length}`,"","Environment evidence:",...i.environment.sources.length?i.environment.sources.map((l)=>`- ${l.kind}: ${l.path}`):["- none detected"],"","Cloud setup commands:",...i.environment.install.length?i.environment.install.map((l)=>`- ${l}`):["- none detected"],"","Required secret keys:",...i.environment.requiredSecretKeys.length?i.environment.requiredSecretKeys.map((l)=>`- ${l}`):["- none detected"],"","Collected secret keys:",...i.secretKeys.length?i.secretKeys.map((l)=>`- ${l}`):["- none detected"],"","Protected and quarantined paths:",...c.length?c.map((l)=>`- ${l}`):["- none"],"","Environment warnings:",...i.environment.warnings.length?i.environment.warnings.map((l)=>`- ${l}`):["- none"],...i.blocking.length?["","Blocking findings:",...i.blocking.map((l)=>`- ${l}`)]:[]].join(`
102
- `)+`
103
- `)}return s.blocking.length?1:0}if(s.blocking.length)throw new y("scan_blocked",`Project scan blocked import:
104
- - ${s.blocking.join(`
105
- - `)}`);let a=await at(s);try{let c=e.requireClient(t),l=await c.imports.create({idempotencyKey:bs(s.manifestSha256,a.bundleSha256),name:i.name,stack:i.stack,defaultBranch:"main",historyMode:s.manifest.git.historyMode,manifest:s.manifest,manifestSha256:s.manifestSha256,bundleSha256:a.bundleSha256,bundleSize:a.bundleSize,commitSha:a.commitSha});if(l.import.status==="pending_upload"){if(!l.upload)throw Error(`Import ${l.import.id} is ${l.import.status} but has no upload target.`);await c.imports.uploadBundle(l.upload,new Blob([Uint8Array.from(await ys(a.bundlePath))]),{onProgress:(h,k)=>{if(!e.json)e.stderr(`Uploading ${h}/${k} bytes\r`)}})}let d=(l.import.status==="ready"?{import:l.import}:await c.imports.finalize(l.import.id,{secrets:s.secretValues,protectedFiles:s.protectedFiles})).import,u=d.projectId??d.requestedProjectId;if(!u||!d.revisionId||!d.generation)throw Error("Import completed without project revision metadata.");Ce(t,{schemaVersion:1,projectId:u,workspaceId:n.workspaceId,apiUrl:n.baseUrl}),$e(t,{schemaVersion:1,revisionId:d.revisionId,generation:d.generation,commitSha:a.commitSha,manifestSha256:s.manifestSha256,historyMode:s.manifest.git.historyMode,rootName:s.manifest.rootName});let m={projectId:u,revisionId:d.revisionId,generation:d.generation,commitSha:a.commitSha,files:s.manifest.totals.files,bytes:s.manifest.totals.bytes};if(e.json)e.stdout(v(j(ct.name,m)));else e.stderr(`
106
- `),e.stdout(`Imported ${i.name}
107
- Project ID: ${u}
108
- Revision: ${d.generation}
109
- `);return 0}finally{await a.dispose()}}};var js=(e)=>e instanceof Error?e.message:String(e);async function Es(e,t,n,r,o){try{let s=await Q(t,{historyMode:n,environment:e.env,rootName:r});return{files:s.manifest.totals.files,manifestSha256:s.manifestSha256,changed:o?s.manifestSha256!==o:null,blocking:s.blocking,error:null}}catch(s){return{files:null,manifestSha256:null,changed:null,blocking:[],error:js(s)}}}var nn={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(`
110
- `),supportsJson:!0,async run(e){let t=B({env:e.env,flags:e.flags,cwd:e.cwd}),n=t.binding,r=n?tt(n.root):null,o=n?await Es(e,n.root,r?.historyMode??"preserve",r?.rootName,r?.manifestSha256):null,s=null;if(n?.config.projectId&&t.credential&&!t.conflict)try{let c=(await e.requireClient().revisions.head(n.config.projectId)).revision;s={revisionId:c.id,generation:c.generation,changed:r?c.id!==r.revisionId||c.generation!==r.generation:null,error:null}}catch(c){s={revisionId:"",generation:0,changed:null,error:Tt(c).code}}let i={cwd:e.cwd,workspace:{id:t.workspaceId,source:t.workspaceSource},api:{baseUrl:t.baseUrl,source:t.baseUrlSource},credential:{present:t.credential!==null,source:t.credentialSource,path:t.credentialPath},conflict:t.conflict,project:n?{root:n.root,projectId:n.config.projectId??null,workspaceId:n.config.workspaceId,apiUrl:n.config.apiUrl}:null,revision:r?{id:r.revisionId,generation:r.generation,commitSha:r.commitSha}:null,local:o,cloud:s};if(e.json)return e.stdout(v(j(nn.name,i))),0;let a=[["folder",e.cwd],["workspace",t.workspaceId?`${t.workspaceId} (from ${t.workspaceSource})`:"none — run `hlix auth login --workspace <id>`"],["api",`${t.baseUrl} (from ${t.baseUrlSource})`],["credential",t.credential?t.credentialSource==="env"?`environment (${t.credential?.sessionToken?"HLIX_SESSION_TOKEN":"HLIX_API_KEY"})`:`file (${t.credentialPath})`:"none — run `hlix auth login`"],["project",n?n.config.projectId??`initialized at ${n.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(s)a.push(["cloud",s.error?`not checked: ${s.error}`:s.changed?`generation ${s.generation} available — run \`hlix pull\``:`generation ${s.generation}, up to date`]);if(t.conflict)a.push(["conflict",t.conflict]);return e.stdout(`${R(a)}
111
- `),0}};import{createHash as Us}from"node:crypto";import{readFile as Ms,realpath as Bs}from"node:fs/promises";import{createHash as Ps}from"node:crypto";import{constants as lt}from"node:fs";import{chmod as jr,copyFile as Cs,lstat as rn,mkdir as $s,mkdtemp as xs,open as Is,realpath as _s,rename as Os,rm as Je,writeFile as Rs}from"node:fs/promises";import{tmpdir as Ts}from"node:os";import{dirname as $r,join as W,relative as As,resolve as Hs,sep as Er}from"node:path";import{spawnSync as Fs}from"node:child_process";function xr(e){let t=e;if(typeof t==="string")try{t=JSON.parse(t)}catch{return{}}if(!t||typeof t!=="object")return{};let n=t,r=n.git&&typeof n.git==="object"?n.git:{},o=r.historyMode==="preserve"||r.historyMode==="abort_on_findings"?r.historyMode:void 0,s=typeof n.rootName==="string"&&n.rootName.trim()?n.rootName:void 0;return{historyMode:o,rootName:s}}function Ir(e){let t=e;if(typeof t==="string")try{t=JSON.parse(t)}catch{return[]}if(!t||typeof t!=="object")return[];let n=t.files;if(!Array.isArray(n))return[];return n.flatMap((r)=>{if(!r||typeof r!=="object")return[];let o=r;return typeof o.path==="string"&&typeof o.sha256==="string"?[{path:o.path,sha256:o.sha256}]:[]})}function qe(e,t){let n=Fs("git",["-C",e,...t],{encoding:"utf8",maxBuffer:52428800,stdio:["ignore","pipe","pipe"]});if(n.status!==0)throw Error(n.stderr.trim().split(`
112
- `).at(-1)??"Git command failed");return n.stdout.trim()}function Pr(e){return Ps("sha256").update(e).digest("hex")}async function on(e,t){let n=await _s(e),r=Hs(n,...t.split("/"));if(r!==n&&!r.startsWith(n+Er))throw Error(`Protected path escapes the project: ${t}`);let o=As(n,$r(r)),s=n;for(let i of o.split(Er).filter(Boolean)){s=W(s,i);try{let a=await rn(s);if(!a.isDirectory()||a.isSymbolicLink())throw Error(`Protected path crosses a non-directory: ${t}`)}catch(a){if(a.code!=="ENOENT")throw a;await $s(s,{mode:448})}}return r}async function Cr(e,t,n){let r=await on(e,t);try{let i=await rn(r);if(!i.isFile()||i.isSymbolicLink())throw Error(`Refusing to replace non-regular protected file: ${t}`)}catch(i){if(i.code!=="ENOENT")throw i}let o=W($r(r),`.hlix-pull-${crypto.randomUUID()}.tmp`),s=await Is(o,lt.O_WRONLY|lt.O_CREAT|lt.O_EXCL|lt.O_NOFOLLOW,384);try{await s.writeFile(n),await s.sync()}finally{await s.close()}try{await Os(o,r)}catch(i){throw await Je(o,{force:!0}),i}}async function Ns(e,t){let n=await on(e,t);try{let r=await rn(n);if(!r.isFile()||r.isSymbolicLink())throw Error(`Refusing to replace non-regular project file: ${t}`)}catch(r){if(r.code!=="ENOENT")throw r}}async function _r(e,t,n,r,o){let s=await xs(W(Ts(),"hlix-pull-"));await jr(s,448);let i=W(s,"project.bundle"),a=W(s,"checkout");try{let c=Buffer.from(await r.arrayBuffer());if(c.byteLength!==n.bundleSize||Pr(c)!==n.bundleSha256)throw Error("Downloaded revision bundle failed integrity verification.");if(await Rs(i,c,{mode:384}),qe(s,["clone","--no-hardlinks","--branch","main",i,a]),qe(a,["bundle","verify",i]),qe(a,["rev-parse","HEAD"])!==n.commitSha)throw Error("Downloaded revision bundle does not match the cloud commit.");let l=n.manifest,p=new Map;for(let m of[...l.secretFiles,...l.quarantinedResources])p.set(m.path,m);if(o.files.length!==p.size)throw Error("Cloud protected files do not match the revision manifest.");let d=new Map;for(let m of o.files){let h=p.get(m.path),k=Buffer.from(m.contentBase64,"base64");if(k.toString("base64").replace(/=+$/,"")!==m.contentBase64.replace(/=+$/,"")||!h||h.kind!==m.kind||k.byteLength!==h.size||Pr(k)!==h.sha256)throw Error(`Cloud protected file failed integrity verification: ${m.path}`);d.set(m.path,k)}let u=new Set([...l.files.map((m)=>m.path),...t.manifest.secretFiles.map((m)=>m.path),...t.manifest.quarantinedResources.map((m)=>m.path),...d.keys()]);for(let m of[...u].sort())await Ns(e,m);for(let[m,h]of d)await Cr(a,m,h);if(t.manifest.git.detected){qe(e,["fetch",i,"refs/heads/main"]),qe(e,["reset","--hard","FETCH_HEAD"]);let m=new Set(l.files.map((h)=>h.path));for(let h of t.manifest.files)if(!m.has(h.path))await Je(W(e,...h.path.split("/")),{force:!0})}else{for(let m of t.manifest.files)await Je(W(e,...m.path.split("/")),{force:!0});for(let m of l.files){let h=await on(e,m.path);await Cs(W(a,...m.path.split("/")),h),await jr(h,m.executable?493:420)}}for(let m of[...t.manifest.secretFiles,...t.manifest.quarantinedResources])if(!d.has(m.path))await Je(W(e,...m.path.split("/")),{force:!0});for(let[m,h]of d)await Cr(e,m,h)}finally{await Je(s,{recursive:!0,force:!0})}}function ge(e,t,n){let r=new Map(Ir(n.manifest).map((c)=>[c.path,c.sha256])),o=new Map(e.manifest.files.map((c)=>[c.path,c.sha256])),s=0,i=0;for(let[c,l]of o){let p=r.get(c);if(p===void 0)s+=1;else if(p!==l)i+=1}let a=0;for(let c of r.keys())if(!o.has(c))a+=1;return{localChanged:!t.manifestSha256||e.manifestSha256!==t.manifestSha256,cloudChanged:n.id!==t.revisionId||n.generation!==t.generation,local:{revisionId:t.revisionId,generation:t.generation},cloud:{revisionId:n.id,generation:n.generation,commitSha:n.commitSha},files:{local:o.size,cloud:r.size,localOnly:s,cloudOnly:a,differing:i}}}function sn(e,t,n){let{localChanged:r,cloudChanged:o}=t;if(e==="push")return o?"conflict":r?"push":"none";if(e==="pull"){if(!o)return"none";return r&&!n?"conflict":"pull"}if(r&&o)return"conflict";return r?"push":o?"pull":"none"}function an(e,t,n){return e==="pull"&&t.localChanged&&!n}var Ls={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 Or(e,t,n,r){let o=n.files;return[`${e} --dry-run: ${Ls[e][t]}`,...r?["Requires --yes (or interactive approval) to execute."]:[],"",R([["local",`generation ${n.local.generation} (${n.local.revisionId})${n.localChanged?" — modified":""}`],["cloud",`generation ${n.cloud.generation} (${n.cloud.revisionId})${n.cloudChanged?" — ahead":""}`],["files",`${o.local} local, ${o.cloud} cloud — ${o.localOnly} local-only, ${o.cloudOnly} cloud-only, ${o.differing} differing`]])].join(`
113
- `)}function Ks(e,t,n){return Us("sha256").update(`project-push-v1\x00${e}\x00${t}\x00${n}`).digest("hex")}var zs={schemaVersion:1,revisionId:"",generation:0,commitSha:""};async function he(e,{allowUnsynced:t=!1}={}){let n=N(e);if(!n?.config.projectId)throw new y("not_initialized","This folder is not bound to an imported Hlix project. Run `hlix import .` first.");let r=tt(n.root)??(t?zs:null);if(!r)throw new y("not_initialized","This folder is bound to a project but has never been pulled. Run `hlix pull` first.");return{root:await Bs(n.root),config:n.config,state:r}}async function Ge(e,t,n,r){let o=await Q(e,{historyMode:n,environment:t,rootName:r});if(o.blocking.length>0)throw new y("scan_blocked",`Project scan blocked sync:
114
- - ${o.blocking.join(`
115
- - `)}`);return o}async function cn(e,t,n,r){let{state:o,config:s}=await he(r,{allowUnsynced:n==="pull"}),i=e.requireClient(),[a,c]=await Promise.all([Ge(r,e.env,o.historyMode??"preserve",o.rootName),i.revisions.head(s.projectId)]),l=ge(a,o,c.revision),p=sn(n,l,e.flags.force===!0),d=an(p,l,e.flags.yes===!0);if(e.json)e.stdout(v(j(t,{dryRun:!0,action:p,approvalRequired:d,...l})));else e.stdout(`${Or(n,p,l,d)}
116
- `);return p==="conflict"?1:0}async function Ds(e,t){if(e.flags.yes===!0)return;if(e.json||!e.confirm)throw new y("approval_required","`pull --force` replaces local files. Review with `hlix pull --dry-run`, then repeat with `--yes`.");let n=[`hlix pull --force will replace this folder with cloud revision ${t.cloud.generation}.`,`Local-only files to delete: ${t.files.localOnly}`,`Files to replace with the cloud copy: ${t.files.differing}`,"Local changes that were never pushed cannot be recovered by Hlix."].join(`
117
- `);if(!await e.confirm(n))throw new y("cancelled","Pull cancelled.")}async function Rr(e,t,n,r){let{state:o,config:s}=await he(e),i=t.requireClient(),a=o.historyMode??"preserve",c=n??await Ge(e,t.env,a,o.rootName),l=r??(await i.revisions.head(s.projectId)).revision;if(l.id!==o.revisionId||l.generation!==o.generation)throw new y("conflict","Cloud changed since the local base. Run `hlix pull` or resolve with `hlix sync`.");if(o.manifestSha256&&c.manifestSha256===o.manifestSha256)return{action:"none",revisionId:o.revisionId,generation:o.generation};let p=await at(c);try{let d=await i.revisions.createUpload(s.projectId,{idempotencyKey:Ks(o.revisionId,c.manifestSha256,p.bundleSha256),expectedRevisionId:o.revisionId,expectedGeneration:o.generation,manifest:c.manifest,manifestSha256:c.manifestSha256,bundleSha256:p.bundleSha256,bundleSize:p.bundleSize,commitSha:p.commitSha});if(d.revisionUpload.status==="pending_upload"){if(!d.upload)throw Error("Revision upload has no bundle target.");await i.revisions.uploadBundle(d.upload,new Blob([Uint8Array.from(await Ms(p.bundlePath))]),{onProgress:(m,h)=>{if(!t.json)t.stderr(`Uploading ${m}/${h} bytes\r`)}})}let u=await i.revisions.finalize(s.projectId,d.revisionUpload.id,{secrets:c.secretValues,protectedFiles:c.protectedFiles});if(!u.revision)throw Error("Revision finalized without head metadata.");return $e(e,{schemaVersion:1,revisionId:u.revision.id,generation:u.revision.generation,commitSha:u.revision.commitSha,manifestSha256:u.revision.manifestSha256,historyMode:a,rootName:o.rootName??c.manifest.rootName}),{action:"push",...u.revision}}finally{await p.dispose()}}async function Tr(e,t,n,r,o){let{state:s,config:i}=await he(e,{allowUnsynced:!0}),a=t.requireClient(),c=s.historyMode??"preserve",l=r??await Ge(e,t.env,c,s.rootName),p=o??(await a.revisions.head(i.projectId)).revision;if(p.id===s.revisionId&&p.generation===s.generation)return{action:"none",revisionId:s.revisionId,generation:s.generation};let d=s.manifestSha256?l.manifestSha256!==s.manifestSha256:(()=>{let{files:E}=ge(l,s,p);return E.localOnly+E.differing>0})();if(d&&!n)throw new y("conflict","Local files changed since the last sync. Push them, or use `hlix pull --force` to replace them.");if(d)await Ds(t,ge(l,s,p));let[u,m]=await Promise.all([a.revisions.downloadBundle(i.projectId,p.id),a.revisions.protectedFiles(i.projectId)]);await _r(e,l,p,u,m);let h=xr(p.manifest),k=h.historyMode??c,_=h.rootName??s.rootName??l.manifest.rootName,D=await Ge(e,t.env,k,_);return $e(e,{schemaVersion:1,revisionId:p.id,generation:p.generation,commitSha:p.commitSha,manifestSha256:D.manifestSha256,historyMode:k,rootName:_}),{action:"pull",revisionId:p.id,generation:p.generation,commitSha:p.commitSha}}function ln(e,t,n){if(e.json)e.stdout(v(j(t,n)));else if("action"in n&&n.action==="none")e.stdout(`Already in sync.
118
- `);else e.stdout(`${String("action"in n?n.action:"sync")} complete.
119
- `)}var dt={name:"push",summary:"Push local changes as an immutable cloud revision",usage:"Usage: hlix push [--dry-run] [--json]",supportsJson:!0,options:["dry-run"],async run(e){if(e.args.length)throw Error("push accepts no positional arguments.");let{root:t}=await he(e.cwd);if(e.flags["dry-run"]===!0)return cn(e,dt.name,"push",t);return ln(e,dt.name,await Rr(t,e)),0}},pt={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(`
120
- `),supportsJson:!0,options:["force","yes","dry-run"],async run(e){if(e.args.length)throw Error("pull accepts no positional arguments.");let{root:t}=await he(e.cwd,{allowUnsynced:!0});if(e.flags["dry-run"]===!0)return cn(e,pt.name,"pull",t);return ln(e,pt.name,await Tr(t,e,e.flags.force===!0)),0}},ut={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(e){if(e.args.length)throw Error("sync accepts no positional arguments.");let{root:t,state:n,config:r}=await he(e.cwd);if(e.flags["dry-run"]===!0)return cn(e,ut.name,"sync",t);let o=e.requireClient(),[s,i]=await Promise.all([Ge(t,e.env,n.historyMode??"preserve",n.rootName),o.revisions.head(r.projectId)]),a=i.revision,c=ge(s,n,a);if(c.localChanged&&c.cloudChanged)throw new y("conflict","Both local and cloud changed since the last sync. Pull or push explicitly after reviewing the conflict.");let l=c.localChanged?await Rr(t,e,s,a):c.cloudChanged?await Tr(t,e,!1,s,a):{action:"none",revisionId:n.revisionId,generation:n.generation};return ln(e,ut.name,l),0}};import{lstat as Ar,readFile as qs,realpath as Js}from"node:fs/promises";import{basename as dn,dirname as Gs,extname as Ws,join as Vs,parse as Hr,resolve as pn}from"node:path";function We(e,t){let n=e.flags[t];return typeof n==="string"&&n.trim()?n.trim():void 0}function un(e){let t=N(e);if(!t?.config.projectId)throw new y("not_initialized","This folder is not bound to an Hlix project. Run `hlix import .` first.");return{root:t.root,projectId:t.config.projectId}}async function mn(e,t){let n=await Ar(e);if(n.isSymbolicLink()||!n.isFile())throw Error(`Refusing to import a non-regular file: ${e}`);if(n.size>t)throw Error(`Import file exceeds ${t} bytes: ${e}`);return{path:await Js(e),content:await qs(e,"utf8")}}function fn(e,t,n,r){if(e.json)e.stdout(v(j(t,n)));else e.stdout(`${r}
121
- `)}var gn={name:"skill import",summary:"Activate a local skill for the bound cloud project",usage:"Usage: hlix skill import <SKILL.md|folder> [--name <slug>] [--json]",supportsJson:!0,options:["name"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("skill import requires one file or folder.");let t=un(e.cwd),n=pn(e.cwd,e.args[0]),r=await Ar(n);if(r.isSymbolicLink())throw Error(`Refusing to import a symlink: ${n}`);let o=r.isDirectory()?Vs(n,"SKILL.md"):n,s=await mn(o,200000),i=r.isDirectory()?dn(n):dn(o)==="SKILL.md"?dn(Gs(o)):Hr(o).name,a=We(e,"name")??i;if(!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(a))throw Error("Skill name must be a lowercase kebab-case slug.");let c=await e.requireClient().resources.importSkill(t.projectId,{slug:a,content:s.content});return fn(e,gn.name,c.skill,`Imported skill ${a}`),0}},hn={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>] [--json]",supportsJson:!0,options:["name","runtime","duty","profile"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("agent import requires one Markdown file.");let t=un(e.cwd),n=pn(e.cwd,e.args[0]);if(![".md",".mdx"].includes(Ws(n).toLowerCase()))throw Error("Agent imports must be Markdown files.");let r=await mn(n,20000),o=We(e,"runtime")??"hlix";if(!["claude-code","codex","cursor-agent","hlix"].includes(o))throw Error("--runtime must be claude-code, codex, cursor-agent, or hlix.");let s=We(e,"duty")??"executor";if(s!=="executor"&&s!=="intake")throw Error("--duty must be executor or intake.");let i=We(e,"name")??Hr(n).name.replace(/[-_]+/g," "),a=await e.requireClient().resources.importAgent(t.projectId,{name:i,instructions:r.content,runtimeKind:o,duty:s});return fn(e,hn.name,a.agent,a.agent.duty==="intake"?`Imported agent ${a.agent.name} as this project's intake agent`:`Imported agent ${a.agent.name}`),0}},yn={name:"mcp import",summary:"Explicitly activate one validated local MCP server",usage:"Usage: hlix mcp import <.mcp.json> [--server <name>] [--allow-stdio] [--json]",supportsJson:!0,options:["server","allow-stdio"],args:{min:1,max:1},async run(e){if(e.args.length!==1)throw Error("mcp import requires one MCP JSON file.");let t=un(e.cwd),n=await mn(pn(e.cwd,e.args[0]),200000),r;try{r=JSON.parse(n.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 s=We(e,"server");if(!s&&o.length>1)throw Error("MCP config contains multiple servers; select one with --server <name>.");let i=s?o.find(([k])=>k===s):o[0];if(!i)throw Error(`MCP server not found: ${s}`);let[a,c]=i,l=c.type==="http"||c.type==="sse"?c.type:typeof c.command==="string"?"stdio":typeof c.url==="string"?"http":null;if(!l)throw Error(`MCP server ${a} has no supported transport.`);if(l==="stdio"&&e.flags["allow-stdio"]!==!0)throw Error("Stdio MCP servers execute a local command in the cloud; repeat with --allow-stdio.");let p=c.env&&typeof c.env==="object"&&!Array.isArray(c.env)?c.env:{},d=c.headers&&typeof c.headers==="object"&&!Array.isArray(c.headers)?c.headers:{};if(Object.values(d).some((k)=>typeof k!=="string"))throw Error(`MCP server ${a} headers must be strings.`);let u=Object.values(d).flatMap((k)=>[...k.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)].map((_)=>_[1]));if(Object.keys(d).length>0&&u.length===0)throw Error("MCP remote headers must use ${KEY} placeholders; literal credentials are refused.");let m=/^(?:(?:Bearer|Basic|Token) )?\$\{[A-Za-z_][A-Za-z0-9_]*\}$/i;if(Object.values(d).some((k)=>!m.test(k)))throw Error("MCP remote headers must be ${KEY} or an approved auth scheme followed by ${KEY}.");let h=await e.requireClient().resources.importMcp(t.projectId,{name:a,transport:l,...typeof c.command==="string"?{command:c.command}:{},...Array.isArray(c.args)&&c.args.every((k)=>typeof k==="string")?{args:c.args}:{},...typeof c.url==="string"?{url:c.url}:{},...Object.keys(d).length>0?{headers:d}:{},envKeys:[...new Set([...Object.keys(p),...u])].sort()});return fn(e,yn.name,h.mcpServer,`Imported MCP server ${a}`),0}};function wn(e,t){let n=e[t];if(typeof n!=="string"||n.trim()==="")throw new y("missing_argument",`--${t} is required.`);return n}var vn={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(`
122
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(e){let t=e.args[0],n=wn(e.flags,"title"),r=wn(e.flags,"description"),o=await e.requireClient().cycles.propose({projectId:t,title:n,description:r});if(e.json)return e.stdout(v(j(vn.name,o))),0;return e.stdout(`${R([["project",t],["title",n],["status",o.adopted?"adopted — the project is planning it now":"recorded — it will be planned on the next pass"]])}
123
- `),0}},kn={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(`
124
- `),supportsJson:!0,options:["title","description"],args:{min:1,max:1},async run(e){let t=e.args[0],n=wn(e.flags,"description"),r=typeof e.flags.title==="string"?e.flags.title:void 0,o=await e.requireClient().tasks.create({projectId:t,description:n,...r?{title:r}:{}});if(e.json)return e.stdout(v(j(kn.name,o))),0;return e.stdout(`${R([["task",o.id],["project",t],["status",o.status??"queued"],["note","not started — dispatch with `hlix cycles create`"]])}
125
- `),0}},bn={name:"harness get",summary:"Show which coder runs, and which setting chose it",usage:["Usage: hlix harness get [project-id] [--json]","","With a project id, what that project would run. Without one, the","workspace-wide answer. `source` names the setting that decided: a project","preference, the workspace preference, or the system default."].join(`
126
- `),supportsJson:!0,args:{min:0,max:1},async run(e){let t=e.args[0],n=e.requireClient(),r=t?await n.modelConfig.resolvedProjectHarness(t):await n.modelConfig.resolvedHarness();if(e.json)return e.stdout(v(j(bn.name,r))),0;return e.stdout(`${R([["scope",t?`project ${t}`:"workspace"],["harness",r.harness],["source",r.source]])}
127
- `),0}},Sn={name:"harness set",summary:"Choose the coder a project or the workspace runs",usage:[`Usage: hlix harness set <${pe.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(`
128
- `),supportsJson:!0,options:["org"],args:{min:1,max:2},async run(e){let t=e.args[0];if(!pe.includes(t))throw new y("invalid_usage",`harness must be one of ${pe.join(", ")}; got "${t}".`);let n=e.args[1],r=e.flags.org===!0;if(n&&r)throw new y("invalid_usage","Name a project or pass --org, not both: they are different scopes.");if(!n&&!r)throw new y("invalid_usage","Name the project to set, or pass --org for the whole workspace.");let o=e.requireClient(),s=n?await o.modelConfig.setProjectHarness(n,t):await o.modelConfig.setHarness(t);if(e.json)return e.stdout(v(j(Sn.name,s))),0;return e.stdout(`${R([["scope",n?`project ${n}`:"workspace"],["harness",t]])}
129
- `),0}};var Qc=[Lt,Ut,me,nn,Mt,Bt,Kt,Qt,ct,ut,pt,dt,gn,hn,yn,zt,Dt,Jt,Gt,Wt,Vt,kn,vn,bn,Sn];
130
- export{y as a,Ys as b,N as c,B as d,bo as e,Di as f,Yn as g,pe as h,ea as i,Ft as j,Qc as k};
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a as w,d as B,e as x,f as _,g as H,h as g,i as S,j as ae,k as y}from"./index-619ayaee.js";import{l as Ze}from"./index-vfqh17y6.js";import{resolve as es}from"node:path";import{parseArgs as ss}from"node:util";import{createMastraCode as ts}from"mastracode";import{hasHeadlessFlag as rs,parseHeadlessArgs as os,runMC as ns}from"mastracode/headless";import{MastraTUI as as}from"mastracode/tui";import{mkdirSync as ge,writeFileSync as fe}from"node:fs";import{join as A}from"node:path";import{createTool as de}from"@mastra/core/tools";import{z as d}from"zod";var k=(e)=>`hlix_${e.split(" ").join("_")}`,ue=d.object({args:d.array(d.string()).optional().describe("Positional arguments that follow the command name."),flags:d.record(d.string(),d.union([d.string(),d.boolean()])).optional().describe('Options without the leading dashes, e.g. { "yes": true, "name": "api" }.')}),me=d.object({exitCode:d.number(),stdout:d.string(),stderr:d.string()});function he(e,s,t){let r=e.name.split(" ").concat(s.args??[]);for(let[o,a]of Object.entries(s.flags??{})){if(a===!1)continue;if(r.push(`--${o}`),typeof a==="string")r.push(a)}if(!s.flags?.cwd)r.push("--cwd",t);if(e.supportsJson&&!s.flags?.json)r.push("--json");return r}async function pe(e,s,t,r=process.env){let o="",a="";return{exitCode:await _([e],he(e,s,t),{stdout:(i)=>{o+=i},stderr:(i)=>{a+=i},env:r}),stdout:o,stderr:a}}function R(e){let s={};for(let t of e.commands??y){let r=k(t.name);s[r]=de({id:r,description:`${t.summary}
3
-
4
- ${t.usage}`,inputSchema:ue,outputSchema:me,execute:async(o)=>pe(t,o,e.cwd,e.env)})}return s}var xe=(e)=>`${e.split(" ").join("-")}.md`;function we(e){return["---",`description: ${e.summary}`,"---","",`Call the tool \`${k(e.name)}\` with the user's arguments: $ARGUMENTS.`,"Show the result.",""].join(`
5
- `)}var be={"follow.md":["---","description: Watch a cloud task being coded, live","---","","Call the tool `hlix_tasks_follow` with `taskId` set to $ARGUMENTS. It streams the","coder's text and tool calls into this session. Summarise what it did.",""].join(`
6
- `),"harness.md":["---","description: Show or change the harness — which coder does the work","---","","Call the tool `hlix_harness` with `harness` set to $ARGUMENTS when the user","named one, and with no argument when they did not. Show `message` verbatim.",""].join(`
7
- `)};function O(e,s=y){let t=A(e,".hlix","commands");ge(t,{recursive:!0});let r=[],o=[...s.map((a)=>[xe(a.name),we(a)]),...Object.entries(be)];for(let[a,n]of o){let i=A(t,a);try{fe(i,n,{flag:"wx"}),r.push(i)}catch(u){if(u.code!=="EEXIST")throw u}}return r}import{execFileSync as ye}from"node:child_process";import{createACPTool as ke}from"@mastra/acp";import{createTool as ve}from"@mastra/core/tools";import{z as h}from"zod";var f={"claude-code":{harness:"claude-code",label:"Claude Code",command:"claude-agent-acp",args:[],authEnvVars:["ANTHROPIC_API_KEY"],install:"npm i -g @agentclientprotocol/claude-agent-acp"},codex:{harness:"codex",label:"Codex",command:"codex-acp",args:[],authEnvVars:["OPENAI_API_KEY"],env:{NO_BROWSER:"1"},install:"npm i -g @agentclientprotocol/codex-acp"},"cursor-agent":{harness:"cursor-agent",label:"Cursor Agent",command:"cursor-agent",args:["acp"],authEnvVars:["CURSOR_API_KEY"],install:"curl https://cursor.com/install -fsS | bash"}};function N(e){if(e.flag)return{harness:Se(e.flag,"--harness"),source:"flag"};if(e.configured)return{harness:e.configured,source:e.configSource??"project"};return{harness:S,source:"default"}}function Se(e,s){if(g.includes(e))return e;throw Error(`${s} must be one of ${g.join(", ")}; got "${e}".`)}var v="hlix_tasks_follow",Ce=(e)=>`hlix_coder_${e.split("-").join("_")}`;function E(e,s){let t=s.source==="default"?"":` (${s.source==="flag"?"--harness":s.source})`;return`${e} · harness: ${s.harness}${t}`}function F(e,s=3000){try{return ye("which",[e],{timeout:s,stdio:"ignore"}),!0}catch{return!1}}var C=(e)=>`harness ${e.harness} needs \`${e.command}\` on PATH. Install it with: ${e.install}`;function He(e){let s=e.options??[],t=s.find((r)=>r.kind==="allow_once")??s.find((r)=>r.kind==="reject_once");if(!t)return{outcome:{outcome:"cancelled"}};return{outcome:{outcome:"selected",optionId:t.optionId}}}var T=["view","search_content","find_files","file_stat","lsp_inspect"],M=["ask_user","task_write","task_update","task_complete","task_check"],je=(e)=>[`harness ${e} runs in the project's Coding Workspace, not on this machine.`,"This session can follow and stream that work, but cannot start it:","which coder the platform uses comes from the project's harness preference,","and this CLI has no command that creates a task."].join(" "),W=(e)=>[e==="unknown"?"This project's harness could not be read from the server. Do NOT guess which coder it runs — say so, and offer to check with the `hlix_harness` tool.":`This project's harness is ${e}: the platform runs ${e} for the coding work it executes, in the project's Coding Workspace.`,"Change it with the `hlix_harness` tool, which writes the project's setting.","","To do coding work here, dispatch it and then watch it:","1. `hlix_cycles_create` with the project id, a title and a description. That"," is what STARTS work — it enters the project's loop, which plans the cycle,"," creates its tasks and starts the coder. It returns no cycle id.","2. `hlix_tasks_list` with that project to find the tasks planning produced.",`3. \`${v}\` with a task id, which streams that coder's own text and`," tool calls into this session live. Report what it did.","","`hlix_tasks_create` only adds a board row; it does not start anything, and","there is no way to start a single task. Never claim otherwise."].join(`
8
- `),Ie=(e,s)=>[`The user chose the ${e.label} harness. Do not edit files or run commands`,`yourself. Hand the whole task to \`${s}\` as one natural-language brief,`,`then report what it did. ${e.label} reads and writes the same working`,"directory you are in.","",`It authenticates from ${e.authEnvVars.join(" or ")} in this shell's`,"environment. If it reports a credential problem, say so — do not retry."].join(`
9
- `);function L(e){if(e.sandbox==="cloud"||e.active==="hlix")return[];let s=new Set(e.unavailable??[]),t=e.model?{defaultModelId:e.model}:{},r=[{id:"hlix",name:"Hlix",description:"The hlix agent codes here, with the full toolset.",...t}];for(let o of Object.values(f)){let a=e.active===o.harness,n=Ce(o.harness);r.push({id:o.harness,name:o.label,description:`${o.label} runs on this machine over ACP and edits ${e.cwd}.`,instructions:Ie(o,n),availableTools:s.has(o.harness)?[...T,...M,v]:[n,...T,...M,v],...s.has(o.harness)?{}:{additionalTools:{[n]:ke({id:n,description:`Run a coding task with ${o.label}. Give it one natural-language brief; it reads and writes the working directory and returns its final output.`,command:o.command,args:o.args,cwd:e.cwd,...o.env?{env:o.env}:{},...e.workspace?{workspace:e.workspace}:{},onPermissionRequest:async(i)=>He(i)})}},...t,...a?{metadata:{default:!0}}:{}})}return r}function Pe(e){let s=[...e.available],t=(o,a="none")=>({harness:e.current,available:s,action:a,message:o});if(!e.requested)return t(`harness: ${e.current}. Available here: ${s.join(", ")}.`);if(!g.includes(e.requested))return t(`/harness must name one of ${g.join(", ")}; got "${e.requested}".`);let r=e.requested;if(e.sandbox==="cloud"){let o=`${e.sandboxLine} · harness: ${r} (project preference)`;return{harness:r,available:s,action:"preference",message:r==="hlix"?o:`${o}. ${je(r)}`}}if(!s.includes(r))return t(C(f[r]));if(!e.modesBuilt)return t(`This session runs the hlix coder, so there is no ${r} mode to switch to. Restart with \`hlix --harness ${r}\`, or make it the default with \`hlix config set harness ${r}\`.`,"restart");return{harness:r,available:s,action:"mode",message:`${e.sandboxLine} · harness: ${r}`}}function D(e){return ve({id:"hlix_harness",description:"Show or change the harness — which coder does the work. In a local or docker sandbox it switches this session's coder; in a cloud sandbox it writes the project's harness preference, which is what the platform runs. With no argument it reports the current harness.",inputSchema:h.object({harness:h.string().optional().describe(`One of ${g.join(", ")}. Omit to report the current one.`)}),outputSchema:h.object({harness:h.string(),available:h.array(h.string()),message:h.string()}),execute:async(s)=>{let t=e.session(),r=Pe({...s.harness?{requested:s.harness}:{},current:t?.mode.get()??S,available:e.available,sandbox:e.sandbox,sandboxLine:e.sandboxLine,modesBuilt:e.modesBuilt}),o={harness:r.harness,available:r.available,message:r.message};if(r.action==="mode"&&t)return await t.mode.switch({modeId:r.harness}),o;if(r.action==="preference"){if(!e.setProjectHarness)return{...o,message:"This folder is not bound to a hlix project, so there is no project preference to write. Run `hlix init` or pass --project <id>."};await e.setProjectHarness(r.harness)}return o}})}import{createTool as _e}from"@mastra/core/tools";import{writeToolProgress as Re}from"mastracode/plugin";import{z as m}from"zod";function Ae(e){switch(e.type){case"on_chat_model_stream":return e.delta?{event:"text",text:e.delta}:null;case"reasoning":return e.delta?{event:"text",text:e.delta}:null;case"on_tool_start":return{event:"tool_start",toolName:e.name,args:e.input};case"on_tool_end":return{event:"tool_end",toolName:e.name,result:e.output,isError:$e(e.output)};case"error":return{event:"finish",isError:!0,result:e.message};case"done":return{event:"finish",isError:!1};default:return null}}function $e(e){return typeof e==="object"&&e!==null&&e.status==="failed"}async function Oe(e,s){let t=[],r=[],o="streamed",a="The coder's turn ended.";for await(let n of e){if(n.type==="idle"){o="idle",a="Nothing is being coded right now. The task is not in build or test.";break}if(n.type==="error")o="error",a=n.message;if(n.type==="on_chat_model_stream")t.push(n.delta);if(n.type==="on_tool_start")r.push(n.name);let i=Ae(n);if(i)await s(i)}return{status:o,text:t.join(""),tools:r,message:a}}function U(e){return _e({id:"hlix_tasks_follow",description:"Watch a hlix task being coded in the cloud, live. Streams the coder's text and tool calls into this session as they happen, and returns what it did. Use it after a task starts building.",inputSchema:m.object({taskId:m.string().describe("The task to follow.")}),outputSchema:m.object({status:m.enum(["streamed","idle","error","unassigned"]),text:m.string(),tools:m.array(m.string()),message:m.string()}),execute:async(s,t)=>{let r=x(e.env??process.env,{cwd:e.cwd,flags:{}}),o=await r.tasks.get(s.taskId);if(!o.agentId)return{status:"unassigned",text:"",tools:[],message:"No agent has picked this task up yet, so there is no coder to watch. Check `hlix_tasks_get` again once it is building."};return Oe(r.projects.observeAgent(o.projectId,o.agentId),(a)=>Re(t,a))}})}import{buildMode as Te}from"@mastra/code-sdk/agents/modes/build";import{fastMode as Me}from"@mastra/code-sdk/agents/modes/explore";import{planMode as Ne}from"@mastra/code-sdk/agents/modes/plan";import{setCustomProvidersSource as Ee}from"@mastra/code-sdk/agents/model";import{getCustomProviderId as q,loadSettings as Fe}from"@mastra/code-sdk/onboarding/settings";var K="hlix",J="default",We=(e)=>`${K}/${e}`;function Le(e){return{name:K,url:`${e.baseUrl.replace(/\/+$/,"")}/v1/api/ai/w/${e.workspaceId}`,apiKey:e.apiKey,models:[...new Set([J,...e.models??[]])]}}function De(e){let s=[Te,Ne,Me];return e?s.map((t)=>({...t,defaultModelId:e})):s}function V(e){let s=B({env:e.env,flags:{},cwd:e.cwd});if(s.conflict||!s.credential||!s.workspaceId)return null;let t=Le({baseUrl:s.baseUrl,workspaceId:s.workspaceId,apiKey:s.credential.apiKey,...e.models?{models:e.models}:{}}),r=q(t.name);return Ee(()=>[...Fe().customProviders.filter((o)=>q(o.name)!==r),t]),{provider:t,modelId:We(J)}}var X=(e,s)=>e.length>0?[...e]:De(s);function Y(e){if(e.configured)return{id:e.configured,source:e.configuredSource??"config"};return e.wired?{id:e.wired.modelId,source:"workspace"}:null}var z=(e,s)=>s?`${e} · model: ${s.id} (${s.source})`:e;import{execFileSync as Xe}from"node:child_process";import{DockerSandbox as Ye}from"@mastra/docker";import{LocalFilesystem as ze,Workspace as Ge}from"@mastra/core/workspace";import{posix as G}from"node:path";import{MastraFilesystem as Ue,MastraSandbox as qe,Workspace as Be}from"@mastra/core/workspace";var Ke=600000,Je=["recursive","overwrite","force","maxDepth","extension"];function p(e){let s=e??{},t={};for(let r of Je)if(s[r]!==void 0)t[r]=s[r];return Object.keys(t).length>0?{options:t}:{}}var Q=(e)=>e instanceof Date?e:new Date(typeof e==="string"||typeof e==="number"?e:0);class Z extends Ue{id;name="RemoteFilesystem";provider="hlix-coding-workspace";basePath;status="ready";client;constructor(e,s){super({name:"RemoteFilesystem"});this.client=e,this.basePath=s.root,this.id=s.id??`hlix-remote-fs:${s.root}`}getInfo(){return{id:this.id,name:this.name,provider:this.provider,status:this.status,metadata:{root:this.basePath}}}resolveAbsolutePath(e){return G.isAbsolute(e)?e:G.join(this.basePath,e)}async call(e){let{result:s}=await this.client.fs({...e,encoding:e.encoding??"utf8",path:this.resolveAbsolutePath(e.path)});return s}async readFile(e,s){let r=await this.call({op:"read",path:e,encoding:"base64"}),o=Buffer.from(r.content,r.encoding);return s?.encoding?o.toString(s.encoding):o}async writeFile(e,s,t){await this.call({op:"write",path:e,content:Buffer.from(s).toString("base64"),encoding:"base64",...p(t)})}async appendFile(e,s){await this.call({op:"append",path:e,content:Buffer.from(s).toString("base64"),encoding:"base64"})}async deleteFile(e,s){await this.call({op:"delete",path:e,...p(s)})}async copyFile(e,s,t){await this.call({op:"copy",path:e,dest:this.resolveAbsolutePath(s),...p(t)})}async moveFile(e,s,t){await this.call({op:"move",path:e,dest:this.resolveAbsolutePath(s),...p(t)})}async mkdir(e,s){await this.call({op:"mkdir",path:e,...p(s)})}async rmdir(e,s){await this.call({op:"rmdir",path:e,...p(s)})}async readdir(e,s){return await this.call({op:"readdir",path:e,...p(s)})??[]}async exists(e){return await this.call({op:"exists",path:e})===!0}async stat(e){let s=await this.call({op:"stat",path:e});return{...s,createdAt:Q(s.createdAt),modifiedAt:Q(s.modifiedAt)}}}var Ve=(e)=>`'${e.split("'").join("'\\''")}'`;class ee extends qe{id;name="RemoteSandbox";provider="hlix-coding-workspace";status="ready";client;constructor(e,s){super({name:"RemoteSandbox"});if(this.client=e,this.id=`hlix-remote-sandbox:${s.projectId}`,s.root)this.setWorkingDirectory(s.root)}async start(){}getInfo(){return{id:this.id,name:this.name,provider:this.provider,status:this.status,createdAt:new Date(0)}}async executeCommand(e,s=[],t){let r=[e,...s.map(Ve)].join(" "),o=Date.now(),a=t?.cwd??this.workingDirectory,n=await this.client.exec({command:r,...a?{cwd:a}:{},timeoutMs:t?.timeout??Ke});return{success:n.exitCode===0,exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr,executionTimeMs:Date.now()-o,command:e,args:s}}}function se(e,s){let t=s.root??"/workspace";return new Be({id:`hlix-project:${s.projectId}`,name:"Hlix Coding Workspace",filesystem:new Z(e,{root:t}),sandbox:new ee(e,{projectId:s.projectId,root:t})})}function Qe(e,s){if(H.includes(e))return e;throw new w("invalid_usage",`${s==="flag"?"--sandbox":"sandbox in .hlix/config.json"} must be one of ${H.join(", ")}; got "${e}".`)}function te(e){if(e.flag){let s=e.flagSource??"flag";return{choice:Qe(e.flag,s),reason:s==="flag"?`--sandbox ${e.flag}`:"config"}}if(e.projectId)return{choice:"cloud",reason:`project ${e.projectId}`};if(e.dockerAvailable())return{choice:"docker",reason:"auto"};return{choice:"local",reason:"auto"}}var re=(e)=>`sandbox: ${e.choice} (${e.reason})`;function oe(e=3000){try{return Xe("docker",["info"],{timeout:e,stdio:"ignore"}),!0}catch{return!1}}function j(e,s){if(e.choice==="local")return;if(e.choice==="cloud"){if(!s.remote||!s.projectId)throw new w("invalid_usage","The cloud sandbox needs a hlix project. Run `hlix init`, pass --project <id>, or choose --sandbox docker|local.");return se(s.remote,{projectId:s.projectId})}let t="/workspace";return new Ge({id:"hlix-code-docker",name:"Hlix Code (Docker)",filesystem:new ze({basePath:s.cwd}),sandbox:new Ye({id:"hlix-code",volumes:{[s.cwd]:t},workingDirectory:t})})}var ne=["You are running inside Hlix Code, the terminal harness for the hlix control plane.","Every `hlix` CLI command is available to you as a tool named `hlix_<command>`,","with spaces replaced by underscores — `hlix_status`, `hlix_tasks_list`, `hlix_push`.","Use those tools instead of running `hlix` through the shell: they resolve the","folder's workspace binding and credential the same way the CLI does, and they","return the CLI's machine-readable output.","Report a non-zero exit code and its stderr to the user verbatim. Never invent a","project, task or workspace id — read one with a tool first."].join(`
10
- `);function is(e){let{values:s}=ss({args:e,allowPositionals:!0,strict:!1,options:{local:{type:"boolean"},sandbox:{type:"string"},harness:{type:"string"},project:{type:"string"},cwd:{type:"string"}}}),t=typeof s.sandbox==="string"?s.sandbox:s.local===!0?"local":void 0;return{...t?{sandbox:t,sandboxSource:"flag"}:{},...typeof s.harness==="string"?{harness:s.harness}:{},...typeof s.project==="string"?{project:s.project}:{},cwd:es(typeof s.cwd==="string"?s.cwd:".")}}function cs(e){let s=Object.keys(f),r=e.sandbox==="cloud"?s:s.filter((u)=>e.installed(u)),o=["hlix",...r],a=s.filter((u)=>!r.includes(u)),n=e.requested.harness;if(n==="hlix"||r.includes(n))return{harness:e.requested,available:o,unavailable:a,refusal:null,warning:null};let i=C(f[n]);if(e.requested.source==="flag")return{harness:e.requested,available:o,unavailable:a,refusal:i,warning:null};return{harness:{harness:"hlix",source:"default"},available:o,unavailable:a,refusal:null,warning:`${i} Falling back to harness hlix.`}}async function ls(e,s){try{let r=await x(process.env,{cwd:e,flags:{}}).modelConfig.resolvedProjectHarness(s);return{harness:r.harness,source:r.source}}catch{return null}}function ds(e,s){if(e.choice!=="cloud")return j(e,{cwd:s.cwd});if(!s.projectId)throw new w("invalid_usage","The cloud sandbox needs a hlix project. Run `hlix init`, pass --project <id>, or choose --sandbox docker|local.");let r=x(process.env,{cwd:s.cwd,flags:{}}).projects.workspace(s.projectId);return j(e,{cwd:s.cwd,projectId:s.projectId,remote:r})}async function lt(e){let s=is(e),t=ae(s.cwd,process.env),r=s.project??t.merged.projectId,o,a,n;try{if(a=te({flag:s.sandbox??t.merged.sandbox,flagSource:s.sandbox?"flag":"config",projectId:r,dockerAvailable:()=>oe()}),n=cs({requested:N({...s.harness?{flag:s.harness}:{},...t.merged.harness?{configured:t.merged.harness}:{},...t.sources.harness?{configSource:t.sources.harness}:{}}),sandbox:a.choice,installed:(c)=>F(f[c].command)}),n.refusal)throw new w("invalid_usage",n.refusal);o=ds(a,{cwd:s.cwd,projectId:r})}catch(c){return process.stderr.write(`error: ${c instanceof Error?c.message:String(c)}
11
- `),2}if(n.warning)process.stderr.write(`warning: ${n.warning}
12
- `);if(a.choice==="cloud"){let c=r?await ls(s.cwd,r):null;if(c&&s.harness&&s.harness!==c.harness)process.stderr.write(`warning: this project runs ${c.harness}. Run \`/harness ${s.harness}\` to make ${s.harness} the project's setting.
13
- `);n={...n,harness:c??{harness:"unknown",source:r?"the project's setting could not be read":"no project bound"}}}let i=Y({wired:V({cwd:s.cwd,env:process.env}),...t.merged.model?{configured:t.merged.model}:{},...t.sources.model?{configuredSource:t.sources.model}:{}}),u=re(a);process.stdout.write(`${z(E(u,n.harness),i)}
14
- `),O(s.cwd);let I=null,ie=n.harness.harness==="unknown"?"hlix":n.harness.harness,P=L({sandbox:a.choice,cwd:s.cwd,active:ie,unavailable:n.unavailable,...o?{workspace:o}:{},...i?{model:i.id}:{}}),{version:ce}=await import("./package-12m4e2y1.js"),l=await ts({configDir:".hlix",cwd:s.cwd,hostInstructions:a.choice==="cloud"?`${ne}
15
-
16
- ${W(n.harness.harness)}`:ne,extraTools:{...R({cwd:s.cwd}),hlix_tasks_follow:U({cwd:s.cwd}),hlix_harness:D({sandbox:a.choice,sandboxLine:u,available:n.available,modesBuilt:P.length>0,session:()=>I,...r?{setProjectHarness:async(c)=>{await x(process.env,{cwd:s.cwd,flags:{}}).modelConfig.setProjectHarness(r,c)}}:{}})},modes:X(P,i?.id),...o?{workspace:o}:{}});if(I=l.session,rs(e)){let c=os(e),b=await ns({controller:l.controller,session:l.session,prompt:c.prompt??"",...c.model?{model:c.model}:{},...c.maxTurns?{maxTurns:c.maxTurns}:{}}).result;if(process.stdout.write(`${b.text}
17
- `),b.error)process.stderr.write(`${b.error.message}
18
- `);return b.exitCode}return await new as({controller:l.controller,session:l.session,...l.hookManager?{hookManager:l.hookManager}:{},...l.mcpManager?{mcpManager:l.mcpManager}:{},...l.pluginManager?{pluginManager:l.pluginManager}:{},...l.knowledgeInspector?{knowledgeInspector:l.knowledgeInspector}:{},authStorage:l.authStorage,storageMaintenance:l.storageMaintenance,appName:"Hlix Code",version:ce}).run(),0}export{is as parseHlixCodeArgs,cs as planHarness,lt as runHlixCode};