@code-partner/codepipe 0.1.137-dev.57.g0540c70 → 0.1.137-dev.59.g4039549
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/dist/index.js +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var ce="0.1.137-dev.
|
|
2
|
+
var ce="0.1.137-dev.59.g4039549",ge="https://hub.dev.codepipe.dev";var he=4,kl=4;function vr(t){return typeof t!="number"||!Number.isFinite(t)?!1:t>=kl&&t<=he}var ye=".codepipe-context.yaml",Jt=".devpipe-context.yaml",Bo=[{version:1,summary:"ADR section: adr/ scaffold (README, template, derived INDEX) + the format-version stamp itself",addedPaths:["adr/README.md","adr/0000-template.md","adr/INDEX.md",ye]},{version:2,summary:"Rename the format-version stamp .devpipe-context.yaml \u2192 .codepipe-context.yaml (drop the devpipe-brand leftover)",addedPaths:[ye]}];function Sr(t=2){return`# CodePipe Context Repo format version.
|
|
3
3
|
# Bumped by the scaffold / the format-migration PR \u2014 do not edit by hand.
|
|
4
4
|
template_version: ${t}
|
|
5
5
|
`}function Mo(t){if(!t)return 0;let e=/^\s*template_version:\s*(\d+)\s*$/m.exec(t),r=e?parseInt(e[1]??"",10):NaN;return Number.isFinite(r)&&r>=0?r:0}function Go(t,e=Bo){let r=[];for(let n of e)if(!(n.version<=t))for(let o of n.addedPaths)r.includes(o)||r.push(o);return r}function Fo(t,e=Bo){return e.filter(r=>r.version>t)}function Ze(){return{inputTokens:0,outputTokens:0,cacheReadInputTokens:0,cacheCreationInputTokens:0,totalCostUsd:0,model:"",numTurns:0,durationMs:0}}var et=/^[a-z][a-z0-9-]{1,30}$/,bl="-codepipe-ctx";function Ce(t){return`${t}${bl}`}var $l=[{name:"rework",pattern:/^@(?:codepipe|devpipe)\s+rework:\s*(.+)$/im,description:"Send the task back to ANALYZING with a new instruction.",hasArg:!0},{name:"approve",pattern:/^@(?:codepipe|devpipe)\s+approve\s*$/im,description:"Merge every PR for this task (TRACKING only)."},{name:"reject",pattern:/^@(?:codepipe|devpipe)\s+reject(?::\s*(.+))?\s*$/im,description:"Abandon this task: close any open PR(s) and move it to DONE (reason rejected_and_closed). Valid from any non-terminal phase; from early phases it just skips the task.",hasArg:!0},{name:"merge",pattern:/^@(?:codepipe|devpipe)\s+merge\s*$/im,description:"Merge the task branch into the default branch without a PR (direct apply path, apply.pull_request=false; TRACKING only)."},{name:"rebase",pattern:/^@(?:codepipe|devpipe)\s+rebase\s*$/im,description:"Re-apply the patch on top of the latest base branch and force-push. Use after a PR merge conflict or APPLYING failure."},{name:"update",pattern:/^@(?:codepipe|devpipe)\s+update(?::\s*(.+))?\s*$/im,description:"Update a conflicting PR: resolve conflicts against the current base branch (TRACKING only). Optional `: <instruction>` is forwarded to the agent.",hasArg:!0},{name:"apply",pattern:/^@(?:codepipe|devpipe)\s+apply:\s*(local|auto)\s*$/im,description:"Override apply mode for this task: local (you apply by hand) or auto.",hasArg:!0}];function Cr(t){for(let e of $l){let r=t.match(e.pattern);if(r)return{name:e.name,args:(r[1]??"").trim()}}return null}var Xt={github:"github.com",gitlab:"gitlab.com",bitbucket:"bitbucket.org"};function gt(t){let e=t.match(/^git@([^:/]+):/);if(e)return e[1]??null;let r=t.match(/^ssh:\/\/(?:[^@/]+@)?([^/:]+)/);if(r)return r[1]??null;let n=t.match(/^https?:\/\/(?:[^@/]+@)?([^/:]+)/);return n?n[1]??null:null}var tt="x-bitbucket-api-token-auth";function Tr(t){switch(t){case Xt.gitlab:return"oauth2";case Xt.bitbucket:return"x-token-auth";default:return"x-access-token"}}var Ho=20;function L(t){return process.env[`CODEPIPE_${t}`]??process.env[`DEVPIPE_${t}`]}import{Command as Zm}from"commander";import{homedir as Vo}from"node:os";import{mkdirSync as jl,readFileSync as Al,writeFileSync as _l,existsSync as In}from"node:fs";import{dirname as Jo,join as Pr,resolve as Nl}from"node:path";import{fileURLToPath as Ol}from"node:url";import{existsSync as Rr,readFileSync as Wo,readdirSync as vl,writeFileSync as Sl}from"node:fs";import{dirname as Cl,join as Oe}from"node:path";import{parse as Tl}from"yaml";import{existsSync as Ko,renameSync as xl}from"node:fs";function rt(t,e,r=n=>console.error(n)){if(Ko(e)||!Ko(t))return!1;try{return xl(t,e),r(`migrated ${t} \u2192 ${e} (DevPipe \u2192 CodePipe)`),!0}catch(n){return r(`failed to migrate ${t} \u2192 ${e}: ${n instanceof Error?n.message:String(n)} \u2014 continuing with the legacy path untouched`),!1}}var we=".codepipe",Rn=".devpipe";function Rl(t=process.cwd()){let e=t;for(;;){if(Rr(Oe(e,we,"project.yaml")))return e;if(Rr(Oe(e,Rn,"project.yaml")))return rt(Oe(e,Rn),Oe(e,we))&&Pl(e),e;let r=Cl(e);if(r===e)return null;e=r}}function Il(t){let e=Oe(t,we);return Rr(e)?e:Oe(t,Rn)}function Pl(t){let e=Oe(t,".gitignore");if(!Rr(e))return;let r=Wo(e,"utf-8"),n=r.split(/\r?\n/).map(o=>{let i=o.trim();return i===".devpipe"||i===".devpipe/"||i==="/.devpipe"||i==="/.devpipe/"?o.replace(".devpipe",".codepipe"):o}).join(`
|
|
@@ -551,7 +551,7 @@ ${i}`}function pf(){let t=[],e=!1,r=null,n=i=>{if(r){let s=r;r=null,s({value:i,d
|
|
|
551
551
|
`).map(v=>f+v).join(`
|
|
552
552
|
`)}function k(b,f,v){let y=f[0]?.workspacePath??"";return b.replace(/\{\{codeDir\}\}/g,y).replace(/\{\{codeRoot\}\}/g,y?y.replace(/\/[^/]+$/,""):"").replace(/\{\{contextDir\}\}/g,v??"")}function w(b,f,v){let y=b,S=v.includes("::")?"":v.split(":",2)[1]??"",R=$=>{if(!f||!S)return"";try{return po(pr(f,"tasks",S,$),"utf-8").trim()}catch{return""}};if(y.includes("{{solutionMd}}")){let $=R("SOLUTION.md")||"(SOLUTION.md missing \u2014 proceed from the task description)";y=y.replace(/\{\{solutionMd\}\}/g,()=>$)}if(y.includes("{{taskDescription}}")){let $=R("task.md")||"(task description unavailable \u2014 see tasks/<KEY>/task.md in the context repo)";y=y.replace(/\{\{taskDescription\}\}/g,()=>$)}return y}let _=b=>{if(a)return;a=!0,console.log(`
|
|
553
553
|
[${b}] shutting down`),c.abort();let f=[...l.keys()];for(let S of l.values())S.abort.abort();let v=new AbortController,y=setTimeout(()=>v.abort(),3e3);(async()=>(await Promise.all(f.map(async S=>{try{await s.releaseJob(S,`sandbox ${b}`,v.signal),console.log(`[${b}] released job ${S}`)}catch(R){let $=R instanceof Error?R.message:String(R);console.warn(`[${b}] release failed: ${$} (sweeper will reclaim)`)}})),clearTimeout(y),p.close(),setTimeout(()=>process.exit(0),200)))()};process.on("SIGINT",()=>_("SIGINT")),process.on("SIGTERM",()=>_("SIGTERM"));let P=[h("implementation")];e.planningLane!==!1?P.push(h("planning")):console.log("[claim] planning lane disabled (SANDBOX_PLANNING_LANE=false)"),await Promise.all(P)}async function nc(t={profile:void 0}){let e=Le(t.profile);console.log(`connecting to ${e.hubUrl} (project=${e.projectId}) \u2026`);let r=Vr(e.hubUrl,e.cliToken),n=await new Promise(i=>{let s=[],a=!1,c=setTimeout(()=>{s.push("timeout"),r.close(),i({ok:!1,events:s})},5e3);r.on("open",()=>{s.push("open");let l={type:"register",projectId:e.projectId};r.send(JSON.stringify(l))}),r.on("message",l=>{let u=l.toString("utf-8");if(s.push(`msg:${u}`),u!=="pong")try{let m=JSON.parse(u);m.type==="registered"?(a=!!m.ok,clearTimeout(c),r.send("ping")):m.type}catch{}}),r.on("error",l=>s.push(`error:${l.message}`)),r.on("close",(l,u)=>{s.push(`close:${l}:${u?.toString()||""}`),clearTimeout(c),i({ok:a,events:s})}),setTimeout(()=>r.close(),1500)});for(let i of n.events)console.log(` ${i}`);n.ok||(console.error("hello failed"),process.exit(1)),console.log("ok \u2014 HUB reachable, CLI auth + project binding works.");try{let i=await te(e.hubUrl,e.cliToken,e.projectId);if(i.duplicateIntake){let s=i.duplicateIntake;console.warn(`warning: project \xAB${s.withProjectId}\xBB watches the same YouTrack columns (${s.columns.join(", ")}) and at least one of the two has no assignee filter \u2014 both will grab the same issues. Enable require_assignee + assignee on both.`)}}catch{}let o=re(t.profile);o?o.hubUrl===e.hubUrl.replace(/\/$/,"")?console.log(`worker: registered as ${o.sandboxId} (${o.name}), llm=${o.llm??"none"} \u2014 live state on the dashboard`):console.log(`worker: registered against a different HUB (${o.hubUrl})`):console.log("worker: not registered (run `codepipe up` or `codepipe worker register`)")}import{spawn as Nf}from"node:child_process";import{existsSync as Bt,mkdirSync as xc,readFileSync as vc,readdirSync as Of,writeFileSync as Sc}from"node:fs";import{join as dt,resolve as Cc}from"node:path";import{setTimeout as ho}from"node:timers/promises";import{cancel as Lf,confirm as Mt,intro as Tc,isCancel as ko,log as x,outro as yo,password as Gt,select as pt,spinner as Rc,text as V}from"@clack/prompts";import{simpleGit as gn}from"simple-git";async function Ut(t,e,r){return e.host==="github"?mf(t,e,r):e.host==="gitlab"?$f(t,e,r):vf(t,e,r)}async function oc(t,e,r={}){let n=r.explain??!0,o=`${t.owner}/${t.name} not found on ${t.host}`;try{if(t.host==="github")return e.githubToken?(await Ve(e.githubToken,"GET",`/repos/${t.owner}/${encodeURIComponent(t.name)}`)).status!==404?{found:!0}:{found:!1,detail:n?await ic(e.githubToken,t):o}:{found:"unknown",detail:"no GitHub token \u2014 existence not checked"};if(t.host==="gitlab"){if(!e.gitlabToken)return{found:"unknown",detail:"no GitLab token \u2014 existence not checked"};let s=encodeURIComponent(`${t.owner}/${t.name}`);return(await qe(e.gitlabToken,"GET",`/projects/${s}`)).status!==404?{found:!0}:{found:!1,detail:n?await sc(e.gitlabToken,t):o}}return e.bitbucket?(await Lt(e.bitbucket,"GET",`/repositories/${t.owner}/${encodeURIComponent(t.name)}`)).status!==404?{found:!0}:{found:!1,detail:n?await ac(e.bitbucket,t):o}:{found:"unknown",detail:"no Bitbucket credentials \u2014 existence not checked"}}catch(i){return{found:"unknown",detail:i instanceof Error?i.message:String(i)}}}async function ic(t,e){let r=!1;try{r=(await Ve(t,"GET",`/users/${encodeURIComponent(e.owner)}`)).status===200}catch{}return r?`GitHub repo ${e.owner}/${e.name} does not exist, or the token cannot see it \u2014 check the name; a fine-grained PAT must be scoped to this repo (and approved in the org)`:`GitHub owner "${e.owner}" not found \u2014 check the org/user spelling`}async function sc(t,e){let r=!1;try{r=(await qe(t,"GET",`/namespaces/${encodeURIComponent(e.owner)}`)).status===200}catch{}return r?`GitLab project ${e.owner}/${e.name} does not exist (the namespace "${e.owner}" is visible to the token) \u2014 check the project name, or the token has no access to this specific project`:`GitLab namespace "${e.owner}" is not visible to this token \u2014 check the group/username spelling; a private group answers 404 until the token's owner is a member`}async function ac(t,e){let r=!1;try{r=(await Lt(t,"GET",`/workspaces/${encodeURIComponent(e.owner)}`)).status===200}catch{}return r?`Bitbucket repo ${e.owner}/${e.name} does not exist in workspace "${e.owner}" (which the credential can see) \u2014 check the repo name, or the API token lacks access to it`:`Bitbucket workspace "${e.owner}" is not visible to this credential \u2014 check the workspace name and the token's read:repository:bitbucket scope`}var ff="https://api.github.com";async function Ve(t,e,r,n){let o={method:e,headers:{Accept:"application/vnd.github+json",Authorization:`Bearer ${t}`,"X-GitHub-Api-Version":"2022-11-28","User-Agent":"codepipe-cli"}};n!==void 0&&(o.body=JSON.stringify(n),o.headers["Content-Type"]="application/json");let i=await fetch(ff+r,o),s=await i.text(),a=s?JSON.parse(s):null;if(i.status>=400&&i.status!==404){let c=typeof a=="object"&&a&&"message"in a?a.message:s;throw new Error(`GitHub ${e} ${r} \u2192 ${i.status} ${c}`)}return{status:i.status,data:a}}async function mf(t,e,r){let n=r.githubToken;if(!n)throw new Error("GitHub PAT required to provision a github-hosted Context Repo \u2014 set GH_TOKEN / GITHUB_TOKEN or provide it during `codepipe init`");let o=await gf(n,e,r),i=await yf(n,o.owner,o.name);r.log.info(`scaffolding Context Repo files \u2192 ${o.owner}/${o.name}@${i}`);let s=St(t,e,r.youtrackWrites,r.trackerUrl);for(let a of s)await wf(n,o.owner,o.name,a.path,i)||await kf(n,o.owner,o.name,a.path,a.content,`chore(codepipe): scaffold ${a.path}`,i);return{host:"github",owner:o.owner,name:o.name,cloneUrl:o.sshUrl,branch:i}}async function gf(t,e,r){let n=await Ve(t,"GET",`/repos/${e.owner}/${encodeURIComponent(e.name)}`);if(n.status===200&&n.data)return r.log.info(`Context Repo ${e.owner}/${e.name} already exists \u2014 reusing`),{owner:n.data.owner.login,name:n.data.name,sshUrl:n.data.ssh_url};if(r.mode==="attach")throw new Error(`attach: ${await ic(t,e)} (attach joins an existing Context Repo and never creates one)`);let o=await hf(t,e.owner),i=o?`/orgs/${e.owner}/repos`:"/user/repos";r.log.info(`creating Context Repo ${e.owner}/${e.name} (${o?"org":"user"})`);let s=await Ve(t,"POST",i,{name:e.name,private:!0,auto_init:!0,description:`CodePipe Context Repo for project ${e.name}`});if(!s.data)throw new Error("GitHub createRepo: empty response");return{owner:s.data.owner.login,name:s.data.name,sshUrl:s.data.ssh_url}}async function hf(t,e){let{status:r,data:n}=await Ve(t,"GET",`/users/${e}`);return r===404||!n?!1:n.type==="Organization"}async function yf(t,e,r){let{data:n}=await Ve(t,"GET",`/repos/${e}/${r}`);if(!n)throw new Error("GitHub getDefaultBranch: empty response");return n.default_branch}async function wf(t,e,r,n,o){let{status:i,data:s}=await Ve(t,"GET",`/repos/${e}/${r}/contents/${encodeURI(n)}?ref=${encodeURIComponent(o)}`);return i===404||!s?null:s.sha}async function kf(t,e,r,n,o,i,s,a){let c={message:i,content:Buffer.from(o,"utf-8").toString("base64"),branch:s};a&&(c.sha=a),await Ve(t,"PUT",`/repos/${e}/${r}/contents/${encodeURI(n)}`,c)}var bf="https://gitlab.com/api/v4";async function qe(t,e,r,n){let o={method:e,headers:{"PRIVATE-TOKEN":t,"User-Agent":"codepipe-cli",...n!==void 0?{"Content-Type":"application/json"}:{}}};n!==void 0&&(o.body=JSON.stringify(n));let i=await fetch(bf+r,o),s=await i.text(),a=s?JSON.parse(s):null;if(i.status>=400&&i.status!==404){let c=typeof a=="object"&&a&&"message"in a?JSON.stringify(a.message):s;throw new Error(`GitLab ${e} ${r} \u2192 ${i.status} ${c}`)}return{status:i.status,data:a}}async function $f(t,e,r){let n=r.gitlabToken;if(!n)throw new Error("GitLab PAT required to provision a gitlab-hosted Context Repo \u2014 set GITLAB_TOKEN or provide it during `codepipe init`");let o=encodeURIComponent(`${e.owner}/${e.name}`),i,s=await qe(n,"GET",`/projects/${o}`);if(s.status===200&&s.data)r.log.info(`Context Repo ${e.owner}/${e.name} already exists \u2014 reusing`),i=s.data;else{if(r.mode==="attach")throw new Error(`attach: ${await sc(n,e)} (attach joins an existing Context Repo and never creates one)`);let m=await qe(n,"GET","/user"),d={name:e.name,path:e.name,visibility:"private",initialize_with_readme:!0,description:`CodePipe Context Repo for project ${e.name}`};if(m.data?.username!==e.owner){let p=await qe(n,"GET",`/namespaces/${encodeURIComponent(e.owner)}`);if(p.status===404||!p.data)throw new Error(`GitLab namespace "${e.owner}" not found (or the token cannot see it) \u2014 use your username or a group the token can create projects in`);d.namespace_id=p.data.id}r.log.info(`creating Context Repo ${e.owner}/${e.name} (gitlab)`);let g=await qe(n,"POST","/projects",d);if(!g.data)throw new Error("GitLab create project: empty response");i=g.data}let a=i.default_branch??"main";r.log.info(`scaffolding Context Repo files \u2192 ${e.owner}/${e.name}@${a}`);let c=St(t,e,r.youtrackWrites,r.trackerUrl),l=new Set;for(let m=1;;m++){let g=(await qe(n,"GET",`/projects/${i.id}/repository/tree?recursive=true&per_page=100&page=${m}&ref=${encodeURIComponent(a)}`)).data??[];for(let p of g)l.add(p.path);if(g.length<100)break}let u=c.filter(m=>!l.has(m.path)).map(m=>({action:"create",file_path:m.path,content:m.content}));return u.length>0?await qe(n,"POST",`/projects/${i.id}/repository/commits`,{branch:a,commit_message:"chore(codepipe): scaffold context repo files",actions:u}):r.log.info("nothing to scaffold \u2014 all files already present"),{host:"gitlab",owner:e.owner,name:i.path,cloneUrl:i.ssh_url_to_repo,branch:a}}var xf="https://api.bitbucket.org/2.0";async function Lt(t,e,r,n){let o={method:e,headers:{Authorization:"Basic "+Buffer.from(`${t.email}:${t.apiToken}`).toString("base64"),"User-Agent":"codepipe-cli"}};n?.json!==void 0?(o.body=JSON.stringify(n.json),o.headers["Content-Type"]="application/json"):n?.form&&(o.body=n.form);let i=await fetch(xf+r,o),s=await i.text(),a=null;try{a=s?JSON.parse(s):null}catch{}if(i.status>=400&&i.status!==404)throw new Error(`Bitbucket ${e} ${r} \u2192 ${i.status} ${s}`);return{status:i.status,data:a}}async function vf(t,e,r){let n=r.bitbucket;if(!n)throw new Error("Bitbucket account email + API token required to provision a bitbucket-hosted Context Repo \u2014 provide them during `codepipe init`");let o=`/repositories/${e.owner}/${encodeURIComponent(e.name)}`,i,s=await Lt(n,"GET",o);if(s.status===200&&s.data)r.log.info(`Context Repo ${e.owner}/${e.name} already exists \u2014 reusing`),i=s.data;else{if(r.mode==="attach")throw new Error(`attach: ${await ac(n,e)} (attach joins an existing Context Repo and never creates one)`);r.log.info(`creating Context Repo ${e.owner}/${e.name} (bitbucket)`);let m=await Lt(n,"POST",o,{json:{scm:"git",is_private:!0,description:`CodePipe Context Repo for project ${e.name}`}});if(m.status===404||!m.data?.slug)throw new Error(`Bitbucket cannot create ${e.owner}/${e.name} \u2014 workspace "${e.owner}" not found or the API token lacks repository-admin access to it`);i=m.data}let a=i.mainbranch?.name??"main";r.log.info(`scaffolding Context Repo files \u2192 ${e.owner}/${e.name}@${a}`);let c=St(t,e,r.youtrackWrites,r.trackerUrl),l=[];for(let m of c)(await Lt(n,"GET",`${o}/src/${encodeURIComponent(a)}/${m.path}?format=meta`)).status===404&&l.push(m);if(l.length>0){let m=new URLSearchParams;m.set("message","chore(codepipe): scaffold context repo files"),m.set("branch",a);for(let g of l)m.set(g.path,g.content);if((await Lt(n,"POST",`${o}/src`,{form:m})).status===404)throw new Error(`Bitbucket src commit to ${e.owner}/${e.name} \u2192 404 \u2014 the repo is not reachable with this credential (check workspace/name and API-token scopes)`)}else r.log.info("nothing to scaffold \u2014 all files already present");let u=i.links?.clone?.find(m=>m.name==="ssh")?.href;return{host:"bitbucket",owner:e.owner,name:i.slug??e.name,cloneUrl:u??`git@bitbucket.org:${e.owner}/${e.name}.git`,branch:a}}var Sf={"github.com":"github","gitlab.com":"gitlab","bitbucket.org":"bitbucket"};function je(t){let e=t.trim();if(!e)return null;let r,n;if(e.includes("://")){let a;try{a=new URL(e)}catch{return null}r=a.hostname.toLowerCase(),n=a.pathname}else{let a=/^(?:[\w.-]+@)?([\w.-]+):(.+)$/.exec(e);if(!a)return null;r=a[1].toLowerCase(),n=a[2]}let o=Sf[r];if(!o)return null;let i=n.replace(/^\/+/,"").replace(/\/+$/,"").split("/").filter(Boolean);if(i.length<2)return null;let s=i[i.length-1].replace(/\.git$/,"");return s?{host:o,owner:i.slice(0,-1).join("/"),repoName:s}:null}import{createHash as Cf}from"node:crypto";import{existsSync as cc,mkdirSync as Tf,readFileSync as lc,readdirSync as Rf,rmSync as fn,writeFileSync as If}from"node:fs";import{homedir as Pf}from"node:os";import{dirname as Ef,join as fo}from"node:path";var jf=24*60*60*1e3;function uc(){return fo(Pf(),".codepipe","init-drafts")}function mo(t){let e=Cf("sha256").update(t).digest("hex").slice(0,16);return fo(uc(),`${e}.json`)}function dc(t){let e=Date.now()-Date.parse(t);return!(e>=0&&e<=jf)}function pc(t){let e=mo(t);if(!cc(e))return null;try{let r=JSON.parse(lc(e,"utf-8"));return!r||r.cwd!==t||typeof r.answers!="object"||!r.answers?null:dc(r.savedAt)?(fn(e,{force:!0}),null):r}catch{return null}}function go(t){fn(mo(t),{force:!0})}function fc(){let t=uc();if(cc(t))for(let e of Rf(t)){let r=fo(t,e);try{let n=JSON.parse(lc(r,"utf-8"));dc(n.savedAt)&&fn(r,{force:!0})}catch{fn(r,{force:!0})}}}var Dt=class{constructor(e,r){this.cwd=e;this.answers=r?.answers?{...r.answers}:{}}answers;get(e){return this.answers[e]}set(e,r){this.answers[e]=r,this.persist()}delete(e){delete this.answers[e],this.persist()}async ask(e,r){if(e in this.answers)return this.answers[e];let n=await r();return this.set(e,n),n}clear(){go(this.cwd)}persist(){let e=mo(this.cwd);Tf(Ef(e),{recursive:!0});let r={cwd:this.cwd,savedAt:new Date().toISOString(),answers:this.answers};If(e,JSON.stringify(r,null,2)+`
|
|
554
|
-
`,{mode:384})}};function mc(t){return t?{message:"An index already exists. Re-index the project?",proceedValue:"yes",reindex:!0,options:[{value:"no",label:"No, keep the existing one"},{value:"yes",label:"Yes, re-index"}],initialValue:"no"}:{message:"Index the project repositories? (recommended on first run)",proceedValue:"yes",reindex:!1,options:[{value:"yes",label:"Yes"},{value:"skip",label:"Skip"}],initialValue:"yes"}}async function gc(t,e){if(t.host!=="github"||!e)return!1;try{return(await fetch(`https://api.github.com/repos/${t.owner}/${t.name}/contents/knowledge/INDEX.md?ref=${encodeURIComponent(t.branch)}`,{headers:{Authorization:`Bearer ${e}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28","User-Agent":"codepipe-cli"}})).status===200}catch{return!1}}import{existsSync as hc}from"node:fs";import{join as yc}from"node:path";import{simpleGit as wc}from"simple-git";var Af={info:t=>console.log(t),warn:t=>console.warn(t)};async function mr(t,e,r={}){let n=r.log??Af,o=[];for(let i of e){let s=yc(t,i.mountAs),a=qo(i);if(!hc(s)){if(r.dryRun){n.info(`would clone ${a} \u2192 ${i.mountAs}/`),o.push({mountAs:i.mountAs,status:"cloned",detail:"(dry-run)"});continue}try{n.info(`cloning ${a} \u2192 ${i.mountAs}/`),await wc().clone(a,s),o.push({mountAs:i.mountAs,status:"cloned"})}catch(u){let m=u instanceof Error?u.message:String(u);n.warn(`clone failed for ${i.mountAs}: ${m}`),o.push({mountAs:i.mountAs,status:"error",detail:m})}continue}if(!hc(yc(s,".git"))){n.warn(`${i.mountAs}/ exists but is not a git repo \u2014 skipping`),o.push({mountAs:i.mountAs,status:"skipped-not-git"});continue}let c=wc(s),l="";try{l=(await c.remote(["get-url","origin"]))?.toString().trim()??""}catch{l=""}if(!_f(l,a)){n.warn(`${i.mountAs}/ origin (${l||"none"}) != expected (${a}) \u2014 skipping`),o.push({mountAs:i.mountAs,status:"skipped-origin-mismatch",detail:l});continue}if(r.dryRun){n.info(`would fetch ${i.mountAs}/`),o.push({mountAs:i.mountAs,status:"fetched",detail:"(dry-run)"});continue}try{await c.fetch(),o.push({mountAs:i.mountAs,status:"fetched"})}catch(u){let m=u instanceof Error?u.message:String(u);n.warn(`fetch failed for ${i.mountAs}: ${m}`),o.push({mountAs:i.mountAs,status:"error",detail:m})}}return o}function _f(t,e){return kc(t)===kc(e)}function kc(t){return t.trim().replace(/\.git$/,"").replace(/^https?:\/\//,"").replace(/^git@/,"").replace(/:/g,"/").toLowerCase()}async function bc(t={}){let e=nt();e||(console.error("no .codepipe/ workspace found in this directory or any parent. run `codepipe init` first."),process.exit(1)),console.log(`codepipe sync \u2014 project ${e.spec.projectId} (${e.spec.repos.length} repos)`);let r=await mr(e.root,e.spec.repos,{dryRun:t.dryRun===!0});for(let n of r)console.log(` ${n.mountAs}: ${n.status}${n.detail?` \u2014 ${n.detail}`:""}`)}var $c=["# codepipe runtime \u2014 added by `codepipe init`","session.log","apply-queue.json"];function H(t){Lf(t),process.exit(1)}function ue(t){return ko(t)&&H("aborted"),t}function G(t){return ko(t)&&H("aborted"),typeof t=="string"?t:""}async function Ic(t={}){Tc("codepipe init \u2014 register a project locally or on a farm");let e=process.cwd();fc();let r=pc(e),n,o=!1;r&&Object.keys(r.answers).length>0?ue(await Mt({message:"You have not completed the initialization, do you want to continue?",initialValue:!0}))?(x.message("continuing with the saved answers \u2014 only the missing ones are asked"),n=new Dt(e,r),o=!0):(go(e),n=new Dt(e)):n=new Dt(e);let i=t.force===!0?null:await bo(e),s=await n.ask("target",async()=>ue(await pt({message:"where should this project run?",options:[{value:"local",label:"local \u2014 a CLI daemon on this machine, in this folder"},{value:"farm",label:"farm \u2014 a CLI daemon on a remote farm host"}],initialValue:"local"}))),a=null;s==="local"&&(a=i,a?x.message(`this folder is a git checkout of ${a.parsed.owner}/${a.parsed.repoName} \u2014 registering this repo in place (.codepipe/ will live inside it)`):o&&n.get("contextRepo")!==void 0||Ec(e,t.force===!0));let c=await n.ask("hubUrl",async()=>G(await V({message:"HUB URL",placeholder:ge,initialValue:L("HUB_URL")??ge,validate:j=>j.trim().startsWith("http")?void 0:"must start with http(s)://"})).trim().replace(/\/$/,"")),l=await n.ask("email",()=>hn()),{cliToken:u,accountEmail:m}=await n.ask("bootstrap",()=>yn(c,l)),d=null;s==="farm"&&(d=await Uf(c,u));let g=a?Bf(a.parsed.repoName):"",p=await n.ask("projectId",async()=>G(await V({message:"project id (slug)",placeholder:g||"acme",...g?{initialValue:g}:{},validate:j=>et.test(j.trim())?void 0:"must match /^[a-z][a-z0-9-]{1,30}$/"})).trim()),h=await n.ask("projectName",async()=>G(await V({message:"project name (human-readable)",placeholder:a?.parsed.repoName??"Acme",...a?{initialValue:a.parsed.repoName}:{},validate:j=>j.trim().length>0?void 0:"required"})).trim()),C=await n.ask("automationLevel",async()=>ue(await pt({message:"automation level",options:[{value:"assisted",label:"assisted \u2014 every gate via manual Run on the dashboard"},{value:"full",label:"full \u2014 gates auto-approve, runs end-to-end"}],initialValue:"assisted"}))),T=await n.ask("youtrack",()=>Uc()),I=await n.ask("youtrackProjectKey",async()=>G(await V({message:"YouTrack project key",placeholder:"DEV",validate:j=>j.trim().length>0?void 0:"required"})).trim()),k=await n.ask("youtrackWrites",async()=>ue(await Mt({message:"Allow CodePipe to write to YouTrack? (status changes, PR comments, dashboard mirror)",initialValue:!0}))),w=n.get("tokens")??{},_=()=>n.set("tokens",w),P=await n.ask("repos",()=>Hf(w,l,a,{onCred:_,initial:n.get("reposPartial")??[],onProgress:j=>n.set("reposPartial",j)}));n.delete("reposPartial");let b=await Kf(await n.ask("contextRepo",()=>Nc(p,P,w,l)),p,P,w,l,_,j=>n.set("contextRepo",j)),{spec:f,mode:v}=b;x.message("Only YouTrack tasks assigned to you enter this pipeline (to lift the filter later, set require_assignee: false in .codepipe/project.yaml).");let y=await n.ask("assigneeLogin",async()=>G(await V({message:"your YouTrack login (the assignee value)",...T.login?{initialValue:T.login}:{},validate:j=>j.trim().length>0?void 0:"required"})).trim()),S=await n.ask("claudeToken",()=>Xf(s==="farm")),R={projectId:p,name:h,automationLevel:C,repos:P,youtrackProjectKey:I,ownerEmail:m};x.step(`${v==="attach"?"attaching to":"provisioning"} Context Repo ${f.owner}/${f.name} (${f.host})\u2026`);let $;try{$=await Ut(R,f,{...Oc(w),youtrackWrites:k,trackerUrl:T.url,mode:v,log:{info:j=>x.message(j),warn:j=>x.warn(j)}})}catch(j){H(`Context Repo provisioning failed: ${j instanceof Error?j.message:String(j)}`)}R.contextRepo=$,x.success(`Context Repo ready: ${$.owner}/${$.name}@${$.branch}`),x.step(`registering project on ${c}\u2026`);let E;try{E=await Rt(c,u,R)}catch(j){if(j instanceof O&&j.status===409){x.warn(`project ${p} already exists on HUB \u2014 reusing it`);try{E=await te(c,u,p)}catch(ae){throw ae instanceof O&&H(`HUB \u2192 ${ae.status} ${ae.message}`),ae}}else if(j instanceof O&&j.status===401)n.delete("cliToken"),H("HUB rejected the sign-in token (401) \u2014 re-run `codepipe init` to sign in again");else if(j instanceof O)H(`HUB \u2192 ${j.status} ${j.message}`);else throw j}let D=E.contextRepo??$;x.success(`project ${E.projectId} ready (${E.provisioningStatus})`);let F=await zf(D),me={url:T.url,token:T.token};if(s==="farm"){let j=d,ae={...w,...F?{contextWrite:F}:{},...S?{claude:{oauthToken:S}}:{},youtrack:me},Ae=w.github?.token;if(D.host==="github"&&Ae)try{let J=sa(`devpipe-${p}`);await aa(D,Ae,J.publicKey,`devpipe-${p}`),ae.contextSsh={privateKey:J.privateKey},x.success("Context Repo SSH deploy key registered (no contextWrite PAT needed on the farm)")}catch(J){x.warn(`could not set up Context Repo SSH deploy key (${J instanceof Error?J.message:String(J)}); the farm will fall back to the token path.`)}let ve={projectId:p,config:{hubUrl:c,cliToken:u,projectId:p},secrets:ae,contextRepo:D,projectConfig:be(R,k,T.url,y||void 0)},$n=Ct(j.farm.publicKey,JSON.stringify(ve));x.step(`handing project ${p} to farm ${j.farm.name}\u2026`);let Xe;try{Xe=await zr(c,u,j.farm.farmId,{projectId:p,sealedBundle:$n})}catch(J){throw J instanceof O&&H(J.status===409?`farm ${j.farm.name} is offline \u2014 start it and re-run.`:J.status===504?`farm ${j.farm.name} did not respond in time.`:`HUB \u2192 ${J.status} ${J.message}`),J}Xe.ok||H(`farm rejected provisioning: ${Xe.error??"unknown error"}`),await wo(c,u,p,D,Ae),n.clear(),yo(`done. project ${p} is now hosted on farm ${j.farm.name} (daemon ${Xe.daemonStatus}). Watch the setup progress on the dashboard \u2014 the project card shows each step until the project is ready.`);return}Lc(w),await jc(e,D.cloneUrl,D.branch),_c(e),a&&await Gf(e);{let j=dt(e,we);xt(j);let ae=be(R,k,T.url,y||void 0),Ae=Zt(j,ae);Ae.length>0&&x.success(`local project config \u2192 .codepipe/{${Ae.join(", ")}}`),st(p,ae,{info:ve=>x.message(ve),warn:ve=>x.warn(ve)})}await Ac(e,E.repos);let Je={hubUrl:c,cliToken:u,projectId:p,...w,...F?{contextWrite:F}:{},...S?{claude:{oauthToken:S}}:{},youtrack:me};q(Je),ot({hubUrl:c,cliToken:u,projectId:p,accountEmail:m},p),x.success(`secrets \u2192 ${it(p)}`),await wo(c,u,p,D,w.github?.token??process.env.GH_TOKEN??process.env.GITHUB_TOKEN),n.clear(),yo("done. next: `codepipe up` from this folder \u2014 starts the daemon and an agent worker. (`codepipe` opens the interactive REPL.)")}async function wo(t,e,r,n,o){let i=await gc(n,o),s=mc(i),a=await pt({message:s.message,options:s.options,initialValue:s.initialValue});if(!(ko(a)||a!==s.proceedValue))try{let{jobId:c}=await Xr(t,e,r,{reindex:s.reindex});x.success(`indexing queued (job ${c}); knowledge/INDEX.md will appear in the Context Repo once the project daemon is running and a SANDBOX picks up the job.`)}catch(c){x.warn(`could not start indexing: ${c instanceof Error?c.message:String(c)}. You can retry later \u2014 registration is not affected.`)}}async function Uf(t,e){let r;try{r=await Ds(t,e)}catch(c){throw c instanceof O&&H(`could not list farms: HUB \u2192 ${c.status} ${c.message}`),c}let n=r.filter(c=>c.publicKey);n.length===0&&H("no farm is available to this account. Farms are assigned by the operator \u2014 ask them to assign one to you (or, if you run your own farm host: `codepipe-farm register --hub <url> --token <token>` and `codepipe-farm start`, then have the operator assign it).");let o=ue(await pt({message:"target farm",options:n.map(c=>({value:c.farmId,label:`${c.name}${c.online?"":" (offline)"} \u2014 ${c.keyFingerprint??"no fingerprint"}`}))})),i=n.find(c=>c.farmId===o),s;try{s=qr(i.farmId,i.publicKey)}catch(c){H(c instanceof Error?c.message:String(c))}return ue(await Mt({message:`confirm farm ${i.name} cred-channel fingerprint:
|
|
554
|
+
`,{mode:384})}};function mc(t){return t?{message:"An index already exists. Re-index the project?",proceedValue:"yes",reindex:!0,options:[{value:"no",label:"No, keep the existing one"},{value:"yes",label:"Yes, re-index"}],initialValue:"no"}:{message:"Index the project repositories? (recommended on first run)",proceedValue:"yes",reindex:!1,options:[{value:"yes",label:"Yes"},{value:"skip",label:"Skip"}],initialValue:"yes"}}async function gc(t,e){if(t.host!=="github"||!e)return!1;try{return(await fetch(`https://api.github.com/repos/${t.owner}/${t.name}/contents/knowledge/INDEX.md?ref=${encodeURIComponent(t.branch)}`,{headers:{Authorization:`Bearer ${e}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28","User-Agent":"codepipe-cli"}})).status===200}catch{return!1}}import{existsSync as hc}from"node:fs";import{join as yc}from"node:path";import{simpleGit as wc}from"simple-git";var Af={info:t=>console.log(t),warn:t=>console.warn(t)};async function mr(t,e,r={}){let n=r.log??Af,o=[];for(let i of e){let s=yc(t,i.mountAs),a=qo(i);if(!hc(s)){if(r.dryRun){n.info(`would clone ${a} \u2192 ${i.mountAs}/`),o.push({mountAs:i.mountAs,status:"cloned",detail:"(dry-run)"});continue}try{n.info(`cloning ${a} \u2192 ${i.mountAs}/`),await wc().clone(a,s),o.push({mountAs:i.mountAs,status:"cloned"})}catch(u){let m=u instanceof Error?u.message:String(u);n.warn(`clone failed for ${i.mountAs}: ${m}`),o.push({mountAs:i.mountAs,status:"error",detail:m})}continue}if(!hc(yc(s,".git"))){n.warn(`${i.mountAs}/ exists but is not a git repo \u2014 skipping`),o.push({mountAs:i.mountAs,status:"skipped-not-git"});continue}let c=wc(s),l="";try{l=(await c.remote(["get-url","origin"]))?.toString().trim()??""}catch{l=""}if(!_f(l,a)){n.warn(`${i.mountAs}/ origin (${l||"none"}) != expected (${a}) \u2014 skipping`),o.push({mountAs:i.mountAs,status:"skipped-origin-mismatch",detail:l});continue}if(r.dryRun){n.info(`would fetch ${i.mountAs}/`),o.push({mountAs:i.mountAs,status:"fetched",detail:"(dry-run)"});continue}try{await c.fetch(),o.push({mountAs:i.mountAs,status:"fetched"})}catch(u){let m=u instanceof Error?u.message:String(u);n.warn(`fetch failed for ${i.mountAs}: ${m}`),o.push({mountAs:i.mountAs,status:"error",detail:m})}}return o}function _f(t,e){return kc(t)===kc(e)}function kc(t){return t.trim().replace(/\.git$/,"").replace(/^https?:\/\//,"").replace(/^git@/,"").replace(/:/g,"/").toLowerCase()}async function bc(t={}){let e=nt();e||(console.error("no .codepipe/ workspace found in this directory or any parent. run `codepipe init` first."),process.exit(1)),console.log(`codepipe sync \u2014 project ${e.spec.projectId} (${e.spec.repos.length} repos)`);let r=await mr(e.root,e.spec.repos,{dryRun:t.dryRun===!0});for(let n of r)console.log(` ${n.mountAs}: ${n.status}${n.detail?` \u2014 ${n.detail}`:""}`)}var $c=["# codepipe runtime \u2014 added by `codepipe init`","session.log","apply-queue.json"];function H(t){Lf(t),process.exit(1)}function ue(t){return ko(t)&&H("aborted"),t}function G(t){return ko(t)&&H("aborted"),typeof t=="string"?t:""}async function Ic(t={}){Tc("codepipe init \u2014 register a project locally or on a farm");let e=process.cwd();fc();let r=pc(e),n,o=!1;r&&Object.keys(r.answers).length>0?ue(await Mt({message:"You have not completed the initialization, do you want to continue?",initialValue:!0}))?(x.message("continuing with the saved answers \u2014 only the missing ones are asked"),n=new Dt(e,r),o=!0):(go(e),n=new Dt(e)):n=new Dt(e);let i=t.force===!0?null:await bo(e),s=await n.ask("target",async()=>ue(await pt({message:"where should this project run?",options:[{value:"local",label:"local \u2014 a CLI daemon on this machine, in this folder"},{value:"farm",label:"farm \u2014 a CLI daemon on a remote farm host"}],initialValue:"local"}))),a=null;s==="local"&&(a=i,a?x.message(`this folder is a git checkout of ${a.parsed.owner}/${a.parsed.repoName} \u2014 registering this repo in place (.codepipe/ will live inside it)`):o&&n.get("contextRepo")!==void 0||Ec(e,t.force===!0));let c=await n.ask("hubUrl",async()=>G(await V({message:"HUB URL",placeholder:ge,initialValue:L("HUB_URL")??ge,validate:j=>j.trim().startsWith("http")?void 0:"must start with http(s)://"})).trim().replace(/\/$/,"")),l=await n.ask("email",()=>hn()),{cliToken:u,accountEmail:m}=await n.ask("bootstrap",()=>yn(c,l)),d=null;s==="farm"&&(d=await Uf(c,u));let g=a?Bf(a.parsed.repoName):"",p=await n.ask("projectId",async()=>G(await V({message:"project id (slug)",placeholder:g||"acme",...g?{initialValue:g}:{},validate:j=>et.test(j.trim())?void 0:"must match /^[a-z][a-z0-9-]{1,30}$/"})).trim()),h=await n.ask("projectName",async()=>G(await V({message:"project name (human-readable)",placeholder:a?.parsed.repoName??"Acme",...a?{initialValue:a.parsed.repoName}:{},validate:j=>j.trim().length>0?void 0:"required"})).trim()),C=await n.ask("automationLevel",async()=>ue(await pt({message:"automation level",options:[{value:"assisted",label:"assisted \u2014 every gate via manual Run on the dashboard"},{value:"full",label:"full \u2014 gates auto-approve, runs end-to-end"}],initialValue:"assisted"}))),T=await n.ask("youtrack",()=>Uc()),I=await n.ask("youtrackProjectKey",async()=>G(await V({message:"YouTrack project key",placeholder:"DEV",validate:j=>j.trim().length>0?void 0:"required"})).trim()),k=await n.ask("youtrackWrites",async()=>ue(await Mt({message:"Allow CodePipe to write to YouTrack? (status changes, PR comments, dashboard mirror)",initialValue:!0}))),w=n.get("tokens")??{},_=()=>n.set("tokens",w),P=await n.ask("repos",()=>Hf(w,l,a,{onCred:_,initial:n.get("reposPartial")??[],onProgress:j=>n.set("reposPartial",j)}));n.delete("reposPartial");let b=await Kf(await n.ask("contextRepo",()=>Nc(p,P,w,l)),p,P,w,l,_,j=>n.set("contextRepo",j)),{spec:f,mode:v}=b;x.message("Only YouTrack tasks assigned to you enter this pipeline (to lift the filter later, set require_assignee: false in .codepipe/project.yaml).");let y=await n.ask("assigneeLogin",async()=>G(await V({message:"your YouTrack login (the assignee value)",...T.login?{initialValue:T.login}:{},validate:j=>j.trim().length>0?void 0:"required"})).trim()),S=await n.ask("claudeToken",()=>Xf(s==="farm")),R={projectId:p,name:h,automationLevel:C,repos:P,youtrackProjectKey:I};x.step(`${v==="attach"?"attaching to":"provisioning"} Context Repo ${f.owner}/${f.name} (${f.host})\u2026`);let $;try{$=await Ut(R,f,{...Oc(w),youtrackWrites:k,trackerUrl:T.url,mode:v,log:{info:j=>x.message(j),warn:j=>x.warn(j)}})}catch(j){H(`Context Repo provisioning failed: ${j instanceof Error?j.message:String(j)}`)}R.contextRepo=$,x.success(`Context Repo ready: ${$.owner}/${$.name}@${$.branch}`),x.step(`registering project on ${c}\u2026`);let E;try{E=await Rt(c,u,R)}catch(j){if(j instanceof O&&j.status===409){x.warn(`project ${p} already exists on HUB \u2014 reusing it`);try{E=await te(c,u,p)}catch(ae){throw ae instanceof O&&H(`HUB \u2192 ${ae.status} ${ae.message}`),ae}}else if(j instanceof O&&j.status===401)n.delete("cliToken"),H("HUB rejected the sign-in token (401) \u2014 re-run `codepipe init` to sign in again");else if(j instanceof O)H(`HUB \u2192 ${j.status} ${j.message}`);else throw j}let D=E.contextRepo??$;x.success(`project ${E.projectId} ready (${E.provisioningStatus})`);let F=await zf(D),me={url:T.url,token:T.token};if(s==="farm"){let j=d,ae={...w,...F?{contextWrite:F}:{},...S?{claude:{oauthToken:S}}:{},youtrack:me},Ae=w.github?.token;if(D.host==="github"&&Ae)try{let J=sa(`devpipe-${p}`);await aa(D,Ae,J.publicKey,`devpipe-${p}`),ae.contextSsh={privateKey:J.privateKey},x.success("Context Repo SSH deploy key registered (no contextWrite PAT needed on the farm)")}catch(J){x.warn(`could not set up Context Repo SSH deploy key (${J instanceof Error?J.message:String(J)}); the farm will fall back to the token path.`)}let ve={projectId:p,config:{hubUrl:c,cliToken:u,projectId:p},secrets:ae,contextRepo:D,projectConfig:be(R,k,T.url,y||void 0)},$n=Ct(j.farm.publicKey,JSON.stringify(ve));x.step(`handing project ${p} to farm ${j.farm.name}\u2026`);let Xe;try{Xe=await zr(c,u,j.farm.farmId,{projectId:p,sealedBundle:$n})}catch(J){throw J instanceof O&&H(J.status===409?`farm ${j.farm.name} is offline \u2014 start it and re-run.`:J.status===504?`farm ${j.farm.name} did not respond in time.`:`HUB \u2192 ${J.status} ${J.message}`),J}Xe.ok||H(`farm rejected provisioning: ${Xe.error??"unknown error"}`),await wo(c,u,p,D,Ae),n.clear(),yo(`done. project ${p} is now hosted on farm ${j.farm.name} (daemon ${Xe.daemonStatus}). Watch the setup progress on the dashboard \u2014 the project card shows each step until the project is ready.`);return}Lc(w),await jc(e,D.cloneUrl,D.branch),_c(e),a&&await Gf(e);{let j=dt(e,we);xt(j);let ae=be(R,k,T.url,y||void 0),Ae=Zt(j,ae);Ae.length>0&&x.success(`local project config \u2192 .codepipe/{${Ae.join(", ")}}`),st(p,ae,{info:ve=>x.message(ve),warn:ve=>x.warn(ve)})}await Ac(e,E.repos);let Je={hubUrl:c,cliToken:u,projectId:p,...w,...F?{contextWrite:F}:{},...S?{claude:{oauthToken:S}}:{},youtrack:me};q(Je),ot({hubUrl:c,cliToken:u,projectId:p,accountEmail:m},p),x.success(`secrets \u2192 ${it(p)}`),await wo(c,u,p,D,w.github?.token??process.env.GH_TOKEN??process.env.GITHUB_TOKEN),n.clear(),yo("done. next: `codepipe up` from this folder \u2014 starts the daemon and an agent worker. (`codepipe` opens the interactive REPL.)")}async function wo(t,e,r,n,o){let i=await gc(n,o),s=mc(i),a=await pt({message:s.message,options:s.options,initialValue:s.initialValue});if(!(ko(a)||a!==s.proceedValue))try{let{jobId:c}=await Xr(t,e,r,{reindex:s.reindex});x.success(`indexing queued (job ${c}); knowledge/INDEX.md will appear in the Context Repo once the project daemon is running and a SANDBOX picks up the job.`)}catch(c){x.warn(`could not start indexing: ${c instanceof Error?c.message:String(c)}. You can retry later \u2014 registration is not affected.`)}}async function Uf(t,e){let r;try{r=await Ds(t,e)}catch(c){throw c instanceof O&&H(`could not list farms: HUB \u2192 ${c.status} ${c.message}`),c}let n=r.filter(c=>c.publicKey);n.length===0&&H("no farm is available to this account. Farms are assigned by the operator \u2014 ask them to assign one to you (or, if you run your own farm host: `codepipe-farm register --hub <url> --token <token>` and `codepipe-farm start`, then have the operator assign it).");let o=ue(await pt({message:"target farm",options:n.map(c=>({value:c.farmId,label:`${c.name}${c.online?"":" (offline)"} \u2014 ${c.keyFingerprint??"no fingerprint"}`}))})),i=n.find(c=>c.farmId===o),s;try{s=qr(i.farmId,i.publicKey)}catch(c){H(c instanceof Error?c.message:String(c))}return ue(await Mt({message:`confirm farm ${i.name} cred-channel fingerprint:
|
|
555
555
|
${s}
|
|
556
556
|
(compare with the farm host's \`codepipe-farm register\` output)`,initialValue:!0}))||H("farm fingerprint not confirmed \u2014 aborting."),Yr(i.farmId,s),{farm:i,fingerprint:s}}async function Pc(t){Tc(`codepipe clone ${t.projectId} \u2014 reconstruct workspace`);let e=process.cwd();Ec(e,t.force===!0);let r=G(await V({message:"HUB URL",initialValue:L("HUB_URL")??ge,validate:m=>m.trim().startsWith("http")?void 0:"must start with http(s)://"})).trim().replace(/\/$/,""),n=await hn(),{cliToken:o,accountEmail:i}=await yn(r,n);x.step(`fetching project ${t.projectId} from HUB\u2026`);let s;try{s=await te(r,o,t.projectId)}catch(m){throw m instanceof O&&H(`HUB \u2192 ${m.status} ${m.message}`),m}s.contextRepo||H(`project ${t.projectId} has no Context Repo on HUB`);let a=await Uc(),c={},l=new Set(s.repos.map(m=>m.host));l.add(s.contextRepo.host);for(let m of l)await mn(m,c,m===s.contextRepo.host?s.contextRepo.owner:s.repos.find(d=>d.host===m)?.owner,n);Lc(c),await jc(e,s.contextRepo.cloneUrl,s.contextRepo.branch),_c(e);{let m=dt(e,we);xt(m);let d={projectId:t.projectId,name:s.name,automationLevel:s.automationLevel,repos:s.repos,...s.youtrackProjectKey?{youtrackProjectKey:s.youtrackProjectKey}:{}},g=be(d,!0,a.url),p=Zt(m,g);p.length>0&&x.success(`local project config \u2192 .codepipe/{${p.join(", ")}} (defaults \u2014 review and adjust)`),st(t.projectId,g,{info:h=>x.message(h),warn:h=>x.warn(h)})}await Ac(e,s.repos);let u={hubUrl:r,cliToken:o,projectId:t.projectId,...c,youtrack:{url:a.url,token:a.token}};q(u),ot({hubUrl:r,cliToken:o,projectId:t.projectId,accountEmail:i},t.projectId),x.success(`secrets \u2192 ${it(t.projectId)}`),await wo(r,o,t.projectId,s.contextRepo,c.github?.token??process.env.GH_TOKEN??process.env.GITHUB_TOKEN),yo("done.")}function Ec(t,e){if(!Bt(t)){xc(t,{recursive:!0});return}let r=new Set([".DS_Store",".codepipe",".devpipe"]),n=Of(t).filter(o=>!r.has(o));n.length!==0&&(e||H(`cwd ${t} is not empty (contains: ${n.slice(0,5).join(", ")}${n.length>5?", \u2026":""}). use --force to bypass.`))}async function bo(t){if(!Bt(dt(t,".git")))return null;try{let r=(await gn(t).remote(["get-url","origin"])||"").toString().trim(),n=r?je(r):null;return n?{parsed:n,defaultBranch:await Df(t)}:null}catch{return null}}async function Df(t){let e=gn(t);try{let n=(await e.raw(["symbolic-ref","--short","refs/remotes/origin/HEAD"])).trim().replace(/^origin\//,"");if(n)return n}catch{}try{let r=(await e.raw(["symbolic-ref","--short","HEAD"])).trim();if(r)return r}catch{}return"main"}function Bf(t){let e=t.toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^[-0-9]+/,"").replace(/-+$/,"").slice(0,31);return et.test(e)?e:""}function Mf(t){return t.split(/\r?\n/).some(e=>{let r=e.trim();return r===".codepipe"||r===".codepipe/"||r==="/.codepipe"||r==="/.codepipe/"})}async function Gf(t){let e=dt(t,".gitignore"),r=Bt(e)?vc(e,"utf-8"):"";if(Mf(r))return;if(!ue(await Mt({message:"add .codepipe/ to this repo's .gitignore? (recommended \u2014 workspace state, not code)",initialValue:!0}))){x.warn("skipped \u2014 remember that .codepipe/ is a separate git repo living inside this one");return}let o=r.length===0||r.endsWith(`
|
|
557
557
|
`)?"":`
|
|
@@ -603,4 +603,4 @@ Re-register it: codepipe up --reregister (or delete that file and run codepipe
|
|
|
603
603
|
`),t.unread+=1,Ro(t),t.rl.prompt(!0)}function Ro(t){let e=t.unread>0?" \u2605":"";t.rl.setPrompt(`codepipe (${t.ws.spec.projectId})${e} > `)}var il=!1;function sl(t){il||(il=!0,Ym(t.rl),t.daemon.stop(),console.log(`
|
|
604
604
|
bye.`),setTimeout(()=>process.exit(0),150))}function Fm(t,e){let r=t.indexOf(e);if(r>=0&&t[r+1])return t[r+1]}function Hm(t,e){let r=[];for(let n=0;n<t.length;n++)t[n]===e&&t[n+1]&&r.push(t[n+1]);return r}function Km(t,e){let r=t.indexOf(e);return r<0?"":t.slice(r+1).join(" ").replace(/^["']|["']$/g,"").trim()}function $r(t){t instanceof O?console.log(` HUB \u2192 ${t.status} ${t.message}`):console.log(` ${t instanceof Error?t.message:String(t)}`)}function Wm(){if(!al(kn))return[];try{return $m(kn,"utf-8").split(/\r?\n/).filter(Boolean).reverse()}catch{return[]}}function Ym(t){let r=(t.history??[]).filter(n=>!/^\/secret\s+set\b/.test(n)&&!/^\/login\b/.test(n));try{bm(Sm(kn),{recursive:!0}),xm(kn,r.slice().reverse().join(`
|
|
605
605
|
`)+`
|
|
606
|
-
`)}catch{}}import{hostname as qm}from"node:os";import{cancel as Vm,confirm as dl,intro as zm,isCancel as ml,log as Wt,multiselect as Jm,outro as pl,password as Xm,select as Io,text as Po}from"@clack/prompts";function xr(t){Vm(t),process.exit(1)}function Yt(t){return ml(t)&&xr("aborted"),t}function bn(t){return ml(t)&&xr("aborted"),typeof t=="string"?t:""}function Eo(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}async function fl(t,e){try{let{secret:r}=await Jr(t,e);return r}catch(r){throw r instanceof O&&r.status===404&&xr("this HUB has no account-issued sandbox registration \u2014 issue a registration token in the dashboard (Status \u2192 SANDBOX) and re-run with it"),r}}async function Qm(t,e){if(Yt(await Io({message:"which projects should this worker serve?",options:[{value:"all",label:"all my projects (recommended \u2014 new projects included automatically)"},{value:"selected",label:"only selected projects"}],initialValue:"all"}))==="all")return[];if(e)try{let o=await Ms(t,e);if(o.length>0)return Yt(await Jm({message:"pick the projects (space to toggle, enter to confirm)",options:o.map(i=>({value:i.id,label:`${i.id} \u2014 ${i.name}`})),required:!0}));Wt.warn("your account owns no projects yet \u2014 enter the ids manually")}catch(o){Wt.warn(`could not list projects (${o instanceof Error?o.message:String(o)}) \u2014 enter the ids manually`)}return bn(await Po({message:"project ids (comma or space separated)",placeholder:"acme, beta",validate:o=>o.trim().length>0?void 0:"required"})).split(/[\s,]+/).filter(Boolean)}async function jo(t){zm("codepipe worker \u2014 set up this machine as a runner");let e=re(t.profile);e&&(Wt.warn(`already registered as ${e.sandboxId} (${e.name}) at ${e.hubUrl} \u2014 the wizard will replace this registration`),Yt(await dl({message:"re-register this worker?",initialValue:!1}))||xr("keeping the existing registration"));let r=Te(t.profile)??Te(),n=bn(await Po({message:"HUB URL",placeholder:ge,initialValue:L("HUB_URL")??r?.hubUrl??ge,validate:d=>d.trim().startsWith("http")?void 0:"must start with http(s)://"})).trim().replace(/\/$/,""),o=r!==null&&r.hubUrl.replace(/\/$/,"")===n,i=Yt(await Io({message:"how to authorize the registration?",options:[...o?[{value:"local",label:"this machine's CLI account (recommended \u2014 no token hand-off)"}]:[],{value:"login",label:"log in by email (magic-link, like codepipe init)"},{value:"paste",label:"paste a registration token from the dashboard"}],initialValue:o?"local":"login"})),s,a=null;if(i==="local")a=r.cliToken,s=await fl(n,a),Wt.success("account-issued registration token minted");else if(i==="login"){let d=await hn();a=(await yn(n,d)).cliToken,s=await fl(n,a),Wt.success("account-issued registration token minted")}else s=bn(await Xm({message:"registration token (from Status \u2192 SANDBOX)"})).trim(),s||xr("a registration token is required");let c=await Qm(n,a),l=bn(await Po({message:"worker name",initialValue:qm(),validate:d=>d.trim().length>0?void 0:"required"})).trim(),u=Yt(await Io({message:"agent backend",options:[{value:"claude-headless",label:"claude-headless \u2014 Claude Code on PATH (the real thing)"},{value:"mock",label:"mock \u2014 deterministic stub (development)"},{value:"",label:"none \u2014 this worker will not claim agent jobs"}],initialValue:"claude-headless"}));if(await ct({hub:n,token:s,name:l,projects:c,...u?{llm:u}:{},force:e!==null,...t.profile?{profile:t.profile}:{}}),Wt.message("the fingerprint above pins on the project CLI on first sight (TOFU); `codepipe up` pins it automatically"),!Yt(await dl({message:"start the claim-loop now?",initialValue:!0}))){pl("registered. start later with `codepipe worker`.");return}pl("starting the claim-loop\u2026"),await fr(t.profile?{profile:t.profile}:{})}function eg(){let t=process.argv;for(let e=0;e<t.length;e++){let r=t[e];if(r==="--profile")return t[e+1];if(r&&r.startsWith("--profile="))return r.slice(10)}return L("PROFILE")}var oe=eg();Xo(oe);ei();var de=new Zm;de.name("codepipe").description("CodePipe CLI \u2014 local client that talks to HUB and performs real-world writes").version(ce).option("--profile <id>","Profile id (project id). Picks `~/.codepipe/profiles/<id>/config.json` and `cli/profiles/<id>/.env`. Default = no profile = legacy single-project config at `~/.codepipe/config.json`.").action(async()=>{try{await ul()}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("init").description("Bootstrap a project: in an empty folder (repos clone as siblings) or in-place inside an existing git repo (origin prefilled, .codepipe/ inside). Magic-link auth; secrets to ~/.codepipe/secrets/<id>.json").option("--force","Bypass the empty-cwd guard",!1).option("--headless","Non-interactive provisioning from a JSON config (no prompts, no magic-link, no local clone) \u2014 for CLI farms").option("--config <path>","Headless config JSON path; '-' or omitted reads stdin").option("--skip-verify","Headless: skip live credential verification").action(async t=>{try{t.headless?await Dc({configPath:t.config,skipVerify:t.skipVerify===!0}):await Ic({force:t.force===!0})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("config").description("Persist HUB URL, CLI token and project id without provisioning/cloning (dev & mock flow; used by `make cli-init`)").requiredOption("--hub <url>","HUB base URL, e.g. http://localhost:3030").requiredOption("--token <token>","CLI token (matches HUB_CLI_TOKEN on HUB)").requiredOption("--project <id>","Project id this CLI is bound to").option("--force","Overwrite existing config",!1).action(async t=>{try{await ui({...t,profile:oe})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("clone").description("Reconstruct an existing project's workspace in the current empty folder \u2014 for continuing work on another machine").argument("<projectId>","Project id (as registered on HUB)").option("--force","Bypass the empty-cwd guard",!1).action(async(t,e)=>{try{await Pc({projectId:t,force:e.force===!0})}catch(r){console.error(r instanceof Error?r.message:r),process.exit(1)}});de.command("daemon").description("Long-running WS daemon that executes WriteActions dispatched by HUB").action(async()=>{try{await ma({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("sync").description("Clone/fetch project repos as siblings of .codepipe/ per project.yaml").option("--dry-run","Show what would happen without touching the filesystem",!1).action(async t=>{try{await bc({dryRun:t.dryRun===!0})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("login").description("Set the Claude OAuth token (sealed into job bundles)").option("--token <token>","Provide the token non-interactively").option("--shared","Save to the machine/farm-wide ~/.codepipe/shared.json instead of this project").option("--stdin","Read the token from stdin (for scripted/ssh delivery)").action(async t=>{try{await Hc({profile:oe,token:t.token,shared:t.shared,stdin:t.stdin})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("hello").description("Open WS to HUB, ping/pong, exit (smoke-test for connectivity & auth)").action(async()=>{try{await nc({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("up").description("Run the CLI daemon and an embedded SANDBOX worker together (solo-developer mode)").option("--name <name>","Worker name (defaults to <hostname>-up; used on first registration)").option("--llm <backend>","Worker agent backend on first registration: 'claude-headless' (default) | 'mock'").option("--projects <ids...>","Project IDs the worker may serve on first registration (empty = all your projects)").option("--reregister","Replace the worker registration when the HUB no longer knows it (it was removed)",!1).action(async t=>{try{await zc({profile:oe,...t})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});var gl=de.command("worker").description("SANDBOX worker role \u2014 claims jobs from HUB and executes agent work");gl.command("register").description("Register this machine as a SANDBOX worker with a HUB (no flags on a TTY \u2192 interactive wizard)").option("--hub <url>","HUB base URL (env CODEPIPE_HUB_URL)").option("--token <token>","Registration token (env CODEPIPE_WORKER_REG_TOKEN)").option("--name <name>","Human-readable name (env CODEPIPE_WORKER_NAME; defaults to hostname)").option("--projects <ids...>","Project IDs this worker can serve (env CODEPIPE_WORKER_PROJECTS, comma/space separated; empty = all your projects)").option("--llm <backend>","Agent backend: 'claude-headless' | 'mock' (env CODEPIPE_WORKER_LLM; omit for none)").option("--force","Overwrite existing registration",!1).action(async t=>{try{let e=t.hub??L("HUB_URL")??Te(oe)?.hubUrl??ge,r=t.token??L("WORKER_REG_TOKEN");if(!r){if(!t.hub&&!t.token&&Eo()){await jo({profile:oe});return}console.error("missing --token (or CODEPIPE_WORKER_REG_TOKEN); run `codepipe worker register` with no flags on a terminal for the wizard"),process.exit(1)}let n=L("WORKER_PROJECTS")?.split(/[\s,]+/).filter(Boolean),o=t.name??L("WORKER_NAME"),i=t.llm??L("WORKER_LLM");await ct({hub:e,token:r,projects:t.projects?.length?t.projects:n??[],force:t.force===!0,...o?{name:o}:{},...i?{llm:i}:{},...oe?{profile:oe}:{}})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});gl.command("start",{isDefault:!0}).description("Connect to HUB and run the claim-loop (default subcommand)").action(async()=>{try{if(!re(oe)&&Eo()){await jo({profile:oe});return}await fr(oe?{profile:oe}:{})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});var tg=de.command("project").description("Manage CodePipe projects");tg.command("add").description("Interactive wizard to register a project with HUB and auto-provision Context Repo").action(async()=>{try{await qc({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.parseAsync();
|
|
606
|
+
`)}catch{}}import{hostname as qm}from"node:os";import{cancel as Vm,confirm as dl,intro as zm,isCancel as ml,log as Wt,multiselect as Jm,outro as pl,password as Xm,select as Io,text as Po}from"@clack/prompts";function xr(t){Vm(t),process.exit(1)}function Yt(t){return ml(t)&&xr("aborted"),t}function bn(t){return ml(t)&&xr("aborted"),typeof t=="string"?t:""}function Eo(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}async function fl(t,e){try{let{secret:r}=await Jr(t,e);return r}catch(r){throw r instanceof O&&r.status===404&&xr("this HUB has no account-issued sandbox registration \u2014 issue a registration token in the dashboard (Status \u2192 SANDBOX) and re-run with it"),r}}async function Qm(t,e){if(Yt(await Io({message:"which projects should this worker serve?",options:[{value:"all",label:"all my projects (recommended \u2014 new projects included automatically)"},{value:"selected",label:"only selected projects"}],initialValue:"all"}))==="all")return[];if(e)try{let o=await Ms(t,e);if(o.length>0)return Yt(await Jm({message:"pick the projects (space to toggle, enter to confirm)",options:o.map(i=>({value:i.id,label:`${i.id} \u2014 ${i.name}`})),required:!0}));Wt.warn("your account owns no projects yet \u2014 enter the ids manually")}catch(o){Wt.warn(`could not list projects (${o instanceof Error?o.message:String(o)}) \u2014 enter the ids manually`)}return bn(await Po({message:"project ids (comma or space separated)",placeholder:"acme, beta",validate:o=>o.trim().length>0?void 0:"required"})).split(/[\s,]+/).filter(Boolean)}async function jo(t){zm("codepipe worker \u2014 set up this machine as a runner");let e=re(t.profile);e&&(Wt.warn(`already registered as ${e.sandboxId} (${e.name}) at ${e.hubUrl} \u2014 the wizard will replace this registration`),Yt(await dl({message:"re-register this worker?",initialValue:!1}))||xr("keeping the existing registration"));let r=Te(t.profile)??Te(),n=bn(await Po({message:"HUB URL",placeholder:ge,initialValue:L("HUB_URL")??r?.hubUrl??ge,validate:d=>d.trim().startsWith("http")?void 0:"must start with http(s)://"})).trim().replace(/\/$/,""),o=r!==null&&r.hubUrl.replace(/\/$/,"")===n,i=Yt(await Io({message:"how to authorize the registration?",options:[...o?[{value:"local",label:"this machine's CLI account (recommended \u2014 no token hand-off)"}]:[],{value:"login",label:"log in by email (magic-link, like codepipe init)"},{value:"paste",label:"paste a registration token from the dashboard"}],initialValue:o?"local":"login"})),s,a=null;if(i==="local")a=r.cliToken,s=await fl(n,a),Wt.success("account-issued registration token minted");else if(i==="login"){let d=await hn();a=(await yn(n,d)).cliToken,s=await fl(n,a),Wt.success("account-issued registration token minted")}else s=bn(await Xm({message:"registration token (from Status \u2192 SANDBOX)"})).trim(),s||xr("a registration token is required");let c=await Qm(n,a),l=bn(await Po({message:"worker name",initialValue:qm(),validate:d=>d.trim().length>0?void 0:"required"})).trim(),u=Yt(await Io({message:"agent backend",options:[{value:"claude-headless",label:"claude-headless \u2014 Claude Code on PATH (the real thing)"},{value:"mock",label:"mock \u2014 deterministic stub (development)"},{value:"",label:"none \u2014 this worker will not claim agent jobs"}],initialValue:"claude-headless"}));if(await ct({hub:n,token:s,name:l,projects:c,...u?{llm:u}:{},force:e!==null,...t.profile?{profile:t.profile}:{}}),Wt.message("the fingerprint above pins on the project CLI on first sight (TOFU); `codepipe up` pins it automatically"),!Yt(await dl({message:"start the claim-loop now?",initialValue:!0}))){pl("registered. start later with `codepipe worker`.");return}pl("starting the claim-loop\u2026"),await fr(t.profile?{profile:t.profile}:{})}function eg(){let t=process.argv;for(let e=0;e<t.length;e++){let r=t[e];if(r==="--profile")return t[e+1];if(r&&r.startsWith("--profile="))return r.slice(10)}return L("PROFILE")}var oe=eg();Xo(oe);ei();var de=new Zm;de.name("codepipe").description("CodePipe CLI \u2014 local client that talks to HUB and performs real-world writes").version(ce).option("--profile <id>","Profile id (project id). Picks `~/.codepipe/profiles/<id>/config.json` and `cli/profiles/<id>/.env`. Default = no profile = legacy single-project config at `~/.codepipe/config.json`.").action(async()=>{try{await ul()}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("init").description("Bootstrap a project: in an empty folder (repos clone as siblings) or in-place inside an existing git repo (origin prefilled, .codepipe/ inside). Magic-link auth; secrets to ~/.codepipe/secrets/<id>.json").option("--force","Bypass the empty-cwd guard",!1).option("--headless","Non-interactive provisioning from a JSON config (no prompts, no magic-link, no local clone) \u2014 for CLI farms").option("--config <path>","Headless config JSON path; '-' or omitted reads stdin").option("--skip-verify","Headless: skip live credential verification").action(async t=>{try{t.headless?await Dc({configPath:t.config,skipVerify:t.skipVerify===!0}):await Ic({force:t.force===!0})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("config").description("Persist HUB URL, CLI token and project id without provisioning/cloning (dev & mock flow; used by `make cli-init`)").requiredOption("--hub <url>","HUB base URL, e.g. http://localhost:3030").requiredOption("--token <token>","Personal CLI token (issued during `codepipe init`)").requiredOption("--project <id>","Project id this CLI is bound to").option("--force","Overwrite existing config",!1).action(async t=>{try{await ui({...t,profile:oe})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("clone").description("Reconstruct an existing project's workspace in the current empty folder \u2014 for continuing work on another machine").argument("<projectId>","Project id (as registered on HUB)").option("--force","Bypass the empty-cwd guard",!1).action(async(t,e)=>{try{await Pc({projectId:t,force:e.force===!0})}catch(r){console.error(r instanceof Error?r.message:r),process.exit(1)}});de.command("daemon").description("Long-running WS daemon that executes WriteActions dispatched by HUB").action(async()=>{try{await ma({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("sync").description("Clone/fetch project repos as siblings of .codepipe/ per project.yaml").option("--dry-run","Show what would happen without touching the filesystem",!1).action(async t=>{try{await bc({dryRun:t.dryRun===!0})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("login").description("Set the Claude OAuth token (sealed into job bundles)").option("--token <token>","Provide the token non-interactively").option("--shared","Save to the machine/farm-wide ~/.codepipe/shared.json instead of this project").option("--stdin","Read the token from stdin (for scripted/ssh delivery)").action(async t=>{try{await Hc({profile:oe,token:t.token,shared:t.shared,stdin:t.stdin})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});de.command("hello").description("Open WS to HUB, ping/pong, exit (smoke-test for connectivity & auth)").action(async()=>{try{await nc({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.command("up").description("Run the CLI daemon and an embedded SANDBOX worker together (solo-developer mode)").option("--name <name>","Worker name (defaults to <hostname>-up; used on first registration)").option("--llm <backend>","Worker agent backend on first registration: 'claude-headless' (default) | 'mock'").option("--projects <ids...>","Project IDs the worker may serve on first registration (empty = all your projects)").option("--reregister","Replace the worker registration when the HUB no longer knows it (it was removed)",!1).action(async t=>{try{await zc({profile:oe,...t})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});var gl=de.command("worker").description("SANDBOX worker role \u2014 claims jobs from HUB and executes agent work");gl.command("register").description("Register this machine as a SANDBOX worker with a HUB (no flags on a TTY \u2192 interactive wizard)").option("--hub <url>","HUB base URL (env CODEPIPE_HUB_URL)").option("--token <token>","Registration token (env CODEPIPE_WORKER_REG_TOKEN)").option("--name <name>","Human-readable name (env CODEPIPE_WORKER_NAME; defaults to hostname)").option("--projects <ids...>","Project IDs this worker can serve (env CODEPIPE_WORKER_PROJECTS, comma/space separated; empty = all your projects)").option("--llm <backend>","Agent backend: 'claude-headless' | 'mock' (env CODEPIPE_WORKER_LLM; omit for none)").option("--force","Overwrite existing registration",!1).action(async t=>{try{let e=t.hub??L("HUB_URL")??Te(oe)?.hubUrl??ge,r=t.token??L("WORKER_REG_TOKEN");if(!r){if(!t.hub&&!t.token&&Eo()){await jo({profile:oe});return}console.error("missing --token (or CODEPIPE_WORKER_REG_TOKEN); run `codepipe worker register` with no flags on a terminal for the wizard"),process.exit(1)}let n=L("WORKER_PROJECTS")?.split(/[\s,]+/).filter(Boolean),o=t.name??L("WORKER_NAME"),i=t.llm??L("WORKER_LLM");await ct({hub:e,token:r,projects:t.projects?.length?t.projects:n??[],force:t.force===!0,...o?{name:o}:{},...i?{llm:i}:{},...oe?{profile:oe}:{}})}catch(e){console.error(e instanceof Error?e.message:e),process.exit(1)}});gl.command("start",{isDefault:!0}).description("Connect to HUB and run the claim-loop (default subcommand)").action(async()=>{try{if(!re(oe)&&Eo()){await jo({profile:oe});return}await fr(oe?{profile:oe}:{})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});var tg=de.command("project").description("Manage CodePipe projects");tg.command("add").description("Interactive wizard to register a project with HUB and auto-provision Context Repo").action(async()=>{try{await qc({profile:oe})}catch(t){console.error(t instanceof Error?t.message:t),process.exit(1)}});de.parseAsync();
|