@rizom/ops 0.2.0-alpha.260 → 0.2.0-alpha.261
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
CHANGED
|
@@ -247,9 +247,9 @@ ${U.comment}`:U.comment}this.doc.range[2]=U.offset;break}default:this.errors.pus
|
|
|
247
247
|
`)+1;while(U!==0)this.onNewLine(this.offset+U),U=this.source.indexOf(`
|
|
248
248
|
`,U)+1}return{type:$,offset:this.offset,indent:this.indent,source:this.source}}startBlockValue($){switch(this.type){case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":return this.flowScalar(this.type);case"block-scalar-header":return{type:"block-scalar",offset:this.offset,indent:this.indent,props:[this.sourceToken],source:""};case"flow-map-start":case"flow-seq-start":return{type:"flow-collection",offset:this.offset,indent:this.indent,start:this.sourceToken,items:[],end:[]};case"seq-item-ind":return{type:"block-seq",offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken]}]};case"explicit-key-ind":{this.onKeyLine=!0;let U=CN($),J=U8(U);return J.push(this.sourceToken),{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:J,explicitKey:!0}]}}case"map-value-ind":{this.onKeyLine=!0;let U=CN($),J=U8(U);return{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:J,key:null,sep:[this.sourceToken]}]}}}return null}atIndentedComment($,U){if(this.type!=="comment")return!1;if(this.indent<=U)return!1;return $.every((J)=>J.type==="newline"||J.type==="space")}*documentEnd($){if(this.type!=="doc-mode"){if($.end)$.end.push(this.sourceToken);else $.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}*lineEnd($){switch(this.type){case"comma":case"doc-start":case"doc-end":case"flow-seq-end":case"flow-map-end":case"map-value-ind":yield*this.pop(),yield*this.step();break;case"newline":this.onKeyLine=!1;case"space":case"comment":default:if($.end)$.end.push(this.sourceToken);else $.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}}Po.Parser=s_});var IE=Z$((ko)=>{var e_=h1(),_o=O4(),H4=W4(),Eo=t5(),Co=u$(),vo=t1(),$E=s1();function UE($){let U=$.prettyErrors!==!1;return{lineCounter:$.lineCounter||U&&new vo.LineCounter||null,prettyErrors:U}}function Fo($,U={}){let{lineCounter:J,prettyErrors:G}=UE(U),I=new $E.Parser(J?.addNewLine),q=new e_.Composer(U),Q=Array.from(q.compose(I.parse($)));if(G&&J)for(let D of Q)D.errors.forEach(H4.prettifyError($,J)),D.warnings.forEach(H4.prettifyError($,J));if(Q.length>0)return Q;return Object.assign([],{empty:!0},q.streamInfo())}function JE($,U={}){let{lineCounter:J,prettyErrors:G}=UE(U),I=new $E.Parser(J?.addNewLine),q=new e_.Composer(U),Q=null;for(let D of q.compose(I.parse($),!0,$.length))if(!Q)Q=D;else if(Q.options.logLevel!=="silent"){Q.errors.push(new H4.YAMLParseError(D.range.slice(0,2),"MULTIPLE_DOCS","Source contains multiple documents; please use YAML.parseAllDocuments()"));break}if(G&&J)Q.errors.forEach(H4.prettifyError($,J)),Q.warnings.forEach(H4.prettifyError($,J));return Q}function bo($,U,J){let G=void 0;if(typeof U==="function")G=U;else if(J===void 0&&U&&typeof U==="object")J=U;let I=JE($,J);if(!I)return null;if(I.warnings.forEach((q)=>Eo.warn(I.options.logLevel,q)),I.errors.length>0)if(I.options.logLevel!=="silent")throw I.errors[0];else I.errors=[];return I.toJS(Object.assign({reviver:G},J))}function uo($,U,J){let G=null;if(typeof U==="function"||Array.isArray(U))G=U;else if(J===void 0&&U)J=U;if(typeof J==="string")J=J.length;if(typeof J==="number"){let I=Math.round(J);J=I<1?void 0:I>8?{indent:8}:{indent:I}}if($===void 0){let{keepUndefined:I}=J??U??{};if(!I)return}if(Co.isDocument($)&&!G)return $.toString(J);return new _o.Document($,G,J).toString(J)}ko.parse=bo;ko.parseAllDocuments=Fo;ko.parseDocument=JE;ko.stringify=uo});var ho,ro,lo,e1,io,gI,po,no,co,oo,OZ$,ao,to,so,FN,GE,eo,$a,Ua,Ja,Ia,Ga,qa,Qa,Da,Xa,zG,PJ,Na,bN,Ya,Oa,Wa,Va,Ra,Za,wa,Ha,Ma,ga,M4,Ta,za,Aa;var $H=O$(()=>{ho=h1(),ro=O4(),lo=L1(),e1=W4(),io=t6(),gI=u$(),po=RI(),no=JU(),co=wI(),oo=HI(),OZ$=_N(),ao=a1(),to=t1(),so=s1(),FN=IE(),GE=o6();eo=ho.Composer,$a=ro.Document,Ua=lo.Schema,Ja=e1.YAMLError,Ia=e1.YAMLParseError,Ga=e1.YAMLWarning,qa=io.Alias,Qa=gI.isAlias,Da=gI.isCollection,Xa=gI.isDocument,zG=gI.isMap,PJ=gI.isNode,Na=gI.isPair,bN=gI.isScalar,Ya=gI.isSeq,Oa=po.Pair,Wa=no.Scalar,Va=co.YAMLMap,Ra=oo.YAMLSeq,Za=ao.Lexer,wa=to.LineCounter,Ha=so.Parser,Ma=FN.parse,ga=FN.parseAllDocuments,M4=FN.parseDocument,Ta=FN.stringify,za=GE.visit,Aa=GE.visitAsync});function XE($){if($==="core")return{bundles:["core"]};if($==="default")return{bundles:["core","site","publishing"],add:["obsidian-vault"],remove:[...La]};return{bundles:["core","site","publishing"],add:["obsidian-vault"]}}function Sa($){let U=ja.parse($);return Dq.parse({brainVersion:U.brainVersion,...XE(U.preset),githubOrg:U.githubOrg,contentRepoPrefix:U.contentRepoPrefix,domainSuffix:U.domainSuffix,aiApiKey:U.aiApiKey,gitSyncToken:U.gitSyncToken,contentRepoAdminToken:U.contentRepoAdminToken,agePublicKey:U.agePublicKey})}function Pa($){let U=Ka.parse($),J=U.presetOverride?XE(U.presetOverride):void 0;return hJ.parse({members:[...U.members],...U.brainVersionOverride?{brainVersionOverride:U.brainVersionOverride}:{},...J?{bundlesOverride:J.bundles,...J.add?{addOverride:J.add}:{},...J.remove?{removeOverride:J.remove}:{}}:{},...U.aiApiKeyOverride?{aiApiKeyOverride:U.aiApiKeyOverride}:{},...U.gitSyncTokenOverride?{gitSyncTokenOverride:U.gitSyncTokenOverride}:{}})}function NE($){let U=M4($,{keepSourceTokens:!0});if(U.errors.length>0)throw Error(`Invalid desired-state YAML: ${U.errors[0]?.message}`);if(!zG(U.contents))throw Error("Desired-state YAML must contain a mapping");return U}function UH($,U){if(!zG($.contents))return;return $.contents.items.find((J)=>bN(J.key)&&J.key.value===U)}function qE($,U){if(!PJ($)||!PJ(U))return;if($.commentBefore!==void 0)U.commentBefore=$.commentBefore;if($.comment!==void 0)U.comment=$.comment;if($.spaceBefore!==void 0)U.spaceBefore=$.spaceBefore}function QE($,U){if(!$||!PJ(U))return;let J=[PJ($.key)?$.key.commentBefore:void 0,PJ($.key)?$.key.comment:void 0,PJ($.value)?$.value.commentBefore:void 0,PJ($.value)?$.value.comment:void 0].filter((G)=>G!==void 0);if(J.length===0)return;U.commentBefore=[U.commentBefore,...J].filter((G)=>G!==void 0).join(`
|
|
249
249
|
`)}function YE($,U,J,G){if(!zG($.contents))throw Error("Desired-state YAML must contain a mapping");let I=$.contents.items.findIndex((Q)=>bN(Q.key)&&Q.key.value===U),q=$.createPair(J,[...G]);if(I>=0){let Q=$.contents.items[I];qE(Q?.key,q.key),qE(Q?.value,q.value),$.contents.items.splice(I,1,q)}else $.contents.add(q);return q}function OE($){let U=NE($),J=Sa(U.toJS()),G=UH(U,"schemaVersion"),I=UH(U,"model");QE(G,UH(U,"brainVersion")?.key),U.delete("schemaVersion");let q=YE(U,"preset","bundles",J.bundles);if(QE(I,q.key),U.delete("model"),J.add)U.set("add",J.add);else U.delete("add");if(J.remove)U.set("remove",J.remove);else U.delete("remove");return Dq.parse(U.toJS()),U.toString({lineWidth:0})}function WE($){let U=NE($),J=Pa(U.toJS());if(J.bundlesOverride)YE(U,"presetOverride","bundlesOverride",J.bundlesOverride);else U.delete("presetOverride"),U.delete("bundlesOverride");if(J.addOverride)U.set("addOverride",J.addOverride);else U.delete("addOverride");if(J.removeOverride)U.set("removeOverride",J.removeOverride);else U.delete("removeOverride");return hJ.parse(U.toJS()),U.toString({lineWidth:0})}var DE,g4,ja,Ka,La;var VE=O$(()=>{zI();k$();$H();Xq();DE=Z.enum(["core","default","pro"]),g4=Z.string().min(1),ja=Z.strictObject({schemaVersion:Z.literal(1),brainVersion:r0,model:Z.literal("rover"),githubOrg:Z.string().min(1),contentRepoPrefix:Z.string().min(1),domainSuffix:Z.string().min(1),preset:DE,aiApiKey:g4,gitSyncToken:g4,contentRepoAdminToken:g4,agePublicKey:Z.string().startsWith("age1").min(1)}),Ka=Z.strictObject({members:Z.array(l0).min(1),brainVersionOverride:r0.optional(),presetOverride:DE.optional(),aiApiKeyOverride:g4.optional(),gitSyncTokenOverride:g4.optional()}).superRefine(($,U)=>{if(new Set($.members).size!==$.members.length)U.addIssue({code:Z.ZodIssueCode.custom,path:["members"],message:"cohort members must be unique"})}),La=["series","portfolio","content-pipeline","social-media","newsletter","stock-photo"]});var ME={};J0(ME,{stageLegacyCrossover:()=>xa,parseReviewedSitePins:()=>HE,loadReviewedSitePins:()=>ua});import{access as Ba,cp as _a,mkdir as RE,readFile as T4,readdir as wE,writeFile as J8}from"fs/promises";import{basename as Ea,join as UJ,relative as uN,resolve as ZE}from"path";import{fileURLToPath as Ca}from"url";function HE($){let U=_G($,va);if(!U.ok)throw Error(`Invalid reviewed site pins: ${U.error}`);return U.data.sites}async function ua($){return HE(await T4($,"utf8"))}async function ka($,U){let J=UJ($,"users"),G=(await wE(J,{withFileTypes:!0})).filter((Q)=>Q.isFile()&&/\.ya?ml$/.test(Q.name)).map((Q)=>Q.name).sort(),I=new Set(Object.keys(U??{})),q=[];for(let Q of G){let D=UJ(J,Q),X=await T4(D,"utf8"),N=M4(X,{keepSourceTokens:!0});if(N.errors.length>0||!zG(N.contents))throw Error(`Invalid user desired-state YAML: ${Q}`);let Y=Fa.parse(N.toJS());if(!Y.siteOverride)continue;let O=U?.[Y.handle];if(!O)throw Error(`User ${Y.handle} has a siteOverride but no reviewed site pin`);if(I.delete(Y.handle),O.package!==Y.siteOverride.package||O.theme!==Y.siteOverride.theme)throw Error(`Reviewed site pin identity does not match user ${Y.handle}`);if(Y.siteOverride.version!==void 0&&Y.siteOverride.version!==O.version)throw Error(`Reviewed site version does not match the existing pin for user ${Y.handle}`);if(Y.siteOverride.themeVersion!==void 0&&Y.siteOverride.themeVersion!==O.themeVersion)throw Error(`Reviewed theme version does not match the existing pin for user ${Y.handle}`);if(N.setIn(["siteOverride","version"],O.version),O.themeVersion!==void 0)N.setIn(["siteOverride","themeVersion"],O.themeVersion);else N.deleteIn(["siteOverride","themeVersion"]);OD.parse(N.toJS());let V=N.toString({lineWidth:0});if(V!==X)await J8(D,V),q.push(uN($,D))}if(I.size>0)throw Error(`Reviewed site pins do not match site users: ${[...I].sort().join(", ")}`);return q}async function xa($,U,J={}){let G=ZE($),I=ZE(U);if(G===I||I.startsWith(`${G}/`))throw Error("Crossover output must be outside the source repository");await _a(G,I,{recursive:!0,errorOnExist:!0,force:!1,filter:(R)=>{let H=Ea(R);return H!==".git"&&H!==".operator"&&H!==".brains-ops"&&H!==".turbo"&&H!=="dist"&&H!=="node_modules"&&H!==".env"&&H!==".env.local"&&!H.endsWith(".secrets.yaml")}});let q=[],Q=UJ(I,"docs","canonical-crossover-record.md");try{await Ba(Q)}catch{await RE(UJ(I,"docs"),{recursive:!0}),await J8(Q,await T4(ba,"utf8")),q.push("docs/canonical-crossover-record.md")}let D=UJ(I,"pilot.yaml"),X=await T4(D,"utf8");await J8(D,OE(X)),q.push("pilot.yaml");let N=UJ(I,"cohorts"),Y=(await wE(N,{withFileTypes:!0})).filter((R)=>R.isFile()&&/\.ya?ml$/.test(R.name)).map((R)=>R.name).sort();for(let R of Y){let H=UJ(N,R),w=await T4(H,"utf8");await J8(H,WE(w)),q.push(uN(I,H))}q.push(...await ka(I,J.sitePins));let O=await VU(I),V=rD(O.pilot.githubOrg);for(let R of O.users){let H=await V(R),w=UJ(I,"users",R.handle);if(await RE(w,{recursive:!0}),H.brainYaml){let M=UJ(w,"brain.yaml");await J8(M,H.brainYaml),q.push(uN(I,M))}if(H.envFile){let M=UJ(w,".env");await J8(M,H.envFile),q.push(uN(I,M))}}return await uI(I,{registry:O}),q.push("views/users.md"),{outputDir:I,changedFiles:[...new Set(q)].sort()}}var va,Fa,ba;var gE=O$(()=>{zI();k$();$H();k7();VE();QJ();s8();Xq();va=Z.strictObject({sites:Z.record(l0,PZ)}),Fa=Z.object({handle:l0,siteOverride:Z.object({package:Z.string().min(1),version:r0.optional(),theme:Z.string().min(1).optional(),themeVersion:r0.optional()}).optional()}).passthrough(),ba=Ca(new URL("../templates/rover-pilot/docs/canonical-crossover-record.md",import.meta.url))});function OU($,U,J,G,I){return zE.parse({id:$,operation:U,count:J,targetProbeCount:G,settleMs:I})}function GH($){return IH.parse(structuredClone(fa[$]))}function xN($){let U=`stress:${$.handle}`;if($.confirmation!==U)throw Error(`Directory-sync stress requires --confirm ${U}`);let J=/(^|[-_.])smoke($|[-_.])/i;if(!J.test($.handle)||!J.test($.domain)||!J.test($.contentRepo))throw Error("Directory-sync stress is smoke-only; handle, domain, and content repository must all identify smoke")}async function mN($,U={}){let J=U.fetchImpl??fetch,G=U.now??(()=>new Date),I=U.timeoutMs??20000,q=G(),Q=new AbortController,D=setTimeout(()=>Q.abort(),I);try{let X=await J($,{method:"GET",signal:Q.signal});return await X.arrayBuffer(),JH.parse({timestamp:q.toISOString(),endpoint:new URL($).pathname,status:X.status,durationMs:Math.max(0,G().getTime()-q.getTime()),ok:X.ok})}catch(X){return JH.parse({timestamp:q.toISOString(),endpoint:new URL($).pathname,status:0,durationMs:Math.max(0,G().getTime()-q.getTime()),ok:!1,error:ha(X)})}finally{clearTimeout(D)}}async function qH($,U){let J=IH.parse($),G=[],I,q=await U.prepare(J),Q,D;try{try{await U.startMonitoring()}catch(X){I=`monitor: ${kN(X)}`}if(!I)for(let X of J.phases)try{let N=AE.parse(await U.executePhase(X,q));if(G.push(N),!N.success){I=`${X.id}: ${N.error??"phase failed"}`;break}}catch(N){let Y=kN(N);G.push({id:X.id,operation:X.operation,count:X.count,success:!1,error:Y}),I=`${X.id}: ${Y}`;break}}finally{try{if(Q=jE.parse(await U.cleanup(q)),!Q.success&&!I)I=Q.error??"cleanup failed"}catch(X){let N=kN(X);Q={success:!1,probesRemaining:0,error:N},I??=`cleanup: ${N}`}try{D=KE.parse(await U.stopMonitoring())}catch(X){let N=kN(X);D={health:[],runtime:[]},I??=`monitor: ${N}`}}return I??=SE(D),LE.parse({profile:J.profile,success:I===void 0&&G.length===J.phases.length&&Q.success,baseline:q,phases:G,cleanup:Q,metrics:D,...I?{failure:I}:{}})}function SE($){let U=$.health.find((G)=>!G.ok);if(U)return`health: ${U.endpoint} unavailable`;if($.container?.oomKilled)return"container: OOM killed";let J=$.container?.restartCount??0;if(J>0)return`container: restarted ${J} time(s)`;if($.container&&$.container.status!=="running")return`container: ${$.container.status}`;return}function ha($){if($ instanceof Error)return`${$.name}: ${$.message}`;return String($)}function kN($){return $U($)}var z4,TE,zE,IH,ma,JH,ya,AE,jE,KE,LE,fa;var QH=O$(()=>{k$();z4=Z.enum(["regression","load","stress"]),TE=Z.enum(["add","update","rename","delete"]),zE=Z.object({id:Z.string().min(1),operation:TE,count:Z.number().int().positive().max(700),targetProbeCount:Z.number().int().min(0).max(700),settleMs:Z.number().int().nonnegative().max(300000)}),IH=Z.object({profile:z4,maximumProbeCount:Z.number().int().positive().max(700),phases:Z.array(zE).min(1)}),ma=Z.object({entities:Z.number().int().nonnegative(),notes:Z.number().int().nonnegative(),version:Z.string().min(1)}),JH=Z.object({timestamp:Z.iso.datetime(),endpoint:Z.string().startsWith("/"),status:Z.number().int().nonnegative(),durationMs:Z.number().nonnegative(),ok:Z.boolean(),error:Z.string().optional()}),ya=Z.object({timestamp:Z.iso.datetime(),cpuPercent:Z.number().nonnegative(),memoryPercent:Z.number().nonnegative(),pids:Z.number().int().nonnegative()}),AE=Z.object({id:Z.string().min(1),operation:TE,count:Z.number().int().positive(),success:Z.boolean(),commitLatencyMs:Z.number().nonnegative().optional(),persistenceLatencyMs:Z.number().nonnegative().optional(),error:Z.string().optional()}),jE=Z.object({success:Z.boolean(),probesRemaining:Z.number().int().nonnegative(),finalEntities:Z.number().int().nonnegative().optional(),finalNotes:Z.number().int().nonnegative().optional(),contentTreeRestored:Z.boolean().optional(),error:Z.string().optional()}),KE=Z.object({health:Z.array(JH),runtime:Z.array(ya),container:Z.object({status:Z.string(),restartCount:Z.number().int().nonnegative(),oomKilled:Z.boolean()}).optional()}),LE=Z.object({profile:z4,success:Z.boolean(),baseline:ma,phases:Z.array(AE),cleanup:jE,metrics:KE,failure:Z.string().optional()}),fa={regression:{profile:"regression",maximumProbeCount:20,phases:[OU("add20","add",20,20,0),OU("update20","update",20,20,30000),OU("delete20","delete",20,0,150000)]},load:{profile:"load",maximumProbeCount:350,phases:[OU("add50","add",50,50,0),OU("add150","add",100,150,0),OU("add350","add",200,350,0),OU("update350a","update",350,350,45000),OU("rename100","rename",100,350,45000),OU("update350b","update",350,350,45000),OU("delete350","delete",350,0,150000)]},stress:{profile:"stress",maximumProbeCount:700,phases:[OU("add50","add",50,50,0),OU("add150","add",100,150,0),OU("add350","add",200,350,0),OU("add700","add",350,700,0),OU("update700a","update",700,700,45000),OU("rename200","rename",200,700,45000),OU("update700b","update",700,700,45000),OU("delete700","delete",700,0,150000)]}}});var WH={};J0(WH,{runStressCommand:()=>OH,runDeployedDirectorySyncStress:()=>FE,removeProbeFiles:()=>YH,parseStressRuntimeSample:()=>mE,listProbeFiles:()=>AG,cleanupDirectorySyncStress:()=>bE,applyDirectorySyncStressPhase:()=>xE});import{spawn as ra}from"child_process";import{chmod as la,mkdir as _E,mkdtemp as EE,readFile as ia,readdir as pa,rename as da,rm as fN,writeFile as JJ}from"fs/promises";import{tmpdir as CE}from"os";import{join as IU,resolve as vE}from"path";async function FE($){let U=$.now??(()=>new Date),J=U().toISOString(),G=fE(J),I=vE($.artifactsDir??IU($.rootDir,".brains-ops","stress",G));await _E(I,{recursive:!0});let{pilot:q,user:Q}=await kE($.rootDir,$.handle);xN({handle:Q.handle,domain:Q.domain,contentRepo:Q.contentRepo,confirmation:$.confirmation});let D=na.parse($.env??process.env),X=z4.parse($.profile),N=new uE({runId:G,artifactsDir:I,user:Q,githubOrg:q.githubOrg,serverLabel:`${q.contentRepoPrefix}${Q.handle}`,environment:D,fetchImpl:$.fetchImpl??fetch,commandRunner:$.commandRunner??OH,logger:$.logger??console.info,now:U,sleep:$.sleep??Bun.sleep}),Y;try{Y=await qH(GH(X),N)}finally{await N.dispose()}let O={runId:G,artifactsDir:I,target:{handle:Q.handle,domain:Q.domain,contentRepo:`${q.githubOrg}/${Q.contentRepo}`},startedAt:J,completedAt:U().toISOString(),report:Y};return await $t(O),O}async function bE($){let U=$.now??(()=>new Date),J=vE($.artifactsDir??IU($.rootDir,".brains-ops","stress",`cleanup-${fE(U().toISOString())}`));await _E(J,{recursive:!0});let{pilot:G,user:I}=await kE($.rootDir,$.handle);xN({handle:I.handle,domain:I.domain,contentRepo:I.contentRepo,confirmation:$.confirmation});let q=($.env??process.env).CONTENT_REPO_ADMIN_TOKEN;if(!q)throw Error("Missing CONTENT_REPO_ADMIN_TOKEN");let Q=$.commandRunner??OH,D=$.logger??console.info,X=await EE(IU(CE(),"brains-ops-directory-sync-cleanup-")),N=IU(X,"content");try{await yE(Q,`${G.githubOrg}/${I.contentRepo}`,N,q);let Y=await YH(N),O;if(Y>0)await BJ(Q,"git",["add","-A"],{cwd:N,env:k0(q)}),await BJ(Q,"git",["-c","user.name=brains-ops","-c","user.email=ops@rizom.ai","commit","-m","test(directory-sync): clean residual stress probes"],{cwd:N,env:k0(q)}),await XH(Q,N,q),O=await sa(Q,N,q,["rev-parse","HEAD"]),D(`Removed ${Y} directory-sync stress probes`);let V=(await AG(N)).length,R=V===0?await ta(Q,N,q):[],H={success:V===0,artifactsDir:J,probesRemoved:Y,probesRemaining:V,backupBranchesDeleted:R,...O?{cleanupCommit:O}:{}};return await JJ(IU(J,"cleanup.json"),`${JSON.stringify(H,null,2)}
|
|
250
|
-
`),H}finally{await fN(X,{recursive:!0,force:!0})}}class uE{#$;#J=[];#A=[];#j=new Set(["/health"]);#q;#U;#X;#Y;#O;#I;#Q;#R;#Z;#D=!0;#w;#W;#H="";#K=0;#M;constructor($){this.#$=$}async prepare($){this.#q=await EE(IU(CE(),"brains-ops-directory-sync-stress-")),this.#U=IU(this.#q,"content"),this.#X=IU(this.#q,"id_ed25519"),this.#Y=IU(this.#q,"known_hosts"),this.#O=await this.#B(),await JJ(this.#X,ea(this.#$.environment.KAMAL_SSH_PRIVATE_KEY),{mode:384}),await la(this.#X,384);let U=await this.#z("ssh-keyscan",["-T","10","-t","ed25519",this.#O]);if(U.exitCode!==0||!U.stdout.trim())throw Error("Unable to resolve smoke SSH host key");await JJ(this.#Y,U.stdout,{mode:384});let J=await this.#N(["docker","ps","--filter","label=service=rover","--filter","label=role=web","--format","{{.Names}}"]);if(this.#I=J.stdout.trim().split(/\r?\n/)[0],!this.#I||!/^[A-Za-z0-9_.-]+$/.test(this.#I))throw Error("Unable to resolve a running smoke container");if(await yE(this.#$.commandRunner,`${this.#$.githubOrg}/${this.#$.user.contentRepo}`,this.#U,this.#$.environment.CONTENT_REPO_ADMIN_TOKEN),(await AG(this.#U)).length>0)throw Error("Directory-sync stress probes already exist");let G=await this.#V(["rev-parse","HEAD"]);this.#R=await this.#V(["rev-parse","HEAD^{tree}"]),this.#Z=await this.#L();let I=await this.#F(60000);if(!I)throw Error("Smoke health was unavailable before stress testing");return this.#Q=`ops/directory-sync-stress-backup-${this.#$.runId}`,await this.#G(["push","origin",`HEAD:refs/heads/${this.#Q}`]),await this.#_(),await JJ(IU(this.#$.artifactsDir,"state.json"),`${JSON.stringify({runId:this.#$.runId,profile:$.profile,originalHead:G,originalTree:this.#R,backupBranch:this.#Q,baseline:{entities:I.entities,notes:A4(I),version:I.version}},null,2)}
|
|
250
|
+
`),H}finally{await fN(X,{recursive:!0,force:!0})}}class uE{#$;#J=[];#A=[];#j=new Set(["/health/ready"]);#q;#U;#X;#Y;#O;#I;#Q;#R;#Z;#D=!0;#w;#W;#H="";#K=0;#M;constructor($){this.#$=$}async prepare($){this.#q=await EE(IU(CE(),"brains-ops-directory-sync-stress-")),this.#U=IU(this.#q,"content"),this.#X=IU(this.#q,"id_ed25519"),this.#Y=IU(this.#q,"known_hosts"),this.#O=await this.#B(),await JJ(this.#X,ea(this.#$.environment.KAMAL_SSH_PRIVATE_KEY),{mode:384}),await la(this.#X,384);let U=await this.#z("ssh-keyscan",["-T","10","-t","ed25519",this.#O]);if(U.exitCode!==0||!U.stdout.trim())throw Error("Unable to resolve smoke SSH host key");await JJ(this.#Y,U.stdout,{mode:384});let J=await this.#N(["docker","ps","--filter","label=service=rover","--filter","label=role=web","--format","{{.Names}}"]);if(this.#I=J.stdout.trim().split(/\r?\n/)[0],!this.#I||!/^[A-Za-z0-9_.-]+$/.test(this.#I))throw Error("Unable to resolve a running smoke container");if(await yE(this.#$.commandRunner,`${this.#$.githubOrg}/${this.#$.user.contentRepo}`,this.#U,this.#$.environment.CONTENT_REPO_ADMIN_TOKEN),(await AG(this.#U)).length>0)throw Error("Directory-sync stress probes already exist");let G=await this.#V(["rev-parse","HEAD"]);this.#R=await this.#V(["rev-parse","HEAD^{tree}"]),this.#Z=await this.#L();let I=await this.#F(60000);if(!I)throw Error("Smoke health was unavailable before stress testing");return this.#Q=`ops/directory-sync-stress-backup-${this.#$.runId}`,await this.#G(["push","origin",`HEAD:refs/heads/${this.#Q}`]),await this.#_(),await JJ(IU(this.#$.artifactsDir,"state.json"),`${JSON.stringify({runId:this.#$.runId,profile:$.profile,originalHead:G,originalTree:this.#R,backupBranch:this.#Q,baseline:{entities:I.entities,notes:A4(I),version:I.version}},null,2)}
|
|
251
251
|
`),this.#$.logger(`Prepared ${$.profile} directory-sync stress run for ${this.#$.user.handle}`),{entities:I.entities,notes:A4(I),version:I.version}}async startMonitoring(){this.#P(),this.#D=!1,this.#W=void 0,this.#K=this.#J.length,this.#M=void 0,this.#H=this.#$.now().toISOString(),this.#w=Promise.all([this.#E(),this.#C()]).then(()=>{return}).catch(($)=>{this.#W=$,this.#D=!0})}async executePhase($,U){this.#P();let J=this.#U;if(!J)throw Error("Directory-sync stress checkout is not prepared");await this.#T();let G=this.#J.length,I=this.#$.now().getTime();await xE(J,$),await this.#G(["add","-A"]),await this.#G(["-c","user.name=brains-ops","-c","user.email=ops@rizom.ai","commit","-m",`test(directory-sync): stress ${$.id}`]),await XH(this.#$.commandRunner,J,this.#$.environment.CONTENT_REPO_ADMIN_TOKEN);let q=this.#$.now().getTime(),Q=await this.#V(["rev-parse","HEAD"]),D=await this.#v(Q,900000);if(D===void 0)return yN($,"runtime did not pull the phase commit");let X;if($.operation==="rename"){let Y=U.notes+$.targetProbeCount;if($.settleMs>0)await this.#$.sleep($.settleMs);let O=await this.#b(Y,void 0,1200000);if(X=this.#$.now().getTime()-q,!O)return yN($,`health did not stabilize at ${Y} notes`,D,X)}else if($.operation==="add"||$.operation==="delete"){let Y=U.notes+$.targetProbeCount,O=this.#$.now().getTime(),V=await this.#g(Y,void 0,1200000);if(X=this.#$.now().getTime()-O,!V)return yN($,`health did not reach ${Y} notes`,D,X)}if($.operation!=="rename"&&$.settleMs>0)await this.#$.sleep($.settleMs);let N=this.#J.slice(G).find((Y)=>!Y.ok);if(N)return yN($,`${N.endpoint} unavailable (${N.status===0?N.error??"unknown":N.status})`,D,X);return this.#$.logger(`Completed ${$.id} in ${this.#$.now().getTime()-I}ms`),{id:$.id,operation:$.operation,count:$.count,success:!0,commitLatencyMs:D,...X===void 0?{}:{persistenceLatencyMs:X}}}async cleanup($){if(!this.#U)return{success:!1,probesRemaining:0,error:"stress checkout was not prepared"};try{if(await this.#T(!0),await YH(this.#U)>0)await this.#G(["add","-A"]),await this.#G(["-c","user.name=brains-ops","-c","user.email=ops@rizom.ai","commit","-m","test(directory-sync): remove stress probes"]),await XH(this.#$.commandRunner,this.#U,this.#$.environment.CONTENT_REPO_ADMIN_TOKEN);let J=(await AG(this.#U)).length;this.#M=this.#J.length;let G=await this.#g($.notes,$.entities,1200000);await this.#T(!0);let q=await this.#V(["rev-parse","HEAD^{tree}"])===this.#R,Q=J===0&&G!==void 0&&q;if(Q&&this.#Q){if((await this.#G(["push","origin","--delete",this.#Q],!1)).exitCode!==0)this.#$.logger(`Warning: unable to delete backup branch ${this.#Q}`)}return{success:Q,probesRemaining:J,...G?{finalEntities:G.entities,finalNotes:A4(G)}:{},contentTreeRestored:q,...!Q?{error:!G?"entity baseline was not restored before cleanup timeout":!q?"content tree differs from the pre-stress baseline":"stress probes remain after cleanup"}:{}}}catch(U){return{success:!1,probesRemaining:(await AG(this.#U)).length,error:$U(U)}}}async stopMonitoring(){if(this.#D=!0,await this.#w,await JJ(IU(this.#$.artifactsDir,"health-samples.json"),`${JSON.stringify(this.#J,null,2)}
|
|
252
|
-
`),this.#I&&this.#H){let G=await this.#N(["docker","logs","--since",this.#H,this.#I],!1);await JJ(IU(this.#$.artifactsDir,"runtime.log"),`${G.stdout}${G.stderr}`)}let $=await this.#L(),U=this.#M??this.#J.length,J={health:this.#J.slice(this.#K,U),runtime:this.#A,...$?{container:$}:{}};if(this.#W)throw this.#W;return J}async dispose(){if(this.#D=!0,await this.#w,this.#q)await fN(this.#q,{recursive:!0,force:!0})}async#L(){if(!this.#I)return;let $=await this.#N(["docker","inspect",this.#I],!1);if($.exitCode!==0)return;try{let J=Z.array(Z.object({RestartCount:Z.number().int().nonnegative(),State:Z.object({Status:Z.string(),OOMKilled:Z.boolean()})})).parse(JSON.parse($.stdout))[0];if(!J)return;return{status:J.State.Status,restartCount:Math.max(0,J.RestartCount-(this.#Z?.restartCount??0)),oomKilled:J.State.OOMKilled&&!(this.#Z?.oomKilled??!1)}}catch{return}}async#B(){let $=encodeURIComponent(`brain=${this.#$.serverLabel}`),U=await this.#$.fetchImpl(`https://api.hetzner.cloud/v1/servers?label_selector=${$}`,{headers:{Authorization:`Bearer ${this.#$.environment.HCLOUD_TOKEN}`}});if(!U.ok)throw Error(`Hetzner server lookup failed with ${U.status}`);let G=ca.parse(await U.json()).servers[0];if(G?.status!=="running")throw Error("Smoke server is not running");return G.public_net.ipv4.ip}async#_(){for(let $ of["/health/live","/health/
|
|
252
|
+
`),this.#I&&this.#H){let G=await this.#N(["docker","logs","--since",this.#H,this.#I],!1);await JJ(IU(this.#$.artifactsDir,"runtime.log"),`${G.stdout}${G.stderr}`)}let $=await this.#L(),U=this.#M??this.#J.length,J={health:this.#J.slice(this.#K,U),runtime:this.#A,...$?{container:$}:{}};if(this.#W)throw this.#W;return J}async dispose(){if(this.#D=!0,await this.#w,this.#q)await fN(this.#q,{recursive:!0,force:!0})}async#L(){if(!this.#I)return;let $=await this.#N(["docker","inspect",this.#I],!1);if($.exitCode!==0)return;try{let J=Z.array(Z.object({RestartCount:Z.number().int().nonnegative(),State:Z.object({Status:Z.string(),OOMKilled:Z.boolean()})})).parse(JSON.parse($.stdout))[0];if(!J)return;return{status:J.State.Status,restartCount:Math.max(0,J.RestartCount-(this.#Z?.restartCount??0)),oomKilled:J.State.OOMKilled&&!(this.#Z?.oomKilled??!1)}}catch{return}}async#B(){let $=encodeURIComponent(`brain=${this.#$.serverLabel}`),U=await this.#$.fetchImpl(`https://api.hetzner.cloud/v1/servers?label_selector=${$}`,{headers:{Authorization:`Bearer ${this.#$.environment.HCLOUD_TOKEN}`}});if(!U.ok)throw Error(`Hetzner server lookup failed with ${U.status}`);let G=ca.parse(await U.json()).servers[0];if(G?.status!=="running")throw Error("Smoke server is not running");return G.public_net.ipv4.ip}async#_(){for(let $ of["/health/live","/health/operate"])if((await mN(`https://${this.#$.user.domain}${$}`,{fetchImpl:this.#$.fetchImpl,now:this.#$.now,timeoutMs:5000})).status!==404)this.#j.add($)}async#E(){while(!this.#D){for(let $ of this.#j)this.#J.push(await mN(`https://${this.#$.user.domain}${$}`,{fetchImpl:this.#$.fetchImpl,now:this.#$.now,timeoutMs:20000}));await this.#$.sleep(4000)}}async#C(){let $=this.#I;if(!$)throw Error("Directory-sync stress container is not prepared");while(!this.#D){let U=await this.#N(["timeout","15","docker","stats","--no-stream","--format","{{.CPUPerc}},{{.MemPerc}},{{.PIDs}}",$],!1),J=mE(U.stdout.trim(),this.#$.now().toISOString());if(J)this.#A.push(J);await this.#$.sleep(1000)}}async#v($,U){let J=this.#I;if(!J)throw Error("Directory-sync stress container is not prepared");let G=this.#$.now().getTime();while(this.#$.now().getTime()-G<U){if((await this.#N(["docker","exec",J,"git","-C","/app/brain-data","merge-base","--is-ancestor",$,"HEAD"],!1)).exitCode===0)return this.#$.now().getTime()-G;await this.#$.sleep(5000)}return}async#F($){return this.#g(void 0,void 0,$)}async#g($,U,J){let G=this.#$.now().getTime();while(this.#$.now().getTime()-G<J){let I=await this.#S();if(I&&($===void 0||A4(I)===$)&&(U===void 0||I.entities===U))return I;await this.#$.sleep(5000)}return}async#b($,U,J){let G=this.#$.now().getTime(),I=0;while(this.#$.now().getTime()-G<J){let q=await this.#S();if(q!==void 0&&($===void 0||A4(q)===$)&&(U===void 0||q.entities===U)){if(I+=1,I===2)return q}else I=0;await this.#$.sleep(5000)}return}async#S(){let $=this.#$.now(),U=new AbortController,J=setTimeout(()=>U.abort(),20000);try{let G=await this.#$.fetchImpl(`https://${this.#$.user.domain}/health/operate`,{signal:U.signal}),I=await G.text();if(this.#J.push({timestamp:$.toISOString(),endpoint:"/health/operate",status:G.status,durationMs:Math.max(0,this.#$.now().getTime()-$.getTime()),ok:G.ok}),!G.ok)return;return oa.parse(JSON.parse(I)).app}catch(G){this.#J.push({timestamp:$.toISOString(),endpoint:"/health/operate",status:0,durationMs:Math.max(0,this.#$.now().getTime()-$.getTime()),ok:!1,error:G instanceof Error?`${G.name}: ${G.message}`:String(G)});return}finally{clearTimeout(J)}}async#T($=!1){if(await this.#G(["fetch","origin","main"]),$)await this.#G(["reset","--hard","origin/main"]);else await this.#G(["pull","--rebase","origin","main"])}async#G($,U=!0){let J=this.#U;if(!J)throw Error("Directory-sync stress checkout is not prepared");let G=await this.#z("git",$,{cwd:J,env:k0(this.#$.environment.CONTENT_REPO_ADMIN_TOKEN)});if(U&&G.exitCode!==0)throw NH("git",$,G);return G}async#V($){return(await this.#G($)).stdout.trim()}async#N($,U=!0){let J=this.#X,G=this.#Y,I=this.#O;if(!J||!G||!I)throw Error("Directory-sync stress SSH access is not prepared");let q=await this.#z("ssh",["-i",J,"-o","BatchMode=yes","-o","IdentitiesOnly=yes","-o","ConnectTimeout=10","-o","StrictHostKeyChecking=yes","-o",`UserKnownHostsFile=${G}`,`root@${I}`,...$]);if(U&&q.exitCode!==0)throw NH("ssh",$,q);return q}async#z($,U,J){return this.#$.commandRunner($,U,J)}#P(){if(!this.#U||!this.#X||!this.#Y||!this.#O||!this.#I)throw Error("Directory-sync stress driver is not prepared")}}async function kE($,U){let J=await VU($),G=J.users.find((I)=>I.handle===U);if(!G)throw Error(`Unknown pilot user: ${U}`);return{pilot:J.pilot,user:G}}async function xE($,U){let J=await AG($);switch(U.operation){case"add":{let G=U.targetProbeCount-J.length;if(G!==U.count)throw Error(`${U.id} expected to add ${U.count} probes from ${J.length}`);let I=J.map(aa).filter((Q)=>Q!==void 0),q=I.length===0?1:Math.max(...I)+1;for(let Q=q;Q<q+G;Q+=1){let D=String(Q).padStart(3,"0");await JJ(IU($,`directory-sync-stress-${D}.md`),["---",`title: "Directory Sync Stress ${D}"`,"---","",`Deterministic directory-sync stress probe ${D}.`,"Payload: abcdefghijklmnopqrstuvwxyz-0123456789-abcdefghijklmnopqrstuvwxyz.",""].join(`
|
|
253
253
|
`))}break}case"update":{if(J.length!==U.count)throw Error(`${U.id} expected ${U.count} probes, found ${J.length}`);for(let G of J){let I=IU($,G),q=await ia(I,"utf8");await JJ(I,`${q.trimEnd()}
|
|
254
254
|
|
|
255
255
|
Update marker: ${U.id}.
|
|
@@ -259,7 +259,7 @@ Update marker: ${U.id}.
|
|
|
259
259
|
`}function fE($){return $.replace(/[-:.TZ]/g,"").slice(0,14)}async function $t($){await JJ(IU($.artifactsDir,"report.json"),`${JSON.stringify($,null,2)}
|
|
260
260
|
`),await JJ(IU($.artifactsDir,"report.md"),Ut($))}function Ut($){let U=$.report.metrics.runtime,J=$.report.metrics.health,G=U.map((D)=>D.cpuPercent).sort((D,X)=>D-X),I=U.map((D)=>D.memoryPercent),q=J.filter((D)=>!D.ok),Q=["# Directory-sync stress report","",`- Run: \`${$.runId}\``,`- Target: \`${$.target.handle}\` (${$.target.domain})`,`- Profile: \`${$.report.profile}\``,`- Version: \`${$.report.baseline.version}\``,`- Result: **${$.report.success?"PASS":"FAIL"}**`,`- Started: ${$.startedAt}`,`- Completed: ${$.completedAt}`,"","## Phases","","| Phase | Operation | Count | Result | Pull latency | Persistence latency |","| --- | --- | ---: | --- | ---: | ---: |",...$.report.phases.map((D)=>`| ${D.id} | ${D.operation} | ${D.count} | ${D.success?"pass":`fail: ${D.error??"unknown"}`} | ${BE(D.commitLatencyMs)} | ${BE(D.persistenceLatencyMs)} |`),"","## Runtime","",`- Samples: ${U.length}`,`- CPU p50/p95/p99/max: ${j4(DH(G,0.5))} / ${j4(DH(G,0.95))} / ${j4(DH(G,0.99))} / ${j4(G.at(-1))}`,`- Memory max: ${j4(I.length?Math.max(...I):void 0)}`,`- PIDs max: ${U.length?Math.max(...U.map((D)=>D.pids)):"n/a"}`,`- Container status/restarts/OOM: ${$.report.metrics.container?`${$.report.metrics.container.status} / ${$.report.metrics.container.restartCount} / ${$.report.metrics.container.oomKilled}`:"unknown"}`,`- Health samples: ${J.length}`,`- Health failures: ${q.length}`,"","## Cleanup","",`- Result: ${$.report.cleanup.success?"pass":"fail"}`,`- Remaining probes: ${$.report.cleanup.probesRemaining}`,`- Final entities: ${$.report.cleanup.finalEntities??"unknown"}`,`- Final notes: ${$.report.cleanup.finalNotes??"unknown"}`,`- Content tree restored: ${$.report.cleanup.contentTreeRestored??"unknown"}`,""];if($.report.failure)Q.push("## Failure","",$.report.failure,"");return`${Q.join(`
|
|
261
261
|
`)}
|
|
262
|
-
`}function DH($,U){if($.length===0)return;let J=Math.max(0,Math.ceil($.length*U)-1);return $[J]}function j4($){return $===void 0?"n/a":`${$.toFixed(2)}%`}function BE($){return $===void 0?"n/a":`${($/1000).toFixed(1)}s`}var na,ca,oa,PE='!f() { test "$1" = get && echo username=x-access-token && echo "password=$GH_TOKEN"; }; f',OH=async($,U,J={})=>new Promise((G,I)=>{let q=ra($,[...U],{cwd:J.cwd,env:J.env?{...process.env,...J.env}:process.env,stdio:["pipe","pipe","pipe"]}),Q="",D="";q.stdout.setEncoding("utf8"),q.stderr.setEncoding("utf8"),q.stdout.on("data",(X)=>{Q+=X}),q.stderr.on("data",(X)=>{D+=X}),q.on("error",I),q.on("close",(X)=>{G({exitCode:X??1,stdout:Q,stderr:D})}),q.stdin.end(J.stdin)});var hN=O$(()=>{k$();QH();QJ();na=Z.object({HCLOUD_TOKEN:Z.string().min(1),KAMAL_SSH_PRIVATE_KEY:Z.string().min(1),CONTENT_REPO_ADMIN_TOKEN:Z.string().min(1)}),ca=Z.object({servers:Z.array(Z.object({id:Z.number().int(),status:Z.string(),public_net:Z.object({ipv4:Z.object({ip:Z.string().min(1)})})}))}),oa=Z.object({status:Z.
|
|
262
|
+
`}function DH($,U){if($.length===0)return;let J=Math.max(0,Math.ceil($.length*U)-1);return $[J]}function j4($){return $===void 0?"n/a":`${$.toFixed(2)}%`}function BE($){return $===void 0?"n/a":`${($/1000).toFixed(1)}s`}var na,ca,oa,PE='!f() { test "$1" = get && echo username=x-access-token && echo "password=$GH_TOKEN"; }; f',OH=async($,U,J={})=>new Promise((G,I)=>{let q=ra($,[...U],{cwd:J.cwd,env:J.env?{...process.env,...J.env}:process.env,stdio:["pipe","pipe","pipe"]}),Q="",D="";q.stdout.setEncoding("utf8"),q.stderr.setEncoding("utf8"),q.stdout.on("data",(X)=>{Q+=X}),q.stderr.on("data",(X)=>{D+=X}),q.on("error",I),q.on("close",(X)=>{G({exitCode:X??1,stdout:Q,stderr:D})}),q.stdin.end(J.stdin)});var hN=O$(()=>{k$();QH();QJ();na=Z.object({HCLOUD_TOKEN:Z.string().min(1),KAMAL_SSH_PRIVATE_KEY:Z.string().min(1),CONTENT_REPO_ADMIN_TOKEN:Z.string().min(1)}),ca=Z.object({servers:Z.array(Z.object({id:Z.number().int(),status:Z.string(),public_net:Z.object({ipv4:Z.object({ip:Z.string().min(1)})})}))}),oa=Z.object({status:Z.literal("ready"),operationalStatus:Z.literal("operational"),app:Z.object({version:Z.string(),entities:Z.number().int().nonnegative(),entityCounts:Z.array(Z.object({entityType:Z.string(),count:Z.number().int().nonnegative()})).default([])})})});import{access as pF,chmod as EZ,mkdir as _z,readFile as Cz,writeFile as Ez}from"fs/promises";import{dirname as dF,join as vZ}from"path";import{fileURLToPath as nF}from"url";var K4={name:"@rizom/ops",version:"0.2.0-alpha.261",description:"Operator CLI for managing private brain fleet registry repos",keywords:["brains","ops","cli","deploy","fleet","operator"],license:"AGPL-3.0-only",author:"Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",bin:{"brains-ops":"./dist/brains-ops.js"},bugs:"https://github.com/rizom-ai/brains/issues",dependencies:{"age-encryption":"^0.3.0",yaml:"^2.9.0"},devDependencies:{"@brains/deploy-support":"workspace:*","@brains/eslint-config":"workspace:*","@brains/site-composition":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"^1.3.14",typescript:"^7.0.2"},engines:{bun:">=1.3.3"},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./deploy":{types:"./dist/deploy.d.ts",import:"./dist/deploy.js",bun:"./dist/deploy.js"}},files:["dist","templates"],homepage:"https://github.com/rizom-ai/brains/tree/main/packages/brains-ops#readme",main:"./dist/index.js",publishConfig:{access:"public"},repository:{type:"git",url:"https://github.com/rizom-ai/brains.git",directory:"packages/brains-ops"},scripts:{build:"bun scripts/build.ts",lint:"eslint . --max-warnings 0","lint:fix":"eslint . --max-warnings 0 --fix",prepublishOnly:"bun scripts/build.ts",test:"bun run build && bun test --timeout 20000","test:smoke":"bun run build && RUN_SMOKE_TESTS=1 bun test --timeout 60000",typecheck:"tsc --noEmit"},type:"module",types:"./dist/index.d.ts"};var MH=`ARG BUN_VERSION=1.3.10
|
|
263
263
|
FROM oven/bun:\${BUN_VERSION}-slim AS runtime
|
|
264
264
|
|
|
265
265
|
LABEL ai.rizom.brain.watchdog="true"
|
|
@@ -489,10 +489,10 @@ agePublicKey: ${U}
|
|
|
489
489
|
`)}import{mkdir as Cf,writeFile as v5}from"fs/promises";import{dirname as EP,join as F5}from"path";import{createSign as Of,generateKeyPairSync as Wf}from"crypto";async function Nf($){let U=await $.text();if(!U.trim())return;try{return JSON.parse(U)}catch{return U}}async function lq($,U,J){let G=await Nf($),I=U.safeParse(G);if(!$.ok||!I.success){let q=J.formatError??Yf;throw Error(`${J.label}${q($,G)}`)}return I.data}function Yf($,U){let J=U===void 0?"":`: ${typeof U==="string"?U:JSON.stringify(U)}`;return` (${$.status} ${$.statusText}${J})`}k$();var Vf="2.5.4.3",Rf="1.2.840.113549.1.1.11",AP="https://api.cloudflare.com/client/v4",Zf="origin-rsa",wf=5475,jP=15000;function KP($){return{Authorization:`Bearer ${$}`,"Content-Type":"application/json"}}var TP=Z.looseObject({message:Z.string().optional()}),Hf=Z.looseObject({errors:Z.array(TP).optional(),messages:Z.array(TP).optional()}),Mf=Z.looseObject({certificate:Z.string().min(1),expires_on:Z.string().optional()}),gf=Z.looseObject({success:Z.literal(!0),result:Mf}),Tf=Z.looseObject({success:Z.literal(!0)});function LP(){let{privateKey:$,publicKey:U}=Wf("rsa",{modulusLength:2048,privateKeyEncoding:{type:"pkcs8",format:"pem"},publicKeyEncoding:{type:"spki",format:"der"}});return{privateKeyPem:$,publicKeyDer:Buffer.from(U)}}function SP($,U){let J=d6(Sf(d6(zP(Vf),jf($)))),G=d6(Af(0),J,Buffer.from(U.publicKeyDer),Pf(0,Buffer.alloc(0))),I=Of("sha256").update(G).sign(U.privateKeyPem),q=d6(G,d6(zP(Rf),Lf()),Kf(I));return{csrPem:zf("CERTIFICATE REQUEST",q),certificationRequestInfoDer:G,signature:I}}async function PP($,U,J,G){let I=await $(`${AP}/certificates`,{method:"POST",headers:KP(U),body:JSON.stringify({hostnames:[G,`*.${G}`],requested_validity:wf,request_type:Zf,csr:J}),signal:AbortSignal.timeout(jP)}),q=await lq(I,gf,{label:"Cloudflare Origin CA request failed",formatError:_P}),D={certificatePem:`${q.result.certificate.trim()}
|
|
490
490
|
`};if(q.result.expires_on)D.expiresOn=q.result.expires_on;return D}async function BP($,U,J){let G=await $(`${AP}/zones/${J}/settings/ssl`,{method:"PATCH",headers:KP(U),body:JSON.stringify({value:"strict"}),signal:AbortSignal.timeout(jP)});await lq(G,Tf,{label:"Cloudflare zone SSL update failed",formatError:_P})}function zf($,U){let G=U.toString("base64").match(/.{1,64}/g)??[];return[`-----BEGIN ${$}-----`,...G,`-----END ${$}-----`,""].join(`
|
|
491
491
|
`)}function Af($){if($!==0)throw Error("Only zero-valued INTEGER encoding is currently supported");return Buffer.from([2,1,0])}function zP($){let U=$.split(".").map((Q)=>Number(Q));if(U.length<2||U.some((Q)=>Number.isNaN(Q)))throw Error(`Invalid OID: ${$}`);let J=U[0],G=U[1];if(J===void 0||G===void 0)throw Error(`Invalid OID: ${$}`);let q=[J*40+G];for(let Q of U.slice(2)){let D=_f(Q);q.push(...D)}return iq(6,Buffer.from(q))}function jf($){return iq(12,Buffer.from($,"utf8"))}function Kf($){return iq(3,Buffer.concat([Buffer.from([0]),$]))}function Lf(){return Buffer.from([5,0])}function d6(...$){return iq(48,Buffer.concat($))}function Sf(...$){return iq(49,Buffer.concat($))}function Pf($,U){return iq(160+$,U)}function iq($,U){return Buffer.concat([Buffer.from([$]),Bf(U.length),U])}function Bf($){if($<128)return Buffer.from([$]);let U=[],J=$;while(J>0)U.unshift(J&255),J>>=8;return Buffer.from([128|U.length,...U])}function _f($){if(!Number.isInteger($)||$<0)throw Error(`Invalid OID component: ${$}`);if($===0)return[0];let U=[],J=$;while(J>0)U.unshift(J&127),J>>=7;for(let G=0;G<U.length-1;G+=1)U[G]=(U[G]??0)|128;return U}function _P($,U){let J=Ef(U),G=J.length>0?`: ${J.join("; ")}`:"";return` (${$.status} ${$.statusText}${G})`}function Ef($){let U=Hf.safeParse($);if(!U.success)return[];return[...U.data.errors??[],...U.data.messages??[]].map((J)=>J.message).filter((J)=>typeof J==="string"&&J.length>0)}QJ();async function b5($,U={}){try{return await vP($,U),{success:!0}}catch(J){return{success:!1,message:$U(J,"Certificate bootstrap failed")}}}async function vP($,U={}){let J=await VU($),G=Ff(J,U.handle),I=G.domain,q=U.env??process.env,Q=S0($),D=U.cfApiToken??DU("CF_API_TOKEN",q,Q),X=U.cfZoneId??G.cloudflareZoneId??DU("CF_ZONE_ID",q,Q);if(!D)throw Error("Missing CF_API_TOKEN");if(!X)throw Error("Missing CF_ZONE_ID");let N=U.fetchImpl??fetch,Y=U.logger??console.log,O=LP(),{csrPem:V}=SP(I,O),R=await PP(N,D,V,I),H=F5($,".brains-ops","certs",G.id,"origin.pem"),w=F5($,".brains-ops","certs",G.id,"origin.key"),M=F5(EP(H),"secrets.yaml");await Cf(EP(H),{recursive:!0}),await Promise.all([v5(H,R.certificatePem,"utf-8"),v5(w,O.privateKeyPem,{encoding:"utf-8",mode:384}),v5(M,vf(R.certificatePem,O.privateKeyPem),"utf-8")]),await BP(N,D,X);let j=VG(U.pushTo);if(j)await KJ(j,[["CERTIFICATE_PEM",R.certificatePem],["PRIVATE_KEY_PEM",O.privateKeyPem]],{logger:Y,runCommand:U.runCommand??fU});if(Y(`Issued ${G.id} Origin CA cert for ${I} and *.${I}`),Y(`Wrote ${H}`),Y(`Wrote ${w}`),Y(`Wrote ${M}`),R.expiresOn)Y(`Expires on ${R.expiresOn}`);if(Y("Cloudflare zone SSL mode set to Full (strict)"),j)Y(`Pushed CERTIFICATE_PEM and PRIVATE_KEY_PEM to ${j}`);return{domain:I,certificatePath:H,privateKeyPath:w,certificatePem:R.certificatePem,secretsSnippetPath:M}}function vf($,U){return[`certificatePem: ${CP($)}`,`privateKeyPem: ${CP(U)}`,""].join(`
|
|
492
|
-
`)}function CP($){return`"${$.replace(/"/g,"\\\"").replace(/\n/g,"\\n")}"`}function Ff($,U){if(!U)return{id:"shared",domain:bf($.pilot.domainSuffix)};let J=$.users.find((G)=>G.handle===U);if(!J)throw Error(`Unknown user handle: ${U}`);return{id:U,domain:J.domain,...J.cloudflareZoneId?{cloudflareZoneId:J.cloudflareZoneId}:{}}}function bf($){let U=$.trim().replace(/^\./,"").replace(/\.$/,"");if(!U||U.includes("*"))throw Error(`Invalid pilot domainSuffix: ${$}`);return U}import{lookup as uf}from"dns/promises";function FP($={}){let U=$.fetchImpl??fetch,J=$.lookupHost??uf;return async function(I){let q=await kf(I.domain,J),Q=await xf(I.domain,U),D=await mf(I.domain,U);return{dnsStatus:q,serverStatus:Q,deployStatus:Q,mcpStatus:D}}}async function kf($,U){try{return(await U($)).address?"ready":"failed"}catch{return"failed"}}async function xf($,U){try{return(await bP(U,`https://${$}/health`,{method:"GET"})).ok?"ready":"failed"}catch{return"failed"}}async function mf($,U){try{let J=await bP(U,`https://${$}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{}})});return J.status===401||J.ok?"ready":"failed"}catch{return"failed"}}async function bP($,U,J){let G=new AbortController,I=setTimeout(()=>G.abort(),5000);try{return await $(U,{...J,signal:G.signal})}finally{clearTimeout(I)}}import{createHash as yf}from"crypto";import{cp as ff,lstat as hf,mkdtemp as rf,readFile as lf,readdir as pf,readlink as df,rm as nf}from"fs/promises";import{tmpdir as cf}from"os";import{basename as of,join as n6,relative as af,resolve as tf,sep as sf}from"path";var ef=new Set([".git",".operator",".brains-ops",".turbo","dist","node_modules"]);async function xP($){let U=tf($),J=await rf(n6(cf(),"brains-ops-reconcile-")),G=n6(J,"repo");try{await ff(U,G,{recursive:!0,errorOnExist:!0,force:!1,filter:(D)=>$h(U,D)});let I=await u5(G);await uP(G);let q=await u5(G);await uP(G);let Q=await u5(G);return{firstPassChangedFiles:kP(I,q),secondPassChangedFiles:kP(q,Q)}}finally{await nf(J,{recursive:!0,force:!0})}}function $h($,U){let J=af($,U);if(J.length===0)return!0;if(J.split(sf).some((I)=>ef.has(I)))return!1;if(J===".env"||J===".env.local")return!1;return!of(J).endsWith(".secrets.yaml")}async function uP($){await X6($,void 0,{env:{},contentRepoRemoteResolver:()=>{return},fetchImpl:async()=>{throw Error("Dry-run reconcile attempted external HTTP access")},runCommand:async()=>{throw Error("Dry-run reconcile attempted a subprocess")}})}async function u5($){let U=new Map;return await mP($,"",U),U}async function mP($,U,J){let G=n6($,U),I=await pf(G,{withFileTypes:!0});I.sort((q,Q)=>q.name.localeCompare(Q.name));for(let q of I){let Q=n6(U,q.name),D=n6($,Q);if(q.isDirectory()){await mP($,Q,J);continue}let N=(await hf(D)).isSymbolicLink()?`symlink:${await df(D)}`:await lf(D);J.set(Q,yf("sha256").update(N).digest("hex"))}}function kP($,U){return[...new Set([...$.keys(),...U.keys()])].filter((G)=>$.get(G)!==U.get(G)).sort()}s8();import{readFileSync as c6}from"fs";import{access as Uh,rm as Jh,writeFile as lP}from"fs/promises";import{join as k5,relative as yP}from"path";zI();k$();var iP=Z.strictObject({gitSyncToken:Z.string().min(1).optional(),discordBotToken:Z.string().min(1).optional(),discordPublicKey:Z.string().min(1).optional(),discordApplicationId:Z.string().min(1).optional(),aiApiKey:Z.string().min(1).optional(),atprotoAppPassword:Z.string().min(1).optional(),certificatePem:Z.string().min(1).optional(),privateKeyPem:Z.string().min(1).optional()});async function x5($,U,J={}){let{registry:G,user:I}=await lD($,U),q=J.env??process.env,Q=J.logger??console.log,D=S0($),X=k5($,"users",`${U}.secrets.yaml.age`),N=k5($,"users",`${U}.secrets.yaml`),Y=rP(yP($,X)),O=rP(yP($,N)),V=qh(N),R=await Qh(X,$,q,D),H=await pP(N),w={sharedAiApiKeySelector:G.pilot.aiApiKey,sharedGitSyncTokenSelector:G.pilot.gitSyncToken,effectiveAiApiKeySelector:I.effectiveAiApiKey,effectiveGitSyncTokenSelector:I.effectiveGitSyncToken,discordEnabled:I.discordEnabled},M;try{M=Ih($,q,D,V,R,w)}catch(_){if(!J.dryRun&&V===void 0&&_ instanceof Error){let p=Nh(w);if(p.length>0)throw await Yh(N,p),Error(`Missing required secrets for ${U}. Created ${O}; fill it in and rerun secrets:encrypt. ${_.message}`,{cause:_})}throw _}let j=`${BG(M).trimEnd()}
|
|
492
|
+
`)}function CP($){return`"${$.replace(/"/g,"\\\"").replace(/\n/g,"\\n")}"`}function Ff($,U){if(!U)return{id:"shared",domain:bf($.pilot.domainSuffix)};let J=$.users.find((G)=>G.handle===U);if(!J)throw Error(`Unknown user handle: ${U}`);return{id:U,domain:J.domain,...J.cloudflareZoneId?{cloudflareZoneId:J.cloudflareZoneId}:{}}}function bf($){let U=$.trim().replace(/^\./,"").replace(/\.$/,"");if(!U||U.includes("*"))throw Error(`Invalid pilot domainSuffix: ${$}`);return U}import{lookup as uf}from"dns/promises";function FP($={}){let U=$.fetchImpl??fetch,J=$.lookupHost??uf;return async function(I){let q=await kf(I.domain,J),Q=await xf(I.domain,U),D=await mf(I.domain,U);return{dnsStatus:q,serverStatus:Q,deployStatus:Q,mcpStatus:D}}}async function kf($,U){try{return(await U($)).address?"ready":"failed"}catch{return"failed"}}async function xf($,U){try{return(await bP(U,`https://${$}/health/ready`,{method:"GET"})).ok?"ready":"failed"}catch{return"failed"}}async function mf($,U){try{let J=await bP(U,`https://${$}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{}})});return J.status===401||J.ok?"ready":"failed"}catch{return"failed"}}async function bP($,U,J){let G=new AbortController,I=setTimeout(()=>G.abort(),5000);try{return await $(U,{...J,signal:G.signal})}finally{clearTimeout(I)}}import{createHash as yf}from"crypto";import{cp as ff,lstat as hf,mkdtemp as rf,readFile as lf,readdir as pf,readlink as df,rm as nf}from"fs/promises";import{tmpdir as cf}from"os";import{basename as of,join as n6,relative as af,resolve as tf,sep as sf}from"path";var ef=new Set([".git",".operator",".brains-ops",".turbo","dist","node_modules"]);async function xP($){let U=tf($),J=await rf(n6(cf(),"brains-ops-reconcile-")),G=n6(J,"repo");try{await ff(U,G,{recursive:!0,errorOnExist:!0,force:!1,filter:(D)=>$h(U,D)});let I=await u5(G);await uP(G);let q=await u5(G);await uP(G);let Q=await u5(G);return{firstPassChangedFiles:kP(I,q),secondPassChangedFiles:kP(q,Q)}}finally{await nf(J,{recursive:!0,force:!0})}}function $h($,U){let J=af($,U);if(J.length===0)return!0;if(J.split(sf).some((I)=>ef.has(I)))return!1;if(J===".env"||J===".env.local")return!1;return!of(J).endsWith(".secrets.yaml")}async function uP($){await X6($,void 0,{env:{},contentRepoRemoteResolver:()=>{return},fetchImpl:async()=>{throw Error("Dry-run reconcile attempted external HTTP access")},runCommand:async()=>{throw Error("Dry-run reconcile attempted a subprocess")}})}async function u5($){let U=new Map;return await mP($,"",U),U}async function mP($,U,J){let G=n6($,U),I=await pf(G,{withFileTypes:!0});I.sort((q,Q)=>q.name.localeCompare(Q.name));for(let q of I){let Q=n6(U,q.name),D=n6($,Q);if(q.isDirectory()){await mP($,Q,J);continue}let N=(await hf(D)).isSymbolicLink()?`symlink:${await df(D)}`:await lf(D);J.set(Q,yf("sha256").update(N).digest("hex"))}}function kP($,U){return[...new Set([...$.keys(),...U.keys()])].filter((G)=>$.get(G)!==U.get(G)).sort()}s8();import{readFileSync as c6}from"fs";import{access as Uh,rm as Jh,writeFile as lP}from"fs/promises";import{join as k5,relative as yP}from"path";zI();k$();var iP=Z.strictObject({gitSyncToken:Z.string().min(1).optional(),discordBotToken:Z.string().min(1).optional(),discordPublicKey:Z.string().min(1).optional(),discordApplicationId:Z.string().min(1).optional(),aiApiKey:Z.string().min(1).optional(),atprotoAppPassword:Z.string().min(1).optional(),certificatePem:Z.string().min(1).optional(),privateKeyPem:Z.string().min(1).optional()});async function x5($,U,J={}){let{registry:G,user:I}=await lD($,U),q=J.env??process.env,Q=J.logger??console.log,D=S0($),X=k5($,"users",`${U}.secrets.yaml.age`),N=k5($,"users",`${U}.secrets.yaml`),Y=rP(yP($,X)),O=rP(yP($,N)),V=qh(N),R=await Qh(X,$,q,D),H=await pP(N),w={sharedAiApiKeySelector:G.pilot.aiApiKey,sharedGitSyncTokenSelector:G.pilot.gitSyncToken,effectiveAiApiKeySelector:I.effectiveAiApiKey,effectiveGitSyncTokenSelector:I.effectiveGitSyncToken,discordEnabled:I.discordEnabled},M;try{M=Ih($,q,D,V,R,w)}catch(_){if(!J.dryRun&&V===void 0&&_ instanceof Error){let p=Nh(w);if(p.length>0)throw await Yh(N,p),Error(`Missing required secrets for ${U}. Created ${O}; fill it in and rerun secrets:encrypt. ${_.message}`,{cause:_})}throw _}let j=`${BG(M).trimEnd()}
|
|
493
493
|
`;Xh(j,M);let L=Object.keys(M);if(J.dryRun){if(Q(`Dry run: would encrypt ${L.length} secrets to ${Y}.`),Q(L.length>0?`Keys: ${L.join(", ")}`:"Keys: (none \u2014 shared defaults only)"),H)Q(`Would remove plaintext file ${O}.`);return{encryptedPath:Y,plaintextPath:O,deletedPlaintext:H,encryptedKeys:L,dryRun:!0}}let E=new S5;E.addRecipient(G.pilot.agePublicKey);let F=await E.encrypt(j),m=p6.encode(F);if(await lP(X,m),await Jh(N,{force:!0}),Q(`Encrypted ${L.length} secrets to ${Y}.`),H)Q(`Removed plaintext file ${O}.`);return{encryptedPath:Y,plaintextPath:O,deletedPlaintext:H,encryptedKeys:L}}function Ih($,U,J,G,I,q){let Q=fP($,U,J,G,I,"aiApiKey",q.effectiveAiApiKeySelector,q.sharedAiApiKeySelector),D=fP($,U,J,G,I,"gitSyncToken",q.effectiveGitSyncTokenSelector,q.sharedGitSyncTokenSelector),X=q.discordEnabled?hX($,U,J,G,I,"discordBotToken","DISCORD_BOT_TOKEN"):void 0,N=q.discordEnabled?hX($,U,J,G,I,"discordPublicKey","DISCORD_PUBLIC_KEY"):void 0,Y=q.discordEnabled?hX($,U,J,G,I,"discordApplicationId","DISCORD_APPLICATION_ID"):void 0,O=rX($,U,J,G,I,"atprotoAppPassword","ATPROTO_APP_PASSWORD"),V=hP(rX($,U,J,G,I,"certificatePem","CERTIFICATE_PEM")),R=hP(rX($,U,J,G,I,"privateKeyPem","PRIVATE_KEY_PEM"));return iP.parse({...Q?{aiApiKey:Q}:{},...D?{gitSyncToken:D}:{},...X?{discordBotToken:X}:{},...N?{discordPublicKey:N}:{},...Y?{discordApplicationId:Y}:{},...O?{atprotoAppPassword:O}:{},...V?{certificatePem:V}:{},...R?{privateKeyPem:R}:{}})}function fP($,U,J,G,I,q,Q,D){if(Q===D)return;return hX($,U,J,G,I,q,Q)}function hX($,U,J,G,I,q,Q){let D=rX($,U,J,G,I,q,Q);if(D===void 0||D.trim().length===0)throw Error(`Missing required secret value for ${String(q)}. Set it in users/<handle>.secrets.yaml or fall back to ${Q}/${Q}_FILE before running secrets:encrypt.`);return D}function hP($){return $?.replace(/\r\n?|\n/g,"\\n")}function rX($,U,J,G,I,q,Q){return Gh(G,I,q,Q,U,J,$)}function Gh($,U,J,G,I,q,Q){let D=$?.[J];if(D!==void 0&&D.trim().length>0)return D;let X=DU(`${G}_FILE`,I,q);if(X&&X.trim().length>0)return c6(EJ(X,Q),"utf8");let N=DU(G,I,q);if(N!==void 0&&N.trim().length>0)return N;let Y=U?.[J];if(Y!==void 0&&Y.trim().length>0)return Y;return}function qh($){let U;try{U=c6($,"utf8")}catch{return}try{return m5(U)}catch(J){throw Error(`Unable to parse plaintext secrets file ${$}: ${$U(J)}`,{cause:J})}}async function Qh($,U,J,G){if(!await pP($))return;let I=Dh(U,J,G);if(!I)return;let q;try{let Q=c6($,"utf8"),D=p6.decode(Q),X=new P5;X.addIdentity(I),q=await X.decrypt(D,"text")}catch{return}try{return m5(q)}catch(Q){throw Error(`Unable to parse decrypted secrets from ${$}: ${$U(Q)}`,{cause:Q})}}function Dh($,U,J){let G=DU("AGE_SECRET_KEY_FILE",U,J);if(G&&G.trim().length>0)return rq(c6(EJ(G,$),"utf8"));let I=DU("AGE_SECRET_KEY",U,J);if(I&&I.trim().length>0)return rq(I);try{return rq(c6(k5($,".brains-ops","age","identity.txt"),"utf8"))}catch{return}}function m5($){let U=VM($),J={};if(U!==null&&typeof U==="object"&&!Array.isArray(U)){for(let[G,I]of Object.entries(U))if(typeof I==="string")J[G]=I}return iP.partial().parse(J)}function Xh($,U){let J={...U},G={...m5($)},I=new Set([...Object.keys(J),...Object.keys(G)]);for(let q of I)if(J[q]!==G[q])throw Error(`secrets:encrypt round-trip verification failed for ${q}; refusing to write a corrupted encrypted payload`)}function Nh($){return[...$.effectiveAiApiKeySelector!==$.sharedAiApiKeySelector?["aiApiKey"]:[],...$.effectiveGitSyncTokenSelector!==$.sharedGitSyncTokenSelector?["gitSyncToken"]:[],...$.discordEnabled?["discordBotToken","discordPublicKey","discordApplicationId"]:[]]}async function Yh($,U){let J=["# local per-user secret staging file","# fill values, run `bunx brains-ops secrets:encrypt . <handle>`, then the plaintext file will be removed",...U.map((G)=>`${G}: `),""].join(`
|
|
494
494
|
`);await lP($,J,{flag:"wx"})}async function pP($){try{return await Uh($),!0}catch{return!1}}function rP($){return $.replaceAll("\\","/")}import{readFileSync as Oh}from"fs";async function y5($,U={}){let J=U.env??process.env,G=U.logger??console.log,I=S0($),q=pN(`${$}/.env.schema`),Q=Vh(q),D=[],X=[],N=new Map;for(let O of Q){N.set(O.key,O.required);let V=Rh(O.key,J,I,$);if(V===void 0||V.trim().length===0){X.push(O.key);continue}D.push([O.key,V])}if(D.length===0)throw Error("No pushable local secrets found for this pilot repo");let Y=(O)=>N.get(O)??!1;if(U.dryRun)return G(`Dry run: would push ${D.length} secrets to GitHub Secrets.`),G(`Secrets: ${D.map(([O])=>O).join(", ")}`),fX(G,X,Y),{pushedKeys:D.map(([O])=>O),skippedKeys:X,dryRun:!0};return await KJ("gh",D,{logger:G,runCommand:U.runCommand??fU}),fX(G,X,Y),{pushedKeys:D.map(([O])=>O),skippedKeys:X}}var Wh=new Set(["DISCORD_BOT_TOKEN","DISCORD_PUBLIC_KEY","DISCORD_APPLICATION_ID"]);function Vh($){return $.filter((U)=>!Wh.has(U.key)).map((U)=>({key:U.key,required:U.required}))}function Rh($,U,J,G){let I=DU(`${$}_FILE`,U,J);if(I&&I.trim().length>0)return Oh(EJ(I,G),"utf8");let q=DU($,U,J);if(q===void 0||q.trim().length===0)return;return q}k$();import{execFileSync as dP}from"child_process";import{chmodSync as Zh,existsSync as wh,mkdirSync as Hh,readFileSync as nP,writeFileSync as Mh}from"fs";import{dirname as gh,join as Th}from"path";import{homedir as zh}from"os";var cP=Z.object({id:Z.number(),name:Z.string(),public_key:Z.string()}),Ah=Z.object({ssh_keys:Z.array(cP)}),jh={createEd25519KeyPair($,U){dP("ssh-keygen",["-t","ed25519","-f",$,"-C",U,"-N",""],{stdio:"ignore"})},derivePublicKey($){return dP("ssh-keygen",["-y","-f",$],{encoding:"utf-8",stdio:["ignore","pipe","inherit"]}).trim()}};async function lX($,U={}){try{let J=await f5($,U);return{success:!0,message:J.createdLocalKey?`SSH deploy key ready at ${J.privateKeyPath}`:`SSH deploy key already ready at ${J.privateKeyPath}`}}catch(J){return{success:!1,message:$U(J,"SSH key bootstrap failed")}}}async function f5($,U={}){let J=U.env??process.env,G=S0($),I=U.logger??console.log,q=U.fetchImpl??fetch,Q=U.sshKeygen??jh,D=DU("HCLOUD_TOKEN",J,G);if(!D)throw Error("Missing HCLOUD_TOKEN");let X=DU("HCLOUD_SSH_KEY_NAME",J,G);if(!X)throw Error("Missing HCLOUD_SSH_KEY_NAME");let N=DU("KAMAL_SSH_PRIVATE_KEY_FILE",J,G),Y=N?EJ(N,$):Th(zh(),".ssh",`${Lh(X)}_ed25519`),O=`${Y}.pub`,V=!1;if(!wh(Y))Hh(gh(Y),{recursive:!0,mode:448}),Q.createEd25519KeyPair(Y,X),V=!0;Zh(Y,384);let R;if(V)R=nP(O,"utf-8").trim();else R=Q.derivePublicKey(Y),Mh(O,`${R}
|
|
495
|
-
`,"utf-8");if(R.length===0)throw Error(`Unable to derive a public key from ${Y}`);let H=await Kh({fetchImpl:q,hcloudToken:D,publicKey:R,sshKeyName:X}),w=VG(U.pushTo);if(w)await KJ(w,[["KAMAL_SSH_PRIVATE_KEY",nP(Y,"utf-8")]],{logger:I,runCommand:U.runCommand??fU});if(I(V?`Created ${Y}`:`Reusing ${Y}`),I(H?`Registered Hetzner SSH key ${X}`:`Hetzner SSH key ${X} already exists`),w)I(`Pushed KAMAL_SSH_PRIVATE_KEY to ${w}`);return{createdHetznerKey:H,createdLocalKey:V,privateKeyPath:Y,publicKeyPath:O,sshKeyName:X}}async function Kh($){let U=new URL("https://api.hetzner.cloud/v1/ssh_keys");U.searchParams.set("name",$.sshKeyName);let J=await $.fetchImpl(U.toString(),{headers:{Authorization:`Bearer ${$.hcloudToken}`,"Content-Type":"application/json"}}),{ssh_keys:G}=await lq(J,Ah,{label:"Hetzner SSH key lookup failed"}),[I]=G;if(I){if(I.public_key.trim()!==$.publicKey)throw Error(`Existing Hetzner SSH key ${$.sshKeyName} does not match the local public key`);return!1}let q=await $.fetchImpl("https://api.hetzner.cloud/v1/ssh_keys",{method:"POST",headers:{Authorization:`Bearer ${$.hcloudToken}`,"Content-Type":"application/json"},body:JSON.stringify({name:$.sshKeyName,public_key:$.publicKey})});return await lq(q,Z.object({ssh_key:cP}),{label:"Hetzner SSH key create failed"}),!0}function Lh($){return $.replace(/[^A-Za-z0-9._-]+/g,"_")}k$();QJ();var Sh=Z.looseObject({status:Z.string().optional(),daemons:Z.array(Z.looseObject({name:Z.string().optional(),status:Z.string().optional(),health:Z.looseObject({status:Z.string().optional(),message:Z.string().optional()}).optional()})).optional()});async function h5($,U,J={}){let G=J.fetchImpl??fetch,q=(await VU($)).users.find((N)=>N.handle===U);if(!q)throw Error(`Unknown pilot user: ${U}`);let Q=`https://${q.domain}`,D=[],X=[];if(await iX("health",()=>Ph(G,Q),D,X),await iX("mcp-auth-gate",()=>Bh(G,Q),D,X),q.bundles.includes("site"))await iX("site",()=>oP(G,`${Q}/`,"site"),D,X),await iX("cms",()=>oP(G,`${Q}/cms`,"cms"),D,X),J.logger?.("WARN Manual check still required: passkey setup/handoff completed from the setup email.");return{handle:q.handle,bundles:q.bundles,domain:q.domain,contentRepo:q.contentRepo,checks:D,failedChecks:X}}async function iX($,U,J,G){try{await U(),J.push($)}catch(I){G.push({name:$,message:$U(I)})}}async function Ph($,U){let J=await r5($,`${U}/health`,{method:"GET"});if(!J.ok)throw Error(`/health returned ${J.status}, expected 200`);let G=Sh.safeParse(await J.json());if(!G.success)throw Error(`/health response did not match expected shape: ${G.error.message}`);let I=G.data;if(I.status&&I.status!=="healthy")throw Error(`/health status is ${I.status}, expected healthy`);for(let q of I.daemons??[]){let Q=q.status??"unknown",D=q.health?.status;if(Q==="error"||D==="unhealthy")throw Error(`daemon ${q.name??"unknown"} is unhealthy (${Q}/${D??"unknown"})`)}}async function Bh($,U){let J=await r5($,`${U}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize"})});if(J.status<400||J.status>=500)throw Error(`unauthenticated POST /mcp returned ${J.status}, expected a 4xx auth failure`)}async function oP($,U,J){let G=await r5($,U,{method:"GET"});if(G.status>=400)throw Error(`${J} ${U} returned ${G.status}, expected < 400`)}async function r5($,U,J){let G=new AbortController,I=setTimeout(()=>G.abort(),20000);try{return await $(U,{...J,redirect:"follow",signal:G.signal})}finally{clearTimeout(I)}}var rE="brains-ops",VH={type:"string",placeholder:"<target>",description:"Push target (`gh` or `github`)"},RH={type:"boolean",description:"Show what would happen without writing anything"};function nU($){return{success:!1,message:WK(rE,$)}}var lE=NU({name:"init",usage:"<repo>",description:"Create a pilot repo skeleton",run:async({args:$})=>{let U=$[0];if(!U)return nU(lE);return await bZ(U),{success:!0,message:`Initialized ${U}`}}}),iE=NU({name:"crossover:stage",usage:"<source-repo> <output-dir> [site-pins.yaml]",description:"Stage a reviewed canonical crossover copy",run:async({args:$})=>{let U=$[0],J=$[1],G=$[2];if(!U||!J)return nU(iE);let{loadReviewedSitePins:I,stageLegacyCrossover:q}=await Promise.resolve().then(() => (gE(),ME)),Q=G?await I(G):void 0,D=await q(U,J,{sitePins:Q});return{success:!0,message:`Staged ${D.changedFiles.length} reviewed crossover files in ${D.outputDir}`}}}),pE=NU({name:"render",usage:"<repo>",description:"Render the observed users table to views/users.md",run:async({args:$},U)=>{let J=$[0];if(!J)return nU(pE);let G=U.resolveStatus??FP({...U.fetchImpl?{fetchImpl:U.fetchImpl}:{},...U.lookupHost?{lookupHost:U.lookupHost}:{}});return await uI(J,{resolveStatus:G}),{success:!0,message:`Rendered ${J}/views/users.md`}}}),dE=NU({name:"user:add",usage:"<repo> <handle> --cohort <cohort>",description:"Add a user to a cohort",flags:{cohort:{type:"string",placeholder:"<cohort>",description:"Cohort the user joins"},"anchor-id":{type:"string",placeholder:"<id>",description:"Discord anchor user id stored on the user record"}},run:async({args:$,flags:U})=>{let J=$[0],G=$[1],I=w0(U,"cohort");if(!J||!G||!I)return nU(dE);let q=w0(U,"anchor-id");return await y7(J,G,{cohort:I,...q?{anchorId:q}:{}}),{success:!0,message:`Added ${G} to ${I}`}}}),nE=NU({name:"onboard",usage:"<repo> <handle>",description:"Generate a user's brain.yaml and .env",run:async({args:$},U)=>{let J=$[0],G=$[1];if(!J||!G)return nU(nE);return await m7(J,G,U.runner,{...U.env?{env:U.env}:{}}),{success:!0,message:`Onboarded ${G}`}}}),cE=NU({name:"age-key:bootstrap",usage:"<repo>",description:"Generate the pilot age key and optional GitHub secret",flags:{"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(cE);let I=w0(U,"push-to");return C5(G,{...J.logger?{logger:J.logger}:{},...I?{pushTo:I}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{}})}}),oE=NU({name:"ssh-key:bootstrap",usage:"<repo>",description:"Bootstrap a deploy SSH key and optional GitHub secret",flags:{"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(oE);let I=w0(U,"push-to");return lX(G,{...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{},...I?{pushTo:I}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{},...J.sshKeygen?{sshKeygen:J.sshKeygen}:{}})}}),aE=NU({name:"cert:bootstrap",usage:"<repo>",description:"Issue Cloudflare Origin CA certificates for pilot users",flags:{handle:{type:"string",placeholder:"<handle>",description:"Only issue the certificate for this user handle"},"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(aE);let I=w0(U,"handle"),q=w0(U,"push-to");return b5(G,{...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{},...I?{handle:I}:{},...q?{pushTo:q}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{}})}}),tE=NU({name:"secrets:push",usage:"<repo>",description:"Push env-backed local secrets to GitHub Secrets",flags:{"dry-run":RH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(tE);let I=await y5(G,{env:J.env,logger:J.logger,dryRun:iD(U,"dry-run")});return{success:!0,message:I.dryRun?`Dry run: would push ${I.pushedKeys.length} secrets`:`Pushed ${I.pushedKeys.length} secrets`}}}),sE=NU({name:"secrets:encrypt",usage:"<repo> <handle>",description:"Encrypt pilot secrets for a user with age",flags:{"dry-run":RH},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1];if(!G||!I)return nU(sE);let q=await x5(G,I,{env:J.env,logger:J.logger,dryRun:iD(U,"dry-run")});return{success:!0,message:q.dryRun?`Dry run: would encrypt ${q.encryptedKeys.length} secrets for ${I}`:`Encrypted ${q.encryptedKeys.length} secrets for ${I}`}}}),eE=NU({name:"stress:directory-sync",usage:"<repo> <handle> --profile <regression|load|stress> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Run a smoke-only directory-sync stress profile",flags:{profile:{type:"string",placeholder:"<profile>",description:"Stress profile (`regression`, `load`, or `stress`)"},confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for JSON, Markdown, samples, and logs"}},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1],q=w0(U,"profile"),Q=w0(U,"confirm");if(!G||!I||!Q||q!=="regression"&&q!=="load"&&q!=="stress")return nU(eE);let D=J.directorySyncStressRunner??(await Promise.resolve().then(() => (hN(),WH))).runDeployedDirectorySyncStress,X=w0(U,"artifacts-dir"),N=await D({rootDir:G,handle:I,profile:q,confirmation:Q,...X?{artifactsDir:X}:{},...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{}});return{success:N.report.success,message:`${N.report.success?"Passed":"Failed"} ${q} directory-sync stress for ${I}; artifacts: ${N.artifactsDir}`}}}),$2=NU({name:"stress:directory-sync:cleanup",usage:"<repo> <handle> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Remove residual smoke directory-sync stress probes",flags:{confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for the cleanup result"}},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1],q=w0(U,"confirm");if(!G||!I||!q)return nU($2);let Q=J.directorySyncStressCleanupRunner??(await Promise.resolve().then(() => (hN(),WH))).cleanupDirectorySyncStress,D=w0(U,"artifacts-dir"),X=await Q({rootDir:G,handle:I,confirmation:q,...D?{artifactsDir:D}:{},...J.env?{env:J.env}:{},...J.logger?{logger:J.logger}:{}});return{success:X.success,message:`${X.success?"Cleaned":"Failed to clean"} directory-sync stress probes for ${I}; removed ${X.probesRemoved}, remaining ${X.probesRemaining}`}}}),U2=NU({name:"verify-user",usage:"<repo> <handle>",description:"Probe a deployed user's endpoints",run:async({args:$},U)=>{let J=$[0],G=$[1];if(!J||!G)return nU(U2);let I=await h5(J,G,{...U.fetchImpl?{fetchImpl:U.fetchImpl}:{},...U.logger?{logger:U.logger}:{}}),q=I.checks.length>0?I.checks.join(", "):"none";if(I.failedChecks.length>0){let Q=I.failedChecks.map((D)=>` ${D.name}: ${D.message}`).join(`
|
|
495
|
+
`,"utf-8");if(R.length===0)throw Error(`Unable to derive a public key from ${Y}`);let H=await Kh({fetchImpl:q,hcloudToken:D,publicKey:R,sshKeyName:X}),w=VG(U.pushTo);if(w)await KJ(w,[["KAMAL_SSH_PRIVATE_KEY",nP(Y,"utf-8")]],{logger:I,runCommand:U.runCommand??fU});if(I(V?`Created ${Y}`:`Reusing ${Y}`),I(H?`Registered Hetzner SSH key ${X}`:`Hetzner SSH key ${X} already exists`),w)I(`Pushed KAMAL_SSH_PRIVATE_KEY to ${w}`);return{createdHetznerKey:H,createdLocalKey:V,privateKeyPath:Y,publicKeyPath:O,sshKeyName:X}}async function Kh($){let U=new URL("https://api.hetzner.cloud/v1/ssh_keys");U.searchParams.set("name",$.sshKeyName);let J=await $.fetchImpl(U.toString(),{headers:{Authorization:`Bearer ${$.hcloudToken}`,"Content-Type":"application/json"}}),{ssh_keys:G}=await lq(J,Ah,{label:"Hetzner SSH key lookup failed"}),[I]=G;if(I){if(I.public_key.trim()!==$.publicKey)throw Error(`Existing Hetzner SSH key ${$.sshKeyName} does not match the local public key`);return!1}let q=await $.fetchImpl("https://api.hetzner.cloud/v1/ssh_keys",{method:"POST",headers:{Authorization:`Bearer ${$.hcloudToken}`,"Content-Type":"application/json"},body:JSON.stringify({name:$.sshKeyName,public_key:$.publicKey})});return await lq(q,Z.object({ssh_key:cP}),{label:"Hetzner SSH key create failed"}),!0}function Lh($){return $.replace(/[^A-Za-z0-9._-]+/g,"_")}k$();QJ();var Sh=Z.looseObject({status:Z.string(),operationalStatus:Z.string(),app:Z.looseObject({daemons:Z.array(Z.looseObject({name:Z.string().optional(),status:Z.string().optional(),health:Z.looseObject({status:Z.string().optional(),message:Z.string().optional()}).optional()})).default([])})});async function h5($,U,J={}){let G=J.fetchImpl??fetch,q=(await VU($)).users.find((N)=>N.handle===U);if(!q)throw Error(`Unknown pilot user: ${U}`);let Q=`https://${q.domain}`,D=[],X=[];if(await iX("health",()=>Ph(G,Q),D,X),await iX("mcp-auth-gate",()=>Bh(G,Q),D,X),q.bundles.includes("site"))await iX("site",()=>oP(G,`${Q}/`,"site"),D,X),await iX("cms",()=>oP(G,`${Q}/cms`,"cms"),D,X),J.logger?.("WARN Manual check still required: passkey setup/handoff completed from the setup email.");return{handle:q.handle,bundles:q.bundles,domain:q.domain,contentRepo:q.contentRepo,checks:D,failedChecks:X}}async function iX($,U,J,G){try{await U(),J.push($)}catch(I){G.push({name:$,message:$U(I)})}}async function Ph($,U){let G=await r5($,`${U}/health/operate`,{method:"GET"});if(!G.ok)throw Error(`/health/operate returned ${G.status}, expected 200`);let I=Sh.safeParse(await G.json());if(!I.success)throw Error(`/health/operate response did not match expected shape: ${I.error.message}`);let q=I.data;if(q.status!=="ready")throw Error(`/health/operate status is ${q.status}, expected ready`);if(q.operationalStatus!=="operational")throw Error(`/health/operate operationalStatus is ${q.operationalStatus}, expected operational`);for(let Q of q.app.daemons){let D=Q.status??"unknown",X=Q.health?.status;if(D==="error"||X==="unhealthy")throw Error(`daemon ${Q.name??"unknown"} is unhealthy (${D}/${X??"unknown"})`)}}async function Bh($,U){let J=await r5($,`${U}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize"})});if(J.status<400||J.status>=500)throw Error(`unauthenticated POST /mcp returned ${J.status}, expected a 4xx auth failure`)}async function oP($,U,J){let G=await r5($,U,{method:"GET"});if(G.status>=400)throw Error(`${J} ${U} returned ${G.status}, expected < 400`)}async function r5($,U,J){let G=new AbortController,I=setTimeout(()=>G.abort(),20000);try{return await $(U,{...J,redirect:"follow",signal:G.signal})}finally{clearTimeout(I)}}var rE="brains-ops",VH={type:"string",placeholder:"<target>",description:"Push target (`gh` or `github`)"},RH={type:"boolean",description:"Show what would happen without writing anything"};function nU($){return{success:!1,message:WK(rE,$)}}var lE=NU({name:"init",usage:"<repo>",description:"Create a pilot repo skeleton",run:async({args:$})=>{let U=$[0];if(!U)return nU(lE);return await bZ(U),{success:!0,message:`Initialized ${U}`}}}),iE=NU({name:"crossover:stage",usage:"<source-repo> <output-dir> [site-pins.yaml]",description:"Stage a reviewed canonical crossover copy",run:async({args:$})=>{let U=$[0],J=$[1],G=$[2];if(!U||!J)return nU(iE);let{loadReviewedSitePins:I,stageLegacyCrossover:q}=await Promise.resolve().then(() => (gE(),ME)),Q=G?await I(G):void 0,D=await q(U,J,{sitePins:Q});return{success:!0,message:`Staged ${D.changedFiles.length} reviewed crossover files in ${D.outputDir}`}}}),pE=NU({name:"render",usage:"<repo>",description:"Render the observed users table to views/users.md",run:async({args:$},U)=>{let J=$[0];if(!J)return nU(pE);let G=U.resolveStatus??FP({...U.fetchImpl?{fetchImpl:U.fetchImpl}:{},...U.lookupHost?{lookupHost:U.lookupHost}:{}});return await uI(J,{resolveStatus:G}),{success:!0,message:`Rendered ${J}/views/users.md`}}}),dE=NU({name:"user:add",usage:"<repo> <handle> --cohort <cohort>",description:"Add a user to a cohort",flags:{cohort:{type:"string",placeholder:"<cohort>",description:"Cohort the user joins"},"anchor-id":{type:"string",placeholder:"<id>",description:"Discord anchor user id stored on the user record"}},run:async({args:$,flags:U})=>{let J=$[0],G=$[1],I=w0(U,"cohort");if(!J||!G||!I)return nU(dE);let q=w0(U,"anchor-id");return await y7(J,G,{cohort:I,...q?{anchorId:q}:{}}),{success:!0,message:`Added ${G} to ${I}`}}}),nE=NU({name:"onboard",usage:"<repo> <handle>",description:"Generate a user's brain.yaml and .env",run:async({args:$},U)=>{let J=$[0],G=$[1];if(!J||!G)return nU(nE);return await m7(J,G,U.runner,{...U.env?{env:U.env}:{}}),{success:!0,message:`Onboarded ${G}`}}}),cE=NU({name:"age-key:bootstrap",usage:"<repo>",description:"Generate the pilot age key and optional GitHub secret",flags:{"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(cE);let I=w0(U,"push-to");return C5(G,{...J.logger?{logger:J.logger}:{},...I?{pushTo:I}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{}})}}),oE=NU({name:"ssh-key:bootstrap",usage:"<repo>",description:"Bootstrap a deploy SSH key and optional GitHub secret",flags:{"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(oE);let I=w0(U,"push-to");return lX(G,{...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{},...I?{pushTo:I}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{},...J.sshKeygen?{sshKeygen:J.sshKeygen}:{}})}}),aE=NU({name:"cert:bootstrap",usage:"<repo>",description:"Issue Cloudflare Origin CA certificates for pilot users",flags:{handle:{type:"string",placeholder:"<handle>",description:"Only issue the certificate for this user handle"},"push-to":VH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(aE);let I=w0(U,"handle"),q=w0(U,"push-to");return b5(G,{...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{},...I?{handle:I}:{},...q?{pushTo:q}:{},...J.bootstrapRunCommand?{runCommand:J.bootstrapRunCommand}:{}})}}),tE=NU({name:"secrets:push",usage:"<repo>",description:"Push env-backed local secrets to GitHub Secrets",flags:{"dry-run":RH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(tE);let I=await y5(G,{env:J.env,logger:J.logger,dryRun:iD(U,"dry-run")});return{success:!0,message:I.dryRun?`Dry run: would push ${I.pushedKeys.length} secrets`:`Pushed ${I.pushedKeys.length} secrets`}}}),sE=NU({name:"secrets:encrypt",usage:"<repo> <handle>",description:"Encrypt pilot secrets for a user with age",flags:{"dry-run":RH},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1];if(!G||!I)return nU(sE);let q=await x5(G,I,{env:J.env,logger:J.logger,dryRun:iD(U,"dry-run")});return{success:!0,message:q.dryRun?`Dry run: would encrypt ${q.encryptedKeys.length} secrets for ${I}`:`Encrypted ${q.encryptedKeys.length} secrets for ${I}`}}}),eE=NU({name:"stress:directory-sync",usage:"<repo> <handle> --profile <regression|load|stress> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Run a smoke-only directory-sync stress profile",flags:{profile:{type:"string",placeholder:"<profile>",description:"Stress profile (`regression`, `load`, or `stress`)"},confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for JSON, Markdown, samples, and logs"}},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1],q=w0(U,"profile"),Q=w0(U,"confirm");if(!G||!I||!Q||q!=="regression"&&q!=="load"&&q!=="stress")return nU(eE);let D=J.directorySyncStressRunner??(await Promise.resolve().then(() => (hN(),WH))).runDeployedDirectorySyncStress,X=w0(U,"artifacts-dir"),N=await D({rootDir:G,handle:I,profile:q,confirmation:Q,...X?{artifactsDir:X}:{},...J.env?{env:J.env}:{},...J.fetchImpl?{fetchImpl:J.fetchImpl}:{},...J.logger?{logger:J.logger}:{}});return{success:N.report.success,message:`${N.report.success?"Passed":"Failed"} ${q} directory-sync stress for ${I}; artifacts: ${N.artifactsDir}`}}}),$2=NU({name:"stress:directory-sync:cleanup",usage:"<repo> <handle> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Remove residual smoke directory-sync stress probes",flags:{confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for the cleanup result"}},run:async({args:$,flags:U},J)=>{let G=$[0],I=$[1],q=w0(U,"confirm");if(!G||!I||!q)return nU($2);let Q=J.directorySyncStressCleanupRunner??(await Promise.resolve().then(() => (hN(),WH))).cleanupDirectorySyncStress,D=w0(U,"artifacts-dir"),X=await Q({rootDir:G,handle:I,confirmation:q,...D?{artifactsDir:D}:{},...J.env?{env:J.env}:{},...J.logger?{logger:J.logger}:{}});return{success:X.success,message:`${X.success?"Cleaned":"Failed to clean"} directory-sync stress probes for ${I}; removed ${X.probesRemoved}, remaining ${X.probesRemaining}`}}}),U2=NU({name:"verify-user",usage:"<repo> <handle>",description:"Probe a deployed user's endpoints",run:async({args:$},U)=>{let J=$[0],G=$[1];if(!J||!G)return nU(U2);let I=await h5(J,G,{...U.fetchImpl?{fetchImpl:U.fetchImpl}:{},...U.logger?{logger:U.logger}:{}}),q=I.checks.length>0?I.checks.join(", "):"none";if(I.failedChecks.length>0){let Q=I.failedChecks.map((D)=>` ${D.name}: ${D.message}`).join(`
|
|
496
496
|
`);return{success:!1,message:`Verified ${I.handle} (${I.bundles.join(",")}) at https://${I.domain}: passed ${q}; failed:
|
|
497
497
|
${Q}`}}return{success:!0,message:`Verified ${I.handle} (${I.bundles.join(",")}) at https://${I.domain}: ${q}`}}}),J2=NU({name:"reconcile-cohort",usage:"<repo> <cohort>",description:"Reconcile all users in a cohort",run:async({args:$},U)=>{let J=$[0],G=$[1];if(!J||!G)return nU(J2);return await f7(J,G,U.runner,{...U.env?{env:U.env}:{}}),{success:!0,message:`Reconciled cohort ${G}`}}});function hE($,U){return[$,...U.length===0?["- (none)"]:U.map((J)=>`- ${J}`)]}var I2=NU({name:"reconcile-all",usage:"<repo> [--dry-run]",description:"Reconcile every cohort",flags:{"dry-run":RH},run:async({args:$,flags:U},J)=>{let G=$[0];if(!G)return nU(I2);if(iD(U,"dry-run")){let I=await xP(G),q=I.firstPassChangedFiles.length,Q=I.secondPassChangedFiles.length;return{success:Q===0,message:[`Dry-run reconcile found ${q} first-pass changed file(s); second pass ${Q===0?"converged with zero drift":`still changed ${Q} file(s)`}`,...hE("First-pass changed files:",I.firstPassChangedFiles),...hE("Second-pass changed files:",I.secondPassChangedFiles)].join(`
|
|
498
498
|
`)}}return await X6(G,J.runner,{...J.env?{env:J.env}:{}}),{success:!0,message:"Reconciled all cohorts"}}}),Jt=NU({name:"help",description:"Show this help message",run:()=>({success:!0,message:VK({cliName:rE,intro:"brains-ops \u2014 operator CLI for private brain fleet repos",commands:rN,globalFlags:ZH})})}),It=NU({name:"version",description:"Show version",run:()=>({success:!0,message:`brains-ops ${K4.version}`})}),ZH={help:{type:"boolean",short:"h",description:"Show help"},version:{type:"boolean",short:"v",description:"Show version"}},rN=[lE,iE,pE,dE,nE,cE,oE,aE,tE,sE,eE,$2,U2,J2,I2,Jt,It],Gt=RK(rN);async function qt($,U={}){let J=Gt.get($.command);if(!J)return{success:!1,message:`Unknown command: ${$.command}`};return J.run({args:$.args,flags:$.flags},U)}function Qt($){return NK($,{commands:rN,globalFlags:ZH})}QH();hN();Xq();export{uI as writeUsersTable,h5 as verifyPilotUser,SE as stressMetricsFailure,vz as sitePackagesFor,uZ as siteImageTag,mN as sampleStressHealth,N3 as runResolveMissingImages,lX as runPilotSshKeyBootstrap,b5 as runPilotCertBootstrap,C5 as runPilotAgeKeyBootstrap,qH as runDirectorySyncStressPlan,FE as runDeployedDirectorySyncStress,qt as runCommand,bz as resolveImageBuilds,GH as resolveDirectorySyncStressPlan,Fz as requiredImages,f7 as reconcileCohort,X6 as reconcileAll,y5 as pushPilotSecrets,Dq as pilotSchema,Qt as parseArgs,m7 as onboardUser,VU as loadPilotRegistry,bZ as initPilotRepo,rq as extractAgeIdentity,x5 as encryptPilotSecrets,LE as directorySyncStressReportSchema,z4 as directorySyncStressProfileSchema,IH as directorySyncStressPlanSchema,Fk as derivePreviewDomain,hJ as cohortSchema,bE as cleanupDirectorySyncStress,Az as canonicalBundleIdSchema,f5 as bootstrapPilotSshKey,vP as bootstrapPilotOriginCertificate,gP as bootstrapPilotAgeKey,xN as assertDirectorySyncStressTarget,y7 as addPilotUser};
|
package/package.json
CHANGED
|
@@ -37,7 +37,7 @@ When a push changes only deploy contract files, CI prints `No affected user conf
|
|
|
37
37
|
## Commands
|
|
38
38
|
|
|
39
39
|
- `brains-ops init <repo>`
|
|
40
|
-
- `brains-ops render <repo>` — regenerates `views/users.md` with live DNS, `/health`, and unauthenticated `/mcp` status checks
|
|
40
|
+
- `brains-ops render <repo>` — regenerates `views/users.md` with live DNS, `/health/ready`, and unauthenticated `/mcp` status checks
|
|
41
41
|
- `brains-ops user:add <repo> <handle> --cohort <cohort>` — scaffolds a user file, per-user secrets template, and cohort membership
|
|
42
42
|
- `brains-ops onboard <repo> <handle>` — creates/seeds the user's content repo with separate admin and sync tokens
|
|
43
43
|
- `brains-ops age-key:bootstrap <repo>`
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
11. Commit and push `users/<handle>.secrets.yaml.age`.
|
|
25
25
|
12. Run `bunx brains-ops onboard <repo> <handle>`.
|
|
26
26
|
13. Verify the deployed canonical contract:
|
|
27
|
-
- `https://<handle>.rizom.ai/health` returns `200`
|
|
27
|
+
- `https://<handle>.rizom.ai/health/operate` returns `200`
|
|
28
28
|
- `https://<handle>.rizom.ai/chat` loads the web chat and accepts passkey sign-in
|
|
29
29
|
- unauthenticated `POST https://<handle>.rizom.ai/mcp` returns the expected auth failure
|
|
30
30
|
- content repo exists and runtime sync is healthy
|
|
@@ -51,7 +51,7 @@ Before the window, record and review:
|
|
|
51
51
|
- the exact unified `@rizom/brain` and `@rizom/ops` versions;
|
|
52
52
|
- every unified image tag and immutable digest;
|
|
53
53
|
- canary-first rollout order, followed by the remaining cohorts;
|
|
54
|
-
- expected `/health` version, unauthenticated MCP response, site marker, and content repository identity for each posture.
|
|
54
|
+
- expected `/health/operate` version, unauthenticated MCP response, site marker, and content repository identity for each posture.
|
|
55
55
|
|
|
56
56
|
Run `bunx brains-ops reconcile-all <canonical-review-copy> --dry-run` against the isolated review copy. The command blocks external content-repository access, leaves the review copy untouched, lists both passes' changed files, and must report second-pass zero drift. Reconciliation owns generated per-user config; only `render` owns the observational `views/users.md` projection.
|
|
57
57
|
|
|
@@ -65,7 +65,7 @@ During the approved window:
|
|
|
65
65
|
6. Enable Deploy and deploy one handle at a time in the approved order. After each deploy, run `bunx brains-ops verify-user . <handle>`, render observed fleet status, and complete the manual identity, content-sync, and app-managed site checks.
|
|
66
66
|
7. Run Reconcile a second time. Require no reconciler-owned generated diff and no deploy work before re-enabling normal automation and lifting the merge/release freeze. Observed status rendering remains separate from this convergence gate.
|
|
67
67
|
|
|
68
|
-
If any gate fails, disable all three workflows again. Restore the prior pilot desired-state and dependency revision, reconcile with the prior ops version, and redeploy the prior image tag/digest as one rollback pair. Verify the prior `/health` version and identity/content/site checks before re-enabling automation. Never restore only config or only an image.
|
|
68
|
+
If any gate fails, disable all three workflows again. Restore the prior pilot desired-state and dependency revision, reconcile with the prior ops version, and redeploy the prior image tag/digest as one rollback pair. Verify the prior `/health/operate` version and identity/content/site checks before re-enabling automation. Never restore only config or only an image.
|
|
69
69
|
|
|
70
70
|
## Directory-sync stress gate
|
|
71
71
|
|
|
@@ -130,7 +130,7 @@ bunx brains-ops verify-user . <handle>
|
|
|
130
130
|
|
|
131
131
|
For every bundle posture it checks:
|
|
132
132
|
|
|
133
|
-
- `https://<handle>.rizom.ai/health` returns `200`;
|
|
133
|
+
- `https://<handle>.rizom.ai/health/operate` returns `200`;
|
|
134
134
|
- unauthenticated `POST https://<handle>.rizom.ai/mcp` returns the expected auth failure;
|
|
135
135
|
- background jobs are not repeatedly failing, except for missing optional integrations.
|
|
136
136
|
|