@rizom/ops 0.2.0-alpha.332 → 0.2.0-alpha.334
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/brains-ops.js +2 -2
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/templates/rover-pilot/deploy/scripts/decrypt-user-secrets.ts +2 -2
- package/templates/rover-pilot/docs/onboarding-checklist.md +2 -2
- package/templates/rover-pilot/docs/operator-playbook.md +6 -6
- package/templates/rover-pilot/docs/user-onboarding.md +5 -5
package/dist/index.js
CHANGED
|
@@ -719,7 +719,7 @@ printf 'REMOTE_ARTIFACT_DIR=%s\\n' "$remote_dir"
|
|
|
719
719
|
`),o}async function yB(e,t){let n=await ut(e),i=n.users.find((r)=>r.handle===t);if(!i)throw Error(`Unknown pilot user: ${t}`);return{pilot:n.pilot,user:i}}async function bB(e){let t=await Ose(ur(Rse(),"brains-ops-watchdog-smoke-")),n=ur(t,"id_ed25519"),i=ur(t,"known_hosts");try{let r=encodeURIComponent(`brain=${e.target.pilot.contentRepoPrefix}${e.target.user.handle}`),o=await e.fetchImpl(`https://api.hetzner.cloud/v1/servers?label_selector=${r}`,{headers:{Authorization:`Bearer ${e.environment.HCLOUD_TOKEN}`}});if(!o.ok)throw Error(`Hetzner server lookup failed with ${o.status}`);let s=Pse.parse(await o.json());if(s.servers.length!==1)throw Error(`Expected one smoke server, found ${s.servers.length}`);let a=s.servers[0];if(a?.status!=="running")throw Error("Smoke server is not running");await Da(n,zse(e.environment.KAMAL_SSH_PRIVATE_KEY),{mode:384}),await Cse(n,384);let c=await e.commandRunner("ssh-keyscan",["-T","10","-t","ed25519",a.public_net.ipv4.ip]);if(c.exitCode!==0||!c.stdout.trim())throw Error("Unable to resolve watchdog smoke SSH host key");return await Da(i,c.stdout,{mode:384}),{temporaryRoot:t,sshKeyPath:n,knownHostsPath:i,serverIp:a.public_net.ipv4.ip,commandRunner:e.commandRunner}}catch(r){throw await H_(t,{recursive:!0,force:!0}),r}}async function Z_(e,t,n){return e.commandRunner("ssh",[...xB(e),`root@${e.serverIp}`,"bash","-s","--",t,n],{stdin:K_()})}async function Nse(e,t,n){return e.commandRunner("scp",[...xB(e),"-r",`root@${e.serverIp}:${t}/.`,n])}function xB(e){return["-i",e.sshKeyPath,"-o","BatchMode=yes","-o","IdentitiesOnly=yes","-o","ConnectTimeout=10","-o","StrictHostKeyChecking=yes","-o",`UserKnownHostsFile=${e.knownHostsPath}`]}async function Dse(e){try{return await Tse(e),!0}catch{return!1}}async function Hm(e,t,n){await Promise.all([Da(ur(e,`${t}.stdout.log`),n.stdout),Da(ur(e,`${t}.stderr.log`),n.stderr)])}function zse(e){return`${e.replace(/\r\n/g,`
|
|
720
720
|
`).replace(/\\n/g,`
|
|
721
721
|
`).trimEnd()}
|
|
722
|
-
`}var mB,Pse;var Vm=se(async()=>{Ne();uB();Yn();su();await lB();mB=h.object({HCLOUD_TOKEN:h.string().min(1),KAMAL_SSH_PRIVATE_KEY:h.string().min(1)}),Pse=h.object({servers:h.array(h.object({status:h.string(),public_net:h.object({ipv4:h.object({ip:h.string().min(1)})})}))})});import{access as dT,chmod as jv,mkdir as td,readFile as mT,writeFile as pT}from"fs/promises";import{dirname as zF,join as As}from"path";import{fileURLToPath as LF}from"url";var fu={name:"@rizom/ops",version:"0.2.0-alpha.
|
|
722
|
+
`}var mB,Pse;var Vm=se(async()=>{Ne();uB();Yn();su();await lB();mB=h.object({HCLOUD_TOKEN:h.string().min(1),KAMAL_SSH_PRIVATE_KEY:h.string().min(1)}),Pse=h.object({servers:h.array(h.object({status:h.string(),public_net:h.object({ipv4:h.object({ip:h.string().min(1)})})}))})});import{access as dT,chmod as jv,mkdir as td,readFile as mT,writeFile as pT}from"fs/promises";import{dirname as zF,join as As}from"path";import{fileURLToPath as LF}from"url";var fu={name:"@rizom/ops",version:"0.2.0-alpha.334",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/profile":"workspace:*","@brains/site-composition":"workspace:*","@brains/test-utils":"workspace:*","@brains/typescript-config":"workspace:*","@brains/utils":"workspace:*","@types/bun":"^1.4.0",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"};zi();Cc();var BF=["pilot.yaml","package.json",".env.schema",".gitignore","cohorts/cohort-1.yaml","users/alice.yaml",".github/actions/varlock-env/action.yml",".github/workflows/build.yml",".github/workflows/deploy.yml",".github/workflows/directory-sync-stress.yml",".github/workflows/health-watchdog-smoke.yml",".github/workflows/reconcile.yml",".github/workflows/upgrade.yml","deploy/Dockerfile","deploy/kamal/deploy.yml","deploy/scripts/helpers.ts","deploy/scripts/install-health-watchdog.ts","deploy/scripts/provision-server.ts","deploy/scripts/update-dns.ts","deploy/scripts/write-ssh-key.ts","deploy/scripts/decrypt-user-secrets.ts","deploy/scripts/validate-secrets.ts","deploy/scripts/write-kamal-secrets.ts","deploy/scripts/resolve-user-config.ts","deploy/scripts/resolve-missing-images.ts","deploy/scripts/resolve-deploy-handles.ts","deploy/scripts/sync-content-repo.ts",".kamal/hooks/pre-deploy","docs/onboarding-checklist.md","docs/canonical-crossover-record.md","docs/operator-playbook.md","docs/user-onboarding.md","README.md"],Fv=new Set([".kamal/hooks/pre-deploy"]),UF=new Set(["cohorts/cohort-1.yaml","users/alice.yaml","docs/canonical-crossover-record.md"]),jF=LF(new URL("../templates/rover-pilot/",import.meta.url)),FF=[`service: rover
|
|
723
723
|
image: <%= ENV['IMAGE_REPOSITORY'] %>
|
|
724
724
|
|
|
725
725
|
servers:
|
|
@@ -802,7 +802,7 @@ users/*.secrets.yaml
|
|
|
802
802
|
`}var pK=/\r?\n|\r/g;function kR(e,t){let n=[],i=0,r=0,o;while(o=pK.exec(e))s(e.slice(i,o.index)),n.push(o[0]),i=o.index+o[0].length,r++;return s(e.slice(i)),n.join("");function s(a){n.push(t(a,r,!a))}}function ER(e,t,n){let i=(n.before||"")+(t||"")+(n.after||""),r=[],o=[],s={},a=-1;while(++a<e.unsafe.length){let u=e.unsafe[a];if(!Pd(e.stack,u))continue;let f=e.compilePattern(u),d;while(d=f.exec(i)){let p="before"in u||Boolean(u.atBreak),b="after"in u,g=d.index+(p?d[1].length:0);if(r.includes(g)){if(s[g].before&&!p)s[g].before=!1;if(s[g].after&&!b)s[g].after=!1}else r.push(g),s[g]={before:p,after:b}}}r.sort(mK);let c=n.before?n.before.length:0,l=i.length-(n.after?n.after.length:0);a=-1;while(++a<r.length){let u=r[a];if(u<c||u>=l)continue;if(u+1<l&&r[a+1]===u+1&&s[u].after&&!s[u+1].before&&!s[u+1].after||r[a-1]===u-1&&s[u].before&&!s[u-1].before&&!s[u-1].after)continue;if(c!==u)o.push(_R(i.slice(c,u),"\\"));if(c=u,/[!-/:-@[-`{-~]/.test(i.charAt(u))&&(!n.encode||!n.encode.includes(i.charAt(u))))o.push("\\");else o.push(hn(i.charCodeAt(u))),c++}return o.push(_R(i.slice(c,l),n.after)),o.join("")}function mK(e,t){return e-t}function _R(e,t){let n=/\\(?=[!-/:-@[-`{-~])/g,i=[],r=[],o=e+t,s=-1,a=0,c;while(c=n.exec(o))i.push(c.index);while(++s<i.length){if(a!==i[s])r.push(e.slice(a,i[s]));r.push("\\"),a=i[s]}return r.push(e.slice(a)),r.join("")}function $R(e){let t=e||{},n=t.now||{},i=t.lineShift||0,r=n.line||1,o=n.column||1;return{move:c,current:s,shift:a};function s(){return{now:{line:r,column:o},lineShift:i}}function a(l){i+=l}function c(l){let u=l||"",f=u.split(/\r?\n|\r/g),d=f[f.length-1];return r+=f.length-1,o=f.length===1?o+d.length:1+d.length+i,u}}function QS(e,t){let n=t||{},i={associationId:xR,containerPhrasing:bK,containerFlow:xK,createTracker:$R,compilePattern:vR,enter:o,handlers:{...gR},handle:void 0,indentLines:kR,indexStack:[],join:[...yR],options:{},safe:vK,stack:[],unsafe:[...bR]};if(US(i,n),i.options.tightDefinitions)i.join.push(yK);i.handle=VO("type",{invalid:hK,unknown:gK,handlers:i.handlers});let r=i.handle(e,void 0,i,{before:`
|
|
803
803
|
`,after:`
|
|
804
804
|
`,now:{line:1,column:1},lineShift:0});if(r&&r.charCodeAt(r.length-1)!==10&&r.charCodeAt(r.length-1)!==13)r+=`
|
|
805
|
-
`;return r;function o(s){return i.stack.push(s),a;function a(){i.stack.pop()}}}function hK(e){throw Error("Cannot handle value `"+e+"`, expected node")}function gK(e){throw Error("Cannot handle unknown node `"+e.type+"`")}function yK(e,t){if(e.type==="definition"&&e.type===t.type)return 0}function bK(e,t){return SR(e,this,t)}function xK(e,t){return wR(e,this,t)}function vK(e,t){return ER(this,e,t)}function Ud(e){let t=this;t.compiler=n;function n(i){return QS(i,{...t.data("settings"),...e,extensions:t.data("toMarkdownExtensions")||[]})}}function ew(e){if(e)throw e}var Zd=Wm(DR(),1);function Vc(e){if(typeof e!=="object"||e===null)return!1;let t=Object.getPrototypeOf(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)}function tw(){let e=[],t={run:n,use:i};return t;function n(...r){let o=-1,s=r.pop();if(typeof s!=="function")throw TypeError("Expected function as last argument, not "+s);a(null,...r);function a(c,...l){let u=e[++o],f=-1;if(c){s(c);return}while(++f<r.length)if(l[f]===null||l[f]===void 0)l[f]=r[f];if(r=l,u)zR(u,a)(...l);else s(null,...l)}}function i(r){if(typeof r!=="function")throw TypeError("Expected `middelware` to be a function, not "+r);return e.push(r),t}}function zR(e,t){let n;return i;function i(...s){let a=e.length>s.length,c;if(a)s.push(r);try{c=e.apply(this,s)}catch(l){let u=l;if(a&&n)throw u;return r(u)}if(!a)if(c&&c.then&&typeof c.then==="function")c.then(o,r);else if(c instanceof Error)r(c);else o(c)}function r(s,...a){if(!n)n=!0,t(s,...a)}function o(s){r(null,s)}}class wt extends Error{constructor(e,t,n){super();if(typeof t==="string")n=t,t=void 0;let i="",r={},o=!1;if(t)if("line"in t&&"column"in t)r={place:t};else if("start"in t&&"end"in t)r={place:t};else if("type"in t)r={ancestors:[t],place:t.position};else r={...t};if(typeof e==="string")i=e;else if(!r.cause&&e)o=!0,i=e.message,r.cause=e;if(!r.ruleId&&!r.source&&typeof n==="string"){let a=n.indexOf(":");if(a===-1)r.ruleId=n;else r.source=n.slice(0,a),r.ruleId=n.slice(a+1)}if(!r.place&&r.ancestors&&r.ancestors){let a=r.ancestors[r.ancestors.length-1];if(a)r.place=a.position}let s=r.place&&"start"in r.place?r.place.start:r.place;this.ancestors=r.ancestors||void 0,this.cause=r.cause||void 0,this.column=s?s.column:void 0,this.fatal=void 0,this.file="",this.message=i,this.line=s?s.line:void 0,this.name=ii(r.place)||"1:1",this.place=r.place||void 0,this.reason=this.message,this.ruleId=r.ruleId||void 0,this.source=r.source||void 0,this.stack=o&&r.cause&&typeof r.cause.stack==="string"?r.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}wt.prototype.file="";wt.prototype.name="";wt.prototype.reason="";wt.prototype.message="";wt.prototype.stack="";wt.prototype.column=void 0;wt.prototype.line=void 0;wt.prototype.ancestors=void 0;wt.prototype.cause=void 0;wt.prototype.fatal=void 0;wt.prototype.place=void 0;wt.prototype.ruleId=void 0;wt.prototype.source=void 0;import{default as Nn}from"path";import{default as LR}from"process";import{fileURLToPath as BR}from"url";function Fd(e){return Boolean(e!==null&&typeof e==="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}var nw=["history","path","basename","stem","extname","dirname"];class Md{constructor(e){let t;if(!e)t={};else if(Fd(e))t={path:e};else if(typeof e==="string"||SK(e))t={value:e};else t=e;this.cwd="cwd"in t?"":LR.cwd(),this.data={},this.history=[],this.messages=[],this.value,this.map,this.result,this.stored;let n=-1;while(++n<nw.length){let r=nw[n];if(r in t&&t[r]!==void 0&&t[r]!==null)this[r]=r==="history"?[...t[r]]:t[r]}let i;for(i in t)if(!nw.includes(i))this[i]=t[i]}get basename(){return typeof this.path==="string"?Nn.basename(this.path):void 0}set basename(e){iw(e,"basename"),rw(e,"basename"),this.path=Nn.join(this.dirname||"",e)}get dirname(){return typeof this.path==="string"?Nn.dirname(this.path):void 0}set dirname(e){UR(this.basename,"dirname"),this.path=Nn.join(e||"",this.basename)}get extname(){return typeof this.path==="string"?Nn.extname(this.path):void 0}set extname(e){if(rw(e,"extname"),UR(this.dirname,"extname"),e){if(e.codePointAt(0)!==46)throw Error("`extname` must start with `.`");if(e.includes(".",1))throw Error("`extname` cannot contain multiple dots")}this.path=Nn.join(this.dirname,this.stem+(e||""))}get path(){return this.history[this.history.length-1]}set path(e){if(Fd(e))e=BR(e);if(iw(e,"path"),this.path!==e)this.history.push(e)}get stem(){return typeof this.path==="string"?Nn.basename(this.path,this.extname):void 0}set stem(e){iw(e,"stem"),rw(e,"stem"),this.path=Nn.join(this.dirname||"",e+(this.extname||""))}fail(e,t,n){let i=this.message(e,t,n);throw i.fatal=!0,i}info(e,t,n){let i=this.message(e,t,n);return i.fatal=void 0,i}message(e,t,n){let i=new wt(e,t,n);if(this.path)i.name=this.path+":"+i.name,i.file=this.path;return i.fatal=!1,this.messages.push(i),i}toString(e){if(this.value===void 0)return"";if(typeof this.value==="string")return this.value;return new TextDecoder(e||void 0).decode(this.value)}}function rw(e,t){if(e&&e.includes(Nn.sep))throw Error("`"+t+"` cannot be a path: did not expect `"+Nn.sep+"`")}function iw(e,t){if(!e)throw Error("`"+t+"` cannot be empty")}function UR(e,t){if(!e)throw Error("Setting `"+t+"` requires `path` to be set too")}function SK(e){return Boolean(e&&typeof e==="object"&&"byteLength"in e&&"byteOffset"in e)}var jR=function(e){let i=this.constructor.prototype,r=i[e],o=function(){return r.apply(o,arguments)};return Object.setPrototypeOf(o,i),o};var wK={}.hasOwnProperty;class cw extends jR{constructor(){super("copy");this.Compiler=void 0,this.Parser=void 0,this.attachers=[],this.compiler=void 0,this.freezeIndex=-1,this.frozen=void 0,this.namespace={},this.parser=void 0,this.transformers=tw()}copy(){let e=new cw,t=-1;while(++t<this.attachers.length){let n=this.attachers[t];e.use(...n)}return e.data(Zd.default(!0,{},this.namespace)),e}data(e,t){if(typeof e==="string"){if(arguments.length===2)return aw("data",this.frozen),this.namespace[e]=t,this;return wK.call(this.namespace,e)&&this.namespace[e]||void 0}if(e)return aw("data",this.frozen),this.namespace=e,this;return this.namespace}freeze(){if(this.frozen)return this;let e=this;while(++this.freezeIndex<this.attachers.length){let[t,...n]=this.attachers[this.freezeIndex];if(n[0]===!1)continue;if(n[0]===!0)n[0]=void 0;let i=t.call(e,...n);if(typeof i==="function")this.transformers.use(i)}return this.frozen=!0,this.freezeIndex=Number.POSITIVE_INFINITY,this}parse(e){this.freeze();let t=qd(e),n=this.parser||this.Parser;return ow("parse",n),n(String(t),t)}process(e,t){let n=this;return this.freeze(),ow("process",this.parser||this.Parser),sw("process",this.compiler||this.Compiler),t?i(void 0,t):new Promise(i);function i(r,o){let s=qd(e),a=n.parse(s);n.run(a,s,function(l,u,f){if(l||!u||!f)return c(l);let d=u,p=n.stringify(d,f);if(_K(p))f.value=p;else f.result=p;c(l,f)});function c(l,u){if(l||!u)o(l);else if(r)r(u);else L(t,"`done` is defined if `resolve` is not"),t(void 0,u)}}}processSync(e){let t=!1,n;return this.freeze(),ow("processSync",this.parser||this.Parser),sw("processSync",this.compiler||this.Compiler),this.process(e,i),MR("processSync","process",t),L(n,"we either bailed on an error or have a tree"),n;function i(r,o){t=!0,ew(r),n=o}}run(e,t,n){FR(e),this.freeze();let i=this.transformers;if(!n&&typeof t==="function")n=t,t=void 0;return n?r(void 0,n):new Promise(r);function r(o,s){L(typeof t!=="function","`file` can\u2019t be a `done` anymore, we checked");let a=qd(t);i.run(e,a,c);function c(l,u,f){let d=u||e;if(l)s(l);else if(o)o(d);else L(n,"`done` is defined if `resolve` is not"),n(void 0,d,f)}}}runSync(e,t){let n=!1,i;return this.run(e,t,r),MR("runSync","run",n),L(i,"we either bailed on an error or have a tree"),i;function r(o,s){ew(o),i=s,n=!0}}stringify(e,t){this.freeze();let n=qd(t),i=this.compiler||this.Compiler;return sw("stringify",i),FR(e),i(e,n)}use(e,...t){let n=this.attachers,i=this.namespace;if(aw("use",this.frozen),e===null||e===void 0);else if(typeof e==="function")a(e,t);else if(typeof e==="object")if(Array.isArray(e))s(e);else o(e);else throw TypeError("Expected usable value, not `"+e+"`");return this;function r(c){if(typeof c==="function")a(c,[]);else if(typeof c==="object")if(Array.isArray(c)){let[l,...u]=c;a(l,u)}else o(c);else throw TypeError("Expected usable value, not `"+c+"`")}function o(c){if(!("plugins"in c)&&!("settings"in c))throw Error("Expected usable value but received an empty preset, which is probably a mistake: presets typically come with `plugins` and sometimes with `settings`, but this has neither");if(s(c.plugins),c.settings)i.settings=Zd.default(!0,i.settings,c.settings)}function s(c){let l=-1;if(c===null||c===void 0);else if(Array.isArray(c))while(++l<c.length){let u=c[l];r(u)}else throw TypeError("Expected a list of plugins, not `"+c+"`")}function a(c,l){let u=-1,f=-1;while(++u<n.length)if(n[u][0]===c){f=u;break}if(f===-1)n.push([c,...l]);else if(l.length>0){let[d,...p]=l,b=n[f][1];if(Vc(b)&&Vc(d))d=Zd.default(!0,b,d);n[f]=[c,d,...p]}}}}var lw=new cw().freeze();function ow(e,t){if(typeof t!=="function")throw TypeError("Cannot `"+e+"` without `parser`")}function sw(e,t){if(typeof t!=="function")throw TypeError("Cannot `"+e+"` without `compiler`")}function aw(e,t){if(t)throw Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function FR(e){if(!Vc(e)||typeof e.type!=="string")throw TypeError("Expected node, got `"+e+"`")}function MR(e,t,n){if(!n)throw Error("`"+e+"` finished async. Use `"+t+"` instead")}function qd(e){return kK(e)?e:new Md(e)}function kK(e){return Boolean(e&&typeof e==="object"&&"message"in e&&"messages"in e)}function _K(e){return typeof e==="string"||EK(e)}function EK(e){return Boolean(e&&typeof e==="object"&&"byteLength"in e&&"byteOffset"in e)}var qR=lw().use(Rd).use(Ud).freeze();var ove=qR();Ne();var ZR=h.object({audiences:h.array(h.string()).optional(),positioning:h.string().optional()}),HR=h.object({summary:h.string().optional(),traits:h.array(h.string()).optional(),principles:h.array(h.string()).optional(),preferredTerms:h.array(h.string()).optional(),avoid:h.array(h.string()).optional()}),KR=h.object({artDirection:h.string().optional(),palette:h.array(h.string()).optional(),composition:h.string().optional(),mood:h.string().optional(),preferred:h.array(h.string()).optional(),avoid:h.array(h.string()).optional()}),AK=h.object({name:h.string().describe("Style guide name"),messaging:ZR.optional(),voice:HR.optional(),visual:KR.optional()});Ne();var TK=h.object({id:h.string().min(1),trigger:h.string().min(1),playbookId:h.string().min(1),once:h.boolean().default(!0),starterText:h.string().min(1),description:h.string().min(1).optional(),starterPrompt:h.string().min(1)}).strict();Ne();var CK=h.object({message:h.string().describe("Natural language response to the query"),summary:h.string().optional().describe("Brief summary if applicable"),topics:h.array(h.string()).optional().describe("Related topics mentioned"),sources:h.array(h.object({id:h.string(),type:h.string(),excerpt:h.string().optional(),relevance:h.number().min(0).max(1).optional()})).optional().describe("Source entities used to answer the query"),metadata:h.record(h.string(),h.unknown()).optional()}).describe("defaultQueryResponse"),OK=h.object({message:h.string()}).describe("simpleTextResponse"),VR=h.object({success:h.boolean(),entityId:h.string().optional(),message:h.string()}).describe("createEntityResponse"),GR=h.object({success:h.boolean(),entityId:h.string(),changes:h.array(h.string()).optional(),message:h.string()}).describe("updateEntityResponse");Ne();var YR=h.discriminatedUnion("type",[h.strictObject({type:h.literal("email"),address:h.email()})]),RK=h.strictObject({recipient:YR.optional(),title:h.string().min(1),body:h.string().min(1),html:h.string().min(1).optional(),sensitivity:h.enum(["normal","secret"]).default("normal"),idempotencyKey:h.string().trim().min(1).max(200).optional()}),PK=h.discriminatedUnion("status",[h.strictObject({status:h.literal("sent"),deliveryId:h.string().optional()}),h.strictObject({status:h.literal("failed")})]);Ne();var HSe=h.record(h.string(),h.unknown());Ne();hu();var GSe=h.record(h.string(),h.unknown());hu();Ne();var MK=h.object({slug:h.string(),title:h.string(),type:h.string(),entityId:h.string(),contentHash:h.string()});Ne();Ne();Ne();var qK=rd.omit({url:!0,analyticsScript:!0}),ZK=qK.extend({title:h.string().optional().describe("Optional site title override"),description:h.string().optional().describe("Optional site description override")});function fw(e,t={}){let n=WR(e),i=WR(t.sharedDomain??"rizom.ai").replace(/^\./,""),r=`.${i}`;if(n.endsWith(r)){let o=n.slice(0,-r.length);if(o.length>0&&!o.includes("."))return`${o}-preview.${i}`}return`preview.${n}`}function WR(e){return e.trim().replace(/^https?:\/\//i,"").replace(/\/$/,"").toLowerCase()}Ne();zv();var XR=["primary","secondary"];var HK=h.custom((e)=>typeof e==="function","Expected a Preact component"),KK=h.strictObject({show:h.boolean().optional(),label:h.string().min(1).optional(),slot:h.enum(XR).optional(),priority:h.number().optional()}),VK=h.strictObject({id:h.string().min(1),template:h.string().min(1),content:h.unknown().optional(),dataQuery:h.looseObject({entityType:h.string().optional(),template:h.string().optional(),query:h.record(h.string(),h.unknown()).optional()}).optional(),order:h.number().optional()}),GK=h.strictObject({id:h.string().min(1),path:h.string().startsWith("/"),title:h.string().optional(),pageLabel:h.string().optional(),description:h.string().optional(),sections:h.array(VK).optional(),layout:h.string().min(1).optional(),fullscreen:h.boolean().optional(),pluginId:h.string().optional(),sourceEntityType:h.string().optional(),external:h.boolean().optional(),navigation:KK.optional()}),YK=h.strictObject({label:h.string().min(1),pluralName:h.string().min(1).optional(),layout:h.string().min(1).optional(),paginate:h.boolean().optional(),pageSize:h.number().int().positive().optional(),navigation:h.strictObject({show:h.boolean().optional(),slot:h.enum(XR).optional(),priority:h.number().optional()}).optional()}),WK=h.strictObject({schema:h.custom((e)=>e instanceof h.ZodType,"Expected a Zod schema"),component:h.custom((e)=>typeof e==="function","Expected a Preact component"),title:h.string().min(1),description:h.string(),requiredPermission:h.enum(["admin","trusted","public"]).optional(),fullscreen:h.boolean().optional()}),JR=h.strictObject({namespace:h.string().min(1),sections:h.record(h.string(),WK)}),JK=h.record(h.string(),h.json()),XK=h.record(h.string(),h.record(h.string(),JK)),QR=h.strictObject({layouts:h.record(h.string(),HK).refine((e)=>typeof e.default==="function",{message:'Site layouts must include a "default" component'}),routes:h.array(GK),content:XK.optional(),sections:h.union([JR,h.array(JR)]).optional(),themeOverride:h.string().optional(),headScripts:h.array(h.string()).optional(),entityDisplay:h.record(h.string(),YK),staticAssets:h.record(h.string(),h.string()).optional()}).superRefine((e,t)=>{let n=new Set;for(let[o,s]of e.routes.entries()){if(n.has(s.id))t.addIssue({code:"custom",path:["routes",o,"id"],message:`Duplicate route id "${s.id}"`});n.add(s.id);let a=s.layout??"default";if(!e.layouts[a])t.addIssue({code:"custom",path:["routes",o,"layout"],message:`Unknown layout "${a}"`})}let i=Array.isArray(e.sections)?e.sections:e.sections?[e.sections]:[],r=new Map(i.map((o)=>[o.namespace,o]));if(r.size!==i.length)t.addIssue({code:"custom",path:["sections"],message:"Section group namespaces must be unique"});for(let[o,s]of Object.entries(e.content??{})){let a=r.get(o);if(!a){t.addIssue({code:"custom",path:["content",o],message:`Content namespace "${o}" has no section group`});continue}for(let[c,l]of Object.entries(s)){let u=a.sections[c];if(!u){t.addIssue({code:"custom",path:["content",o,c],message:`Content section "${o}.${c}" is not defined`});continue}let f=u.schema.safeParse(l);if(!f.success)t.addIssue({code:"custom",path:["content",o,c],message:`Content does not satisfy the "${o}.${c}" schema: ${h.prettifyError(f.error)}`})}}});var QK=h.string();function e7(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}var t7=h.custom((e)=>{if(!e7(e))return!1;let{plugin:t,...n}=e;if(t!==void 0&&typeof t!=="function")return!1;return QR.safeParse(n).success});function n7(e,t={}){return fw(e,t)}Cc();import{mkdir as _7,writeFile as E7}from"fs/promises";import{dirname as $7,join as cP}from"path";zi();import{mkdtemp as r7,mkdir as i7,readFile as o7,rm as s7,writeFile as a7}from"fs/promises";import{tmpdir as c7}from"os";import{dirname as l7,join as rP}from"path";var u7=["name: Your Name Here","Delete this and write your own"];async function iP(e,t,n,i,r={}){if(i.length===0)return;let o=r.env??process.env,s=Rn(e),a=tP(o,s,n.effectiveGitSyncToken),c=r.contentRepoAdminTokenSelector?tP(o,s,r.contentRepoAdminTokenSelector):void 0,l=dw(n.contentRepo,t),u=r.contentRepoRemoteResolver?.(n,t,a)??p7(l,a);if(!u)return;let f=await r7(rP(c7(),`brains-ops-content-sync-${n.handle}-`)),d=r.runCommand??qt,p=r.fetchImpl??fetch;try{if(!r.contentRepoRemoteResolver){if(!c)throw Error(`${r.contentRepoAdminTokenSelector??"CONTENT_REPO_ADMIN_TOKEN"} is required to check or create content repos`);await m7(l,c,p)}await d("git",["clone",u,f]),await h7(f,d),await d("git",["config","user.name","brains-ops[bot]"],{cwd:f}),await d("git",["config","user.email","41898282+github-actions[bot]@users.noreply.github.com"],{cwd:f});let b=!1;for(let g of i)if(await f7(f,g))b=!0;if(!b)return;await d("git",["add","."],{cwd:f}),await d("git",["commit","-m",`chore(content): seed ${n.handle} anchor profile`],{cwd:f}),await d("git",["push","origin","HEAD:main"],{cwd:f})}finally{await s7(f,{recursive:!0,force:!0})}}async function f7(e,t){let n=rP(e,t.path),i=await o7(n,"utf8").catch(()=>{return});if(i===t.content)return!1;if(i!==void 0&&!d7(i))return!1;return await i7(l7(n),{recursive:!0}),await a7(n,t.content),!0}function d7(e){return u7.some((t)=>e.includes(t))}function tP(e,t,n){return gt(n,e,t)}function p7(e,t){if(!t)return;return`https://x-access-token:${encodeURIComponent(t)}@github.com/${e.org}/${e.name}.git`}async function m7(e,t,n){let{org:i,name:r}=e,s=`https://api.github.com/repos/${`${encodeURIComponent(i)}/${encodeURIComponent(r)}`}`,a={Accept:"application/vnd.github+json",Authorization:`Bearer ${t}`,"User-Agent":"brains-ops","X-GitHub-Api-Version":"2022-11-28"},c=await n(s,{headers:a});if(c.ok)return;if(c.status!==404)throw Error(`Failed to check GitHub repo ${i}/${r}: ${c.status} ${await nP(c)}`);let l=await n(`https://api.github.com/orgs/${encodeURIComponent(i)}/repos`,{method:"POST",headers:a,body:JSON.stringify({name:r,private:!0,auto_init:!1})});if(l.ok){console.log(`Created missing content repo ${i}/${r}`);return}if(l.status===422){if((await n(s,{headers:a})).ok)return}throw Error(`Failed to create GitHub repo ${i}/${r}: ${l.status} ${await nP(l)}`)}async function nP(e){let t=await e.text();return t.trim().length===0?e.statusText:t}async function h7(e,t){try{await t("git",["checkout","-B","main","origin/main"],{cwd:e})}catch{await t("git",["checkout","-B","main"],{cwd:e})}}pw();Yn();async function Gs(e,t,n,i,r={}){let o=Hd(t.pilot.githubOrg);for(let s of n){let a={};if(i){let d=await i(s);if(d!==void 0)a=d}let c=await o(s),l=a.brainYaml??c.brainYaml,u=a.envFile??c.envFile,f=a.contentRepoFiles??c.contentRepoFiles??[];if(u)await mw(e,s.handle,".env",u);if(l)await mw(e,s.handle,"brain.yaml",l);await iP(e,t.pilot.githubOrg,s,f,{contentRepoAdminTokenSelector:t.pilot.contentRepoAdminToken,...r});for(let d of f)await mw(e,s.handle,cP("content",d.path),d.content)}}async function mw(e,t,n,i){let r=cP(e,"users",t,n);await _7($7(r),{recursive:!0}),await E7(r,i)}async function Kd(e,t){let n=await ut(e),i=n.users.find((r)=>r.handle===t);if(!i)throw Error(`Unknown user handle: ${t}`);return{registry:n,user:i}}async function lP(e,t){let n=await ut(e),i=n.cohorts.find((r)=>r.id===t);if(!i)throw Error(`Unknown cohort: ${t}`);return{registry:n,users:n.users.filter((r)=>r.cohort===i.id)}}async function uP(e){let t=await ut(e);return{registry:t,users:t.users}}async function hw(e,t,n,i={}){let{registry:r,user:o}=await Kd(e,t);await Gs(e,r,[o],n,i)}Ur();Yi();import{access as I7,mkdir as fP,readFile as A7,writeFile as pP}from"fs/promises";import{basename as T7,join as Ys}from"path";async function gw(e,t,n){let i=dn.parse(t),r=dn.parse(n.cohort),o=Ys(e,"users"),s=Ys(e,"cohorts"),a=Ys(o,`${i}.yaml`),c=Ys(o,`${i}.secrets.yaml`),l=Ys(o,`${i}.secrets.yaml.age`),u=Ys(s,`${r}.yaml`);await Promise.all([fP(o,{recursive:!0}),fP(s,{recursive:!0})]);let f=await dP(a,R7(i,n.anchorId)),p=await D7(l)?!1:await dP(c,P7(i)),{addedToCohort:b}=await C7(u,i);return{handle:i,cohort:r,userPath:a,secretsTemplatePath:c,cohortPath:u,createdUser:f,createdSecretsTemplate:p,addedToCohort:b}}async function C7(e,t){let n=await O7(e);if(n.members.includes(t))return{addedToCohort:!1};let i={...n,members:[...n.members,t].sort()};return await pP(e,N7(i)),{addedToCohort:!0}}async function O7(e){try{let t=await A7(e,"utf8"),n=Br(t,Gn);if(!n.ok)throw Error(`${T7(e)}: ${n.error}`);return n.data}catch(t){if(L7(t))return{members:[]};throw t}}function R7(e,t){return[`handle: ${e}`,"anchorProfile:",` name: ${B7(e)}`,"discord:"," enabled: true",...t?[` anchorUserId: ${JSON.stringify(t)}`]:[],""].join(`
|
|
805
|
+
`;return r;function o(s){return i.stack.push(s),a;function a(){i.stack.pop()}}}function hK(e){throw Error("Cannot handle value `"+e+"`, expected node")}function gK(e){throw Error("Cannot handle unknown node `"+e.type+"`")}function yK(e,t){if(e.type==="definition"&&e.type===t.type)return 0}function bK(e,t){return SR(e,this,t)}function xK(e,t){return wR(e,this,t)}function vK(e,t){return ER(this,e,t)}function Ud(e){let t=this;t.compiler=n;function n(i){return QS(i,{...t.data("settings"),...e,extensions:t.data("toMarkdownExtensions")||[]})}}function ew(e){if(e)throw e}var Zd=Wm(DR(),1);function Vc(e){if(typeof e!=="object"||e===null)return!1;let t=Object.getPrototypeOf(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)}function tw(){let e=[],t={run:n,use:i};return t;function n(...r){let o=-1,s=r.pop();if(typeof s!=="function")throw TypeError("Expected function as last argument, not "+s);a(null,...r);function a(c,...l){let u=e[++o],f=-1;if(c){s(c);return}while(++f<r.length)if(l[f]===null||l[f]===void 0)l[f]=r[f];if(r=l,u)zR(u,a)(...l);else s(null,...l)}}function i(r){if(typeof r!=="function")throw TypeError("Expected `middelware` to be a function, not "+r);return e.push(r),t}}function zR(e,t){let n;return i;function i(...s){let a=e.length>s.length,c;if(a)s.push(r);try{c=e.apply(this,s)}catch(l){let u=l;if(a&&n)throw u;return r(u)}if(!a)if(c&&c.then&&typeof c.then==="function")c.then(o,r);else if(c instanceof Error)r(c);else o(c)}function r(s,...a){if(!n)n=!0,t(s,...a)}function o(s){r(null,s)}}class wt extends Error{constructor(e,t,n){super();if(typeof t==="string")n=t,t=void 0;let i="",r={},o=!1;if(t)if("line"in t&&"column"in t)r={place:t};else if("start"in t&&"end"in t)r={place:t};else if("type"in t)r={ancestors:[t],place:t.position};else r={...t};if(typeof e==="string")i=e;else if(!r.cause&&e)o=!0,i=e.message,r.cause=e;if(!r.ruleId&&!r.source&&typeof n==="string"){let a=n.indexOf(":");if(a===-1)r.ruleId=n;else r.source=n.slice(0,a),r.ruleId=n.slice(a+1)}if(!r.place&&r.ancestors&&r.ancestors){let a=r.ancestors[r.ancestors.length-1];if(a)r.place=a.position}let s=r.place&&"start"in r.place?r.place.start:r.place;this.ancestors=r.ancestors||void 0,this.cause=r.cause||void 0,this.column=s?s.column:void 0,this.fatal=void 0,this.file="",this.message=i,this.line=s?s.line:void 0,this.name=ii(r.place)||"1:1",this.place=r.place||void 0,this.reason=this.message,this.ruleId=r.ruleId||void 0,this.source=r.source||void 0,this.stack=o&&r.cause&&typeof r.cause.stack==="string"?r.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}wt.prototype.file="";wt.prototype.name="";wt.prototype.reason="";wt.prototype.message="";wt.prototype.stack="";wt.prototype.column=void 0;wt.prototype.line=void 0;wt.prototype.ancestors=void 0;wt.prototype.cause=void 0;wt.prototype.fatal=void 0;wt.prototype.place=void 0;wt.prototype.ruleId=void 0;wt.prototype.source=void 0;import{default as Nn}from"path";import{default as LR}from"process";import{fileURLToPath as BR}from"url";function Fd(e){return Boolean(e!==null&&typeof e==="object"&&"href"in e&&e.href&&"protocol"in e&&e.protocol&&e.auth===void 0)}var nw=["history","path","basename","stem","extname","dirname"];class Md{constructor(e){let t;if(!e)t={};else if(Fd(e))t={path:e};else if(typeof e==="string"||SK(e))t={value:e};else t=e;this.cwd="cwd"in t?"":LR.cwd(),this.data={},this.history=[],this.messages=[],this.value,this.map,this.result,this.stored;let n=-1;while(++n<nw.length){let r=nw[n];if(r in t&&t[r]!==void 0&&t[r]!==null)this[r]=r==="history"?[...t[r]]:t[r]}let i;for(i in t)if(!nw.includes(i))this[i]=t[i]}get basename(){return typeof this.path==="string"?Nn.basename(this.path):void 0}set basename(e){iw(e,"basename"),rw(e,"basename"),this.path=Nn.join(this.dirname||"",e)}get dirname(){return typeof this.path==="string"?Nn.dirname(this.path):void 0}set dirname(e){UR(this.basename,"dirname"),this.path=Nn.join(e||"",this.basename)}get extname(){return typeof this.path==="string"?Nn.extname(this.path):void 0}set extname(e){if(rw(e,"extname"),UR(this.dirname,"extname"),e){if(e.codePointAt(0)!==46)throw Error("`extname` must start with `.`");if(e.includes(".",1))throw Error("`extname` cannot contain multiple dots")}this.path=Nn.join(this.dirname,this.stem+(e||""))}get path(){return this.history[this.history.length-1]}set path(e){if(Fd(e))e=BR(e);if(iw(e,"path"),this.path!==e)this.history.push(e)}get stem(){return typeof this.path==="string"?Nn.basename(this.path,this.extname):void 0}set stem(e){iw(e,"stem"),rw(e,"stem"),this.path=Nn.join(this.dirname||"",e+(this.extname||""))}fail(e,t,n){let i=this.message(e,t,n);throw i.fatal=!0,i}info(e,t,n){let i=this.message(e,t,n);return i.fatal=void 0,i}message(e,t,n){let i=new wt(e,t,n);if(this.path)i.name=this.path+":"+i.name,i.file=this.path;return i.fatal=!1,this.messages.push(i),i}toString(e){if(this.value===void 0)return"";if(typeof this.value==="string")return this.value;return new TextDecoder(e||void 0).decode(this.value)}}function rw(e,t){if(e&&e.includes(Nn.sep))throw Error("`"+t+"` cannot be a path: did not expect `"+Nn.sep+"`")}function iw(e,t){if(!e)throw Error("`"+t+"` cannot be empty")}function UR(e,t){if(!e)throw Error("Setting `"+t+"` requires `path` to be set too")}function SK(e){return Boolean(e&&typeof e==="object"&&"byteLength"in e&&"byteOffset"in e)}var jR=function(e){let i=this.constructor.prototype,r=i[e],o=function(){return r.apply(o,arguments)};return Object.setPrototypeOf(o,i),o};var wK={}.hasOwnProperty;class cw extends jR{constructor(){super("copy");this.Compiler=void 0,this.Parser=void 0,this.attachers=[],this.compiler=void 0,this.freezeIndex=-1,this.frozen=void 0,this.namespace={},this.parser=void 0,this.transformers=tw()}copy(){let e=new cw,t=-1;while(++t<this.attachers.length){let n=this.attachers[t];e.use(...n)}return e.data(Zd.default(!0,{},this.namespace)),e}data(e,t){if(typeof e==="string"){if(arguments.length===2)return aw("data",this.frozen),this.namespace[e]=t,this;return wK.call(this.namespace,e)&&this.namespace[e]||void 0}if(e)return aw("data",this.frozen),this.namespace=e,this;return this.namespace}freeze(){if(this.frozen)return this;let e=this;while(++this.freezeIndex<this.attachers.length){let[t,...n]=this.attachers[this.freezeIndex];if(n[0]===!1)continue;if(n[0]===!0)n[0]=void 0;let i=t.call(e,...n);if(typeof i==="function")this.transformers.use(i)}return this.frozen=!0,this.freezeIndex=Number.POSITIVE_INFINITY,this}parse(e){this.freeze();let t=qd(e),n=this.parser||this.Parser;return ow("parse",n),n(String(t),t)}process(e,t){let n=this;return this.freeze(),ow("process",this.parser||this.Parser),sw("process",this.compiler||this.Compiler),t?i(void 0,t):new Promise(i);function i(r,o){let s=qd(e),a=n.parse(s);n.run(a,s,function(l,u,f){if(l||!u||!f)return c(l);let d=u,p=n.stringify(d,f);if(_K(p))f.value=p;else f.result=p;c(l,f)});function c(l,u){if(l||!u)o(l);else if(r)r(u);else L(t,"`done` is defined if `resolve` is not"),t(void 0,u)}}}processSync(e){let t=!1,n;return this.freeze(),ow("processSync",this.parser||this.Parser),sw("processSync",this.compiler||this.Compiler),this.process(e,i),MR("processSync","process",t),L(n,"we either bailed on an error or have a tree"),n;function i(r,o){t=!0,ew(r),n=o}}run(e,t,n){FR(e),this.freeze();let i=this.transformers;if(!n&&typeof t==="function")n=t,t=void 0;return n?r(void 0,n):new Promise(r);function r(o,s){L(typeof t!=="function","`file` can\u2019t be a `done` anymore, we checked");let a=qd(t);i.run(e,a,c);function c(l,u,f){let d=u||e;if(l)s(l);else if(o)o(d);else L(n,"`done` is defined if `resolve` is not"),n(void 0,d,f)}}}runSync(e,t){let n=!1,i;return this.run(e,t,r),MR("runSync","run",n),L(i,"we either bailed on an error or have a tree"),i;function r(o,s){ew(o),i=s,n=!0}}stringify(e,t){this.freeze();let n=qd(t),i=this.compiler||this.Compiler;return sw("stringify",i),FR(e),i(e,n)}use(e,...t){let n=this.attachers,i=this.namespace;if(aw("use",this.frozen),e===null||e===void 0);else if(typeof e==="function")a(e,t);else if(typeof e==="object")if(Array.isArray(e))s(e);else o(e);else throw TypeError("Expected usable value, not `"+e+"`");return this;function r(c){if(typeof c==="function")a(c,[]);else if(typeof c==="object")if(Array.isArray(c)){let[l,...u]=c;a(l,u)}else o(c);else throw TypeError("Expected usable value, not `"+c+"`")}function o(c){if(!("plugins"in c)&&!("settings"in c))throw Error("Expected usable value but received an empty preset, which is probably a mistake: presets typically come with `plugins` and sometimes with `settings`, but this has neither");if(s(c.plugins),c.settings)i.settings=Zd.default(!0,i.settings,c.settings)}function s(c){let l=-1;if(c===null||c===void 0);else if(Array.isArray(c))while(++l<c.length){let u=c[l];r(u)}else throw TypeError("Expected a list of plugins, not `"+c+"`")}function a(c,l){let u=-1,f=-1;while(++u<n.length)if(n[u][0]===c){f=u;break}if(f===-1)n.push([c,...l]);else if(l.length>0){let[d,...p]=l,b=n[f][1];if(Vc(b)&&Vc(d))d=Zd.default(!0,b,d);n[f]=[c,d,...p]}}}}var lw=new cw().freeze();function ow(e,t){if(typeof t!=="function")throw TypeError("Cannot `"+e+"` without `parser`")}function sw(e,t){if(typeof t!=="function")throw TypeError("Cannot `"+e+"` without `compiler`")}function aw(e,t){if(t)throw Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function FR(e){if(!Vc(e)||typeof e.type!=="string")throw TypeError("Expected node, got `"+e+"`")}function MR(e,t,n){if(!n)throw Error("`"+e+"` finished async. Use `"+t+"` instead")}function qd(e){return kK(e)?e:new Md(e)}function kK(e){return Boolean(e&&typeof e==="object"&&"message"in e&&"messages"in e)}function _K(e){return typeof e==="string"||EK(e)}function EK(e){return Boolean(e&&typeof e==="object"&&"byteLength"in e&&"byteOffset"in e)}var qR=lw().use(Rd).use(Ud).freeze();var ove=qR();Ne();var ZR=h.object({audiences:h.array(h.string()).optional(),positioning:h.string().optional()}),HR=h.object({summary:h.string().optional(),traits:h.array(h.string()).optional(),principles:h.array(h.string()).optional(),preferredTerms:h.array(h.string()).optional(),avoid:h.array(h.string()).optional()}),KR=h.object({artDirection:h.string().optional(),palette:h.array(h.string()).optional(),composition:h.string().optional(),mood:h.string().optional(),preferred:h.array(h.string()).optional(),avoid:h.array(h.string()).optional()}),AK=h.object({name:h.string().describe("Style guide name"),messaging:ZR.optional(),voice:HR.optional(),visual:KR.optional()});Ne();var TK=h.object({id:h.string().min(1),trigger:h.string().min(1),playbookId:h.string().min(1),once:h.boolean().default(!0),starterText:h.string().min(1),description:h.string().min(1).optional(),starterPrompt:h.string().min(1)}).strict();Ne();var CK=h.object({message:h.string().describe("Natural language response to the query"),summary:h.string().optional().describe("Brief summary if applicable"),topics:h.array(h.string()).optional().describe("Related topics mentioned"),sources:h.array(h.object({id:h.string(),type:h.string(),excerpt:h.string().optional(),relevance:h.number().min(0).max(1).optional()})).optional().describe("Source entities used to answer the query"),metadata:h.record(h.string(),h.unknown()).optional()}).describe("defaultQueryResponse"),OK=h.object({message:h.string()}).describe("simpleTextResponse"),VR=h.object({success:h.boolean(),entityId:h.string().optional(),message:h.string()}).describe("createEntityResponse"),GR=h.object({success:h.boolean(),entityId:h.string(),changes:h.array(h.string()).optional(),message:h.string()}).describe("updateEntityResponse");Ne();var YR=h.discriminatedUnion("type",[h.strictObject({type:h.literal("email"),address:h.email()})]),RK=h.strictObject({recipient:YR.optional(),title:h.string().min(1),body:h.string().min(1),html:h.string().min(1).optional(),sensitivity:h.enum(["normal","secret"]).default("normal"),idempotencyKey:h.string().trim().min(1).max(200).optional()}),PK=h.discriminatedUnion("status",[h.strictObject({status:h.literal("sent"),deliveryId:h.string().optional()}),h.strictObject({status:h.literal("failed")})]);Ne();var HSe=h.record(h.string(),h.unknown());Ne();hu();var GSe=h.record(h.string(),h.unknown());hu();Ne();var MK=h.object({slug:h.string(),title:h.string(),type:h.string(),entityId:h.string(),contentHash:h.string()});Ne();Ne();Ne();var qK=rd.omit({url:!0,analyticsScript:!0}),ZK=qK.extend({title:h.string().optional().describe("Optional site title override"),description:h.string().optional().describe("Optional site description override")});function fw(e,t={}){let n=WR(e),i=WR(t.sharedDomain??"rizom.ai").replace(/^\./,""),r=`.${i}`;if(n.endsWith(r)){let o=n.slice(0,-r.length);if(o.length>0&&!o.includes("."))return`${o}-preview.${i}`}return`preview.${n}`}function WR(e){return e.trim().replace(/^https?:\/\//i,"").replace(/\/$/,"").toLowerCase()}Ne();zv();var XR=["primary","secondary"];var HK=h.custom((e)=>typeof e==="function","Expected a React component"),KK=h.strictObject({show:h.boolean().optional(),label:h.string().min(1).optional(),slot:h.enum(XR).optional(),priority:h.number().optional()}),VK=h.strictObject({id:h.string().min(1),template:h.string().min(1),content:h.unknown().optional(),dataQuery:h.looseObject({entityType:h.string().optional(),template:h.string().optional(),query:h.record(h.string(),h.unknown()).optional()}).optional(),order:h.number().optional()}),GK=h.strictObject({id:h.string().min(1),path:h.string().startsWith("/"),title:h.string().optional(),pageLabel:h.string().optional(),description:h.string().optional(),sections:h.array(VK).optional(),layout:h.string().min(1).optional(),fullscreen:h.boolean().optional(),pluginId:h.string().optional(),sourceEntityType:h.string().optional(),external:h.boolean().optional(),navigation:KK.optional()}),YK=h.strictObject({label:h.string().min(1),pluralName:h.string().min(1).optional(),layout:h.string().min(1).optional(),paginate:h.boolean().optional(),pageSize:h.number().int().positive().optional(),navigation:h.strictObject({show:h.boolean().optional(),slot:h.enum(XR).optional(),priority:h.number().optional()}).optional()}),WK=h.strictObject({schema:h.custom((e)=>e instanceof h.ZodType,"Expected a Zod schema"),component:h.custom((e)=>typeof e==="function","Expected a React component"),title:h.string().min(1),description:h.string(),requiredPermission:h.enum(["admin","trusted","public"]).optional(),fullscreen:h.boolean().optional()}),JR=h.strictObject({namespace:h.string().min(1),sections:h.record(h.string(),WK)}),JK=h.record(h.string(),h.json()),XK=h.record(h.string(),h.record(h.string(),JK)),QR=h.strictObject({layouts:h.record(h.string(),HK).refine((e)=>typeof e.default==="function",{message:'Site layouts must include a "default" component'}),routes:h.array(GK),content:XK.optional(),sections:h.union([JR,h.array(JR)]).optional(),themeOverride:h.string().optional(),headScripts:h.array(h.string()).optional(),entityDisplay:h.record(h.string(),YK),staticAssets:h.record(h.string(),h.string()).optional()}).superRefine((e,t)=>{let n=new Set;for(let[o,s]of e.routes.entries()){if(n.has(s.id))t.addIssue({code:"custom",path:["routes",o,"id"],message:`Duplicate route id "${s.id}"`});n.add(s.id);let a=s.layout??"default";if(!e.layouts[a])t.addIssue({code:"custom",path:["routes",o,"layout"],message:`Unknown layout "${a}"`})}let i=Array.isArray(e.sections)?e.sections:e.sections?[e.sections]:[],r=new Map(i.map((o)=>[o.namespace,o]));if(r.size!==i.length)t.addIssue({code:"custom",path:["sections"],message:"Section group namespaces must be unique"});for(let[o,s]of Object.entries(e.content??{})){let a=r.get(o);if(!a){t.addIssue({code:"custom",path:["content",o],message:`Content namespace "${o}" has no section group`});continue}for(let[c,l]of Object.entries(s)){let u=a.sections[c];if(!u){t.addIssue({code:"custom",path:["content",o,c],message:`Content section "${o}.${c}" is not defined`});continue}let f=u.schema.safeParse(l);if(!f.success)t.addIssue({code:"custom",path:["content",o,c],message:`Content does not satisfy the "${o}.${c}" schema: ${h.prettifyError(f.error)}`})}}});var QK=h.string();function e7(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}var t7=h.custom((e)=>{if(!e7(e))return!1;let{plugin:t,...n}=e;if(t!==void 0&&typeof t!=="function")return!1;return QR.safeParse(n).success});function n7(e,t={}){return fw(e,t)}Cc();import{mkdir as _7,writeFile as E7}from"fs/promises";import{dirname as $7,join as cP}from"path";zi();import{mkdtemp as r7,mkdir as i7,readFile as o7,rm as s7,writeFile as a7}from"fs/promises";import{tmpdir as c7}from"os";import{dirname as l7,join as rP}from"path";var u7=["name: Your Name Here","Delete this and write your own"];async function iP(e,t,n,i,r={}){if(i.length===0)return;let o=r.env??process.env,s=Rn(e),a=tP(o,s,n.effectiveGitSyncToken),c=r.contentRepoAdminTokenSelector?tP(o,s,r.contentRepoAdminTokenSelector):void 0,l=dw(n.contentRepo,t),u=r.contentRepoRemoteResolver?.(n,t,a)??p7(l,a);if(!u)return;let f=await r7(rP(c7(),`brains-ops-content-sync-${n.handle}-`)),d=r.runCommand??qt,p=r.fetchImpl??fetch;try{if(!r.contentRepoRemoteResolver){if(!c)throw Error(`${r.contentRepoAdminTokenSelector??"CONTENT_REPO_ADMIN_TOKEN"} is required to check or create content repos`);await m7(l,c,p)}await d("git",["clone",u,f]),await h7(f,d),await d("git",["config","user.name","brains-ops[bot]"],{cwd:f}),await d("git",["config","user.email","41898282+github-actions[bot]@users.noreply.github.com"],{cwd:f});let b=!1;for(let g of i)if(await f7(f,g))b=!0;if(!b)return;await d("git",["add","."],{cwd:f}),await d("git",["commit","-m",`chore(content): seed ${n.handle} anchor profile`],{cwd:f}),await d("git",["push","origin","HEAD:main"],{cwd:f})}finally{await s7(f,{recursive:!0,force:!0})}}async function f7(e,t){let n=rP(e,t.path),i=await o7(n,"utf8").catch(()=>{return});if(i===t.content)return!1;if(i!==void 0&&!d7(i))return!1;return await i7(l7(n),{recursive:!0}),await a7(n,t.content),!0}function d7(e){return u7.some((t)=>e.includes(t))}function tP(e,t,n){return gt(n,e,t)}function p7(e,t){if(!t)return;return`https://x-access-token:${encodeURIComponent(t)}@github.com/${e.org}/${e.name}.git`}async function m7(e,t,n){let{org:i,name:r}=e,s=`https://api.github.com/repos/${`${encodeURIComponent(i)}/${encodeURIComponent(r)}`}`,a={Accept:"application/vnd.github+json",Authorization:`Bearer ${t}`,"User-Agent":"brains-ops","X-GitHub-Api-Version":"2022-11-28"},c=await n(s,{headers:a});if(c.ok)return;if(c.status!==404)throw Error(`Failed to check GitHub repo ${i}/${r}: ${c.status} ${await nP(c)}`);let l=await n(`https://api.github.com/orgs/${encodeURIComponent(i)}/repos`,{method:"POST",headers:a,body:JSON.stringify({name:r,private:!0,auto_init:!1})});if(l.ok){console.log(`Created missing content repo ${i}/${r}`);return}if(l.status===422){if((await n(s,{headers:a})).ok)return}throw Error(`Failed to create GitHub repo ${i}/${r}: ${l.status} ${await nP(l)}`)}async function nP(e){let t=await e.text();return t.trim().length===0?e.statusText:t}async function h7(e,t){try{await t("git",["checkout","-B","main","origin/main"],{cwd:e})}catch{await t("git",["checkout","-B","main"],{cwd:e})}}pw();Yn();async function Gs(e,t,n,i,r={}){let o=Hd(t.pilot.githubOrg);for(let s of n){let a={};if(i){let d=await i(s);if(d!==void 0)a=d}let c=await o(s),l=a.brainYaml??c.brainYaml,u=a.envFile??c.envFile,f=a.contentRepoFiles??c.contentRepoFiles??[];if(u)await mw(e,s.handle,".env",u);if(l)await mw(e,s.handle,"brain.yaml",l);await iP(e,t.pilot.githubOrg,s,f,{contentRepoAdminTokenSelector:t.pilot.contentRepoAdminToken,...r});for(let d of f)await mw(e,s.handle,cP("content",d.path),d.content)}}async function mw(e,t,n,i){let r=cP(e,"users",t,n);await _7($7(r),{recursive:!0}),await E7(r,i)}async function Kd(e,t){let n=await ut(e),i=n.users.find((r)=>r.handle===t);if(!i)throw Error(`Unknown user handle: ${t}`);return{registry:n,user:i}}async function lP(e,t){let n=await ut(e),i=n.cohorts.find((r)=>r.id===t);if(!i)throw Error(`Unknown cohort: ${t}`);return{registry:n,users:n.users.filter((r)=>r.cohort===i.id)}}async function uP(e){let t=await ut(e);return{registry:t,users:t.users}}async function hw(e,t,n,i={}){let{registry:r,user:o}=await Kd(e,t);await Gs(e,r,[o],n,i)}Ur();Yi();import{access as I7,mkdir as fP,readFile as A7,writeFile as pP}from"fs/promises";import{basename as T7,join as Ys}from"path";async function gw(e,t,n){let i=dn.parse(t),r=dn.parse(n.cohort),o=Ys(e,"users"),s=Ys(e,"cohorts"),a=Ys(o,`${i}.yaml`),c=Ys(o,`${i}.secrets.yaml`),l=Ys(o,`${i}.secrets.yaml.age`),u=Ys(s,`${r}.yaml`);await Promise.all([fP(o,{recursive:!0}),fP(s,{recursive:!0})]);let f=await dP(a,R7(i,n.anchorId)),p=await D7(l)?!1:await dP(c,P7(i)),{addedToCohort:b}=await C7(u,i);return{handle:i,cohort:r,userPath:a,secretsTemplatePath:c,cohortPath:u,createdUser:f,createdSecretsTemplate:p,addedToCohort:b}}async function C7(e,t){let n=await O7(e);if(n.members.includes(t))return{addedToCohort:!1};let i={...n,members:[...n.members,t].sort()};return await pP(e,N7(i)),{addedToCohort:!0}}async function O7(e){try{let t=await A7(e,"utf8"),n=Br(t,Gn);if(!n.ok)throw Error(`${T7(e)}: ${n.error}`);return n.data}catch(t){if(L7(t))return{members:[]};throw t}}function R7(e,t){return[`handle: ${e}`,"anchorProfile:",` name: ${B7(e)}`,"discord:"," enabled: true",...t?[` anchorUserId: ${JSON.stringify(t)}`]:[],""].join(`
|
|
806
806
|
`)}function P7(e){return["# local per-user secret staging file",`# fill values, run \`bunx brains-ops secrets:encrypt . ${e}\`, then the plaintext file will be removed`,"discordBotToken: ","atprotoAppPassword: ","# For custom-domain sites, paste PEMs with literal \\n escapes.","certificatePem: ","privateKeyPem: ",""].join(`
|
|
807
807
|
`)}function N7(e){return["members:",...e.members.map((t)=>` - ${t}`),...e.brainVersionOverride?[`brainVersionOverride: ${e.brainVersionOverride}`]:[],...e.bundlesOverride?["bundlesOverride:",...e.bundlesOverride.map((t)=>` - ${t}`)]:[],...e.addOverride?["addOverride:",...e.addOverride.map((t)=>` - ${t}`)]:[],...e.removeOverride?["removeOverride:",...e.removeOverride.map((t)=>` - ${t}`)]:[],...e.aiApiKeyOverride?[`aiApiKeyOverride: ${e.aiApiKeyOverride}`]:[],...e.gitSyncTokenOverride?[`gitSyncTokenOverride: ${e.gitSyncTokenOverride}`]:[],""].join(`
|
|
808
808
|
`)}async function dP(e,t){try{return await pP(e,t,{flag:"wx"}),!0}catch(n){if(z7(n))return!1;throw n}}async function D7(e){try{return await I7(e),!0}catch{return!1}}function z7(e){return mP(e,"EEXIST")}function L7(e){return mP(e,"ENOENT")}function mP(e,t){return typeof e==="object"&&e!==null&&"code"in e&&e.code===t}function B7(e){return e.split("-").filter((t)=>t.length>0).map((t)=>`${t[0]?.toUpperCase()??""}${t.slice(1)}`).join(" ")}async function yw(e,t,n,i={}){let{registry:r,users:o}=await lP(e,t);await Gs(e,r,o,n,i)}async function Gc(e,t,n={}){let{registry:i,users:r}=await uP(e);await Gs(e,i,r,t,n)}import{parseArgs as U7}from"util";function et(e){return e}class hP extends Error{constructor(e){super(e);this.name="CliUsageError"}}function j7(e,t){let n={...t};for(let i of e)for(let[r,o]of Object.entries(i.flags??{})){let s=n[r];if(s===void 0){n[r]=o;continue}if(s.type!==o.type||s.short!==o.short||s.default!==o.default)throw Error(`Conflicting definitions for flag --${r}: commands must agree on type, short, and default`)}return n}function F7(e){let t={};for(let[n,i]of Object.entries(e))t[n]={type:i.type,...i.short!==void 0?{short:i.short}:{},...i.default!==void 0?{default:i.default}:{}};return t}function M7(e){if(!(e instanceof Error)||!("code"in e))return!1;return e.code==="ERR_PARSE_ARGS_UNKNOWN_OPTION"||e.code==="ERR_PARSE_ARGS_INVALID_OPTION_VALUE"}function gP(e,t){let n=j7(t.commands,t.globalFlags??{}),i,r;try{({values:i,positionals:r}=U7({args:e,options:F7(n),allowPositionals:!0,strict:t.strict??!0}))}catch(s){if(M7(s))throw new hP(s.message.split(". ")[0]??s.message);throw s}if("help"in n&&i.help===!0)return{command:"help",args:[],flags:{help:!0}};if("version"in n&&i.version===!0)return{command:"version",args:[],flags:{version:!0}};let o={};for(let[s,a]of Object.entries(n)){let c=i[s];if(typeof c==="string"&&a.type==="string")o[s]=c;else if(typeof c==="boolean"&&a.type==="boolean")o[s]=c}return{command:r[0]??"help",args:r.slice(1),flags:o}}function yP(e){let t=e.reduce((n,i)=>Math.max(n,i.label.length),0);return e.map((n)=>` ${n.label.padEnd(t)} ${n.description}`)}function q7(e){return yP(e.map((t)=>({label:t.usage?`${t.name} ${t.usage}`:t.name,description:t.description})))}function Z7(e,t){let n=t.type==="string"?` ${t.placeholder??"<value>"}`:"",i=t.short!==void 0?`, -${t.short}`:"";return`--${e}${n}${i}`}function bP(e){return yP(Object.entries(e).map(([t,n])=>({label:Z7(t,n),description:n.description})))}function xP(e,t){return`Usage: ${e} ${t.name}${t.usage?` ${t.usage}`:""}`}function H7(e){return JSON.stringify(Object.entries(e).map(([t,n])=>[t,n.type,n.short??"",n.description,n.placeholder??"",n.default??""]).sort((t,n)=>String(t[0]).localeCompare(String(n[0]))))}function K7(e){let t=[],n=new Map;for(let r of e){let o=r.flags??{};if(Object.keys(o).length===0)continue;let s=H7(o),a=n.get(s);if(a){a.names.push(r.name);continue}let c={names:[r.name],flags:o};n.set(s,c),t.push(c)}let i=[];for(let r of t)i.push("",`${r.names.join(" / ")} options:`),i.push(...bP(r.flags));return i}function vP(e){let t=[e.intro,"",`Usage: ${e.cliName} ${e.usage??"<command> [args]"}`,"","Commands:",...q7(e.commands)];if(e.globalFlags&&Object.keys(e.globalFlags).length>0)t.push("","Options:",...bP(e.globalFlags));return t.push(...K7(e.commands)),t.join(`
|
|
@@ -828,7 +828,7 @@ agePublicKey: ${t}
|
|
|
828
828
|
`)}function M6(e){return`"${e.replace(/"/g,"\\\"").replace(/\n/g,"\\n")}"`}function GY(e,t){if(!t)return{id:"shared",domain:YY(e.pilot.domainSuffix)};let n=e.users.find((i)=>i.handle===t);if(!n)throw Error(`Unknown user handle: ${t}`);return{id:t,domain:n.domain,...n.cloudflareZoneId?{cloudflareZoneId:n.cloudflareZoneId}:{}}}function YY(e){let t=e.trim().replace(/^\./,"").replace(/\.$/,"");if(!t||t.includes("*"))throw Error(`Invalid pilot domainSuffix: ${e}`);return t}import{lookup as WY}from"dns/promises";function H6(e={}){let t=e.fetchImpl??fetch,n=e.lookupHost??WY;return async function(r){let o=await JY(r.domain,n),[s,a,c]=await Promise.all([Z6(r.domain,"/health/ready",t),Z6(r.domain,"/health/operate",t),XY(r.domain,t)]);return{dnsStatus:o,serverStatus:s,deployStatus:a,mcpStatus:c}}}async function JY(e,t){try{return(await t(e)).address?"ready":"failed"}catch{return"failed"}}async function Z6(e,t,n){try{return(await K6(n,`https://${e}${t}`,{method:"GET"})).ok?"ready":"failed"}catch{return"failed"}}async function XY(e,t){try{let n=await K6(t,`https://${e}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{}})});return n.status===401||n.ok?"ready":"failed"}catch{return"failed"}}async function K6(e,t,n){let i=new AbortController,r=setTimeout(()=>i.abort(),5000);try{return await e(t,{...n,signal:i.signal})}finally{clearTimeout(r)}}import{createHash as QY}from"crypto";import{cp as eW,lstat as tW,mkdtemp as nW,readFile as rW,readdir as iW,readlink as oW,rm as sW}from"fs/promises";import{tmpdir as aW}from"os";import{basename as cW,join as Ol,relative as lW,resolve as uW,sep as fW}from"path";var dW=new Set([".git",".operator",".brains-ops",".turbo","dist","node_modules"]);async function Y6(e){let t=uW(e),n=await nW(Ol(aW(),"brains-ops-reconcile-")),i=Ol(n,"repo");try{await eW(t,i,{recursive:!0,errorOnExist:!0,force:!1,filter:(a)=>pW(t,a)});let r=await uk(i);await V6(i);let o=await uk(i);await V6(i);let s=await uk(i);return{firstPassChangedFiles:G6(r,o),secondPassChangedFiles:G6(o,s)}}finally{await sW(n,{recursive:!0,force:!0})}}function pW(e,t){let n=lW(e,t);if(n.length===0)return!0;if(n.split(fW).some((r)=>dW.has(r)))return!1;if(n===".env"||n===".env.local")return!1;return!cW(n).endsWith(".secrets.yaml")}async function V6(e){await Gc(e,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 uk(e){let t=new Map;return await W6(e,"",t),t}async function W6(e,t,n){let i=Ol(e,t),r=await iW(i,{withFileTypes:!0});r.sort((o,s)=>o.name.localeCompare(s.name));for(let o of r){let s=Ol(t,o.name),a=Ol(e,s);if(o.isDirectory()){await W6(e,s,n);continue}let l=(await tW(a)).isSymbolicLink()?`symlink:${await oW(a)}`:await rW(a);n.set(s,QY("sha256").update(l).digest("hex"))}}function G6(e,t){return[...new Set([...e.keys(),...t.keys()])].filter((i)=>e.get(i)!==t.get(i)).sort()}Cc();import{readFileSync as Rl}from"fs";import{access as mW,rm as hW,writeFile as tz}from"fs/promises";import{join as fk,relative as J6}from"path";zi();Ur();Ne();var nz=h.strictObject({gitSyncToken:h.string().min(1).optional(),discordBotToken:h.string().min(1).optional(),discordPublicKey:h.string().min(1).optional(),discordApplicationId:h.string().min(1).optional(),aiApiKey:h.string().min(1).optional(),atprotoAppPassword:h.string().min(1).optional(),certificatePem:h.string().min(1).optional(),privateKeyPem:h.string().min(1).optional()});async function dk(e,t,n={}){let{registry:i,user:r}=await Kd(e,t),o=n.env??process.env,s=n.logger??console.log,a=Rn(e),c=fk(e,"users",`${t}.secrets.yaml.age`),l=fk(e,"users",`${t}.secrets.yaml`),u=ez(J6(e,c)),f=ez(J6(e,l)),d=bW(l),p=await xW(c,e,o,a),b=await rz(l),g={sharedAiApiKeySelector:i.pilot.aiApiKey,sharedGitSyncTokenSelector:i.pilot.gitSyncToken,effectiveAiApiKeySelector:r.effectiveAiApiKey,effectiveGitSyncTokenSelector:r.effectiveGitSyncToken,discordEnabled:r.discordEnabled},y;try{y=gW(e,o,a,d,p,g)}catch(C){if(!n.dryRun&&d===void 0&&C instanceof Error){let H=wW(g);if(H.length>0)throw await kW(l,H),Error(`Missing required secrets for ${t}. Created ${f}; fill it in and rerun secrets:encrypt. ${C.message}`,{cause:C})}throw C}let k=`${Wo(y).trimEnd()}
|
|
829
829
|
`;SW(k,y);let E=Object.keys(y);if(n.dryRun){if(s(`Dry run: would encrypt ${E.length} secrets to ${u}.`),s(E.length>0?`Keys: ${E.join(", ")}`:"Keys: (none \u2014 shared defaults only)"),b)s(`Would remove plaintext file ${f}.`);return{encryptedPath:u,plaintextPath:f,deletedPlaintext:b,encryptedKeys:E,dryRun:!0}}let O=new tk;O.addRecipient(i.pilot.agePublicKey);let P=await O.encrypt(k),U=Tl.encode(P);if(await tz(c,U),await hW(l,{force:!0}),s(`Encrypted ${E.length} secrets to ${u}.`),b)s(`Removed plaintext file ${f}.`);return{encryptedPath:u,plaintextPath:f,deletedPlaintext:b,encryptedKeys:E}}function gW(e,t,n,i,r,o){let s=X6(e,t,n,i,r,"aiApiKey",o.effectiveAiApiKeySelector,o.sharedAiApiKeySelector),a=X6(e,t,n,i,r,"gitSyncToken",o.effectiveGitSyncTokenSelector,o.sharedGitSyncTokenSelector),c=o.discordEnabled?Zp(e,t,n,i,r,"discordBotToken","DISCORD_BOT_TOKEN"):void 0,l=o.discordEnabled?Zp(e,t,n,i,r,"discordPublicKey","DISCORD_PUBLIC_KEY"):void 0,u=o.discordEnabled?Zp(e,t,n,i,r,"discordApplicationId","DISCORD_APPLICATION_ID"):void 0,f=Hp(e,t,n,i,r,"atprotoAppPassword","ATPROTO_APP_PASSWORD"),d=Q6(Hp(e,t,n,i,r,"certificatePem","CERTIFICATE_PEM")),p=Q6(Hp(e,t,n,i,r,"privateKeyPem","PRIVATE_KEY_PEM"));return nz.parse({...s?{aiApiKey:s}:{},...a?{gitSyncToken:a}:{},...c?{discordBotToken:c}:{},...l?{discordPublicKey:l}:{},...u?{discordApplicationId:u}:{},...f?{atprotoAppPassword:f}:{},...d?{certificatePem:d}:{},...p?{privateKeyPem:p}:{}})}function X6(e,t,n,i,r,o,s,a){if(s===a)return;return Zp(e,t,n,i,r,o,s)}function Zp(e,t,n,i,r,o,s){let a=Hp(e,t,n,i,r,o,s);if(a===void 0||a.trim().length===0)throw Error(`Missing required secret value for ${String(o)}. Set it in users/<handle>.secrets.yaml or fall back to ${s}/${s}_FILE before running secrets:encrypt.`);return a}function Q6(e){return e?.replace(/\r\n?|\n/g,"\\n")}function Hp(e,t,n,i,r,o,s){return yW(i,r,o,s,t,n,e)}function yW(e,t,n,i,r,o,s){let a=e?.[n];if(a!==void 0&&a.trim().length>0)return a;let c=gt(`${i}_FILE`,r,o);if(c&&c.trim().length>0)return Rl(zr(c,s),"utf8");let l=gt(i,r,o);if(l!==void 0&&l.trim().length>0)return l;let u=t?.[n];if(u!==void 0&&u.trim().length>0)return u;return}function bW(e){let t;try{t=Rl(e,"utf8")}catch{return}try{return pk(t)}catch(n){throw Error(`Unable to parse plaintext secrets file ${e}: ${Je(n)}`,{cause:n})}}async function xW(e,t,n,i){if(!await rz(e))return;let r=vW(t,n,i);if(!r)return;let o;try{let s=Rl(e,"utf8"),a=Tl.decode(s),c=new nk;c.addIdentity(r),o=await c.decrypt(a,"text")}catch{return}try{return pk(o)}catch(s){throw Error(`Unable to parse decrypted secrets from ${e}: ${Je(s)}`,{cause:s})}}function vW(e,t,n){let i=gt("AGE_SECRET_KEY_FILE",t,n);if(i&&i.trim().length>0)return ya(Rl(zr(i,e),"utf8"));let r=gt("AGE_SECRET_KEY",t,n);if(r&&r.trim().length>0)return ya(r);try{return ya(Rl(fk(e,".brains-ops","age","identity.txt"),"utf8"))}catch{return}}function pk(e){let t=XE(e),n={};if(t!==null&&typeof t==="object"&&!Array.isArray(t)){for(let[i,r]of Object.entries(t))if(typeof r==="string")n[i]=r}return nz.partial().parse(n)}function SW(e,t){let n={...t},i={...pk(e)},r=new Set([...Object.keys(n),...Object.keys(i)]);for(let o of r)if(n[o]!==i[o])throw Error(`secrets:encrypt round-trip verification failed for ${o}; refusing to write a corrupted encrypted payload`)}function wW(e){return[...e.effectiveAiApiKeySelector!==e.sharedAiApiKeySelector?["aiApiKey"]:[],...e.effectiveGitSyncTokenSelector!==e.sharedGitSyncTokenSelector?["gitSyncToken"]:[],...e.discordEnabled?["discordBotToken","discordPublicKey","discordApplicationId"]:[]]}async function kW(e,t){let n=["# local per-user secret staging file","# fill values, run `bunx brains-ops secrets:encrypt . <handle>`, then the plaintext file will be removed",...t.map((i)=>`${i}: `),""].join(`
|
|
830
830
|
`);await tz(e,n,{flag:"wx"})}async function rz(e){try{return await mW(e),!0}catch{return!1}}function ez(e){return e.replaceAll("\\","/")}zi();import{readFileSync as _W}from"fs";async function mk(e,t={}){let n=t.env??process.env,i=t.logger??console.log,r=Rn(e),o=Qm(`${e}/.env.schema`),s=$W(o),a=[],c=[],l=new Map;for(let f of s){l.set(f.key,f.required);let d=IW(f.key,n,r,e);if(d===void 0||d.trim().length===0){c.push(f.key);continue}a.push([f.key,d])}if(a.length===0)throw Error("No pushable local secrets found for this pilot repo");let u=(f)=>l.get(f)??!1;if(t.dryRun)return i(`Dry run: would push ${a.length} secrets to GitHub Secrets.`),i(`Secrets: ${a.map(([f])=>f).join(", ")}`),qp(i,c,u),{pushedKeys:a.map(([f])=>f),skippedKeys:c,dryRun:!0};return await Cr("gh",a,{logger:i,runCommand:t.runCommand??qt}),qp(i,c,u),{pushedKeys:a.map(([f])=>f),skippedKeys:c}}var EW=new Set(["DISCORD_BOT_TOKEN","DISCORD_PUBLIC_KEY","DISCORD_APPLICATION_ID"]);function $W(e){return e.filter((t)=>!EW.has(t.key)).map((t)=>({key:t.key,required:t.required}))}function IW(e,t,n,i){let r=gt(`${e}_FILE`,t,n);if(r&&r.trim().length>0)return _W(zr(r,i),"utf8");let o=gt(e,t,n);if(o===void 0||o.trim().length===0)return;return o}Ne();import{execFileSync as iz}from"child_process";import{chmodSync as AW,existsSync as TW,mkdirSync as CW,readFileSync as oz,writeFileSync as OW}from"fs";import{dirname as RW,join as PW}from"path";import{homedir as NW}from"os";th();var sz=h.object({id:h.number(),name:h.string(),public_key:h.string()}),DW=h.object({ssh_keys:h.array(sz)}),zW={createEd25519KeyPair(e,t){iz("ssh-keygen",["-t","ed25519","-f",e,"-C",t,"-N",""],{stdio:"ignore"})},derivePublicKey(e){return iz("ssh-keygen",["-y","-f",e],{encoding:"utf-8",stdio:["ignore","pipe","inherit"]}).trim()}};async function Kp(e,t={}){try{let n=await hk(e,t);return{success:!0,message:n.createdLocalKey?`SSH deploy key ready at ${n.privateKeyPath}`:`SSH deploy key already ready at ${n.privateKeyPath}`}}catch(n){return{success:!1,message:Je(n,"SSH key bootstrap failed")}}}async function hk(e,t={}){let n=t.env??process.env,i=Rn(e),r=t.logger??console.log,o=t.fetchImpl??fetch,s=t.sshKeygen??zW,a=gt("HCLOUD_TOKEN",n,i);if(!a)throw Error("Missing HCLOUD_TOKEN");let c=gt("HCLOUD_SSH_KEY_NAME",n,i);if(!c)throw Error("Missing HCLOUD_SSH_KEY_NAME");let l=gt("KAMAL_SSH_PRIVATE_KEY_FILE",n,i),u=l?zr(l,e):PW(NW(),".ssh",`${BW(c)}_ed25519`),f=`${u}.pub`,d=!1;if(!TW(u))CW(RW(u),{recursive:!0,mode:448}),s.createEd25519KeyPair(u,c),d=!0;AW(u,384);let p;if(d)p=oz(f,"utf-8").trim();else p=s.derivePublicKey(u),OW(f,`${p}
|
|
831
|
-
`,"utf-8");if(p.length===0)throw Error(`Unable to derive a public key from ${u}`);let b=await LW({fetchImpl:o,hcloudToken:a,publicKey:p,sshKeyName:c}),g=zo(t.pushTo);if(g)await Cr(g,[["KAMAL_SSH_PRIVATE_KEY",oz(u,"utf-8")]],{logger:r,runCommand:t.runCommand??qt});if(r(d?`Created ${u}`:`Reusing ${u}`),r(b?`Registered Hetzner SSH key ${c}`:`Hetzner SSH key ${c} already exists`),g)r(`Pushed KAMAL_SSH_PRIVATE_KEY to ${g}`);return{createdHetznerKey:b,createdLocalKey:d,privateKeyPath:u,publicKeyPath:f,sshKeyName:c}}async function LW(e){let t=new URL("https://api.hetzner.cloud/v1/ssh_keys");t.searchParams.set("name",e.sshKeyName);let n=await e.fetchImpl(t.toString(),{headers:{Authorization:`Bearer ${e.hcloudToken}`,"Content-Type":"application/json"}}),{ssh_keys:i}=await ba(n,DW,{label:"Hetzner SSH key lookup failed"}),[r]=i;if(r){if(r.public_key.trim()!==e.publicKey)throw Error(`Existing Hetzner SSH key ${e.sshKeyName} does not match the local public key`);return!1}let o=await e.fetchImpl("https://api.hetzner.cloud/v1/ssh_keys",{method:"POST",headers:{Authorization:`Bearer ${e.hcloudToken}`,"Content-Type":"application/json"},body:JSON.stringify({name:e.sshKeyName,public_key:e.publicKey})});return await ba(o,h.object({ssh_key:sz}),{label:"Hetzner SSH key create failed"}),!0}function BW(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_")}Ne();Yn();var UW=h.looseObject({status:h.string(),operationalStatus:h.string(),checks:h.array(h.looseObject({name:h.string(),status:h.string(),message:h.string().optional()})).default([]),app:h.looseObject({daemons:h.array(h.looseObject({name:h.string().optional(),status:h.string().optional(),health:h.looseObject({status:h.string().optional(),message:h.string().optional()}).optional()})).default([])}).default({daemons:[]})});async function gk(e,t,n={}){let i=n.fetchImpl??fetch,o=(await ut(e)).users.find((d)=>d.handle===t);if(!o)throw Error(`Unknown pilot user: ${t}`);let s=`https://${o.domain}`,a=[],c=[],l=h.number().int().positive().max(30).parse(n.operationalRetryAttempts??6),u=h.number().int().nonnegative().max(60000).parse(n.operationalRetryDelayMs??1e4),f=n.sleep??((d)=>new Promise((p)=>setTimeout(p,d)));if(await Vp("health",()=>jW(i,s,l,u,f),a,c),await Vp("mcp-auth-gate",()=>qW(i,s),a,c),o.bundles.includes("site"))await Vp("site",()=>az(i,`${s}/`,"site"),a,c),await Vp("cms",()=>az(i,`${s}/cms`,"cms"),a,c),n.logger?.("WARN Manual check still required: passkey setup/handoff completed from the setup email.");return{handle:o.handle,bundles:o.bundles,domain:o.domain,contentRepo:o.contentRepo,checks:a,failedChecks:c}}async function Vp(e,t,n,i){try{await t(),n.push(e)}catch(r){i.push({name:e,message:Je(r)})}}async function jW(e,t,n,i,r){let o;for(let s=1;s<=n;s++)try{await FW(e,t);return}catch(a){if(o=a,s<n)await r(i)}throw o}async function FW(e,t){let i=await yk(e,`${t}/health/operate`,{method:"GET"}),r=await i.json().catch(()=>null),o=UW.safeParse(r);if(!i.ok){let a=o.success?o.data.checks.filter((c)=>c.status!=="healthy").slice(0,10).map((c)=>`${c.name}: ${MW(c.message??c.status)}`):[];throw Error(`/health/operate returned ${i.status}, expected 200${a.length>0?` (${a.join("; ")})`:""}`)}if(!o.success)throw Error(`/health/operate response did not match expected shape: ${o.error.message}`);let s=o.data;if(s.status!=="ready")throw Error(`/health/operate status is ${s.status}, expected ready`);if(s.operationalStatus!=="operational")throw Error(`/health/operate operationalStatus is ${s.operationalStatus}, expected operational`);for(let a of s.app.daemons){let c=a.status??"unknown",l=a.health?.status;if(c==="error"||l==="unhealthy")throw Error(`daemon ${a.name??"unknown"} is unhealthy (${c}/${l??"unknown"})`)}}function MW(e){let t=e.replaceAll(/\s+/g," ").trim();return t.length<=300?t:`${t.slice(0,297)}...`}async function qW(e,t){let n=await yk(e,`${t}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize"})});if(n.status<400||n.status>=500)throw Error(`unauthenticated POST /mcp returned ${n.status}, expected a 4xx auth failure`)}async function az(e,t,n){let i=await yk(e,t,{method:"GET"});if(i.status>=400)throw Error(`${n} ${t} returned ${i.status}, expected < 400`)}async function yk(e,t,n){let i=new AbortController,r=setTimeout(()=>i.abort(),20000);try{return await e(t,{...n,redirect:"follow",signal:i.signal})}finally{clearTimeout(r)}}var SB="brains-ops",G_={type:"string",placeholder:"<target>",description:"Push target (`gh` or `github`)"},Y_={type:"boolean",description:"Show what would happen without writing anything"};function ht(e){return{success:!1,message:xP(SB,e)}}var wB=et({name:"init",usage:"<repo>",description:"Create a pilot repo skeleton",run:async({args:e})=>{let t=e[0];if(!t)return ht(wB);return await qv(t),{success:!0,message:`Initialized ${t}`}}}),kB=et({name:"upgrade",usage:"<repo>",description:"Bump @rizom/ops and refresh the generated scaffold",flags:{to:{type:"string",placeholder:"<version>",description:"Explicit @rizom/ops version (`latest` by default)"}},run:async({args:e,flags:t})=>{let n=e[0];if(!n)return ht(kB);let i=rt(t,"to"),{upgradePilotRepo:r}=await Promise.resolve().then(() => (uz(),lz)),{from:o,to:s}=await r(n,{...i&&i!=="latest"?{version:i}:{}});return{success:!0,message:o===s?`Already at @rizom/ops@${s}; scaffold refreshed`:`Upgraded @rizom/ops ${o} -> ${s}; scaffold refreshed`}}}),_B=et({name:"crossover:stage",usage:"<source-repo> <output-dir> <bundle-review.yaml> [site-pins.yaml]",description:"Stage a reviewed capability-bundle crossover copy",run:async({args:e})=>{let t=e[0],n=e[1],i=e[2],r=e[3];if(!t||!n||!i)return ht(_B);let{loadCapabilityBundleReview:o,loadReviewedSitePins:s,stageLegacyCrossover:a}=await Promise.resolve().then(() => (F4(),j4)),c=await o(i),l=r?await s(r):void 0,u=await a(t,n,{bundleReview:c,sitePins:l});return{success:!0,message:`Staged ${u.changedFiles.length} reviewed crossover files in ${u.outputDir}`}}}),EB=et({name:"render",usage:"<repo>",description:"Render the observed users table to views/users.md",run:async({args:e},t)=>{let n=e[0];if(!n)return ht(EB);let i=t.resolveStatus??H6({...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},...t.lookupHost?{lookupHost:t.lookupHost}:{}});return await Ji(n,{resolveStatus:i}),{success:!0,message:`Rendered ${n}/views/users.md`}}}),$B=et({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:e,flags:t})=>{let n=e[0],i=e[1],r=rt(t,"cohort");if(!n||!i||!r)return ht($B);let o=rt(t,"anchor-id");return await gw(n,i,{cohort:r,...o?{anchorId:o}:{}}),{success:!0,message:`Added ${i} to ${r}`}}}),IB=et({name:"onboard",usage:"<repo> <handle>",description:"Generate a user's brain.yaml and .env",run:async({args:e},t)=>{let n=e[0],i=e[1];if(!n||!i)return ht(IB);return await hw(n,i,t.runner,{...t.env?{env:t.env}:{}}),{success:!0,message:`Onboarded ${i}`}}}),AB=et({name:"age-key:bootstrap",usage:"<repo>",description:"Generate the pilot age key and optional GitHub secret",flags:{"push-to":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(AB);let r=rt(t,"push-to");return sk(i,{...n.logger?{logger:n.logger}:{},...r?{pushTo:r}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{}})}}),TB=et({name:"ssh-key:bootstrap",usage:"<repo>",description:"Bootstrap a deploy SSH key and optional GitHub secret",flags:{"push-to":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(TB);let r=rt(t,"push-to");return Kp(i,{...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{},...r?{pushTo:r}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{},...n.sshKeygen?{sshKeygen:n.sshKeygen}:{}})}}),CB=et({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":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(CB);let r=rt(t,"handle"),o=rt(t,"push-to");return lk(i,{...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{},...r?{handle:r}:{},...o?{pushTo:o}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{}})}}),OB=et({name:"secrets:push",usage:"<repo>",description:"Push env-backed local secrets to GitHub Secrets",flags:{"dry-run":Y_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(OB);let r=await mk(i,{env:n.env,logger:n.logger,dryRun:Vd(t,"dry-run")});return{success:!0,message:r.dryRun?`Dry run: would push ${r.pushedKeys.length} secrets`:`Pushed ${r.pushedKeys.length} secrets`}}}),RB=et({name:"secrets:encrypt",usage:"<repo> <handle>",description:"Encrypt pilot secrets for a user with age",flags:{"dry-run":Y_},run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1];if(!i||!r)return ht(RB);let o=await dk(i,r,{env:n.env,logger:n.logger,dryRun:Vd(t,"dry-run")});return{success:!0,message:o.dryRun?`Dry run: would encrypt ${o.encryptedKeys.length} secrets for ${r}`:`Encrypted ${o.encryptedKeys.length} secrets for ${r}`}}}),PB=et({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:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"profile"),s=rt(t,"confirm");if(!i||!r||!s||o!=="regression"&&o!=="load"&&o!=="stress")return ht(PB);let a=n.directorySyncStressRunner??(await Promise.resolve().then(() => (uu(),Zm))).runDeployedDirectorySyncStress,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,profile:o,confirmation:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.report.success,message:`${l.report.success?"Passed":"Failed"} ${o} directory-sync stress for ${r}; artifacts: ${l.artifactsDir}`}}}),NB=et({name:"stress:directory-sync:verify-access",usage:"<repo> <handle> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Verify smoke stress credentials without remote writes",flags:{confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for the access-check result"}},run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm");if(!i||!r||!o)return ht(NB);let s=n.directorySyncStressAccessRunner??(await Promise.resolve().then(() => (uu(),Zm))).verifyDirectorySyncStressAccess,a=rt(t,"artifacts-dir"),c=await s({rootDir:i,handle:r,confirmation:o,...a?{artifactsDir:a}:{},...n.env?{env:n.env}:{}});return{success:c.success,message:`Verified directory-sync stress access for ${r} at ${c.remoteHead}; artifacts: ${c.artifactsDir}`}}}),DB=et({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:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm");if(!i||!r||!o)return ht(DB);let s=n.directorySyncStressCleanupRunner??(await Promise.resolve().then(() => (uu(),Zm))).cleanupDirectorySyncStress,a=rt(t,"artifacts-dir"),c=await s({rootDir:i,handle:r,confirmation:o,...a?{artifactsDir:a}:{},...n.env?{env:n.env}:{},...n.logger?{logger:n.logger}:{}});return{success:c.success,message:`${c.success?"Cleaned":"Failed to clean"} directory-sync stress probes for ${r}; removed ${c.probesRemoved}, remaining ${c.probesRemaining}`}}}),zB={confirm:{type:"string",placeholder:"watchdog-smoke:<handle>",description:"Explicit smoke target confirmation"},"run-id":{type:"string",placeholder:"<id>",description:"Stable workflow run identifier used for cleanup"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for remote smoke evidence"}},LB=et({name:"smoke:health-watchdog",usage:"<repo> <handle> --confirm watchdog-smoke:<handle> --run-id <id> [--artifacts-dir <path>]",description:"Run the smoke-fleet host watchdog isolation check",flags:zB,run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm"),s=rt(t,"run-id");if(!i||!r||!o||!s)return ht(LB);let a=n.healthWatchdogSmokeRunner??(await Vm().then(() => V_)).runHealthWatchdogSmoke,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,confirmation:o,runId:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.success,message:`Passed health watchdog smoke for ${r}; artifacts: ${l.artifactsDir}`}}}),BB=et({name:"smoke:health-watchdog:cleanup",usage:"<repo> <handle> --confirm watchdog-smoke:<handle> --run-id <id> [--artifacts-dir <path>]",description:"Remove residual smoke-fleet watchdog fixtures",flags:zB,run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm"),s=rt(t,"run-id");if(!i||!r||!o||!s)return ht(BB);let a=n.healthWatchdogSmokeCleanupRunner??(await Vm().then(() => V_)).cleanupHealthWatchdogSmoke,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,confirmation:o,runId:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.success,message:`Cleaned health watchdog smoke fixtures for ${r}; artifacts: ${l.artifactsDir}`}}}),UB=et({name:"verify-user",usage:"<repo> <handle>",description:"Probe a deployed user's endpoints",run:async({args:e},t)=>{let n=e[0],i=e[1];if(!n||!i)return ht(UB);let r=await gk(n,i,{...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},...t.logger?{logger:t.logger}:{},...t.verificationRetryAttempts!==void 0?{operationalRetryAttempts:t.verificationRetryAttempts}:{},...t.verificationRetryDelayMs!==void 0?{operationalRetryDelayMs:t.verificationRetryDelayMs}:{},...t.sleep?{sleep:t.sleep}:{}}),o=r.checks.length>0?r.checks.join(", "):"none";if(r.failedChecks.length>0){let s=r.failedChecks.map((a)=>` ${a.name}: ${a.message}`).join(`
|
|
831
|
+
`,"utf-8");if(p.length===0)throw Error(`Unable to derive a public key from ${u}`);let b=await LW({fetchImpl:o,hcloudToken:a,publicKey:p,sshKeyName:c}),g=zo(t.pushTo);if(g)await Cr(g,[["KAMAL_SSH_PRIVATE_KEY",oz(u,"utf-8")]],{logger:r,runCommand:t.runCommand??qt});if(r(d?`Created ${u}`:`Reusing ${u}`),r(b?`Registered Hetzner SSH key ${c}`:`Hetzner SSH key ${c} already exists`),g)r(`Pushed KAMAL_SSH_PRIVATE_KEY to ${g}`);return{createdHetznerKey:b,createdLocalKey:d,privateKeyPath:u,publicKeyPath:f,sshKeyName:c}}async function LW(e){let t=new URL("https://api.hetzner.cloud/v1/ssh_keys");t.searchParams.set("name",e.sshKeyName);let n=await e.fetchImpl(t.toString(),{headers:{Authorization:`Bearer ${e.hcloudToken}`,"Content-Type":"application/json"}}),{ssh_keys:i}=await ba(n,DW,{label:"Hetzner SSH key lookup failed"}),[r]=i;if(r){if(r.public_key.trim()!==e.publicKey)throw Error(`Existing Hetzner SSH key ${e.sshKeyName} does not match the local public key`);return!1}let o=await e.fetchImpl("https://api.hetzner.cloud/v1/ssh_keys",{method:"POST",headers:{Authorization:`Bearer ${e.hcloudToken}`,"Content-Type":"application/json"},body:JSON.stringify({name:e.sshKeyName,public_key:e.publicKey})});return await ba(o,h.object({ssh_key:sz}),{label:"Hetzner SSH key create failed"}),!0}function BW(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_")}Ne();Yn();var UW=h.looseObject({status:h.string(),operationalStatus:h.string(),checks:h.array(h.looseObject({name:h.string(),status:h.string(),message:h.string().optional()})).default([]),app:h.looseObject({daemons:h.array(h.looseObject({name:h.string().optional(),status:h.string().optional(),health:h.looseObject({status:h.string().optional(),message:h.string().optional()}).optional()})).default([])}).default({daemons:[]})});async function gk(e,t,n={}){let i=n.fetchImpl??fetch,o=(await ut(e)).users.find((d)=>d.handle===t);if(!o)throw Error(`Unknown pilot user: ${t}`);let s=`https://${o.domain}`,a=[],c=[],l=h.number().int().positive().max(30).parse(n.operationalRetryAttempts??6),u=h.number().int().nonnegative().max(60000).parse(n.operationalRetryDelayMs??1e4),f=n.sleep??((d)=>new Promise((p)=>setTimeout(p,d)));if(await Vp("health",()=>jW(i,s,l,u,f),a,c),await Vp("mcp-auth-gate",()=>qW(i,s),a,c),o.bundles.includes("site"))await Vp("site",()=>az(i,`${s}/`,"site"),a,c),await Vp("studio",()=>az(i,`${s}/studio`,"studio"),a,c),n.logger?.("WARN Manual check still required: passkey setup/handoff completed from the setup email.");return{handle:o.handle,bundles:o.bundles,domain:o.domain,contentRepo:o.contentRepo,checks:a,failedChecks:c}}async function Vp(e,t,n,i){try{await t(),n.push(e)}catch(r){i.push({name:e,message:Je(r)})}}async function jW(e,t,n,i,r){let o;for(let s=1;s<=n;s++)try{await FW(e,t);return}catch(a){if(o=a,s<n)await r(i)}throw o}async function FW(e,t){let i=await yk(e,`${t}/health/operate`,{method:"GET"}),r=await i.json().catch(()=>null),o=UW.safeParse(r);if(!i.ok){let a=o.success?o.data.checks.filter((c)=>c.status!=="healthy").slice(0,10).map((c)=>`${c.name}: ${MW(c.message??c.status)}`):[];throw Error(`/health/operate returned ${i.status}, expected 200${a.length>0?` (${a.join("; ")})`:""}`)}if(!o.success)throw Error(`/health/operate response did not match expected shape: ${o.error.message}`);let s=o.data;if(s.status!=="ready")throw Error(`/health/operate status is ${s.status}, expected ready`);if(s.operationalStatus!=="operational")throw Error(`/health/operate operationalStatus is ${s.operationalStatus}, expected operational`);for(let a of s.app.daemons){let c=a.status??"unknown",l=a.health?.status;if(c==="error"||l==="unhealthy")throw Error(`daemon ${a.name??"unknown"} is unhealthy (${c}/${l??"unknown"})`)}}function MW(e){let t=e.replaceAll(/\s+/g," ").trim();return t.length<=300?t:`${t.slice(0,297)}...`}async function qW(e,t){let n=await yk(e,`${t}/mcp`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize"})});if(n.status<400||n.status>=500)throw Error(`unauthenticated POST /mcp returned ${n.status}, expected a 4xx auth failure`)}async function az(e,t,n){let i=await yk(e,t,{method:"GET"});if(i.status>=400)throw Error(`${n} ${t} returned ${i.status}, expected < 400`)}async function yk(e,t,n){let i=new AbortController,r=setTimeout(()=>i.abort(),20000);try{return await e(t,{...n,redirect:"follow",signal:i.signal})}finally{clearTimeout(r)}}var SB="brains-ops",G_={type:"string",placeholder:"<target>",description:"Push target (`gh` or `github`)"},Y_={type:"boolean",description:"Show what would happen without writing anything"};function ht(e){return{success:!1,message:xP(SB,e)}}var wB=et({name:"init",usage:"<repo>",description:"Create a pilot repo skeleton",run:async({args:e})=>{let t=e[0];if(!t)return ht(wB);return await qv(t),{success:!0,message:`Initialized ${t}`}}}),kB=et({name:"upgrade",usage:"<repo>",description:"Bump @rizom/ops and refresh the generated scaffold",flags:{to:{type:"string",placeholder:"<version>",description:"Explicit @rizom/ops version (`latest` by default)"}},run:async({args:e,flags:t})=>{let n=e[0];if(!n)return ht(kB);let i=rt(t,"to"),{upgradePilotRepo:r}=await Promise.resolve().then(() => (uz(),lz)),{from:o,to:s}=await r(n,{...i&&i!=="latest"?{version:i}:{}});return{success:!0,message:o===s?`Already at @rizom/ops@${s}; scaffold refreshed`:`Upgraded @rizom/ops ${o} -> ${s}; scaffold refreshed`}}}),_B=et({name:"crossover:stage",usage:"<source-repo> <output-dir> <bundle-review.yaml> [site-pins.yaml]",description:"Stage a reviewed capability-bundle crossover copy",run:async({args:e})=>{let t=e[0],n=e[1],i=e[2],r=e[3];if(!t||!n||!i)return ht(_B);let{loadCapabilityBundleReview:o,loadReviewedSitePins:s,stageLegacyCrossover:a}=await Promise.resolve().then(() => (F4(),j4)),c=await o(i),l=r?await s(r):void 0,u=await a(t,n,{bundleReview:c,sitePins:l});return{success:!0,message:`Staged ${u.changedFiles.length} reviewed crossover files in ${u.outputDir}`}}}),EB=et({name:"render",usage:"<repo>",description:"Render the observed users table to views/users.md",run:async({args:e},t)=>{let n=e[0];if(!n)return ht(EB);let i=t.resolveStatus??H6({...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},...t.lookupHost?{lookupHost:t.lookupHost}:{}});return await Ji(n,{resolveStatus:i}),{success:!0,message:`Rendered ${n}/views/users.md`}}}),$B=et({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:e,flags:t})=>{let n=e[0],i=e[1],r=rt(t,"cohort");if(!n||!i||!r)return ht($B);let o=rt(t,"anchor-id");return await gw(n,i,{cohort:r,...o?{anchorId:o}:{}}),{success:!0,message:`Added ${i} to ${r}`}}}),IB=et({name:"onboard",usage:"<repo> <handle>",description:"Generate a user's brain.yaml and .env",run:async({args:e},t)=>{let n=e[0],i=e[1];if(!n||!i)return ht(IB);return await hw(n,i,t.runner,{...t.env?{env:t.env}:{}}),{success:!0,message:`Onboarded ${i}`}}}),AB=et({name:"age-key:bootstrap",usage:"<repo>",description:"Generate the pilot age key and optional GitHub secret",flags:{"push-to":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(AB);let r=rt(t,"push-to");return sk(i,{...n.logger?{logger:n.logger}:{},...r?{pushTo:r}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{}})}}),TB=et({name:"ssh-key:bootstrap",usage:"<repo>",description:"Bootstrap a deploy SSH key and optional GitHub secret",flags:{"push-to":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(TB);let r=rt(t,"push-to");return Kp(i,{...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{},...r?{pushTo:r}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{},...n.sshKeygen?{sshKeygen:n.sshKeygen}:{}})}}),CB=et({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":G_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(CB);let r=rt(t,"handle"),o=rt(t,"push-to");return lk(i,{...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{},...r?{handle:r}:{},...o?{pushTo:o}:{},...n.bootstrapRunCommand?{runCommand:n.bootstrapRunCommand}:{}})}}),OB=et({name:"secrets:push",usage:"<repo>",description:"Push env-backed local secrets to GitHub Secrets",flags:{"dry-run":Y_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(OB);let r=await mk(i,{env:n.env,logger:n.logger,dryRun:Vd(t,"dry-run")});return{success:!0,message:r.dryRun?`Dry run: would push ${r.pushedKeys.length} secrets`:`Pushed ${r.pushedKeys.length} secrets`}}}),RB=et({name:"secrets:encrypt",usage:"<repo> <handle>",description:"Encrypt pilot secrets for a user with age",flags:{"dry-run":Y_},run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1];if(!i||!r)return ht(RB);let o=await dk(i,r,{env:n.env,logger:n.logger,dryRun:Vd(t,"dry-run")});return{success:!0,message:o.dryRun?`Dry run: would encrypt ${o.encryptedKeys.length} secrets for ${r}`:`Encrypted ${o.encryptedKeys.length} secrets for ${r}`}}}),PB=et({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:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"profile"),s=rt(t,"confirm");if(!i||!r||!s||o!=="regression"&&o!=="load"&&o!=="stress")return ht(PB);let a=n.directorySyncStressRunner??(await Promise.resolve().then(() => (uu(),Zm))).runDeployedDirectorySyncStress,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,profile:o,confirmation:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.report.success,message:`${l.report.success?"Passed":"Failed"} ${o} directory-sync stress for ${r}; artifacts: ${l.artifactsDir}`}}}),NB=et({name:"stress:directory-sync:verify-access",usage:"<repo> <handle> --confirm stress:<handle> [--artifacts-dir <path>]",description:"Verify smoke stress credentials without remote writes",flags:{confirm:{type:"string",placeholder:"stress:<handle>",description:"Explicit smoke target confirmation"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for the access-check result"}},run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm");if(!i||!r||!o)return ht(NB);let s=n.directorySyncStressAccessRunner??(await Promise.resolve().then(() => (uu(),Zm))).verifyDirectorySyncStressAccess,a=rt(t,"artifacts-dir"),c=await s({rootDir:i,handle:r,confirmation:o,...a?{artifactsDir:a}:{},...n.env?{env:n.env}:{}});return{success:c.success,message:`Verified directory-sync stress access for ${r} at ${c.remoteHead}; artifacts: ${c.artifactsDir}`}}}),DB=et({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:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm");if(!i||!r||!o)return ht(DB);let s=n.directorySyncStressCleanupRunner??(await Promise.resolve().then(() => (uu(),Zm))).cleanupDirectorySyncStress,a=rt(t,"artifacts-dir"),c=await s({rootDir:i,handle:r,confirmation:o,...a?{artifactsDir:a}:{},...n.env?{env:n.env}:{},...n.logger?{logger:n.logger}:{}});return{success:c.success,message:`${c.success?"Cleaned":"Failed to clean"} directory-sync stress probes for ${r}; removed ${c.probesRemoved}, remaining ${c.probesRemaining}`}}}),zB={confirm:{type:"string",placeholder:"watchdog-smoke:<handle>",description:"Explicit smoke target confirmation"},"run-id":{type:"string",placeholder:"<id>",description:"Stable workflow run identifier used for cleanup"},"artifacts-dir":{type:"string",placeholder:"<path>",description:"Directory for remote smoke evidence"}},LB=et({name:"smoke:health-watchdog",usage:"<repo> <handle> --confirm watchdog-smoke:<handle> --run-id <id> [--artifacts-dir <path>]",description:"Run the smoke-fleet host watchdog isolation check",flags:zB,run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm"),s=rt(t,"run-id");if(!i||!r||!o||!s)return ht(LB);let a=n.healthWatchdogSmokeRunner??(await Vm().then(() => V_)).runHealthWatchdogSmoke,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,confirmation:o,runId:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.success,message:`Passed health watchdog smoke for ${r}; artifacts: ${l.artifactsDir}`}}}),BB=et({name:"smoke:health-watchdog:cleanup",usage:"<repo> <handle> --confirm watchdog-smoke:<handle> --run-id <id> [--artifacts-dir <path>]",description:"Remove residual smoke-fleet watchdog fixtures",flags:zB,run:async({args:e,flags:t},n)=>{let i=e[0],r=e[1],o=rt(t,"confirm"),s=rt(t,"run-id");if(!i||!r||!o||!s)return ht(BB);let a=n.healthWatchdogSmokeCleanupRunner??(await Vm().then(() => V_)).cleanupHealthWatchdogSmoke,c=rt(t,"artifacts-dir"),l=await a({rootDir:i,handle:r,confirmation:o,runId:s,...c?{artifactsDir:c}:{},...n.env?{env:n.env}:{},...n.fetchImpl?{fetchImpl:n.fetchImpl}:{},...n.logger?{logger:n.logger}:{}});return{success:l.success,message:`Cleaned health watchdog smoke fixtures for ${r}; artifacts: ${l.artifactsDir}`}}}),UB=et({name:"verify-user",usage:"<repo> <handle>",description:"Probe a deployed user's endpoints",run:async({args:e},t)=>{let n=e[0],i=e[1];if(!n||!i)return ht(UB);let r=await gk(n,i,{...t.fetchImpl?{fetchImpl:t.fetchImpl}:{},...t.logger?{logger:t.logger}:{},...t.verificationRetryAttempts!==void 0?{operationalRetryAttempts:t.verificationRetryAttempts}:{},...t.verificationRetryDelayMs!==void 0?{operationalRetryDelayMs:t.verificationRetryDelayMs}:{},...t.sleep?{sleep:t.sleep}:{}}),o=r.checks.length>0?r.checks.join(", "):"none";if(r.failedChecks.length>0){let s=r.failedChecks.map((a)=>` ${a.name}: ${a.message}`).join(`
|
|
832
832
|
`);return{success:!1,message:`Verified ${r.handle} (${r.bundles.join(",")}) at https://${r.domain}: passed ${o}; failed:
|
|
833
833
|
${s}`}}return{success:!0,message:`Verified ${r.handle} (${r.bundles.join(",")}) at https://${r.domain}: ${o}`}}}),jB=et({name:"reconcile-cohort",usage:"<repo> <cohort>",description:"Reconcile all users in a cohort",run:async({args:e},t)=>{let n=e[0],i=e[1];if(!n||!i)return ht(jB);return await yw(n,i,t.runner,{...t.env?{env:t.env}:{}}),{success:!0,message:`Reconciled cohort ${i}`}}});function vB(e,t){return[e,...t.length===0?["- (none)"]:t.map((n)=>`- ${n}`)]}var FB=et({name:"reconcile-all",usage:"<repo> [--dry-run]",description:"Reconcile every cohort",flags:{"dry-run":Y_},run:async({args:e,flags:t},n)=>{let i=e[0];if(!i)return ht(FB);if(Vd(t,"dry-run")){let r=await Y6(i),o=r.firstPassChangedFiles.length,s=r.secondPassChangedFiles.length;return{success:s===0,message:[`Dry-run reconcile found ${o} first-pass changed file(s); second pass ${s===0?"converged with zero drift":`still changed ${s} file(s)`}`,...vB("First-pass changed files:",r.firstPassChangedFiles),...vB("Second-pass changed files:",r.secondPassChangedFiles)].join(`
|
|
834
834
|
`)}}return await Gc(i,n.runner,{...n.env?{env:n.env}:{}}),{success:!0,message:"Reconciled all cohorts"}}}),Lse=et({name:"help",description:"Show this help message",run:()=>({success:!0,message:vP({cliName:SB,intro:"brains-ops \u2014 operator CLI for private brain fleet repos",commands:Gm,globalFlags:W_})})}),Bse=et({name:"version",description:"Show version",run:()=>({success:!0,message:`brains-ops ${fu.version}`})}),W_={help:{type:"boolean",short:"h",description:"Show help"},version:{type:"boolean",short:"v",description:"Show version"}},Gm=[wB,kB,_B,EB,$B,IB,AB,TB,CB,OB,RB,PB,NB,DB,LB,BB,UB,jB,FB,Lse,Bse],Use=SP(Gm);async function jse(e,t={}){let n=Use.get(e.command);if(!n)return{success:!1,message:`Unknown command: ${e.command}`};return n.run({args:e.args,flags:e.flags},t)}function Fse(e){return gP(e,{commands:Gm,globalFlags:W_})}qm();uu();Yi();await Vm();export{Yr as CAPABILITY_BUNDLE_CONTRACT,gw as addPilotUser,ou as assertDirectorySyncStressTarget,Km as assertHealthWatchdogSmokeTarget,C6 as bootstrapPilotAgeKey,q6 as bootstrapPilotOriginCertificate,hk as bootstrapPilotSshKey,Qf as canonicalBundleIdSchema,nB as cleanupDirectorySyncStress,gB as cleanupHealthWatchdogSmoke,Gn as cohortSchema,n7 as derivePreviewDomain,iu as directorySyncStressPlanSchema,ru as directorySyncStressProfileSchema,V4 as directorySyncStressReportSchema,dk as encryptPilotSecrets,ya as extractAgeIdentity,qv as initPilotRepo,ut as loadPilotRegistry,hw as onboardUser,Fse as parseArgs,Wr as pilotSchema,mk as pushPilotSecrets,Gc as reconcileAll,yw as reconcileCohort,K_ as renderHealthWatchdogSmokeRemoteScript,gT as requiredImages,R_ as resolveDirectorySyncStressPlan,yT as resolveImageBuilds,jse as runCommand,eB as runDeployedDirectorySyncStress,P_ as runDirectorySyncStressPlan,hB as runHealthWatchdogSmoke,sk as runPilotAgeKeyBootstrap,lk as runPilotCertBootstrap,Kp as runPilotSshKeyBootstrap,i5 as runResolveMissingImages,Mm as sampleStressHealth,Zv as siteImageTag,hT as sitePackagesFor,G4 as stressMetricsFailure,tB as verifyDirectorySyncStressAccess,gk as verifyPilotUser,Ji as writeUsersTable};
|
package/package.json
CHANGED
|
@@ -21,8 +21,8 @@ const pilot = parseStringYamlMapping(readFileSync("pilot.yaml", "utf8"));
|
|
|
21
21
|
writeSecretGitHubEnv("AI_API_KEY", secrets["aiApiKey"]);
|
|
22
22
|
writeSecretGitHubEnv("GIT_SYNC_TOKEN", secrets["gitSyncToken"]);
|
|
23
23
|
writeSecretGitHubEnv(
|
|
24
|
-
"
|
|
25
|
-
secrets["
|
|
24
|
+
"STUDIO_CONTENT_REPO_PAT",
|
|
25
|
+
secrets["studioContentRepoPat"] ?? secrets["gitSyncToken"],
|
|
26
26
|
);
|
|
27
27
|
writeSecretGitHubEnv("DISCORD_BOT_TOKEN", secrets["discordBotToken"]);
|
|
28
28
|
writeSecretGitHubEnv("DISCORD_PUBLIC_KEY", secrets["discordPublicKey"]);
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
- unauthenticated `POST https://<handle>.rizom.ai/mcp` returns the expected auth failure
|
|
30
30
|
- content repo exists and runtime sync is healthy
|
|
31
31
|
- background jobs are not repeatedly failing, except for expected missing optional integrations
|
|
32
|
-
- when `site` is selected, the browser/
|
|
32
|
+
- when `site` is selected, the browser/Studio surfaces load and the initial app-managed site build completes
|
|
33
33
|
14. For fleet upgrades, edit `pilot.yaml.brainVersion` and push once; CI rebuilds the required default/site image tags, refreshes generated user env files, and redeploys affected users. Every external site and theme package keeps its own required exact version pin and never follows the brain version implicitly.
|
|
34
34
|
15. Confirm the user received the setup email, registered their passkey, and can sign in to web chat at `https://<handle>.rizom.ai/chat`. That completes the default onboarding; everything below is per-cohort extras.
|
|
35
35
|
16. Hand over the browser surfaces:
|
|
36
36
|
- Chat (primary): `https://<handle>.rizom.ai/chat`
|
|
37
37
|
- Dashboard: `https://<handle>.rizom.ai/`
|
|
38
|
-
-
|
|
38
|
+
- Studio: `https://<handle>.rizom.ai/studio`, plus GitHub token guidance if Studio editing is part of their cohort
|
|
39
39
|
17. For Discord-enabled cohorts, hand the Discord setup details to the user as a secondary chat surface.
|
|
40
40
|
18. If they need direct client access (MCP), use OAuth/passkey-capable clients where possible.
|
|
41
41
|
19. If you are also giving them a content repo workflow, describe it as optional and frame git/Obsidian as an advanced file-based path, not the default.
|
|
@@ -165,7 +165,7 @@ For every bundle posture it checks:
|
|
|
165
165
|
- unauthenticated `POST https://<handle>.rizom.ai/mcp` returns the expected auth failure;
|
|
166
166
|
- background jobs are not repeatedly failing, except for missing optional integrations.
|
|
167
167
|
|
|
168
|
-
A `core`-only instance is MCP-only; a bare `GET /` may return `401` without indicating a bad deploy. When `site` is selected, verification also checks the browser and
|
|
168
|
+
A `core`-only instance is MCP-only; a bare `GET /` may return `401` without indicating a bad deploy. When `site` is selected, verification also checks the browser and Studio/login surfaces.
|
|
169
169
|
|
|
170
170
|
Manual checks that remain:
|
|
171
171
|
|
|
@@ -175,7 +175,7 @@ Manual checks that remain:
|
|
|
175
175
|
|
|
176
176
|
## One-user canonical site canary
|
|
177
177
|
|
|
178
|
-
Run this before adding custom site/theme packages or rolling a larger browser/
|
|
178
|
+
Run this before adding custom site/theme packages or rolling a larger browser/Studio-first cohort.
|
|
179
179
|
|
|
180
180
|
1. Create or choose a canary cohort with explicit bundles:
|
|
181
181
|
|
|
@@ -187,7 +187,7 @@ Run this before adding custom site/theme packages or rolling a larger browser/CM
|
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
2. Add exactly one canary user to that cohort.
|
|
190
|
-
3. For browser/
|
|
190
|
+
3. For browser/Studio-first onboarding, configure setup email in `users/<handle>.yaml`:
|
|
191
191
|
|
|
192
192
|
```yaml
|
|
193
193
|
setup:
|
|
@@ -234,14 +234,14 @@ separate packages.
|
|
|
234
234
|
2. Apply the exact package names and versions to one healthy canonical site canary.
|
|
235
235
|
3. Reconcile the canary, push the generated output, and let build/deploy create its site image.
|
|
236
236
|
4. Run `bunx brains-ops verify-user . <handle>`.
|
|
237
|
-
5. Manually verify the site, theme,
|
|
237
|
+
5. Manually verify the site, theme, Studio, content sync, and passkey sign-in before adding more users.
|
|
238
238
|
|
|
239
239
|
To roll back, remove or change `siteOverride`, reconcile, and redeploy that user.
|
|
240
240
|
The default image and other users remain untouched.
|
|
241
241
|
|
|
242
242
|
## Setup email checklist
|
|
243
243
|
|
|
244
|
-
Use this for browser/
|
|
244
|
+
Use this for browser/Studio-first users who should receive their own first-passkey setup link by email.
|
|
245
245
|
|
|
246
246
|
1. Add setup delivery to the user file:
|
|
247
247
|
|
|
@@ -262,7 +262,7 @@ Use this for browser/CMS-first users who should receive their own first-passkey
|
|
|
262
262
|
4. Verify the generated `users/<handle>/brain.yaml` contains `auth-service.setupEmail` and `email` interface config.
|
|
263
263
|
5. Ask the user to complete passkey setup from the email link, then use:
|
|
264
264
|
- Dashboard: `https://<handle>.rizom.ai/`
|
|
265
|
-
-
|
|
265
|
+
- Studio: `https://<handle>.rizom.ai/studio`
|
|
266
266
|
|
|
267
267
|
Notes:
|
|
268
268
|
|
|
@@ -24,7 +24,7 @@ Your main interfaces are:
|
|
|
24
24
|
|
|
25
25
|
- **Chat** (`/chat`) — talk to your brain;
|
|
26
26
|
- **Dashboard/site** (`/`) — the configured browser surface;
|
|
27
|
-
- **
|
|
27
|
+
- **Studio** (`/studio`) — edit durable content in a browser.
|
|
28
28
|
|
|
29
29
|
Start with Chat.
|
|
30
30
|
|
|
@@ -36,11 +36,11 @@ Start with Chat.
|
|
|
36
36
|
|
|
37
37
|
That save–ask–use loop is the core workflow.
|
|
38
38
|
|
|
39
|
-
## Chat or
|
|
39
|
+
## Chat or Studio?
|
|
40
40
|
|
|
41
41
|
**Chat** is for thinking aloud, asking questions, saving things quickly, and day-to-day work.
|
|
42
42
|
|
|
43
|
-
**
|
|
43
|
+
**Studio** is for deliberate browsing and editing. It becomes more useful as your content grows.
|
|
44
44
|
|
|
45
45
|
## Other interfaces and peer brains
|
|
46
46
|
|
|
@@ -59,7 +59,7 @@ MCP is a standard protocol that lets compatible AI clients use your brain's tool
|
|
|
59
59
|
|
|
60
60
|
**How do I access my data?**
|
|
61
61
|
|
|
62
|
-
Use the
|
|
62
|
+
Use the Studio. If your cohort includes GitHub access, the same durable markdown also lives in a private repository.
|
|
63
63
|
|
|
64
64
|
**Does it search the public internet?**
|
|
65
65
|
|
|
@@ -82,7 +82,7 @@ We will send details in this shape:
|
|
|
82
82
|
```text
|
|
83
83
|
Chat URL: https://<handle>.rizom.ai/chat
|
|
84
84
|
Dashboard URL: https://<handle>.rizom.ai/
|
|
85
|
-
|
|
85
|
+
Studio URL: https://<handle>.rizom.ai/studio
|
|
86
86
|
Discord: yes/no — setup steps if enabled
|
|
87
87
|
MCP: enabled/not enabled — setup details if enabled
|
|
88
88
|
```
|